Compare commits

...

5 Commits
osrc ... master

Author SHA1 Message Date
tomsun28
15aae19140 [web-app]bugfix: recently alerts in dashboard load error when go back (#105) 2022-04-24 22:39:59 +08:00
MaxKey
bcce79f9cc change theme 2022-04-24 19:10:53 +08:00
tomsun28
02ebca02cc [docs]api tags i18n, update readme (#103) 2022-04-21 22:04:15 +08:00
会编程的王学长
1c31b3ff0c feat: [manager]feature:App/Account Controller compatible with Chinese and English #wqh (#90) 2022-04-21 21:44:54 +08:00
tomsun28
0b82096ff7 [doc,manager,webapp]support deploy with osrc.com 2022-04-19 20:18:01 +08:00
38 changed files with 321 additions and 143 deletions

View File

@@ -8,7 +8,7 @@
## HertzBeat 赫兹跳动 | [English Documentation](README_EN.md)
> 易用友好的监控告警系统。
> 易用友好的监控系统无需Agent强大自定义监控能力
![tan-cloud](https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/badge/web-monitor.svg)
![tan-cloud](https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/badge/ping-connect.svg)
@@ -21,12 +21,14 @@
**官网: [hertzbeat.com](https://hertzbeat.com) | [tancloud.cn](https://tancloud.cn)**
在开源运行时社区[OSCR.COM](https://osrc.com)快速运行HertzBeat - [部署流程](https://osrc.com/user/articles/wiki_776513931985080320)
## 🎡 <font color="green">介绍</font>
> [HertzBeat赫兹跳动](https://github.com/dromara/hertzbeat) 是由[Dromara](https://dromara.org)孵化,[TanCloud](https://tancloud.cn)开源的一个支持网站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 模块化,`manager, collector, warehouse, alerter` 各个模块解耦合,方便理解与定制开发。
> HertzBeat 支持更自由化的告警配置(计算表达式),支持告警通知,告警模版,邮件钉钉微信飞书等及时通知送达
> 欢迎登录 HertzBeat 的 [云环境TanCloud](https://console.tancloud.cn) 试用发现更多。
> 我们正在快速迭代中,欢迎参与加入一起共建项目开源生态。
@@ -45,8 +47,6 @@
> 提供对监控的管理,监控应用配置的管理,系统用户租户后台管理等。
- **[collector](https://github.com/dromara/hertzbeat/tree/master/collector)** 提供监控数据采集服务
> 使用通用协议远程采集获取对端指标数据。
- **[scheduler](https://github.com/dromara/hertzbeat/tree/master/scheduler)** 提供监控任务调度服务
> 采集任务管理,一次性任务和周期性任务的调度分发。
- **[warehouse](https://github.com/dromara/hertzbeat/tree/master/warehouse)** 提供监控数据仓储服务
> 采集指标结果数据管理,数据落盘,查询,计算统计。
- **[alerter](https://github.com/dromara/hertzbeat/tree/master/alerter)** 提供告警服务

View File

@@ -22,6 +22,8 @@
**Home: [hertzbeat.com](https://hertzbeat.com) | [tancloud.cn](https://tancloud.cn)**
Running HertzBeat in [OSCR.COM](https://osrc.com) Open Source Runtime Community - [Doc](https://osrc.com/user/articles/wiki_776513931985080320)
## 🎡 <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.
@@ -45,9 +47,7 @@
- **[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.
> Use common protocols to remotely collect and obtain peer-to-peer metrics data.
- **[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.

View File

@@ -31,7 +31,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/9 10:32
*/
@Api(tags = "告警定义管理API")
@Api(tags = "Alert Define API | 告警定义管理API")
@RestController
@RequestMapping(path = "/alert/define", produces = {APPLICATION_JSON_VALUE})
public class AlertDefineController {

View File

@@ -31,7 +31,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/9 10:32
*/
@Api(tags = "告警定义管理API")
@Api(tags = "Alert Define Batch API | 告警定义管理API")
@RestController
@RequestMapping(path = "/alert/defines", produces = {APPLICATION_JSON_VALUE})
public class AlertDefinesController {

View File

@@ -35,7 +35,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/9 10:32
*/
@Api(tags = "en: Alarm batch management API, zh:告警批量管理API")
@Api(tags = "Alarm Manage Batch API | 告警批量管理API")
@RestController
@RequestMapping(path = "/alerts", produces = {APPLICATION_JSON_VALUE})
public class AlertsController {

View File

@@ -22,7 +22,9 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
/**
* todo 字段默认值
* Monitoring parameter definitions
* 监控参数定义
*
* @author tomsun28
* @date 2021/11/13 21:49
*/
@@ -32,57 +34,68 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "参数结构定义实体")
@ApiModel(description = "en: Parameter structure definition entity,zh: 参数结构定义实体")
public class ParamDefine {
/**
* Parameter Structure ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty(value = "参数结构ID", example = "87584674384", accessMode = READ_ONLY, position = 0)
private Long id;
/**
* Monitoring application type name
* 监控应用类型名称
*/
@ApiModelProperty(value = "监控类型", example = "TanCloud", accessMode = READ_WRITE, position = 1)
private String app;
/**
* Parameter field external display name
* 参数字段对外显示名称
*/
@ApiModelProperty(value = "参数字段显示名称", example = "端口", accessMode = READ_WRITE, position = 2)
private String name;
/**
* Parameter Field Identifier
* 参数字段标识符
*/
@ApiModelProperty(value = "参数字段标识符", example = "port", accessMode = READ_WRITE, position = 3)
private String field;
/**
* Field type, style (mostly map the input tag type attribute)
* 字段类型,样式(大部分映射input标签type属性)
*/
@ApiModelProperty(value = "字段类型,样式(大部分映射input标签type属性)", example = "number", accessMode = READ_WRITE, position = 4)
private String type;
/**
* Is it mandatory true-required false-optional
* 是否是必输项 true-必填 false-可选
*/
@ApiModelProperty(value = "是否是必输项 true-必填 false-可选", example = "true", accessMode = READ_WRITE, position = 5)
private boolean required = false;
/**
* Parameter Default Value
* 参数默认值
*/
@ApiModelProperty(value = "参数默认值", example = "12", accessMode = READ_WRITE, position = 6)
private String defaultValue;
/**
* Parameter input box prompt information
* 参数输入框提示信息
*/
@ApiModelProperty(value = "参数输入框提示信息", example = "请输入密码", accessMode = READ_WRITE, position = 7)
private String placeholder;
/**
* When type is number, use range to represent the range eg: 0-233
* 当type为number时,用range表示范围 eg: 0-233
*/
@ApiModelProperty(value = "当type为number时,用range区间表示范围", example = "[0,233]", accessMode = READ_WRITE, position = 6)
@@ -90,6 +103,7 @@ public class ParamDefine {
private String range;
/**
* When type is text, use limit to indicate the limit size of the string. The maximum is 255
* 当type为text时,用limit表示字符串限制大小.最大255
*/
@ApiModelProperty(value = "当type为text时,用limit表示字符串限制大小.最大255", example = "30", accessMode = READ_WRITE, position = 7)
@@ -97,10 +111,11 @@ public class ParamDefine {
private Short limit;
/**
* When the type is radio radio box, checkbox checkbox, options represents a list of optional values
* 当type为radio单选框,checkbox复选框时,options表示可选项值列表
* eg: {
* "key1":"value1",
* "key2":"value2"
* "key1":"value1",
* "key2":"value2"
* }
* key-值显示标签
* value-真正值
@@ -111,36 +126,42 @@ public class ParamDefine {
private List<Option> options;
/**
* Valid when type is key-value, indicating the alias description of the key
* 当type为key-value时有效,表示key的别名描述
*/
@ApiModelProperty(value = "当type为key-value时有效,表示key的别名描述", example = "Name", accessMode = READ_WRITE, position = 9)
private String keyAlias;
/**
* Valid when type is key-value, indicating the alias description of value type
* 当type为key-value时有效,表示value的别名描述
*/
@ApiModelProperty(value = "当type为key-value时有效,表示value的别名描述", example = "Value", accessMode = READ_WRITE, position = 10)
private String valueAlias;
/**
* Is it an advanced hidden parameter true-yes false-no
* 是否是高级隐藏参数 true-是 false-否
*/
@ApiModelProperty(value = "是否是高级隐藏参数 true-是 false-否", example = "true", accessMode = READ_WRITE, position = 11)
private boolean hide = false;
/**
* The creator of this record
* 此条记录创建者
*/
@ApiModelProperty(value = "此条记录创建者", example = "tom", accessMode = READ_ONLY, position = 11)
private String creator;
/**
* This record was last modified by
* 此条记录最新修改者
*/
@ApiModelProperty(value = "此条记录最新修改者", example = "tom", accessMode = READ_ONLY, position = 12)
private String modifier;
/**
* record creation time
* 记录创建时间
*/
@ApiModelProperty(value = "记录创建时间(毫秒时间戳)", example = "1612198922000", accessMode = READ_ONLY, position = 13)
@@ -148,6 +169,7 @@ public class ParamDefine {
private LocalDateTime gmtCreate;
/**
* Record the latest modification time
* 记录最新修改时间
*/
@ApiModelProperty(value = "记录最新修改时间(毫秒时间戳)", example = "1612198444000", accessMode = READ_ONLY, position = 14)
@@ -159,10 +181,12 @@ public class ParamDefine {
@NoArgsConstructor
public static final class Option {
/**
* value display label
* 值显示标签
*/
private String label;
/**
* optional value
* 可选值
*/
private String value;

View File

@@ -47,7 +47,7 @@ sidebar_label: Docker方式部署
在主机目录下创建sureness.ymleg:/opt/sureness.yml
配置文件内容参考 项目仓库[/script/sureness.yml](https://gitee.com/dromara/hertzbeat/blob/master/script/sureness.yml)
```yaml
```yaml
resourceRole:
- /account/auth/refresh===post===[admin,user,guest]
@@ -115,11 +115,11 @@ account:
salt: 123
role: [guest]
```
```
修改sureness.yml的如下**部分参数****[注意⚠sureness配置的其它默认参数需保留]**
```yaml
```yaml
# 用户账户信息
# 下面有 admin tom lili 三个账户
@@ -144,7 +144,7 @@ account:
salt: 123
role: [guest]
```
```
6. 启动HertzBeat Docker容器
```

View File

@@ -50,7 +50,7 @@ sidebar_label: 安装包方式部署
若需要新增删除修改账户或密码,可以通过修改位于 `hertzbeat/config/sureness.yml` 的配置文件实现,若无此需求可忽略此步骤
修改sureness.yml的如下**部分参数****[注意⚠sureness配置的其它默认参数需保留]**
```yaml
```yaml
# 用户账户信息
# 下面有 admin tom lili 三个账户
@@ -75,7 +75,7 @@ account:
salt: 123
role: [guest]
```
```
5. 部署启动
执行位于安装目录hertzbeat/bin/下的启动脚本 startup.sh

View File

@@ -52,12 +52,12 @@ Detailed steps refer to [Install HertzBeat via package](https://hertzbeat.com/do
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)
Detailed steps refer to [CONTRIBUTING](../others/contributing)
##### 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).
Install and deploy the mysql database, tdengine database and hertzbeat at one time through [docker-compose deployment script](https://github.com/dromara/hertzbeat/tree/master/script/docker-compose).
Detailed steps refer to [docker-compose install](script/docker-compose/README.md)
Detailed steps refer to [docker-compose install](https://github.com/dromara/hertzbeat/tree/master/script/docker-compose)
**HAVE FUN**

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -26,7 +26,7 @@ public class SwaggerConfig {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.enable(true)
.groupName("TanCloud")
.groupName("HertzBeat")
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.regex("(?!/error.*).*"))
@@ -35,7 +35,7 @@ public class SwaggerConfig {
private ApiInfo apiInfo(){
return new ApiInfo(
"TanCloud",
"HertzBeat",
null,
"v1.0",
null,

View File

@@ -29,17 +29,20 @@ import static com.usthe.common.util.CommonConstants.MONITOR_LOGIN_FAILED_CODE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* Authentication registration TOKEN management API
* 认证注册TOKEN管理API
*
* @author tomsun28
* @date 13:11 2019-05-26
*/
@Api(tags = "认证注册TOKEN管理API")
@Api(tags = "Auth Manage API | 认证注册TOKEN管理API")
@RestController()
@RequestMapping(value = "/account/auth", produces = {APPLICATION_JSON_VALUE})
@Slf4j
public class AccountController {
/**
* Token validity time in seconds
* TOKEN有效期时间 单位秒
*/
private static final long PERIOD_TIME = 3600L;
@@ -50,7 +53,7 @@ public class AccountController {
private SurenessAccountProvider accountProvider = new DocumentAccountProvider();
@PostMapping("/form")
@ApiOperation(value = "账户登录", notes = "账户密码登录获取关联用户信息")
@ApiOperation(value = "Account password login to obtain associated user information", notes = "账户密码登录获取关联用户信息")
public ResponseEntity<Message<Map<String, String>>> authGetToken(@RequestBody LoginDto loginDto) {
SurenessAccount account = accountProvider.loadAccount(loginDto.getIdentifier());
@@ -76,7 +79,7 @@ public class AccountController {
}
// Get the roles the user has - rbac
List<String> roles = account.getOwnRoles();
// 签发TOKEN
// Issue TOKEN 签发TOKEN
String issueToken = JsonWebTokenUtil.issueJwt(loginDto.getIdentifier(), PERIOD_TIME, roles);
Map<String, Object> customClaimMap = new HashMap<>(1);
customClaimMap.put("refresh", true);
@@ -88,9 +91,9 @@ public class AccountController {
}
@GetMapping("/refresh/{refreshToken}")
@ApiOperation(value = "TOKEN刷新", notes = "使用刷新TOKEN重新获取TOKEN")
@ApiOperation(value = "Use refresh TOKEN to re-acquire TOKEN", notes = "使用刷新TOKEN重新获取TOKEN")
public ResponseEntity<Message<Map<String, String>>> refreshToken(
@ApiParam(value = "刷新TOKEN", example = "xxx")
@ApiParam(value = "en: Refresh TOKEN,zh: 刷新TOKEN", example = "xxx")
@PathVariable("refreshToken") @NotNull final String refreshToken) {
String userId;
boolean isRefresh;
@@ -116,7 +119,7 @@ public class AccountController {
return ResponseEntity.ok(message);
}
List<String> roles = account.getOwnRoles();
// 签发TOKEN
// Issue TOKEN 签发TOKEN
String issueToken = JsonWebTokenUtil.issueJwt(userId, PERIOD_TIME, roles);
Map<String, Object> customClaimMap = new HashMap<>(1);
customClaimMap.put("refresh", true);

View File

@@ -21,11 +21,13 @@ import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* Monitoring Type Management API
* 监控类型管理API
*
* @author tomsun28
* @date 2021/11/14 16:47
*/
@Api(tags = "监控类型管理API")
@Api(tags = "Monitor Type Manage API | 监控类型管理API")
@RestController
@RequestMapping(path = "/apps", produces = {APPLICATION_JSON_VALUE})
public class AppController {
@@ -34,31 +36,32 @@ public class AppController {
private AppService appService;
@GetMapping(path = "/{app}/params")
@ApiOperation(value = "查询监控类型的参数结构", notes = "根据app查询指定监控类型的需要输入参数的结构")
@ApiOperation(value = "The structure of the input parameters required to specify the monitoring type according to the app query", notes = "根据app查询指定监控类型的需要输入参数的结构")
public ResponseEntity<Message<List<ParamDefine>>> queryAppParamDefines(
@ApiParam(value = "监控类型名称", example = "api") @PathVariable("app") final String app) {
@ApiParam(value = "en: Monitoring type name,zh: 监控类型名称", example = "api") @PathVariable("app") final String app) {
List<ParamDefine> paramDefines = appService.getAppParamDefines(app.toLowerCase());
return ResponseEntity.ok(new Message<>(paramDefines));
}
@GetMapping(path = "/{app}/define")
@ApiOperation(value = "查询监控类型的结构定义", notes = "根据app查询指定监控类型的定义结构")
@ApiOperation(value = "The definition structure of the specified monitoring type according to the app query", notes = "根据app查询指定监控类型的定义结构")
public ResponseEntity<Message<Job>> queryAppDefine(
@ApiParam(value = "监控类型名称", example = "api") @PathVariable("app") final String app) {
@ApiParam(value = "en: Monitoring type name,zh: 监控类型名称", example = "api") @PathVariable("app") final String app) {
Job define = appService.getAppDefine(app.toLowerCase());
return ResponseEntity.ok(new Message<>(define));
}
@GetMapping(path = "/hierarchy")
@ApiOperation(value = "查询全部监控指标层级", notes = "查询所有监控的类型-指标组-指标层级,以层级结构输出")
@ApiOperation(value = "Query all monitored types-indicator group-indicator level, output in a hierarchical structure", notes = "查询所有监控的类型-指标组-指标层级,以层级结构输出")
public ResponseEntity<Message<List<Hierarchy>>> queryAppsHierarchy(
@ApiParam(value = "语言类型", example = "zh-CN", defaultValue = "zh-CN")
@ApiParam(value = "en: language type,zh: 语言类型",
example = "zh-CN", defaultValue = "zh-CN")
@RequestParam(name = "lang", required = false) String lang) {
if (lang == null || "".equals(lang)) {
lang = "zh-CN";
}
lang = "zh-cn".equalsIgnoreCase(lang)? "zh-CN" : lang;
lang = "en-us".equalsIgnoreCase(lang)? "en-US" : lang;
lang = "zh-cn".equalsIgnoreCase(lang) ? "zh-CN" : lang;
lang = "en-us".equalsIgnoreCase(lang) ? "en-US" : lang;
List<Hierarchy> appHierarchies = appService.getAllAppHierarchy(lang);
return ResponseEntity.ok(new Message<>(appHierarchies));
}

View File

@@ -21,7 +21,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/4 21:40
*/
@Api(tags = "I18N国际化资源API")
@Api(tags = "I18N API | I18N国际化资源API")
@RestController
@RequestMapping(path = "/i18n", produces = {APPLICATION_JSON_VALUE})
public class I18nController {

View File

@@ -30,7 +30,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tomsun28
* @date 2021/11/14 10:57
*/
@Api(tags = "en: Monitoring management API,zh: 监控管理API")
@Api(tags = "Monitor Manage API | 监控管理API")
@RestController
@RequestMapping(path = "/monitor", produces = {APPLICATION_JSON_VALUE})
public class MonitorController {

View File

@@ -35,7 +35,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/1 20:43
*/
@Api(tags = "en: Monitor and manage batch API,zh: 监控列表API")
@Api(tags = "Monitor Manage Batch API | 监控列表API")
@RestController
@RequestMapping(path = "/monitors", produces = {APPLICATION_JSON_VALUE})
public class MonitorsController {

View File

@@ -34,7 +34,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/16 16:18
*/
@Api(tags = "en: Message Notification Configuration API,zh: 消息通知配置API")
@Api(tags = "Notification Config API | 消息通知配置API")
@RestController()
@RequestMapping(value = "/notice", produces = {APPLICATION_JSON_VALUE})
public class NoticeConfigController {

View File

@@ -24,7 +24,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
* @author tom
* @date 2021/12/7 15:57
*/
@Api(tags = "en: System Summary Statistics API,zh: 系统摘要统计API")
@Api(tags = "Summary Statistics API | 系统摘要统计API")
@RestController
@RequestMapping(path = "/summary", produces = {APPLICATION_JSON_VALUE})
public class SummaryController {

View File

@@ -6,16 +6,20 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
* Param Define Database Operations
* ParamDefine数据库操作
*
* @author tomsun28
* @date 2021/11/14 11:27
*/
public interface ParamDefineDao extends JpaRepository<ParamDefine, Long> {
/**
* Query the parameter definitions under it according to the monitoring type
* 根据监控类型查询其下的参数定义
* @param app 监控类型
* @return 参数定义列表
*
* @param app Monitoring type 监控类型
* @return parameter definition list 参数定义列表
*/
List<ParamDefine> findParamDefinesByApp(String app);
}

View File

@@ -11,8 +11,11 @@ import java.util.List;
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
/**
* Hierarchical structure
* 层级关系结构
* eg: Monitoring Type Indicator Group Indicator Information Hierarchy Relationship
* eg: 监控类型指标组指标信息层级关系
*
* @author tom
* @date 2021/12/12 16:23
*/
@@ -21,18 +24,33 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
@Data
public class Hierarchy {
/**
* Category value
*/
@ApiModelProperty(value = "类别值", example = "os", accessMode = READ_WRITE, position = 0)
String category;
/**
* Attribute value
*/
@ApiModelProperty(value = "属性值", example = "linux", accessMode = READ_WRITE, position = 1)
String value;
/**
* Attribute internationalization tag
*/
@ApiModelProperty(value = "属性国际化标签", example = "Linux系统", accessMode = READ_WRITE, position = 2)
String label;
/**
* Is it a leaf node
*/
@ApiModelProperty(value = "是否是叶子节点", example = "true", accessMode = READ_WRITE, position = 3)
Boolean isLeaf = false;
/**
* Next level of association
*/
@ApiModelProperty(value = "下一关联层级", accessMode = READ_WRITE, position = 4)
private List<Hierarchy> children;
}

View File

@@ -13,7 +13,9 @@ import javax.validation.constraints.NotBlank;
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
/**
* Login registered account information transfer body username phone email
* 登录注册账户信息传输体 username phone email
*
* @author tomsun28
* @date 20:36 2019-08-01
*/
@@ -21,17 +23,27 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "账户信息传输体")
@ApiModel(description = "en: Account information transfer body,zh: 账户信息传输体")
public class LoginDto {
/**
* type
* 1. Account (email username and mobile phone number) password login 2. github login 3. WeChat login
*/
@ApiModelProperty(value = "类型", example = "1", accessMode = READ_ONLY, position = 0)
@Range(min = 0, max = 4, message = "1.账户(邮箱用户名手机号)密码登录 2.github登录 3.微信登录")
private Byte type;
/**
* User ID
*/
@ApiModelProperty(value = "用户标识", example = "1", accessMode = READ_ONLY, position = 0)
@NotBlank(message = "Identifier can not null")
private String identifier;
/**
* key
*/
@ApiModelProperty(value = "密钥", example = "1", accessMode = READ_ONLY, position = 0)
@NotBlank(message = "Credential can not null")
private String credential;

View File

@@ -8,6 +8,7 @@ import java.util.List;
import java.util.Map;
/**
* Monitoring Type Management Interface
* 监控类型管理接口
*
* @author tomsun28
@@ -16,10 +17,11 @@ import java.util.Map;
public interface AppService {
/**
* Query the defined parameter structure based on the monitoring type
* 根据监控类型查询定义的参数结构
*
* @param app 监控类型
* @return 参数结构列表
* @param app Monitoring type 监控类型
* @return list of parameter structures 参数结构列表
*/
List<ParamDefine> getAppParamDefines(String app);
@@ -35,18 +37,20 @@ public interface AppService {
Job getAppDefine(String app) throws IllegalArgumentException;
/**
* Get defined monitoring I 18 N resources
* 获取定义的监控I18N资源
*
* @param lang 语言类型
* @return I18N资源
* @param lang Language type 语言类型
* @return I18N Resources I18N资源
*/
Map<String, String> getI18nResources(String lang);
/**
* Query all types of monitoring - indicator group - indicator level
* 查询所有监控的类型-指标组-指标层级
*
* @param lang 语言
* @return 层级信息
* @param lang language 语言
* @return level information 层级信息
*/
List<Hierarchy> getAllAppHierarchy(String lang);

View File

@@ -11,6 +11,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.Yaml;
@@ -18,6 +21,7 @@ import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -122,6 +126,8 @@ public class AppServiceImpl implements AppService, CommandLineRunner {
@Override
public void run(String... args) throws Exception {
boolean loadFromFile = true;
final List<InputStream> inputStreams = new LinkedList<>();
// 读取app定义配置加载到内存中 define/app/*.yml
Yaml yaml = new Yaml();
String classpath = this.getClass().getClassLoader().getResource("").getPath();
@@ -132,37 +138,82 @@ public class AppServiceImpl implements AppService, CommandLineRunner {
defineAppPath = classpath + File.separator + "define" + File.separator + "app";
directory = new File(defineAppPath);
if (!directory.exists() || directory.listFiles() == null) {
throw new IllegalArgumentException("define app directory not exist: " + defineAppPath);
}
}
log.info("query define path {}", defineAppPath);
for (File appFile : Objects.requireNonNull(directory.listFiles())) {
if (appFile.exists()) {
try (FileInputStream fileInputStream = new FileInputStream(appFile)) {
Job app = yaml.loadAs(fileInputStream, Job.class);
appDefines.put(app.getApp().toLowerCase(), app);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new IOException(e);
// load define app yml in jar
log.info("load define app yml in internal jar");
loadFromFile = false;
try {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:define/app/*.yml");
for (Resource resource : resources) {
inputStreams.add(resource.getInputStream());
}
} catch (Exception e) {
log.error("define app yml not exist");
throw e;
}
}
}
if (loadFromFile) {
log.info("load define path {}", defineAppPath);
for (File appFile : Objects.requireNonNull(directory.listFiles())) {
if (appFile.exists()) {
try (FileInputStream fileInputStream = new FileInputStream(appFile)) {
Job app = yaml.loadAs(fileInputStream, Job.class);
appDefines.put(app.getApp().toLowerCase(), app);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new IOException(e);
}
}
}
} else {
if (inputStreams.isEmpty()) {
throw new IllegalArgumentException("define app directory not exist");
} else {
inputStreams.forEach(stream -> {
try {
Job app = yaml.loadAs(stream, Job.class);
appDefines.put(app.getApp().toLowerCase(), app);
stream.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
});
}
}
// 读取监控参数定义配置加载到数据库中 define/param/*.yml
String defineParamPath = classpath + File.separator + "define" + File.separator + "param";
directory = new File(defineParamPath);
if (!directory.exists() || directory.listFiles() == null) {
throw new IllegalArgumentException("define param directory not exist: " + defineParamPath);
}
for (File appFile : Objects.requireNonNull(directory.listFiles())) {
if (appFile.exists()) {
try (FileInputStream fileInputStream = new FileInputStream(appFile)) {
ParamDefineDto paramDefine = yaml.loadAs(fileInputStream, ParamDefineDto.class);
paramDefines.put(paramDefine.getApp().toLowerCase(), paramDefine.getParam());
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new IOException(e);
if (loadFromFile) {
String defineParamPath = classpath + File.separator + "define" + File.separator + "param";
directory = new File(defineParamPath);
if (!directory.exists() || directory.listFiles() == null) {
throw new IllegalArgumentException("define param directory not exist: " + defineParamPath);
}
for (File appFile : Objects.requireNonNull(directory.listFiles())) {
if (appFile.exists()) {
try (FileInputStream fileInputStream = new FileInputStream(appFile)) {
ParamDefineDto paramDefine = yaml.loadAs(fileInputStream, ParamDefineDto.class);
paramDefines.put(paramDefine.getApp().toLowerCase(), paramDefine.getParam());
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new IOException(e);
}
}
}
} else {
try {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:define/param/*.yml");
for (Resource resource : resources) {
InputStream stream = resource.getInputStream();
ParamDefineDto paramDefine = yaml.loadAs(stream, ParamDefineDto.class);
paramDefines.put(paramDefine.getApp().toLowerCase(), paramDefine.getParam());
stream.close();
}
} catch (Exception e) {
log.error("define param yml not exist");
throw e;
}
}
}
}

View File

@@ -34,7 +34,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
*/
@RestController
@RequestMapping(produces = {APPLICATION_JSON_VALUE})
@Api(tags = "监控指标数据API")
@Api(tags = "Metrics Data API | 监控指标数据API")
public class MetricsDataController {
private static final Integer METRIC_FULL_LENGTH = 3;

View File

@@ -1,5 +1,5 @@
{
"name": "web-app",
"name": "hertzbeat-web-app",
"version": "0.0.0",
"scripts": {
"ng": "ng",

View File

@@ -17,11 +17,7 @@ import { environment } from '@env/environment';
<i nz-icon nzIconfont="icon-gitee"></i>
</a>
</layout-default-header-item>
<layout-default-header-item direction="left" hidden="mobile">
<a layout-default-header-item-trigger routerLink="/passport/lock">
<i nz-icon nzType="lock"></i>
</a>
</layout-default-header-item>
<layout-default-header-item direction="left" hidden="pc">
<div layout-default-header-item-trigger (click)="searchToggleStatus = !searchToggleStatus">
<i nz-icon nzType="search"></i>
@@ -33,6 +29,11 @@ import { environment } from '@env/environment';
<layout-default-header-item direction="right" hidden="mobile">
<header-notify></header-notify>
</layout-default-header-item>
<layout-default-header-item direction="right" hidden="mobile">
<a layout-default-header-item-trigger routerLink="/passport/lock">
<i nz-icon nzType="lock"></i>
</a>
</layout-default-header-item>
<layout-default-header-item direction="right" hidden="mobile">
<div layout-default-header-item-trigger nz-dropdown [nzDropdownMenu]="settingsMenu" nzTrigger="click" nzPlacement="bottomRight">
<i nz-icon nzType="setting"></i>

View File

@@ -7,6 +7,11 @@ import { LocalStorageService } from '../../../service/local-storage.service';
@Component({
selector: 'header-user',
template: `
<div class="alain-default__nav-item d-flex align-items-center px-sm" (click)="logout()">
<i nz-icon nzType="logout" class="mr-sm"></i>
{{ 'menu.account.logout' | i18n }}
</div>
<!--
<div class="alain-default__nav-item d-flex align-items-center px-sm" nz-dropdown nzPlacement="bottomRight" [nzDropdownMenu]="userMenu">
<nz-avatar [nzSrc]="user.avatar" nzSize="small" class="mr-sm"></nz-avatar>
{{ user.name }}
@@ -20,6 +25,7 @@ import { LocalStorageService } from '../../../service/local-storage.service';
</div>
</div>
</nz-dropdown-menu>
-->
`,
changeDetection: ChangeDetectionStrategy.OnPush
})

View File

@@ -14,10 +14,10 @@
<nz-divider></nz-divider>
<div>
<button nz-button nzType="primary" (click)="onDeleteAlerts()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
{{ 'alert.center.delete' | i18n }}
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onMarkReadAlerts()">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
{{ 'alert.center.deal' | i18n }}
@@ -26,8 +26,9 @@
<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]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
<button nz-button nzType="primary" nzDanger (click)="onDeleteAlerts()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
{{ 'alert.center.delete' | i18n }}
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="loadAlertsTable()">
@@ -122,9 +123,6 @@
</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]="'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]="'alert.center.deal' | i18n">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
@@ -137,6 +135,16 @@
>
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
nzDanger
(click)="onDeleteOneAlert(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.center.delete' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
</tr>
</tbody>

View File

@@ -19,13 +19,16 @@
<nz-tabset nzSize="large">
<nz-tab [nzTitle]="'alert.notice.receiver' | i18n">
<button nz-button nzType="primary" (click)="syncReceiver()">
<i nz-icon nzType="sync" nzTheme="outline"></i>
{{ 'common.refresh' | i18n }}
</button>
<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]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
#fixedTable
[nzData]="receivers"
@@ -100,6 +103,7 @@
<button
nz-button
nzType="primary"
nzDanger
(click)="onDeleteOneNoticeReceiver(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.receiver.delete' | i18n"
@@ -112,13 +116,16 @@
</nz-table>
</nz-tab>
<nz-tab [nzTitle]="'alert.notice.rule' | i18n">
<button nz-button nzType="primary" (click)="syncRule()">
<i nz-icon nzType="sync" nzTheme="outline"></i>
{{ 'common.refresh' | i18n }}
</button>
<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]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
#ruleFixedTable
[nzData]="rules"
@@ -174,6 +181,7 @@
<button
nz-button
nzType="primary"
nzDanger
(click)="onDeleteOneNoticeRule(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.rule.delete' | i18n"

View File

@@ -17,21 +17,17 @@
</nz-breadcrumb>
<nz-divider></nz-divider>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<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()">
<button nz-button nzType="primary" nzDanger (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]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
#fixedTable
@@ -116,6 +112,7 @@
</button>
<button
nz-button
nzDanger
nzType="primary"
(click)="onDeleteOneAlertDefine(data.id)"
nz-tooltip

View File

@@ -10,8 +10,7 @@
</div>
<div nz-col nzSpan="14" class="p-md text-white">
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.available' | i18n }} </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>{{ 'monitor.status.unavailable' | i18n }} </span
@@ -91,10 +90,12 @@
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unavailable' | i18n }} </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>{{ 'monitor.status.unreachable' | i18n }} </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>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unManageSize }}</span>

View File

@@ -352,6 +352,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
if (message.code === 0) {
let page = message.data;
this.alerts = page.content;
this.cdr.detectChanges();
} else {
console.warn(message.msg);
}

View File

@@ -14,30 +14,27 @@
<nz-divider></nz-divider>
<div>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary">
<a routerLink="/monitors/new" [queryParams]="{ app: app }">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
{{ '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()">
<button nz-button nzType="primary" nzDanger (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]="'common.refresh' | i18n">
<i nz-icon nzType="sync" nzTheme="outline"></i>
<button nz-button nzType="primary" nzDanger (click)="onDeleteMonitors()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
{{ 'monitors.delete' | i18n }}
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchMonitors()">
@@ -130,15 +127,6 @@
<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]="'monitors.delete-monitor' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
@@ -150,6 +138,7 @@
</button>
<button
nz-button
nzDanger
nzType="primary"
(click)="onCancelManageOneMonitor(data.id)"
nz-tooltip
@@ -157,6 +146,16 @@
>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
<button
nz-button
nzDanger
nzType="primary"
(click)="onDeleteOneMonitor(data.id)"
nz-tooltip
[nzTooltipTitle]="'monitors.delete-monitor' | i18n"
>
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
</tr>
</tbody>

View File

@@ -22,7 +22,7 @@ const routes: Routes = [
children: [
// todo 根据路由自动生成面包屑
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent, data: { title: '仪表盘' } },
{ path: 'dashboard', component: DashboardComponent, data: { titleI18n: 'menu.dashboard' } },
{ path: 'exception', loadChildren: () => import('./exception/exception.module').then(m => m.ExceptionModule) },
{ path: 'monitors', loadChildren: () => import('./monitor/monitor.module').then(m => m.MonitorModule) },
{ path: 'alert', loadChildren: () => import('./alert/alert.module').then(m => m.AlertModule) }
@@ -40,8 +40,8 @@ const routes: Routes = [
path: 'passport',
component: LayoutPassportComponent,
children: [
{ path: 'login', component: UserLoginComponent, data: { title: '登录' } },
{ path: 'lock', component: UserLockComponent, data: { title: '锁屏' } }
{ path: 'login', component: UserLoginComponent, data: { titleI18n: 'app.login.login' } },
{ path: 'lock', component: UserLockComponent, data: { titleI18n: 'app.lock' } }
]
},
{ path: '**', redirectTo: 'exception/404' }

View File

@@ -2,6 +2,8 @@ import { NgModule, Type } from '@angular/core';
import { SharedModule } from '@shared';
// dashboard pages
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzTimelineModule } from 'ng-zorro-antd/timeline';
import { NgxEchartsModule } from 'ngx-echarts';
import { DashboardComponent } from './dashboard/dashboard.component';
@@ -10,8 +12,6 @@ import { UserLockComponent } from './passport/lock/lock.component';
// passport pages
import { UserLoginComponent } from './passport/login/login.component';
import { RouteRoutingModule } from './routes-routing.module';
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzTimelineModule } from 'ng-zorro-antd/timeline';
const COMPONENTS: Array<Type<void>> = [
DashboardComponent,

View File

@@ -22,7 +22,7 @@
"security": "安全设置",
"binding": "账号绑定",
"trigger": "触发错误",
"logout": "退出登录"
"logout": "退出"
},
"alert": {
"": "告警",

View File

@@ -22,7 +22,7 @@
"security": "安全設置",
"binding": "賬號綁定",
"trigger": "觸發錯誤",
"logout": "退出登錄"
"logout": "退出"
},
"alert": {
"": "告警",

View File

@@ -7,12 +7,50 @@
// ==========The following is the custom theme variable area==========
// The theme parameters can be generated at https://ng-alain.github.io/ng-alain/
// @primary-color: #f50;
@primary-color: #722ED1;
@primary-color: #3f51b5;
@font-size-base: 12px;
@nz-table-rep-padding-vertical: 2px;
@nz-table-rep-padding-horizontal: 2px;
@alain-default-header-hg: 52px;
@alain-default-header-bg: #722ED1;
@alain-default-header-bg: #3f51b5;
@alain-default-header-padding: 8px;
@alain-default-aside-nav-text-hover-color: #722ED1;
@alain-default-aside-nav-selected-text-color: #722ED1;
@alain-default-aside-nav-text-hover-color: #3f51b5;
@alain-default-aside-nav-selected-text-color: #3f51b5;
.ant-switch-checked{
background-color: #ff4081;
}
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #ff4081;
border-color: #ff4081;
}
.ant-radio-wrapper:hover .ant-radio,
.ant-radio:hover .ant-radio-inner,
.ant-radio-input:focus + .ant-radio-inner {
border-color: #ff4081;
background: #ff4081;
}
.sidebar-nav .sidebar-nav__selected{
background: rgba(63,81,181,.15);
color: #3f51b5;
}
.sidebar-nav__sub .sidebar-nav__item{
color: #000000a6;
}
.sidebar-nav__open > .sidebar-nav__sub {
background-color: #fafafa;
}
.sidebar-nav__sub .sidebar-nav__item:hover{
background: rgba(0,0,0,.04);
}
.ant-btn-dangerous.ant-btn-primary {
border-color: #ff4081;
background: #ff4081;
}