class CloudNode extends MetaModelUpdateVo implements DataProxy<CloudNode>, TagsFetchHandler, Tpl.TplHandler {

    public static final String NODE_NAME = LambdaSee.field(CloudNode::getNodeName);

    public static final String ACCESS_TOKEN = LambdaSee.field(CloudNode::getAccessToken);

    @Column(unique = true)
    @EruptField(
            views = @View(title = "节点名", sortable = true),
            edit = @Edit(title = "节点名", desc = "NodeName", notNull = true, search = @Search(vague = true))
    )
    private String nodeName;

    @EruptField(
            views = @View(title = "友好名称", sortable = true),
            edit = @Edit(title = "友好名称", notNull = true, search = @Search(vague = true))
    )
    private String name;

    @ManyToOne
    @EruptField(
            views = @View(title = "所属分组", column = "name"),
            edit = @Edit(title = "所属分组", type = EditType.REFERENCE_TREE, search = @Search)
    )
    private CloudNodeGroup cloudNodeGroup;

    @EruptField(
            views = @View(title = "状态", sortable = true),
            edit = @Edit(title = "状态", search = @Search, notNull = true, boolType = @BoolType(
                    trueText = "启用", falseText = "禁用"
            ))
    )
    private Boolean status = true;

    @Transient
    @EruptField(
            views = @View(title = "Erupt 类数量", className = "text-center", width = "120px")
    )
    private Integer eruptNum;

    @Transient
    @EruptField(
            views = @View(title = "模块数", className = "text-center", width = "70px")
    )
    private Integer eruptModuleNum;

    @Transient
    @EruptField(
            views = @View(title = "实例数", className = "text-center", width = "70px"
                    , tpl = @Tpl(path = "/tpl/node-instance.ftl", width = "400px", tplHandler = CloudNode.class)
            )
    )
    private Integer instanceNum;

    @Transient
    @EruptField(
            views = @View(title = "版本", className = "text-center", width = "120px")
    )
    private String version;

    @EruptField(
            views = @View(title = "负责人", sortable = true),
            edit = @Edit(title = "负责人", type = EditType.TAGS,
                    tagsType = @TagsType(fetchHandler = CloudNode.class), notNull = true)
    )
    private String duty;

    @Lob
    @Type(type = "org.hibernate.type.TextType")
    @EruptField(
            views = @View(title = "节点配置"),
            edit = @Edit(title = "节点配置", desc = "配置后可在子节点中读取", type = EditType.CODE_EDITOR, codeEditType = @CodeEditorType(language = "json"))
    )
    private String config;

    @EruptField(
            views = @View(title = "Access Token", width = "120px")
    )
    private String accessToken;

    @Column(length = AnnotationConst.REMARK_LENGTH)
    @EruptField(
            views = @View(title = "描述", type = ViewType.HTML),
            edit = @Edit(title = "描述", type = EditType.TEXTAREA)
    )
    private String remark;

    @Transient
    @Resource
    private NodeManager nodeManager;

    @Transient
    @Resource
    private EruptDao eruptDao;

    @Override
    public void afterUpdate(CloudNode cloudNode) {
        DataProxy.super.afterUpdate(cloudNode);
    }

    @Override
    public void beforeAdd(CloudNode cloudNode) {
        if (null == cloudNode.getAccessToken()) cloudNode.setAccessToken(Erupts.generateCode(16).toUpperCase());
    }

    @Override
    public void beforeUpdate(CloudNode cloudNode) {
        this.beforeAdd(cloudNode);
    }

    @Override
    public void afterFetch(Collection<Map<String, Object>> list) {<FILL_FUNCTION_BODY>}

    @Override
    public void afterDelete(CloudNode cloudNode) {
        nodeManager.removeNode(cloudNode.getNodeName());
    }

    @Override
    public List<String> fetchTags(String[] params) {
        return eruptDao.getJdbcTemplate().queryForList("select name from e_upms_user", String.class);
    }

    @Override
    public void bindTplData(Map<String, Object> binding, String[] params) {
        CloudNode cloudNode = (CloudNode) binding.get(EngineConst.INJECT_ROW);
        MetaNode metaNode = nodeManager.getNode(cloudNode.getNodeName());
        if (null == metaNode) {
            binding.put("instances", "[]");
        } else {
            binding.put("instances", GsonFactory.getGson().toJson(metaNode.getLocations()));
        }
    }

}

        for (Map<String, Object> map : list) {
            Optional.ofNullable(map.get(ACCESS_TOKEN)).ifPresent(it -> {
                String token = it.toString();
                map.put(ACCESS_TOKEN, token.substring(0, 3) + "******" + token.substring(token.length() - 3));
            });
            map.put(LambdaSee.field(CloudNode::getEruptNum), '-');
            map.put(LambdaSee.field(CloudNode::getInstanceNum), '-');
            map.put(LambdaSee.field(CloudNode::getVersion), '-');
            map.put(LambdaSee.field(CloudNode::getEruptModuleNum), '-');
            try {
                MetaNode metaNode = nodeManager.getNode(map.get(NODE_NAME).toString());
                Optional.ofNullable(nodeManager.getNode(map.get(NODE_NAME).toString())).ifPresent(metaNode1 -> {
                    Function<Collection<String>, Object> function = (it) -> null == it ? 0 : String.format("<a href='javascript:alert(`%s`);'>%d</a>", String.join("\\u000a", it), it.size());
                    map.put(LambdaSee.field(CloudNode::getEruptNum), function.apply(metaNode.getErupts()));
                    map.put(LambdaSee.field(CloudNode::getInstanceNum), metaNode.getLocations().size());
                    map.put(LambdaSee.field(CloudNode::getEruptModuleNum), function.apply(metaNode.getEruptModules()));
                    map.put(LambdaSee.field(CloudNode::getVersion), metaNode.getVersion());
                });
            } catch (Exception e) {
                map.put(LambdaSee.field(CloudNode::getVersion), String.format("<span style='color:#f00'>%s</span>", e.getMessage()));
                log.warn("node warn → " + map.get(NODE_NAME), e);
            }
        }
    
<methods>public non-sealed void <init>() <variables>private java.lang.String updateBy,private java.time.LocalDateTime updateTime