diff options
| author | fangshunjian <[email protected]> | 2022-10-10 17:35:46 +0800 |
|---|---|---|
| committer | fangshunjian <[email protected]> | 2022-10-10 17:35:46 +0800 |
| commit | a2939495abd551b225f0a88ad6fdb7ec64eb365b (patch) | |
| tree | a7dff16cae74f34fa890ac2e8a12fd60236c32ee | |
| parent | 2ac4c6aae76c53bfb5e646b0371fceb08567cc3b (diff) | |
fix: snapshot 核心线程数 和 空闲时间支持配置rel-22.07.12
| -rw-r--r-- | nz-admin/src/main/java/com/nis/modules/panel/service/impl/VisualPanelServiceImpl.java | 3936 |
1 files changed, 2037 insertions, 1899 deletions
diff --git a/nz-admin/src/main/java/com/nis/modules/panel/service/impl/VisualPanelServiceImpl.java b/nz-admin/src/main/java/com/nis/modules/panel/service/impl/VisualPanelServiceImpl.java index 5b19f68c..111191c9 100644 --- a/nz-admin/src/main/java/com/nis/modules/panel/service/impl/VisualPanelServiceImpl.java +++ b/nz-admin/src/main/java/com/nis/modules/panel/service/impl/VisualPanelServiceImpl.java @@ -20,7 +20,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -90,7 +89,6 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.log.Log; - @Service("visualPanelService") public class VisualPanelServiceImpl extends ServiceImpl<VisualPanelDao, VisualPanel> implements VisualPanelService { @@ -101,1937 +99,2077 @@ public class VisualPanelServiceImpl extends ServiceImpl<VisualPanelDao, VisualPa @Value("${dashboard.snapshot.timeout:300000}") private Integer timeout; - @Autowired - private VisualChartService visualChartService; - - @Autowired - private SysConfigService sysConfigService; - - @Autowired - private VisualChartElementService chartElementService; - - @Autowired - private DataSourceTransactionManager dataSourceTransactionManager; + @Autowired + private VisualChartService visualChartService; + + @Autowired + private SysConfigService sysConfigService; + + @Autowired + private VisualChartElementService chartElementService; + + @Autowired + private DataSourceTransactionManager dataSourceTransactionManager; + + @Autowired + private TransactionDefinition transactionDefinition; + + @Autowired + private SysDictService sysDictService; + + @Autowired + private BasicImportAndExportServices basicImportAndExportServices; @Autowired - private TransactionDefinition transactionDefinition; - + private StatServiceImpl statServiceImpl; + @Autowired - private SysDictService sysDictService; + private PromApiService promApiService; - @Autowired - private BasicImportAndExportServices basicImportAndExportServices; + @Autowired + private LokiApiService lokiApiService; - @Autowired - private StatServiceImpl statServiceImpl; + @Autowired + private SysConfigDao sysConfigDao; - @Autowired - private PromApiService promApiService; + @Autowired + private SysUserStarredService starredService; - @Autowired - private LokiApiService lokiApiService; + @Autowired + private AssetAssetService assetAssetService; - @Autowired - private SysConfigDao sysConfigDao; + @Autowired + private MonitorEndpointService monitorEndpointService; - @Autowired - private SysUserStarredService starredService; + @Autowired + private RedisTemplate redisTemplate; - @Autowired - private AssetAssetService assetAssetService; + @Autowired + private ReportJobManager reportJobManager; - @Autowired - private MonitorEndpointService monitorEndpointService; + @Autowired + private TimezoneService timezoneService; - @Autowired - private RedisTemplate redisTemplate; + @Value("${snapshot.concurrency:10}") + private Integer snapshotConcurrency; - @Autowired - private ReportJobManager reportJobManager; + @Value("${snapshot.corePoolSize:5}") + private Integer snapshotCorePoolSize; - @Autowired - private TimezoneService timezoneService; + @Value("${snapshot.keepAliveTime:30}") + private Long snapshotKeepAliveTime; - @Value("${snapshot.concurrency:10}") - private Integer snapshotConcurrency; - - @Value("${snapshot.capacity:10000}") + @Value("${snapshot.capacity:10000}") private Integer snapshotCapacity; - // snapshot 执行线程池,避免大量请求访问 prometheus 服务 - private ExecutorService snapshotThreadPool; - - @Override - public VisualPanel queryInfo(Integer id) { - VisualPanel visualPanel = this.baseMapper.queryInfo(id); - if(ToolUtil.isNotEmpty(visualPanel.getParam())) - visualPanel.setParam(JSONObject.parseObject(String.valueOf(visualPanel.getParam()), Map.class)); - - // 当前用户收藏状态 1:收藏 0:未收藏 - int count = starredService.count(new LambdaQueryWrapper<SysUserStarredEntity>() - .eq(SysUserStarredEntity::getTid, visualPanel.getId()) - .eq(SysUserStarredEntity::getType, "panel") - .eq(SysUserStarredEntity::getUid, ShiroUtils.getUserId().intValue()) - ); - - visualPanel.setStarred(count == 0 ? 0 : 1); - return visualPanel; - } - - @Override - public List<VisualPanel> queryList(Map<String, Object> params) { - String ids = (String) params.get("ids"); - if(StrUtil.isNotBlank(ids)) { - List<String> listIds = Arrays.asList(ids.split(",")); - params.put("ids",listIds); - } - //获取当前登录用户的id - Long currentLoginUserID = ShiroUtils.getUserId(); - params.put("currentLoginUserID",currentLoginUserID); - // 1. 查询时 type 为空则默认 dashboard 类型 - String type = (String) params.get("type"); - if (StringUtils.isEmpty(type)) { - type = Constant.PanelType.DASHBOARD.getValue(); - params.put("type", type); - } - // 2. dashboard 类型 需要进行排序返回 - List<VisualPanel> panelList = new ArrayList<>(); - if (StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(),type)) { - panelList = this.baseMapper.queryList(params); - if (CollectionUtils.isNotEmpty(panelList) && panelList.size() != 1) { - panelList = this.getVisualPanelTreeList(panelList, 0); - } - } else { - // 3. 其他类型不进行排序 - panelList = this.baseMapper.queryList(params); - for (VisualPanel visualPanel: panelList) { - if(ToolUtil.isNotEmpty(visualPanel.getParam())) - visualPanel.setParam(JSONObject.parseObject(String.valueOf(visualPanel.getParam()), Map.class)); - } - } - - // 查询当前panel下的chart数量并且进行赋值 + // snapshot 执行线程池,避免大量请求访问 prometheus 服务 + private ExecutorService snapshotThreadPool; + + @Override + public VisualPanel queryInfo(Integer id) { + VisualPanel visualPanel = this.baseMapper.queryInfo(id); + if (ToolUtil.isNotEmpty(visualPanel.getParam())) + visualPanel.setParam(JSONObject.parseObject(String.valueOf(visualPanel.getParam()), Map.class)); + + // 当前用户收藏状态 1:收藏 0:未收藏 + int count = starredService.count(new LambdaQueryWrapper<SysUserStarredEntity>() + .eq(SysUserStarredEntity::getTid, visualPanel.getId()).eq(SysUserStarredEntity::getType, "panel") + .eq(SysUserStarredEntity::getUid, ShiroUtils.getUserId().intValue())); + + visualPanel.setStarred(count == 0 ? 0 : 1); + return visualPanel; + } + + @Override + public List<VisualPanel> queryList(Map<String, Object> params) { + String ids = (String) params.get("ids"); + if (StrUtil.isNotBlank(ids)) { + List<String> listIds = Arrays.asList(ids.split(",")); + params.put("ids", listIds); + } + // 获取当前登录用户的id + Long currentLoginUserID = ShiroUtils.getUserId(); + params.put("currentLoginUserID", currentLoginUserID); + // 1. 查询时 type 为空则默认 dashboard 类型 + String type = (String) params.get("type"); + if (StringUtils.isEmpty(type)) { + type = Constant.PanelType.DASHBOARD.getValue(); + params.put("type", type); + } + // 2. dashboard 类型 需要进行排序返回 + List<VisualPanel> panelList = new ArrayList<>(); + if (StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(), type)) { + panelList = this.baseMapper.queryList(params); + if (CollectionUtils.isNotEmpty(panelList) && panelList.size() != 1) { + panelList = this.getVisualPanelTreeList(panelList, 0); + } + } else { + // 3. 其他类型不进行排序 + panelList = this.baseMapper.queryList(params); + for (VisualPanel visualPanel : panelList) { + if (ToolUtil.isNotEmpty(visualPanel.getParam())) + visualPanel.setParam(JSONObject.parseObject(String.valueOf(visualPanel.getParam()), Map.class)); + } + } + + // 查询当前panel下的chart数量并且进行赋值 // Map<Integer, Integer> chartNums = visualChartService.queryChartNum(); // for(VisualPanel visualPanel : panelList) { // Integer chartNum = ObjectUtil.isEmpty(chartNums.get(visualPanel.getId()))?0:chartNums.get(visualPanel.getId()); // visualPanel.setChartNum(chartNum); // } - return panelList; - } - - /** - * 递归获取树结构 - * - * @param panelList - * @param parentId - * @return - */ - private List<VisualPanel> getVisualPanelTreeList(List<VisualPanel> panelList, Integer parentId) { - List<VisualPanel> resultList = new ArrayList<>(); - for (VisualPanel panel : panelList) { - if(ToolUtil.isNotEmpty(panel.getParam()) && panel.getParam() instanceof String) - panel.setParam(JSONObject.parseObject(String.valueOf(panel.getParam()), Map.class)); - Integer id = panel.getId(); - Integer pid = panel.getPid(); - if (parentId.equals(pid)) { - panel.setChildren(this.getVisualPanelTreeList(panelList, id)); - resultList.add(panel); - } - } - return resultList; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void delPanelsAndChartInfoByPanelIds(Set<Integer> panelIds) { - if (CollectionUtils.isNotEmpty(panelIds)) { - // 删除 panel - this.removeByIds(panelIds); - - // 删除 chart info - Integer[] removePanelIds = panelIds.stream().toArray(n -> new Integer[n]); - visualChartService.delVisualChartsByPanelId(removePanelIds); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void delPanels(Integer... ids) { - if (ToolUtil.isEmpty(ids)) { - return; - } - - List<VisualPanel> panels = this.list(); - - // 1. 校验内置panel不能被删除 - this.validateBuildInPanels(panels, ids); - - // 获取这些节点的所有子节点 - List<Integer> idList = Arrays.stream(ids).collect(Collectors.toList()); - List<VisualPanel> panelList = this.list(); - Set<Integer> allPanelIds = new HashSet<>(); - for (Integer id : idList) { - allPanelIds.add(id); - allPanelIds.addAll(this.getChildrenIds(panelList, id)); - } - - // 2. 删除 panel ,如果包含子节点,也一并删除 - this.removeByIds(allPanelIds); - - //删除对应的收藏记录 - starredService.remove(new LambdaQueryWrapper<SysUserStarredEntity>().eq(SysUserStarredEntity::getType,"panel").in(SysUserStarredEntity::getTid,allPanelIds)); - - // 3. 删除关联的 chart chartElement - Integer[] removePanelIds = allPanelIds.stream().toArray(n -> new Integer[n]); - visualChartService.delVisualChartsByPanelId(removePanelIds); - - try { - // 删除 Report job - for (Integer panelId : allPanelIds) { - reportJobManager.delJobByName(panelId.toString()); - } - } catch (SchedulerException e) { - log.error("Delete dashboard report job error", e); - } - } - - /** - * 查询所有子节点 ID - * @param panelList - * @param parentId - * @return - */ - private List<Integer> getChildrenIds(List<VisualPanel> panelList, Integer parentId) { - List<Integer> resultList = new ArrayList<>(); - for (VisualPanel panel : panelList) { - Integer id = panel.getId(); - Integer pid = panel.getPid(); - if (parentId.equals(pid)) { - resultList.add(id); - resultList.addAll(this.getChildrenIds(panelList, id)); - } - } - return resultList; - } - - /** - * 处理删除后的位置 - * @param sequentialPanelList 删除之前有序的链表 - * @param deleteIds 删除的 IDS - */ - @Override - public void handlePositionAfterDelete(List<VisualPanel> sequentialPanelList, List<Integer> deleteIds) { - // 1. 全删除了 - if (sequentialPanelList.size() == deleteIds.size()) { - return; - } - - // 2. 删除之后的剩余元素 有序 - List<VisualPanel> deletedPanelList = new ArrayList<>(); - for (VisualPanel obj : sequentialPanelList) { - if (!deleteIds.contains(obj.getId())) { - deletedPanelList.add(obj); - } - } - - // 开头 panel - VisualPanel firstPanel = deletedPanelList.get(0); - - // 剩余一个 - if (deletedPanelList.size() == 1) { - this.updateById(firstPanel); - } else { - // 剩余数量大于 1 - List<VisualPanel> updatePanels = new ArrayList<>(); - - // 批量更新 - VisualPanel tempPanel = null; - int size = deletedPanelList.size(); - for (int i = 0; i < size; i++) { - if (i == 0) { - updatePanels.add(firstPanel); - } else { - tempPanel = deletedPanelList.get(i); - updatePanels.add(tempPanel); - } - } - this.saveOrUpdateBatch(updatePanels); - } - } - - /** - * 校验内置 panel 不可删除 - * @param panels - * @param removeIds - */ - private void validateBuildInPanels(List<VisualPanel> panels, Integer... removeIds) { - // 内置 panel 不能删除 - List<Integer> buildInPanels = panels.stream().filter(panel -> panel.getBuildIn() == 1).map(VisualPanel::getId).collect(Collectors.toList()); - List<Integer> removeIdList = Arrays.stream(removeIds).collect(Collectors.toList()); - removeIdList.retainAll(buildInPanels); - if (CollectionUtils.isNotEmpty(removeIdList)) { - List<String> panelNames = this.listByIds(removeIdList).stream().map(VisualPanel::getName).collect(Collectors.toList()); - throw new NZException("These panel is built-in and cannot be deleted, panels info: " + panelNames.toString(), RCode.PANEL_BUILDIN_CAN_NOT_REMOVE.getCode()); - } - } - - /** - * 校验 panel 相关参数是否正确 - * - * @param panel - */ - public void validatePanel(VisualPanel panel) { - String name = panel.getName(); - ValidateUtils.is(name).notNull(RCode.PANEL_NAME_ISNULL); - - if (name.contains("/")) { - throw new NZException(RCode.PANEL_NAME_FORMAT_ERROR); - } - - Integer pid = panel.getPid(); - pid = (pid == null) ? 0 : pid; - // 校验name是否重复 - List<VisualPanel> list = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getPid, pid).eq(VisualPanel::getName, panel.getName())); - boolean flag = false; - //当只有一个结果并且这个结果是自身时,或没有结果时,说明名称不重复 - if ((list == null || list.size() == 0) || (list != null && list.size() == 1 && list.get(0).getId().equals(panel.getId()))) { - flag = true; - } - - if (!flag) { - throw new NZException(RCode.PANEL_NAME_DUPLICATE); - } - - // link 不为空时 - if (ToolUtil.isNotEmpty(panel.getLink())) { - // 校验 type - String type = panel.getType(); - ValidateUtils.is(type).notNull(RCode.PANEL_TYPE_ISNULL); - List<Constant.PanelType> panelTypes = Arrays.asList(Constant.PanelType.values()); - List<String> types = panelTypes.stream().map(Constant.PanelType::getValue).collect(Collectors.toList()); - if (!types.contains(type)) { - throw new NZException(RCode.PANEL_TYPE_INVALIDE); - } - } - - // pid 是否存在 - if (panel.getPid() != null && panel.getPid() != 0) { - VisualPanel entity = this.getById(panel.getPid()); - if (entity == null) { - throw new NZException(RCode.PANEL_NOT_EXIST); - } - } - - // panel param 校验 - if(ToolUtil.isNotEmpty(panel.getParam())){ - Map param = JSONObject.parseObject(JSONObject.toJSONString(panel.getParam()), Map.class); - if(ToolUtil.isNotEmpty(param.get("report"))){ - Map report = JSONObject.parseObject(JSONObject.toJSONString(param.get("report")), Map.class); - // enable 为 true 时 - if(ToolUtil.isNotEmpty(report.get("enable")) && ToolUtil.equals("true", report.get("enable").toString())){ - ValidateUtils.is(report.get("range")).notNull(RCode.PANEL_PARAM_REPORTRANGE_ISNULL) - .and(report.get("schedule")).notNull(RCode.PANEL_PARAM_REPORTSCHEDULE_ISNULL) - .and(report.get("receivers")).notNull(RCode.PANEL_PARAM_REPORTRECEIVERS_ISNULL); - Map range = JSONObject.parseObject(JSONObject.toJSONString(report.get("range")), Map.class); - ValidateUtils.is(range.get("type")).notNull(RCode.PANEL_PARAM_RANGETYPE_ISNULL) - .and(range.get("interval")).notNull(RCode.PANEL_PARAM_RANGEINTERVAL_ISNULL) - .and(range.get("unit")).notNull(RCode.PANEL_PARAM_RANGEUNIT_ISNULL); - if(!Arrays.asList(new String[]{"previous", "last"}).contains(range.get("type"))){ - throw new NZException(RCode.PANEL_PARAM_RANGETYPE_INVALIDE); - }else if(!Arrays.asList(new String[]{"hour", "day", "week", "month"}).contains(range.get("unit"))){ - throw new NZException(RCode.PANEL_PARAM_RANGEUNIT_INVALIDE); - } - Map schedule = JSONObject.parseObject(JSONObject.toJSONString(report.get("schedule")), Map.class); - ValidateUtils.is(schedule.get("type")).notNull(RCode.PANEL_PARAM_SCHEDULETYPE_ISNULL) - .and(schedule.get("stime")).notNull(RCode.PANEL_PARAM_SCHEDULESTIME_ISNULL); - if(!Arrays.asList(new Integer[]{1, 2, 3, 4}).contains(schedule.get("type"))){ - throw new NZException(RCode.PANEL_PARAM_SCHEDULETYPE_INVALIDE); - } - if(ToolUtil.equals(schedule.get("type").toString(),"2")) { - ValidateUtils.is(schedule.get("repeat")).notNull(RCode.PANEL_PARAM_SCHEDULEREPEAT_ISNULL); - }else if(ToolUtil.equals(schedule.get("type").toString(),"3")){ - ValidateUtils.is(schedule.get("repeat")).notNull(RCode.PANEL_PARAM_SCHEDULEREPEAT_ISNULL) - .and(schedule.get("nums")).notNull(RCode.PANEL_PARAM_SCHEDULENUMS_ISNULL); - if(!Arrays.asList(new Integer[]{1, 2, 3, 4, 5, 6, 7}).containsAll(JSONArray.parseObject(JSONObject.toJSONString(schedule.get("nums")), List.class))){ - throw new NZException(RCode.PANEL_PARAM_SCHEDULENUMS_INVALIDE); - } - }else if(ToolUtil.equals(schedule.get("type").toString(),"4")){ - ValidateUtils.is(schedule.get("nums")).notNull(RCode.PANEL_PARAM_SCHEDULENUMS_ISNULL); - List<Integer> monthlyList = new ArrayList<>(); - for (int i = 1; i < 32; i++) { - monthlyList.add(i); - } - monthlyList.add(-1); - if(!monthlyList.containsAll(JSONArray.parseObject(JSONObject.toJSONString(schedule.get("nums")), List.class))){ - throw new NZException(RCode.PANEL_PARAM_SCHEDULENUMS_INVALIDE); - } - } - }else{ - if(ToolUtil.isEmpty(report.get("enable"))){ - report.put("enable", false); - param.put("report", report); - } - } - } - if(ToolUtil.isNotEmpty(param.get("chartShare"))){ - if(!Arrays.asList(new String[]{"none", "crosshair", "tooltip"}).contains(param.get("chartShare"))){ - throw new NZException(RCode.PANEL_PARAM_REPORTCHARTSHARE_INVALIDE); - } - }else{ - param.put("chartShare","none"); - } - panel.setParam(JSONObject.toJSONString(param)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void saveVisualPanel(VisualPanel panel) { - this.validatePanel(panel); - - Long userId = ShiroUtils.getUserId(); - panel.setCreateBy(userId.intValue()); - - if (ToolUtil.isEmpty(panel.getLink())) { - panel.setType(Constant.PanelType.DASHBOARD.getValue()); - } - panel.setUts(System.currentTimeMillis()); - String reportEnable = null; - if (ToolUtil.isNotEmpty(panel.getParam())) { - reportEnable = JSONPath.read(panel.getParam().toString(), "report.enable").toString(); - panel.setParam(String.valueOf(panel.getParam())); - } - - Integer pid = panel.getPid(); - pid = (pid == null) ? 0 : pid; - // 查询该父级节点下是否存在 Panel 节点 - List<VisualPanel> list = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, panel.getType()).eq(VisualPanel::getPid, pid)); - if (CollectionUtils.isEmpty(list)) { - // 父级节点下暂无其他节点,直接保存 - this.save(panel); - } else { - // 找到当前末尾的 panel , 加到其后 - VisualPanel endPanel = list.stream().max(Comparator.comparingInt(VisualPanel::getWeight)).get(); - Integer weight = endPanel.getWeight(); - panel.setWeight(++weight); - this.save(panel); - } - - // publish report config when reportEnable is true - if (Tool.StrUtil.equalsIgnoreCase("true", StrUtil.nullToDefault(reportEnable, "false"))) { - Map publishMap = new HashMap(4); - publishMap.put("panelId", panel.getId()); - publishMap.putAll(JSONObject.parseObject(panel.getParam().toString(), Map.class)); - - redisTemplate.convertAndSend(Constant.REPORT_TOPIC_NAME, JSONObject.toJSONString(publishMap)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateVisualPanel(VisualPanel panel) { - this.validatePanel(panel); - - VisualPanel oldPanel = this.getById(panel.getId()); - - if (oldPanel == null) { - throw new NZException(RCode.PANEL_NOT_EXIST); - } - panel.setUts(System.currentTimeMillis()); - if (ToolUtil.isNotEmpty(panel.getParam())) - panel.setParam(String.valueOf(panel.getParam())); - - // 改变 pid 父级节点时,将该 panel 加入到该 pid 下末尾位置 - if (!oldPanel.getPid().equals(panel.getPid())) { - VisualPanel endPanel = this.getOne(new LambdaQueryWrapper<VisualPanel>().eq(VisualPanel::getPid, panel.getPid()).orderByDesc(VisualPanel::getWeight).last("limit 0,1")); - // 该 pid 下存在节点 - if (endPanel != null) { - Integer weight = endPanel.getWeight(); - panel.setWeight(++weight); - } else { - panel.setWeight(0); - } - } - - // 修改 - this.updateById(panel); - - // report - String oldParamStr = ToolUtil.isEmpty(oldPanel.getParam()) ? JSONObject.toJSONString(Tool.MapUtil.empty()) : oldPanel.getParam().toString(); - Map oldParamMap = JSONObject.parseObject(oldParamStr, LinkedHashMap.class); - String newParamStr = ToolUtil.isEmpty(panel.getParam()) ? JSONObject.toJSONString(Tool.MapUtil.empty()) : panel.getParam().toString(); - Map newParamMap = JSONObject.parseObject(newParamStr, LinkedHashMap.class); - if (!oldParamMap.equals(newParamMap)) { - Map publishMap = new HashMap(4); - publishMap.put("panelId", panel.getId()); - publishMap.putAll(newParamMap); - - redisTemplate.convertAndSend(Constant.REPORT_TOPIC_NAME, JSONObject.toJSONString(publishMap)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void modify(List<VisualPanel> panelList) { - if (CollectionUtils.isEmpty(panelList)) throw new NZException(RCode.PANEL_ID_ISNULL); - for (VisualPanel panel : panelList) { - if (panel.getId() == null) throw new NZException(RCode.PANEL_ID_ISNULL); - if (panel.getPid() == null) throw new NZException(RCode.PANEL_PID_ISNULL); - if (panel.getWeight() == null) throw new NZException(RCode.PANEL_WEIGHT_ISNULL); - } - - this.getBaseMapper().updateWeightBatch(panelList); - } - - @Override - public List<VisualPanel> getSequentialPanelList(List<VisualPanel> panels) { - if (CollectionUtils.isEmpty(panels)) { - return new ArrayList<>(); - } - List<VisualPanel> resultList = new ArrayList<>(); - - // 按照prev升序排序 + return panelList; + } + + /** + * 递归获取树结构 + * + * @param panelList + * @param parentId + * @return + */ + private List<VisualPanel> getVisualPanelTreeList(List<VisualPanel> panelList, Integer parentId) { + List<VisualPanel> resultList = new ArrayList<>(); + for (VisualPanel panel : panelList) { + if (ToolUtil.isNotEmpty(panel.getParam()) && panel.getParam() instanceof String) + panel.setParam(JSONObject.parseObject(String.valueOf(panel.getParam()), Map.class)); + Integer id = panel.getId(); + Integer pid = panel.getPid(); + if (parentId.equals(pid)) { + panel.setChildren(this.getVisualPanelTreeList(panelList, id)); + resultList.add(panel); + } + } + return resultList; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delPanelsAndChartInfoByPanelIds(Set<Integer> panelIds) { + if (CollectionUtils.isNotEmpty(panelIds)) { + // 删除 panel + this.removeByIds(panelIds); + + // 删除 chart info + Integer[] removePanelIds = panelIds.stream().toArray(n -> new Integer[n]); + visualChartService.delVisualChartsByPanelId(removePanelIds); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delPanels(Integer... ids) { + if (ToolUtil.isEmpty(ids)) { + return; + } + + List<VisualPanel> panels = this.list(); + + // 1. 校验内置panel不能被删除 + this.validateBuildInPanels(panels, ids); + + // 获取这些节点的所有子节点 + List<Integer> idList = Arrays.stream(ids).collect(Collectors.toList()); + List<VisualPanel> panelList = this.list(); + Set<Integer> allPanelIds = new HashSet<>(); + for (Integer id : idList) { + allPanelIds.add(id); + allPanelIds.addAll(this.getChildrenIds(panelList, id)); + } + + // 2. 删除 panel ,如果包含子节点,也一并删除 + this.removeByIds(allPanelIds); + + // 删除对应的收藏记录 + starredService.remove(new LambdaQueryWrapper<SysUserStarredEntity>().eq(SysUserStarredEntity::getType, "panel") + .in(SysUserStarredEntity::getTid, allPanelIds)); + + // 3. 删除关联的 chart chartElement + Integer[] removePanelIds = allPanelIds.stream().toArray(n -> new Integer[n]); + visualChartService.delVisualChartsByPanelId(removePanelIds); + + try { + // 删除 Report job + for (Integer panelId : allPanelIds) { + reportJobManager.delJobByName(panelId.toString()); + } + } catch (SchedulerException e) { + log.error("Delete dashboard report job error", e); + } + } + + /** + * 查询所有子节点 ID + * + * @param panelList + * @param parentId + * @return + */ + private List<Integer> getChildrenIds(List<VisualPanel> panelList, Integer parentId) { + List<Integer> resultList = new ArrayList<>(); + for (VisualPanel panel : panelList) { + Integer id = panel.getId(); + Integer pid = panel.getPid(); + if (parentId.equals(pid)) { + resultList.add(id); + resultList.addAll(this.getChildrenIds(panelList, id)); + } + } + return resultList; + } + + /** + * 处理删除后的位置 + * + * @param sequentialPanelList 删除之前有序的链表 + * @param deleteIds 删除的 IDS + */ + @Override + public void handlePositionAfterDelete(List<VisualPanel> sequentialPanelList, List<Integer> deleteIds) { + // 1. 全删除了 + if (sequentialPanelList.size() == deleteIds.size()) { + return; + } + + // 2. 删除之后的剩余元素 有序 + List<VisualPanel> deletedPanelList = new ArrayList<>(); + for (VisualPanel obj : sequentialPanelList) { + if (!deleteIds.contains(obj.getId())) { + deletedPanelList.add(obj); + } + } + + // 开头 panel + VisualPanel firstPanel = deletedPanelList.get(0); + + // 剩余一个 + if (deletedPanelList.size() == 1) { + this.updateById(firstPanel); + } else { + // 剩余数量大于 1 + List<VisualPanel> updatePanels = new ArrayList<>(); + + // 批量更新 + VisualPanel tempPanel = null; + int size = deletedPanelList.size(); + for (int i = 0; i < size; i++) { + if (i == 0) { + updatePanels.add(firstPanel); + } else { + tempPanel = deletedPanelList.get(i); + updatePanels.add(tempPanel); + } + } + this.saveOrUpdateBatch(updatePanels); + } + } + + /** + * 校验内置 panel 不可删除 + * + * @param panels + * @param removeIds + */ + private void validateBuildInPanels(List<VisualPanel> panels, Integer... removeIds) { + // 内置 panel 不能删除 + List<Integer> buildInPanels = panels.stream().filter(panel -> panel.getBuildIn() == 1).map(VisualPanel::getId) + .collect(Collectors.toList()); + List<Integer> removeIdList = Arrays.stream(removeIds).collect(Collectors.toList()); + removeIdList.retainAll(buildInPanels); + if (CollectionUtils.isNotEmpty(removeIdList)) { + List<String> panelNames = this.listByIds(removeIdList).stream().map(VisualPanel::getName) + .collect(Collectors.toList()); + throw new NZException( + "These panel is built-in and cannot be deleted, panels info: " + panelNames.toString(), + RCode.PANEL_BUILDIN_CAN_NOT_REMOVE.getCode()); + } + } + + /** + * 校验 panel 相关参数是否正确 + * + * @param panel + */ + public void validatePanel(VisualPanel panel) { + String name = panel.getName(); + ValidateUtils.is(name).notNull(RCode.PANEL_NAME_ISNULL); + + if (name.contains("/")) { + throw new NZException(RCode.PANEL_NAME_FORMAT_ERROR); + } + + Integer pid = panel.getPid(); + pid = (pid == null) ? 0 : pid; + // 校验name是否重复 + List<VisualPanel> list = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getPid, pid) + .eq(VisualPanel::getName, panel.getName())); + boolean flag = false; + // 当只有一个结果并且这个结果是自身时,或没有结果时,说明名称不重复 + if ((list == null || list.size() == 0) + || (list != null && list.size() == 1 && list.get(0).getId().equals(panel.getId()))) { + flag = true; + } + + if (!flag) { + throw new NZException(RCode.PANEL_NAME_DUPLICATE); + } + + // link 不为空时 + if (ToolUtil.isNotEmpty(panel.getLink())) { + // 校验 type + String type = panel.getType(); + ValidateUtils.is(type).notNull(RCode.PANEL_TYPE_ISNULL); + List<Constant.PanelType> panelTypes = Arrays.asList(Constant.PanelType.values()); + List<String> types = panelTypes.stream().map(Constant.PanelType::getValue).collect(Collectors.toList()); + if (!types.contains(type)) { + throw new NZException(RCode.PANEL_TYPE_INVALIDE); + } + } + + // pid 是否存在 + if (panel.getPid() != null && panel.getPid() != 0) { + VisualPanel entity = this.getById(panel.getPid()); + if (entity == null) { + throw new NZException(RCode.PANEL_NOT_EXIST); + } + } + + // panel param 校验 + if (ToolUtil.isNotEmpty(panel.getParam())) { + Map param = JSONObject.parseObject(JSONObject.toJSONString(panel.getParam()), Map.class); + if (ToolUtil.isNotEmpty(param.get("report"))) { + Map report = JSONObject.parseObject(JSONObject.toJSONString(param.get("report")), Map.class); + // enable 为 true 时 + if (ToolUtil.isNotEmpty(report.get("enable")) + && ToolUtil.equals("true", report.get("enable").toString())) { + ValidateUtils.is(report.get("range")).notNull(RCode.PANEL_PARAM_REPORTRANGE_ISNULL) + .and(report.get("schedule")).notNull(RCode.PANEL_PARAM_REPORTSCHEDULE_ISNULL) + .and(report.get("receivers")).notNull(RCode.PANEL_PARAM_REPORTRECEIVERS_ISNULL); + Map range = JSONObject.parseObject(JSONObject.toJSONString(report.get("range")), Map.class); + ValidateUtils.is(range.get("type")).notNull(RCode.PANEL_PARAM_RANGETYPE_ISNULL) + .and(range.get("interval")).notNull(RCode.PANEL_PARAM_RANGEINTERVAL_ISNULL) + .and(range.get("unit")).notNull(RCode.PANEL_PARAM_RANGEUNIT_ISNULL); + if (!Arrays.asList(new String[] { "previous", "last" }).contains(range.get("type"))) { + throw new NZException(RCode.PANEL_PARAM_RANGETYPE_INVALIDE); + } else if (!Arrays.asList(new String[] { "hour", "day", "week", "month" }) + .contains(range.get("unit"))) { + throw new NZException(RCode.PANEL_PARAM_RANGEUNIT_INVALIDE); + } + Map schedule = JSONObject.parseObject(JSONObject.toJSONString(report.get("schedule")), Map.class); + ValidateUtils.is(schedule.get("type")).notNull(RCode.PANEL_PARAM_SCHEDULETYPE_ISNULL) + .and(schedule.get("stime")).notNull(RCode.PANEL_PARAM_SCHEDULESTIME_ISNULL); + if (!Arrays.asList(new Integer[] { 1, 2, 3, 4 }).contains(schedule.get("type"))) { + throw new NZException(RCode.PANEL_PARAM_SCHEDULETYPE_INVALIDE); + } + if (ToolUtil.equals(schedule.get("type").toString(), "2")) { + ValidateUtils.is(schedule.get("repeat")).notNull(RCode.PANEL_PARAM_SCHEDULEREPEAT_ISNULL); + } else if (ToolUtil.equals(schedule.get("type").toString(), "3")) { + ValidateUtils.is(schedule.get("repeat")).notNull(RCode.PANEL_PARAM_SCHEDULEREPEAT_ISNULL) + .and(schedule.get("nums")).notNull(RCode.PANEL_PARAM_SCHEDULENUMS_ISNULL); + if (!Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7 }).containsAll( + JSONArray.parseObject(JSONObject.toJSONString(schedule.get("nums")), List.class))) { + throw new NZException(RCode.PANEL_PARAM_SCHEDULENUMS_INVALIDE); + } + } else if (ToolUtil.equals(schedule.get("type").toString(), "4")) { + ValidateUtils.is(schedule.get("nums")).notNull(RCode.PANEL_PARAM_SCHEDULENUMS_ISNULL); + List<Integer> monthlyList = new ArrayList<>(); + for (int i = 1; i < 32; i++) { + monthlyList.add(i); + } + monthlyList.add(-1); + if (!monthlyList.containsAll( + JSONArray.parseObject(JSONObject.toJSONString(schedule.get("nums")), List.class))) { + throw new NZException(RCode.PANEL_PARAM_SCHEDULENUMS_INVALIDE); + } + } + } else { + if (ToolUtil.isEmpty(report.get("enable"))) { + report.put("enable", false); + param.put("report", report); + } + } + } + if (ToolUtil.isNotEmpty(param.get("chartShare"))) { + if (!Arrays.asList(new String[] { "none", "crosshair", "tooltip" }).contains(param.get("chartShare"))) { + throw new NZException(RCode.PANEL_PARAM_REPORTCHARTSHARE_INVALIDE); + } + } else { + param.put("chartShare", "none"); + } + panel.setParam(JSONObject.toJSONString(param)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveVisualPanel(VisualPanel panel) { + this.validatePanel(panel); + + Long userId = ShiroUtils.getUserId(); + panel.setCreateBy(userId.intValue()); + + if (ToolUtil.isEmpty(panel.getLink())) { + panel.setType(Constant.PanelType.DASHBOARD.getValue()); + } + panel.setUts(System.currentTimeMillis()); + String reportEnable = null; + if (ToolUtil.isNotEmpty(panel.getParam())) { + reportEnable = JSONPath.read(panel.getParam().toString(), "report.enable").toString(); + panel.setParam(String.valueOf(panel.getParam())); + } + + Integer pid = panel.getPid(); + pid = (pid == null) ? 0 : pid; + // 查询该父级节点下是否存在 Panel 节点 + List<VisualPanel> list = this.list(new QueryWrapper<VisualPanel>().lambda() + .eq(VisualPanel::getType, panel.getType()).eq(VisualPanel::getPid, pid)); + if (CollectionUtils.isEmpty(list)) { + // 父级节点下暂无其他节点,直接保存 + this.save(panel); + } else { + // 找到当前末尾的 panel , 加到其后 + VisualPanel endPanel = list.stream().max(Comparator.comparingInt(VisualPanel::getWeight)).get(); + Integer weight = endPanel.getWeight(); + panel.setWeight(++weight); + this.save(panel); + } + + // publish report config when reportEnable is true + if (Tool.StrUtil.equalsIgnoreCase("true", StrUtil.nullToDefault(reportEnable, "false"))) { + Map publishMap = new HashMap(4); + publishMap.put("panelId", panel.getId()); + publishMap.putAll(JSONObject.parseObject(panel.getParam().toString(), Map.class)); + + redisTemplate.convertAndSend(Constant.REPORT_TOPIC_NAME, JSONObject.toJSONString(publishMap)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateVisualPanel(VisualPanel panel) { + this.validatePanel(panel); + + VisualPanel oldPanel = this.getById(panel.getId()); + + if (oldPanel == null) { + throw new NZException(RCode.PANEL_NOT_EXIST); + } + panel.setUts(System.currentTimeMillis()); + if (ToolUtil.isNotEmpty(panel.getParam())) + panel.setParam(String.valueOf(panel.getParam())); + + // 改变 pid 父级节点时,将该 panel 加入到该 pid 下末尾位置 + if (!oldPanel.getPid().equals(panel.getPid())) { + VisualPanel endPanel = this.getOne(new LambdaQueryWrapper<VisualPanel>() + .eq(VisualPanel::getPid, panel.getPid()).orderByDesc(VisualPanel::getWeight).last("limit 0,1")); + // 该 pid 下存在节点 + if (endPanel != null) { + Integer weight = endPanel.getWeight(); + panel.setWeight(++weight); + } else { + panel.setWeight(0); + } + } + + // 修改 + this.updateById(panel); + + // report + String oldParamStr = ToolUtil.isEmpty(oldPanel.getParam()) ? JSONObject.toJSONString(Tool.MapUtil.empty()) + : oldPanel.getParam().toString(); + Map oldParamMap = JSONObject.parseObject(oldParamStr, LinkedHashMap.class); + String newParamStr = ToolUtil.isEmpty(panel.getParam()) ? JSONObject.toJSONString(Tool.MapUtil.empty()) + : panel.getParam().toString(); + Map newParamMap = JSONObject.parseObject(newParamStr, LinkedHashMap.class); + if (!oldParamMap.equals(newParamMap)) { + Map publishMap = new HashMap(4); + publishMap.put("panelId", panel.getId()); + publishMap.putAll(newParamMap); + + redisTemplate.convertAndSend(Constant.REPORT_TOPIC_NAME, JSONObject.toJSONString(publishMap)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void modify(List<VisualPanel> panelList) { + if (CollectionUtils.isEmpty(panelList)) + throw new NZException(RCode.PANEL_ID_ISNULL); + for (VisualPanel panel : panelList) { + if (panel.getId() == null) + throw new NZException(RCode.PANEL_ID_ISNULL); + if (panel.getPid() == null) + throw new NZException(RCode.PANEL_PID_ISNULL); + if (panel.getWeight() == null) + throw new NZException(RCode.PANEL_WEIGHT_ISNULL); + } + + this.getBaseMapper().updateWeightBatch(panelList); + } + + @Override + public List<VisualPanel> getSequentialPanelList(List<VisualPanel> panels) { + if (CollectionUtils.isEmpty(panels)) { + return new ArrayList<>(); + } + List<VisualPanel> resultList = new ArrayList<>(); + + // 按照prev升序排序 // panels = panels.stream().sorted(Comparator.comparing(VisualPanel::getPrev)).collect(Collectors.toList()); - Map<Integer, VisualPanel> idAndPanelMap = new HashMap<>(); - for (VisualPanel panel : panels) { - idAndPanelMap.put(panel.getId(), panel); - } + Map<Integer, VisualPanel> idAndPanelMap = new HashMap<>(); + for (VisualPanel panel : panels) { + idAndPanelMap.put(panel.getId(), panel); + } - VisualPanel firstPanel = panels.get(0); + VisualPanel firstPanel = panels.get(0); - VisualPanel tempPanel = firstPanel; - resultList.add(firstPanel); - VisualPanel nextPanel = null; + VisualPanel tempPanel = firstPanel; + resultList.add(firstPanel); + VisualPanel nextPanel = null; - while (true) { + while (true) { // nextPanel = idAndPanelMap.get(tempPanel.getNext()); - if (nextPanel != null) { - resultList.add(nextPanel); - tempPanel = nextPanel; - } else { - break; - } - } - return resultList; - } - - @Override - public void getTemplateByLanguage(HttpServletResponse response, String format, String type) throws IOException{ + if (nextPanel != null) { + resultList.add(nextPanel); + tempPanel = nextPanel; + } else { + break; + } + } + return resultList; + } + + @Override + public void getTemplateByLanguage(HttpServletResponse response, String format, String type) throws IOException { // 按类型获取表头模板信息 - String configKey = this.getChartTemplateConfigKeyByType(type); - String sysHeaderJsonStr = sysConfigService.getValue(configKey); - String fileName = "PanelChartTemplate"; - basicImportAndExportServices.getTemplate(sysHeaderJsonStr, format, fileName, response); + String configKey = this.getChartTemplateConfigKeyByType(type); + String sysHeaderJsonStr = sysConfigService.getValue(configKey); + String fileName = "PanelChartTemplate"; + basicImportAndExportServices.getTemplate(sysHeaderJsonStr, format, fileName, response); + } + + @Override + public Map importChartData(MultipartFile multipartFile, String type, Integer linkId, String language) + throws IOException { + String configKey = this.getChartTemplateConfigKeyByType(type); + String sysHeaderJsonStr = sysConfigService.getValue(configKey); + Map<String, String> exportHeaderMap = basicImportAndExportServices.getI18nHeaderMap(sysHeaderJsonStr); + List<Map<Integer, String>> importDataList = basicImportAndExportServices + .getImportDataFromMultipartFile(multipartFile, sysHeaderJsonStr); + + List<Map> failDetails = new ArrayList<>(); + String seqUUID = UUID.randomUUID().toString(); + type = StringUtils.isEmpty(type) ? Constant.PanelType.DASHBOARD.getValue() : type; + + SysConfigEntity i18nConfig = sysConfigService.getOne(new QueryWrapper<SysConfigEntity>().lambda() + .eq(SysConfigEntity::getParamKey, Constant.I18N_MAPPING).eq(SysConfigEntity::getStatus, 1)); + Map i18nConfigMap = JSONObject.parseObject(i18nConfig.getParamValue(), Map.class); + Map chartTypeMap = (Map) i18nConfigMap.get(Constant.DICT_CHART_TYPE); + Map chartTypeMapByLanguage = (Map) chartTypeMap.get(language); + if (ToolUtil.isEmpty(chartTypeMapByLanguage)) { + throw new NZException(RCode.EXCELFILE_HEADER_LANGUAGE_ERROR); + } + + ArrayList<String> headerInfos = new ArrayList<>(exportHeaderMap.keySet()); + int successNum = 0; + List<Map<Integer, String>> handleImportData = null; + if (StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(), type)) { + // 处理excel表数据 将group chart相关排在前列 + handleImportData = this.groupChartRowHandle(importDataList, 1); + successNum = this.saveDashboardChartData(handleImportData, failDetails, headerInfos, seqUUID, + chartTypeMapByLanguage); + } else { + handleImportData = this.groupChartRowHandle(importDataList, 0); + successNum = this.saveAssetEndpointChartData(handleImportData, failDetails, seqUUID, type, linkId, + chartTypeMapByLanguage, headerInfos); + } + int totalNum = ToolUtil.isNotEmpty(handleImportData) ? handleImportData.size() : 0; + + Map resultMap = new HashMap(8); + resultMap.put("seq", seqUUID); + resultMap.put("totalNum", totalNum); + resultMap.put("successNum", successNum); + resultMap.put("failNum", totalNum - successNum); + resultMap.put("failDetail", CommonUtils.handleImportFailDetails(failDetails)); + + return resultMap; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void duplicate(Integer id) { + VisualPanel panel = this.getById(id); + if (panel == null) { + throw new NZException(RCode.CHART_PANEL_ISNULL); + } + + panel.setName("copy from " + panel.getName()); + if (panel.getName().length() > 64) { + throw new NZException(RCode.PANEL_NAME_TOO_LONG); + } + Long userId = ShiroUtils.getUserId(); + panel.setCreateBy(userId.intValue()); + panel.setId(null); + panel.setUts(System.currentTimeMillis()); + String reportEnable = null; + if (ToolUtil.isNotEmpty(panel.getParam()) && ToolUtil.contains(panel.getParam(), "enable")) { + reportEnable = JSONPath.read(panel.getParam().toString(), "report.enable").toString(); + panel.setParam(String.valueOf(panel.getParam())); + } + + Integer pid = panel.getPid(); + // 查询该父级节点下是否存在 Panel 节点 + List<VisualPanel> list = this.list(new QueryWrapper<VisualPanel>().lambda() + .eq(VisualPanel::getType, panel.getType()).eq(VisualPanel::getPid, pid == null ? 0 : pid)); + // 找到当前末尾的 panel , 加到其后 + VisualPanel endPanel = list.stream().max(Comparator.comparingInt(VisualPanel::getWeight)).get(); + Integer weight = endPanel.getWeight(); + panel.setWeight(++weight); + this.save(panel); + + // publish report config when reportEnable is true + if (Tool.StrUtil.equalsIgnoreCase("true", StrUtil.nullToDefault(reportEnable, "false"))) { + Map publishMap = new HashMap(4); + publishMap.put("panelId", panel.getId()); + publishMap.putAll(JSONObject.parseObject(panel.getParam().toString(), Map.class)); + + redisTemplate.convertAndSend(Constant.REPORT_TOPIC_NAME, JSONObject.toJSONString(publishMap)); + } + + // 复制panel 下的 charts + List<VisualChart> chartsGroupList = visualChartService.list(new QueryWrapper<VisualChart>().lambda() + .eq(VisualChart::getPanelId, id).orderByAsc(VisualChart::getGroupId)); + Map<Integer, Integer> chartsGroupMap = new HashMap<>(); + Integer chartId; + if (!CollectionUtils.isEmpty(chartsGroupList)) { + for (VisualChart chart : chartsGroupList) { + chartId = chart.getId(); + chart.setId(null); + chart.setUpdateAt(new Date()); + chart.setUpdateBy(userId.intValue()); + chart.setPanelId(panel.getId()); + if (ToolUtil.equals(chart.getType(), "group")) { + visualChartService.save(chart); + chartsGroupMap.put(chartId, chart.getId()); + } else { + if (!ToolUtil.equals(chart.getGroupId(), 0)) + chart.setGroupId(chartsGroupMap.get(chart.getGroupId())); + visualChartService.save(chart); + } + // 查询当前chart下的chartElement + List<VisualChartElement> elementList = chartElementService.list( + new QueryWrapper<VisualChartElement>().lambda().eq(VisualChartElement::getChartId, chartId)); + if (!CollectionUtils.isEmpty(elementList)) { + for (VisualChartElement element : elementList) { + element.setId(null); + element.setChartId(chart.getId()); + } + chartElementService.saveOrUpdateElements(chart.getId(), elementList); + } + } + } + } + + @Override + public void snapshot(HttpServletResponse response, String format, Integer panelId, Long start, Long end, + String language, String vars) { + VisualPanel panel = this.getById(panelId); + if (panel == null) { + throw new NZException(RCode.CHART_PANEL_ISNULL); + } + + // 生成模板 + String snapshotStr = this.genSnapshotByTemplate(panel, start, end, language, vars); + + format = StrUtil.emptyToDefault(format, "html"); + try { + response.setCharacterEncoding("utf-8"); + response.setContentType("multipart/form-data"); + response.setHeader("Content-disposition", "attachment;filename=panel-" + panel.getName() + "." + format + + ";filename*=utf-8''" + URLEncoder.encode("panel-" + panel.getName() + "." + format, "UTF-8")); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.getOutputStream().write(snapshotStr.getBytes()); + } catch (IOException e) { + log.error(e); + } + } + + @Override + public String snapshot(String format, Integer panelId, Long start, Long end, String language, String vars) { + VisualPanel panel = this.getById(panelId); + if (panel == null) { + throw new NZException(RCode.CHART_PANEL_ISNULL); + } + + // 生成模板 + String snapshotStr = this.genSnapshotByTemplate(panel, start, end, language, vars); + return snapshotStr; + } + + private String genSnapshotByTemplate(VisualPanel panel, Long start, Long end, String language, String vars) { + // 计算步长 + String step = getTimeStep(start, end); + // 封装返回结果 + Map<String, Object> resultMap = new HashMap(); + resultMap.put("language", language); + resultMap.put("start", start); + resultMap.put("end", end); + resultMap.put("panel", R.ok(panel)); + // 查询系统时区信息 + String timezone = sysConfigService.getValue("timezone"); + Timezone timezoneEntity = timezoneService + .getOne(new LambdaUpdateWrapper<Timezone>().eq(Timezone::getName, timezone)); + resultMap.put("offset", timezoneEntity.getOffset()); + resultMap.put("timezone", timezone); + // charts 查询 + Map param = new HashMap<>(); + param.put("pageSize", "-1"); + param.put("panelId", panel.getId()); + param.put("groupId", 0); + PageUtils chartPageUtils = visualChartService.queryPage(param); + resultMap.put("charts", R.ok(chartPageUtils)); + List<VisualChart> chartsList = (List<VisualChart>) chartPageUtils.getList(); + if (Tool.CollUtil.isEmpty(chartsList)) { + throw new NZException(RCode.CHART_NOTEXSITS); + } else { + // 封装公共请求参数 + Map<String, String> basicQueryParam = new HashMap(); + basicQueryParam.put("start", StrUtil.toString(start)); + basicQueryParam.put("end", StrUtil.toString(end)); + basicQueryParam.put("step", step); + + List<Map> varList = StrUtil.isNotEmpty(vars) ? JSONObject.parseArray(vars, Map.class) + : Tool.ListUtil.empty(); + + // 将chartsData获取任务装入futureList + List<CompletableFuture<Map>> futureList = this.recursionChartsData(chartsList, basicQueryParam, varList); + try { + Map chartsDataMap = new HashMap(); + CompletableFuture.allOf((CompletableFuture<?>[]) futureList.toArray(new CompletableFuture[0])) + .get(timeout, TimeUnit.MILLISECONDS); + futureList.forEach(future -> { + Map<String, Object> result = future.getNow(null); + if (Tool.MapUtil.isNotEmpty(result)) { + if (Tool.MapUtil.isNotEmpty(result)) { // && + // Tool.StrUtil.equals("success",Tool.StrUtil.toString(result.get("status"))) + chartsDataMap.put(StrUtil.concat(true, StrUtil.toString(result.get("chartId")), "_", + StrUtil.toString(result.get("eleIndex"))), result); + } + } + }); + resultMap.put("chartsData", chartsDataMap); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + log.error(e); + } + } + // 读取模板,替换数据 + BufferedReader reader = null; + StringBuffer sbf = new StringBuffer(); + try { + String path = sysConfigDao.queryByKey("snapshot_template_path").getParamValue(); + reader = new BufferedReader( + new FileReader(Tool.StrUtil.concat(true, path, File.separator, "snapshot_template.html"))); + String line = null; + while ((line = reader.readLine()) != null) { + if (Tool.StrUtil.startWith(line, "<script>window.dataJson")) + line = "<script>window.dataJson=" + JSONUtil.toJsonStr(resultMap) + "</script>"; + sbf.append(line + "\n"); + } + } catch (IOException e) { + log.error(e); + } finally { + if (reader != null) + IoUtil.close(reader); + } + return sbf.toString(); + } + + /** + * 根据 vars 渲染 element 表达式 + * + * @param expr + * @param varList + */ + private String replaceExprByVars(String expr, List<Map> varList) { + if (Tool.CollectionUtil.isEmpty(varList)) + return expr; + // 将 expr $xxx 变量渲染 + for (Map<String, String> map : varList) { + String name = map.get("name"); + String value = map.get("value"); + expr = expr.replaceAll("\\$" + name, value); + } + return expr; + } + + private List<CompletableFuture<Map>> recursionChartsData(List<VisualChart> chartsList, + Map<String, String> basicQueryParam, List<Map> varList) { + List<CompletableFuture<Map>> futureList = new ArrayList<>(); + for (VisualChart chart : chartsList) { + String datasource = chart.getDatasource(); + if (StrUtil.equals("misc", datasource)) { + if (Tool.CollUtil.isNotEmpty(chart.getChildren())) { + List<CompletableFuture<Map>> callables = this.recursionChartsData(chart.getChildren(), + basicQueryParam, varList); + if (Tool.CollUtil.isNotEmpty(callables)) + futureList.addAll(callables); + } + continue; + } + Map<String, Object> chartParam = (HashMap) chart.getParam(); + if (StrUtil.equals("system", datasource)) { + CompletableFuture<Map> mapCompletableFuture = null; + if (StrUtil.equals("assetInfo", chart.getType())) { + mapCompletableFuture = CompletableFuture.supplyAsync(() -> { + VisualPanel visualPanel = this.getById(chart.getPanelId()); + R ok = R.ok(assetAssetService.queryAssetInfo(visualPanel.getLink())); + ok.put("status", "success"); + ok.put("eleIndex", "0"); + ok.put("chartId", chart.getId()); + return ok; + }, this.getSnapshotThreadPool()); + } else if (StrUtil.equals("endpointInfo", chart.getType())) { + mapCompletableFuture = CompletableFuture.supplyAsync(() -> { + VisualPanel visualPanel = this.getById(chart.getPanelId()); + R ok = R.ok(monitorEndpointService.queryEndpointEntity(visualPanel.getLink())); + ok.put("status", "success"); + ok.put("eleIndex", "0"); + ok.put("chartId", chart.getId()); + return ok; + }, this.getSnapshotThreadPool()); + } else { + mapCompletableFuture = CompletableFuture.supplyAsync(() -> { + JSONObject dataSource = JSONArray + .parseArray(JSONObject.toJSONString(chartParam.get("datasource"))).getJSONObject(0); + JSONArray selectAry = new JSONArray(); + selectAry.add(dataSource.get("select")); + dataSource.put("select", selectAry); + HashMap analyseMap = new HashMap(); + analyseMap.put("q", dataSource.toJSONString()); + Map resultMap = new HashMap<>(); + resultMap.put("status", "success"); + resultMap.put("eleIndex", "0"); + resultMap.put("chartId", chart.getId()); + resultMap.putAll(statServiceImpl.queryAnalyse(analyseMap)); + return resultMap; + }, this.getSnapshotThreadPool()); + } + futureList.add(mapCompletableFuture); + } else { + Integer eleIndex = 0; + String start = basicQueryParam.get("start"); + String end = basicQueryParam.get("end"); + String step = basicQueryParam.get("step"); + + if (Tool.CollUtil.isNotEmpty(chart.getElements())) { + for (VisualChartElement element : chart.getElements()) { + String indexStr = StrUtil.toString(eleIndex++); + // 将表达式进行变量渲染 + String expr = this.replaceExprByVars(element.getExpression(), varList); + switch (datasource) { + case "metrics": + futureList.add(CompletableFuture.supplyAsync(() -> { + JSONObject jsonObject = null; + try { + jsonObject = promApiService.query_range(expr, start, end, step, + chartParam.get("nullType").toString(), null); + jsonObject.put("eleIndex", indexStr); + jsonObject.put("chartId", chart.getId()); + } catch (NZException e) { + log.error(e); + } + return jsonObject; + }, this.getSnapshotThreadPool())); + break; + case "logs": + String limit = chartParam.get("limit") == null ? "100" : chartParam.get("limit").toString(); + futureList.add(CompletableFuture.supplyAsync(() -> { + JSONObject jsonObject = null; + try { + jsonObject = lokiApiService.query_range(expr, start, end, limit, step, null, + "backward", "1", null); + jsonObject.put("eleIndex", indexStr); + jsonObject.put("chartId", chart.getId()); + } catch (NZException e) { + log.error(e); + } + return jsonObject; + }, this.getSnapshotThreadPool())); + break; + default: + break; + } + } + } else { + futureList.add(CompletableFuture.supplyAsync(() -> { + Map emptyElementsMap = Tool.MapUtil.newHashMap(); + emptyElementsMap.put("eleIndex", 0); + emptyElementsMap.put("chartId", chart.getId()); + return emptyElementsMap; + }, this.getSnapshotThreadPool())); + } + } + } + return futureList; + } + + /** + * 计算Dashboards step + */ + public String getTimeStep(Long start, Long end) { + Long timeDiff = (end - start) / (24 * 60 * 60); + if (timeDiff < 1) { + return "15s"; + } else if (timeDiff < 7) { + return "5m"; + } else if (timeDiff < 30) { + return "10m"; + } else { + return "30m"; + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelImport(String seq) { + List<VisualPanel> panelList = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, + Constant.PanelType.DASHBOARD.getValue())); + List<Integer> delPanelIds = panelList.stream().filter(panel -> seq.equals(panel.getSeq())) + .map(VisualPanel::getId).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(delPanelIds)) { + // 删除 panel + this.remove(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getSeq, seq)); + } + + List<VisualChart> delCharts = visualChartService + .list(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getSeq, seq)); + if (CollectionUtils.isNotEmpty(delCharts)) { + // 删除 charts + visualChartService.remove(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getSeq, seq)); + } + chartElementService.remove(new QueryWrapper<VisualChartElement>().lambda().eq(VisualChartElement::getSeq, seq)); + } + + @Override + public void export(HttpServletResponse response, Map<String, Object> params) throws IOException { + String maxLine = sysConfigService.getValue(Constant.SYSCONFIG_KEY_EXPORT_MAX_LINE); + long exportMaxLine = Integer.parseInt(StrUtil.emptyToDefault(maxLine, "10000")); + // 导出最大条数限制 + Object limit = params.get(Constant.LIMIT) == null ? Constant.PAGESIZE : params.get(Constant.LIMIT); + Long pageSize = Long.parseLong(limit.toString()); + if (pageSize == -1) { + // 导出所有直接限制 pageSize + params.put(Constant.PAGE, "1"); + params.put(Constant.LIMIT, Long.toString(exportMaxLine)); + } else if (pageSize > exportMaxLine) { + // 分页超过最大限制 则设置最大限制为 系统配置值,和 pageSize == -1 判断区别在于 pageNo + params.put(Constant.LIMIT, Long.toString(exportMaxLine)); + } + // 导出查询与列表查询一致 + List<VisualChart> charts = this.exportDataByParams(params); + String type = Constant.PanelType.DASHBOARD.getValue(); + if (CollectionUtils.isNotEmpty(charts)) { + VisualChart chart = charts.stream().findFirst().get(); + VisualPanel panel = this.getById(chart.getPanelId()); + if (panel == null || !StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(), panel.getType())) { + type = Constant.PanelType.ASSET.getValue(); + } + } + String language = (String) params.get("language"); + + // 获取导出配置 key 名称 + String configKey = this.getChartTemplateConfigKeyByType(type); + String sysHeaderJsonStr = sysConfigService.getValue(configKey); + + String i18nConfigJsonStr = sysConfigService.getValue(Constant.I18N_MAPPING); + Map i18nConfigMap = JSONObject.parseObject(i18nConfigJsonStr, Map.class); + Map chartTypeMap = (Map) i18nConfigMap.get(Constant.DICT_CHART_TYPE); + Map chartTypeMapByLanguage = (Map) chartTypeMap.get(StrUtil.emptyToDefault(language, "en")); + + charts = charts.stream().sorted(Comparator.comparing(VisualChart::getGroupId)).collect(Collectors.toList()); + String fileName = "Charts"; + String formatStr = params.get("format").toString(); + + if (StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(), type)) { + List<List<String>> exportDataList = this.handleDashboardChartExportDataList(charts, chartTypeMapByLanguage); + basicImportAndExportServices.exportDataByFormat(response, exportDataList, sysHeaderJsonStr, formatStr, + fileName); + } else { + List<List<String>> exportDataList = this.handleAssetEndpointChartExportDataList(charts, + chartTypeMapByLanguage); + basicImportAndExportServices.exportDataByFormat(response, exportDataList, sysHeaderJsonStr, formatStr, + fileName); + } } - - @Override - public Map importChartData(MultipartFile multipartFile, String type, Integer linkId,String language) throws IOException { - String configKey = this.getChartTemplateConfigKeyByType(type); - String sysHeaderJsonStr = sysConfigService.getValue(configKey); - Map<String, String> exportHeaderMap = basicImportAndExportServices.getI18nHeaderMap(sysHeaderJsonStr); - List<Map<Integer, String>> importDataList = basicImportAndExportServices.getImportDataFromMultipartFile(multipartFile, sysHeaderJsonStr); - - List<Map> failDetails = new ArrayList<>(); - String seqUUID = UUID.randomUUID().toString(); - type = StringUtils.isEmpty(type) ? Constant.PanelType.DASHBOARD.getValue() : type; - - SysConfigEntity i18nConfig = sysConfigService.getOne(new QueryWrapper<SysConfigEntity>().lambda().eq(SysConfigEntity::getParamKey, Constant.I18N_MAPPING).eq(SysConfigEntity::getStatus, 1)); - Map i18nConfigMap = JSONObject.parseObject(i18nConfig.getParamValue(), Map.class); - Map chartTypeMap = (Map) i18nConfigMap.get(Constant.DICT_CHART_TYPE); - Map chartTypeMapByLanguage = (Map) chartTypeMap.get(language); - if (ToolUtil.isEmpty(chartTypeMapByLanguage)) { - throw new NZException(RCode.EXCELFILE_HEADER_LANGUAGE_ERROR); - } - - ArrayList<String> headerInfos = new ArrayList<>(exportHeaderMap.keySet()); - int successNum = 0; - List<Map<Integer, String>> handleImportData = null; - if(StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(),type)) { - // 处理excel表数据 将group chart相关排在前列 - handleImportData = this.groupChartRowHandle(importDataList, 1); - successNum = this.saveDashboardChartData(handleImportData, failDetails, headerInfos, seqUUID, chartTypeMapByLanguage); - } else { - handleImportData = this.groupChartRowHandle(importDataList, 0); - successNum = this.saveAssetEndpointChartData(handleImportData, failDetails, seqUUID, type, linkId, chartTypeMapByLanguage,headerInfos); - } - int totalNum = ToolUtil.isNotEmpty(handleImportData) ? handleImportData.size() : 0; - - Map resultMap = new HashMap(8); - resultMap.put("seq", seqUUID); - resultMap.put("totalNum", totalNum); - resultMap.put("successNum", successNum); - resultMap.put("failNum", totalNum - successNum); - resultMap.put("failDetail", CommonUtils.handleImportFailDetails(failDetails)); - - return resultMap; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void duplicate(Integer id) { - VisualPanel panel = this.getById(id); - if (panel == null) { - throw new NZException(RCode.CHART_PANEL_ISNULL); - } - - panel.setName("copy from " + panel.getName()); - if(panel.getName().length() > 64) { - throw new NZException(RCode.PANEL_NAME_TOO_LONG); - } - Long userId = ShiroUtils.getUserId(); - panel.setCreateBy(userId.intValue()); - panel.setId(null); - panel.setUts(System.currentTimeMillis()); - String reportEnable = null; - if (ToolUtil.isNotEmpty(panel.getParam()) && ToolUtil.contains(panel.getParam(), "enable")) { - reportEnable = JSONPath.read(panel.getParam().toString(), "report.enable").toString(); - panel.setParam(String.valueOf(panel.getParam())); - } - - Integer pid = panel.getPid(); - // 查询该父级节点下是否存在 Panel 节点 - List<VisualPanel> list = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, panel.getType()).eq(VisualPanel::getPid, pid == null ? 0 : pid)); - // 找到当前末尾的 panel , 加到其后 - VisualPanel endPanel = list.stream().max(Comparator.comparingInt(VisualPanel::getWeight)).get(); - Integer weight = endPanel.getWeight(); - panel.setWeight(++weight); - this.save(panel); - - // publish report config when reportEnable is true - if (Tool.StrUtil.equalsIgnoreCase("true", StrUtil.nullToDefault(reportEnable, "false"))) { - Map publishMap = new HashMap(4); - publishMap.put("panelId", panel.getId()); - publishMap.putAll(JSONObject.parseObject(panel.getParam().toString(), Map.class)); - - redisTemplate.convertAndSend(Constant.REPORT_TOPIC_NAME, JSONObject.toJSONString(publishMap)); - } - - // 复制panel 下的 charts - List<VisualChart> chartsGroupList = visualChartService.list(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getPanelId, id).orderByAsc(VisualChart::getGroupId)); - Map<Integer,Integer> chartsGroupMap = new HashMap<>(); - Integer chartId; - if (!CollectionUtils.isEmpty(chartsGroupList)) { - for (VisualChart chart:chartsGroupList) { - chartId = chart.getId(); - chart.setId(null); - chart.setUpdateAt(new Date()); - chart.setUpdateBy(userId.intValue()); - chart.setPanelId(panel.getId()); - if(ToolUtil.equals(chart.getType(),"group")){ - visualChartService.save(chart); - chartsGroupMap.put(chartId,chart.getId()); - }else{ - if(!ToolUtil.equals(chart.getGroupId(),0)) - chart.setGroupId(chartsGroupMap.get(chart.getGroupId())); - visualChartService.save(chart); - } - // 查询当前chart下的chartElement - List<VisualChartElement> elementList = chartElementService.list(new QueryWrapper<VisualChartElement>().lambda().eq(VisualChartElement::getChartId, chartId)); - if (!CollectionUtils.isEmpty(elementList)) { - for (VisualChartElement element:elementList) { - element.setId(null); - element.setChartId(chart.getId()); - } - chartElementService.saveOrUpdateElements(chart.getId(), elementList); - } - } - } - } - - @Override - public void snapshot(HttpServletResponse response, String format, Integer panelId, Long start, Long end, String language, String vars) { - VisualPanel panel = this.getById(panelId); - if (panel == null) { - throw new NZException(RCode.CHART_PANEL_ISNULL); - } - - // 生成模板 - String snapshotStr = this.genSnapshotByTemplate(panel, start, end, language, vars); - - format = StrUtil.emptyToDefault(format, "html"); - try { - response.setCharacterEncoding("utf-8"); - response.setContentType("multipart/form-data"); - response.setHeader("Content-disposition", "attachment;filename=panel-" + panel.getName() + "." + format + ";filename*=utf-8''" + URLEncoder.encode("panel-" + panel.getName() + "." + format, "UTF-8")); - response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); - response.getOutputStream().write(snapshotStr.getBytes()); - } catch (IOException e) { - log.error(e); - } - } - - @Override - public String snapshot(String format, Integer panelId, Long start, Long end, String language, String vars) { - VisualPanel panel = this.getById(panelId); - if (panel == null) { - throw new NZException(RCode.CHART_PANEL_ISNULL); - } - - // 生成模板 - String snapshotStr = this.genSnapshotByTemplate(panel, start, end, language, vars); - return snapshotStr; - } - - private String genSnapshotByTemplate(VisualPanel panel, Long start, Long end, String language, String vars) { - // 计算步长 - String step = getTimeStep(start, end); - // 封装返回结果 - Map<String, Object> resultMap = new HashMap(); - resultMap.put("language", language); - resultMap.put("start", start); - resultMap.put("end", end); - resultMap.put("panel", R.ok(panel)); - // 查询系统时区信息 - String timezone = sysConfigService.getValue("timezone"); - Timezone timezoneEntity = timezoneService.getOne(new LambdaUpdateWrapper<Timezone>().eq(Timezone::getName, timezone)); - resultMap.put("offset", timezoneEntity.getOffset()); - resultMap.put("timezone", timezone); - // charts 查询 - Map param = new HashMap<>(); - param.put("pageSize", "-1"); - param.put("panelId", panel.getId()); - param.put("groupId", 0); - PageUtils chartPageUtils = visualChartService.queryPage(param); - resultMap.put("charts", R.ok(chartPageUtils)); - List<VisualChart> chartsList = (List<VisualChart>) chartPageUtils.getList(); - if (Tool.CollUtil.isEmpty(chartsList)) { - throw new NZException(RCode.CHART_NOTEXSITS); - } else { - // 封装公共请求参数 - Map<String, String> basicQueryParam = new HashMap(); - basicQueryParam.put("start", StrUtil.toString(start)); - basicQueryParam.put("end", StrUtil.toString(end)); - basicQueryParam.put("step", step); - - List<Map> varList = StrUtil.isNotEmpty(vars) ? JSONObject.parseArray(vars, Map.class) : Tool.ListUtil.empty(); - - // 将chartsData获取任务装入futureList - List<CompletableFuture<Map>> futureList = this.recursionChartsData(chartsList, basicQueryParam, varList); - try { - Map chartsDataMap = new HashMap(); - CompletableFuture.allOf((CompletableFuture<?>[]) futureList.toArray(new CompletableFuture[0])) - .get(timeout, TimeUnit.MILLISECONDS); - futureList.forEach(future -> { - Map<String, Object> result = future.getNow(null); - if (Tool.MapUtil.isNotEmpty(result)) { - if (Tool.MapUtil.isNotEmpty(result)) { // && Tool.StrUtil.equals("success",Tool.StrUtil.toString(result.get("status"))) - chartsDataMap.put(StrUtil.concat(true, StrUtil.toString(result.get("chartId")), "_", StrUtil.toString(result.get("eleIndex"))), result); - } - } - }); - resultMap.put("chartsData", chartsDataMap); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - log.error(e); - } - } - // 读取模板,替换数据 - BufferedReader reader = null; - StringBuffer sbf = new StringBuffer(); - try { - String path = sysConfigDao.queryByKey("snapshot_template_path").getParamValue(); - reader = new BufferedReader(new FileReader(Tool.StrUtil.concat(true, path, File.separator, "snapshot_template.html"))); - String line = null; - while ((line = reader.readLine()) != null) { - if (Tool.StrUtil.startWith(line, "<script>window.dataJson")) - line = "<script>window.dataJson=" + JSONUtil.toJsonStr(resultMap) + "</script>"; - sbf.append(line + "\n"); - } - } catch (IOException e) { - log.error(e); - } finally { - if (reader != null) IoUtil.close(reader); - } - return sbf.toString(); - } - - /** - * 根据 vars 渲染 element 表达式 - * - * @param expr - * @param varList - */ - private String replaceExprByVars(String expr, List<Map> varList) { - if (Tool.CollectionUtil.isEmpty(varList)) return expr; - // 将 expr $xxx 变量渲染 - for (Map<String, String> map : varList) { - String name = map.get("name"); - String value = map.get("value"); - expr = expr.replaceAll("\\$" + name, value); - } - return expr; - } - - private List<CompletableFuture<Map>> recursionChartsData(List<VisualChart> chartsList, Map<String, String> basicQueryParam, List<Map> varList) { - List<CompletableFuture<Map>> futureList = new ArrayList<>(); - for (VisualChart chart : chartsList) { - String datasource = chart.getDatasource(); - if (StrUtil.equals("misc",datasource)){ - if (Tool.CollUtil.isNotEmpty(chart.getChildren())) { - List<CompletableFuture<Map>> callables = this.recursionChartsData(chart.getChildren(), basicQueryParam, varList); - if (Tool.CollUtil.isNotEmpty(callables)) - futureList.addAll(callables); - } - continue; - } - Map<String, Object> chartParam = (HashMap) chart.getParam(); - if(StrUtil.equals("system", datasource)) { - CompletableFuture<Map> mapCompletableFuture = null; - if(StrUtil.equals("assetInfo",chart.getType())){ - mapCompletableFuture = CompletableFuture.supplyAsync(() -> { - VisualPanel visualPanel = this.getById(chart.getPanelId()); - R ok = R.ok(assetAssetService.queryAssetInfo(visualPanel.getLink())); - ok.put("status", "success"); - ok.put("eleIndex", "0"); - ok.put("chartId", chart.getId()); - return ok; - }, this.getSnapshotThreadPool()); - }else if(StrUtil.equals("endpointInfo",chart.getType())){ - mapCompletableFuture = CompletableFuture.supplyAsync(() -> { - VisualPanel visualPanel = this.getById(chart.getPanelId()); - R ok = R.ok(monitorEndpointService.queryEndpointEntity(visualPanel.getLink())); - ok.put("status", "success"); - ok.put("eleIndex", "0"); - ok.put("chartId", chart.getId()); - return ok; - }, this.getSnapshotThreadPool()); - }else{ - mapCompletableFuture = CompletableFuture.supplyAsync(() -> { - JSONObject dataSource = JSONArray.parseArray(JSONObject.toJSONString(chartParam.get("datasource"))).getJSONObject(0); - JSONArray selectAry = new JSONArray(); - selectAry.add(dataSource.get("select")); - dataSource.put("select", selectAry); - HashMap analyseMap = new HashMap(); - analyseMap.put("q", dataSource.toJSONString()); - Map resultMap = new HashMap<>(); - resultMap.put("status", "success"); - resultMap.put("eleIndex", "0"); - resultMap.put("chartId", chart.getId()); - resultMap.putAll(statServiceImpl.queryAnalyse(analyseMap)); - return resultMap; - }, this.getSnapshotThreadPool()); - } - futureList.add(mapCompletableFuture); - } else { - Integer eleIndex = 0; - String start = basicQueryParam.get("start"); - String end = basicQueryParam.get("end"); - String step = basicQueryParam.get("step"); - - if(Tool.CollUtil.isNotEmpty(chart.getElements())){ - for (VisualChartElement element : chart.getElements()) { - String indexStr = StrUtil.toString(eleIndex++); - // 将表达式进行变量渲染 - String expr = this.replaceExprByVars(element.getExpression(), varList); - switch (datasource) { - case "metrics": - futureList.add(CompletableFuture.supplyAsync(() -> { - JSONObject jsonObject = null; - try { - jsonObject = promApiService.query_range(expr, start, end, step, chartParam.get("nullType").toString(), null); - jsonObject.put("eleIndex", indexStr); - jsonObject.put("chartId", chart.getId()); - }catch (NZException e){ - log.error(e); - } - return jsonObject; - }, this.getSnapshotThreadPool())); - break; - case "logs": - String limit = chartParam.get("limit") == null ? "100" : chartParam.get("limit").toString(); - futureList.add(CompletableFuture.supplyAsync(() -> { - JSONObject jsonObject = null; - try { - jsonObject = lokiApiService.query_range(expr, start, end, limit, step, null, "backward", "1", null); - jsonObject.put("eleIndex", indexStr); - jsonObject.put("chartId", chart.getId()); - }catch (NZException e){ - log.error(e); - } - return jsonObject; - }, this.getSnapshotThreadPool())); - break; - default:break; - } - } - }else{ - futureList.add(CompletableFuture.supplyAsync(() -> { - Map emptyElementsMap = Tool.MapUtil.newHashMap(); - emptyElementsMap.put("eleIndex", 0); - emptyElementsMap.put("chartId", chart.getId()); - return emptyElementsMap; - }, this.getSnapshotThreadPool())); - } - } - } - return futureList; - } - - /** - * 计算Dashboards step - */ - public String getTimeStep(Long start, Long end){ - Long timeDiff = (end - start) / (24 * 60 * 60); - if(timeDiff < 1){ - return "15s"; - }else if(timeDiff < 7){ - return "5m"; - }else if(timeDiff < 30){ - return "10m"; - }else{ - return "30m"; - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void cancelImport(String seq) { - List<VisualPanel> panelList = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, Constant.PanelType.DASHBOARD.getValue())); - List<Integer> delPanelIds = panelList.stream().filter(panel -> seq.equals(panel.getSeq())).map(VisualPanel::getId).collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(delPanelIds)) { - // 删除 panel - this.remove(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getSeq, seq)); - } - - List<VisualChart> delCharts = visualChartService.list(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getSeq, seq)); - if (CollectionUtils.isNotEmpty(delCharts)) { - // 删除 charts - visualChartService.remove(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getSeq, seq)); - } - chartElementService.remove(new QueryWrapper<VisualChartElement>().lambda().eq(VisualChartElement::getSeq, seq)); - } - - @Override - public void export(HttpServletResponse response, Map<String, Object> params) throws IOException { - String maxLine = sysConfigService.getValue(Constant.SYSCONFIG_KEY_EXPORT_MAX_LINE); - long exportMaxLine = Integer.parseInt(StrUtil.emptyToDefault(maxLine, "10000")); - // 导出最大条数限制 - Object limit = params.get(Constant.LIMIT) == null ? Constant.PAGESIZE : params.get(Constant.LIMIT); - Long pageSize = Long.parseLong(limit.toString()); - if (pageSize == -1) { - // 导出所有直接限制 pageSize - params.put(Constant.PAGE, "1"); - params.put(Constant.LIMIT, Long.toString(exportMaxLine)); - } else if (pageSize > exportMaxLine) { - // 分页超过最大限制 则设置最大限制为 系统配置值,和 pageSize == -1 判断区别在于 pageNo - params.put(Constant.LIMIT, Long.toString(exportMaxLine)); - } - // 导出查询与列表查询一致 - List<VisualChart> charts = this.exportDataByParams(params); - String type = Constant.PanelType.DASHBOARD.getValue(); - if (CollectionUtils.isNotEmpty(charts)) { - VisualChart chart = charts.stream().findFirst().get(); - VisualPanel panel = this.getById(chart.getPanelId()); - if (panel == null || !StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(), panel.getType())) { - type = Constant.PanelType.ASSET.getValue(); - } - } - String language = (String) params.get("language"); - - // 获取导出配置 key 名称 - String configKey = this.getChartTemplateConfigKeyByType(type); - String sysHeaderJsonStr = sysConfigService.getValue(configKey); - - String i18nConfigJsonStr = sysConfigService.getValue(Constant.I18N_MAPPING); - Map i18nConfigMap = JSONObject.parseObject(i18nConfigJsonStr, Map.class); - Map chartTypeMap = (Map) i18nConfigMap.get(Constant.DICT_CHART_TYPE); - Map chartTypeMapByLanguage = (Map) chartTypeMap.get(StrUtil.emptyToDefault(language, "en")); - - charts = charts.stream().sorted(Comparator.comparing(VisualChart::getGroupId)).collect(Collectors.toList()); - String fileName = "Charts"; - String formatStr = params.get("format").toString(); - - if (StrUtil.equals(Constant.PanelType.DASHBOARD.getValue(), type)) { - List<List<String>> exportDataList = this.handleDashboardChartExportDataList(charts, chartTypeMapByLanguage); - basicImportAndExportServices.exportDataByFormat(response, exportDataList, sysHeaderJsonStr, formatStr, fileName); - } else { - List<List<String>> exportDataList = this.handleAssetEndpointChartExportDataList(charts, chartTypeMapByLanguage); - basicImportAndExportServices.exportDataByFormat(response, exportDataList, sysHeaderJsonStr, formatStr, fileName); - } - } - private String getChartTemplateConfigKeyByType(String type) { - // 默认 dashboard 类型 - type = StringUtils.isEmpty(type) ? Constant.PanelType.DASHBOARD.getValue() : type; - String chartTemplateTyep; - switch (type) { - case "dashboard": { - chartTemplateTyep = Constant.SYSCONFIG_KEY_CHART_EXPORT_HEADER; - break; - } - /*case "model": { - chartTemplateTyep = Constant.SYSCONFIG_KEY_MODEL_CHART_EXPORT_HEADER; - break; - }*/ - case "asset": - case "template": - case "endpoint": { - chartTemplateTyep = Constant.SYSCONFIG_KEY_ASSET_CHART_EXPORT_HEADER; - break; - } - default: - throw new NZException(RCode.PANEL_CHART_TEMPLATE_TYPE_INCORRECT); - } - return chartTemplateTyep; - } - - - private List<List<String>> handleAssetEndpointChartExportDataList(List<VisualChart> charts, Map chartTypeMapByLanguage) { - Map<Integer, String> varTypeIdAndNameMap = new HashMap<>(4); - varTypeIdAndNameMap.put(1, "Asset"); - varTypeIdAndNameMap.put(2, "Endpoint"); - - List<List<String>> exportDataList = new ArrayList<>(); - for (VisualChart chart : charts) { - if (chart == null || Constant.CHART_ASSETINFO_TYPE.equalsIgnoreCase(chart.getType()) - || Constant.CHART_ENDPOINTINFO_TYPE.equalsIgnoreCase(chart.getType())) continue; - List<String> tempList = new ArrayList<>(); - String type = chart.getType(); - tempList.add(chart.getGroup().getName()); - tempList.add(chart.getName()); - tempList.add(this.getI18nChartTypeValue(chartTypeMapByLanguage, type)); - tempList.add(ToolUtil.isEmpty(varTypeIdAndNameMap.get(chart.getVarType())) ? "" : varTypeIdAndNameMap.get(chart.getVarType())); - tempList.add(ObjectUtil.defaultIfNull(chart.getSpan(), "").toString()); - tempList.add(ObjectUtil.defaultIfNull(chart.getHeight(), "").toString()); - if (StrUtil.equals(Constant.CHART_TEXT_TYPE, type)) { - tempList.add(""); - } else { - tempList.add(this.getUnitDescrByVal(chart.getUnit())); - } - tempList.add(this.handleChartParam(chart.getParam())); - tempList.add(this.handleChartElementForExport(chart.getElements())); - tempList.add(chart.getRemark()); - tempList.add(chart.getDatasource()); - tempList.add(ObjectUtil.defaultIfNull(chart.getX(), "").toString()); - tempList.add(ObjectUtil.defaultIfNull(chart.getY(), "").toString()); - exportDataList.add(tempList); - } - return exportDataList; - } - - private String handleChartElementForExport(List<VisualChartElement> chartElements) { - if (CollectionUtils.isEmpty(chartElements)) { - return ""; - } - List<Map> handleMaps = new ArrayList<>(); - Map tempMap; - for (VisualChartElement element : chartElements) { - tempMap = new LinkedHashMap(4); - tempMap.put("expression", element.getExpression()); - tempMap.put("state", element.getState()); - if (ToolUtil.isNotEmpty(element.getLegend())) { - tempMap.put("legend", element.getLegend()); - } - if (ToolUtil.isNotEmpty(element.getName())) { - tempMap.put("name", element.getName()); - } - handleMaps.add(tempMap); - } - return JSONArray.toJSONString(handleMaps); - } - - private String getI18nChartTypeValue(Map chartTypeMapByLanguage, String type) { - Object value = chartTypeMapByLanguage.get(type); - return value == null ? "" : value.toString(); - } - - private String getUnitDescrByVal(Integer unitVal) { - String unitDescr = null; - for (Map.Entry<String, Integer> entry : Constant.ALERT_RULE_UNIT_MAP.entrySet()) { - if (entry.getValue().equals(unitVal)) { - unitDescr = entry.getKey(); - break; - } - } - return unitDescr; - } - - private String handleChartParam(Object param) { - if (ToolUtil.isEmpty(param)) { - return ""; - } - Map<String, Object> map = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); - map.entrySet().removeIf(entry -> ToolUtil.isEmpty(entry.getValue())); - return ToolUtil.isEmpty(map) ? "" : JSONObject.toJSONString(map); - } - - public void getPanelNamePathAndIdMapFromTree(VisualPanel panel, String path, Map<String, Integer> nodeNamePathAndIdMap) { - if (CollectionUtils.isEmpty(panel.getChildren())) { - return; - } - for (VisualPanel cPanel : panel.getChildren()) { - String cPath = ""; - cPath += path + "/" + cPanel.getName(); - nodeNamePathAndIdMap.put(cPath, cPanel.getId()); - this.getPanelNamePathAndIdMapFromTree(cPanel, cPath, nodeNamePathAndIdMap); - } - } - - private int saveDashboardChartData(List<Map<Integer, String>> importDataList, List<Map> failDetails, List<String> headerInfos, String seqUUID, Map<String, String> chartTypeMapByLanguage) { - List<VisualPanel> panelTreeList = this.queryList(new HashMap()); - Map<String, Integer> nodeNamePathAndIdMap = new HashMap<>(); - for (VisualPanel panel : panelTreeList) { - nodeNamePathAndIdMap.put(panel.getName(), panel.getId()); - this.getPanelNamePathAndIdMapFromTree(panel, panel.getName(), nodeNamePathAndIdMap); - } - - List<VisualPanel> dashboardTypePanelList = this.list(new LambdaQueryWrapper<VisualPanel>().eq(VisualPanel::getType, Constant.PanelType.DASHBOARD.getValue())); - Integer panelMaxWeight; - if (CollectionUtils.isEmpty(dashboardTypePanelList)) { - panelMaxWeight = 0; - } else { - VisualPanel endPanel = dashboardTypePanelList.stream().max(Comparator.comparingInt(VisualPanel::getWeight)).get(); - panelMaxWeight = endPanel.getWeight(); - } - - // 查询 chart datasource类型防止频繁查库 - List<SysDictEntity> chartDatasources = sysDictService.list(new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, Constant.DICT_CHART_DATASOURCE)); - List<String> datasources = chartDatasources.stream().map(SysDictEntity::getValue).collect(Collectors.toList()); - - int successNum = 0; - for (int i = 0; i < importDataList.size(); i++) { - int dataFromExcelRowNum = i + 1; - Map<Integer, String> dataMap = importDataList.get(i); - - boolean saveFlag = true; - boolean typeFlag = true; - String panelName = dataMap.get(0); - if (StringUtils.isEmpty(panelName)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(0), RCode.PANEL_NAME_ISNULL.getMsg()); - } - Integer panelId = this.handlePanelNameForCellVal(nodeNamePathAndIdMap, panelName, seqUUID, ++panelMaxWeight); - Integer groupId=0; - String groupName = dataMap.get(1); - if(StrUtil.isNotBlank(groupName) && saveFlag) { - VisualChart groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getName, groupName).eq(VisualChart::getPanelId, panelId).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE.toString())); - if(ToolUtil.isEmpty(groupChart)) { - groupChart = new VisualChart(); - groupChart.setPanelId(panelId); - groupChart.setName(groupName); - groupChart.setGroupId(0); - groupChart.setSpan(12d); - groupChart.setHeight(-1d); - groupChart.setUpdateBy((ShiroUtils.getUserId()).intValue()); - groupChart.setUpdateAt(new Date()); - groupChart.setType(Constant.CHART_GROUP_TYPE.toString()); - groupChart.setUnit(2); - groupChart.setBuildIn(0); - groupChart.setRemark(""); - groupChart.setSeq(seqUUID); - // group 默认 datasource misc - groupChart.setDatasource(Constant.ChartDatasourceType.MISC.getValue()); - visualChartService.save(groupChart); - } - groupId = groupChart.getId(); - } - - String name = dataMap.get(2); - if (StringUtils.isEmpty(name)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), RCode.CHART_TITLE_ISNULL.getMsg()); - } else if(name.length() > 64) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), RCode.CHART_NAME_TOO_LONG.getMsg()); - } - String type = dataMap.get(3); - - if (StringUtils.isEmpty(type)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), RCode.CHART_TYPE_ISNULL.getMsg()); - } else { - type = this.validateChartTypeForImport(type, chartTypeMapByLanguage); - if (StringUtils.isEmpty(type)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), RCode.CHART_TYPE_INVALIDE.getMsg()); - } - } - - VisualChart groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getName, name).eq(VisualChart::getPanelId, panelId).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE.toString())); - if(StrUtil.equals(type, Constant.CHART_GROUP_TYPE.toString())&&ToolUtil.isNotEmpty(groupChart)) { - // chart group 不允许重复 - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), RCode.CHART_GROUP_NAME_DUPLICATE.getMsg()); - } - - String span = dataMap.get(4); - if (StringUtils.isEmpty(span)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), RCode.CHART_SPAN_ISNULL.getMsg()); - }else{ - Integer width = null; - try { - width = Double.valueOf(span).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), RCode.CHART_WIDTH_FORMAT.getMsg()); - } - if(width != null && (width < 1 || width > 12)){ - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), RCode.CHART_WIDTH_INVALIDE.getMsg()); - } - } - String height = dataMap.get(5); - if (StringUtils.isEmpty(height)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), RCode.CHART_HEIGHT_ISNULL.getMsg()); - }else{ - Integer heightIntVal = null; - try { - heightIntVal = Double.valueOf(height).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), RCode.CHART_HEIGHT_FORMAT.getMsg()); - } - if (heightIntVal != null && (heightIntVal < 1 || heightIntVal > 12)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), RCode.CHART_HEIGHT_INVALIDE.getMsg()); - } - } - String unit = dataMap.get(6); - if (StringUtils.isNotEmpty(unit)) { - if (ToolUtil.isEmpty(Constant.ALERT_RULE_UNIT_MAP.get(unit))) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(6), RCode.CHART_UNIT_NOTFOUND.getMsg()); - } - } - String param = dataMap.get(7); - if(typeFlag){ - String msg = this.validateChartParamForImport(type, param, "dashboard"); - if(StringUtils.isNotEmpty(msg)){ - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(7), msg); - } - } - - String datasource = dataMap.get(10); - if (StringUtils.isEmpty(datasource)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), RCode.CHART_DATASOURCE_ISNULL.getMsg()); - } else { - if (!datasources.contains(datasource)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), RCode.CHART_DATASOURCE_INVALIDE.getMsg()); - } - } - - String elements = dataMap.get(8); - if(typeFlag){ - String msg = this.validateChartElementForImport(datasource, elements); - if(StringUtils.isNotEmpty(msg)){ - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(8), msg); - } - } - String description = dataMap.get(9); - - String x = dataMap.get(11); - if (StringUtils.isEmpty(x)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_ISNULL.getMsg()); - }else{ - Integer xIntVal = null; - try { - xIntVal = Double.valueOf(x).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_FORMAT.getMsg()); - } - if (xIntVal != null && (xIntVal < 0 || xIntVal > 12)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_INVALIDE.getMsg()); - } - } - - // x和width之和不能大于12 - if(StringUtils.isNotEmpty(x) && StringUtils.isNotEmpty(span)) { - Double xVal = Double.valueOf(x); - Double widthVal = Double.valueOf(span); - if(xVal+widthVal>12) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_WIDTH_INVALIDE.getMsg()); - } - } - - String y = dataMap.get(12); - if (StringUtils.isEmpty(y)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), RCode.CHART_Y_ISNULL.getMsg()); - }else{ - Integer yIntVal = null; - try { - yIntVal = Double.valueOf(y).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), RCode.CHART_Y_FORMAT.getMsg()); - } - } - - if(saveFlag){ - TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); - try { - VisualChart chart = new VisualChart(); - chart.setSeq(seqUUID); - chart.setPanelId(panelId); - chart.setName(name); - chart.setType(type); - chart.setSpan(Double.valueOf(span)); - chart.setHeight(Double.valueOf(height)); - // unit 为空 设置默认值为 short - unit = StringUtils.isEmpty(unit) ? "short" : unit; - chart.setUnit(Constant.ALERT_RULE_UNIT_MAP.get(unit)); - chart.setParam(param.toString()); - chart.setUpdateAt(new Date()); - chart.setUpdateBy((ShiroUtils.getUserId()).intValue()); - chart.setGroupId(groupId); - chart.setRemark(description); - chart.setDatasource(datasource); - chart.setX(Double.valueOf(x)); - chart.setY(Double.valueOf(y)); - // 查询当前 panel 下的 charts - List<VisualChart> chartList = visualChartService.list(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getPanelId, chart.getPanelId())); - if (CollectionUtils.isEmpty(chartList)) { - visualChartService.save(chart); - } else { - VisualChart endChart = visualChartService.getOne(new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getPanelId, chart.getPanelId()).orderByDesc(VisualChart::getWeight).last("limit 0,1")); - Integer weight = endChart.getWeight(); - chart.setWeight(++weight); - visualChartService.save(chart); - } - List<VisualChartElement> chartElements = JSONArray.parseArray(elements, VisualChartElement.class); - if (CollectionUtils.isNotEmpty(chartElements)) { - chartElements.forEach(chartElement -> { - chartElement.setChartId(chart.getId()); - chartElement.setSeq(seqUUID); - chartElement.setType(Constant.CHART_ELEMENT_EXPERT_TYPE); - }); - chartElementService.saveBatch(chartElements); - } - dataSourceTransactionManager.commit(transactionStatus); - // panelNameAndIdMap.put(panelName, panelId); - successNum++; - } catch (RuntimeException e) { - dataSourceTransactionManager.rollback(transactionStatus); - this.addFailDetail(dataFromExcelRowNum, failDetails, "System", e.getMessage() + ""); - log.error(String.format("保存 panel chart chartelement失败,回滚事务,错误信息:%s", e)); - } - } - } - return successNum; - } - - private String validateChartElementForImport(String datasource,String elements) { - // datasource类型为metrics logs的需要校验elements - if (datasource.equals(Constant.ChartDatasourceType.METRICS.getValue()) || datasource.equals(Constant.ChartDatasourceType.LOGS.getValue())) { - if(StringUtils.isEmpty(elements)){ - return RCode.CHART_ELEMENT_ISNULL.getMsg(); - } - List<VisualChartElement> elementsList = null; - try { - elementsList = JSONArray.parseArray(elements, VisualChartElement.class); - } catch (JSONException e) { - return RCode.CHART_ELEMENTS_FORMAT.getMsg(); - } - - if(CollectionUtils.isEmpty(elementsList)){ - return RCode.CHART_ELEMENT_ISNULL.getMsg(); - } - - for (VisualChartElement element : elementsList) { - if(ToolUtil.isEmpty(element.getExpression())){ - return RCode.CHARTELEMENT_EXPRESSION_ISNULL.getMsg(); - } - if (ToolUtil.isEmpty(element.getName())) { - return RCode.CHARTELEMENT_NAME_ISNULL.getMsg(); - } - /*if (ToolUtil.isEmpty(element.getType())) { - return RCode.CHARTELEMENT_TYPE_ISNULL.getMsg(); - }*/ - } - } - return ""; - } - - /** - * @param panelName 格式: 使用 / 作为字符分隔,表示 父子节点关系 - * @param seqUUID 导入序列号 - */ - private Integer handlePanelNameForCellVal(Map<String, Integer> nodeNamePathAndIdMap, String panelName, String seqUUID, Integer panelWeight) { - String savePanelNames = panelName; - Integer panelId; - while (true) { - panelId = nodeNamePathAndIdMap.get(panelName); - if (panelId != null) { - break; - } - // 仍然包含 ‘/’ 证明还是有父子关系 - if (panelName.lastIndexOf("/") != -1) { - panelName = panelName.substring(0, panelName.lastIndexOf("/")); - } else { - // 最后的 panel 也不存在,赋值 为空 ,下面会进行过滤添加 - panelName = ""; - break; - } - } - savePanelNames = savePanelNames.replace(panelName, ""); - - // 如果存在需要保存的 panel - if (StringUtils.isNotEmpty(savePanelNames)) { - if (savePanelNames.startsWith("/")) { - savePanelNames = savePanelNames.substring(savePanelNames.indexOf("/") + 1); - } - - VisualPanel panel = new VisualPanel(); - panel.setType(Constant.PanelType.DASHBOARD.getValue()); - panel.setCreateBy(ShiroUtils.getUserId().intValue()); - panel.setSeq(seqUUID); - panel.setWeight(panelWeight); - panel.setUts(System.currentTimeMillis()); - - List<String> saveList = Arrays.asList(savePanelNames.split("/")); - int size = saveList.size(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < size; i++) { - String name = saveList.get(i); - panel.setName(name); - if (panel.getId() == null) { - panel.setPid(panelId); - } else { - panel.setPid(panel.getId()); - } - this.save(panel); - sb.append(name + "/"); - String temp = panelName + "/" + sb.substring(0, sb.lastIndexOf("/")); - // 因为用户输入根节点没有 ‘/’,所以不保存根节点 '/' 路径作为对比 - if (temp.startsWith("/")) { - temp = temp.substring(temp.indexOf("/") + 1); - } - nodeNamePathAndIdMap.put(temp, panel.getId()); - } - return panel.getId(); - } - return panelId; - } - - - private String validateChartParamForImport(String type, String param, String panelType) { - switch (type){ - // url - case Constant.CHART_URL_TYPE: { - if (StringUtils.isEmpty(param)) { - return RCode.CHART_URLPARAM_ISNULL.getMsg(); - } - Map map = null; - try { - map = JSONObject.parseObject(param, Map.class); - } catch (JSONException e) { - return RCode.CHART_PARAM_FORMAT.getMsg(); - } - Object url = map.get(Constant.CHART_URL_TYPE); - if (ToolUtil.isEmpty(url)) { - return RCode.CHART_URLPARAM_ISNULL.getMsg(); - } - - if(StrUtil.equals(Constant.PanelType.MODEL.getValue(),panelType)) { - // 替换全部变量 替换为 a(任意字符) 不影响原来的数据格式 然后进行校验 - String urlStr = url.toString(); - urlStr = urlStr.replaceAll("\\{\\{asset\\..*?\\}\\}", "a"); - - boolean b = CommonUtils.checkUrlInModel(urlStr); - boolean b1 = CommonUtils.checkUrl(urlStr); - - if (!b && !b1) { - return RCode.CHART_PARAMURL_FORMAT.getMsg(); - } - } else { - if (!CommonUtils.checkUrl(url.toString())) { - return RCode.CHART_PARAMURL_FORMAT.getMsg(); - } - } - break; - } - // singleStat - case Constant.CHART_SINGLESTAT_TYPE: { - if (StringUtils.isEmpty(param)) { - return RCode.CHART_SINGLESTATPARAM_ISNULL.getMsg(); - } - Map map = null; - try { - map = JSONObject.parseObject(param, Map.class); - } catch (JSONException e) { - return RCode.CHART_PARAM_FORMAT.getMsg(); - } - Object statistics = map.get(Constant.CHART_SINGLESTAT_PARAMkEY); - if (ToolUtil.isEmpty(statistics)) { - return RCode.CHART_PARAMSINGLESTAT_ISNULL.getMsg(); - } - if (!Constant.CHART_SINGLESTAT_STATISTICS.contains(statistics.toString())) { - return RCode.CHART_PARAMSINGLESTAT_INVALIDE.getMsg(); - } - break; - } - case Constant.CHART_TEXT_TYPE: { - if (StringUtils.isEmpty(param)) { - return RCode.CHART_TEXTPARAM_ISNULL.getMsg(); - } - Map map = null; - try { - map = JSONObject.parseObject(param, Map.class); - } catch (JSONException e) { - return RCode.CHART_PARAM_FORMAT.getMsg(); - } - Object text = map.get(Constant.CHART_TEXT_TYPE); - if (ToolUtil.isEmpty(text)) { - return RCode.CHART_TEXTPARAM_ISNULL.getMsg(); - } - break; - } - default:{ - if(StringUtils.isNotEmpty(param)){ - try { - JSONObject.parseObject(param, Map.class); - } catch (JSONException e) { - return RCode.CHART_PARAM_FORMAT.getMsg(); - } - } - } - } - return ""; - } - - private void addFailDetail(int i, List<Map> failDetails, String headerInfo, String msg) { - Map failDetail = new HashMap(4); - failDetail.put("lineNo", i); - failDetail.put("errorMsg", headerInfo + ": " + msg); - failDetails.add(failDetail); - } - - private String validateChartTypeForImport(String type, Map<String,String> chartTypeMapByLanguage) { - for (Map.Entry<String, String> entry : chartTypeMapByLanguage.entrySet()) { - if(StrUtil.equals(type,entry.getValue())){ - return entry.getKey(); - } - } - return null; - } - - private int saveAssetEndpointChartData(List<Map<Integer, String>> importDataList, List<Map> failDetails, String seqUUID, String panelType, Integer linkId, Map chartTypeMapByLanguage, List<String> headerInfos) { - // 导入类型 template 标识 - Boolean templateFlag = Constant.PanelType.TEMPLATE.getValue().equalsIgnoreCase(panelType); - // chart template 导入导出 varType map - Map<String, Integer> varTypeAndValMap = new HashMap<>(4); - varTypeAndValMap.put("Asset", 1); - varTypeAndValMap.put("Endpoint", 2); - - if (linkId == null && !templateFlag) throw new NZException(RCode.PANEL_CHART_IMPORT_LINKID_ISNULL); - - VisualPanel panel = this.getOne(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, panelType).eq(VisualPanel::getLink, linkId)); - if (panel == null && !templateFlag) throw new NZException(RCode.PANEL_NOT_EXIST); - - // 查询 chart datasource类型防止频繁查库 - List<SysDictEntity> chartDatasources = sysDictService.list(new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, Constant.DICT_CHART_DATASOURCE)); - List<String> datasources = chartDatasources.stream().map(SysDictEntity::getValue).collect(Collectors.toList()); - - int successNum = 0; - for (int i = 0; i < importDataList.size(); i++) { - int dataFromExcelRowNum = i + 1; - Map<Integer, String> dataMap = importDataList.get(i); - boolean saveFlag = true; - boolean typeFlag = true; - - Integer groupId=0; - String groupName = dataMap.get(0); - String varType = dataMap.get(3); - if(StrUtil.isNotBlank(groupName)) { - VisualChart groupChart; - if (templateFlag) { - // template 类型,panel = 0 为 template - groupChart = visualChartService.getOne(new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getName, groupName).eq(VisualChart::getPanelId, 0).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE).eq(VisualChart::getVarType, varTypeAndValMap.get(varType.trim()))); - } else { - // asset endpoint 类型,通过指定 panel group name 查找 group - groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getName, groupName).eq(VisualChart::getPanelId, panel.getId()).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE.toString())); - } - if(ToolUtil.isEmpty(groupChart)) { - groupChart = new VisualChart(); - // panel 为 null,即为 template type, panel_id = 0 - groupChart.setPanelId(ToolUtil.isEmpty(panel) ? 0 : panel.getId()); - groupChart.setName(groupName); - groupChart.setGroupId(0); - groupChart.setSpan(12d); - groupChart.setHeight(-1d); - groupChart.setUpdateBy((ShiroUtils.getUserId()).intValue()); - groupChart.setUpdateAt(new Date()); - groupChart.setType(Constant.CHART_GROUP_TYPE.toString()); - groupChart.setUnit(2); - groupChart.setBuildIn(0); - groupChart.setRemark(""); - if(templateFlag) { - groupChart.setVarType(varTypeAndValMap.get(varType.trim())); - } - // group 默认 datasource misc - groupChart.setDatasource(Constant.ChartDatasourceType.MISC.getValue()); - groupChart.setSeq(seqUUID); - visualChartService.save(groupChart); - } - groupId = groupChart.getId(); - } - - String name = dataMap.get(1); - if (StringUtils.isEmpty(name)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(0), RCode.CHART_TITLE_ISNULL.getMsg()); - } else if(name.length() > 64) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), RCode.CHART_NAME_TOO_LONG.getMsg()); - } - - String type = dataMap.get(2); - if (StringUtils.isEmpty(type)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), RCode.CHART_TYPE_ISNULL.getMsg()); - } else { - type = this.validateChartTypeForImport(type, chartTypeMapByLanguage); - if (StringUtils.isEmpty(type)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), RCode.CHART_TYPE_INVALIDE.getMsg()); - } - } - - VisualChart groupChart = null; - if (templateFlag) { - groupChart = visualChartService.getOne(new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getName, name).eq(VisualChart::getPanelId, 0).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE).eq(VisualChart::getVarType, varTypeAndValMap.get(varType.trim()))); - } else { - groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getName, name).eq(VisualChart::getPanelId, panel.getId()).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE)); - } - if (StrUtil.equals(type, Constant.CHART_GROUP_TYPE)&&ToolUtil.isNotEmpty(groupChart)) { - // chart group 不允许重复 - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), RCode.CHART_GROUP_NAME_DUPLICATE.getMsg()); - } - - // varType, type = template required - - if(templateFlag){ - if (StringUtils.isEmpty(varType)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), RCode.CHART_VARTYPE_ISNULL.getMsg()); - } else if (ToolUtil.isEmpty(varTypeAndValMap.get(varType.trim()))) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), RCode.CHART_VARTYPE_ERROR.getMsg()); - } - } - - String span = dataMap.get(4); - if (StringUtils.isEmpty(span)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), RCode.CHART_SPAN_ISNULL.getMsg()); - } else { - Integer width = null; - try { - width = Double.valueOf(span).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), RCode.CHART_WIDTH_FORMAT.getMsg()); - } - if (width != null && (width < 1 || width > 12)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), RCode.CHART_WIDTH_INVALIDE.getMsg()); - } - } - String height = dataMap.get(5); - if (StringUtils.isEmpty(height)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), RCode.CHART_HEIGHT_ISNULL.getMsg()); - } else { - Integer heightIntVal = null; - try { - heightIntVal = Double.valueOf(height).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), RCode.CHART_HEIGHT_FORMAT.getMsg()); - } - if (heightIntVal != null && (heightIntVal < 1 || heightIntVal > 12)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), RCode.CHART_HEIGHT_INVALIDE.getMsg()); - } - } - String unit = dataMap.get(6); - if (StringUtils.isNotEmpty(unit)) { - if (ToolUtil.isEmpty(Constant.ALERT_RULE_UNIT_MAP.get(unit))) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(6), RCode.CHART_UNIT_NOTFOUND.getMsg()); - } - } - String param = dataMap.get(7); - if (typeFlag) { - String msg = this.validateChartParamForImport(type, param, type); - if (StringUtils.isNotEmpty(msg)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(7), msg); - } - } - - String datasource = dataMap.get(10); - if (StringUtils.isEmpty(datasource)) { - saveFlag = typeFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), RCode.CHART_DATASOURCE_ISNULL.getMsg()); - } else { - if (!datasources.contains(datasource)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), RCode.CHART_DATASOURCE_INVALIDE.getMsg()); - } - } - - String elements = dataMap.get(8); - if (typeFlag) { - String msg = this.validateChartElementForImport(datasource, elements); - if (StringUtils.isNotEmpty(msg)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(8), msg); - } - } - String description = dataMap.get(9); - - String x = dataMap.get(11); - if (StringUtils.isEmpty(x)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_ISNULL.getMsg()); - }else{ - Integer xIntVal = null; - try { - xIntVal = Double.valueOf(x).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_FORMAT.getMsg()); - } - if (xIntVal != null && (xIntVal < 0 || xIntVal > 12)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_INVALIDE.getMsg()); - } - } - - // x和width之和不能大于12 - if(StringUtils.isNotEmpty(x) && StringUtils.isNotEmpty(span)) { - Double xVal = Double.valueOf(x); - Double widthVal = Double.valueOf(span); - if(xVal+widthVal>12) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), RCode.CHART_X_WIDTH_INVALIDE.getMsg()); - } - } - - String y = dataMap.get(12); - if (StringUtils.isEmpty(y)) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), RCode.CHART_Y_ISNULL.getMsg()); - }else{ - Integer yIntVal = null; - try { - yIntVal = Double.valueOf(y).intValue(); - } catch (NumberFormatException e) { - saveFlag = false; - this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), RCode.CHART_Y_FORMAT.getMsg()); - } - } - - if (saveFlag) { - TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); - try { - VisualChart chart = new VisualChart(); - chart.setSeq(seqUUID); - // panel 为 null,即为 template type, panel_id = 0 - chart.setPanelId(ToolUtil.isEmpty(panel) ? 0 : panel.getId()); - chart.setName(name); - chart.setType(type); - chart.setSpan(Double.valueOf(span)); - chart.setHeight(Double.valueOf(height)); - // unit 为空 设置默认值为 short - unit = StringUtils.isEmpty(unit) ? "short" : unit; - chart.setUnit(Constant.ALERT_RULE_UNIT_MAP.get(unit)); - chart.setParam(param.toString()); - chart.setUpdateAt(new Date()); - chart.setUpdateBy((ShiroUtils.getUserId()).intValue()); - chart.setGroupId(groupId); - chart.setVarType(varTypeAndValMap.get(varType)); - chart.setVarId(linkId); - chart.setRemark(description); - chart.setDatasource(datasource); - chart.setX(Double.valueOf(x)); - chart.setY(Double.valueOf(y)); - // 查询当前 panel 下的 charts - List<VisualChart> chartList = visualChartService.list(new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getPanelId, chart.getPanelId())); - if (CollectionUtils.isEmpty(chartList)) { - visualChartService.save(chart); - } else { - VisualChart endChart = visualChartService.getOne(new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getPanelId, chart.getPanelId()).orderByDesc(VisualChart::getWeight).last("limit 0,1")); - Integer weight = endChart.getWeight(); - chart.setWeight(++weight); - visualChartService.save(chart); - } - List<VisualChartElement> chartElements = JSONArray.parseArray(elements, VisualChartElement.class); - if (CollectionUtils.isNotEmpty(chartElements)) { - chartElements.forEach(chartElement -> { - chartElement.setChartId(chart.getId()); - chartElement.setSeq(seqUUID); - chartElement.setType(Constant.CHART_ELEMENT_EXPERT_TYPE); - }); - chartElementService.saveBatch(chartElements); - } - dataSourceTransactionManager.commit(transactionStatus); - successNum++; - } catch (RuntimeException e) { - dataSourceTransactionManager.rollback(transactionStatus); - this.addFailDetail(dataFromExcelRowNum, failDetails, "System", e.getMessage() + ""); - log.error(String.format("保存 panel chart chartelement失败,回滚事务,错误信息:%s", e)); - } - } - } - return successNum; - } - - private List<VisualChart> exportDataByParams(Map<String, Object> params) { - String panelId = null; - if (ToolUtil.isNotEmpty(params.get("panelId"))) { - panelId = params.get("panelId").toString(); - } - String chartId = null; - if (ToolUtil.isNotEmpty(params.get("chartId"))) { - chartId = params.get("chartId").toString(); - } - String panelType=null; - if(ToolUtil.isNotEmpty(params.get("type"))) { - panelType = params.get("type").toString(); - if (!Constant.PanelType.TEMPLATE.getValue().equals(panelType)) { - params.put("panelType", panelType); - }else { - panelId = "0"; - } - params.remove("type"); - } - List<VisualChart> chartList = new ArrayList<VisualChart>(); - if(chartId != null) { - // 只导出当前 chart - chartList.addAll(this.queryChartsByPanelId(panelId, chartId,params)); - }else if (ToolUtil.isEmpty(panelId)) { - // 导出所有 dashboard panel - List<VisualPanel> panelList = this.list(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, Constant.PanelType.DASHBOARD.getValue()).orderByAsc(VisualPanel::getWeight, VisualPanel::getId)); - // panelList = panelService.getSequentialPanelList(panelList); - for (VisualPanel panel : panelList) { - Map<String, Object> param = new HashMap<String,Object>(); - param.put("panelType", panelType); - param.put("pageSize", (String) params.get("pageSize")); - chartList.addAll(this.queryChartsByPanelId(panel.getId().toString(),null,param)); - } - } else if(ToolUtil.isNotEmpty(panelId)){ - // 导出 panel 下所有chart - chartList.addAll(this.queryChartsByPanelId(panelId, null,params)); - } - return chartList; - } - - private List<List<String>> handleDashboardChartExportDataList(List<VisualChart> charts, Map chartTypeMapByLanguage) { - List<VisualPanel> panelTreeList = this.queryList(new HashMap()); - Map<Integer, String> nodeIdAndNamePathMap = new HashMap<>(); - for (VisualPanel panel : panelTreeList) { - nodeIdAndNamePathMap.put(panel.getId(), panel.getName()); - this.getPanelIdAndNamePathMapFromTree(panel, panel.getName(), nodeIdAndNamePathMap); - } - - List<List<String>> exportDataList = new ArrayList<>(); - for (VisualChart chart : charts) { - if (chart == null) continue; - List<String> tempList = new ArrayList<>(); - String type = chart.getType(); - tempList.add(nodeIdAndNamePathMap.get(chart.getPanelId())); - tempList.add(chart.getGroup().getName()); - tempList.add(chart.getName()); - tempList.add(this.getI18nChartTypeValue(chartTypeMapByLanguage, type)); - tempList.add(ObjectUtil.defaultIfNull(chart.getSpan(), "").toString()); - tempList.add(ObjectUtil.defaultIfNull(chart.getHeight(), "").toString()); - if (StrUtil.equals(Constant.CHART_TEXT_TYPE, type)) { - tempList.add(""); - } else { - tempList.add(this.getUnitDescrByVal(chart.getUnit())); - } - tempList.add(this.handleChartParam(chart.getParam())); - tempList.add(this.handleChartElementForExport(chart.getElements())); - tempList.add(chart.getRemark()); - tempList.add(chart.getDatasource()); - tempList.add(ObjectUtil.defaultIfNull(chart.getX(), "").toString()); - tempList.add(ObjectUtil.defaultIfNull(chart.getY(), "").toString()); - exportDataList.add(tempList); - } - return exportDataList; - } - - public void getPanelIdAndNamePathMapFromTree(VisualPanel panel, String path, Map<Integer, String> nodeIdAndNamePathMap) { - if (CollectionUtils.isEmpty(panel.getChildren())) { - return; - } - for (VisualPanel cPanel : panel.getChildren()) { - String cPath = ""; - cPath += path + "/" + cPanel.getName(); - nodeIdAndNamePathMap.put(cPanel.getId(), cPath); - this.getPanelIdAndNamePathMapFromTree(cPanel, cPath, nodeIdAndNamePathMap); - } - } - - public List<VisualChart> queryChartsByPanelId(String panelId, String chartId, Map<String, Object> params) { - params.put("panelId", panelId); - // 加上原有 ids - String ids = (String) params.get("ids"); - if (StrUtil.isNotEmpty(ids)) { - chartId = StrUtil.emptyToDefault(chartId, ""); - chartId += chartId.endsWith(",") ? ids : "," + ids; - } - params.put("ids", chartId); - params.put("returnChildren", "1"); - params.put("groupId", 0); - PageUtils queryPage = visualChartService.queryPage(params); - List<VisualChart> result = (List<VisualChart>) queryPage.getList(); - - // 递归展开节点信息 - List<VisualChart> allChartList = new ArrayList<>(); - for (VisualChart entity : result) { - getAllChildrenChartList(entity, allChartList); - } - return allChartList; - } - - /** - * 平铺 获取所有 chart 节点 - * - * @param chart - * @param chartList - */ - public void getAllChildrenChartList(VisualChart chart, List<VisualChart> chartList) { - chartList.add(chart); - if (CollectionUtils.isNotEmpty(chart.getChildren())) { - for (VisualChart pojo : chart.getChildren()) { - getAllChildrenChartList(pojo, chartList); - } - } - } - - public List<Map<Integer, String>> groupChartRowHandle(List<Map<Integer, String>> importDataList, Integer index) { - // type标识dashboard还是asset 区别去第几列查找group chart信息 - List<Map<Integer, String>> list = importDataList.stream().filter(dataMap -> { - String groupName = dataMap.get(index); - if (StringUtils.isEmpty(groupName)) { - return true; - } - return false; - }).collect(Collectors.toList()); - importDataList.removeAll(list); - list.addAll(importDataList); - return list; - } - + // 默认 dashboard 类型 + type = StringUtils.isEmpty(type) ? Constant.PanelType.DASHBOARD.getValue() : type; + String chartTemplateTyep; + switch (type) { + case "dashboard": { + chartTemplateTyep = Constant.SYSCONFIG_KEY_CHART_EXPORT_HEADER; + break; + } + /* + * case "model": { chartTemplateTyep = + * Constant.SYSCONFIG_KEY_MODEL_CHART_EXPORT_HEADER; break; } + */ + case "asset": + case "template": + case "endpoint": { + chartTemplateTyep = Constant.SYSCONFIG_KEY_ASSET_CHART_EXPORT_HEADER; + break; + } + default: + throw new NZException(RCode.PANEL_CHART_TEMPLATE_TYPE_INCORRECT); + } + return chartTemplateTyep; + } + + private List<List<String>> handleAssetEndpointChartExportDataList(List<VisualChart> charts, + Map chartTypeMapByLanguage) { + Map<Integer, String> varTypeIdAndNameMap = new HashMap<>(4); + varTypeIdAndNameMap.put(1, "Asset"); + varTypeIdAndNameMap.put(2, "Endpoint"); + + List<List<String>> exportDataList = new ArrayList<>(); + for (VisualChart chart : charts) { + if (chart == null || Constant.CHART_ASSETINFO_TYPE.equalsIgnoreCase(chart.getType()) + || Constant.CHART_ENDPOINTINFO_TYPE.equalsIgnoreCase(chart.getType())) + continue; + List<String> tempList = new ArrayList<>(); + String type = chart.getType(); + tempList.add(chart.getGroup().getName()); + tempList.add(chart.getName()); + tempList.add(this.getI18nChartTypeValue(chartTypeMapByLanguage, type)); + tempList.add(ToolUtil.isEmpty(varTypeIdAndNameMap.get(chart.getVarType())) ? "" + : varTypeIdAndNameMap.get(chart.getVarType())); + tempList.add(ObjectUtil.defaultIfNull(chart.getSpan(), "").toString()); + tempList.add(ObjectUtil.defaultIfNull(chart.getHeight(), "").toString()); + if (StrUtil.equals(Constant.CHART_TEXT_TYPE, type)) { + tempList.add(""); + } else { + tempList.add(this.getUnitDescrByVal(chart.getUnit())); + } + tempList.add(this.handleChartParam(chart.getParam())); + tempList.add(this.handleChartElementForExport(chart.getElements())); + tempList.add(chart.getRemark()); + tempList.add(chart.getDatasource()); + tempList.add(ObjectUtil.defaultIfNull(chart.getX(), "").toString()); + tempList.add(ObjectUtil.defaultIfNull(chart.getY(), "").toString()); + exportDataList.add(tempList); + } + return exportDataList; + } + + private String handleChartElementForExport(List<VisualChartElement> chartElements) { + if (CollectionUtils.isEmpty(chartElements)) { + return ""; + } + List<Map> handleMaps = new ArrayList<>(); + Map tempMap; + for (VisualChartElement element : chartElements) { + tempMap = new LinkedHashMap(4); + tempMap.put("expression", element.getExpression()); + tempMap.put("state", element.getState()); + if (ToolUtil.isNotEmpty(element.getLegend())) { + tempMap.put("legend", element.getLegend()); + } + if (ToolUtil.isNotEmpty(element.getName())) { + tempMap.put("name", element.getName()); + } + handleMaps.add(tempMap); + } + return JSONArray.toJSONString(handleMaps); + } + + private String getI18nChartTypeValue(Map chartTypeMapByLanguage, String type) { + Object value = chartTypeMapByLanguage.get(type); + return value == null ? "" : value.toString(); + } + + private String getUnitDescrByVal(Integer unitVal) { + String unitDescr = null; + for (Map.Entry<String, Integer> entry : Constant.ALERT_RULE_UNIT_MAP.entrySet()) { + if (entry.getValue().equals(unitVal)) { + unitDescr = entry.getKey(); + break; + } + } + return unitDescr; + } + + private String handleChartParam(Object param) { + if (ToolUtil.isEmpty(param)) { + return ""; + } + Map<String, Object> map = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); + map.entrySet().removeIf(entry -> ToolUtil.isEmpty(entry.getValue())); + return ToolUtil.isEmpty(map) ? "" : JSONObject.toJSONString(map); + } + + public void getPanelNamePathAndIdMapFromTree(VisualPanel panel, String path, + Map<String, Integer> nodeNamePathAndIdMap) { + if (CollectionUtils.isEmpty(panel.getChildren())) { + return; + } + for (VisualPanel cPanel : panel.getChildren()) { + String cPath = ""; + cPath += path + "/" + cPanel.getName(); + nodeNamePathAndIdMap.put(cPath, cPanel.getId()); + this.getPanelNamePathAndIdMapFromTree(cPanel, cPath, nodeNamePathAndIdMap); + } + } + + private int saveDashboardChartData(List<Map<Integer, String>> importDataList, List<Map> failDetails, + List<String> headerInfos, String seqUUID, Map<String, String> chartTypeMapByLanguage) { + List<VisualPanel> panelTreeList = this.queryList(new HashMap()); + Map<String, Integer> nodeNamePathAndIdMap = new HashMap<>(); + for (VisualPanel panel : panelTreeList) { + nodeNamePathAndIdMap.put(panel.getName(), panel.getId()); + this.getPanelNamePathAndIdMapFromTree(panel, panel.getName(), nodeNamePathAndIdMap); + } + + List<VisualPanel> dashboardTypePanelList = this.list(new LambdaQueryWrapper<VisualPanel>() + .eq(VisualPanel::getType, Constant.PanelType.DASHBOARD.getValue())); + Integer panelMaxWeight; + if (CollectionUtils.isEmpty(dashboardTypePanelList)) { + panelMaxWeight = 0; + } else { + VisualPanel endPanel = dashboardTypePanelList.stream().max(Comparator.comparingInt(VisualPanel::getWeight)) + .get(); + panelMaxWeight = endPanel.getWeight(); + } + + // 查询 chart datasource类型防止频繁查库 + List<SysDictEntity> chartDatasources = sysDictService.list( + new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, Constant.DICT_CHART_DATASOURCE)); + List<String> datasources = chartDatasources.stream().map(SysDictEntity::getValue).collect(Collectors.toList()); + + int successNum = 0; + for (int i = 0; i < importDataList.size(); i++) { + int dataFromExcelRowNum = i + 1; + Map<Integer, String> dataMap = importDataList.get(i); + + boolean saveFlag = true; + boolean typeFlag = true; + String panelName = dataMap.get(0); + if (StringUtils.isEmpty(panelName)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(0), + RCode.PANEL_NAME_ISNULL.getMsg()); + } + Integer panelId = this.handlePanelNameForCellVal(nodeNamePathAndIdMap, panelName, seqUUID, + ++panelMaxWeight); + Integer groupId = 0; + String groupName = dataMap.get(1); + if (StrUtil.isNotBlank(groupName) && saveFlag) { + VisualChart groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda() + .eq(VisualChart::getName, groupName).eq(VisualChart::getPanelId, panelId) + .eq(VisualChart::getType, Constant.CHART_GROUP_TYPE.toString())); + if (ToolUtil.isEmpty(groupChart)) { + groupChart = new VisualChart(); + groupChart.setPanelId(panelId); + groupChart.setName(groupName); + groupChart.setGroupId(0); + groupChart.setSpan(12d); + groupChart.setHeight(-1d); + groupChart.setUpdateBy((ShiroUtils.getUserId()).intValue()); + groupChart.setUpdateAt(new Date()); + groupChart.setType(Constant.CHART_GROUP_TYPE.toString()); + groupChart.setUnit(2); + groupChart.setBuildIn(0); + groupChart.setRemark(""); + groupChart.setSeq(seqUUID); + // group 默认 datasource misc + groupChart.setDatasource(Constant.ChartDatasourceType.MISC.getValue()); + visualChartService.save(groupChart); + } + groupId = groupChart.getId(); + } + + String name = dataMap.get(2); + if (StringUtils.isEmpty(name)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), + RCode.CHART_TITLE_ISNULL.getMsg()); + } else if (name.length() > 64) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), + RCode.CHART_NAME_TOO_LONG.getMsg()); + } + String type = dataMap.get(3); + + if (StringUtils.isEmpty(type)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), + RCode.CHART_TYPE_ISNULL.getMsg()); + } else { + type = this.validateChartTypeForImport(type, chartTypeMapByLanguage); + if (StringUtils.isEmpty(type)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), + RCode.CHART_TYPE_INVALIDE.getMsg()); + } + } + + VisualChart groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda() + .eq(VisualChart::getName, name).eq(VisualChart::getPanelId, panelId) + .eq(VisualChart::getType, Constant.CHART_GROUP_TYPE.toString())); + if (StrUtil.equals(type, Constant.CHART_GROUP_TYPE.toString()) && ToolUtil.isNotEmpty(groupChart)) { + // chart group 不允许重复 + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), + RCode.CHART_GROUP_NAME_DUPLICATE.getMsg()); + } + + String span = dataMap.get(4); + if (StringUtils.isEmpty(span)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), + RCode.CHART_SPAN_ISNULL.getMsg()); + } else { + Integer width = null; + try { + width = Double.valueOf(span).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), + RCode.CHART_WIDTH_FORMAT.getMsg()); + } + if (width != null && (width < 1 || width > 12)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), + RCode.CHART_WIDTH_INVALIDE.getMsg()); + } + } + String height = dataMap.get(5); + if (StringUtils.isEmpty(height)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), + RCode.CHART_HEIGHT_ISNULL.getMsg()); + } else { + Integer heightIntVal = null; + try { + heightIntVal = Double.valueOf(height).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), + RCode.CHART_HEIGHT_FORMAT.getMsg()); + } + if (heightIntVal != null && (heightIntVal < 1 || heightIntVal > 12)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), + RCode.CHART_HEIGHT_INVALIDE.getMsg()); + } + } + String unit = dataMap.get(6); + if (StringUtils.isNotEmpty(unit)) { + if (ToolUtil.isEmpty(Constant.ALERT_RULE_UNIT_MAP.get(unit))) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(6), + RCode.CHART_UNIT_NOTFOUND.getMsg()); + } + } + String param = dataMap.get(7); + if (typeFlag) { + String msg = this.validateChartParamForImport(type, param, "dashboard"); + if (StringUtils.isNotEmpty(msg)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(7), msg); + } + } + + String datasource = dataMap.get(10); + if (StringUtils.isEmpty(datasource)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), + RCode.CHART_DATASOURCE_ISNULL.getMsg()); + } else { + if (!datasources.contains(datasource)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), + RCode.CHART_DATASOURCE_INVALIDE.getMsg()); + } + } + + String elements = dataMap.get(8); + if (typeFlag) { + String msg = this.validateChartElementForImport(datasource, elements); + if (StringUtils.isNotEmpty(msg)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(8), msg); + } + } + String description = dataMap.get(9); + + String x = dataMap.get(11); + if (StringUtils.isEmpty(x)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_ISNULL.getMsg()); + } else { + Integer xIntVal = null; + try { + xIntVal = Double.valueOf(x).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_FORMAT.getMsg()); + } + if (xIntVal != null && (xIntVal < 0 || xIntVal > 12)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_INVALIDE.getMsg()); + } + } + + // x和width之和不能大于12 + if (StringUtils.isNotEmpty(x) && StringUtils.isNotEmpty(span)) { + Double xVal = Double.valueOf(x); + Double widthVal = Double.valueOf(span); + if (xVal + widthVal > 12) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_WIDTH_INVALIDE.getMsg()); + } + } + + String y = dataMap.get(12); + if (StringUtils.isEmpty(y)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), + RCode.CHART_Y_ISNULL.getMsg()); + } else { + Integer yIntVal = null; + try { + yIntVal = Double.valueOf(y).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), + RCode.CHART_Y_FORMAT.getMsg()); + } + } + + if (saveFlag) { + TransactionStatus transactionStatus = dataSourceTransactionManager + .getTransaction(transactionDefinition); + try { + VisualChart chart = new VisualChart(); + chart.setSeq(seqUUID); + chart.setPanelId(panelId); + chart.setName(name); + chart.setType(type); + chart.setSpan(Double.valueOf(span)); + chart.setHeight(Double.valueOf(height)); + // unit 为空 设置默认值为 short + unit = StringUtils.isEmpty(unit) ? "short" : unit; + chart.setUnit(Constant.ALERT_RULE_UNIT_MAP.get(unit)); + chart.setParam(param.toString()); + chart.setUpdateAt(new Date()); + chart.setUpdateBy((ShiroUtils.getUserId()).intValue()); + chart.setGroupId(groupId); + chart.setRemark(description); + chart.setDatasource(datasource); + chart.setX(Double.valueOf(x)); + chart.setY(Double.valueOf(y)); + // 查询当前 panel 下的 charts + List<VisualChart> chartList = visualChartService.list( + new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getPanelId, chart.getPanelId())); + if (CollectionUtils.isEmpty(chartList)) { + visualChartService.save(chart); + } else { + VisualChart endChart = visualChartService.getOne( + new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getPanelId, chart.getPanelId()) + .orderByDesc(VisualChart::getWeight).last("limit 0,1")); + Integer weight = endChart.getWeight(); + chart.setWeight(++weight); + visualChartService.save(chart); + } + List<VisualChartElement> chartElements = JSONArray.parseArray(elements, VisualChartElement.class); + if (CollectionUtils.isNotEmpty(chartElements)) { + chartElements.forEach(chartElement -> { + chartElement.setChartId(chart.getId()); + chartElement.setSeq(seqUUID); + chartElement.setType(Constant.CHART_ELEMENT_EXPERT_TYPE); + }); + chartElementService.saveBatch(chartElements); + } + dataSourceTransactionManager.commit(transactionStatus); + // panelNameAndIdMap.put(panelName, panelId); + successNum++; + } catch (RuntimeException e) { + dataSourceTransactionManager.rollback(transactionStatus); + this.addFailDetail(dataFromExcelRowNum, failDetails, "System", e.getMessage() + ""); + log.error(String.format("保存 panel chart chartelement失败,回滚事务,错误信息:%s", e)); + } + } + } + return successNum; + } + + private String validateChartElementForImport(String datasource, String elements) { + // datasource类型为metrics logs的需要校验elements + if (datasource.equals(Constant.ChartDatasourceType.METRICS.getValue()) + || datasource.equals(Constant.ChartDatasourceType.LOGS.getValue())) { + if (StringUtils.isEmpty(elements)) { + return RCode.CHART_ELEMENT_ISNULL.getMsg(); + } + List<VisualChartElement> elementsList = null; + try { + elementsList = JSONArray.parseArray(elements, VisualChartElement.class); + } catch (JSONException e) { + return RCode.CHART_ELEMENTS_FORMAT.getMsg(); + } + + if (CollectionUtils.isEmpty(elementsList)) { + return RCode.CHART_ELEMENT_ISNULL.getMsg(); + } + + for (VisualChartElement element : elementsList) { + if (ToolUtil.isEmpty(element.getExpression())) { + return RCode.CHARTELEMENT_EXPRESSION_ISNULL.getMsg(); + } + if (ToolUtil.isEmpty(element.getName())) { + return RCode.CHARTELEMENT_NAME_ISNULL.getMsg(); + } + /* + * if (ToolUtil.isEmpty(element.getType())) { return + * RCode.CHARTELEMENT_TYPE_ISNULL.getMsg(); } + */ + } + } + return ""; + } + + /** + * @param panelName 格式: 使用 / 作为字符分隔,表示 父子节点关系 + * @param seqUUID 导入序列号 + */ + private Integer handlePanelNameForCellVal(Map<String, Integer> nodeNamePathAndIdMap, String panelName, + String seqUUID, Integer panelWeight) { + String savePanelNames = panelName; + Integer panelId; + while (true) { + panelId = nodeNamePathAndIdMap.get(panelName); + if (panelId != null) { + break; + } + // 仍然包含 ‘/’ 证明还是有父子关系 + if (panelName.lastIndexOf("/") != -1) { + panelName = panelName.substring(0, panelName.lastIndexOf("/")); + } else { + // 最后的 panel 也不存在,赋值 为空 ,下面会进行过滤添加 + panelName = ""; + break; + } + } + savePanelNames = savePanelNames.replace(panelName, ""); + + // 如果存在需要保存的 panel + if (StringUtils.isNotEmpty(savePanelNames)) { + if (savePanelNames.startsWith("/")) { + savePanelNames = savePanelNames.substring(savePanelNames.indexOf("/") + 1); + } + + VisualPanel panel = new VisualPanel(); + panel.setType(Constant.PanelType.DASHBOARD.getValue()); + panel.setCreateBy(ShiroUtils.getUserId().intValue()); + panel.setSeq(seqUUID); + panel.setWeight(panelWeight); + panel.setUts(System.currentTimeMillis()); + + List<String> saveList = Arrays.asList(savePanelNames.split("/")); + int size = saveList.size(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size; i++) { + String name = saveList.get(i); + panel.setName(name); + if (panel.getId() == null) { + panel.setPid(panelId); + } else { + panel.setPid(panel.getId()); + } + this.save(panel); + sb.append(name + "/"); + String temp = panelName + "/" + sb.substring(0, sb.lastIndexOf("/")); + // 因为用户输入根节点没有 ‘/’,所以不保存根节点 '/' 路径作为对比 + if (temp.startsWith("/")) { + temp = temp.substring(temp.indexOf("/") + 1); + } + nodeNamePathAndIdMap.put(temp, panel.getId()); + } + return panel.getId(); + } + return panelId; + } + + private String validateChartParamForImport(String type, String param, String panelType) { + switch (type) { + // url + case Constant.CHART_URL_TYPE: { + if (StringUtils.isEmpty(param)) { + return RCode.CHART_URLPARAM_ISNULL.getMsg(); + } + Map map = null; + try { + map = JSONObject.parseObject(param, Map.class); + } catch (JSONException e) { + return RCode.CHART_PARAM_FORMAT.getMsg(); + } + Object url = map.get(Constant.CHART_URL_TYPE); + if (ToolUtil.isEmpty(url)) { + return RCode.CHART_URLPARAM_ISNULL.getMsg(); + } + + if (StrUtil.equals(Constant.PanelType.MODEL.getValue(), panelType)) { + // 替换全部变量 替换为 a(任意字符) 不影响原来的数据格式 然后进行校验 + String urlStr = url.toString(); + urlStr = urlStr.replaceAll("\\{\\{asset\\..*?\\}\\}", "a"); + + boolean b = CommonUtils.checkUrlInModel(urlStr); + boolean b1 = CommonUtils.checkUrl(urlStr); + + if (!b && !b1) { + return RCode.CHART_PARAMURL_FORMAT.getMsg(); + } + } else { + if (!CommonUtils.checkUrl(url.toString())) { + return RCode.CHART_PARAMURL_FORMAT.getMsg(); + } + } + break; + } + // singleStat + case Constant.CHART_SINGLESTAT_TYPE: { + if (StringUtils.isEmpty(param)) { + return RCode.CHART_SINGLESTATPARAM_ISNULL.getMsg(); + } + Map map = null; + try { + map = JSONObject.parseObject(param, Map.class); + } catch (JSONException e) { + return RCode.CHART_PARAM_FORMAT.getMsg(); + } + Object statistics = map.get(Constant.CHART_SINGLESTAT_PARAMkEY); + if (ToolUtil.isEmpty(statistics)) { + return RCode.CHART_PARAMSINGLESTAT_ISNULL.getMsg(); + } + if (!Constant.CHART_SINGLESTAT_STATISTICS.contains(statistics.toString())) { + return RCode.CHART_PARAMSINGLESTAT_INVALIDE.getMsg(); + } + break; + } + case Constant.CHART_TEXT_TYPE: { + if (StringUtils.isEmpty(param)) { + return RCode.CHART_TEXTPARAM_ISNULL.getMsg(); + } + Map map = null; + try { + map = JSONObject.parseObject(param, Map.class); + } catch (JSONException e) { + return RCode.CHART_PARAM_FORMAT.getMsg(); + } + Object text = map.get(Constant.CHART_TEXT_TYPE); + if (ToolUtil.isEmpty(text)) { + return RCode.CHART_TEXTPARAM_ISNULL.getMsg(); + } + break; + } + default: { + if (StringUtils.isNotEmpty(param)) { + try { + JSONObject.parseObject(param, Map.class); + } catch (JSONException e) { + return RCode.CHART_PARAM_FORMAT.getMsg(); + } + } + } + } + return ""; + } + + private void addFailDetail(int i, List<Map> failDetails, String headerInfo, String msg) { + Map failDetail = new HashMap(4); + failDetail.put("lineNo", i); + failDetail.put("errorMsg", headerInfo + ": " + msg); + failDetails.add(failDetail); + } + + private String validateChartTypeForImport(String type, Map<String, String> chartTypeMapByLanguage) { + for (Map.Entry<String, String> entry : chartTypeMapByLanguage.entrySet()) { + if (StrUtil.equals(type, entry.getValue())) { + return entry.getKey(); + } + } + return null; + } + + private int saveAssetEndpointChartData(List<Map<Integer, String>> importDataList, List<Map> failDetails, + String seqUUID, String panelType, Integer linkId, Map chartTypeMapByLanguage, List<String> headerInfos) { + // 导入类型 template 标识 + Boolean templateFlag = Constant.PanelType.TEMPLATE.getValue().equalsIgnoreCase(panelType); + // chart template 导入导出 varType map + Map<String, Integer> varTypeAndValMap = new HashMap<>(4); + varTypeAndValMap.put("Asset", 1); + varTypeAndValMap.put("Endpoint", 2); + + if (linkId == null && !templateFlag) + throw new NZException(RCode.PANEL_CHART_IMPORT_LINKID_ISNULL); + + VisualPanel panel = this.getOne(new QueryWrapper<VisualPanel>().lambda().eq(VisualPanel::getType, panelType) + .eq(VisualPanel::getLink, linkId)); + if (panel == null && !templateFlag) + throw new NZException(RCode.PANEL_NOT_EXIST); + + // 查询 chart datasource类型防止频繁查库 + List<SysDictEntity> chartDatasources = sysDictService.list( + new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, Constant.DICT_CHART_DATASOURCE)); + List<String> datasources = chartDatasources.stream().map(SysDictEntity::getValue).collect(Collectors.toList()); + + int successNum = 0; + for (int i = 0; i < importDataList.size(); i++) { + int dataFromExcelRowNum = i + 1; + Map<Integer, String> dataMap = importDataList.get(i); + boolean saveFlag = true; + boolean typeFlag = true; + + Integer groupId = 0; + String groupName = dataMap.get(0); + String varType = dataMap.get(3); + if (StrUtil.isNotBlank(groupName)) { + VisualChart groupChart; + if (templateFlag) { + // template 类型,panel = 0 为 template + groupChart = visualChartService + .getOne(new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getName, groupName) + .eq(VisualChart::getPanelId, 0).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE) + .eq(VisualChart::getVarType, varTypeAndValMap.get(varType.trim()))); + } else { + // asset endpoint 类型,通过指定 panel group name 查找 group + groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda() + .eq(VisualChart::getName, groupName).eq(VisualChart::getPanelId, panel.getId()) + .eq(VisualChart::getType, Constant.CHART_GROUP_TYPE.toString())); + } + if (ToolUtil.isEmpty(groupChart)) { + groupChart = new VisualChart(); + // panel 为 null,即为 template type, panel_id = 0 + groupChart.setPanelId(ToolUtil.isEmpty(panel) ? 0 : panel.getId()); + groupChart.setName(groupName); + groupChart.setGroupId(0); + groupChart.setSpan(12d); + groupChart.setHeight(-1d); + groupChart.setUpdateBy((ShiroUtils.getUserId()).intValue()); + groupChart.setUpdateAt(new Date()); + groupChart.setType(Constant.CHART_GROUP_TYPE.toString()); + groupChart.setUnit(2); + groupChart.setBuildIn(0); + groupChart.setRemark(""); + if (templateFlag) { + groupChart.setVarType(varTypeAndValMap.get(varType.trim())); + } + // group 默认 datasource misc + groupChart.setDatasource(Constant.ChartDatasourceType.MISC.getValue()); + groupChart.setSeq(seqUUID); + visualChartService.save(groupChart); + } + groupId = groupChart.getId(); + } + + String name = dataMap.get(1); + if (StringUtils.isEmpty(name)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(0), + RCode.CHART_TITLE_ISNULL.getMsg()); + } else if (name.length() > 64) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), + RCode.CHART_NAME_TOO_LONG.getMsg()); + } + + String type = dataMap.get(2); + if (StringUtils.isEmpty(type)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), + RCode.CHART_TYPE_ISNULL.getMsg()); + } else { + type = this.validateChartTypeForImport(type, chartTypeMapByLanguage); + if (StringUtils.isEmpty(type)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), + RCode.CHART_TYPE_INVALIDE.getMsg()); + } + } + + VisualChart groupChart = null; + if (templateFlag) { + groupChart = visualChartService + .getOne(new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getName, name) + .eq(VisualChart::getPanelId, 0).eq(VisualChart::getType, Constant.CHART_GROUP_TYPE) + .eq(VisualChart::getVarType, varTypeAndValMap.get(varType.trim()))); + } else { + groupChart = visualChartService.getOne(new QueryWrapper<VisualChart>().lambda() + .eq(VisualChart::getName, name).eq(VisualChart::getPanelId, panel.getId()) + .eq(VisualChart::getType, Constant.CHART_GROUP_TYPE)); + } + if (StrUtil.equals(type, Constant.CHART_GROUP_TYPE) && ToolUtil.isNotEmpty(groupChart)) { + // chart group 不允许重复 + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(2), + RCode.CHART_GROUP_NAME_DUPLICATE.getMsg()); + } + + // varType, type = template required + + if (templateFlag) { + if (StringUtils.isEmpty(varType)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), + RCode.CHART_VARTYPE_ISNULL.getMsg()); + } else if (ToolUtil.isEmpty(varTypeAndValMap.get(varType.trim()))) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(3), + RCode.CHART_VARTYPE_ERROR.getMsg()); + } + } + + String span = dataMap.get(4); + if (StringUtils.isEmpty(span)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), + RCode.CHART_SPAN_ISNULL.getMsg()); + } else { + Integer width = null; + try { + width = Double.valueOf(span).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), + RCode.CHART_WIDTH_FORMAT.getMsg()); + } + if (width != null && (width < 1 || width > 12)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(4), + RCode.CHART_WIDTH_INVALIDE.getMsg()); + } + } + String height = dataMap.get(5); + if (StringUtils.isEmpty(height)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), + RCode.CHART_HEIGHT_ISNULL.getMsg()); + } else { + Integer heightIntVal = null; + try { + heightIntVal = Double.valueOf(height).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), + RCode.CHART_HEIGHT_FORMAT.getMsg()); + } + if (heightIntVal != null && (heightIntVal < 1 || heightIntVal > 12)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(5), + RCode.CHART_HEIGHT_INVALIDE.getMsg()); + } + } + String unit = dataMap.get(6); + if (StringUtils.isNotEmpty(unit)) { + if (ToolUtil.isEmpty(Constant.ALERT_RULE_UNIT_MAP.get(unit))) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(6), + RCode.CHART_UNIT_NOTFOUND.getMsg()); + } + } + String param = dataMap.get(7); + if (typeFlag) { + String msg = this.validateChartParamForImport(type, param, type); + if (StringUtils.isNotEmpty(msg)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(7), msg); + } + } + + String datasource = dataMap.get(10); + if (StringUtils.isEmpty(datasource)) { + saveFlag = typeFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), + RCode.CHART_DATASOURCE_ISNULL.getMsg()); + } else { + if (!datasources.contains(datasource)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(10), + RCode.CHART_DATASOURCE_INVALIDE.getMsg()); + } + } + + String elements = dataMap.get(8); + if (typeFlag) { + String msg = this.validateChartElementForImport(datasource, elements); + if (StringUtils.isNotEmpty(msg)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(8), msg); + } + } + String description = dataMap.get(9); + + String x = dataMap.get(11); + if (StringUtils.isEmpty(x)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_ISNULL.getMsg()); + } else { + Integer xIntVal = null; + try { + xIntVal = Double.valueOf(x).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_FORMAT.getMsg()); + } + if (xIntVal != null && (xIntVal < 0 || xIntVal > 12)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_INVALIDE.getMsg()); + } + } + + // x和width之和不能大于12 + if (StringUtils.isNotEmpty(x) && StringUtils.isNotEmpty(span)) { + Double xVal = Double.valueOf(x); + Double widthVal = Double.valueOf(span); + if (xVal + widthVal > 12) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(11), + RCode.CHART_X_WIDTH_INVALIDE.getMsg()); + } + } + + String y = dataMap.get(12); + if (StringUtils.isEmpty(y)) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), + RCode.CHART_Y_ISNULL.getMsg()); + } else { + Integer yIntVal = null; + try { + yIntVal = Double.valueOf(y).intValue(); + } catch (NumberFormatException e) { + saveFlag = false; + this.addFailDetail(dataFromExcelRowNum, failDetails, headerInfos.get(12), + RCode.CHART_Y_FORMAT.getMsg()); + } + } + + if (saveFlag) { + TransactionStatus transactionStatus = dataSourceTransactionManager + .getTransaction(transactionDefinition); + try { + VisualChart chart = new VisualChart(); + chart.setSeq(seqUUID); + // panel 为 null,即为 template type, panel_id = 0 + chart.setPanelId(ToolUtil.isEmpty(panel) ? 0 : panel.getId()); + chart.setName(name); + chart.setType(type); + chart.setSpan(Double.valueOf(span)); + chart.setHeight(Double.valueOf(height)); + // unit 为空 设置默认值为 short + unit = StringUtils.isEmpty(unit) ? "short" : unit; + chart.setUnit(Constant.ALERT_RULE_UNIT_MAP.get(unit)); + chart.setParam(param.toString()); + chart.setUpdateAt(new Date()); + chart.setUpdateBy((ShiroUtils.getUserId()).intValue()); + chart.setGroupId(groupId); + chart.setVarType(varTypeAndValMap.get(varType)); + chart.setVarId(linkId); + chart.setRemark(description); + chart.setDatasource(datasource); + chart.setX(Double.valueOf(x)); + chart.setY(Double.valueOf(y)); + // 查询当前 panel 下的 charts + List<VisualChart> chartList = visualChartService.list( + new QueryWrapper<VisualChart>().lambda().eq(VisualChart::getPanelId, chart.getPanelId())); + if (CollectionUtils.isEmpty(chartList)) { + visualChartService.save(chart); + } else { + VisualChart endChart = visualChartService.getOne( + new LambdaQueryWrapper<VisualChart>().eq(VisualChart::getPanelId, chart.getPanelId()) + .orderByDesc(VisualChart::getWeight).last("limit 0,1")); + Integer weight = endChart.getWeight(); + chart.setWeight(++weight); + visualChartService.save(chart); + } + List<VisualChartElement> chartElements = JSONArray.parseArray(elements, VisualChartElement.class); + if (CollectionUtils.isNotEmpty(chartElements)) { + chartElements.forEach(chartElement -> { + chartElement.setChartId(chart.getId()); + chartElement.setSeq(seqUUID); + chartElement.setType(Constant.CHART_ELEMENT_EXPERT_TYPE); + }); + chartElementService.saveBatch(chartElements); + } + dataSourceTransactionManager.commit(transactionStatus); + successNum++; + } catch (RuntimeException e) { + dataSourceTransactionManager.rollback(transactionStatus); + this.addFailDetail(dataFromExcelRowNum, failDetails, "System", e.getMessage() + ""); + log.error(String.format("保存 panel chart chartelement失败,回滚事务,错误信息:%s", e)); + } + } + } + return successNum; + } + + private List<VisualChart> exportDataByParams(Map<String, Object> params) { + String panelId = null; + if (ToolUtil.isNotEmpty(params.get("panelId"))) { + panelId = params.get("panelId").toString(); + } + String chartId = null; + if (ToolUtil.isNotEmpty(params.get("chartId"))) { + chartId = params.get("chartId").toString(); + } + String panelType = null; + if (ToolUtil.isNotEmpty(params.get("type"))) { + panelType = params.get("type").toString(); + if (!Constant.PanelType.TEMPLATE.getValue().equals(panelType)) { + params.put("panelType", panelType); + } else { + panelId = "0"; + } + params.remove("type"); + } + List<VisualChart> chartList = new ArrayList<VisualChart>(); + if (chartId != null) { + // 只导出当前 chart + chartList.addAll(this.queryChartsByPanelId(panelId, chartId, params)); + } else if (ToolUtil.isEmpty(panelId)) { + // 导出所有 dashboard panel + List<VisualPanel> panelList = this.list(new QueryWrapper<VisualPanel>().lambda() + .eq(VisualPanel::getType, Constant.PanelType.DASHBOARD.getValue()) + .orderByAsc(VisualPanel::getWeight, VisualPanel::getId)); + // panelList = panelService.getSequentialPanelList(panelList); + for (VisualPanel panel : panelList) { + Map<String, Object> param = new HashMap<String, Object>(); + param.put("panelType", panelType); + param.put("pageSize", (String) params.get("pageSize")); + chartList.addAll(this.queryChartsByPanelId(panel.getId().toString(), null, param)); + } + } else if (ToolUtil.isNotEmpty(panelId)) { + // 导出 panel 下所有chart + chartList.addAll(this.queryChartsByPanelId(panelId, null, params)); + } + return chartList; + } + + private List<List<String>> handleDashboardChartExportDataList(List<VisualChart> charts, + Map chartTypeMapByLanguage) { + List<VisualPanel> panelTreeList = this.queryList(new HashMap()); + Map<Integer, String> nodeIdAndNamePathMap = new HashMap<>(); + for (VisualPanel panel : panelTreeList) { + nodeIdAndNamePathMap.put(panel.getId(), panel.getName()); + this.getPanelIdAndNamePathMapFromTree(panel, panel.getName(), nodeIdAndNamePathMap); + } + + List<List<String>> exportDataList = new ArrayList<>(); + for (VisualChart chart : charts) { + if (chart == null) + continue; + List<String> tempList = new ArrayList<>(); + String type = chart.getType(); + tempList.add(nodeIdAndNamePathMap.get(chart.getPanelId())); + tempList.add(chart.getGroup().getName()); + tempList.add(chart.getName()); + tempList.add(this.getI18nChartTypeValue(chartTypeMapByLanguage, type)); + tempList.add(ObjectUtil.defaultIfNull(chart.getSpan(), "").toString()); + tempList.add(ObjectUtil.defaultIfNull(chart.getHeight(), "").toString()); + if (StrUtil.equals(Constant.CHART_TEXT_TYPE, type)) { + tempList.add(""); + } else { + tempList.add(this.getUnitDescrByVal(chart.getUnit())); + } + tempList.add(this.handleChartParam(chart.getParam())); + tempList.add(this.handleChartElementForExport(chart.getElements())); + tempList.add(chart.getRemark()); + tempList.add(chart.getDatasource()); + tempList.add(ObjectUtil.defaultIfNull(chart.getX(), "").toString()); + tempList.add(ObjectUtil.defaultIfNull(chart.getY(), "").toString()); + exportDataList.add(tempList); + } + return exportDataList; + } + + public void getPanelIdAndNamePathMapFromTree(VisualPanel panel, String path, + Map<Integer, String> nodeIdAndNamePathMap) { + if (CollectionUtils.isEmpty(panel.getChildren())) { + return; + } + for (VisualPanel cPanel : panel.getChildren()) { + String cPath = ""; + cPath += path + "/" + cPanel.getName(); + nodeIdAndNamePathMap.put(cPanel.getId(), cPath); + this.getPanelIdAndNamePathMapFromTree(cPanel, cPath, nodeIdAndNamePathMap); + } + } + + public List<VisualChart> queryChartsByPanelId(String panelId, String chartId, Map<String, Object> params) { + params.put("panelId", panelId); + // 加上原有 ids + String ids = (String) params.get("ids"); + if (StrUtil.isNotEmpty(ids)) { + chartId = StrUtil.emptyToDefault(chartId, ""); + chartId += chartId.endsWith(",") ? ids : "," + ids; + } + params.put("ids", chartId); + params.put("returnChildren", "1"); + params.put("groupId", 0); + PageUtils queryPage = visualChartService.queryPage(params); + List<VisualChart> result = (List<VisualChart>) queryPage.getList(); + + // 递归展开节点信息 + List<VisualChart> allChartList = new ArrayList<>(); + for (VisualChart entity : result) { + getAllChildrenChartList(entity, allChartList); + } + return allChartList; + } + + /** + * 平铺 获取所有 chart 节点 + * + * @param chart + * @param chartList + */ + public void getAllChildrenChartList(VisualChart chart, List<VisualChart> chartList) { + chartList.add(chart); + if (CollectionUtils.isNotEmpty(chart.getChildren())) { + for (VisualChart pojo : chart.getChildren()) { + getAllChildrenChartList(pojo, chartList); + } + } + } + + public List<Map<Integer, String>> groupChartRowHandle(List<Map<Integer, String>> importDataList, Integer index) { + // type标识dashboard还是asset 区别去第几列查找group chart信息 + List<Map<Integer, String>> list = importDataList.stream().filter(dataMap -> { + String groupName = dataMap.get(index); + if (StringUtils.isEmpty(groupName)) { + return true; + } + return false; + }).collect(Collectors.toList()); + importDataList.removeAll(list); + list.addAll(importDataList); + return list; + } + private synchronized ExecutorService getSnapshotThreadPool() { if (snapshotThreadPool == null) { - snapshotThreadPool = new ThreadPoolExecutor(0, snapshotConcurrency, 60L, TimeUnit.SECONDS, - new LinkedBlockingQueue<Runnable>(snapshotCapacity), new NamedThreadFactory("SNAPSHOT-", true)); + snapshotThreadPool = new ThreadPoolExecutor(snapshotCorePoolSize, snapshotConcurrency, + snapshotKeepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(snapshotCapacity), + new NamedThreadFactory("SNAPSHOT-", true)); } return snapshotThreadPool; } |
