Compare commits

...

22 Commits

Author SHA1 Message Date
tomsun28
0281e5f0c2 [web-app]i18n for notify 2022-04-11 22:58:22 +08:00
tomsun28
89efd96448 [web-app]i18n for alert setting 2022-04-11 22:35:36 +08:00
tomsun28
1126d2e41e [web-app]i18n for alert notice 2022-04-11 18:11:54 +08:00
tomsun28
b78f463ed1 [web-app]i18n for alert center 2022-04-11 13:21:22 +08:00
tomsun28
2de1aa4069 [web-app]i18n for login 2022-04-11 11:42:48 +08:00
tomsun28
95a062eff4 [web-app]i18n for monitor detail 2022-04-11 11:15:35 +08:00
tomsun28
7fbf112240 [web-app]i18n for add edit monitor 2022-04-11 10:13:31 +08:00
tomsun28
a3d1f08b39 [web-app]i18n for monitor list 2022-04-11 08:06:55 +08:00
tomsun28
f685298741 [web-app]dashboard and monitor list i18n 2022-04-10 22:14:20 +08:00
tomsun28
a7658624ab [docs]support en webapp 2022-04-10 19:15:42 +08:00
tomsun28
69af6d2a12 [docs]support en docs 2022-04-10 17:14:05 +08:00
tomsun28
c79f66dd9f [script]update service startup script 2022-04-08 21:28:30 +08:00
tomsun28
835df039e8 [home]add v1.0-beat.7 publish blog 2022-04-08 19:50:45 +08:00
tomsun28
f23ea9ffd5 [docs]update gif show 2022-04-08 08:00:44 +08:00
tomsun28
7994d7ef15 [script,docs]change version 1.0-beta.6 to 1.0-beta.7 2022-04-07 20:33:52 +08:00
tomsun28
323e5f8981 [git]ignore dependency 2022-04-07 19:59:01 +08:00
tomsun28
e1916b937e [monitor]feature:support linux cpu usage,memory usage,disk free (#76) 2022-04-07 17:51:48 +08:00
tomsun28
2ecf40e873 [manager]bugfix:fix linux interface metrics no instance (#75) 2022-04-07 14:25:11 +08:00
常清静矣
63ea0a87f7 [manager] bugfix: remove oracle field - database_type due 11g not support 2022-04-06 14:49:31 +00:00
学习代码的小白
a3f4e42034 [manager]code format and optimization 2022-04-06 14:46:49 +00:00
tomsun28
018db2a14f [manager]feature:[website api]monitor support keyword match (#72) 2022-04-06 10:26:33 +08:00
tomsun28
f238a1d4ea [manager]feature:only collect available metrics when detect (#70) 2022-04-06 08:32:38 +08:00
64 changed files with 1657 additions and 699 deletions

6
.gitignore vendored
View File

@@ -37,4 +37,10 @@ nbdist/
### VS Code ###
.vscode/
# dependencies
node_modules
.docusaurus
yarn.lock
# debug env
application-dev.yml

View File

@@ -6,7 +6,7 @@
[comment]: <> (<img alt="sureness" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/hertzbeat-brand.svg" width="300">)
## HertzBeat 赫兹跳动
## HertzBeat 赫兹跳动 | [English Documentation](README_EN.md)
> 易用友好的监控告警系统。
@@ -35,7 +35,7 @@
----
[![tancloud](tancloud.gif)](https://www.bilibili.com/video/BV1Vi4y1f7i8)
[![tancloud](tancloud.gif)](https://www.bilibili.com/video/BV1DY4y1i7ts)
----
@@ -76,7 +76,7 @@
##### 安装TDengine
1. docker安装TDengine
`docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/tcp -p 6030-6049:6030-6049/udp --name tdengine tdengine/tdengine:2.4.0.12`
`docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp --name tdengine tdengine/tdengine:2.4.0.12`
2. 创建名称为hertzbeat的数据库
详细步骤参考 [依赖服务TDengine安装初始化](https://hertzbeat.com/docs/start/tdengine-init)
@@ -93,6 +93,7 @@
1. 下载您系统环境对应的安装包 [GITEE Release](https://gitee.com/dromara/hertzbeat/releases) [GITHUB Release](https://github.com/dromara/hertzbeat/releases)
2. 配置HertzBeat的配置文件 hertzbeat/config/application.yml
3. 部署启动 `$ ./startup.sh `
4. 浏览器访问 localhost:1157 即可开始,默认账号密码 admin/admin
详细步骤参考 [通过安装包安装HertzBeat](https://hertzbeat.com/docs/start/package-deploy)

148
README_EN.md Normal file
View File

@@ -0,0 +1,148 @@
<p align="center">
<a href="https://hertzbeat.com">
<img alt="hertzbeat" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/hertzbeat-brand.svg" width="260">
</a>
</p>
[comment]: <> (<img alt="sureness" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/hertzbeat-brand.svg" width="300">)
## HertzBeat | [中文文档](README.md)
> Friendly cloud monitoring system.
![tan-cloud](https://img.shields.io/badge/web-monitor-4EB1BA)
![tan-cloud](https://img.shields.io/badge/api-monitor-lightgrey)
![tan-cloud](https://img.shields.io/badge/ping-connect-brightgreen)
![tan-cloud](https://img.shields.io/badge/port-available-green)
![tan-cloud](https://img.shields.io/badge/database-monitor-yellowgreen)
![tan-cloud](https://img.shields.io/badge/os-monitor-yellow)
![tan-cloud](https://img.shields.io/badge/custom-monitor-orange)
![tan-cloud](https://img.shields.io/badge/threshold-red)
![tan-cloud](https://img.shields.io/badge/alert-bule)
**Home: [hertzbeat.com](https://hertzbeat.com) | [tancloud.cn](https://tancloud.cn)**
## 🎡 <font color="green">Introduction</font>
> [HertzBeat](https://github.com/dromara/hertzbeat) is an opensource monitoring and alarm project incubated by [Dromara](https://dromara.org) and open sourced by [TanCloud](https://tancloud.cn), which supports Website, API, PING, Port, Database, OS Monitor etc.
> We also provide **[Monitoring Cloud For Saas](https://console.tancloud.cn)**, people no longer need to deploy a cumbersome monitoring system in order to monitor their website resources. **[Sign in to get started for free](https://console.tancloud.cn)**.
> HertzBeat supports more liberal threshold alarm configuration (calculation expression), supports alarm notification, alarm template, email, DingDing, WeChat FeiShu and WebHook.
> Most important is HertzBeat supports [Custom Monitoring](https://hertzbeat.com/docs/advanced/extend-point), just by configuring the YML file, we can customize the monitoring types and metrics what we need.
> HertzBeat is modular, `manager, collector, scheduler, warehouse, alerter` modules are decoupled for easy understanding and custom development.
> Welcome to HertzBeat's [Cloud Environment TanCloud](https://console.tancloud.cn) to try and discover more.
> Welcome to join us to build hertzbeat together.
> `HertzBeat`'s multi-type support, easy expansion, low coupling, hope to help developers and micro teams to quickly build their own monitoring system.
----
[![tancloud](tancloud.gif)](https://www.bilibili.com/video/BV1DY4y1i7ts)
----
## 🥐 Architecture
- **[manager](https://github.com/dromara/hertzbeat/tree/master/manager)** Provide monitoring management, system management basic services.
> Provides monitoring management, monitoring configuration management, system user management, etc.
- **[collector](https://github.com/dromara/hertzbeat/tree/master/collector)** Provide metrics data collection services.
> Use common protocols to remotely collect and obtain peer-to-peer metrics data.
- **[scheduler](https://github.com/dromara/hertzbeat/tree/master/scheduler)** Provide monitoring task scheduling service.
> Collection task management, scheduling and distribution of one-time tasks and periodic tasks.
- **[warehouse](https://github.com/dromara/hertzbeat/tree/master/warehouse)** Provide monitoring data warehousing services.
> Metrics data management, data query, calculation and statistics.
- **[alerter](https://github.com/dromara/hertzbeat/tree/master/alerter)** Provide alert service.
> Alarm calculation trigger, monitoring status linkage, alarm configuration, and alarm notification.
- **[web-app](https://github.com/dromara/hertzbeat/tree/master/web-app)** Provide web ui.
> Angular Web UI.
![hertzBeat](home/static/img/docs/hertzbeat-stru-en.svg)
## 🐕 Quick Start
- If you dont want to deploy but use it directly, we provide [SAAS Monitoring Cloud-TanCloud](https://console.tancloud.cn), **[Log In And Register For Free](https://console.tancloud.cn) **.
- If you want to deploy HertzBeat local, please refer to the following [Deployment Documentation](https://hertzbeat.com/docs/start/quickstart) for operation.
### 🐵 Dependency Service Deployment
> HertzBeat depends at least on relational database [MYSQL5+](https://www.mysql.com/) and time series database [TDengine2+](https://www.taosdata.com/getting-started)
##### Install MYSQL
1. Install mysql with docker
`docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7`
2. Create database names `hertzbeat`
3. Run the database sql script [schema.sql](https://gitee.com/dromara/hertzbeat/raw/master/script/sql/schema.sql) located in the project repository `/script/sql/` directory.
For detailed steps, refer to [MYSQL Installation And Initialization](https://hertzbeat.com/docs/start/mysql-init)
##### Install TDengine
1. Install TDengine with docker
`docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp --name tdengine tdengine/tdengine:2.4.0.12`
2. Create database names `hertzbeat`
For detailed steps, refer to [TDengine Installation And Initialization](https://hertzbeat.com/docs/start/tdengine-init).
### 🍞 Install HertzBeat
> HertzBeat supports installation through source code, docker or package.
##### 1Install quickly via docker
`docker run -d -p 1157:1157 -v /opt/application.yml:/opt/hertzbeat/config/application.yml --name hertzbeat tancloud/hertzbeat:[版本tag]`
Detailed steps refer to [Install HertzBeat via Docker](https://hertzbeat.com/docs/start/docker-deploy)
##### 2Install via package
1. Download the installation package [GITEE Release](https://gitee.com/dromara/hertzbeat/releases) [GITHUB Release](https://github.com/dromara/hertzbeat/releases)
2. Configure the HertzBeat configuration yml file `hertzbeat/config/application.yml`
3. Run shell `$ ./startup.sh `
4. Access `localhost:1157` to start, default account: `admin/admin`
Detailed steps refer to [Install HertzBeat via package](https://hertzbeat.com/docs/start/package-deploy)
##### 3Start via source code
1. Local source code debugging needs to start the back-end project manager and the front-end project web-app.
2. Backendneed `maven3+`, `java8+`, start the manager service.
3. Webneed `nodejs npm angular-cli` environment, Run `ng serve --open` in `web-app` directory after backend startup.
4. Access `localhost:4200` to start, default account: `admin/admin`
Detailed steps refer to [CONTRIBUTING](CONTRIBUTING.md)
##### 4Install All(mysql+tdengine+hertzbeat) via Docker-compose
Install and deploy the mysql database, tdengine database and hertzbeat at one time through [docker-compose deployment script](script/docker-compose).
Detailed steps refer to [docker-compose install](script/docker-compose/README.md)
**HAVE FUN**
## 💬 Join discussion
HertzBeat is an incubation project of [Dromara Open Source Community](https://dromara.org/).
##### WeChat Group
Add WeChat account `tan-cloud` or scan the QR code below to pull you into the WeChat group.
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/docs/help/tan-cloud-wechat.jpg" width="200"/>
##### QQ Group
QQ group number `718618151` or scan the group QR code below, verify code: `tancloud`
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/docs/help/qq-qr.jpg" width="200"/>
##### Github Discussion
Welcome to Discuss in [Github Discussion](https://github.com/dromara/hertzbeat/discussions)
##### Public WeChat
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/wechat.png" width="400"/>
##### Sponsor
Thanks [吉实信息(构建全新的微波+光交易网络)](https://www.flarespeed.com) sponsored server node.
Thanks [天上云计算(全新智慧上云)](https://www.tsyvps.com/aff/BZBEGYLX) sponsored server node.
## 🛡️ License
[`Apache License, Version 2.0`](https://www.apache.org/licenses/LICENSE-2.0.html)

View File

@@ -7,6 +7,7 @@ import com.google.gson.JsonParser;
import com.usthe.collector.collect.AbstractCollect;
import com.usthe.collector.collect.common.http.CommonHttpClient;
import com.usthe.collector.dispatch.DispatchConstants;
import com.usthe.collector.util.CollectUtil;
import com.usthe.collector.util.CollectorConstants;
import com.usthe.collector.util.JsonPathParser;
import com.usthe.common.entity.job.Metrics;
@@ -100,7 +101,7 @@ public class HttpCollectImpl extends AbstractCollect {
String parseType = metrics.getHttp().getParseType();
try {
if (DispatchConstants.PARSE_DEFAULT.equals(parseType)) {
parseResponseByDefault(resp, metrics.getAliasFields(), builder, responseTime);
parseResponseByDefault(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
} else if (DispatchConstants.PARSE_JSON_PATH.equals(parseType)) {
parseResponseByJsonPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
} else if (DispatchConstants.PARSE_PROMETHEUS.equals(parseType)) {
@@ -108,11 +109,11 @@ public class HttpCollectImpl extends AbstractCollect {
} else if (DispatchConstants.PARSE_XML_PATH.equals(parseType)) {
parseResponseByXmlPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder);
} else if (DispatchConstants.PARSE_WEBSITE.equals(parseType)){
parseResponseByWebsite(resp, metrics.getAliasFields(), builder, responseTime);
parseResponseByWebsite(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
} else if (DispatchConstants.PARSE_SITE_MAP.equals(parseType)) {
parseResponseBySiteMap(resp, metrics.getAliasFields(), builder);
} else {
parseResponseByDefault(resp, metrics.getAliasFields(), builder, responseTime);
parseResponseByDefault(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
}
} catch (Exception e) {
log.info("parse error: {}.", e.getMessage(), e);
@@ -169,13 +170,16 @@ public class HttpCollectImpl extends AbstractCollect {
}
}
private void parseResponseByWebsite(String resp, List<String> aliasFields,
private void parseResponseByWebsite(String resp, List<String> aliasFields, HttpProtocol http,
CollectRep.MetricsData.Builder builder, Long responseTime) {
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
// todo resp 网站关键监测
// 网站关键词数量监测
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
for (String alias : aliasFields) {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(responseTime.toString());
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(Integer.toString(keywordNum));
} else {
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
}
@@ -277,6 +281,7 @@ public class HttpCollectImpl extends AbstractCollect {
private void parseResponseByJsonPath(String resp, List<String> aliasFields, HttpProtocol http,
CollectRep.MetricsData.Builder builder, Long responseTime) {
List<Map<String, Object>> results = JsonPathParser.parseContentWithJsonPath(resp, http.getParseScript());
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
for (Map<String, Object> stringMap : results) {
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
for (String alias : aliasFields) {
@@ -286,6 +291,8 @@ public class HttpCollectImpl extends AbstractCollect {
} else {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(responseTime.toString());
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(Integer.toString(keywordNum));
} else {
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
}
@@ -300,9 +307,10 @@ public class HttpCollectImpl extends AbstractCollect {
}
private void parseResponseByDefault(String resp, List<String> aliasFields,
private void parseResponseByDefault(String resp, List<String> aliasFields, HttpProtocol http,
CollectRep.MetricsData.Builder builder, Long responseTime) {
JsonElement element = JsonParser.parseString(resp);
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
if (element.isJsonArray()) {
JsonArray array = element.getAsJsonArray();
for (JsonElement jsonElement : array) {
@@ -317,6 +325,8 @@ public class HttpCollectImpl extends AbstractCollect {
} else {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(responseTime.toString());
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(Integer.toString(keywordNum));
} else {
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
}

View File

@@ -247,6 +247,10 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
value = aliasFieldValueMap.get(realField);
}
}
// 处理可能带单位的指标数值 比如 34%, 34Mb并将数值小数点限制到4位
if (CommonConstants.TYPE_NUMBER == field.getType()) {
value = CommonUtil.parseDoubleStr(value, field.getUnit());
}
if (value == null) {
value = CommonConstants.NULL_VALUE;
}

View File

@@ -0,0 +1,35 @@
package com.usthe.collector.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 采集器工具类
* @author tom
* @date 2022/4/6 09:35
*/
public class CollectUtil {
/**
* 关键字匹配计数
* @param content 内容
* @param keyword 关键字
* @return 匹配次数
*/
public static int countMatchKeyword(String content, String keyword) {
if (content == null || "".equals(content) || keyword == null || "".equals(keyword.trim())) {
return 0;
}
try {
Pattern pattern = Pattern.compile(keyword);
Matcher matcher = pattern.matcher(content);
int count = 0;
while (matcher.find()) {
count++;
}
return count;
} catch (Exception e) {
return 0;
}
}
}

View File

@@ -9,6 +9,8 @@ public interface CollectorConstants {
String RESPONSE_TIME = "responseTime";
String KEYWORD = "keyword";
String STATUS_CODE = "statusCode";
String ERROR_MSG = "errorMsg";

View File

@@ -4,6 +4,7 @@ import org.apache.commons.net.telnet.TelnetClient;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.ConnectException;
import static org.junit.jupiter.api.Assertions.*;
@@ -20,7 +21,7 @@ class TelnetCollectImplTest {
telnetClient = new TelnetClient("vt200");
telnetClient.setConnectTimeout(5000);
TelnetClient finalTelnetClient = telnetClient;
assertDoesNotThrow(() -> finalTelnetClient.connect("baidu.com",80));
assertThrows(ConnectException.class,() -> finalTelnetClient.connect("127.0.0.1",0));
telnetClient.disconnect();
} catch (IOException e) {
e.printStackTrace();

View File

@@ -49,7 +49,6 @@ public class HttpProtocol {
* http请求携带的请求体
*/
private String payload;
/**
* 认证信息
*/
@@ -66,6 +65,10 @@ public class HttpProtocol {
* 数据解析脚本 当解析方式为 jsonPath or xmlPath时存在
*/
private String parseScript;
/**
* 内容关键字
*/
private String keyword;
/**
* 认证信息

View File

@@ -2,6 +2,8 @@ package com.usthe.common.util;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -15,7 +17,7 @@ public class CommonUtil {
private static final Pattern EMAIL_PATTERN = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
private static final Pattern PHONE_PATTERN = Pattern.compile("^(((13[0-9])|(15[0-9])|(18[0-9])|(17[0-9]))+\\d{8})?$");
private static final Pattern PHONE_PATTERN = Pattern.compile("^(((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(19[0-9])|(18[0-9])|(17[0-9]))+\\d{8})?$");
private static final int PHONE_LENGTH = 11;
@@ -36,6 +38,30 @@ public class CommonUtil {
}
}
/**
* 将字符串str,此字符串可能带单位,转换为double数字类型
* 将数值小数点限制到4位
* @param str string
* @param unit 字符串单位
* @return string格式的 double 数字 小数点最大到4位
*/
public static String parseDoubleStr(String str, String unit) {
if (str == null || "".equals(str)) {
return null;
}
try {
if (unit != null && str.endsWith(unit)) {
str = str.substring(0, str.length() - unit.length());
}
BigDecimal bigDecimal = new BigDecimal(str);
double value = bigDecimal.setScale(4, RoundingMode.HALF_UP).doubleValue();
return String.valueOf(value);
} catch (Exception e) {
log.debug(e.getMessage(), e);
return null;
}
}
/**
* 邮箱格式校验
* @param email 邮箱

View File

@@ -0,0 +1,40 @@
package com.usthe.common.util;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author tom
* @date 2022/4/7 17:18
*/
class CommonUtilTest {
@Test
void testParseDoubleStr() {
assertEquals("9.3454",CommonUtil.parseDoubleStr("9.345435345", null));
assertEquals("9.3454",CommonUtil.parseDoubleStr("9.345435345%", "%"));
assertEquals("10.0",CommonUtil.parseDoubleStr("10%", "%"));
assertEquals("588.0",CommonUtil.parseDoubleStr("588Mb", "Mb"));
}
@Test
void validateEmail() {
assertTrue(CommonUtil.validateEmail("tom@usthe.com"));
assertTrue(CommonUtil.validateEmail("demo@qq.com"));
assertFalse(CommonUtil.validateEmail("tom.usthe.com"));
}
@Test
void validatePhoneNum() {
assertTrue(CommonUtil.validatePhoneNum("19234554432"));
assertTrue(CommonUtil.validatePhoneNum("13234554432"));
assertTrue(CommonUtil.validatePhoneNum("14234554432"));
assertTrue(CommonUtil.validatePhoneNum("16234554432"));
assertFalse(CommonUtil.validatePhoneNum("12234554432"));
assertFalse(CommonUtil.validatePhoneNum("11234554432"));
assertFalse(CommonUtil.validatePhoneNum("35234554432"));
assertFalse(CommonUtil.validatePhoneNum("46234554432"));
}
}

View File

@@ -0,0 +1,92 @@
---
title: HertzBeat入GVP啦并 v1.0.beta.7 发布,易用友好的云监控系统
author: tom
author_title: tom
author_url: https://github.com/tomsun28
author_image_url: https://avatars.githubusercontent.com/u/24788200?s=400&v=4
tags: [opensource]
---
HertzBeat赫兹跳动 是一个由Dromara孵化的支持网站APIPING端口数据库全站操作系统等监控类型支持阈值告警告警通知(邮箱webhook钉钉企业微信飞书机器人),拥有易用友好的可视化操作界面的开源监控告警项目。
很高兴Hertzbeat被评定为GVP - Gitee最有价值开源项目
![截屏2022-04-08 09.14.44.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8899bc4e836943dba2ec9efeec4ff629~tplv-k3u1fbpfcp-watermark.image?)
老哥们帮忙在Gitee STAR起来https://gitee.com/dromara/hertzbeat
官网:hertzbeat.com | tancloud.cn
然后来说说最新的版本这个版本看这么多feature其实简单来说主要是这几个
支持了ORACLE数据库的监控包括ORACLE的基本信息表空间连接数TPSQPS等指标
支持了LINUX的CPU利用率内存利用率磁盘占用相关指标使LINUX监控贴合实际业务
还有前端参数支持了KEY-VALUE以后我们就可以在页面上配置HTTP Headers等类似参数了还有就是参数配置那优化改版把非常用告警参数隐藏起来了稍微好看些然后支持了windows下bat启动脚本更多的就是稳定性的提升和一些其它的小修复小需求啦
版本特性:
1. feature 支持oracle数据库监控类型-xgf 由 @gf-8 贡献 thanks
2. feature oracle监控支持tablespace,连接数,qps,tps等指标
3. feature linux监控支持设置超时时间 (#49)
4. feature 检测网站SSL证书是否过期 (#50) 由 @weihongbin 提出 thanks
5. feature 页面配置参数支持KEY-VALUE数组(#57)
6. feature API和网站监控支持页面配置Headers和Params (#58)(#59)
7. feature API和网站监控支持页面配置 basic auth, digest auth (#60)
8. feature http 端口跟随SSL是否启用变更443或80 (#61)
9. feature 修改默认超时时间3000毫秒为6000毫秒 (#55)
10. feature:make tdengine optional, not required (#62)
11. feature:support win bat service (#65)
12. feature:support hide advanced params define (#68)
13. feature:enable auto redirect when 301 302 http code (#69)
14. feature:only collect available metrics when detect (#70)
15. feature:[website api]monitor support keyword match (#72)
16. feature:support linux cpu usage,memory usage,disk free (#76)
BUG修复
1. 添加sqlserver关联文档fix connection指标入库tdengine失败 (#41)
2. 使用docker部署TDengine开放tcp访问端口!16 由 @老姜bei 贡献 thanks
3. 补充sureness配置文档 避免误配导致权限异常
4. bugfix:monitors always timeout alert (#67)
5. code format and optimization 由 @学习代码的小白 贡献 thanks
6. bugfix: remove oracle field - database_type due 11g not support 由 @syongaaa 贡献 thanks
7. bugfix:fix linux interface metrics no instance (#75)
欢迎在线试用 https://console.tancloud.cn.
-----------------------
> [HertzBeat赫兹跳动](https://github.com/dromara/hertzbeat) 是一个支持网站APIPING端口数据库操作系统等监控类型拥有易用友好的可视化操作界面的开源监控告警项目。
> 我们也提供了对应的 **[SAAS版本监控云](https://console.tancloud.cn)**,中小团队和个人无需再为了监控自己的网站资源,而去部署一套繁琐的监控系统,**[登录即可免费开始](https://console.tancloud.cn)**。
> HertzBeat 支持[自定义监控](https://hertzbeat.com/docs/advanced/extend-point) ,只用通过配置YML文件我们就可以自定义需要的监控类型和指标来满足常见的个性化需求。
> HertzBeat 模块化,`manager, collector, scheduler, warehouse, alerter` 各个模块解耦合,方便理解与定制开发。
> HertzBeat 支持更自由化的告警配置(计算表达式),支持告警通知,告警模版,邮件钉钉微信飞书等及时通知送达
> 欢迎登录 HertzBeat 的 [云环境TanCloud](https://console.tancloud.cn) 试用发现更多。
> 我们正在快速迭代中,欢迎参与加入一起共建项目开源生态。
> `HertzBeat`的多类型支持,易扩展,低耦合,希望能帮助开发者和中小团队快速搭建自有监控系统。
老铁们可以通过演示视频来直观了解功能: https://www.bilibili.com/video/BV1DY4y1i7ts
欢迎在线试用 [https://console.tancloud.cn](https://gitee.com/link?target=https%3A%2F%2Fconsole.tancloud.cn)
优化后的参数输入界面:
![输入图片说明](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4b07908ba5a4b50a094a02dde6a38f3~tplv-k3u1fbpfcp-zoom-1.image "截屏2022-04-07 21.32.52.png")
Linux新增指标:
![输入图片说明](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92828224f8cd4cac84245aa4217b29e7~tplv-k3u1fbpfcp-zoom-1.image "截屏2022-04-07 17.50.22.png")
ORACLE监控:
哦豁oracle环境不在了之前没有截图先脑补一张
**仓库地址**
[Github](https://github.com/dromara/hertzbeat) https://github.com/dromara/hertzbeat
[Gitee](https://gitee.com/dromara/hertzbeat) https://gitee.com/dromara/hertzbeat
看到这里不妨给个Star支持下哦灰常感谢弯腰!!

View File

@@ -38,6 +38,7 @@ sidebar_label: Linux操作系统
| interrupt | 个数 | CPU中断数量 |
| load | 无 | CPU最近1/5/15分钟的平均负载 |
| context_switch | 个数 | 当前上下文切换数量 |
| usage | % | CPU使用率 |
#### 指标集合memory
@@ -49,6 +50,7 @@ sidebar_label: Linux操作系统
| free | Mb | 空闲内存容量 |
| buff_cache | Mb | 缓存占用内存 |
| available | Mb | 剩余可用内存容 |
| usage | % | 内存使用率 |
#### 指标集合disk
@@ -68,3 +70,12 @@ sidebar_label: Linux操作系统
| receive_bytes | byte | 入站数据流量(bytes) |
| transmit_bytes | byte | 出站数据流量(bytes) |
#### 指标集合disk_free
| 指标名称 | 指标单位 | 指标帮助描述 |
| ----------- | ----------- | ----------- |
| filesystem | 无 | 文件系统的名称 |
| used | Mb | 已使用磁盘大小 |
| available | Mb | 可用磁盘大小 |
| usage | % | 使用率 |
| mounted | 无 | 挂载点目录 |

View File

@@ -18,10 +18,11 @@ TDengine是一款国产的开源物联网时序型数据库我们使用其替
```
2. Docker安装TDengine
```
$ docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp -v /opt/taosdata:/var/lib/taos --name tdengine tdengine/tdengine:2.4.0.12
$ docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp -v /opt/taosdata:/var/lib/taos --name tdengine -e TZ=Asia/Shanghai tdengine/tdengine:2.4.0.12
526aa188da767ae94b244226a2b2eec2b5f17dd8eff594533d9ec0cd0f3a1ccd
```
`-v /opt/taosdata:/var/lib/taos` 为tdengine数据目录本地持久化挂载需将`/opt/taosdata`替换为实际本地存在的目录
`-v /opt/taosdata:/var/lib/taos` 为tdengine数据目录本地持久化挂载需将`/opt/taosdata`替换为实际本地存在的目录
`-e TZ="Asia/Shanghai"` 为tdengine设置时区这里可选设置对应的时区
使用```$ docker ps```查看数据库是否启动成功
### 创建数据库实例
@@ -51,4 +52,4 @@ TDengine是一款国产的开源物联网时序型数据库我们使用其替
```
**注意⚠若是安装包安装的TDengine2.3+版本**
> 除了启动server外还需执行 `systemctl start taosadapter` 启动 adapter
> 除了启动server外还需执行 `systemctl start taosadapter` 启动 adapter

View File

@@ -28,7 +28,7 @@ function Home() {
<h1 className="hero__title">
<img style={{width: '500px', marginTop: '100px'}} src={cdnTransfer('img/hertzbeat-brand.svg')} alt={'#'}/>
</h1>
<p className="hero__subtitle"><Translate>易用友好的监控告警系统</Translate></p>
<p className="hero__subtitle"><Translate>易用友好的监控系统</Translate></p>
<div className={styles.social}>
<a href="https://console.tancloud.cn"><img src={cdnTransfer('img/badge/web-monitor.svg')} alt={''}/></a>
<a href="https://console.tancloud.cn"><img src={cdnTransfer('img/badge/ping-connect.svg')} alt={''}/></a>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -31,6 +31,7 @@ import java.util.List;
/**
* 告警信息入库分发
*
* @author tom
* @date 2021/12/10 12:58
*/
@@ -107,9 +108,9 @@ public class DispatchAlarm {
}
} else {
// 若是恢复告警 需对监控状态进行恢复
if (alert.getStatus() == CommonConstants.ALERT_STATUS_CODE_RESTORED) {
monitorService.updateMonitorStatus(alert.getMonitorId(), CommonConstants.AVAILABLE_CODE);
}
if (alert.getStatus() == CommonConstants.ALERT_STATUS_CODE_RESTORED) {
monitorService.updateMonitorStatus(alert.getMonitorId(), CommonConstants.AVAILABLE_CODE);
}
}
// 告警落库
alertService.addAlert(alert);
@@ -122,22 +123,37 @@ public class DispatchAlarm {
for (NoticeReceiver receiver : receivers) {
switch (receiver.getType()) {
// todo 短信通知
case 0: break;
case 1: sendEmailAlert(receiver, alert); break;
case 2: sendWebHookAlert(receiver, alert); break;
case 3: sendWeChatAlert(receiver, alert); break;
case 4: sendWeWorkRobotAlert(receiver, alert); break;
case 5: sendDingTalkRobotAlert(receiver, alert); break;
case 6: sendFlyBookAlert(receiver,alert); break;
default: break;
case 0:
break;
case 1:
sendEmailAlert(receiver, alert);
break;
case 2:
sendWebHookAlert(receiver, alert);
break;
case 3:
sendWeChatAlert(receiver, alert);
break;
case 4:
sendWeWorkRobotAlert(receiver, alert);
break;
case 5:
sendDingTalkRobotAlert(receiver, alert);
break;
case 6:
sendFlyBookAlert(receiver, alert);
break;
default:
break;
}
}
}
/**
* 通过飞书发送告警信息
*
* @param receiver 接收人
* @param alert 告警信息
* @param alert 告警信息
*/
private void sendFlyBookAlert(NoticeReceiver receiver, Alert alert) {
FlyBookWebHookDto flyBookWebHookDto = new FlyBookWebHookDto();
@@ -184,8 +200,9 @@ public class DispatchAlarm {
/**
* 通过钉钉机器人发送告警信息
* @param receiver 通知配置信息
* @param alert 告警信息
*
* @param receiver 通知配置信息
* @param alert 告警信息
*/
private void sendDingTalkRobotAlert(NoticeReceiver receiver, Alert alert) {
DingTalkWebHookDto dingTalkWebHookDto = new DingTalkWebHookDto();
@@ -217,8 +234,9 @@ public class DispatchAlarm {
/**
* 通过企业微信发送告警信息
* @param receiver 通知配置信息
* @param alert 告警信息
*
* @param receiver 通知配置信息
* @param alert 告警信息
*/
private void sendWeWorkRobotAlert(NoticeReceiver receiver, Alert alert) {
WeWorkWebHookDto weWorkWebHookDTO = new WeWorkWebHookDto();
@@ -231,7 +249,7 @@ public class DispatchAlarm {
if (alert.getPriority() < CommonConstants.ALERT_PRIORITY_CODE_WARNING) {
content.append("告警级别 : <font color=\"warning\">")
.append(CommonUtil.transferAlertPriority(alert.getPriority())).append("</font>\n");
}else {
} else {
content.append("告警级别 : <font color=\"comment\">")
.append(CommonUtil.transferAlertPriority(alert.getPriority())).append("</font>\n");
}
@@ -273,23 +291,23 @@ public class DispatchAlarm {
}
private void sendEmailAlert(final NoticeReceiver receiver,final Alert alert){
try{
private void sendEmailAlert(final NoticeReceiver receiver, final Alert alert) {
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true,"UTF-8");
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
messageHelper.setSubject("TanCloud探云-监控告警");
//设置发件人Email
messageHelper.setFrom(emailFromUser);
//设定收件人Email
messageHelper.setTo(receiver.getEmail());
messageHelper.setTo(receiver.getEmail());
messageHelper.setSentDate(new Date());
//构建邮件模版
String process = mailService.buildAlertHtmlTemplate(alert);
//设置邮件内容模版
messageHelper.setText(process,true);
messageHelper.setText(process, true);
javaMailSender.send(mimeMessage);
}catch (Exception e){
log.error("[邮箱告警] errorException information={}",e.getMessage());
} catch (Exception e) {
log.error("[邮箱告警] errorException information={}", e.getMessage());
}
}

View File

@@ -7,6 +7,7 @@ import lombok.NoArgsConstructor;
/**
* 企业微信机器人请求消息体
*
* @author 花城
* @version 1.0
* @date 2022/2/21 6:55 下午
@@ -18,7 +19,14 @@ import lombok.NoArgsConstructor;
public class WeWorkWebHookDto {
public static final String WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=";
/**
* markdown格式
*/
private static final String MARKDOWN = "markdown";
/**
* 文本格式
*/
private static final String TEXT = "TEXT";
/**
* 消息类型

View File

@@ -79,6 +79,10 @@ public class MonitorServiceImpl implements MonitorService {
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getValue(), param.getType())).collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
// 探测可用性只需要采集优先级为0的可用性指标集合
List<Metrics> availableMetrics = appDefine.getMetrics().stream()
.filter(item -> item.getPriority() == 0).collect(Collectors.toList());
appDefine.setMetrics(availableMetrics);
List<CollectRep.MetricsData> collectRep = collectJobService.collectSyncJobData(appDefine);
// 判断探测结果 失败则抛出探测异常
if (collectRep == null || collectRep.isEmpty()) {

View File

@@ -4,7 +4,7 @@ category: custom
app: example
name:
zh-CN: 模拟应用类型
en-US: EXAMPLE APP
en-US: EXAMPLE
# 参数映射map. type是参数类型: 0-number数字, 1-string明文字符串, 2-secret加密字符串, 3-map映射的json串
# 强制固定必须参数 - host
configmap:

View File

@@ -32,6 +32,8 @@ configmap:
type: 3
- key: params
type: 3
- key: keyword
type: 1
# 指标组列表
metrics:
# 第一个监控指标组 cpu
@@ -46,6 +48,9 @@ metrics:
- field: responseTime
type: 0
unit: ms
- field: keyword
type: 0
unit: 次数
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: http
# 当protocol为http协议时具体的采集配置
@@ -78,4 +83,5 @@ metrics:
digestAuthPassword: ^_^password^_^
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
# todo xmlPath-xmlPath脚本,prometheus-Prometheus数据规则
parseType: website
parseType: website
keyword: ^_^keyword^_^

View File

@@ -2,7 +2,7 @@ category: service
app: fullsite
name:
zh-CN: 全站监控
en-US: FULL WEBSITE MONITOR
en-US: SITE MAP
configmap:
- key: host
type: 1

View File

@@ -68,6 +68,26 @@ metrics:
- field: context_switch
type: 0
unit: 个数
- field: usage
type: 0
unit: '%'
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
aliasFields:
- info
- cores
- interrupt
- load
- context_switch
- idle
# (非必须)指标计算表达式,与上面的别名一起作用,计算出最终需要的指标值
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
calculates:
- info=info
- cores=cores
- interrupt=interrupt
- load=load
- context_switch=context_switch
- usage=100-idle
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: ssh
# 当protocol为http协议时具体的采集配置
@@ -79,7 +99,7 @@ metrics:
username: ^_^username^_^
password: ^_^password^_^
timeout: ^_^timeout^_^
script: "LANG=C lscpu | awk -F: '/Model name/ {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}'"
script: "LANG=C lscpu | awk -F: '/Model name/ {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 1 | awk 'NR==3{print $15}'"
parseType: oneRow
- name: memory
@@ -101,6 +121,25 @@ metrics:
- field: available
type: 0
unit: Mb
- field: usage
type: 0
unit: '%'
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
aliasFields:
- total
- used
- free
- buff_cache
- available
# (非必须)指标计算表达式,与上面的别名一起作用,计算出最终需要的指标值
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
calculates:
- total=total
- used=used
- free=free
- buff_cache=buff_cache
- available=available
- usage=(used / total) * 100
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: ssh
# 当protocol为http协议时具体的采集配置
@@ -154,6 +193,7 @@ metrics:
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
- field: interface_name
type: 1
instance: true
- field: receive_bytes
type: 0
unit: byte
@@ -172,4 +212,36 @@ metrics:
password: ^_^password^_^
timeout: ^_^timeout^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
- name: disk_free
priority: 5
fields:
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
- field: filesystem
type: 1
- field: used
type: 0
unit: Mb
- field: available
type: 0
unit: Mb
- field: usage
type: 0
unit: '%'
- field: mounted
type: 1
instance: true
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: ssh
# 当protocol为http协议时具体的采集配置
ssh:
# 主机host: ipv4 ipv6 域名
host: ^_^host^_^
# 端口
port: ^_^port^_^
username: ^_^username^_^
password: ^_^password^_^
timeout: ^_^timeout^_^
script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow

View File

@@ -32,8 +32,6 @@ metrics:
- field: database_version
type: 1
instance: true
- field: database_type
type: 1
- field: hostname
type: 1
- field: instance_name
@@ -45,7 +43,6 @@ metrics:
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
aliasFields:
- VERSION
- DATABASE_TYPE
- HOST_NAME
- INSTANCE_NAME
- STARTUP_TIME
@@ -54,7 +51,6 @@ metrics:
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
calculates:
- database_version=VERSION
- database_type=DATABASE_TYPE
- hostname=HOST_NAME
- instance_name=INSTANCE_NAME
- startup_time=STARTUP_TIME
@@ -179,4 +175,4 @@ metrics:
queryType: columns
# sql
sql: select metric_name, value from gv$sysmetric where metric_name = 'I/O Megabytes per Second' or metric_name = 'User Transaction Per Sec' or metric_name = 'I/O Requests per Second'
url: ^_^url^_^
url: ^_^url^_^

View File

@@ -2,7 +2,7 @@ category: service
app: website
name:
zh-CN: 网站监测
en-US: WEBSITE MONITOR
en-US: WEBSITE
configmap:
- key: host
type: 1
@@ -18,10 +18,12 @@ configmap:
type: 1
- key: password
type: 2
- key: keyword
type: 1
# 指标组列表
metrics:
# 第一个监控指标组 cpu
# 注意:内置监控指标有 (responseTime - 响应时间)
# 注意:内置监控指标有 (responseTime - 响应时间, keyword - 关键字数量)
- name: summary
# 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集
# 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度
@@ -32,6 +34,9 @@ metrics:
- field: responseTime
type: 0
unit: ms
- field: keyword
type: 0
unit: 次数
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: http
# 当protocol为http协议时具体的采集配置
@@ -55,4 +60,5 @@ metrics:
digestAuthPassword: ^_^password^_^
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
# todo xmlPath-xmlPath脚本,prometheus-Prometheus数据规则
parseType: website
parseType: website
keyword: ^_^keyword^_^

View File

@@ -90,3 +90,8 @@ param:
type: password
required: false
hide: true
- field: keyword
name: 关键字
type: text
required: false
hide: true

View File

@@ -51,4 +51,9 @@ param:
name: 密码
type: password
required: false
hide: true
- field: keyword
name: 关键字
type: text
required: false
hide: true

View File

@@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd
http://maven.apache.org/ASSEMBLY/2.0.0 ">
<!--必填,会追加到打包文件名称的末尾-->
<id>1.0-beta.6</id>
<id>1.0-beta.7</id>
<!--打包类型,可以设置多种类型,打包的时候不同的类型都会打包打出来-->
<formats>
<format>tar</format>

View File

@@ -28,9 +28,7 @@ if [ ! -d $LOGS_DIR ]; then
fi
# JVM Configuration
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
JAVA_MEM_OPTS=" -server -Xms256m -Xmx1024m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
JAVA_MEM_OPTS=" -server -XX:SurvivorRatio=6 -XX:+UseParallelGC "
# 加载外部log文件的配置
LOG_IMPL_FILE=logback-spring.xml
@@ -41,4 +39,4 @@ then
fi
CONFIG_FILES=" -Dlogging.path=$LOGS_DIR $LOGGING_CONFIG -Dspring.config.location=$CONF_DIR/ "
echo -e "Starting the $SERVER_NAME ..."
java $JAVA_OPTS $JAVA_MEM_OPTS $CONFIG_FILES -jar $DEPLOY_DIR/$JAR_NAME --spring.profiles.active=prod
java $JAVA_MEM_OPTS $CONFIG_FILES -jar $DEPLOY_DIR/$JAR_NAME --spring.profiles.active=prod

View File

@@ -34,9 +34,9 @@ rem 项目日志输出绝对路径
set LOGS_DIR=%DEPLOY_DIR%\logs
rem JVM Configuration
set JAVA_OPTS= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Shanghai
set JAVA_OPTS= -Duser.timezone=Asia/Shanghai
set JAVA_MEM_OPTS= -server -Xms256m -Xmx1024m -XX:SurvivorRatio=2 -XX:+UseParallelGC
set JAVA_MEM_OPTS= -server -XX:SurvivorRatio=6 -XX:+UseParallelGC
rem 加载外部log文件的配置
set LOGGING_CONFIG=-Dlogging.config=%CONF_DIR%\logback-spring.xml

View File

@@ -66,9 +66,9 @@ if [ ! -d $LOGS_DIR ]; then
fi
# JVM Configuration
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Shanghai"
JAVA_OPTS=" -Duser.timezone=Asia/Shanghai"
JAVA_MEM_OPTS=" -server -Xms256m -Xmx1024m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
JAVA_MEM_OPTS=" -server -XX:SurvivorRatio=6 -XX:+UseParallelGC "
# 加载外部log文件的配置
LOG_IMPL_FILE=logback-spring.xml

View File

@@ -35,7 +35,7 @@ services:
- heartzbeat
hertzbeat:
image: "tancloud/hertzbeat:1.0-beta.6"
image: "tancloud/hertzbeat:1.0-beta.7"
container_name: hertzbeat
hostname: hertzbeat
restart: always

View File

@@ -2,7 +2,7 @@ FROM openjdk:8-alpine
MAINTAINER tomsun28 "tomsun28@outlook.com"
ADD hertzbeat-1.0-beta.6.tar /opt/
ADD hertzbeat-1.0-beta.7.tar /opt/
RUN apk add --no-cache tzdata

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 MiB

After

Width:  |  Height:  |  Size: 15 MiB

View File

@@ -71,9 +71,9 @@ import { environment } from '@env/environment';
<setting-drawer *ngIf="showSettingDrawer"></setting-drawer>
<theme-btn
[types]="[
{ key: 'default', text: '浅色主题' },
{ key: 'dark', text: '深色主题' },
{ key: 'compact', text: '紧凑主题' }
{ key: 'default', text: 'app.theme.default' | i18n },
{ key: 'dark', text: 'app.theme.dark' | i18n },
{ key: 'compact', text: 'app.theme.compact' | i18n }
]"
></theme-btn>
`

View File

@@ -1,4 +1,6 @@
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostListener, Inject } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
@@ -14,15 +16,19 @@ import { NzModalService } from 'ng-zorro-antd/modal';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeaderClearStorageComponent {
constructor(private modalSrv: NzModalService, private messageSrv: NzMessageService) {}
constructor(
private modalSrv: NzModalService,
private messageSrv: NzMessageService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
@HostListener('click')
_click(): void {
this.modalSrv.confirm({
nzTitle: '请确认是否清理缓存?',
nzTitle: this.i18nSvc.fanyi('common.confirm.clear-cache'),
nzOnOk: () => {
localStorage.clear();
this.messageSrv.success('清理成功!');
this.messageSrv.success(this.i18nSvc.fanyi('common.notify.clear-success'));
}
});
}

View File

@@ -26,11 +26,11 @@ import { AlertService } from '../../../service/alert.service';
export class HeaderNotifyComponent implements OnInit {
data: NoticeItem[] = [
{
title: '近期未处理告警',
title: this.i18nSvc.fanyi('dashboard.alerts.title-no'),
list: [],
emptyText: '暂无未处理告警',
emptyText: this.i18nSvc.fanyi('dashboard.alerts.no'),
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
clearText: '进入告警中心'
clearText: this.i18nSvc.fanyi('dashboard.alerts.enter')
}
];
count = 0;
@@ -69,10 +69,10 @@ export class HeaderNotifyComponent implements OnInit {
let item = {
id: alert.id,
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: `监控-${alert.monitorName}-发出${this.i18nSvc.fanyi(`alert.priority.${alert.priority}`)}`,
title: `${alert.monitorName}--${this.i18nSvc.fanyi(`alert.priority.${alert.priority}`)}`,
datetime: alert.gmtCreate,
color: 'blue',
type: '近期未处理告警'
type: this.i18nSvc.fanyi('dashboard.alerts.title-no')
};
this.data[0].list.push(item);
});

View File

@@ -40,8 +40,8 @@ import { MonitorService } from '../../../service/monitor.service';
<nz-autocomplete nzBackfill="false" nzDefaultActiveFirstOption #auto>
<nz-auto-option *ngFor="let option of options" [nzValue]="option.id" [nzLabel]="option.name">
<a [routerLink]="['/monitors/' + option.id]">
监控名称: {{ option.name }}
<span style="left:50% ; position: absolute;">监控Host: {{ option.host }}</span>
{{ 'monitor.name' | i18n }} : {{ option.name }}
<span style="left:50% ; position: absolute;">{{ 'monitor.host' | i18n }} : {{ option.host }}</span>
<span style="right: 10px; position: absolute;"><i nz-icon nzType="arrow-right" nzTheme="outline"></i></span>
</a>
</nz-auto-option>

View File

@@ -6,15 +6,15 @@
<img class="logo" src="./assets/logo.svg" alt="" />
<span class="title">HertzBeat</span>
</div>
<div class="desc">TanCloud-易用友好的高性能监控云服务</div>
<div class="desc">{{ 'app.passport.desc' | i18n }}</div>
</div>
<router-outlet></router-outlet>
<global-footer [links]="links">
Copyright
<i nz-icon nzType="copyright" nzTheme="outline"></i>
2022
<a href="https://tancloud.cn" target="_blank">探云 tancloud.cn | </a>
<a href="https://hertzbeat.com" target="_blank">赫兹跳动 hertzbeat.com</a>
<a href="https://tancloud.cn" target="_blank">TanCloud tancloud.cn | </a>
<a href="https://hertzbeat.com" target="_blank">HertzBeat hertzbeat.com</a>
</global-footer>
</div>
</div>

View File

@@ -1,5 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
@Component({
selector: 'layout-passport',
@@ -9,12 +11,12 @@ import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
export class LayoutPassportComponent implements OnInit {
links = [
{
title: '欢迎使用TanCloud探云-监控云服务-tancloud.cn',
title: this.i18nSvc.fanyi('app.passport.welcome'),
href: 'https://tancloud.cn'
}
];
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService, @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService) {}
ngOnInit(): void {
this.tokenService.clear();

View File

@@ -3,12 +3,12 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="alert"></i>
<span>告警中心</span>
<span>{{ 'menu.alert.center' | i18n }}</span>
</nz-breadcrumb-item>
</nz-breadcrumb>
<nz-divider></nz-divider>
@@ -16,26 +16,28 @@
<div>
<button nz-button nzType="primary" (click)="onDeleteAlerts()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除告警
{{ 'alert.center.delete' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onMarkReadAlerts()">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
标记已处理
{{ 'alert.center.deal' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onMarkUnReadAlerts()">
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
标记未处理
{{ 'alert.center.no-deal' | i18n }}
</button>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchAlerts()"> 搜索 </button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchAlerts()">
{{ 'common.search' | i18n }}
</button>
<input
style="margin-right: 5px; float: right; width: 150px; border-radius: 9px; text-align: center"
nz-input
type="text"
placeholder="搜索告警内容"
[placeholder]="'alert.center.search' | i18n"
nzSize="default"
(keyup.enter)="onFilterSearchAlerts()"
[(ngModel)]="filterContent"
@@ -43,23 +45,24 @@
<nz-select
style="margin-right: 10px; float: right; width: 120px"
nzAllowClear
[nzPlaceHolder]="'告警状态过滤'"
[nzPlaceHolder]="'alert.center.filter-status' | i18n"
[(ngModel)]="filterStatus"
>
<nz-option nzLabel="全部状态" nzValue="9"></nz-option>
<nz-option nzLabel="未处理" nzValue="0"></nz-option>
<nz-option nzLabel="已处理" nzValue="3"></nz-option>
<nz-option [nzLabel]="'alert.status.all' | i18n" nzValue="9"></nz-option>
<nz-option [nzLabel]="'alert.status.0' | i18n" nzValue="0"></nz-option>
<nz-option [nzLabel]="'alert.status.2' | i18n" nzValue="2"></nz-option>
<nz-option [nzLabel]="'alert.status.3' | i18n" nzValue="3"></nz-option>
</nz-select>
<nz-select
style="margin-right: 10px; float: right; width: 120px"
nzAllowClear
[nzPlaceHolder]="'告警级别过滤'"
[nzPlaceHolder]="'alert.center.filter-priority' | i18n"
[(ngModel)]="filterPriority"
>
<nz-option nzLabel="全部级别" nzValue="9"></nz-option>
<nz-option nzLabel="警告级别" nzValue="2"></nz-option>
<nz-option nzLabel="严重级别" nzValue="1"></nz-option>
<nz-option nzLabel="紧急级别" nzValue="0"></nz-option>
<nz-option [nzLabel]="'alert.priority.all' | i18n" nzValue="9"></nz-option>
<nz-option [nzLabel]="'alert.priority.2' | i18n" nzValue="2"></nz-option>
<nz-option [nzLabel]="'alert.priority.1' | i18n" nzValue="1"></nz-option>
<nz-option [nzLabel]="'alert.priority.0' | i18n" nzValue="0"></nz-option>
</nz-select>
</div>
@@ -81,13 +84,13 @@
<thead>
<tr>
<th nzAlign="center" nzLeft nzWidth="4%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
<th nzAlign="center" nzLeft>告警指标</th>
<th nzAlign="center">所属监控</th>
<th nzAlign="center">级别</th>
<th nzAlign="center">告警内容</th>
<th nzAlign="center">状态</th>
<th nzAlign="center">告警时间</th>
<th nzAlign="center">操作</th>
<th nzAlign="center" nzLeft>{{ 'alert.center.target' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.monitor' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.priority' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.content' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.status' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.time' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit' | i18n }}</th>
</tr>
</thead>
<tbody>
@@ -102,30 +105,36 @@
<td nzAlign="center">
<nz-tag *ngIf="data.priority == 0" nzColor="red">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>紧急告警</span>
<span>{{ 'alert.priority.0' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 1" nzColor="orange">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>严重告警</span>
<span>{{ 'alert.priority.1' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 2" nzColor="yellow">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>警告告警</span>
<span>{{ 'alert.priority.2' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">{{ data.content }}</td>
<td nzAlign="center">
{{ data.status === 0 ? '未处理' : '已处理' }}
{{ 'alert.status.' + data.status | i18n }}
</td>
<td nzAlign="center">{{ data.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onDeleteOneAlert(data.id)" nz-tooltip nzTooltipTitle="删除告警">
<button nz-button nzType="primary" (click)="onDeleteOneAlert(data.id)" nz-tooltip [nzTooltipTitle]="'alert.center.delete' | i18n">
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onMarkReadOneAlert(data.id)" nz-tooltip nzTooltipTitle="标记已处理">
<button nz-button nzType="primary" (click)="onMarkReadOneAlert(data.id)" nz-tooltip [nzTooltipTitle]="'alert.center.deal' | i18n">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onMarkUnReadOneAlert(data.id)" nz-tooltip nzTooltipTitle="标记未处理">
<button
nz-button
nzType="primary"
(click)="onMarkUnReadOneAlert(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.center.no-deal' | i18n"
>
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
</button>
</td>
@@ -133,4 +142,4 @@
</tbody>
</nz-table>
<ng-template #rangeTemplate> 总量 {{ total }} </ng-template>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }} </ng-template>

View File

@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTableQueryParams } from 'ng-zorro-antd/table';
@@ -12,7 +14,12 @@ import { AlertService } from '../../../service/alert.service';
styles: []
})
export class AlertCenterComponent implements OnInit {
constructor(private notifySvc: NzNotificationService, private modal: NzModalService, private alertSvc: AlertService) {}
constructor(
private notifySvc: NzNotificationService,
private modal: NzModalService,
private alertSvc: AlertService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
pageIndex: number = 1;
pageSize: number = 8;
@@ -87,13 +94,13 @@ export class AlertCenterComponent implements OnInit {
onDeleteAlerts() {
if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) {
this.notifySvc.warning('未选中任何待删除项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('alert.center.notify.no-delete'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.delete-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlerts(this.checkedAlertIds)
@@ -102,13 +109,13 @@ export class AlertCenterComponent implements OnInit {
onMarkReadAlerts() {
if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) {
this.notifySvc.warning('未选中任何待标记项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('alert.center.notify.no-mark'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量标记已处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-done-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(this.checkedAlertIds, 3)
@@ -116,13 +123,13 @@ export class AlertCenterComponent implements OnInit {
}
onMarkUnReadAlerts() {
if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) {
this.notifySvc.warning('未选中任何待标记项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('alert.center.notify.no-mark'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量标记未处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-no-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(this.checkedAlertIds, 0)
@@ -133,9 +140,9 @@ export class AlertCenterComponent implements OnInit {
let alerts = new Set<number>();
alerts.add(alertId);
this.modal.confirm({
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlerts(alerts)
@@ -146,9 +153,9 @@ export class AlertCenterComponent implements OnInit {
let alerts = new Set<number>();
alerts.add(alertId);
this.modal.confirm({
nzTitle: '请确认是否标记已处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-done'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(alerts, 3)
@@ -159,9 +166,9 @@ export class AlertCenterComponent implements OnInit {
let alerts = new Set<number>();
alerts.add(alertId);
this.modal.confirm({
nzTitle: '请确认是否标记未处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-no'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(alerts, 0)
@@ -174,17 +181,17 @@ export class AlertCenterComponent implements OnInit {
message => {
deleteAlerts$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success('删除成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.loadAlertsTable();
} else {
this.tableLoading = false;
this.notifySvc.error('删除失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
}
},
error => {
this.tableLoading = false;
deleteAlerts$.unsubscribe();
this.notifySvc.error('删除失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
}
);
}
@@ -195,17 +202,17 @@ export class AlertCenterComponent implements OnInit {
message => {
markAlertsStatus$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success('标记成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.mark-success'), '');
this.loadAlertsTable();
} else {
this.tableLoading = false;
this.notifySvc.error('标记失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), message.msg);
}
},
error => {
this.tableLoading = false;
markAlertsStatus$.unsubscribe();
this.notifySvc.error('标记失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), error.msg);
}
);
}

View File

@@ -3,14 +3,14 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="alert"></i>
<span>告警通知配置</span>
<span>{{ 'menu.alert.dispatch' | i18n }}</span>
<a href="https://tancloud.cn/docs/help/alert_email" target="_blank" style="float: right; margin-right: 5%">
<span>帮助&nbsp;</span>
<span>{{ 'common.button.help' | i18n }}&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -18,12 +18,12 @@
<nz-divider></nz-divider>
<nz-tabset nzSize="large">
<nz-tab nzTitle="告警接收人">
<nz-tab [nzTitle]="'alert.notice.receiver' | i18n">
<button nz-button nzType="primary" (click)="onNewNoticeReceiver()">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
新增接收人
{{ 'alert.notice.receiver.new' | i18n }}
</button>
<button nz-button nzType="primary" (click)="syncReceiver()" nz-tooltip nzTooltipTitle="刷新">
<button nz-button nzType="primary" (click)="syncReceiver()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
@@ -35,11 +35,11 @@
>
<thead>
<tr>
<th nzAlign="center" nzWidth="10%">接收人</th>
<th nzAlign="center" nzWidth="20%">通知方式</th>
<th nzAlign="center" nzWidth="20%">配置</th>
<th nzAlign="center" nzWidth="20%">最新修改时间</th>
<th nzAlign="center" nzWidth="30%">操作</th>
<th nzAlign="center" nzWidth="10%">{{ 'alert.notice.receiver.people' | i18n }}</th>
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.receiver.type' | i18n }}</th>
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.receiver.setting' | i18n }}</th>
<th nzAlign="center" nzWidth="20%">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center" nzWidth="30%">{{ 'common.edit' | i18n }}</th>
</tr>
</thead>
<tbody>
@@ -50,11 +50,11 @@
<td nzAlign="center">
<nz-tag *ngIf="data.type == 0" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>短信</span>
<span>{{ 'alert.notice.type.sms' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.type == 1" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>邮件</span>
<span>{{ 'alert.notice.type.email' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.type == 2" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
@@ -62,19 +62,19 @@
</nz-tag>
<nz-tag *ngIf="data.type == 3" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>微信公众号</span>
<span>{{ 'alert.notice.type.wechat' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.type == 4" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>企业微信机器人</span>
<span>{{ 'alert.notice.type.wework' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.type == 5" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>钉钉机器人</span>
<span>{{ 'alert.notice.type.ding' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.type == 6" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>飞书机器人</span>
<span>{{ 'alert.notice.type.fei-shu' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">
@@ -88,10 +88,22 @@
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onEditOneNoticeReceiver(data)" nz-tooltip nzTooltipTitle="修改接收人">
<button
nz-button
nzType="primary"
(click)="onEditOneNoticeReceiver(data)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.receiver.edit' | i18n"
>
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onDeleteOneNoticeReceiver(data.id)" nz-tooltip nzTooltipTitle="删除接收人">
<button
nz-button
nzType="primary"
(click)="onDeleteOneNoticeReceiver(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.receiver.delete' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
@@ -99,12 +111,12 @@
</tbody>
</nz-table>
</nz-tab>
<nz-tab nzTitle="告警通知策略">
<nz-tab [nzTitle]="'alert.notice.rule' | i18n">
<button nz-button nzType="primary" (click)="onNewNoticeRule()">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
新增通知策略
{{ 'alert.notice.rule.new' | i18n }}
</button>
<button nz-button nzType="primary" (click)="syncRule()" nz-tooltip nzTooltipTitle="刷新">
<button nz-button nzType="primary" (click)="syncRule()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
@@ -116,12 +128,12 @@
>
<thead>
<tr>
<th nzAlign="center" nzWidth="15%">策略名称</th>
<th nzAlign="center" nzWidth="12%">接收人</th>
<th nzAlign="center" nzWidth="12%">转发所有</th>
<th nzAlign="center" nzWidth="15%">是否启用</th>
<th nzAlign="center" nzWidth="15%">最新修改时间</th>
<th nzAlign="center" nzWidth="25%">操作</th>
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.rule.name' | i18n }}</th>
<th nzAlign="center" nzWidth="12%">{{ 'alert.notice.receiver.people' | i18n }}</th>
<th nzAlign="center" nzWidth="12%">{{ 'alert.notice.rule.all' | i18n }}</th>
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.rule.enable' | i18n }}</th>
<th nzAlign="center" nzWidth="15%">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center" nzWidth="25%">{{ 'common.edit' | i18n }}</th>
</tr>
</thead>
<tbody>
@@ -134,26 +146,38 @@
</td>
<td nzAlign="center">
<nz-tag *ngIf="data.filterAll" nzColor="green">
<span></span>
<span>{{ 'common.yes' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="!data.filterAll" nzColor="orange">
<span></span>
<span>{{ 'common.no' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">
<nz-tag *ngIf="data.enable" nzColor="green">
<span>开启</span>
<span>{{ 'common.enable' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="!data.enable" nzColor="orange">
<span>关闭</span>
<span>{{ 'common.disable' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onEditOneNoticeRule(data)" nz-tooltip nzTooltipTitle="修改告警策略">
<button
nz-button
nzType="primary"
(click)="onEditOneNoticeRule(data)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.rule.edit' | i18n"
>
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onDeleteOneNoticeRule(data.id)" nz-tooltip nzTooltipTitle="删除告警策略">
<button
nz-button
nzType="primary"
(click)="onDeleteOneNoticeRule(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.rule.delete' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
@@ -166,7 +190,7 @@
<!-- 新增或修改通知接收人弹出框 -->
<nz-modal
[(nzVisible)]="isManageReceiverModalVisible"
[nzTitle]="isManageReceiverModalAdd ? '新增接收人' : '修改接收人'"
[nzTitle]="isManageReceiverModalAdd ? ('alert.notice.receiver.new' | i18n) : ('alert.notice.receiver.edit' | i18n)"
(nzOnCancel)="onManageReceiverModalCancel()"
(nzOnOk)="onManageReceiverModalOk()"
nzMaskClosable="false"
@@ -176,27 +200,27 @@
<div *nzModalContent class="-inner-content">
<form nz-form #receiverForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true">接收人名称</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true">{{ 'alert.notice.receiver.people.name' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.name" nz-input required name="name" type="text" id="name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="type">通知方式 </nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="type">{{ 'alert.notice.receiver.type' | i18n }} </nz-form-label>
<nz-form-control nzSpan="12" [nzErrorTip]="'validation.required' | i18n">
<nz-select [(ngModel)]="receiver.type" nzPlaceHolder="Choose" required name="type" id="type">
<nz-option [nzValue]="0" nzDisabled nzLabel="短信"></nz-option>
<nz-option [nzValue]="1" nzLabel="邮箱"></nz-option>
<nz-option [nzValue]="0" nzDisabled [nzLabel]="'alert.notice.type.sms' | i18n"></nz-option>
<nz-option [nzValue]="1" [nzLabel]="'alert.notice.type.email' | i18n"></nz-option>
<nz-option [nzValue]="2" nzLabel="WebHook"></nz-option>
<nz-option [nzValue]="3" nzDisabled nzLabel="微信公众号"></nz-option>
<nz-option [nzValue]="4" nzLabel="企业微信机器人"></nz-option>
<nz-option [nzValue]="5" nzLabel="钉钉机器人"></nz-option>
<nz-option [nzValue]="6" nzLabel="飞书机器人"></nz-option>
<nz-option [nzValue]="3" nzDisabled [nzLabel]="'alert.notice.type.wechat' | i18n"></nz-option>
<nz-option [nzValue]="4" [nzLabel]="'alert.notice.type.wework' | i18n"></nz-option>
<nz-option [nzValue]="5" [nzLabel]="'alert.notice.type.ding' | i18n"></nz-option>
<nz-option [nzValue]="6" [nzLabel]="'alert.notice.type.fei-shu' | i18n"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 0">
<nz-form-label [nzSpan]="7" nzFor="phone" [nzRequired]="receiver.type === 0">手机号</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="phone" [nzRequired]="receiver.type === 0">{{ 'alert.notice.type.phone' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.phone.invalid' | i18n">
<input
[(ngModel)]="receiver.phone"
@@ -210,37 +234,45 @@
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 1">
<nz-form-label [nzSpan]="7" nzFor="email" [nzRequired]="receiver.type === 1">邮箱</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="email" [nzRequired]="receiver.type === 1">{{ 'alert.notice.type.email' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.email.invalid' | i18n">
<input [(ngModel)]="receiver.email" nz-input [required]="receiver.type === 1" email name="email" type="email" id="email" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 2">
<nz-form-label [nzSpan]="7" nzFor="hookUrl" [nzRequired]="receiver.type === 2">URL地址</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="hookUrl" [nzRequired]="receiver.type === 2">{{ 'alert.notice.type.url' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.hookUrl" nz-input [required]="receiver.type === 2" name="hookUrl" type="url" id="hookUrl" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 3">
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 3">微信OPENID</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 3">{{
'alert.notice.type.wechat-id' | i18n
}}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 3" name="wechatId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 4">
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 4">企业微信机器人KEY</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 4">{{
'alert.notice.type.wework-key' | i18n
}}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 4" name="wechatId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 5">
<nz-form-label [nzSpan]="7" nzFor="accessToken" [nzRequired]="receiver.type === 5">机器人ACCESS_TOKEN</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="accessToken" [nzRequired]="receiver.type === 5">{{
'alert.notice.type.access-token' | i18n
}}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.accessToken" nz-input [required]="receiver.type === 5" name="accessToken" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 6">
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 6">飞书机器人KEY</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 6">{{
'alert.notice.type.fei-shu-key' | i18n
}}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 6" name="wechatId" type="text" />
</nz-form-control>
@@ -252,7 +284,7 @@
<!-- 新增或修改通知策略弹出框 -->
<nz-modal
[(nzVisible)]="isManageRuleModalVisible"
[nzTitle]="isManageRuleModalAdd ? '新增策略' : '修改策略'"
[nzTitle]="isManageRuleModalAdd ? ('alert.notice.rule.new' | i18n) : ('alert.notice.rule.edit' | i18n)"
(nzOnCancel)="onManageRuleModalCancel()"
(nzOnOk)="onManageRuleModalOk()"
nzMaskClosable="false"
@@ -262,19 +294,19 @@
<div *nzModalContent class="-inner-content">
<form nz-form #ruleForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="rule_name" nzRequired="true">策略名称</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="rule_name" nzRequired="true">{{ 'alert.notice.rule.name' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="rule.name" nz-input required name="rule_name" type="text" id="rule_name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="filterAll">转发所有</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="filterAll">{{ 'alert.notice.rule.all' | i18n }}</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="rule.filterAll" disabled name="filterAll" id="filterAll"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="receiver">接收人</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="receiver">{{ 'alert.notice.receiver.people' | i18n }}</nz-form-label>
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-select
[(ngModel)]="rule.receiverId"
@@ -291,7 +323,7 @@
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable">是否启用</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable">{{ 'alert.notice.rule.enable' | i18n }}</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="rule.enable" name="enable" id="enable"></nz-switch>
</nz-form-control>

View File

@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { finalize } from 'rxjs/operators';
@@ -18,7 +20,8 @@ export class AlertNoticeComponent implements OnInit {
private notifySvc: NzNotificationService,
private noticeReceiverSvc: NoticeReceiverService,
private modal: NzModalService,
private noticeRuleSvc: NoticeRuleService
private noticeRuleSvc: NoticeRuleService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
receivers!: NoticeReceiver[];
@@ -78,9 +81,9 @@ export class AlertNoticeComponent implements OnInit {
onDeleteOneNoticeReceiver(receiveId: number) {
this.modal.confirm({
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteOneNoticeReceiver(receiveId)
@@ -98,23 +101,23 @@ export class AlertNoticeComponent implements OnInit {
.subscribe(
message => {
if (message.code === 0) {
this.notifySvc.success('删除成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.loadReceiversTable();
} else {
this.notifySvc.error('删除失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
}
},
error => {
this.notifySvc.error('删除失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
}
);
}
onDeleteOneNoticeRule(ruleId: number) {
this.modal.confirm({
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteOneNoticeRule(ruleId)
@@ -132,14 +135,14 @@ export class AlertNoticeComponent implements OnInit {
.subscribe(
message => {
if (message.code === 0) {
this.notifySvc.success('删除成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.loadRulesTable();
} else {
this.notifySvc.error('删除失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
}
},
error => {
this.notifySvc.error('删除失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
}
);
}
@@ -179,14 +182,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageReceiverModalVisible = false;
this.notifySvc.success('新增成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
this.loadReceiversTable();
} else {
this.notifySvc.error('新增失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
}
},
error => {
this.notifySvc.error('新增失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
}
);
} else {
@@ -202,14 +205,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageReceiverModalVisible = false;
this.notifySvc.success('修改成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
this.loadReceiversTable();
} else {
this.notifySvc.error('修改失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
}
},
error => {
this.notifySvc.error('修改失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
}
);
}
@@ -310,14 +313,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageRuleModalVisible = false;
this.notifySvc.success('新增成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
this.loadRulesTable();
} else {
this.notifySvc.error('新增失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
}
},
error => {
this.notifySvc.error('新增失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
}
);
} else {
@@ -333,14 +336,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageRuleModalVisible = false;
this.notifySvc.success('修改成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
this.loadRulesTable();
} else {
this.notifySvc.error('修改失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
}
},
error => {
this.notifySvc.error('修改失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
}
);
}

View File

@@ -3,14 +3,14 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="alert"></i>
<span>告警阈值配置</span>
<span>{{ 'menu.alert.setting' | i18n }}</span>
<a href="https://tancloud.cn/docs/help/alert_threshold" target="_blank" style="float: right; margin-right: 5%">
<span>帮助&nbsp;</span>
<span>{{ 'common.button.help' | i18n }}&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -19,17 +19,17 @@
<button nz-button nzType="primary" (click)="onNewAlertDefine()">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
新增阈值
{{ 'alert.setting.new' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onEditAlertDefine()">
<i nz-icon nzType="edit" nzTheme="outline"></i>
编辑
{{ 'common.button.edit' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onDeleteAlertDefines()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
{{ 'common.button.delete' | i18n }}
</button>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
@@ -51,14 +51,14 @@
<thead>
<tr>
<th nzAlign="center" nzLeft nzWidth="4%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
<th nzAlign="center" nzLeft>指标对象</th>
<th nzAlign="center">阈值触发表达式</th>
<th nzAlign="center">告警级别</th>
<th nzAlign="center">触发次数</th>
<th nzAlign="center">通知模版</th>
<th nzAlign="center">全局默认</th>
<th nzAlign="center">最新修改时间</th>
<th nzAlign="center">操作</th>
<th nzAlign="center" nzLeft>{{ 'alert.setting.target' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.expr' | i18n }}</th>
<th nzAlign="center">{{ 'alert.priority' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.times' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.template' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.default' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit' | i18n }}</th>
</tr>
</thead>
<tbody>
@@ -73,36 +73,54 @@
<td nzAlign="center">
<nz-tag *ngIf="data.priority == 0" nzColor="red">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>紧急告警</span>
<span>{{ 'alert.priority.0' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 1" nzColor="orange">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>严重告警</span>
<span>{{ 'alert.priority.1' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 2" nzColor="yellow">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>警告告警</span>
<span>{{ 'alert.priority.2' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">{{ data.times }}</td>
<td nzAlign="center">{{ data.template }}</td>
<td nzAlign="center">
<nz-tag *ngIf="data.preset" nzColor="green">
<span></span>
<span>{{ 'common.yes' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="!data.preset" nzColor="orange">
<span></span>
<span>{{ 'common.no' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onOpenConnectModal(data.id, data.app)" nz-tooltip nzTooltipTitle="配置关联监控">
<button
nz-button
nzType="primary"
(click)="onOpenConnectModal(data.id, data.app)"
nz-tooltip
[nzTooltipTitle]="'alert.setting.connect' | i18n"
>
<i nz-icon nzType="link" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onEditOneAlertDefine(data.id)" nz-tooltip nzTooltipTitle="修改告警配置">
<button
nz-button
nzType="primary"
(click)="onEditOneAlertDefine(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.setting.edit' | i18n"
>
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onDeleteOneAlertDefine(data.id)" nz-tooltip nzTooltipTitle="删除告警配置">
<button
nz-button
nzType="primary"
(click)="onDeleteOneAlertDefine(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.setting.delete' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
@@ -110,12 +128,12 @@
</tbody>
</nz-table>
<ng-template #rangeTemplate> 总量 {{ total }} </ng-template>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }} </ng-template>
<!-- 新增或修改告警定义弹出框 -->
<nz-modal
[(nzVisible)]="isManageModalVisible"
[nzTitle]="isManageModalAdd ? '新增告警阈值' : '修改告警阈值'"
[nzTitle]="isManageModalAdd ? ('alert.setting.new' | i18n) : ('alert.setting.edit' | i18n)"
(nzOnCancel)="onManageModalCancel()"
(nzOnOk)="onManageModalOk()"
nzMaskClosable="false"
@@ -125,7 +143,7 @@
<div *nzModalContent class="-inner-content">
<form nz-form #defineForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="target" nzRequired="true">指标对象</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="target" nzRequired="true">{{ 'alert.setting.target' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<nz-cascader
required
@@ -140,19 +158,19 @@
<nz-form-item>
<nz-col [nzSpan]="8" nzOffset="7">
<nz-collapse>
<nz-collapse-panel [nzActive]="isManageModalAdd" nzHeader="支持的阈值触发表达式环境变量与操作符">
<nz-collapse-panel [nzActive]="isManageModalAdd" [nzHeader]="'alert.setting.expr.tip' | i18n">
<nz-list nzSize="small" nzSplit="false">
<nz-list-item *ngIf="cascadeValues.length == 3">
<code>{{ cascadeValues[2] }} : 选中的指标对象</code>
<code>{{ cascadeValues[2] }} : {{ 'alert.setting.target.tip' | i18n }}</code>
</nz-list-item>
<nz-list-item *ngFor="let item of otherMetrics">
<code>{{ item }} : 所属行其它指标对象</code>
<code>{{ item }} : {{ 'alert.setting.target.other' | i18n }}</code>
</nz-list-item>
<nz-list-item *ngIf="otherMetrics.length != 0">
<code>instance : 所属行实例</code>
<code>instance : {{ 'alert.setting.target.instance' | i18n }}</code>
</nz-list-item>
<nz-list-item>
<code>支持操作符函数 : equals(str1,str2), ==, <, <=, >, >=, !=, ( ), +, -, &&, ||</code>
<code>{{ 'alert.setting.operator' | i18n }} : equals(str1,str2), ==, <, <=, >, >=, !=, ( ), +, -, &&, ||</code>
</nz-list-item>
</nz-list>
</nz-collapse-panel>
@@ -160,13 +178,8 @@
</nz-col>
</nz-form-item>
<nz-form-item>
<nz-form-label
[nzSpan]="7"
nzFor="expr"
nzRequired="true"
nzTooltipTitle="根据此表达式来计算判断是否触发阈值,表达式环境变量和操作符见上方"
>
阈值触发表达式
<nz-form-label [nzSpan]="7" nzFor="expr" nzRequired="true" [nzTooltipTitle]="'alert.setting.expr.label' | i18n">
{{ 'alert.setting.expr' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<nz-textarea-count [nzMaxCharacterCount]="100">
@@ -177,32 +190,27 @@
nz-input
name="expr"
id="expr"
placeholder="根据此表达式计算判断是否触发阈值.&#10;示例: responseTime&gt;40"
[placeholder]="('alert.setting.expr.example' | i18n) + ': responseTime&gt;40'"
>
</textarea>
</nz-textarea-count>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
nzSpan="7"
nzRequired="true"
nzFor="priority"
nzTooltipTitle="触发阈值的告警级别,从低到高依次为:警告-warning严重-critical紧急-emergency"
>
告警级别
<nz-form-label nzSpan="7" nzRequired="true" nzFor="priority" [nzTooltipTitle]="'alert.setting.priority.tip' | i18n">
{{ 'alert.priority' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-select [(ngModel)]="define.priority" nzPlaceHolder="Choose" name="priority" id="priority">
<nz-option [nzValue]="0" nzLabel="紧急告警"></nz-option>
<nz-option [nzValue]="1" nzLabel="严重告警"></nz-option>
<nz-option [nzValue]="2" nzLabel="警告告警"></nz-option>
<nz-option [nzValue]="0" [nzLabel]="'alert.priority.0' | i18n"></nz-option>
<nz-option [nzValue]="1" [nzLabel]="'alert.priority.1' | i18n"></nz-option>
<nz-option [nzValue]="2" [nzLabel]="'alert.priority.2' | i18n"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="duration" nzTooltipTitle="设置触发阈值多少次之后才会发送告警">
触发次数
<nz-form-label nzSpan="7" nzRequired="true" nzFor="duration" [nzTooltipTitle]="'alert.setting.times.tip' | i18n">
{{ 'alert.setting.times' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-input-number [(ngModel)]="define.times" [nzMin]="1" [nzMax]="10" [nzStep]="1" required name="duration" id="duration">
@@ -212,25 +220,25 @@
<nz-form-item>
<nz-col [nzSpan]="8" nzOffset="7">
<nz-collapse>
<nz-collapse-panel [nzActive]="isManageModalAdd" nzHeader="支持的通知模版环境变量">
<nz-collapse-panel [nzActive]="isManageModalAdd" [nzHeader]="'alert.setting.template.tip' | i18n">
<nz-list nzSize="small" nzSplit="false">
<nz-list-item>
<code>&#36;&#123;app&#125; : 监控类型名称</code>
<code>&#36;&#123;app&#125; : {{ 'alert.setting.template.monitor-type' | i18n }}</code>
</nz-list-item>
<nz-list-item>
<code>&#36;&#123;metrics&#125; : 监控指标集合名称</code>
<code>&#36;&#123;metrics&#125; : {{ 'alert.setting.template.metrics-name' | i18n }}</code>
</nz-list-item>
<nz-list-item *ngIf="cascadeValues.length == 3">
<code>&#36;&#123;metric&#125; : 监控指标名称</code>
<code>&#36;&#123;metric&#125; : {{ 'alert.setting.template.metric-name' | i18n }}</code>
</nz-list-item>
<nz-list-item *ngIf="cascadeValues.length == 3">
<code>&#36;{{ '{' + cascadeValues[2] + '}' }} : 监控指标对象值</code>
<code>&#36;{{ '{' + cascadeValues[2] + '}' }} : {{ 'alert.setting.template.metric-value' | i18n }}</code>
</nz-list-item>
<nz-list-item *ngFor="let item of otherMetrics">
<code>&#36;{{ '{' + item + '}' }} : 所属行其它指标值</code>
<code>&#36;{{ '{' + item + '}' }} : {{ 'alert.setting.template.other-value' | i18n }}</code>
</nz-list-item>
<nz-list-item>
<code>&#36;&#123;instance&#125; : 所属行实例值</code>
<code>&#36;&#123;instance&#125; : {{ 'alert.setting.template.instance-value' | i18n }}</code>
</nz-list-item>
</nz-list>
</nz-collapse-panel>
@@ -238,8 +246,8 @@
</nz-col>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="template" nzRequired="true" nzTooltipTitle="告警触发后发送的通知信息模版,模版环境变量见上方">
通知模版
<nz-form-label [nzSpan]="7" nzFor="template" nzRequired="true" [nzTooltipTitle]="'alert.setting.template.label' | i18n">
{{ 'alert.setting.template' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<nz-textarea-count [nzMaxCharacterCount]="200">
@@ -250,20 +258,24 @@
required
name="template"
id="template"
placeholder="请输入告警的通知模版.&#10;示例: ${app}.${metrics}.${metric}'s value is too high"
[placeholder]="'alert.setting.template.example' | i18n"
>
</textarea>
</nz-textarea-count>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="preset" nzTooltipTitle="此告警阈值配置是否应用于全局所有此类型监控"> 全局默认 </nz-form-label>
<nz-form-label nzSpan="7" nzFor="preset" [nzTooltipTitle]="'alert.setting.default.tip' | i18n">
{{ 'alert.setting.default' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="define.preset" name="preset" id="preset"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable" nzTooltipTitle="此告警阈值配置开启生效或关闭"> 启用告警 </nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable" [nzTooltipTitle]="'alert.setting.enable.tip' | i18n">
{{ 'alert.setting.enable' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="define.enable" [ngModelOptions]="{ standalone: true }" name="enable" id="enable"></nz-switch>
</nz-form-control>
@@ -276,7 +288,7 @@
<nz-modal
[(nzVisible)]="isConnectModalVisible"
nzTitle="告警定义关联监控"
[nzTitle]="'alert.setting.connect' | i18n"
(nzOnCancel)="onConnectModalCancel()"
(nzOnOk)="onConnectModalOk()"
nzMaskClosable="false"
@@ -303,8 +315,8 @@
<thead>
<tr>
<th [nzChecked]="stat.checkAll" [nzIndeterminate]="stat.checkHalf" (nzCheckedChange)="onItemSelectAll($event)"></th>
<th *ngIf="direction == 'left'">未关联监控</th>
<th *ngIf="direction == 'right'">已关联监控</th>
<th *ngIf="direction == 'left'">{{ 'alert.setting.connect.left' | i18n }}</th>
<th *ngIf="direction == 'right'">{{ 'alert.setting.connect.right' | i18n }}</th>
</tr>
</thead>
<tbody>

View File

@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTableQueryParams } from 'ng-zorro-antd/table';
@@ -25,7 +27,8 @@ export class AlertSettingComponent implements OnInit {
private notifySvc: NzNotificationService,
private appDefineSvc: AppDefineService,
private monitorSvc: MonitorService,
private alertDefineSvc: AlertDefineService
private alertDefineSvc: AlertDefineService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
pageIndex: number = 1;
@@ -98,7 +101,7 @@ export class AlertSettingComponent implements OnInit {
onEditOneAlertDefine(alertDefineId: number) {
if (alertDefineId == null) {
this.notifySvc.warning('未选中任何待编辑项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
return;
}
this.editAlertDefine(alertDefineId);
@@ -107,11 +110,11 @@ export class AlertSettingComponent implements OnInit {
onEditAlertDefine() {
// 编辑时只能选中一个
if (this.checkedDefineIds == null || this.checkedDefineIds.size === 0) {
this.notifySvc.warning('未选中任何待编辑项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
return;
}
if (this.checkedDefineIds.size > 1) {
this.notifySvc.warning('只能对一个选中项进行编辑!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.one-select-edit'), '');
return;
}
let alertDefineId = 0;
@@ -138,24 +141,24 @@ export class AlertSettingComponent implements OnInit {
this.cascadeValues = [this.define.app, this.define.metric, this.define.field];
this.cascadeOnChange(this.cascadeValues);
} else {
this.notifySvc.error('查询此监控定义详情失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.monitor-fail'), message.msg);
}
},
error => {
this.notifySvc.error('查询此监控定义详情失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.monitor-fail'), error.msg);
}
);
}
onDeleteAlertDefines() {
if (this.checkedDefineIds == null || this.checkedDefineIds.size === 0) {
this.notifySvc.warning('未选中任何待删除项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlertDefines(this.checkedDefineIds)
@@ -166,9 +169,9 @@ export class AlertSettingComponent implements OnInit {
let defineIds = new Set<number>();
defineIds.add(alertDefineId);
this.modal.confirm({
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlertDefines(defineIds)
@@ -177,7 +180,7 @@ export class AlertSettingComponent implements OnInit {
deleteAlertDefines(defineIds: Set<number>) {
if (defineIds == null || defineIds.size == 0) {
this.notifySvc.warning('未选中任何待删除项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
return;
}
this.tableLoading = true;
@@ -185,17 +188,17 @@ export class AlertSettingComponent implements OnInit {
message => {
deleteDefines$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success('删除成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.loadAlertDefineTable();
} else {
this.tableLoading = false;
this.notifySvc.error('删除失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
}
},
error => {
this.tableLoading = false;
deleteDefines$.unsubscribe();
this.notifySvc.error('删除失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
}
);
}
@@ -242,7 +245,7 @@ export class AlertSettingComponent implements OnInit {
}
this.appHierarchies.forEach(hierarchy => {
if (hierarchy.value == values[0]) {
hierarchy.children.forEach((metrics: { value: string; children: any[]}) => {
hierarchy.children.forEach((metrics: { value: string; children: any[] }) => {
if (metrics.value == values[1]) {
this.otherMetrics = [];
metrics.children.forEach(item => {
@@ -276,14 +279,14 @@ export class AlertSettingComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageModalVisible = false;
this.notifySvc.success('新增成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
this.loadAlertDefineTable();
} else {
this.notifySvc.error('新增失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
}
},
error => {
this.notifySvc.error('新增失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
}
);
} else {
@@ -299,14 +302,14 @@ export class AlertSettingComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageModalVisible = false;
this.notifySvc.success('修改成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
this.loadAlertDefineTable();
} else {
this.notifySvc.error('修改失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
}
},
error => {
this.notifySvc.error('修改失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
}
);
}
@@ -373,16 +376,16 @@ export class AlertSettingComponent implements OnInit {
message => {
this.isConnectModalOkLoading = false;
if (message.code === 0) {
this.notifySvc.success('应用成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.apply-success'), '');
this.isConnectModalVisible = false;
this.loadAlertDefineTable();
} else {
this.notifySvc.error('应用失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), message.msg);
}
},
error => {
this.isConnectModalOkLoading = false;
this.notifySvc.error('应用失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), error.msg);
}
);
}

View File

@@ -10,16 +10,19 @@
</div>
<div nz-col nzSpan="14" class="p-md text-white">
<nz-tag class="mb-xs">
<span>正常 </span><span style="font-weight: bolder">{{ appCountService.availableSize }}</span>
<span>{{ 'monitor.status.available' | i18n }} </span
><span style="font-weight: bolder">{{ appCountService.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可用 </span><span style="font-weight: bolder">{{ appCountService.unAvailableSize }}</span>
<span>{{ 'monitor.status.unavailable' | i18n }} </span
><span style="font-weight: bolder">{{ appCountService.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可达 </span><span style="font-weight: bolder">{{ appCountService.unReachableSize }}</span>
<span>{{ 'monitor.status.unreachable' | i18n }} </span
><span style="font-weight: bolder">{{ appCountService.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>未监控 </span><span style="font-weight: bolder">{{ appCountService.unManageSize }}</span>
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountService.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -35,16 +38,16 @@
</div>
<div nz-col nzSpan="14">
<nz-tag class="mb-xs">
<span>正常 </span><span style="font-weight: bolder">{{ appCountDb.availableSize }}</span>
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可用 </span><span style="font-weight: bolder">{{ appCountDb.unAvailableSize }}</span>
<span>{{ 'monitor.status.unavailable' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可达 </span><span style="font-weight: bolder">{{ appCountDb.unReachableSize }}</span>
<span>{{ 'monitor.status.unreachable' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>未监控 </span><span style="font-weight: bolder">{{ appCountDb.unManageSize }}</span>
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -60,16 +63,16 @@
</div>
<div nz-col nzSpan="14">
<nz-tag class="mb-xs">
<span>正常 </span><span style="font-weight: bolder">{{ appCountOs.availableSize }}</span>
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可用 </span><span style="font-weight: bolder">{{ appCountOs.unAvailableSize }}</span>
<span>{{ 'monitor.status.unavailable' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可达 </span><span style="font-weight: bolder">{{ appCountOs.unReachableSize }}</span>
<span>{{ 'monitor.status.unreachable' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>未监控 </span><span style="font-weight: bolder">{{ appCountOs.unManageSize }}</span>
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -85,16 +88,16 @@
</div>
<div nz-col nzSpan="14">
<nz-tag class="mb-xs">
<span>正常 </span><span style="font-weight: bolder">{{ appCountCustom.availableSize }}</span>
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可用 </span><span style="font-weight: bolder">{{ appCountCustom.unAvailableSize }}</span>
<span>{{ 'monitor.status.unavailable' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>不可达 </span><span style="font-weight: bolder">{{ appCountCustom.unReachableSize }}</span>
<span>{{ 'monitor.status.unreachable' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>未监控 </span><span style="font-weight: bolder">{{ appCountCustom.unManageSize }}</span>
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -114,21 +117,21 @@
<div nz-row nzGutter="16" style="margin-top: 10px">
<div nz-col nzXs="24" nzSm="24" nzMd="12" class="mb-md">
<nz-card nzHoverable nzTitle="最近告警列表" [nzExtra]="extraTemplate">
<nz-card nzHoverable [nzTitle]="'dashboard.alerts.title' | i18n" [nzExtra]="extraTemplate">
<nz-timeline nzMode="left">
<nz-timeline-item *ngFor="let alert of alerts; let i = index" [nzLabel]="(alert.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss')?.trim()">
<p style="font-weight: 400">
<nz-tag *ngIf="alert.priority == 0" nzColor="red">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>紧急告警</span>
<span>{{ 'alert.priority.0' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="alert.priority == 1" nzColor="orange">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>严重告警</span>
<span>{{ 'alert.priority.1' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="alert.priority == 2" nzColor="yellow">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>警告告警</span>
<span>{{ 'alert.priority.2' | i18n }}</span>
</nz-tag>
<span>[{{ alert.monitorName }}] </span>
{{ alert.content }}
@@ -162,5 +165,5 @@
</div>
<ng-template #extraTemplate>
<a [routerLink]="['/alert/center']">进入告警中心</a>
<a [routerLink]="['/alert/center']">{{ 'dashboard.alerts.enter' | i18n }}</a>
</ng-template>

View File

@@ -48,13 +48,13 @@ export class DashboardComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.appsCountTheme = {
title: {
text: '监控总览',
subtext: '监控类型纳管数量分布',
text: this.i18nSvc.fanyi('dashboard.monitors.title'),
subtext: this.i18nSvc.fanyi('dashboard.monitors.sub-title'),
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c}个监控 占比({d}%)'
formatter: `{a} <br/>{b} : {c}${this.i18nSvc.fanyi('dashboard.monitors.formatter')}({d}%)`
},
legend: {
show: false,
@@ -66,7 +66,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
calculable: true,
series: [
{
name: '总量',
name: this.i18nSvc.fanyi('dashboard.monitors.total'),
type: 'pie',
selectedMode: 'single',
color: '#722ED1',
@@ -81,10 +81,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
labelLine: {
show: false
},
data: [{ value: 0, name: '监控总量' }]
data: [{ value: 0, name: this.i18nSvc.fanyi('dashboard.monitors.total') }]
},
{
name: '纳管数量分布',
name: this.i18nSvc.fanyi('dashboard.monitors.distribute'),
type: 'pie',
radius: ['45%', '65%'],
labelLine: {
@@ -127,7 +127,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
};
this.alertsTheme = {
title: {
subtext: '告警分布',
subtext: this.i18nSvc.fanyi('dashboard.alerts.distribute'),
left: 'center'
},
tooltip: {
@@ -138,14 +138,14 @@ export class DashboardComponent implements OnInit, OnDestroy {
},
xAxis: {
type: 'category',
data: ['警告告警', '严重告警', '紧急告警']
data: [this.i18nSvc.fanyi('alert.priority.2'), this.i18nSvc.fanyi('alert.priority.1'), this.i18nSvc.fanyi('alert.priority.0')]
},
yAxis: {
type: 'value'
},
series: [
{
name: '告警数量',
name: this.i18nSvc.fanyi('dashboard.alerts.num'),
type: 'bar',
data: [
{
@@ -176,7 +176,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
};
this.alertsDealTheme = {
title: {
subtext: '告警处理',
subtext: this.i18nSvc.fanyi('dashboard.alerts.deal'),
left: 'center'
},
tooltip: {
@@ -184,7 +184,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
},
series: [
{
name: '告警处理率',
name: this.i18nSvc.fanyi('dashboard.alerts.deal-percent'),
type: 'gauge',
progress: {
show: true
@@ -196,7 +196,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
data: [
{
value: 100,
name: '告警处理率'
name: this.i18nSvc.fanyi('dashboard.alerts.deal-percent')
}
]
}
@@ -279,7 +279,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
}
});
// @ts-ignore
this.appsCountTheme.series[0].data = [{ value: total, name: '监控总量' }];
this.appsCountTheme.series[0].data = [{ value: total, name: this.i18nSvc.fanyi('dashboard.monitors.total') }];
// @ts-ignore
this.appsCountTheme.series[1].data = this.appsCountTableData;
this.appsCountEChartOption = this.appsCountTheme;
@@ -397,7 +397,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.alertsDealTheme.series[0].data = [
{
value: summary.rate,
name: '告警处理率'
name: this.i18nSvc.fanyi('dashboard.alerts.deal-percent')
}
];
this.alertsEChartOption = this.alertsTheme;

View File

@@ -1,4 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { EChartsOption } from 'echarts';
import { finalize } from 'rxjs/operators';
@@ -32,7 +34,7 @@ export class MonitorDataChartComponent implements OnInit {
echartsInstance!: any;
// 查询历史数据时间段 默认最近6小时
timePeriod: string = '6h';
constructor(private monitorSvc: MonitorService) {}
constructor(private monitorSvc: MonitorService, @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService) {}
ngOnInit(): void {
this.lineHistoryTheme = {
@@ -51,8 +53,8 @@ export class MonitorDataChartComponent implements OnInit {
dataZoom: {
yAxisIndex: 'none',
title: {
zoom: '区域缩放',
back: '缩放还原'
zoom: this.i18nSvc.fanyi('monitors.detail.chart.zoom'),
back: this.i18nSvc.fanyi('monitors.detail.chart.back')
},
emphasis: {
iconStyle: {
@@ -61,7 +63,7 @@ export class MonitorDataChartComponent implements OnInit {
}
},
saveAsImage: {
title: '保存图片',
title: this.i18nSvc.fanyi('monitors.detail.chart.save'),
emphasis: {
iconStyle: {
textPosition: 'left'
@@ -70,7 +72,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod1h: {
show: true,
title: '查询近1小时',
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1h'),
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -83,7 +85,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod6h: {
show: true,
title: '查询近6小时',
title: this.i18nSvc.fanyi('monitors.detail.chart.query-6h'),
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -96,7 +98,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod1d: {
show: true,
title: '查询近1天',
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1d'),
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -109,7 +111,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod1w: {
show: true,
title: '查询近1周',
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1w'),
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -122,7 +124,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod4w: {
show: true,
title: '查询近1月',
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1m'),
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -135,7 +137,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myRefresh: {
show: true,
title: '刷新',
title: this.i18nSvc.fanyi('common.refresh'),
icon: 'path://M663.881 339.763l274.021-0.742 0.058-13.271 0.699 0c-0.204-0.48-0.495-0.945-0.699-1.426L938.658 65l-23.776 0.044L914.3 280.41C835.9 151.374 694.321 65 532.342 65c-246.869 0-447 200.132-447 447 0 246.84 200.131 447 447 447 180.343 0 335.657-106.919 406.316-260.75l-33.176 0C836.948 835.027 695.456 929.2 532.342 929.2c-230.048 0-417.2-187.152-417.2-417.2s187.152-417.2 417.2-417.2c158.895 0 297.068 89.487 367.466 220.547l-235.868 0.64L663.881 339.763z',
emphasis: {
iconStyle: {
@@ -183,7 +185,7 @@ export class MonitorDataChartComponent implements OnInit {
};
if (this.unit != undefined || this.unit != null) {
// @ts-ignore
this.lineHistoryTheme.title?.subtext = `单位 ${this.unit}`;
this.lineHistoryTheme.title?.subtext = `${this.i18nSvc.fanyi('monitors.detail.chart.unit')} ${this.unit}`;
}
this.loadData();
}
@@ -251,7 +253,7 @@ export class MonitorDataChartComponent implements OnInit {
} else {
this.eChartOption = this.lineHistoryTheme;
this.eChartOption.title = {
text: `${this.metrics}.${this.metric}` + '\n\n\n' + '暂无数据',
text: `${`${this.metrics}.${this.metric}` + '\n\n\n'}${this.i18nSvc.fanyi('monitors.detail.chart.no-data')}`,
textStyle: {
fontSize: 16,
fontFamily: 'monospace',

View File

@@ -17,8 +17,8 @@
<nz-table #smallTable nzSize="small" nzNoResult="No Metrics Data" nzFrontPagination="false" [nzData]="valueRows">
<thead>
<tr>
<th style="text-align: center">属性</th>
<th style="text-align: center"></th>
<th style="text-align: center">{{ 'common.name' | i18n }}</th>
<th style="text-align: center">{{ 'common.value' | i18n }}</th>
</tr>
</thead>
<tbody>
@@ -33,17 +33,11 @@
<ng-template #monitor_metrics_card_title>
<p style="font-size: small; text-align: center; margin-bottom: 3px">{{ metrics }}</p>
<div>
<a nz-popover [nzPopoverContent]="'最近采集时间 ' + (time | _date: 'yyyy-MM-dd HH:mm:ss')">
<a nz-popover [nzPopoverContent]="'Last Collect Time ' + (time | _date: 'yyyy-MM-dd HH:mm:ss')">
<i nz-icon nzType="field-time" nzTheme="outline"></i
></a>
<i style="font-size: 0.3px; font-weight: normal; color: rgba(112,112,112,0.89)">采集时间:{{ time | _date: 'HH:mm:ss' }}</i>
<i style="font-size: 0.3px; font-weight: normal; color: rgba(112, 112, 112, 0.89)">
{{ 'monitors.collect.time' | i18n }}:{{ time | _date: 'HH:mm:ss' }}
</i>
</div>
</ng-template>
<!--<nz-card *ngIf="!isTable" nzHoverable style="height:auto;margin-left: 14px;" [nzBordered]="true"-->
<!-- [nzTitle]="monitor_metrics_card_title" >-->
<!-- <div *ngFor="let field of fields;let i = index;" nz-row nzGutter="16">-->
<!-- <div nz-col nzSpan="10"><p style="text-align: right">{{field.name}}</p></div>-->
<!-- <div nz-col nzSpan="14"><p style="text-align: left">{{rowValues[i].origin}}</p></div>-->
<!-- </div>-->
<!--</nz-card>-->

View File

@@ -3,20 +3,20 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/monitors']" [queryParams]="{ app: app ? app : '' }">
<i nz-icon nzType="monitor"></i>
<span>监控列表</span>
<span>{{ 'monitors.list' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="pie-chart"></i>
<span>{{ 'monitor.app.' + app | i18n }} 监控详情</span>
<span>{{ 'monitor.app.' + app | i18n }} {{ 'monitors.detail' | i18n }}</span>
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
<span>帮助&nbsp;</span>
<span>{{ 'common.button.help' | i18n }} </span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -33,7 +33,9 @@
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">名称</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.name' | i18n }}</p></div
>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.name }}</p></div
>
@@ -45,58 +47,66 @@
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">端口</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.port' | i18n }}</p></div
>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ port }}</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">描述</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.description' | i18n }}</p></div
>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.description }}</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">状态</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.status' | i18n }}</p></div
>
<div nz-col nzSpan="16">
<nz-tag *ngIf="monitor?.status == 0" nzColor="default">
<i nz-icon nzType="robot" nzTheme="outline"></i>
<span>未监控</span>
<span>{{ 'monitor.status.un-manage' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 1" nzColor="success">
<i nz-icon nzType="smile" nzTheme="outline"></i>
<span>正常监控</span>
<span>{{ 'monitor.status.available' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 2" nzColor="warning">
<i nz-icon nzType="meh" nzTheme="outline"></i>
<span>监控不可用</span>
<span>{{ 'monitor.status.unavailable' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 3" nzColor="error">
<i nz-icon nzType="frown" nzTheme="outline"></i>
<span>监控不可达</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 4" nzColor="default">
<i nz-icon nzType="sync"></i>
<span>监控已挂起</span>
<span>{{ 'monitor.status.unreachable' | i18n }}</span>
</nz-tag>
</div>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">采集间隔</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitor.intervals' | i18n }}</p></div
>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.intervals }}s</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">创建时间</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'common.new-time' | i18n }}</p></div
>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss' }}</p></div
><p style="text-align: left">{{ monitor?.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss' }}</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"><p style="text-align: right">更新时间</p></div>
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'common.edit-time' | i18n }}</p></div
>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.gmtUpdate | date: 'YYYY-MM-dd HH:mm:ss' }}</p></div
><p style="text-align: left">{{ monitor?.gmtUpdate | date: 'YYYY-MM-dd HH:mm:ss' }}</p></div
>
</div>
</nz-card>
@@ -107,7 +117,7 @@
<nz-tab [nzTitle]="titleTemplate">
<ng-template #titleTemplate>
<i nz-icon nzType="pic-right" style="margin-left: 10px"></i>
监控实时数据详情
{{ 'monitors.detail.realtime' | i18n }}
</ng-template>
<div style="display: flex; justify-content: flex-start; flex-wrap: wrap">
<div *ngFor="let metric of metrics; let i = index">
@@ -118,7 +128,7 @@
<nz-tab [nzTitle]="title2Template" (nzClick)="initMetricChart()">
<ng-template #title2Template>
<i nz-icon nzType="pic-right" style="margin-left: 10px"></i>
监控历史图表详情
{{ 'monitors.detail.history' | i18n }}
</ng-template>
<div style="display: flex; justify-content: flex-start; flex-wrap: wrap">
<div *ngFor="let item of chartMetrics; let i = index">
@@ -138,5 +148,5 @@
</nz-layout>
<ng-template #monitor_basic_card_title>
<p style="font-size: small; text-align: left; margin-bottom: 3px">监控基本属性</p>
<p style="font-size: small; text-align: left; margin-bottom: 3px">{{ 'monitors.detail.basic' | i18n }}</p>
</ng-template>

View File

@@ -3,20 +3,20 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/monitors']" [queryParams]="{ app: monitor.app ? monitor.app : '' }">
<i nz-icon nzType="monitor"></i>
<span>监控列表</span>
<span>{{ 'monitors.list' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="edit"></i>
<span>修改 {{ 'monitor.app.' + monitor.app | i18n }} 监控</span>
<span>{{ 'monitors.edit' | i18n }} {{ 'monitor.app.' + monitor.app | i18n }} {{ 'monitor' | i18n }}</span>
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
<span>帮助&nbsp;</span>
<span>{{ 'common.button.help' | i18n }} </span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -27,17 +27,19 @@
<div class="-inner-content">
<form nz-form #editForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" nzTooltipTitle="被监控的对端IP或域名"> 监控Host </nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" [nzTooltipTitle]="'monitor.host.tip' | i18n">
{{ 'monitor.host' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="monitor.host" nz-input name="host" type="text" id="host" required placeholder="请输入域名或IP" />
<input [(ngModel)]="monitor.host" nz-input name="host" type="text" id="host" required [placeholder]="'monitor.host.tip' | i18n" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" nzTooltipTitle="标识此监控的名称,名称需要保证唯一性">
监控名称
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" [nzTooltipTitle]="'monitor.name.tip' | i18n">
{{ 'monitor.name' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" placeholder="监控名称需要保证唯一性" />
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" [placeholder]="'monitor.name.tip' | i18n" />
</nz-form-control>
</nz-form-item>
@@ -163,7 +165,7 @@
</nz-form-item>
<nz-collapse [nzGhost]="true">
<nz-collapse-panel nzHeader="高级" [nzHeader]="extraColHeader" [nzShowArrow]="false">
<nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
<nz-form-item *ngFor="let paramDefine of advancedParamDefines; let i = index">
<nz-form-label
*ngIf="paramDefine.field !== 'host' && paramDefine.type === 'text'"
@@ -296,8 +298,8 @@
</nz-collapse-panel>
</nz-collapse>
<ng-template #extraColHeader>
<button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" nz-tooltip nzTooltipTitle="设置高级可选参数">
<span>高级设置</span>
<button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
<span>{{ 'monitors.advanced' | i18n }}</span>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</ng-template>
@@ -305,7 +307,9 @@
<nz-divider></nz-divider>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="intervals" nzTooltipTitle="监控周期性采集数据间隔时间,单位秒"> 采集间隔 </nz-form-label>
<nz-form-label nzSpan="7" nzFor="intervals" [nzTooltipTitle]="'monitor.intervals.tip' | i18n">
{{ 'monitor.intervals' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-input-number [(ngModel)]="monitor.intervals" [nzMin]="10" [nzMax]="604800" [nzStep]="60" name="intervals" id="intervals">
</nz-input-number>
@@ -313,14 +317,18 @@
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="detect" nzTooltipTitle="新增监控前是否先探测检查监控可用性"> 测试连接 </nz-form-label>
<nz-form-label nzSpan="7" nzFor="detect" [nzTooltipTitle]="'monitors.detect.tip' | i18n">
{{ 'monitors.detect' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="detected" name="detect" id="detect"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="description" nzTooltipTitle="更多标识和描述此监控的备注信息"> 描述备注 </nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="description" [nzTooltipTitle]="'monitor.description.tip' | i18n">
{{ 'monitor.description' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8">
<nz-textarea-count [nzMaxCharacterCount]="100">
<textarea [(ngModel)]="monitor.description" rows="3" nz-input name="description" id="description"></textarea>
@@ -330,9 +338,9 @@
<div nz-row>
<div nz-col nzSpan="8" nzOffset="9">
<button nz-button nzType="primary" type="submit" (click)="onDetect(editForm.form)"> 测试 </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(editForm.form)"> 确定 </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> 取消 </button>
<button nz-button nzType="primary" type="submit" (click)="onDetect(editForm.form)"> {{ 'common.button.detect' | i18n }} </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(editForm.form)"> {{ 'common.button.ok' | i18n }} </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
</div>
</div>
</form>

View File

@@ -1,8 +0,0 @@
.dynamic-button {
font-size: 20px;
margin-left: 45%;
}
.dynamic-button:hover {
font-size: 30px;
}

View File

@@ -1,7 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { TitleService } from '@delon/theme';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN, TitleService } from '@delon/theme';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { throwError } from 'rxjs';
import { switchMap } from 'rxjs/operators';
@@ -16,7 +17,7 @@ import { MonitorService } from '../../../service/monitor.service';
@Component({
selector: 'app-monitor-modify',
templateUrl: './monitor-edit.component.html',
styleUrls: ['./monitor-edit.component.less']
styles: []
})
export class MonitorEditComponent implements OnInit {
constructor(
@@ -25,7 +26,8 @@ export class MonitorEditComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private titleSvc: TitleService,
private notifySvc: NzNotificationService
private notifySvc: NzNotificationService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
paramDefines!: ParamDefine[];
@@ -64,15 +66,14 @@ export class MonitorEditComponent implements OnInit {
this.detected = message.data.detected ? message.data.detected : true;
} else {
console.warn(message.msg);
this.notifySvc.error('查询异常,此监控不存在', message.msg);
return throwError('查询此监控异常');
this.notifySvc.error(this.i18nSvc.fanyi('monitors.not-found'), message.msg);
return throwError(this.i18nSvc.fanyi('monitors.not-found'));
}
return this.appDefineSvc.getAppParamsDefine(this.monitor.app);
})
)
.subscribe(message => {
if (message.code === 0) {
this.paramDefines = message.data;
this.params = [];
this.advancedParams = [];
this.paramDefines = [];
@@ -169,15 +170,15 @@ export class MonitorEditComponent implements OnInit {
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success('修改监控成功', '');
this.notifySvc.success(this.i18nSvc.fanyi('monitors.edit.success'), '');
this.router.navigateByUrl(`/monitors?app=${this.monitor.app}`);
} else {
this.notifySvc.error('修改监控失败', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.edit.failed'), message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error('修改监控失败', error.error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.edit.failed'), error.error.msg);
}
);
}
@@ -218,14 +219,14 @@ export class MonitorEditComponent implements OnInit {
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success('探测成功', '');
this.notifySvc.success(this.i18nSvc.fanyi('monitors.detect.success'), '');
} else {
this.notifySvc.error('探测失败', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error('探测异常', error.error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), error.error.msg);
}
);
}

View File

@@ -3,12 +3,12 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="monitor"></i>
<span>{{ 'monitor.app.' + app | i18n }} 监控列表</span>
<span>{{ 'monitor.app.' + app | i18n }} {{ 'monitors.list' | i18n }}</span>
</nz-breadcrumb-item>
</nz-breadcrumb>
<nz-divider></nz-divider>
@@ -17,35 +17,37 @@
<button nz-button nzType="primary">
<a routerLink="/monitors/new" [queryParams]="{ app: app }">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
新增 {{ 'monitor.app.' + app | i18n }}
{{ 'monitors.new' | i18n }} {{ 'monitor.app.' + app | i18n }}
</a>
</button>
<button nz-button nzType="primary" (click)="onEditMonitor()">
<i nz-icon nzType="edit" nzTheme="outline"></i>
编辑
{{ 'monitors.edit' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onDeleteMonitors()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
{{ 'monitors.delete' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onEnableManageMonitors()">
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
启用监控
{{ 'monitors.enable' | i18n }}
</button>
<button nz-button nzType="primary" (click)="onCancelManageMonitors()">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
取消监控
{{ 'monitors.cancel' | i18n }}
</button>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchMonitors()"> 搜索 </button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchMonitors()">
{{ 'common.search' | i18n }}
</button>
<input
style="margin-right: 5px; float: right; width: 150px; border-radius: 9px; text-align: center"
nz-input
type="text"
placeholder="搜索监控"
[placeholder]="'monitors.search.placeholder' | i18n"
nzSize="default"
(keyup.enter)="onFilterSearchMonitors()"
[(ngModel)]="filterContent"
@@ -53,14 +55,14 @@
<nz-select
style="margin-right: 10px; float: right; width: 120px"
nzAllowClear
[nzPlaceHolder]="'监控状态过滤'"
[nzPlaceHolder]="'monitors.search.filter' | i18n"
[(ngModel)]="filterStatus"
>
<nz-option nzLabel="全部状态" nzValue="9"></nz-option>
<nz-option nzLabel="监控正常" nzValue="1"></nz-option>
<nz-option nzLabel="不可用" nzValue="2"></nz-option>
<nz-option nzLabel="不可达" nzValue="3"></nz-option>
<nz-option nzLabel="未监控" nzValue="0"></nz-option>
<nz-option [nzLabel]="'monitor.status.all' | i18n" nzValue="9"></nz-option>
<nz-option [nzLabel]="'monitor.status.available' | i18n" nzValue="1"></nz-option>
<nz-option [nzLabel]="'monitor.status.unavailable' | i18n" nzValue="2"></nz-option>
<nz-option [nzLabel]="'monitor.status.unreachable' | i18n" nzValue="3"></nz-option>
<nz-option [nzLabel]="'monitor.status.un-manage' | i18n" nzValue="0"></nz-option>
</nz-select>
</div>
@@ -82,12 +84,12 @@
<thead>
<tr>
<th nzAlign="center" nzLeft nzWidth="4%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
<th nzAlign="center" nzLeft>监控名称</th>
<th nzAlign="center">监控状态</th>
<th nzAlign="center">监控Host</th>
<th nzAlign="center">监控类型</th>
<th nzAlign="center">最新修改时间</th>
<th nzAlign="center">操作</th>
<th nzAlign="center" nzLeft>{{ 'monitor.name' | i18n }}</th>
<th nzAlign="center">{{ 'monitor.status' | i18n }}</th>
<th nzAlign="center">{{ 'monitor.host' | i18n }}</th>
<th nzAlign="center">{{ 'monitor.app' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit' | i18n }}</th>
</tr>
</thead>
<tbody>
@@ -101,23 +103,19 @@
<td nzAlign="center">
<nz-tag *ngIf="data.status == 0" nzColor="default">
<i nz-icon nzType="robot" nzTheme="outline"></i>
<span>未监控</span>
<span>{{ 'monitor.status.un-manage' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.status == 1" nzColor="success">
<i nz-icon nzType="smile" nzTheme="outline"></i>
<span>正常监控</span>
<span>{{ 'monitor.status.available' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.status == 2" nzColor="warning">
<i nz-icon nzType="meh" nzTheme="outline"></i>
<span>监控不可用</span>
<span>{{ 'monitor.status.unavailable' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.status == 3" nzColor="error">
<i nz-icon nzType="frown" nzTheme="outline"></i>
<span>监控不可达</span>
</nz-tag>
<nz-tag *ngIf="data.status == 4" nzColor="default">
<i nz-icon nzType="sync"></i>
<span>监控已挂起</span>
<span>{{ 'monitor.status.unreachable' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">{{ data.host }}</td>
@@ -129,16 +127,34 @@
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onEditOneMonitor(data.id)" nz-tooltip nzTooltipTitle="修改监控">
<button nz-button nzType="primary" (click)="onEditOneMonitor(data.id)" nz-tooltip [nzTooltipTitle]="'monitors.edit-monitor' | i18n">
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onDeleteOneMonitor(data.id)" nz-tooltip nzTooltipTitle="删除监控">
<button
nz-button
nzType="primary"
(click)="onDeleteOneMonitor(data.id)"
nz-tooltip
[nzTooltipTitle]="'monitors.delete-monitor' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onEnableManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="启用监控">
<button
nz-button
nzType="primary"
(click)="onEnableManageOneMonitor(data.id)"
nz-tooltip
[nzTooltipTitle]="'monitors.enable' | i18n"
>
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onCancelManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="取消监控">
<button
nz-button
nzType="primary"
(click)="onCancelManageOneMonitor(data.id)"
nz-tooltip
[nzTooltipTitle]="'monitors.cancel' | i18n"
>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</td>
@@ -146,4 +162,4 @@
</tbody>
</nz-table>
<ng-template #rangeTemplate> 总量 {{ total }} </ng-template>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }} </ng-template>

View File

@@ -1,5 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
@@ -20,7 +22,8 @@ export class MonitorListComponent implements OnInit {
private modal: NzModalService,
private notifySvc: NzNotificationService,
private msg: NzMessageService,
private monitorSvc: MonitorService
private monitorSvc: MonitorService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
app!: string;
@@ -102,7 +105,7 @@ export class MonitorListComponent implements OnInit {
onEditOneMonitor(monitorId: number) {
if (monitorId == null) {
this.notifySvc.warning('未选中任何待编辑项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
return;
}
this.router.navigateByUrl(`/monitors/${monitorId}/edit`);
@@ -113,11 +116,11 @@ export class MonitorListComponent implements OnInit {
onEditMonitor() {
// 编辑时只能选中一个监控
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning('未选中任何待编辑项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
return;
}
if (this.checkedMonitorIds.size > 1) {
this.notifySvc.warning('只能对一个选中项进行编辑!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.one-select-edit'), '');
return;
}
let monitorId = 0;
@@ -129,9 +132,9 @@ export class MonitorListComponent implements OnInit {
let monitors = new Set<number>();
monitors.add(monitorId);
this.modal.confirm({
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteMonitors(monitors)
@@ -140,13 +143,13 @@ export class MonitorListComponent implements OnInit {
onDeleteMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning('未选中任何待删除项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.delete-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteMonitors(this.checkedMonitorIds)
@@ -155,7 +158,7 @@ export class MonitorListComponent implements OnInit {
deleteMonitors(monitors: Set<number>) {
if (monitors == null || monitors.size == 0) {
this.notifySvc.warning('未选中任何待删除项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
return;
}
this.tableLoading = true;
@@ -163,30 +166,30 @@ export class MonitorListComponent implements OnInit {
message => {
deleteMonitors$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success('删除成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.loadMonitorTable();
} else {
this.tableLoading = false;
this.notifySvc.error('删除失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
}
},
error => {
this.tableLoading = false;
deleteMonitors$.unsubscribe();
this.notifySvc.error('删除失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
}
);
}
onCancelManageMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning('未选中任何待取消项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-cancel'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量取消监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.cancel-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.cancelManageMonitors(this.checkedMonitorIds)
@@ -197,9 +200,9 @@ export class MonitorListComponent implements OnInit {
let monitors = new Set<number>();
monitors.add(monitorId);
this.modal.confirm({
nzTitle: '请确认是否取消监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.cancel'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.cancelManageMonitors(monitors)
@@ -212,30 +215,30 @@ export class MonitorListComponent implements OnInit {
message => {
cancelManage$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success('取消监控成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.cancel-success'), '');
this.loadMonitorTable();
} else {
this.tableLoading = false;
this.notifySvc.error('取消监控失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.cancel-fail'), message.msg);
}
},
error => {
this.tableLoading = false;
cancelManage$.unsubscribe();
this.notifySvc.error('取消监控失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.cancel-fail'), error.msg);
}
);
}
onEnableManageMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning('未选中任何待启用监控项!', '');
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-enable'), '');
return;
}
this.modal.confirm({
nzTitle: '请确认是否批量启用监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.enable-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.enableManageMonitors(this.checkedMonitorIds)
@@ -246,9 +249,9 @@ export class MonitorListComponent implements OnInit {
let monitors = new Set<number>();
monitors.add(monitorId);
this.modal.confirm({
nzTitle: '请确认是否启用监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzTitle: this.i18nSvc.fanyi('common.confirm.enable'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.enableManageMonitors(monitors)
@@ -261,17 +264,17 @@ export class MonitorListComponent implements OnInit {
message => {
enableManage$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success('启用监控成功!', '');
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.enable-success'), '');
this.loadMonitorTable();
} else {
this.tableLoading = false;
this.notifySvc.error('启用监控失败!', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.enable-fail'), message.msg);
}
},
error => {
this.tableLoading = false;
enableManage$.unsubscribe();
this.notifySvc.error('启用监控失败!', error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.enable-fail'), error.msg);
}
);
}

View File

@@ -3,20 +3,20 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>仪表盘</span>
<span>{{ 'menu.dashboard' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/monitors']" [queryParams]="{ app: monitor.app ? monitor.app : '' }">
<i nz-icon nzType="monitor"></i>
<span>监控列表</span>
<span>{{ 'monitors.list' | i18n }}</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="plus-circle"></i>
<span>新增 {{ 'monitor.app.' + monitor.app | i18n }} 监控</span>
<span>{{ 'monitors.new' | i18n }} {{ 'monitor.app.' + monitor.app | i18n }} {{ 'monitor' | i18n }}</span>
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
<span>帮助&nbsp;</span>
<span>{{ 'common.button.help' | i18n }} </span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -27,7 +27,9 @@
<div class="-inner-content">
<form nz-form #newForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" nzTooltipTitle="被监控的对端IP或域名"> 监控Host </nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" [nzTooltipTitle]="'monitor.host.tip' | i18n">
{{ 'monitor.host' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input
[(ngModel)]="monitor.host"
@@ -36,17 +38,17 @@
type="text"
id="host"
required
placeholder="请输入域名或IP"
[placeholder]="'monitor.host.tip' | i18n"
(ngModelChange)="onHostChange($event)"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" nzTooltipTitle="标识此监控的名称,名称需要保证唯一性">
监控名称
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" [nzTooltipTitle]="'monitor.name.tip' | i18n">
{{ 'monitor.name' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" placeholder="监控名称需要保证唯一性" />
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" [placeholder]="'monitor.name.tip' | i18n" />
</nz-form-control>
</nz-form-item>
@@ -172,7 +174,7 @@
</nz-form-item>
<nz-collapse [nzGhost]="true">
<nz-collapse-panel nzHeader="高级" [nzHeader]="extraColHeader" [nzShowArrow]="false">
<nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
<nz-form-item *ngFor="let paramDefine of advancedParamDefines; let i = index">
<nz-form-label
*ngIf="paramDefine.field !== 'host' && paramDefine.type === 'text'"
@@ -305,8 +307,8 @@
</nz-collapse-panel>
</nz-collapse>
<ng-template #extraColHeader>
<button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" nz-tooltip nzTooltipTitle="设置高级可选参数">
<span>高级设置</span>
<button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
<span>{{ 'monitors.advanced' | i18n }}</span>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</ng-template>
@@ -314,7 +316,9 @@
<nz-divider></nz-divider>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="intervals" nzTooltipTitle="监控周期性采集数据间隔时间,单位秒"> 采集间隔 </nz-form-label>
<nz-form-label nzSpan="7" nzFor="intervals" [nzTooltipTitle]="'monitor.intervals.tip' | i18n">
{{ 'monitor.intervals' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-input-number [(ngModel)]="monitor.intervals" [nzMin]="10" [nzMax]="604800" [nzStep]="60" name="intervals" id="intervals">
</nz-input-number>
@@ -322,14 +326,18 @@
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="detect" nzTooltipTitle="新增监控前是否先探测检查监控可用性"> 测试连接 </nz-form-label>
<nz-form-label nzSpan="7" nzFor="detect" [nzTooltipTitle]="'monitors.detect.tip' | i18n">
{{ 'monitors.detect' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="detected" name="detect" id="detect"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="description" nzTooltipTitle="更多标识和描述此监控的备注信息"> 描述备注 </nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="description" [nzTooltipTitle]="'monitor.description.tip' | i18n">
{{ 'monitor.description' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="8">
<nz-textarea-count [nzMaxCharacterCount]="100">
<textarea [(ngModel)]="monitor.description" rows="3" nz-input name="description" id="description"></textarea>
@@ -339,9 +347,9 @@
<div nz-row>
<div nz-col nzSpan="8" nzOffset="9">
<button nz-button nzType="primary" type="submit" (click)="onDetect(newForm.form)"> 测试 </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(newForm.form)"> 确定 </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> 取消 </button>
<button nz-button nzType="primary" type="submit" (click)="onDetect(newForm.form)"> {{ 'common.button.detect' | i18n }} </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(newForm.form)"> {{ 'common.button.ok' | i18n }} </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
</div>
</div>
</form>

View File

@@ -1,8 +1,8 @@
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { I18NService } from '@core';
import { TitleService } from '@delon/theme';
import { ALAIN_I18N_TOKEN, TitleService } from '@delon/theme';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { switchMap } from 'rxjs/operators';
@@ -34,7 +34,7 @@ export class MonitorNewComponent implements OnInit {
private router: Router,
private notifySvc: NzNotificationService,
private cdr: ChangeDetectorRef,
private i18n: I18NService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
private titleSvc: TitleService,
private formBuilder: FormBuilder
) {
@@ -150,15 +150,15 @@ export class MonitorNewComponent implements OnInit {
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success('新增监控成功', '');
this.notifySvc.success(this.i18nSvc.fanyi('monitors.new.success'), '');
this.router.navigateByUrl(`/monitors?app=${this.monitor.app}`);
} else {
this.notifySvc.error('新增监控失败', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.new.failed'), message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error('新增监控失败', error.error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.new.failed'), error.error.msg);
}
);
}
@@ -199,14 +199,14 @@ export class MonitorNewComponent implements OnInit {
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success('探测成功', '');
this.notifySvc.success(this.i18nSvc.fanyi('monitors.detect.success'), '');
} else {
this.notifySvc.error('探测失败', message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error('探测异常', error.error.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), error.error.msg);
}
);
}

View File

@@ -1,6 +1,7 @@
import { NgModule, Type } from '@angular/core';
import { SharedModule } from '@shared';
import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
import { NzDividerModule } from 'ng-zorro-antd/divider';
import { NzLayoutModule } from 'ng-zorro-antd/layout';
import { NzRadioModule } from 'ng-zorro-antd/radio';
@@ -16,7 +17,6 @@ import { MonitorEditComponent } from './monitor-edit/monitor-edit.component';
import { MonitorListComponent } from './monitor-list/monitor-list.component';
import { MonitorNewComponent } from './monitor-new/monitor-new.component';
import { MonitorRoutingModule } from './monitor-routing.module';
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
const COMPONENTS: Array<Type<void>> = [
MonitorNewComponent,

View File

@@ -7,11 +7,11 @@
<nz-form-item>
<nz-form-control [nzErrorTip]="'validation.password.required' | i18n">
<nz-input-group nzSuffixIcon="lock">
<input type="text" nz-input formControlName="password" placeholder="输入任意解锁" />
<input type="text" nz-input formControlName="password" [placeholder]="'app.lock.placeholder' | i18n" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-row nzType="flex" nzAlign="middle">
<nz-row nzAlign="middle">
<nz-col [nzOffset]="12" [nzSpan]="12" style="text-align: right">
<button nz-button [disabled]="!f.valid" nzType="primary">{{ 'app.lock' | i18n }}</button>
</nz-col>

View File

@@ -3,16 +3,16 @@
<nz-tab [nzTitle]="'app.login.tab-login-credentials' | i18n">
<nz-alert *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert>
<nz-form-item>
<nz-form-control nzErrorTip="请输入用户名">
<nz-form-control [nzErrorTip]="'app.login.message-need-identifier' | i18n">
<nz-input-group nzSize="large" nzPrefixIcon="user">
<input nz-input formControlName="userName" placeholder="请输入用户名" />
<input nz-input formControlName="userName" [placeholder]="'app.login.message-need-identifier' | i18n" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzErrorTip="请输入密码">
<nz-form-control [nzErrorTip]="'app.login.message-need-credential' | i18n">
<nz-input-group nzSize="large" nzPrefixIcon="lock">
<input nz-input type="password" formControlName="password" placeholder="请输入密码" />
<input nz-input type="password" formControlName="password" [placeholder]="'app.login.message-need-credential' | i18n" />
</nz-input-group>
</nz-form-control>
</nz-form-item>

View File

@@ -1,10 +1,10 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, Optional } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { StartupService } from '@core';
import { I18NService, StartupService } from '@core';
import { ReuseTabService } from '@delon/abc/reuse-tab';
import { DA_SERVICE_TOKEN, ITokenService, SocialOpenType, SocialService } from '@delon/auth';
import { SettingsService, _HttpClient } from '@delon/theme';
import { DA_SERVICE_TOKEN, ITokenService, SocialService } from '@delon/auth';
import { SettingsService, _HttpClient, ALAIN_I18N_TOKEN } from '@delon/theme';
import { User } from '@delon/theme/src/services/settings/types';
import { NzTabChangeEvent } from 'ng-zorro-antd/tabs';
import { finalize } from 'rxjs/operators';
@@ -29,6 +29,7 @@ export class UserLoginComponent implements OnDestroy {
@Inject(ReuseTabService)
private reuseTabService: ReuseTabService,
@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
private startupSrv: StartupService,
private http: _HttpClient,
private cdr: ChangeDetectorRef,
@@ -125,7 +126,7 @@ export class UserLoginComponent implements OnDestroy {
let user: User = {
name: this.userName.value,
avatar: './assets/img/avatar.svg',
email: '管理员'
email: this.i18nSvc.fanyi('app.role.admin')
};
this.settingsService.setUser(user);
// 重新获取 StartupService 内容,我们始终认为应用信息一般都会受当前用户授权范围而影响

View File

@@ -1,138 +1,296 @@
{
"menu.search.placeholder": "Search for people, file, photos...",
"menu.fullscreen": "Fullscreen",
"menu.fullscreen.exit": "Exit Fullscreen",
"menu.clear.local.storage": "Clear Local Storage",
"menu.lang": "Language",
"menu.main": "Main Navigation",
"menu.dashboard": "Dashboard",
"menu.dashboard.v1": "Default",
"menu.dashboard.analysis": "Analysis",
"menu.dashboard.monitor": "Monitor",
"menu.dashboard.workplace": "Workplace",
"menu.shortcut": "Shortcut",
"menu.widgets": "Widgets",
"menu.alain": "Alain",
"menu.style": "Style",
"menu.style.typography": "Typography",
"menu.style.gridmasonry": "Grid Masonry",
"menu.style.colors": "Colors",
"menu.delon": "Delon Lib",
"menu.delon.form": "Dynamic Form",
"menu.delon.table": "Simple table",
"menu.delon.util": "Util",
"menu.delon.print": "Print",
"menu.delon.guard": "Route Guard",
"menu.delon.cache": "Cache",
"menu.delon.qr": "QR",
"menu.delon.acl": "ACL",
"menu.delon.downfile": "Download File",
"menu.delon.xlsx": "Excel",
"menu.delon.zip": "Zip",
"menu.pro": "Antd Pro",
"menu.form": "Form",
"menu.form.basicform": "Basic Form",
"menu.form.stepform": "Step Form",
"menu.form.stepform.info": "Step Form(write transfer information)",
"menu.form.stepform.confirm": "Step Form(confirm transfer information)",
"menu.form.stepform.result": "Step Form(finished)",
"menu.form.advancedform": "Advanced Form",
"menu.list": "List",
"menu.list.searchtable": "Search Table",
"menu.list.basiclist": "Basic List",
"menu.list.cardlist": "Card List",
"menu.list.searchlist": "Search List",
"menu.list.searchlist.articles": "Search List(articles)",
"menu.list.searchlist.projects": "Search List(projects)",
"menu.list.searchlist.applications": "Search List(applications)",
"menu.profile": "Profile",
"menu.profile.basic": "Basic Profile",
"menu.profile.advanced": "Advanced Profile",
"menu.result": "Result",
"menu.result.success": "Success",
"menu.result.fail": "Fail",
"menu.exception": "Exception",
"menu.exception.not-permission": "403",
"menu.exception.not-find": "404",
"menu.exception.server-error": "500",
"menu.account": "Account",
"menu.account.center": "Account Center",
"menu.account.settings": "Account Settings",
"menu.account.trigger": "Trigger Error",
"menu.account.logout": "Logout",
"menu.more": "More",
"menu.report": "Report",
"menu.report.relation": "Relation Map",
"menu.extras": "Extra",
"menu.extras.helpcenter": "Help Center",
"menu.extras.settings": "Settings",
"menu.extras.poi": "Poi",
"app.analysis.test": "Gongzhuan No.{{no}} shop",
"app.analysis.introduce": "Introduce",
"app.analysis.total-sales": "Total Sales",
"app.analysis.day-sales": "Day Sales",
"app.analysis.visits": "Visits",
"app.analysis.visits-trend": "Visits Trend",
"app.analysis.visits-ranking": "Visits Ranking",
"app.analysis.day-visits": "Day Visits",
"app.analysis.week": "Week Ratio",
"app.analysis.day": "Day Ratio",
"app.analysis.payments": "Payments",
"app.analysis.conversion-rate": "Conversion Rate",
"app.analysis.operational-effect": "Operational Effect",
"app.analysis.sales-trend": "Stores Sales Trend",
"app.analysis.sales-ranking": "Sales Ranking",
"app.analysis.all-year": "All Year",
"app.analysis.all-month": "All Month",
"app.analysis.all-week": "All Week",
"app.analysis.all-today": "All day",
"app.analysis.search-users": "Search Users",
"app.analysis.per-capita-search": "Per Capita Search",
"app.analysis.online-top-search": "Online Top Search",
"app.analysis.the-proportion-of-sales": "The Proportion Of Sales",
"app.analysis.channel.all": "ALL",
"app.analysis.channel.online": "Online",
"app.analysis.channel.stores": "Stores",
"app.analysis.sales": "Sales",
"app.analysis.traffic": "Traffic",
"app.analysis.table.rank": "Rank",
"app.analysis.table.search-keyword": "Keyword",
"app.analysis.table.users": "Users",
"app.analysis.table.weekly-range": "Weekly Range",
"app.monitor.trading-activity": "Real-Time Trading Activity",
"app.monitor.total-transactions": "Total transactions today",
"app.monitor.sales-target": "Sales target completion rate",
"app.monitor.remaining-time": "Remaining time of activity",
"app.monitor.total-transactions-per-second": "Total transactions per second",
"app.monitor.activity-forecast": "Activity forecast",
"app.monitor.efficiency": "Efficiency",
"app.monitor.ratio": "Ratio",
"app.monitor.proportion-per-category": "Proportion Per Category",
"app.monitor.fast-food": "Fast food",
"app.monitor.western-food": "Western food",
"app.monitor.hot-pot": "Hot pot",
"app.monitor.waiting-for-implementation": "Waiting for implementation",
"app.monitor.popular-searches": "Popular Searches",
"app.monitor.resource-surplus": "Resource Surplus",
"app.monitor.fund-surplus": "Fund Surplus",
"menu": {
"main": "Main",
"lang": "Language",
"dashboard": "DashBoard",
"search.placeholder": "SearchMonitor Name、IP",
"fullscreen": "Full Screen",
"fullscreen.exit": "Exit",
"clear.local.storage": "Clear Local Storage",
"monitor": {
"": "Monitor",
"service": "Service Monitor",
"db": "DB Monitor",
"os": "OS Monitor",
"mid": "Mid Monitor",
"custom": "Custom Monitor"
},
"account": {
"": "Personal",
"center": "Personal Center",
"settings": "Account Setting",
"security": "Security Setting",
"binding": "Account Binding",
"trigger": "Trigger Error",
"logout": "Logout"
},
"alert": {
"": "Alert",
"center": "Alert Center",
"setting": "Alert Setting",
"dispatch": "Alert Notify"
},
"extras": {
"": "More",
"help": "Help Center",
"setting": "Setting"
},
"more": "More"
},
"monitor": {
"": "Monitor",
"name": "Monitor Name",
"name.tip": "Monitor name, the name needs to be unique",
"host": "Monitor Host",
"host.tip": "The monitored peer IP or domain name",
"description": "Description",
"description.tip": "Description and remarks",
"intervals": "Intervals",
"intervals.tip": "Monitor the interval time of periodic collection of data, second",
"category": {
"": "Category",
"service": "Service",
"db": "Database",
"os": "OS",
"mid": "Middleware",
"custom": "Custom"
},
"app": {
"": "Monitor Type",
"website": "Website Monitor",
"api": "HTTP API",
"http": "HTTP API",
"ping": "PING Connect",
"port": "Port Available",
"mysql": "Mysql",
"oracle": "Oracle",
"redis": "Redis",
"fullsite": "SiteMap Monitor"
},
"status": {
"": "Monitor Status",
"all": "All Status",
"available": "Available",
"unavailable": "UnAvailable",
"unreachable": "UnReachable",
"un-manage": "UnManaged"
}
},
"alert": {
"": "Alert",
"status": {
"": "Alert Status",
"all": "All Status",
"0": "Pending",
"2": "Restored",
"3": "Processed"
},
"priority": {
"": "Alarm Priority",
"all": "All Priority",
"0": "Emergency",
"1": "Critical",
"2": "Warning"
}
},
"alert.setting.new": "New Threshold",
"alert.setting.edit": "Edit Threshold",
"alert.setting.delete": "Delete Threshold",
"alert.setting.target": "Metric Target",
"alert.setting.expr": "Threshold Trigger Expr",
"alert.setting.times": "Trigger Times",
"alert.setting.times.tip": "Set how many times the threshold is triggered before sending an alert",
"alert.setting.template": "Notice Template",
"alert.setting.template.tip": "Supported notification template environment variables",
"alert.setting.template.label": "The notification information template sent after the alarm is triggered, see the template environment variable above",
"alert.setting.template.example": "Please input notice template.Eg: ${app}.${metrics}.${metric}'s value is too high",
"alert.setting.template.monitor-type": "Monitor Type Name",
"alert.setting.template.metrics-name": "Metrics Name",
"alert.setting.template.metric-name": "Metric Name",
"alert.setting.template.metric-value": "Metric Target Value",
"alert.setting.template.other-value": "Other Metric Value",
"alert.setting.template.instance-value": "Instance Value",
"alert.setting.default": "Global Default",
"alert.setting.default.tip": "Whether this alarm threshold configuration applies to all this type of monitoring globally",
"alert.setting.enable": "Enable Alert",
"alert.setting.enable.tip": "This alarm threshold configuration is enabled or disabled",
"alert.setting.connect": "Alert Associate Monitors",
"alert.setting.connect.left": "No Associate",
"alert.setting.connect.right": "Associated",
"alert.setting.expr.tip": "Supported Threshold Trigger Expression Environment Variables and Operators",
"alert.setting.expr.label": "Calculate and judge whether the threshold is triggered according to this expression. The expression environment variables and operators are shown above.",
"alert.setting.expr.example": "Calculate whether to trigger the threshold according to this expression.Eg",
"alert.setting.priority.tip": "The alarm level that triggers the threshold, from low to high:WarningCriticalEmergency",
"alert.setting.target.tip": "The selected metric object",
"alert.setting.target.other": "Other metric objects of the row",
"alert.setting.target.instance": "Instance of the row",
"alert.setting.operator": "Supported operator functions",
"alert.center.delete": "Delete Alerts",
"alert.center.deal": "Mark Processed",
"alert.center.no-deal": "Mark Pending",
"alert.center.search": "Search Alert Content",
"alert.center.filter-status": "Filter Alert Status",
"alert.center.filter-priority": "Filter Alert Priority",
"alert.center.target": "Metric Target",
"alert.center.monitor": "Belong Monitor",
"alert.center.priority": "Priority",
"alert.center.content": "Alert Content",
"alert.center.status": "Status",
"alert.center.time": "Alert Time",
"alert.center.notify.no-delete": "No items selected for deletion!",
"alert.center.confirm.delete": "Please confirm whether to delete!",
"alert.center.confirm.delete-batch": "Please confirm whether to delete in batch!",
"alert.center.notify.no-mark": "No items selected for mark!",
"alert.center.confirm.mark-done-batch": "Please confirm whether to mark processed in batch!",
"alert.center.confirm.mark-done": "Please confirm whether to mark processed!",
"alert.center.confirm.mark-no-batch": "Please confirm whether to mark Pending in batch!",
"alert.center.confirm.mark-no": "Please confirm whether to mark Pending!",
"alert.notice.receiver": "Alert Receiver",
"alert.notice.receiver.new": "New Receiver",
"alert.notice.receiver.edit": "Edit Receiver",
"alert.notice.receiver.delete": "Delete Receiver",
"alert.notice.receiver.people": "Receiver",
"alert.notice.receiver.people.name": "Receiver Name",
"alert.notice.receiver.type": "Notice Type",
"alert.notice.receiver.setting": "Setting",
"alert.notice.type.sms": "SMS",
"alert.notice.type.phone": "Phone",
"alert.notice.type.email": "Email",
"alert.notice.type.url": "URL",
"alert.notice.type.wechat": "Open WeChat",
"alert.notice.type.wechat-id": "WeChat OPENID",
"alert.notice.type.wework": "WeWork Robot",
"alert.notice.type.wework-key": "WeWork Robot KEY",
"alert.notice.type.access-token": "Robot ACCESS_TOKEN",
"alert.notice.type.ding": "DingDing Robot",
"alert.notice.type.fei-shu": "FeiShu Robot",
"alert.notice.type.fei-shu-key": "FeiShu Robot KEY",
"alert.notice.rule": "Alert Notice Rule",
"alert.notice.rule.new": "New Notice Rule",
"alert.notice.rule.edit": "Edit Notice Rule",
"alert.notice.rule.delete": "Delete Notice Rule",
"alert.notice.rule.name": "Rule Name",
"alert.notice.rule.all": "Dispatch ALl",
"alert.notice.rule.enable": "Enable",
"dashboard.alerts.title": "Recently Alerts List",
"dashboard.alerts.title-no": "Recently Pending Alerts",
"dashboard.alerts.no": "No Pending Alerts",
"dashboard.alerts.enter": "Go Alert Center",
"dashboard.alerts.distribute": "The Distribution Of Alerts",
"dashboard.alerts.num": "Alerts Num",
"dashboard.alerts.deal": "Alerts Dealing",
"dashboard.alerts.deal-percent": "Dealing Rate",
"dashboard.monitors.total": "Monitor Total",
"dashboard.monitors.title": "Monitoring Overview",
"dashboard.monitors.sub-title": "The Distribution Of Monitors",
"dashboard.monitors.formatter": " Monitors ",
"dashboard.monitors.distribute": "Monitor Distribution",
"monitors.list": "Monitor List",
"monitors.new": "New",
"monitors.new.success": "New Monitor Success",
"monitors.new.failed": "New Monitor Failed",
"monitors.edit": "Edit",
"monitors.edit.success": "Update Monitor Success",
"monitors.edit.failed": "Update Monitor Failed",
"monitors.not-found": "This Monitor Not Found",
"monitors.delete": "Delete",
"monitors.edit-monitor": "Edit Monitor",
"monitors.delete-monitor": "Delete Monitor",
"monitors.enable": "Enable Monitor",
"monitors.cancel": "Cancel Monitor",
"monitors.search.placeholder": "Search Monitor",
"monitors.search.filter": "Filter Monitor Status",
"monitors.total": "Total",
"monitors.advanced": "Advanced",
"monitors.advanced.tip": "Setting Advanced Param",
"monitors.detect": "Detect",
"monitors.detect.success": "Detect Success",
"monitors.detect.failed": "Detect Failed",
"monitors.detect.tip": "Detect monitor available before apply",
"monitors.detail": "Monitor Detail",
"monitors.detail.name": "Name",
"monitors.detail.port": "Port",
"monitors.detail.description": "Desc",
"monitors.detail.status": "Status",
"monitors.detail.basic": "Monitor Basic",
"monitors.detail.realtime": "Monitor Real-Time Detail",
"monitors.detail.history": "Monitor Historical Chart Detail",
"monitors.collect.time": "Collect Time",
"monitors.collect.time.tip": "Last collect time",
"monitors.detail.chart.zoom": "Zoom In",
"monitors.detail.chart.back": "Zoom restore",
"monitors.detail.chart.save": "Save as Image",
"monitors.detail.chart.query-1h": "Query 1 Hour",
"monitors.detail.chart.query-6h": "Query 6 Hours",
"monitors.detail.chart.query-1d": "Query 1 Day",
"monitors.detail.chart.query-1w": "Query 1 Week",
"monitors.detail.chart.query-1m": "Query 1 Month",
"monitors.detail.chart.no-data": "No Metrics Data",
"monitors.detail.chart.unit": "Unit",
"common.name": "Name",
"common.value": "Value",
"common.search": "Search",
"common.refresh": "Refresh",
"common.edit-time": "Last Update Time",
"common.new-time": "Create Time",
"common.edit": "Operate",
"common.total": "Total",
"common.yes": "Yes",
"common.no": "No",
"common.enable": "Enable",
"common.disable": "Disable",
"common.notify.no-select-edit": "No items selected for editing!",
"common.notify.one-select-edit": "Only one selection can be edited!",
"common.confirm.delete": "Please confirm whether to delete!",
"common.notify.no-select-delete": "No items selected for deletion!",
"common.confirm.delete-batch": "Please confirm whether to delete in batches!",
"common.notify.delete-success": "Delete Success!",
"common.notify.delete-fail": "Delete Failed!",
"common.notify.new-success": "Add Success!",
"common.notify.new-fail": "Add Failed!",
"common.notify.apply-success": "Apply Success!",
"common.notify.apply-fail": "Apply Failed!",
"common.notify.monitor-fail": "Query Monitor Failed!",
"common.notify.edit-success": "Edit Success!",
"common.notify.edit-fail": "Edit Failed!",
"common.notify.no-select-cancel": "No items selected for cancel!",
"common.confirm.cancel-batch": "Please confirm whether to cancel monitor in batches!",
"common.confirm.cancel": "Please confirm whether to cancel monitor!",
"common.notify.cancel-success": "Cancel Success!",
"common.notify.cancel-fail": "Cancel Failed!",
"common.notify.mark-success": "Mark Success!",
"common.notify.mark-fail": "Mark Failed!",
"common.notify.no-select-enable": "No items selected for enable!",
"common.confirm.enable-batch": "Please confirm whether to enable monitor in batches!",
"common.confirm.enable": "Please confirm whether to enable monitor!",
"common.notify.enable-success": "Enable Success!",
"common.notify.enable-fail": "Enable Failed!",
"common.confirm.clear-cache": "Please confirm whether to clear cache!",
"common.notify.clear-success": "Clear Success!",
"common.button.ok": "OK",
"common.button.cancel": "Cancel",
"common.button.help": "Help",
"common.button.edit": "Edit",
"common.button.delete": "Delete",
"common.button.detect": "Detect",
"validation.email.invalid": "Invalid email",
"validation.phone.invalid": "Invalid phone number",
"validation.verification-code.invalid": "Invalid verification code, should be 6 digits",
"validation.required": "Please fill in the required fields! ",
"app.theme.default": "Light Theme",
"app.theme.dark": "Dark Theme",
"app.theme.compact": "Compact Theme",
"app.role.admin": "Administrator",
"app.lock": "Lock",
"app.login.message-invalid-credentials": "Invalid username or passwordadmin/ant.design",
"app.login.message-invalid-verification-code": "Invalid verification code",
"app.lock.placeholder": "Enter Any To Unlock",
"app.passport.desc": "TanCloud-Friendly High Performance Monitoring Cloud Service",
"app.passport.welcome": "Welcome To Use TanCloud-Monitoring Cloud Service-tancloud.cn",
"app.login.message-need-identifier": "Please enter your username",
"app.login.message-need-credential": "Please enter password",
"app.login.message-invalid-credentials": "Invalid username or password",
"app.login.tab-login-credentials": "Credentials",
"app.login.tab-login-mobile": "Mobile number",
"app.login.remember-me": "Remember me",
"app.login.forgot-password": "Forgot your password?",
"app.login.sign-in-with": "Sign in with",
"app.login.signup": "Sign up",
"app.login.login": "Login",
"app.register.register": "Register",
"app.register.get-verification-code": "Get code",
"app.register.sign-in": "Already have an account?",
"app.register-result.msg": "Accountregistered at {{email}}",
"app.register-result.activation-email":
"The activation email has been sent to your email address and is valid for 24 hours. Please log in to the email in time and click on the link in the email to activate the account.",
"app.register-result.back-home": "Back to home",
"app.register-result.view-mailbox": "View mailbox",
"validation.email.required": "Please enter your email!",
"validation.email.wrong-format": "The email address is in the wrong format!",
"validation.password.required": "Please enter your password!",

View File

@@ -27,7 +27,7 @@
"alert": {
"": "告警",
"center": "告警中心",
"setting": "告警配置",
"setting": "告警阈值",
"dispatch": "告警通知"
},
"extras": {
@@ -39,6 +39,14 @@
},
"monitor": {
"": "监控",
"name": "监控名称",
"name.tip": "标识监控的名称,名称需要保证唯一性",
"host": "监控Host",
"host.tip": "被监控的对端IP或域名",
"description": "描述备注",
"description.tip": "更多标识和描述此监控的备注信息",
"intervals": "采集间隔",
"intervals.tip": "监控周期性采集数据间隔时间,单位秒",
"category": {
"": "监控类别",
"service": "应用服务",
@@ -58,46 +66,227 @@
"oracle": "Oracle",
"redis": "Redis",
"fullsite": "全站监控"
},
"status": {
"": "监控状态",
"all": "全部状态",
"available": "正常监控",
"unavailable": "不可用",
"unreachable": "不可达",
"un-manage": "未管理"
}
},
"alert": {
"": "告警",
"status": {
"": "告警状态",
"0": "待处理",
"all": "全部状态",
"0": "未处理",
"2": "已恢复",
"3": "已处理"
},
"priority": {
"": "告警级别",
"all": "全部级别",
"0": "紧急告警",
"1": "严重告警",
"2": "警告告警"
}
},
"alert.setting.new": "新增阈值",
"alert.setting.edit": "编辑阈值",
"alert.setting.delete": "删除阈值",
"alert.setting.target": "指标对象",
"alert.setting.expr": "阈值触发表达式",
"alert.setting.times": "触发次数",
"alert.setting.times.tip": "设置触发阈值多少次之后才会发送告警",
"alert.setting.template": "通知模版",
"alert.setting.template.tip": "支持的通知模版环境变量",
"alert.setting.template.label": "告警触发后发送的通知信息模版,模版环境变量见上方",
"alert.setting.template.example": "请输入告警的通知模版.示例: ${app}.${metrics}.${metric}'s value is too high",
"alert.setting.template.monitor-type": "监控类型名称",
"alert.setting.template.metrics-name": "监控指标集合名称",
"alert.setting.template.metric-name": "监控指标名称",
"alert.setting.template.metric-value": "监控指标对象值",
"alert.setting.template.other-value": "所属行其它指标值",
"alert.setting.template.instance-value": "所属行实例值",
"alert.setting.default": "全局默认",
"alert.setting.default.tip": "此告警阈值配置是否应用于全局所有此类型监控",
"alert.setting.enable": "启用告警",
"alert.setting.enable.tip": "此告警阈值配置开启生效或关闭",
"alert.setting.connect": "告警定义关联监控",
"alert.setting.connect.left": "未关联监控",
"alert.setting.connect.right": "已关联监控",
"alert.setting.expr.tip": "支持的阈值触发表达式环境变量与操作符",
"alert.setting.expr.label": "根据此表达式来计算判断是否触发阈值,表达式环境变量和操作符见上方",
"alert.setting.expr.example": "根据此表达式计算判断是否触发阈值.示例",
"alert.setting.priority.tip": "触发阈值的告警级别,从低到高依次为:警告-warning严重-critical紧急-emergency",
"alert.setting.target.tip": "选中的指标对象",
"alert.setting.target.other": "所属行其它指标对象",
"alert.setting.target.instance": "所属行实例",
"alert.setting.operator": "支持操作符函数",
"alert.center.delete": "删除告警",
"alert.center.deal": "标记已处理",
"alert.center.no-deal": "标记未处理",
"alert.center.search": "搜索告警内容",
"alert.center.filter-status": "告警状态过滤",
"alert.center.filter-priority": "告警级别过滤",
"alert.center.target": "告警指标",
"alert.center.monitor": "所属监控",
"alert.center.priority": "级别",
"alert.center.content": "告警内容",
"alert.center.status": "状态",
"alert.center.time": "告警时间",
"alert.center.notify.no-delete": "未选中任何待删除项!",
"alert.center.confirm.delete": "请确认是否删除!",
"alert.center.confirm.delete-batch": "请确认是否批量删除!",
"alert.center.notify.no-mark": "未选中任何待标记项!",
"alert.center.confirm.mark-done-batch": "请确认是否批量标记已处理!",
"alert.center.confirm.mark-done": "请确认是否标记已处理!",
"alert.center.confirm.mark-no-batch": "请确认是否批量标记未处理!",
"alert.center.confirm.mark-no": "请确认是否标记未处理!",
"alert.notice.receiver": "告警接收人",
"alert.notice.receiver.new": "新增接收人",
"alert.notice.receiver.edit": "编辑接收人",
"alert.notice.receiver.delete": "删除接收人",
"alert.notice.receiver.people": "接收人",
"alert.notice.receiver.people.name": "接收人名称",
"alert.notice.receiver.type": "通知方式",
"alert.notice.receiver.setting": "配置",
"alert.notice.type.sms": "短信",
"alert.notice.type.phone": "手机号",
"alert.notice.type.email": "邮箱",
"alert.notice.type.url": "URL地址",
"alert.notice.type.wechat": "微信公众号",
"alert.notice.type.wechat-id": "微信OPENID",
"alert.notice.type.wework": "企业微信机器人",
"alert.notice.type.wework-key": "企业微信机器人KEY",
"alert.notice.type.access-token": "机器人ACCESS_TOKEN",
"alert.notice.type.ding": "钉钉机器人",
"alert.notice.type.fei-shu": "飞书机器人",
"alert.notice.type.fei-shu-key": "飞书机器人KEY",
"alert.notice.rule": "告警通知策略",
"alert.notice.rule.new": "新增通知策略",
"alert.notice.rule.edit": "编辑通知策略",
"alert.notice.rule.delete": "删除通知策略",
"alert.notice.rule.name": "策略名称",
"alert.notice.rule.all": "转发所有",
"alert.notice.rule.enable": "是否启用",
"dashboard.alerts.title": "最近告警列表",
"dashboard.alerts.title-no": "最近未处理告警",
"dashboard.alerts.no": "暂无未处理告警",
"dashboard.alerts.enter": "进入告警中心",
"dashboard.alerts.distribute": "告警分布",
"dashboard.alerts.num": "告警数量",
"dashboard.alerts.deal": "告警处理",
"dashboard.alerts.deal-percent": "告警处理率",
"dashboard.monitors.total": "监控总量",
"dashboard.monitors.title": "监控总览",
"dashboard.monitors.sub-title": "监控类型纳管数量分布",
"dashboard.monitors.formatter": "个监控 占比",
"dashboard.monitors.distribute": "纳管数量分布",
"monitors.list": "监控列表",
"monitors.new": "新增",
"monitors.new.success": "新增监控成功",
"monitors.new.failed": "新增监控失败",
"monitors.edit": "编辑",
"monitors.edit.success": "修改监控成功",
"monitors.edit.failed": "修改监控失败",
"monitors.not-found": "查询异常,此监控不存在",
"monitors.delete": "删除",
"monitors.edit-monitor": "编辑监控",
"monitors.delete-monitor": "删除监控",
"monitors.enable": "启用监控",
"monitors.cancel": "取消监控",
"monitors.search.placeholder": "搜索监控",
"monitors.search.filter": "监控状态过滤",
"monitors.total": "总量",
"monitors.advanced": "高级设置",
"monitors.advanced.tip": "设置高级可选参数",
"monitors.detect": "测试连接",
"monitors.detect.success": "测试连接成功",
"monitors.detect.failed": "测试连接失败",
"monitors.detect.tip": "新增监控前是否先探测检查监控可用性",
"monitors.detail": "监控详情",
"monitors.detail.name": "名称",
"monitors.detail.port": "端口",
"monitors.detail.description": "描述",
"monitors.detail.status": "状态",
"monitors.detail.basic": "监控基本属性",
"monitors.detail.realtime": "监控实时数据详情",
"monitors.detail.history": "监控历史图表详情",
"monitors.collect.time": "采集时间",
"monitors.collect.time.tip": "最近采集时间",
"monitors.detail.chart.zoom": "区域缩放",
"monitors.detail.chart.back": "缩放还原",
"monitors.detail.chart.save": "保存图片",
"monitors.detail.chart.query-1h": "查询近1小时",
"monitors.detail.chart.query-6h": "查询近6小时",
"monitors.detail.chart.query-1d": "查询近1天",
"monitors.detail.chart.query-1w": "查询近1周",
"monitors.detail.chart.query-1m": "查询近1月",
"monitors.detail.chart.no-data": "暂无数据",
"monitors.detail.chart.unit": "单位",
"common.name": "名称",
"common.value": "值",
"common.search": "搜索",
"common.refresh": "刷新",
"common.edit-time": "更新时间",
"common.new-time": "创建时间",
"common.edit": "操作",
"common.total": "总量",
"common.yes": "是",
"common.no": "否",
"common.enable": "开启",
"common.disable": "关闭",
"common.notify.no-select-edit": "未选中任何待编辑项!",
"common.notify.one-select-edit": "只能对一个选中项进行编辑!",
"common.confirm.delete": "请确认是否删除!",
"common.notify.no-select-delete": "未选中任何待删除项!",
"common.confirm.delete-batch": "请确认是否批量删除!",
"common.notify.delete-success": "删除成功!",
"common.notify.delete-fail": "删除失败!",
"common.notify.new-success": "新增成功!",
"common.notify.new-fail": "新增失败!",
"common.notify.apply-success": "应用成功!",
"common.notify.apply-fail": "应用失败!",
"common.notify.monitor-fail": "查询此监控定义详情失败!",
"common.notify.edit-success": "修改成功!",
"common.notify.edit-fail": "修改失败!",
"common.notify.mark-success": "标记成功!",
"common.notify.mark-fail": "标记失败!",
"common.notify.no-select-cancel": "未选中任何待取消项!",
"common.confirm.cancel-batch": "请确认是否批量取消监控!",
"common.confirm.cancel": "请确认是否取消监控!",
"common.notify.cancel-success": "取消监控成功!",
"common.notify.cancel-fail": "取消监控失败!",
"common.notify.no-select-enable": "未选中任何待启用监控项!",
"common.confirm.enable-batch": "请确认是否批量启用监控!",
"common.confirm.enable": "请确认是否启用监控!",
"common.notify.enable-success": "启用监控成功!",
"common.notify.enable-fail": "启用监控失败!",
"common.confirm.clear-cache": "请确认是否清理缓存!",
"common.notify.clear-success": "清理成功!",
"common.button.ok": "确定",
"common.button.detect": "测试",
"common.button.cancel": "取消",
"common.button.help": "帮助",
"common.button.edit": "编辑",
"common.button.delete": "删除",
"app.theme.default": "浅色主题",
"app.theme.dark": "深色主题",
"app.theme.compact": "紧凑主题",
"app.role.admin": "管理员",
"app.lock": "锁屏",
"app.login.message-need-identifier": "输入邮箱或手机号",
"app.lock.placeholder": "输入任意解锁",
"app.passport.desc": "TanCloud-易用友好的高性能监控云服务",
"app.passport.welcome": "欢迎使用TanCloud探云-监控云服务-tancloud.cn",
"app.login.message-need-identifier": "请输入用户名",
"app.login.message-need-credential": "请输入密码",
"app.login.message-invalid-credentials": "账户或密码错误",
"app.login.message-invalid-verification-code": "验证码错误",
"app.login.tab-login-credentials": "账户密码登录",
"app.login.tab-login-mobile": "手机号登录",
"app.login.remember-me": "自动登录",
"app.login.forgot-password": "忘记密码",
"app.login.sign-in-with": "其他登录方式",
"app.login.signup": "注册账户",
"app.login.login": "登录",
"app.password.forgot": "忘记密码",
"app.password.reset": "重置密码",
"app.register.register": "注册",
"app.register.get-verification-code": "获取验证码",
"app.register.sign-in": "使用已有账户登录",
"app.register-result.msg": "你的账户:{{email}} 注册成功",
"app.register-result.activation-email":
"额外赠送监控额度邮件已发送到你的邮箱中。请及时登录邮箱,点击邮件中的链接领取。",
"app.register-result.login": "开始登录",
"app.register-result.back-home": "返回首页",
"app.register-result.view-mailbox": "查看邮箱",
"validation.email.required": "请输入邮箱地址!",
"validation.email.wrong-format": "邮箱地址格式错误!",
"validation.email.invalid": "无效的邮箱地址!",