diff --git a/web-ai/web-ai-mcp/pom.xml b/web-ai/web-ai-mcp/pom.xml index 96925ca7..10ed1421 100644 --- a/web-ai/web-ai-mcp/pom.xml +++ b/web-ai/web-ai-mcp/pom.xml @@ -83,15 +83,6 @@ - - - org.apache.maven.plugins - maven-eclipse-plugin - - ${finalName} - - - diff --git a/web-api/src/main/java/com/jeesite/modules/app/appStart.java b/web-api/src/main/java/com/jeesite/modules/app/appStart.java index 0ac0ba86..5c7a55ee 100644 --- a/web-api/src/main/java/com/jeesite/modules/app/appStart.java +++ b/web-api/src/main/java/com/jeesite/modules/app/appStart.java @@ -1,9 +1,12 @@ package com.jeesite.modules.app; +import com.jeesite.common.config.Global; import com.jeesite.modules.app.Service.MyService; import com.jeesite.modules.app.dao.MyWorkInfo; +import com.jeesite.modules.app.dao.info.DockerInfo; import com.jeesite.modules.app.utils.DateUtils; +import com.jeesite.modules.app.utils.DockerUtils; import com.jeesite.modules.app.utils.MyUtils; import com.jeesite.modules.biz.entity.*; @@ -15,9 +18,13 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static com.jeesite.common.web.BaseController.text; +import static com.jeesite.common.web.http.ServletUtils.renderResult; + @Controller @RequestMapping(value = "${adminPath}/biz/myWork") @@ -32,6 +39,9 @@ public class appStart { @Resource private BizProjectInfoService bizProjectInfoService; + @Resource + private BizMonitorHostService bizMonitorHostService; + @Resource private BizCalendarInfoService bizCalendarInfoService; @@ -88,4 +98,66 @@ public class appStart { return new MyWorkInfo(weatherText, notifyNums, listItems.size(), projectNums, projectInfos.size(), calendarNums, schedules.size(), employees.size()); } + @RequestMapping(value = "dockerList") + @ResponseBody + public List dockerList(DockerInfo dockerInfo) { + BizMonitorHost monitorHost = new BizMonitorHost(); + monitorHost.setHostId(dockerInfo.getHostId()); + List bizMonitorHostList = bizMonitorHostService.findList(monitorHost); + BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0); + if (bizMonitorHost.getIsAuth().equals("1")) { + try { + DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort()); + return dockerUtils.dockerInfoList(bizMonitorHost.getHostId()); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + return new ArrayList<>(); + } + + + @RequestMapping(value = "restart") + @ResponseBody + public String restart(DockerInfo dockerInfo) { + BizMonitorHost monitorHost = new BizMonitorHost(); + monitorHost.setHostId(dockerInfo.getHostId()); + List bizMonitorHostList = bizMonitorHostService.findList(monitorHost); + BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0); + if (bizMonitorHost.getIsAuth().equals("1")) { + DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort()); + dockerUtils.stopContainer(dockerInfo.getId()); + dockerUtils.startContainer(dockerInfo.getId()); + } + return renderResult(Global.TRUE, text("重启容器成功!")); + } + + @RequestMapping(value = "start") + @ResponseBody + public String start(DockerInfo dockerInfo) { + BizMonitorHost monitorHost = new BizMonitorHost(); + monitorHost.setHostId(dockerInfo.getHostId()); + List bizMonitorHostList = bizMonitorHostService.findList(monitorHost); + BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0); + if (bizMonitorHost.getIsAuth().equals("1")) { + DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort()); + dockerUtils.startContainer(dockerInfo.getId()); + } + return renderResult(Global.TRUE, text("启动容器成功!")); + } + + @RequestMapping(value = "stop") + @ResponseBody + public String stop(DockerInfo dockerInfo) { + BizMonitorHost monitorHost = new BizMonitorHost(); + monitorHost.setHostId(dockerInfo.getHostId()); + List bizMonitorHostList = bizMonitorHostService.findList(monitorHost); + BizMonitorHost bizMonitorHost = bizMonitorHostList.get(0); + if (bizMonitorHost.getIsAuth().equals("1")) { + DockerUtils dockerUtils = new DockerUtils(bizMonitorHost.getIpAddress(), bizMonitorHost.getCheckTargetPort()); + dockerUtils.stopContainer(dockerInfo.getId()); + } + return renderResult(Global.TRUE, text("停止容器成功!")); + } + } diff --git a/web-api/src/main/java/com/jeesite/modules/app/dao/info/DockerInfo.java b/web-api/src/main/java/com/jeesite/modules/app/dao/info/DockerInfo.java new file mode 100644 index 00000000..30d61a07 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/app/dao/info/DockerInfo.java @@ -0,0 +1,39 @@ +package com.jeesite.modules.app.dao.info; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class DockerInfo implements Serializable { + + private String name; // 容器名称 + private String id; // 容器id + private String cid; + private String imageName; // 镜像名称 + private String mapPorts; // 映射端口 + private String status; // 运行时长 + private String state; // 运行状态 + private double cpuUsage; //CPU + private double memUsage; // 内存 + + private String hostId; + + public DockerInfo() { + + } + + public DockerInfo(String name, String id,String imageName, String mapPorts, String status, String state, double cpuUsage, double memUsage,String hostId) { + this.name = name; + this.id = id; + this.cid = id.substring(0, 12); + this.imageName = imageName; + this.mapPorts = mapPorts; + this.state = state; + this.status = status; + this.cpuUsage = cpuUsage; + this.memUsage = memUsage; + this.hostId = hostId; + } +} diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/DockerUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/DockerUtils.java index 150806be..86ba18ec 100644 --- a/web-api/src/main/java/com/jeesite/modules/app/utils/DockerUtils.java +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/DockerUtils.java @@ -1,66 +1,229 @@ package com.jeesite.modules.app.utils; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.Container; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.okhttp.OkDockerHttpClient; +import com.jeesite.modules.app.dao.info.DockerInfo; import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + + +public class DockerUtils implements AutoCloseable { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + // 重试次数 + private static final int RETRY_COUNT = 3; + // 重试间隔(秒) + private static final int RETRY_INTERVAL = 2; -public class DockerUtils { private final DockerClient dockerClient; + /** + * 构造Docker客户端连接(重点:调整HTTP客户端超时配置) + * + * @param dockerIp Docker服务端IP + * @param dockerPort Docker服务端端口 + * @throws IllegalArgumentException IP/端口不合法时抛出 + */ public DockerUtils(String dockerIp, int dockerPort) { + if (dockerIp == null || dockerIp.isBlank()) { + throw new IllegalArgumentException("Docker IP地址不能为空"); + } + if (dockerPort <= 0 || dockerPort > 65535) { + throw new IllegalArgumentException("Docker端口号必须在1-65535之间"); + } + String dockerHostStr = String.format("tcp://%s:%d", dockerIp, dockerPort); URI dockerHost = URI.create(dockerHostStr); + + // 核心调整:增大HTTP客户端超时时间(连接超时60秒,读取超时120秒) OkDockerHttpClient httpClient = new OkDockerHttpClient.Builder() .dockerHost(dockerHost) - .connectTimeout(10) - .readTimeout(30) + .connectTimeout(60) // 连接超时从10秒→60秒 + .readTimeout(120) // 读取超时从30秒→120秒 .build(); + this.dockerClient = DockerClientBuilder.getInstance() .withDockerHttpClient(httpClient) .build(); } /** - * 获取容器列表 all true=包含停止容器,false=仅运行中容器 + * 启动容器(移除无效的withTimeout,保留重试机制+延长HTTP超时) + * + * @param containerId 容器ID/名称 + * @return true=启动成功,false=启动失败 + */ + public boolean startContainer(String containerId) { + // 1. 参数校验 + if (containerId == null || containerId.isBlank()) { + return false; + } + // 2. 增加重试机制 + int retry = 0; + while (retry < RETRY_COUNT) { + try { + // 检查容器是否存在 + InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); + // 检查容器是否已启动 + if (containerInfo.getState().getRunning()) { + return true; + } + // 修复点:移除无效的withTimeout调用,仅保留核心启动逻辑 + dockerClient.startContainerCmd(containerId).exec(); + // 等待2秒后验证启动结果(给容器足够的启动时间,避免状态未同步) + TimeUnit.SECONDS.sleep(2); + InspectContainerResponse afterStart = dockerClient.inspectContainerCmd(containerId).exec(); + if (afterStart.getState().getRunning()) { + System.out.println("容器[" + containerId + "]启动成功(重试次数:" + retry + ")"); + return true; + } + } catch (Exception e) { + retry++; + // 非最后一次重试时,等待后重试 + if (retry < RETRY_COUNT) { + try { + TimeUnit.SECONDS.sleep(RETRY_INTERVAL); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + } + } + return false; + } + + /** + * 获取容器列表 */ public List listContainers(boolean all) { - return dockerClient.listContainersCmd().withShowAll(all).exec(); + try { + return dockerClient.listContainersCmd().withShowAll(all).exec(); + } catch (Exception e) { + System.out.println(e.getMessage()); + return Collections.emptyList(); + } } /** - * 创建容器(指定镜像+唯一容器名,后台运行) + * 封装容器信息为业务模型 + */ + public List dockerInfoList(String hostId) { + if (hostId == null || hostId.isBlank()) { + return Collections.emptyList(); + } + + List dockerInfos = new ArrayList<>(); + try { + List containers = listContainers(true); + for (Container container : containers) { + String containerName = container.getNames() != null + ? String.join("", container.getNames()).replace("/", "") + : "未知容器"; + String portsJson; + try { + portsJson = OBJECT_MAPPER.writeValueAsString(container.getPorts()); + } catch (JsonProcessingException e) { + System.out.println("容器[" + container.getId() + "]端口信息序列化失败:" + e.getMessage()); + portsJson = "[]"; + } + dockerInfos.add(new DockerInfo( + containerName, + container.getId(), + container.getImage(), + portsJson, + container.getStatus(), + "running".equals(container.getState()) ? "1" : "0", + 0, + 0, + hostId + )); + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return dockerInfos; + } + + /** + * 创建容器(指定镜像+唯一容器名) */ public String createContainer(String image, String containerName) { - CreateContainerResponse resp = dockerClient.createContainerCmd(image) - .withName(containerName) - .withTty(true) // 分配伪终端,后台运行 - .exec(); - return resp.getId(); + if (image == null || image.isBlank()) { + throw new IllegalArgumentException("镜像名称不能为空"); + } + if (containerName == null || containerName.isBlank()) { + throw new IllegalArgumentException("容器名称不能为空"); + } + try { + CreateContainerResponse resp = dockerClient.createContainerCmd(image) + .withName(containerName) + .withTty(true) + .exec(); + return resp.getId(); + } catch (Exception e) { + System.out.println(e.getMessage()); + return null; + } } /** - * 启动容器(支持完整ID/短ID/容器名) + * 停止容器 */ - public void startContainer(String containerId) { - dockerClient.startContainerCmd(containerId).exec(); + public boolean stopContainer(String containerId) { + if (containerId == null || containerId.isBlank()) { + return false; + } + try { + InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec(); + if (!containerInfo.getState().getRunning()) { + return true; + } + dockerClient.stopContainerCmd(containerId).exec(); + return true; + } catch (Exception e) { + System.out.println(e.getMessage()); + return false; + } } /** - * 停止容器(支持完整ID/短ID/容器名) + * 删除容器 */ - public void stopContainer(String containerId) { - dockerClient.stopContainerCmd(containerId).exec(); + public boolean removeContainer(String containerId, boolean force) { + if (containerId == null || containerId.isBlank()) { + return false; + } + try { + dockerClient.removeContainerCmd(containerId).withForce(force).exec(); + return true; + } catch (Exception e) { + System.out.println(e.getMessage()); + return false; + } } /** - * 删除容器 true=强制删除运行中的容器,false=仅删除停止的 + * 关闭Docker客户端连接,释放资源 */ - public void removeContainer(String containerId, boolean force) { - dockerClient.removeContainerCmd(containerId).withForce(force).exec(); + @Override + public void close() { + if (Objects.nonNull(dockerClient)) { + try { + dockerClient.close(); + System.out.println("Docker客户端连接已关闭"); + } catch (Exception e) { + System.err.println("关闭Docker客户端连接失败,异常信息:" + e.getMessage()); + } + } } } \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java index 02853592..0d463011 100644 --- a/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizFoldersController.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; import com.jeesite.modules.app.dao.file.FolderItem; import com.jeesite.modules.app.utils.MyUtils; @@ -160,51 +162,49 @@ public class BizFoldersController extends BaseController { @RequestMapping(value = "foldersAll") @ResponseBody public List> foldersAll(BizFolders bizFolders) { + // 构建根节点 List> treeData = new ArrayList<>(); Map rootNode = new HashMap<>(); rootNode.put("id", "0"); rootNode.put("name", "根目录"); rootNode.put("disabled", false); - rootNode.put("children", new ArrayList<>()); - bizFolders.setParentId("0"); - bizFolders.setIsDeleted(0); - List firstLevelFolders = bizFoldersService.findList(bizFolders); - List> firstNodeList = new ArrayList<>(); - for (BizFolders firstFolder : firstLevelFolders) { - Map firstNode = MyUtils.convertToTreeNode(firstFolder, "根目录"); - BizFolders secondQuery = new BizFolders(); - secondQuery.setParentId(firstFolder.getFolderId()); - secondQuery.setIsDeleted(0); - List secondLevelFolders = bizFoldersService.findList(secondQuery); - List> secondNodeList = new ArrayList<>(); - for (BizFolders secondFolder : secondLevelFolders) { - Map secondNode = MyUtils.convertToTreeNode(secondFolder, firstFolder.getFolderName()); - BizFolders thirdQuery = new BizFolders(); - thirdQuery.setParentId(secondFolder.getFolderId()); - thirdQuery.setIsDeleted(0); - List thirdLevelFolders = bizFoldersService.findList(thirdQuery); - List> thirdNodeList = new ArrayList<>(); - for (BizFolders thirdFolder : thirdLevelFolders) { - Map thirdNode = MyUtils.convertToTreeNode(thirdFolder, secondFolder.getFolderName()); - BizFolders fourthQuery = new BizFolders(); - fourthQuery.setParentId(thirdFolder.getFolderId()); - fourthQuery.setIsDeleted(0); - List fourthLevelFolders = bizFoldersService.findList(fourthQuery); - List> fourthNodeList = new ArrayList<>(); - for (BizFolders fourthFolder : fourthLevelFolders) { - Map fourthNode = MyUtils.convertToTreeNode(fourthFolder, thirdFolder.getFolderName()); - fourthNodeList.add(fourthNode); - } - thirdNode.put("children", fourthNodeList); - thirdNodeList.add(thirdNode); + // 1. 一次性查询所有未删除的文件夹 + BizFolders query = new BizFolders(); + query.setIsDeleted(0); + List allFolders = bizFoldersService.findList(query); + // 2. 按parentId分组,构建映射Map + Map> folderMap = allFolders.stream() + .collect(Collectors.groupingBy(BizFolders::getParentId, Collectors.toList())); + // 3. 递归构建树形结构的核心逻辑(内部递归方法) + Function>> buildTree = new Function>>() { + @Override + public List> apply(String parentId) { + List> nodeList = new ArrayList<>(); + List childFolders = folderMap.getOrDefault(parentId, new ArrayList<>()); + for (BizFolders folder : childFolders) { + // 转换为节点 + Map node = MyUtils.convertToTreeNode(folder, + parentId.equals("0") ? "根目录" : getFolderNameById(folderMap, parentId)); + // 递归获取子节点 + node.put("children", this.apply(folder.getFolderId())); + nodeList.add(node); } - secondNode.put("children", thirdNodeList); - secondNodeList.add(secondNode); + return nodeList; } - firstNode.put("children", secondNodeList); - firstNodeList.add(firstNode); - } - rootNode.put("children", firstNodeList); + // 辅助方法:根据folderId获取文件夹名称 + private String getFolderNameById(Map> folderMap, String folderId) { + for (List folders : folderMap.values()) { + for (BizFolders f : folders) { + if (folderId.equals(f.getFolderId())) { + return f.getFolderName(); + } + } + } + return ""; + } + }; + // 4. 构建根节点的子节点并返回 + rootNode.put("children", buildTree.apply("0")); treeData.add(rootNode); return treeData; } @@ -213,53 +213,47 @@ public class BizFoldersController extends BaseController { @RequestMapping(value = "treeData") @ResponseBody public List> treeFoldersData(BizFolders bizFolders) { + // 1. 构建根节点 List> treeData = new ArrayList<>(); Map rootNode = new HashMap<>(); rootNode.put("id", "0"); rootNode.put("name", "根目录"); rootNode.put("disabled", false); - rootNode.put("children", new ArrayList<>()); - bizFolders.setParentId("0"); - bizFolders.setIsDeleted(0); - List firstLevelFolders = bizFoldersService.findList(bizFolders); - List> firstNodeList = new ArrayList<>(); - for (BizFolders firstFolder : firstLevelFolders) { - Map firstNode = MyUtils.convertToTreeNode(firstFolder, false); - BizFolders secondQuery = new BizFolders(); - secondQuery.setParentId(firstFolder.getFolderId()); - secondQuery.setIsDeleted(0); - List secondLevelFolders = bizFoldersService.findList(secondQuery); - List> secondNodeList = new ArrayList<>(); - for (BizFolders secondFolder : secondLevelFolders) { - Map secondNode = MyUtils.convertToTreeNode(secondFolder, false); - BizFolders thirdQuery = new BizFolders(); - thirdQuery.setParentId(secondFolder.getFolderId()); - thirdQuery.setIsDeleted(0); - List thirdLevelFolders = bizFoldersService.findList(thirdQuery); - List> thirdNodeList = new ArrayList<>(); - for (BizFolders thirdFolder : thirdLevelFolders) { - Map thirdNode = MyUtils.convertToTreeNode(thirdFolder, false); - BizFolders fourthQuery = new BizFolders(); - fourthQuery.setParentId(thirdFolder.getFolderId()); - fourthQuery.setIsDeleted(0); - List fourthLevelFolders = bizFoldersService.findList(fourthQuery); - List> fourthNodeList = new ArrayList<>(); - for (BizFolders fourthFolder : fourthLevelFolders) { - Map fourthNode = MyUtils.convertToTreeNode(fourthFolder, bizFolders.getDescription().equals("add") ? true : false); - fourthNode.put("children", new ArrayList<>()); - fourthNodeList.add(fourthNode); - } - thirdNode.put("children", fourthNodeList); - thirdNodeList.add(thirdNode); + // 2. 一次性查询所有未删除的文件夹(仅1次数据库查询) + BizFolders query = new BizFolders(); + query.setIsDeleted(0); + List allFolders = bizFoldersService.findList(query); + // 3. 按parentId分组,快速查找子节点 + Map> folderMap = allFolders.stream() + .collect(Collectors.groupingBy(BizFolders::getParentId, Collectors.toList())); + final List>>> recursiveHolder = new ArrayList<>(); + // 匿名内部类实现递归逻辑(BiFunction:入参parentId+level,出参节点列表) + java.util.function.BiFunction>> buildTree = new java.util.function.BiFunction>>() { + @Override + public List> apply(String parentId, Integer level) { + List> nodeList = new ArrayList<>(); + // 空值保护:获取当前父ID下的子文件夹 + List childFolders = folderMap.getOrDefault(parentId, new ArrayList<>()); + for (BizFolders folder : childFolders) { + // 原业务逻辑:四级节点特殊处理,其他传false + boolean flag = level == 4 ? "add".equals(bizFolders.getDescription()) : false; + Map node = MyUtils.convertToTreeNode(folder, flag); + // 递归调用自身(通过holder获取) + List> children = recursiveHolder.get(0).apply(folder.getFolderId(), level + 1); + // 无子节点时设为空列表(和原代码一致) + node.put("children", children.isEmpty() ? new ArrayList<>() : children); + nodeList.add(node); } - secondNode.put("children", thirdNodeList); - secondNodeList.add(secondNode); + return nodeList; } - firstNode.put("children", secondNodeList); - firstNodeList.add(firstNode); - } - rootNode.put("children", firstNodeList); + }; + + // 将递归逻辑放入holder,供内部调用 + recursiveHolder.add(buildTree); + // 5. 从根节点(parentId=0,层级1)开始构建 + rootNode.put("children", buildTree.apply("0", 1)); treeData.add(rootNode); + return treeData; } } \ No newline at end of file diff --git a/web-vue/packages/biz/api/biz/myWork.ts b/web-vue/packages/biz/api/biz/myWork.ts index 77e2a325..5070be20 100644 --- a/web-vue/packages/biz/api/biz/myWork.ts +++ b/web-vue/packages/biz/api/biz/myWork.ts @@ -17,7 +17,33 @@ export interface MyWorkInfo extends BasicModel { calendarNums?: number; calendarAllNums?: number; teamNums?: number; -} +} + + +export interface DockerInfo extends BasicModel { + name?: string; + id: string; + cid: string; + createTime?: string; + imageName?: string; + mapPorts?: string; + status?: string; + state?: string; + cpuUsage?: string; + memUsage?: string; +} export const bizMyWorkInfoList = () => - defHttp.get({ url: adminPath + '/biz/myWork/list'}); + defHttp.get({ url: adminPath + '/biz/myWork/list'}); + +export const bizDockerInfoList = (params?: DockerInfo | any) => + defHttp.get({ url: adminPath + '/biz/myWork/dockerList' , params }); + +export const bizDockerRestart = (params?: DockerInfo | any) => + defHttp.get({ url: adminPath + '/biz/myWork/restart', params }); + +export const bizDockerStart = (params?: DockerInfo | any) => + defHttp.get({ url: adminPath + '/biz/myWork/start', params }); + +export const bizDockerStop = (params?: DockerInfo | any) => + defHttp.get({ url: adminPath + '/biz/myWork/stop', params }); \ No newline at end of file diff --git a/web-vue/packages/biz/views/biz/mailInfo/received/list.vue b/web-vue/packages/biz/views/biz/mailInfo/received/list.vue index 55dd4834..82deadcb 100644 --- a/web-vue/packages/biz/views/biz/mailInfo/received/list.vue +++ b/web-vue/packages/biz/views/biz/mailInfo/received/list.vue @@ -95,7 +95,7 @@ component: 'Input', }, { - label: t('是否有附件'), + label: t('有无附件'), field: 'hasAttachment', component: 'Select', componentProps: { @@ -138,7 +138,7 @@ dataIndex: 'fromAddress', key: 'a.from_address', sorter: true, - width: 130, + width: 225, align: 'left', }, { @@ -146,20 +146,12 @@ dataIndex: 'subject', key: 'a.subject', sorter: true, - width: 425, + width: 1000, align: 'left', slot: 'slotBizKey', }, { - title: t('接收时间'), - dataIndex: 'receivedTime', - key: 'a.received_time', - sorter: true, - width: 180, - align: 'center', - }, - { - title: t('是否有附件'), + title: t('有无附件'), dataIndex: 'hasAttachment', key: 'a.has_attachment', sorter: true, diff --git a/web-vue/packages/biz/views/biz/mailInfo/received/view.vue b/web-vue/packages/biz/views/biz/mailInfo/received/view.vue index d85050d5..e3952d2d 100644 --- a/web-vue/packages/biz/views/biz/mailInfo/received/view.vue +++ b/web-vue/packages/biz/views/biz/mailInfo/received/view.vue @@ -19,8 +19,8 @@
邮件内容 暂无邮件内容 -
-
+ +
@@ -66,7 +66,14 @@ emits: ['modalClose'], setup(props, { emit }) { const ReceivedList = ref(); - const MailAttachments = ref([]); + const MailAttachments = ref([]); + + const decodeHtmlEntities = (html: string) => { + if (!html) return ''; + const txt = document.createElement('textarea'); + txt.innerHTML = html; + return txt.value.replace(/\s+/g, ' ').trim(); + }; const [register, { closeModal }] = useModalInner(async (data: any) => { if (!data) return; @@ -123,7 +130,8 @@ ReceivedList, MailAttachments, downloadAttachment, - formatFileSize, + formatFileSize, + decodeHtmlEntities }; }, }); @@ -234,7 +242,7 @@ padding: 14px; margin: 0; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; - white-space: pre-wrap; + white-space: normal; word-break: break-all; color: #333; flex: 1; diff --git a/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue b/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue index 6e11c024..80668b8e 100644 --- a/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue +++ b/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue @@ -95,9 +95,18 @@ label: t('邮件主题'), field: 'subject', component: 'Input', - }, + }, + { + label: t('有无附件'), + field: 'hasAttachment', + component: 'Select', + componentProps: { + dictType: 'has_attachment', + allowClear: true, + }, + }, { - label: t('发送状态'), + label: t('状态'), field: 'sendStatus', component: 'Select', componentProps: { @@ -105,15 +114,6 @@ allowClear: true, }, }, - { - label: t('有无附件'), - field: 'hasAttachment', - component: 'Select', - componentProps: { - dictType: 'has_attachment', - allowClear: true, - }, - }, ], }; diff --git a/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue b/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue index 4909d5b0..887a15be 100644 --- a/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue +++ b/web-vue/packages/core/layouts/views/desktop/analysis/components/DynamicInfo.vue @@ -6,9 +6,11 @@
- {{ item.sysHostname || '未知IP' }} + {{ item.sysHostname || '未知IP' }} - {{ item.ustatus === '1' ? '运行中' : '已离线' }} + + {{ item.ustatus === '1' ? '运行中' : '已离线' }} +
@@ -67,7 +69,8 @@
- + + + + \ No newline at end of file diff --git a/web-vue/packages/core/layouts/views/desktop/analysis/components/info/Echart/Monitor.vue b/web-vue/packages/core/layouts/views/desktop/analysis/components/info/Echart/Monitor.vue index 70457612..5443fc7c 100644 --- a/web-vue/packages/core/layouts/views/desktop/analysis/components/info/Echart/Monitor.vue +++ b/web-vue/packages/core/layouts/views/desktop/analysis/components/info/Echart/Monitor.vue @@ -36,15 +36,13 @@ const chartDom = ref(null); const statusOptions = ref([ { value: '-12', label: '12小时' }, { value: '-24', label: '24小时' }, - { value: '-36', label: '36小时' }, + { value: '-48', label: '48小时' }, { value: '-72', label: '72小时' }, ]); const currentStatus = ref('-12'); -// 防抖处理resize,避免频繁触发 const resizeHandler = () => { if (chartInstance.value) { - // 使用nextTick确保DOM更新完成后再调整大小 nextTick(() => { chartInstance.value?.resize({ animation: { duration: 200 } diff --git a/web-vue/packages/core/layouts/views/desktop/workbench/components/tableInfo/formImport.vue b/web-vue/packages/core/layouts/views/desktop/workbench/components/tableInfo/formImport.vue deleted file mode 100644 index cd6c0615..00000000 --- a/web-vue/packages/core/layouts/views/desktop/workbench/components/tableInfo/formImport.vue +++ /dev/null @@ -1,103 +0,0 @@ - - - diff --git a/web-vue/packages/core/layouts/views/desktop/workbench/components/tableInfo/list.vue b/web-vue/packages/core/layouts/views/desktop/workbench/components/tableInfo/list.vue deleted file mode 100644 index 058d4975..00000000 --- a/web-vue/packages/core/layouts/views/desktop/workbench/components/tableInfo/list.vue +++ /dev/null @@ -1,262 +0,0 @@ - - - diff --git a/web-vue/packages/core/layouts/views/desktop/workbench/index.vue b/web-vue/packages/core/layouts/views/desktop/workbench/index.vue index 0495112c..eb30ca6a 100644 --- a/web-vue/packages/core/layouts/views/desktop/workbench/index.vue +++ b/web-vue/packages/core/layouts/views/desktop/workbench/index.vue @@ -11,9 +11,6 @@ - - - @@ -23,7 +20,6 @@ import { Tag, Tabs, TabPane } from 'ant-design-vue'; import MySchedule from './components/MySchedule.vue'; import Calendar from './components/calendar/list.vue'; - import TableInfo from './components/tableInfo/list.vue'; import ItemsInfo from './components/listItem/list.vue'; import MyfileInfo from './components/myfiles/index.vue';