已合并
智能运维模块630需求内容,含实例监控插件、SQL诊断插件、告警通知插件 #277
Louisyzh创建于 2023年6月24日
智能运维模块630需求内容,含实例监控插件、SQL诊断插件、告警通知插件 #277
已合并
共 754 个文件变更+59336-22775
| @@ -0,0 +1,543 @@ | |||
| 1 | +# 告警通知插件(alert-center) 用户手册 | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +## 1告警通知插件(alert-center)用户手册 | ||
| 6 | + | ||
| 7 | + 告警通知插件主要目的是为 openGauss 用户提供告警通知能力。它作为一体化平台的可插拔插件开发,本特性依赖于openGauss一体化平台的插件特性。 | ||
| 8 | + | ||
| 9 | +## 2 前言 | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +### 2.1 概述 | ||
| 14 | + | ||
| 15 | + 本章介绍手册相关信息。 | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +### 2.2 读者对象 | ||
| 20 | + | ||
| 21 | + 本手册主要适用于以下人员: | ||
| 22 | + | ||
| 23 | +- 数据库开发人员 | ||
| 24 | +- 数据库管理员 | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +### 2.3 修订记录 | ||
| 29 | + | ||
| 30 | +| 日期 | 版本 | 变更说明 | 修改人 | 审核人 | | ||
| 31 | +| ---------- | ------ | ------------ | -------- | ----------- | | ||
| 32 | +| 2023/06/12 | v1.0.0 | 新增编译初版 | wuyuebin | zengseliang | | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +### 2.4 文档约定 | ||
| 37 | + | ||
| 38 | + 本节描述了本手册的(内容、符号、GUI 和文本)约定。 | ||
| 39 | + | ||
| 40 | +**图形化界面格式约定** | ||
| 41 | + | ||
| 42 | + 本手册中可能出现下列图形化界面格式约定,它们所代表的含义如下。 | ||
| 43 | + | ||
| 44 | +| 格式 | 说明 | | ||
| 45 | +| ---- | ------------------------------------------------------------ | | ||
| 46 | +| 粗体 | 按钮、菜单、参数、页签、窗口及对话框标题均使用【】括起来。例如,单击【确定】。 | | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + | ||
| 50 | +### 2.5 第三方许可证 | ||
| 51 | + | ||
| 52 | + 本节包含适用于该插件的第三方许可证。 | ||
| 53 | + | ||
| 54 | + **表2-1 第三方软件列表** | ||
| 55 | + | ||
| 56 | +| 第三方软件 | | ||
| 57 | +| -------------- | | ||
| 58 | +| 木兰宽松许可证 | | ||
| 59 | + | ||
| 60 | + | ||
| 61 | + | ||
| 62 | +### 2.6 参考文档 | ||
| 63 | + | ||
| 64 | +无 | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + | ||
| 68 | +## 3告警通知插件(alert-center)简介 | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + | ||
| 72 | +### 3.1 概述 | ||
| 73 | + | ||
| 74 | + 告警通知插件主要目的是为 openGauss 用户提供告警通知能力。它作为一体化平台的可插拔插件开发,本特性依赖于openGauss一体化平台的插件特性。 | ||
| 75 | + | ||
| 76 | + 实例监控功能主要分监控告警和通知配置两大功能。其中监控告警分告警记录、告警配置、告警模板、告警规则;通知配置分通知模板和通知方式,而通知方式又分为通知方式和通知渠道。 | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +### 3.2 支持的功能 | ||
| 81 | + | ||
| 82 | + 告警通知插件(alert-center)提供的功能如下: | ||
| 83 | + | ||
| 84 | + **告警记录** | ||
| 85 | + | ||
| 86 | +- 展示prometheus发送过来的告警信息 | ||
| 87 | +- 统计告警信息 | ||
| 88 | +- 显示关联视图:根据告警规则获取指标的告警数据,通过图表展示 | ||
| 89 | + | ||
| 90 | + **告警配置** | ||
| 91 | + | ||
| 92 | +- 展示告警配置列表 | ||
| 93 | +- 支持为单个或者批量实例配置模板 | ||
| 94 | +- 也可以直接为实例配置规则 | ||
| 95 | + | ||
| 96 | + **告警模板** | ||
| 97 | + | ||
| 98 | +- 展示告警模板列表 | ||
| 99 | +- 支持增删改查 | ||
| 100 | +- 可以对告警模板中的规则进行修改 | ||
| 101 | + | ||
| 102 | + **告警规则** | ||
| 103 | + | ||
| 104 | +- 展示告警规则列表,可查询规则详细 | ||
| 105 | +- 已内置一些规则:CPU使用率、内存使用率、磁盘使用量、IO、数据库LOCK个数和锁时间的告警 | ||
| 106 | + | ||
| 107 | + **通知模板** | ||
| 108 | + | ||
| 109 | +- 展示通知模板列表,支持增删改查 | ||
| 110 | + | ||
| 111 | + **通知方式** | ||
| 112 | + | ||
| 113 | +- 展示通知方式列表,支持增删改查 | ||
| 114 | +- 目前只支持邮箱的通知方式 | ||
| 115 | + | ||
| 116 | + **通知渠道** | ||
| 117 | + | ||
| 118 | +- 展示发送人的邮箱、企业微信和钉钉相关信息,支持修改 | ||
| 119 | +- 提供通知渠道是否有效的测试功能,目前只支持邮箱测试 | ||
| 120 | +- 通知渠道目前只支持通过邮箱去发送告警信息 | ||
| 121 | + | ||
| 122 | + | ||
| 123 | + | ||
| 124 | +### 3.3 约束和限制 | ||
| 125 | + | ||
| 126 | +**安装插件前提** | ||
| 127 | + | ||
| 128 | +安装该插件之前,必须先安装实例监控插件,并在插件中安装prometheus | ||
| 129 | + | ||
| 130 | +**第一次使用** | ||
| 131 | + | ||
| 132 | +第一次安装该插件时,需要去设置告警接口的IP和端口号,IP为平台IP,端口后为后端的端口号。 | ||
| 133 | + | ||
| 134 | +**项目运行** | ||
| 135 | + | ||
| 136 | +本项目依赖一体化主平台,若需要使用本项目所有功能,只能通过编译成 jar 包的形式作为插件运行在主平台上。 | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + | ||
| 140 | +### 3.4 告警通知插件(alert-center)项目结构 | ||
| 141 | + | ||
| 142 | +下载告警通知插件(alert-center)项目代码 | ||
| 143 | + | ||
| 144 | +``` | ||
| 145 | +git clone https://gitee.com/opengauss/openGauss-workbench | ||
| 146 | +``` | ||
| 147 | + | ||
| 148 | +告警通知插件(alert-center)项目结构如下图所示: | ||
| 149 | + | ||
| 150 | + | ||
| 151 | + | ||
| 152 | +告警通知插件项目结构说明如下: | ||
| 153 | + | ||
| 154 | +| 文件夹/文件 | 说明 | | ||
| 155 | +| ----------- | ---------------------- | | ||
| 156 | +| src | 保存后端代码及资源文件 | | ||
| 157 | +| web-ui | 保存前端代码 | | ||
| 158 | +| .gitignore | 提交git忽略的目录 | | ||
| 159 | +| pom.xml | 后端依赖项 | | ||
| 160 | +| LICENSE | 许可证 | | ||
| 161 | + | ||
| 162 | +### 3.5 系统要求 | ||
| 163 | + | ||
| 164 | + 本节介绍使用告警通知插件(alert center)的最低系统要求。 | ||
| 165 | + | ||
| 166 | +**系统要求** | ||
| 167 | + | ||
| 168 | +| 操作系统 | 版本 | | ||
| 169 | +| -------- | -------------- | | ||
| 170 | +| windows | windows7及以上 | | ||
| 171 | + | ||
| 172 | +**软件要求** | ||
| 173 | + | ||
| 174 | +| 软件 | 规格 | | ||
| 175 | +| ---- | ----------- | | ||
| 176 | +| Java | jdk 8及以上 | | ||
| 177 | + | ||
| 178 | +**数据库版本要求** | ||
| 179 | + | ||
| 180 | +| 数据库 | 版本 | | ||
| 181 | +| --------- | ---- | | ||
| 182 | +| openGauss | 所有 | | ||
| 183 | + | ||
| 184 | + | ||
| 185 | + | ||
| 186 | +## 4 部署告警通知插件(alert-center) | ||
| 187 | + | ||
| 188 | + 本章详细介绍如何部署告警通知插件(alert-center)。 | ||
| 189 | + | ||
| 190 | + 前端技术栈:Vue3.0 + TS + Element plus | ||
| 191 | + | ||
| 192 | + 后端技术栈:Java + Spring boot | ||
| 193 | + | ||
| 194 | +### 4.1 编译项目并部署至一体化平台 | ||
| 195 | + | ||
| 196 | +**前置条件:**① 安装 node.js,建议使用 v16 以上版本 | ||
| 197 | + | ||
| 198 | + ② 安装Java jdk (建议使用v11及以上版本) 和 maven 3.X | ||
| 199 | + | ||
| 200 | +**步骤 1:** 检查自动构建前端项目的配置是否为false | ||
| 201 | + | ||
| 202 | +``` | ||
| 203 | +在 plugins > observability-instance > pom.xml 下将以下值设为false: | ||
| 204 | +<web.build.skip>false</web.build.skip> | ||
| 205 | +<web.clean.skip>false</web.clean.skip> | ||
| 206 | +``` | ||
| 207 | + | ||
| 208 | +**步骤 2:** 启动打包命令 | ||
| 209 | + | ||
| 210 | +``` | ||
| 211 | +mvn clean package -P prod | ||
| 212 | +``` | ||
| 213 | + | ||
| 214 | +**步骤 3:**在target目录下找到生成的alert-center-5.0.0-repackage.jar,安装到一体化平台 | ||
| 215 | + | ||
| 216 | + | ||
| 217 | + | ||
| 218 | +### 4.2本地调试项目 | ||
| 219 | + | ||
| 220 | +下面介绍如何在本地启动项目进行开发调试。 | ||
| 221 | + | ||
| 222 | +#### 4.2.1 启动后端项目 | ||
| 223 | + | ||
| 224 | +**前置条件**:安装Java jdk (建议使用v8及以上版本) 和 maven 3.X。 | ||
| 225 | + | ||
| 226 | +**步骤 1:**使用idea打开项目,并配置好maven | ||
| 227 | + | ||
| 228 | +**步骤 2:**将pom.xml文件中的的<scope>provided</scope>注释,刷新maven | ||
| 229 | + | ||
| 230 | + | ||
| 231 | + | ||
| 232 | +**步骤 3:**注释application.yml中的 | ||
| 233 | + | ||
| 234 | +``` | ||
| 235 | +context: | ||
| 236 | + listener: | ||
| 237 | + classes: org.opengauss.plugin.alertcenter.listener.PluginListener | ||
| 238 | +``` | ||
| 239 | + | ||
| 240 | + | ||
| 241 | + | ||
| 242 | + | ||
| 243 | + | ||
| 244 | +**步骤 4:**修改application-dev.yml中数据库信息,改为自己开发环境的数据库 | ||
| 245 | + | ||
| 246 | + | ||
| 247 | + | ||
| 248 | + | ||
| 249 | + | ||
| 250 | +**步骤 5:**启动ObservabilityPluginBootApplication的main函数,启动时,带上--spring.profiles.active=dev,启动时可能会报一些错误,但不会影响系统启动。 | ||
| 251 | + | ||
| 252 | + | ||
| 253 | + | ||
| 254 | + | ||
| 255 | + | ||
| 256 | +**步骤 6(可忽略):**报错的原因是:解析用户密码的工具类来自平台,由于是单独启动,无法使用该工具类,导致解码失败。要解决该错误,可以修改下面画圈部分(不修改也不会影响主体流程,但是连接prometheus的服务器功能不可用,无法修改prometheus的配置) | ||
| 257 | + | ||
| 258 | + | ||
| 259 | + | ||
| 260 | +**步骤 7(可忽略):**将密码改为明文,写死在代码中,然后重新启动项目 | ||
| 261 | + | ||
| 262 | + | ||
| 263 | + | ||
| 264 | + | ||
| 265 | + | ||
| 266 | + | ||
| 267 | + | ||
| 268 | +#### 4.2.2 启动前端项目 | ||
| 269 | + | ||
| 270 | +**前置条件:**安装 node.js,建议使用 v16 以上版本。 | ||
| 271 | + | ||
| 272 | +**步骤 1:**下载依赖包 | ||
| 273 | + | ||
| 274 | +``` | ||
| 275 | + 任选以下一种命令: | ||
| 276 | + npm install | ||
| 277 | + yarn install | ||
| 278 | +``` | ||
| 279 | + | ||
| 280 | +**步骤 2:**启动前端项目 | ||
| 281 | + | ||
| 282 | +``` | ||
| 283 | + 根据package.json配置任选以下一种命令: | ||
| 284 | + npm run dev | ||
| 285 | + npm run lint | ||
| 286 | + npm run lint:prettier | ||
| 287 | +``` | ||
| 288 | + | ||
| 289 | +**步骤 3:** 根据启动提示进入对应的URL地址,如下图所示: | ||
| 290 | + | ||
| 291 | + | ||
| 292 | + | ||
| 293 | + | ||
| 294 | + | ||
| 295 | +## 5 使用告警通知插件(alert-center) | ||
| 296 | + | ||
| 297 | +### 5.1 概述 | ||
| 298 | + | ||
| 299 | + 本章详细介绍如何使用告警通知插件(alert-center) 的功能。 | ||
| 300 | + | ||
| 301 | +### 5.2 告警记录 | ||
| 302 | + | ||
| 303 | + 当触发告警后,Prometheus将告警信息推送到平台,平台将告警信息记录下来,并在告警记录页面展示出来。同时,告警记录支持查看告警详细以及告警的相关指标的关联视图。 | ||
| 304 | + | ||
| 305 | +#### 5.2.1 告警记录列表 | ||
| 306 | + | ||
| 307 | +**步骤 1:**点击DataKit菜单【监控告警】-【告警记录】,进入告警记录列表,显示告警统计信息、饼图和列表 | ||
| 308 | + | ||
| 309 | + **说明:**【集群/实例】、【告警时间范围】选项为可选 | ||
| 310 | + | ||
| 311 | + 更改【集群/实例】或者【告警时间范围】,将根据条件查询数据 | ||
| 312 | + | ||
| 313 | + 选择数据,点击【**标记为未读**】,将数据标记为未读 | ||
| 314 | + | ||
| 315 | + 选择数据,点击【**标记为已读**】,将数据标记为已读 | ||
| 316 | + | ||
| 317 | +| 配置项 | 必填 | 组件形式 | 数据类型限制 | 配置说明 | | ||
| 318 | +| ------------ | ---- | -------- | ------------ | ------------------- | | ||
| 319 | +| 集群/实例 | 否 | 下拉框 | - | | | ||
| 320 | +| 告警时间范围 | 否 | 下拉框 | - | yyyy-MM-dd HH:mm:ss | | ||
| 321 | + | ||
| 322 | + | ||
| 323 | + | ||
| 324 | +#### 5.2.2告警详情 | ||
| 325 | + | ||
| 326 | +**步骤 1:**点击上面的告警记录列表数据中的【**查看**】按钮,进入告警详情 | ||
| 327 | + | ||
| 328 | + | ||
| 329 | + | ||
| 330 | + | ||
| 331 | + | ||
| 332 | +### 5.3 告警配置 | ||
| 333 | + | ||
| 334 | + 为实例配置告警模板(包含多个告警规则),并展示在告警配置页面中。同时将实例的告警规则配置到prometheus配置文件中,prometheus将根据配置的规则对实例进行监控。 | ||
| 335 | + | ||
| 336 | +#### 5.3.1 告警配置列表显示 | ||
| 337 | + | ||
| 338 | +**步骤 1:**点击DataKit菜单【监控告警】-【告警配置】,进入告警配置列表,显示告警配置列表 | ||
| 339 | + | ||
| 340 | + **说明:** 【实例名称】条件可选 | ||
| 341 | + | ||
| 342 | + 单击 查询图标将根据条件查询数据。 | ||
| 343 | + | ||
| 344 | +| 配置项 | 必填 | 组件形式 | 数据类型限制 | 配置说明 | | ||
| 345 | +| -------- | ---- | -------- | ------------ | -------- | | ||
| 346 | +| 实例名称 | 否 | 输入框 | - | | | ||
| 347 | + | ||
| 348 | + | ||
| 349 | + | ||
| 350 | + | ||
| 351 | + | ||
| 352 | +#### 5.3.2 告警配置 | ||
| 353 | + | ||
| 354 | +**步骤 1:** 在上面的告警配置列表中,选择数据,点击列表上方的【**配置**】按钮,或者直接列表点击【**配置**】按钮,进入告警配置页面。 | ||
| 355 | + | ||
| 356 | + | ||
| 357 | + | ||
| 358 | + | ||
| 359 | + | ||
| 360 | +**步骤 2:**告警配置可根据告警模板进行配置,也可以直接选择告警规则进行配置,下面使用告警规则进行配置 | ||
| 361 | + | ||
| 362 | + | ||
| 363 | + | ||
| 364 | + | ||
| 365 | + | ||
| 366 | + | ||
| 367 | + | ||
| 368 | +### 5.4 告警模板 | ||
| 369 | + | ||
| 370 | + 告警模板统一组合多个告警规则,为实例提供统一配置告警规则的模板。同时支持对告警规则的再次编辑(比如对告警规则的阈值更改)。告警模板展示模板列表,支持对模板进行增删改查。 | ||
| 371 | + | ||
| 372 | +#### 5.4.1 告警模板列表 | ||
| 373 | + | ||
| 374 | +**步骤 1:**点击DataKit菜单【监控告警】-【告警模板】,进入告警模板列表,显示告警模板列表 | ||
| 375 | + | ||
| 376 | + **说明:** 【模板名称】和【规则名称】条件均可选 | ||
| 377 | + | ||
| 378 | + 单击 查询图标将根据条件查询数据。 | ||
| 379 | + | ||
| 380 | +| 配置项 | 必填 | 组件形式 | 数据类型限制 | 配置说明 | | ||
| 381 | +| -------- | ---- | -------- | ------------ | -------- | | ||
| 382 | +| 模板名称 | 否 | 输入框 | - | | | ||
| 383 | +| 规则名称 | 否 | 输入框 | - | | | ||
| 384 | + | ||
| 385 | + | ||
| 386 | + | ||
| 387 | + | ||
| 388 | + | ||
| 389 | +#### 5.4.2 新增或者修改模板 | ||
| 390 | + | ||
| 391 | +**步骤 1:**在上面的告警模板页面左侧的告警模板列表中,点击【**新增**】或者直接点击列表中的【**编辑**】按钮,进入编辑页面 | ||
| 392 | + | ||
| 393 | + | ||
| 394 | + | ||
| 395 | +**步骤 2(可省略):**对告警规则再次编辑,可修改告警级别、告警内容、告警规则阈值、告警描述、告警通知、是否重复通知、是否静默、通知方式等等 | ||
| 396 | + | ||
| 397 | + | ||
| 398 | + | ||
| 399 | +#### 5.4.3 删除告警模板 | ||
| 400 | + | ||
| 401 | +**步骤 1:**在5.4.1的告警模板页面左侧的告警模板列表中,点击列表中的【删除】按钮,弹出删除提示,点击【确定】按钮,即可删除告警模板 | ||
| 402 | + | ||
| 403 | + | ||
| 404 | + | ||
| 405 | + | ||
| 406 | + | ||
| 407 | +### 5.5 告警规则 | ||
| 408 | + | ||
| 409 | + 告警规则主要内置多种规则,提供给告警模板进行配置。告警规则页面展示告警规则列表,并能支持查看功能。 | ||
| 410 | + | ||
| 411 | +#### 5.5.1 告警规则列表 | ||
| 412 | + | ||
| 413 | + **步骤 1:**点击DataKit菜单【监控告警】-【告警规则】,进入告警规则页面,显示告警规则列表 | ||
| 414 | + | ||
| 415 | + **说明:** 【规则名称】、【规则类型】、【告警级别】条件均可选 | ||
| 416 | + | ||
| 417 | + 单击 查询图标将根据条件查询数据。 | ||
| 418 | + | ||
| 419 | +| 配置项 | 必填 | 组件形式 | 数据类型限制 | 配置说明 | | ||
| 420 | +| -------- | ---- | -------- | ------------ | -------- | | ||
| 421 | +| 规则名称 | 否 | 输入框 | - | | | ||
| 422 | +| 规则类型 | 否 | 下拉框 | - | | | ||
| 423 | +| 告警级别 | 否 | 下拉框 | - | | | ||
| 424 | + | ||
| 425 | + | ||
| 426 | + | ||
| 427 | + | ||
| 428 | + | ||
| 429 | +#### 5.5.2 告警规则详细 | ||
| 430 | + | ||
| 431 | + **步骤 1:**点击5.5.1告警规则列表中的某个数据的【**查看**】按钮,进入规则详细页面 | ||
| 432 | + | ||
| 433 | + | ||
| 434 | + | ||
| 435 | + | ||
| 436 | + | ||
| 437 | +### 5.6 通知模板 | ||
| 438 | + | ||
| 439 | + 对告警通知的内容进行个性化包装,当出现告警时,将包装后的内容发给用户。支持增删改查,用于通知方式设置。 | ||
| 440 | + | ||
| 441 | +#### 5.6.1 通知模板列表 | ||
| 442 | + | ||
| 443 | + **步骤 1:**点击DataKit菜单【通知配置】-【通知模板】,进入通知模板页面,显示通知模板列表 | ||
| 444 | + | ||
| 445 | + **说明:** 【模板名称】、【模板类型】条件均可选 | ||
| 446 | + | ||
| 447 | + 单击 查询图标将根据条件查询数据。 | ||
| 448 | + | ||
| 449 | +| 配置项 | 必填 | 组件形式 | 数据类型限制 | 配置说明 | | ||
| 450 | +| -------- | ---- | -------- | ------------ | -------- | | ||
| 451 | +| 模板名称 | 否 | 输入框 | - | | | ||
| 452 | +| 模板类型 | 否 | 下拉框 | - | | | ||
| 453 | + | ||
| 454 | + | ||
| 455 | + | ||
| 456 | + | ||
| 457 | + | ||
| 458 | + | ||
| 459 | + | ||
| 460 | +#### 5.6.2 新增/修改通知模板 | ||
| 461 | + | ||
| 462 | +**步骤 1:**点击5.6.1 通知模板页面中的【**新增**】按钮或者点击通知模板列表中的【**修改**】按钮,进入模板修改页面 | ||
| 463 | + | ||
| 464 | + | ||
| 465 | + | ||
| 466 | + | ||
| 467 | + | ||
| 468 | +#### 5.6.3 删除告警模板 | ||
| 469 | + | ||
| 470 | +**步骤 1:**点击5.6.1 通知模板列表中的【**删除**】按钮,弹出删除提示,点击【确定】按钮,即可对通知模板进行删除 | ||
| 471 | + | ||
| 472 | + | ||
| 473 | + | ||
| 474 | + | ||
| 475 | + | ||
| 476 | +### 5.7 通知方式 | ||
| 477 | + | ||
| 478 | + 配置通知人的相关信息(邮件、钉钉、企业微信)和通知模板,为告警规则提供通知方式,支持增删改查。 | ||
| 479 | + | ||
| 480 | +#### 5.6.1 通知方式列表 | ||
| 481 | + | ||
| 482 | + **步骤 1:**点击DataKit菜单【通知配置】-【通知方式】,默认选择【通知方式】TAB,进入通知方式页面,显示通知方式列表 | ||
| 483 | + | ||
| 484 | + **说明:** 【通知方式名称】、【发送方式】条件均可选 | ||
| 485 | + | ||
| 486 | + 更改【发送方式】条件将查询数据; | ||
| 487 | + | ||
| 488 | + 单击 查询图标将根据条件查询数据。 | ||
| 489 | + | ||
| 490 | +| 配置项 | 必填 | 组件形式 | 数据类型限制 | 配置说明 | | ||
| 491 | +| ------------ | ---- | -------- | ------------ | -------- | | ||
| 492 | +| 通知方式名称 | 否 | 输入框 | - | | | ||
| 493 | +| 发送方式 | 否 | 下拉框 | - | | | ||
| 494 | + | ||
| 495 | + | ||
| 496 | + | ||
| 497 | + | ||
| 498 | + | ||
| 499 | + | ||
| 500 | + | ||
| 501 | +#### 5.6.2 新增/修改通知方式 | ||
| 502 | + | ||
| 503 | + **步骤 1:**点击5.6.2 通知方式页面中的【**新增**】按钮或者点击列表中的【**修改**】按钮,进入通知方式修改页面 | ||
| 504 | + | ||
| 505 | + | ||
| 506 | + | ||
| 507 | + | ||
| 508 | + | ||
| 509 | +#### 5.6.3 删除通知方式 | ||
| 510 | + | ||
| 511 | + **步骤 1:**点击5.6.2 通知方式列表中的【**删除**】按钮,弹出删除提示,点击【确定】按钮,即可对通知方式进行删除 | ||
| 512 | + | ||
| 513 | + | ||
| 514 | + | ||
| 515 | + | ||
| 516 | + | ||
| 517 | +### 5.8 通知渠道 | ||
| 518 | + | ||
| 519 | + 配置发送人的邮箱、企业微信、钉钉等等,目前只支持邮箱。 | ||
| 520 | + | ||
| 521 | +#### 5.6.1 通知渠道页面 | ||
| 522 | + | ||
| 523 | + **步骤 1:**点击DataKit菜单【通知配置】-【通知方式】,选择【通知渠道】Tab,进入通知渠道页面 | ||
| 524 | + | ||
| 525 | +**步骤 2:**修改相关配置,点击【**确定**】按钮,可修改通知渠道 | ||
| 526 | + | ||
| 527 | + | ||
| 528 | + | ||
| 529 | + | ||
| 530 | + | ||
| 531 | +**步骤 3:**点击右边的【**测试**】按钮,对通知渠道进行测试,目前只支持邮箱 | ||
| 532 | + | ||
| 533 | + | ||
| 534 | + | ||
| 535 | + | ||
| 536 | + | ||
| 537 | +## 6 FAQS | ||
| 538 | + | ||
| 539 | +1、第一次安装平台时,需要设置告警接口,IP为平台IP,端口后为后端的端口号 | ||
| 540 | + | ||
| 541 | + | ||
| 542 | + | ||
| 543 | + | ||
| @@ -0,0 +1,358 @@ | |||
| 1 | + | ||
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| 5 | + <modelVersion>4.0.0</modelVersion> | ||
| 6 | + | ||
| 7 | + <groupId>org.opengauss</groupId> | ||
| 8 | + <artifactId>alert-center</artifactId> | ||
| 9 | + <version>5.0.0</version> | ||
| 10 | + <packaging>jar</packaging> | ||
| 11 | + | ||
| 12 | + <properties> | ||
| 13 | + | ||
| 14 | + <!--config--> | ||
| 15 | + <plugin-id>alert-center</plugin-id> | ||
| 16 | + <npm.run.script>buildNoTest</npm.run.script> | ||
| 17 | + <web.build.skip>false</web.build.skip> | ||
| 18 | + <web.clean.skip>false</web.clean.skip> | ||
| 19 | + | ||
| 20 | + <java.version>11</java.version> | ||
| 21 | + <maven.compiler.source>11</maven.compiler.source> | ||
| 22 | + <maven.compiler.target>11</maven.compiler.target> | ||
| 23 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| 24 | + | ||
| 25 | + <!-- dependency version --> | ||
| 26 | + <spring-brick.version>3.1.0</spring-brick.version> | ||
| 27 | + <junit.version>4.13</junit.version> | ||
| 28 | + <mybatis-plus.version>3.5.2</mybatis-plus.version> | ||
| 29 | + <fastjson.version>1.2.78</fastjson.version> | ||
| 30 | + <lombok.version>1.18.24</lombok.version> | ||
| 31 | + <hutool.version>5.0.3</hutool.version> | ||
| 32 | + </properties> | ||
| 33 | + | ||
| 34 | + <dependencies> | ||
| 35 | + <!-- same as framework --> | ||
| 36 | + <dependency> | ||
| 37 | + <groupId>org.springframework.boot</groupId> | ||
| 38 | + <artifactId>spring-boot-starter</artifactId> | ||
| 39 | + </dependency> | ||
| 40 | + <dependency> | ||
| 41 | + <groupId>org.opengauss</groupId> | ||
| 42 | + <artifactId>visualtool-framework</artifactId> | ||
| 43 | + <version>5.0.0</version> | ||
| 44 | + <scope>provided</scope> | ||
| 45 | + <exclusions> | ||
| 46 | + <!--druid-spring-boot-starter removed--> | ||
| 47 | + <exclusion> | ||
| 48 | + <groupId>org.springframework.boot</groupId> | ||
| 49 | + <artifactId>spring-boot-starter-data-redis</artifactId> | ||
| 50 | + </exclusion> | ||
| 51 | + </exclusions> | ||
| 52 | + </dependency> | ||
| 53 | + <dependency> | ||
| 54 | + <groupId>com.sun.mail</groupId> | ||
| 55 | + <artifactId>jakarta.mail</artifactId> | ||
| 56 | + <version>2.0.1</version> | ||
| 57 | + </dependency> | ||
| 58 | + <dependency> | ||
| 59 | + <groupId>jakarta.activation</groupId> | ||
| 60 | + <artifactId>jakarta.activation-api</artifactId> | ||
| 61 | + <version>2.0.1</version> | ||
| 62 | + </dependency> | ||
| 63 | +<!-- <dependency>--> | ||
| 64 | +<!-- <groupId>org.springframework.boot</groupId>--> | ||
| 65 | +<!-- <artifactId>spring-boot-starter-mail</artifactId>--> | ||
| 66 | +<!-- <exclusions>--> | ||
| 67 | +<!-- <exclusion>--> | ||
| 68 | +<!-- <groupId>com.sun.activation</groupId>--> | ||
| 69 | +<!-- <artifactId>jakarta.activation</artifactId>--> | ||
| 70 | +<!-- </exclusion>--> | ||
| 71 | +<!-- </exclusions>--> | ||
| 72 | +<!-- </dependency>--> | ||
| 73 | + | ||
| 74 | + <dependency> | ||
| 75 | + <groupId>org.springframework.boot</groupId> | ||
| 76 | + <artifactId>spring-boot-starter-validation</artifactId> | ||
| 77 | + </dependency> | ||
| 78 | + <dependency> | ||
| 79 | + <groupId>com.gitee.starblues</groupId> | ||
| 80 | + <artifactId>spring-brick-bootstrap</artifactId> | ||
| 81 | + <version>${spring-brick.version}</version> | ||
| 82 | + </dependency> | ||
| 83 | + | ||
| 84 | + <dependency> | ||
| 85 | + <groupId>com.gitee.starblues</groupId> | ||
| 86 | + <artifactId>spring-brick-maven-packager</artifactId> | ||
| 87 | + <version>${spring-brick.version}</version> | ||
| 88 | + </dependency> | ||
| 89 | + <dependency> | ||
| 90 | + <groupId>junit</groupId> | ||
| 91 | + <artifactId>junit</artifactId> | ||
| 92 | + <scope>test</scope> | ||
| 93 | + </dependency> | ||
| 94 | + | ||
| 95 | + <dependency> | ||
| 96 | + <groupId>org.projectlombok</groupId> | ||
| 97 | + <artifactId>lombok</artifactId> | ||
| 98 | + <scope>provided</scope> | ||
| 99 | + </dependency> | ||
| 100 | + <!-- same as framework --> | ||
| 101 | + | ||
| 102 | + <!-- common --> | ||
| 103 | + <dependency> | ||
| 104 | + <groupId>org.springframework.boot</groupId> | ||
| 105 | + <artifactId>spring-boot-starter-test</artifactId> | ||
| 106 | + <scope>test</scope> | ||
| 107 | + </dependency> | ||
| 108 | + <dependency> | ||
| 109 | + <groupId>com.alibaba</groupId> | ||
| 110 | + <artifactId>fastjson</artifactId> | ||
| 111 | + <version>${fastjson.version}</version> | ||
| 112 | + </dependency> | ||
| 113 | + <dependency> | ||
| 114 | + <groupId>cn.hutool</groupId> | ||
| 115 | + <artifactId>hutool-all</artifactId> | ||
| 116 | + <version>${hutool.version}</version> | ||
| 117 | + </dependency> | ||
| 118 | + <!-- common --> | ||
| 119 | + | ||
| 120 | + <!-- data --> | ||
| 121 | + <dependency> | ||
| 122 | + <groupId>com.baomidou</groupId> | ||
| 123 | + <artifactId>mybatis-plus-boot-starter</artifactId> | ||
| 124 | + <version>${mybatis-plus.version}</version> | ||
| 125 | + </dependency> | ||
| 126 | + <dependency> | ||
| 127 | + <groupId>com.alibaba</groupId> | ||
| 128 | + <artifactId>druid-spring-boot-starter</artifactId> | ||
| 129 | + <version>1.2.8</version> | ||
| 130 | + </dependency> | ||
| 131 | + <dependency> | ||
| 132 | + <groupId>com.baomidou</groupId> | ||
| 133 | + <artifactId>dynamic-datasource-spring-boot-starter</artifactId> | ||
| 134 | + <version>${mybatis-plus.version}</version> | ||
| 135 | + </dependency> | ||
| 136 | + <dependency> | ||
| 137 | + <groupId>org.postgresql</groupId> | ||
| 138 | + <artifactId>postgresql</artifactId> | ||
| 139 | + <version>42.2.24</version> | ||
| 140 | + </dependency> | ||
| 141 | + <dependency> | ||
| 142 | + <groupId>org.opengauss</groupId> | ||
| 143 | + <artifactId>opengauss-jdbc</artifactId> | ||
| 144 | + <version>3.0.0</version> | ||
| 145 | + </dependency> | ||
| 146 | + <dependency> | ||
| 147 | + <groupId>com.jcraft</groupId> | ||
| 148 | + <artifactId>jsch</artifactId> | ||
| 149 | + <version>0.1.55</version> | ||
| 150 | + </dependency> | ||
| 151 | + <!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc --> | ||
| 152 | + <dependency> | ||
| 153 | + <groupId>org.xerial</groupId> | ||
| 154 | + <artifactId>sqlite-jdbc</artifactId> | ||
| 155 | + <version>3.39.3.0</version> | ||
| 156 | + </dependency> | ||
| 157 | + <!-- https://mvnrepository.com/artifact/org.apache.sshd/sshd-scp --> | ||
| 158 | + <dependency> | ||
| 159 | + <groupId>org.apache.sshd</groupId> | ||
| 160 | + <artifactId>sshd-sftp</artifactId> | ||
| 161 | + <version>2.9.2</version> | ||
| 162 | + </dependency> | ||
| 163 | + <dependency> | ||
| 164 | + <groupId>org.hibernate.validator</groupId> | ||
| 165 | + <artifactId>hibernate-validator</artifactId> | ||
| 166 | + </dependency> | ||
| 167 | + </dependencies> | ||
| 168 | + | ||
| 169 | + <dependencyManagement> | ||
| 170 | + <!-- Compiler properties --> | ||
| 171 | + <dependencies> | ||
| 172 | + <dependency> | ||
| 173 | + <groupId>org.springframework.boot</groupId> | ||
| 174 | + <artifactId>spring-boot-dependencies</artifactId> | ||
| 175 | + <version>2.5.6</version> | ||
| 176 | + <type>pom</type> | ||
| 177 | + <scope>import</scope> | ||
| 178 | + </dependency> | ||
| 179 | + </dependencies> | ||
| 180 | + </dependencyManagement> | ||
| 181 | + | ||
| 182 | + <repositories> | ||
| 183 | + <repository> | ||
| 184 | + <id>gitee-eb-repo</id> | ||
| 185 | + <name>The Maven Repository on Gitee</name> | ||
| 186 | + <url>https://gitee.com/agile-adept-team/spring-brick-eb/tree/master/maven-repo</url> | ||
| 187 | + </repository> | ||
| 188 | + </repositories> | ||
| 189 | + | ||
| 190 | + <profiles> | ||
| 191 | + <profile> | ||
| 192 | + <id>dev</id> | ||
| 193 | + <properties> | ||
| 194 | + <profiles.active>dev</profiles.active> | ||
| 195 | + <swagger.scope>compile</swagger.scope> | ||
| 196 | + </properties> | ||
| 197 | + <activation> | ||
| 198 | + <activeByDefault>true</activeByDefault> | ||
| 199 | + </activation> | ||
| 200 | + </profile> | ||
| 201 | + <profile> | ||
| 202 | + <id>prod</id> | ||
| 203 | + <properties> | ||
| 204 | + <profiles.active>prod</profiles.active> | ||
| 205 | + <swagger.scope>provided</swagger.scope> | ||
| 206 | + </properties> | ||
| 207 | + </profile> | ||
| 208 | + </profiles> | ||
| 209 | + | ||
| 210 | + <build> | ||
| 211 | + <pluginManagement> | ||
| 212 | + <plugins> | ||
| 213 | + <plugin> | ||
| 214 | + <groupId>com.gitee.starblues</groupId> | ||
| 215 | + <artifactId>spring-brick-maven-packager</artifactId> | ||
| 216 | + <version>${spring-brick.version}</version> | ||
| 217 | + </plugin> | ||
| 218 | + </plugins> | ||
| 219 | + </pluginManagement> | ||
| 220 | + <plugins> | ||
| 221 | + <plugin> | ||
| 222 | + <groupId>com.gitee.starblues</groupId> | ||
| 223 | + <artifactId>spring-brick-maven-packager</artifactId> | ||
| 224 | + <configuration> | ||
| 225 | + <mode>prod</mode> | ||
| 226 | + <pluginInfo> | ||
| 227 | + <id>${plugin-id}</id> | ||
| 228 | + <bootstrapClass>org.opengauss.plugin.alertcenter.ObservabilityPluginApplication</bootstrapClass> | ||
| 229 | + <version>${project.version}</version> | ||
| 230 | + <provider>ncti-gba</provider> | ||
| 231 | + <description>Intelligent OPS</description> | ||
| 232 | + </pluginInfo> | ||
| 233 | + </configuration> | ||
| 234 | + <executions> | ||
| 235 | + <execution> | ||
| 236 | + <goals> | ||
| 237 | + <goal>repackage</goal> | ||
| 238 | + </goals> | ||
| 239 | + </execution> | ||
| 240 | + </executions> | ||
| 241 | + </plugin> | ||
| 242 | + <plugin> | ||
| 243 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 244 | + <artifactId>maven-compiler-plugin</artifactId> | ||
| 245 | + <version>3.1</version> | ||
| 246 | + <configuration> | ||
| 247 | + <source>${java.version}</source> | ||
| 248 | + <target>${java.version}</target> | ||
| 249 | + <encoding>${project.build.sourceEncoding}</encoding> | ||
| 250 | + </configuration> | ||
| 251 | + </plugin> | ||
| 252 | + <plugin> | ||
| 253 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 254 | + <artifactId>maven-surefire-plugin</artifactId> | ||
| 255 | + <configuration> | ||
| 256 | + <skip>true</skip> | ||
| 257 | + </configuration> | ||
| 258 | + </plugin> | ||
| 259 | + | ||
| 260 | + <plugin> | ||
| 261 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 262 | + <artifactId>maven-clean-plugin</artifactId> | ||
| 263 | + <version>3.2.0</version> | ||
| 264 | + <configuration> | ||
| 265 | + <filesets> | ||
| 266 | + <fileset> | ||
| 267 | + <directory>web-ui/dist</directory> | ||
| 268 | + <includes> | ||
| 269 | + <include>**/*</include> | ||
| 270 | + </includes> | ||
| 271 | + <followSymlinks>false</followSymlinks> | ||
| 272 | + </fileset> | ||
| 273 | + <fileset> | ||
| 274 | + <directory>${basedir}/src/main/resources/resources</directory> | ||
| 275 | + <includes> | ||
| 276 | + <include>**/*</include> | ||
| 277 | + </includes> | ||
| 278 | + <followSymlinks>false</followSymlinks> | ||
| 279 | + </fileset> | ||
| 280 | + </filesets> | ||
| 281 | + <skip>${web.clean.skip}</skip> | ||
| 282 | + <failOnError>true</failOnError> | ||
| 283 | + </configuration> | ||
| 284 | + </plugin> | ||
| 285 | + | ||
| 286 | + <plugin> | ||
| 287 | + <groupId>org.codehaus.mojo</groupId> | ||
| 288 | + <artifactId>exec-maven-plugin</artifactId> | ||
| 289 | + <version>1.6.0</version> | ||
| 290 | + <configuration> | ||
| 291 | + <skip>false</skip> | ||
| 292 | + </configuration> | ||
| 293 | + <executions> | ||
| 294 | + <execution> | ||
| 295 | + <id>exec-npm-install</id> | ||
| 296 | + <phase>generate-resources</phase> | ||
| 297 | + <goals> | ||
| 298 | + <goal>exec</goal> | ||
| 299 | + </goals> | ||
| 300 | + <configuration> | ||
| 301 | + <executable>npm</executable> | ||
| 302 | + <arguments> | ||
| 303 | + <argument>install</argument> | ||
| 304 | + </arguments> | ||
| 305 | + <workingDirectory>web-ui</workingDirectory> | ||
| 306 | + </configuration> | ||
| 307 | + </execution> | ||
| 308 | + | ||
| 309 | + <execution> | ||
| 310 | + <id>exec-npm-run-build</id> | ||
| 311 | + <phase>generate-resources</phase> | ||
| 312 | + <goals> | ||
| 313 | + <goal>exec</goal> | ||
| 314 | + </goals> | ||
| 315 | + <configuration> | ||
| 316 | + <skip>${web.build.skip}</skip> | ||
| 317 | + <executable>npm</executable> | ||
| 318 | + <arguments> | ||
| 319 | + <argument>run</argument> | ||
| 320 | + <argument>${npm.run.script}</argument> | ||
| 321 | + </arguments> | ||
| 322 | + <workingDirectory>web-ui</workingDirectory> | ||
| 323 | + </configuration> | ||
| 324 | + </execution> | ||
| 325 | + </executions> | ||
| 326 | + </plugin> | ||
| 327 | + | ||
| 328 | + <plugin> | ||
| 329 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 330 | + <artifactId>maven-resources-plugin</artifactId> | ||
| 331 | + <configuration> | ||
| 332 | + <delimiters>@</delimiters> | ||
| 333 | + <useDefaultDelimiters>false</useDefaultDelimiters> | ||
| 334 | + </configuration> | ||
| 335 | + <version>2.5</version> | ||
| 336 | + <executions> | ||
| 337 | + <execution> | ||
| 338 | + <id>copy-web</id> | ||
| 339 | + <phase>generate-resources</phase> | ||
| 340 | + <goals> | ||
| 341 | + <goal>copy-resources</goal> | ||
| 342 | + </goals> | ||
| 343 | + <configuration> | ||
| 344 | + <outputDirectory>${basedir}/src/main/resources</outputDirectory> | ||
| 345 | + <resources> | ||
| 346 | + <resource> | ||
| 347 | + <directory>web-ui/dist</directory> | ||
| 348 | + <targetPath>resources</targetPath> | ||
| 349 | + </resource> | ||
| 350 | + </resources> | ||
| 351 | + </configuration> | ||
| 352 | + </execution> | ||
| 353 | + </executions> | ||
| 354 | + </plugin> | ||
| 355 | + </plugins> | ||
| 356 | + </build> | ||
| 357 | + | ||
| 358 | +</project> | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/ObservabilityPluginApplication.java+31-0
| @@ -0,0 +1,31 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter; | ||
| 6 | + | ||
| 7 | +import com.gitee.starblues.bootstrap.SpringPluginBootstrap; | ||
| 8 | +import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| 9 | +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; | ||
| 10 | +import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; | ||
| 11 | +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | ||
| 12 | +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; | ||
| 13 | +import org.springframework.scheduling.annotation.EnableScheduling; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * wuyuebin | ||
| 17 | + * 2023/4/7 16:24 | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + DataSourceAutoConfiguration.class, | ||
| 22 | + HibernateJpaAutoConfiguration.class, | ||
| 23 | + RedisAutoConfiguration.class, | ||
| 24 | + RedisRepositoriesAutoConfiguration.class | ||
| 25 | +}) | ||
| 26 | + | ||
| 27 | +public class ObservabilityPluginApplication extends SpringPluginBootstrap { | ||
| 28 | + public static void main(String[] args) { | ||
| 29 | + new ObservabilityPluginApplication().run(args); | ||
| 30 | + } | ||
| 31 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/ObservabilityPluginBootApplication.java+49-0
| @@ -0,0 +1,49 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter; | ||
| 6 | + | ||
| 7 | +import org.mybatis.spring.annotation.MapperScan; | ||
| 8 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 9 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 10 | +import org.springframework.boot.SpringApplication; | ||
| 11 | +import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| 12 | +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; | ||
| 13 | +import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; | ||
| 14 | +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; | ||
| 15 | +import org.springframework.context.annotation.ComponentScan; | ||
| 16 | +import org.springframework.context.annotation.FilterType; | ||
| 17 | +import org.springframework.context.annotation.Profile; | ||
| 18 | +import org.springframework.scheduling.annotation.EnableScheduling; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * wuyuebin | ||
| 22 | + * 2023/4/7 16:36 | ||
| 23 | + * | ||
| 24 | + */ | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + HibernateJpaAutoConfiguration.class, | ||
| 29 | + RedisAutoConfiguration.class, | ||
| 30 | + RedisRepositoriesAutoConfiguration.class}) | ||
| 31 | + | ||
| 32 | + "org.opengauss.admin.system.service.ops", | ||
| 33 | + "org.opengauss.admin.common.utils.ops", | ||
| 34 | + "org.opengauss.admin.common.core.handler.ops.cache"}, | ||
| 35 | + basePackageClasses = {HostFacade.class, | ||
| 36 | + HostUserFacade.class}, | ||
| 37 | + excludeFilters = {.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = | ||
| 38 | + {org.opengauss.admin.system.plugin.facade.MenuFacade.class, | ||
| 39 | + org.opengauss.admin.system.plugin.facade.MonitorToolsFacade.class, | ||
| 40 | + org.opengauss.admin.system.plugin.facade.PluginFacade.class, | ||
| 41 | + org.opengauss.admin.system.plugin.facade.SysSettingFacade.class, | ||
| 42 | + org.opengauss.admin.system.plugin.facade.TaskFacade.class, | ||
| 43 | + org.opengauss.admin.system.plugin.facade.WsFacade.class})}) | ||
| 44 | + | ||
| 45 | +public class ObservabilityPluginBootApplication { | ||
| 46 | + public static void main(String[] args) { | ||
| 47 | + SpringApplication.run(ObservabilityPluginBootApplication.class, args); | ||
| 48 | + } | ||
| 49 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/AlertApplicationRunner.java+29-0
| @@ -0,0 +1,29 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config; | ||
| 6 | + | ||
| 7 | +import lombok.extern.slf4j.Slf4j; | ||
| 8 | +import org.opengauss.plugin.alertcenter.service.PrometheusService; | ||
| 9 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 10 | +import org.springframework.boot.ApplicationArguments; | ||
| 11 | +import org.springframework.boot.ApplicationRunner; | ||
| 12 | +import org.springframework.stereotype.Component; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * wuyuebin | ||
| 16 | + * 2023/4/27 16:17 | ||
| 17 | + * 初始化操作 | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +public class AlertApplicationRunner implements ApplicationRunner { | ||
| 22 | + | ||
| 23 | + private PrometheusService prometheusService; | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + public void run(ApplicationArguments args) throws Exception { | ||
| 27 | + prometheusService.initPrometheusConfig(); | ||
| 28 | + } | ||
| 29 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/DataSourceConfig.java+43-0
| @@ -0,0 +1,43 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config; | ||
| 6 | + | ||
| 7 | +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; | ||
| 8 | +import com.gitee.starblues.bootstrap.PluginContextHolder; | ||
| 9 | +import com.gitee.starblues.spring.environment.EnvironmentProvider; | ||
| 10 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 11 | +import org.springframework.boot.jdbc.DataSourceBuilder; | ||
| 12 | +import org.springframework.context.annotation.Bean; | ||
| 13 | +import org.springframework.context.annotation.Configuration; | ||
| 14 | +import org.springframework.context.annotation.Profile; | ||
| 15 | + | ||
| 16 | +import javax.sql.DataSource; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * wuyuebin | ||
| 20 | + * 2023/4/13 09:39 | ||
| 21 | + * | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | +public class DataSourceConfig { | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + public DataSource dataSource() { | ||
| 29 | + EnvironmentProvider environmentProvider = PluginContextHolder.getEnvironmentProvider(); | ||
| 30 | + // read config from dataKit platform | ||
| 31 | + String url = environmentProvider.getString("spring.datasource.url"); | ||
| 32 | + String username = environmentProvider.getString("spring.datasource.username"); | ||
| 33 | + String password = environmentProvider.getString("spring.datasource.password"); | ||
| 34 | + String driverClassName = environmentProvider.getString("spring.datasource.driver-class-name"); | ||
| 35 | + | ||
| 36 | + DataSource primary = DataSourceBuilder.create().driverClassName(driverClassName).url(url).username(username) | ||
| 37 | + .password(password).build(); | ||
| 38 | + DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); | ||
| 39 | + dataSource.addDataSource("primary", primary); | ||
| 40 | + dataSource.setPrimary("primary"); | ||
| 41 | + return dataSource; | ||
| 42 | + } | ||
| 43 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/MybatisPlusConfig.java+50-0
| @@ -0,0 +1,50 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.DbType; | ||
| 8 | +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | ||
| 9 | +import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; | ||
| 10 | +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; | ||
| 11 | +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; | ||
| 12 | +import org.springframework.context.annotation.Bean; | ||
| 13 | +import org.springframework.context.annotation.Configuration; | ||
| 14 | +import org.springframework.transaction.annotation.EnableTransactionManagement; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * Description: mybatis-plus configuration | ||
| 18 | + * | ||
| 19 | + * xielibo | ||
| 20 | + * 1.0 | ||
| 21 | + * : 2021/9/28 5:54 PM | ||
| 22 | + * JDK 1.8 | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +public class MybatisPlusConfig { | ||
| 27 | + | ||
| 28 | + public MybatisPlusInterceptor mybatisPlusInterceptor() { | ||
| 29 | + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); | ||
| 30 | + interceptor.addInnerInterceptor(paginationInnerInterceptor()); | ||
| 31 | + interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); | ||
| 32 | + interceptor.addInnerInterceptor(blockAttackInnerInterceptor()); | ||
| 33 | + return interceptor; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public PaginationInnerInterceptor paginationInnerInterceptor() { | ||
| 37 | + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); | ||
| 38 | + paginationInnerInterceptor.setDbType(DbType.POSTGRE_SQL); | ||
| 39 | + paginationInnerInterceptor.setMaxLimit(-1L); | ||
| 40 | + return paginationInnerInterceptor; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { | ||
| 44 | + return new OptimisticLockerInnerInterceptor(); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public BlockAttackInnerInterceptor blockAttackInnerInterceptor() { | ||
| 48 | + return new BlockAttackInnerInterceptor(); | ||
| 49 | + } | ||
| 50 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/PluginExtensionInfoConfig.java+36-0
| @@ -0,0 +1,36 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config; | ||
| 6 | + | ||
| 7 | +import com.gitee.starblues.core.PluginExtensionInfo; | ||
| 8 | + | ||
| 9 | +import java.util.HashMap; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * wuyuebin | ||
| 14 | + * 2023/4/13 11:37 | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | +public class PluginExtensionInfoConfig implements PluginExtensionInfo { | ||
| 18 | + | ||
| 19 | + public Map<String, Object> extensionInfo() { | ||
| 20 | + Map<String, Object> map = new HashMap<>(); | ||
| 21 | + map.put("logo", | ||
| 22 | + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdml" | ||
| 23 | + + "ld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tl" | ||
| 24 | + + "LXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIG" | ||
| 25 | + + "NsYXNzPSJmZWF0aGVyIGZlYXRoZXItZGF0YWJhc2UiPjxlbGxpcHNlIGN4PSIxMiIgY3k9IjUiIHJ4" | ||
| 26 | + + "PSI5IiByeT0iMyI+PC9lbGxpcHNlPjxwYXRoIGQ9Ik0yMSAxMmMwIDEuNjYtNCAzLTkgM3MtOS0xLj" | ||
| 27 | + + "M0LTktMyI+PC9wYXRoPjxwYXRoIGQ9Ik0zIDV2MTRjMCAxLjY2IDQgMyA5IDNzOS0xLjM0IDktM1Y1" | ||
| 28 | + + "Ij48L3BhdGg+PC9zdmc+"); | ||
| 29 | + map.put("theme", "light"); | ||
| 30 | + map.put("pluginType", 1); | ||
| 31 | + map.put("isNeedConfigured", 0); | ||
| 32 | + map.put("configAttrs", "[{\"attrCode\":\"esHost\",\"attrLabel\":\"ES服务器\"}," | ||
| 33 | + + "{\"attrCode\":\"esPort\",\"attrLabel\":\"端口\"}]"); | ||
| 34 | + return map; | ||
| 35 | + } | ||
| 36 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/annotation/AlertContentParam.java+27-0
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config.annotation; | ||
| 6 | + | ||
| 7 | +import java.lang.annotation.ElementType; | ||
| 8 | +import java.lang.annotation.Retention; | ||
| 9 | +import java.lang.annotation.RetentionPolicy; | ||
| 10 | +import java.lang.annotation.Target; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * wuyuebin | ||
| 14 | + * 2023/6/16 14:53 | ||
| 15 | + * 常驻参数说明 | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +public AlertContentParam { | ||
| 20 | + String name() default ""; | ||
| 21 | + | ||
| 22 | + String preVal() default ""; | ||
| 23 | + | ||
| 24 | + boolean isI18nPreVal() default false; | ||
| 25 | + | ||
| 26 | + String[] group() default {}; | ||
| 27 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/properties/AlertProperty.java+31-0
| @@ -0,0 +1,31 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config.properties; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 9 | +import org.springframework.boot.context.properties.NestedConfigurationProperty; | ||
| 10 | +import org.springframework.stereotype.Component; | ||
| 11 | + | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * wuyuebin | ||
| 16 | + * 2023/4/27 15:21 | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +public class AlertProperty { | ||
| 23 | + private String ruleFilePrefix; | ||
| 24 | + | ||
| 25 | + private String ruleFileSuffix; | ||
| 26 | + | ||
| 27 | + private AlertmanagerProperty alertmanager; | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + private List<RuleItemProperty> ruleItems; | ||
| 31 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/properties/AlertmanagerProperty.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config.properties; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * wuyuebin | ||
| 11 | + * 2023/4/27 15:35 | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +public class AlertmanagerProperty { | ||
| 16 | + private String pathPrefix; | ||
| 17 | + private String apiVersion; | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/properties/RuleItemExpProperty.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config.properties; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * wuyuebin | ||
| 11 | + * 2023/5/29 10:51 | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +public class RuleItemExpProperty { | ||
| 16 | + private String type; | ||
| 17 | + private String exp; | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/properties/RuleItemParamProperty.java+19-0
| @@ -0,0 +1,19 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config.properties; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * wuyuebin | ||
| 11 | + * 2023/5/29 10:59 | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +public class RuleItemParamProperty { | ||
| 16 | + private String paramName; | ||
| 17 | + private String paramValue; | ||
| 18 | + private Integer paramOrder; | ||
| 19 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/config/properties/RuleItemProperty.java+25-0
| @@ -0,0 +1,25 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.config.properties; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import org.springframework.boot.context.properties.NestedConfigurationProperty; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * wuyuebin | ||
| 14 | + * 2023/5/29 10:46 | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +public class RuleItemProperty { | ||
| 19 | + private String name; | ||
| 20 | + private String unit; | ||
| 21 | + | ||
| 22 | + private List<RuleItemExpProperty> ruleExps; | ||
| 23 | + | ||
| 24 | + private List<RuleItemParamProperty> params; | ||
| 25 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/constant/CommonConstants.java+35-0
| @@ -0,0 +1,35 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.constant; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * wuyuebin | ||
| 9 | + * 2023/4/27 17:49 | ||
| 10 | + * | ||
| 11 | + */ | ||
| 12 | +public class CommonConstants { | ||
| 13 | + public static final String PROMETHEUS_YML = "/prometheus.yml"; | ||
| 14 | + public static final Integer IS_DELETE = 1; | ||
| 15 | + public static final Integer IS_NOT_DELETE = 0; | ||
| 16 | + public static final Integer UNREAD_STATUS = 0; | ||
| 17 | + public static final Integer READ_STATUS = 1; | ||
| 18 | + public static final Integer FIRING_STATUS = 0; | ||
| 19 | + public static final Integer RECOVER_STATUS = 1; | ||
| 20 | + public static final String SERIOUS = "serious"; | ||
| 21 | + public static final String WARN = "warn"; | ||
| 22 | + public static final String INFO = "info"; | ||
| 23 | + public static final String DELIMITER = ","; | ||
| 24 | + public static final Integer IS_NOT_REPEAT = 0; | ||
| 25 | + public static final Integer IS_REPEAT = 1; | ||
| 26 | + public static final Integer IS_NOT_SILENCE = 0; | ||
| 27 | + public static final Integer IS_SILENCE = 1; | ||
| 28 | + public static final String EMAIL = "email"; | ||
| 29 | + public static final String WE_COM = "WeCom"; | ||
| 30 | + public static final String DING_TALK = "DingTalk"; | ||
| 31 | + public static final Integer ENABLE = 1; | ||
| 32 | + public static final Integer DISABLE = 0; | ||
| 33 | + public static final String LINE_FEED = "\n"; | ||
| 34 | + public static final String SLASH = "/"; | ||
| 35 | +} | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.constant; | ||
| 6 | + | ||
| 7 | +import lombok.Getter; | ||
| 8 | +import lombok.RequiredArgsConstructor; | ||
| 9 | + | ||
| 10 | +import java.util.Arrays; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.stream.Collectors; | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +public enum OSType { | ||
| 17 | + DEFAULT("CentOS 7.6"), KYLIN_V10("kylinv10"), OPENEULER_203LTS("openEuler 20.3LTS"); | ||
| 18 | + private final String osType; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * Get the list of supported server operating systems | ||
| 22 | + * | ||
| 23 | + * Return to the list of server operating systems | ||
| 24 | + */ | ||
| 25 | + public static List<String> getAllOSType() { | ||
| 26 | + return Arrays.stream(OSType.values()).map(OSType::getOsType).collect(Collectors.toList()); | ||
| 27 | + } | ||
| 28 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/AlertApiController.java+60-0
| @@ -0,0 +1,60 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import cn.hutool.json.JSONObject; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.plugin.alertcenter.model.api.AlertApiReq; | ||
| 10 | +import org.opengauss.plugin.alertcenter.service.AlertApiService; | ||
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 12 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 13 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 14 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.RestController; | ||
| 16 | + | ||
| 17 | +import javax.validation.Valid; | ||
| 18 | +import java.util.ArrayList; | ||
| 19 | +import java.util.List; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * wuyuebin | ||
| 23 | + * 2023/4/28 08:44 | ||
| 24 | + * | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +public class AlertApiController { | ||
| 29 | + | ||
| 30 | + private AlertApiService alertApiService; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 这是prometheus推送数据的接口 | ||
| 34 | + * prometheus固定推送的接口是:/%pre/api/%v/alerts | ||
| 35 | + * prometheus配置文件中的path_prefix(%pre)是: /alertCenter | ||
| 36 | + * prometheus配置文件中的api_version(%v)是: v1 | ||
| 37 | + * <p> | ||
| 38 | + * appcation.yml中配置的context-path是/alertCenter/api/v1 | ||
| 39 | + * <p> | ||
| 40 | + * 注:context-path的"/alertCenter" 和 "v1" 必须和prometheus配置文件中的path_prefix、api_version匹配, | ||
| 41 | + * 后续如果需要修改context-path,需要去修改prometheus的配置或本接口的url路径 | ||
| 42 | + * | ||
| 43 | + * paramList 告警信息 | ||
| 44 | + * 返回成功信息 | ||
| 45 | + */ | ||
| 46 | + | ||
| 47 | + public AjaxResult alerts( List<JSONObject> paramList) { | ||
| 48 | + List<AlertApiReq> alertApiReqList = new ArrayList<>(); | ||
| 49 | + for (JSONObject jsonObject : paramList) { | ||
| 50 | + jsonObject.put("startsAt", jsonObject.getStr("startsAt").replace("T", " ").substring(0, 19)); | ||
| 51 | + jsonObject.put("endsAt", jsonObject.getStr("endsAt").replace("T", " ").substring(0, 19)); | ||
| 52 | + AlertApiReq alertApiReq = jsonObject.toBean(AlertApiReq.class); | ||
| 53 | + alertApiReq.setStartsAt(alertApiReq.getStartsAt().plusHours(8)); | ||
| 54 | + alertApiReq.setEndsAt(alertApiReq.getEndsAt().plusHours(8)); | ||
| 55 | + alertApiReqList.add(alertApiReq); | ||
| 56 | + } | ||
| 57 | + alertApiService.alerts(alertApiReqList); | ||
| 58 | + return AjaxResult.success(); | ||
| 59 | + } | ||
| 60 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/AlertClusterNodeConfController.java+59-0
| @@ -0,0 +1,59 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 8 | +import org.opengauss.plugin.alertcenter.dto.AlertClusterNodeConfDto; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertClusterNodeConf; | ||
| 10 | +import org.opengauss.plugin.alertcenter.model.AlertClusterNodeAndTemplateReq; | ||
| 11 | +import org.opengauss.plugin.alertcenter.model.AlertClusterNodeConfReq; | ||
| 12 | +import org.opengauss.plugin.alertcenter.service.AlertClusterNodeConfService; | ||
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 14 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 16 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 17 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 18 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 19 | +import org.springframework.web.bind.annotation.RestController; | ||
| 20 | + | ||
| 21 | +import javax.validation.Valid; | ||
| 22 | +import java.util.List; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * wuyuebin | ||
| 26 | + * 2023/4/26 15:57 | ||
| 27 | + * | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +public class AlertClusterNodeConfController extends BaseController { | ||
| 32 | + | ||
| 33 | + private AlertClusterNodeConfService alertClusterNodeConfService; | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + public AjaxResult getList() { | ||
| 37 | + List<AlertClusterNodeConfDto> list = alertClusterNodeConfService.getList(); | ||
| 38 | + return AjaxResult.success(list); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + public AjaxResult getByClusterNodeId( String clusterNodeId) { | ||
| 43 | + AlertClusterNodeConf alertClusterNodeConf = alertClusterNodeConfService.getByClusterNodeId(clusterNodeId); | ||
| 44 | + return AjaxResult.success(alertClusterNodeConf); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + public AjaxResult saveClusterNodeConf( AlertClusterNodeConfReq alertClusterNodeConfReq) { | ||
| 49 | + alertClusterNodeConfService.saveClusterNodeConf(alertClusterNodeConfReq); | ||
| 50 | + return AjaxResult.success(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + public AjaxResult saveAlertTemplateAndConfig( | ||
| 55 | + AlertClusterNodeAndTemplateReq clusterNodeAndTemplateReq) { | ||
| 56 | + alertClusterNodeConfService.saveAlertTemplateAndConfig(clusterNodeAndTemplateReq); | ||
| 57 | + return AjaxResult.success(); | ||
| 58 | + } | ||
| 59 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/AlertConfigController.java+46-0
| @@ -0,0 +1,46 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertConfig; | ||
| 10 | +import org.opengauss.plugin.alertcenter.service.AlertConfigService; | ||
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 12 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 13 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 14 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 15 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 16 | +import org.springframework.web.bind.annotation.RestController; | ||
| 17 | + | ||
| 18 | +import javax.validation.Valid; | ||
| 19 | +import java.util.List; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * wuyuebin | ||
| 23 | + * 2023/6/9 10:47 | ||
| 24 | + * | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +public class AlertConfigController { | ||
| 29 | + | ||
| 30 | + private AlertConfigService alertConfigService; | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + public AjaxResult getAlertConf() { | ||
| 34 | + List<AlertConfig> list = alertConfigService.list(); | ||
| 35 | + if (CollectionUtil.isEmpty(list)) { | ||
| 36 | + return AjaxResult.success(new AlertConfig()); | ||
| 37 | + } | ||
| 38 | + return AjaxResult.success(list.get(0)); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + public AjaxResult saveAlertConf( AlertConfig alertConfig) { | ||
| 43 | + alertConfigService.saveAlertConf(alertConfig); | ||
| 44 | + return AjaxResult.success(); | ||
| 45 | + } | ||
| 46 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/AlertRecordController.java+78-0
| @@ -0,0 +1,78 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.admin.common.core.page.TableDataInfo; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.AlertRecordDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.dto.AlertRelationDto; | ||
| 12 | +import org.opengauss.plugin.alertcenter.dto.AlertStatisticsDto; | ||
| 13 | +import org.opengauss.plugin.alertcenter.model.AlertRecordReq; | ||
| 14 | +import org.opengauss.plugin.alertcenter.model.AlertStatisticsReq; | ||
| 15 | +import org.opengauss.plugin.alertcenter.service.AlertRecordService; | ||
| 16 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 17 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 18 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 19 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 20 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 21 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 22 | +import org.springframework.web.bind.annotation.RestController; | ||
| 23 | + | ||
| 24 | +import java.util.List; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * wuyuebin | ||
| 28 | + * 2023/4/14 15:03 | ||
| 29 | + * | ||
| 30 | + */ | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +public class AlertRecordController extends BaseController { | ||
| 34 | + | ||
| 35 | + private AlertRecordService alertRecordService; | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + public TableDataInfo alertRecordListPage(AlertRecordReq alertRecordReq) { | ||
| 39 | + Page<AlertRecordDto> page = alertRecordService.getListPage(alertRecordReq, startPage()); | ||
| 40 | + return getDataTable(page); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + public AjaxResult alertRecordStatistics(AlertStatisticsReq alertStatisticsReq) { | ||
| 45 | + AlertStatisticsDto statisticsDto = alertRecordService.alertRecordStatistics(alertStatisticsReq); | ||
| 46 | + return AjaxResult.success(statisticsDto); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + public AjaxResult getById( Long id) { | ||
| 51 | + AlertRecordDto alertRecordDto = alertRecordService.getById(id); | ||
| 52 | + return AjaxResult.success(alertRecordDto); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + public AjaxResult markAsUnread( String ids) { | ||
| 57 | + String result = alertRecordService.markAsUnread(ids); | ||
| 58 | + return AjaxResult.success(result); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + /** | ||
| 62 | + * 处理告警信息,将未读状态改为已读 | ||
| 63 | + * | ||
| 64 | + * ids 多个,逗号分隔 | ||
| 65 | + * success | ||
| 66 | + */ | ||
| 67 | + | ||
| 68 | + public AjaxResult markAsRead( String ids) { | ||
| 69 | + String result = alertRecordService.markAsRead(ids); | ||
| 70 | + return AjaxResult.success(result); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + public AjaxResult getRelationData( Long id) { | ||
| 75 | + List<AlertRelationDto> relationData = alertRecordService.getRelationData(id); | ||
| 76 | + return AjaxResult.success(relationData); | ||
| 77 | + } | ||
| 78 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/AlertRuleController.java+51-0
| @@ -0,0 +1,51 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.admin.common.core.page.TableDataInfo; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.AlertRuleDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.model.RuleReq; | ||
| 12 | +import org.opengauss.plugin.alertcenter.service.AlertRuleService; | ||
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 14 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 16 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 17 | +import org.springframework.web.bind.annotation.RestController; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * wuyuebin | ||
| 21 | + * 2023/4/13 17:39 | ||
| 22 | + * | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +public class AlertRuleController extends BaseController { | ||
| 27 | + | ||
| 28 | + private AlertRuleService alertRuleService; | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + public TableDataInfo getRuleListPage(RuleReq ruleReq) { | ||
| 32 | + Page<AlertRuleDto> ruleIPage = alertRuleService.getRulePage(ruleReq, startPage()); | ||
| 33 | + return getDataTable(ruleIPage); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + public AjaxResult getRuleList() { | ||
| 38 | + return AjaxResult.success(alertRuleService.getRuleList()); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + | ||
| 43 | + public AjaxResult getRuleById( Long ruleId) { | ||
| 44 | + return AjaxResult.success(alertRuleService.getRuleById(ruleId)); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + public AjaxResult getRuleItemProperties() { | ||
| 49 | + return AjaxResult.success(alertRuleService.getRuleItemProperties()); | ||
| 50 | + } | ||
| 51 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/AlertTemplateController.java+96-0
| @@ -0,0 +1,96 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.admin.common.core.page.TableDataInfo; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateRuleDto; | ||
| 12 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 13 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 14 | +import org.opengauss.plugin.alertcenter.model.AlertTemplateReq; | ||
| 15 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleService; | ||
| 16 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateService; | ||
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 18 | +import org.springframework.web.bind.annotation.DeleteMapping; | ||
| 19 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 20 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 21 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 22 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 23 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 24 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 25 | +import org.springframework.web.bind.annotation.RestController; | ||
| 26 | + | ||
| 27 | +import javax.validation.Valid; | ||
| 28 | +import java.util.List; | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * wuyuebin | ||
| 32 | + * 2023/4/14 17:03 | ||
| 33 | + * 告警模板相关 | ||
| 34 | + */ | ||
| 35 | + | ||
| 36 | + | ||
| 37 | +public class AlertTemplateController extends BaseController { | ||
| 38 | + | ||
| 39 | + private AlertTemplateService templateService; | ||
| 40 | + | ||
| 41 | + private AlertTemplateRuleService templateRuleService; | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + public TableDataInfo getTemplatePage(String templateName) { | ||
| 45 | + Page<AlertTemplate> page = templateService.getTemplatePage(templateName, startPage()); | ||
| 46 | + return getDataTable(page); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + public AjaxResult getTemplateList() { | ||
| 51 | + List<AlertTemplate> list = templateService.getTemplateList(); | ||
| 52 | + return AjaxResult.success(list); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + public AjaxResult getTemplateDto( Long id) { | ||
| 57 | + AlertTemplateDto templateDto = templateService.getTemplate(id); | ||
| 58 | + return AjaxResult.success(templateDto); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + | ||
| 62 | + public TableDataInfo getTemplateRulePage( Long id, String ruleName) { | ||
| 63 | + Page<AlertTemplateRuleDto> page = templateService.getTemplateRulePage(id, ruleName, startPage()); | ||
| 64 | + return getDataTable(page); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + public AjaxResult getTemplateRuleListById( Long id) { | ||
| 69 | + List<AlertTemplateRuleDto> list = templateService.getTemplateRuleListById(id); | ||
| 70 | + return AjaxResult.success(list); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + public AjaxResult getTemplateRule( Long templateRuleId) { | ||
| 75 | + AlertTemplateRule alertTemplateRule = templateRuleService.getTemplateRule(templateRuleId); | ||
| 76 | + return AjaxResult.success(alertTemplateRule); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + public AjaxResult saveTemplate( AlertTemplateReq templateReq) { | ||
| 81 | + AlertTemplate alertTemplate = templateService.saveTemplate(templateReq); | ||
| 82 | + return AjaxResult.success(alertTemplate); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + | ||
| 86 | + public AjaxResult delTemplate( Long id) { | ||
| 87 | + templateService.delTemplate(id); | ||
| 88 | + return AjaxResult.success(); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + | ||
| 92 | + public AjaxResult saveTemplateRule( AlertTemplateRule alertTemplateRule) { | ||
| 93 | + AlertTemplateRuleDto templateRuleDto = templateRuleService.saveTemplateRule(alertTemplateRule); | ||
| 94 | + return AjaxResult.success(templateRuleDto); | ||
| 95 | + } | ||
| 96 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/BaseController.java+41-0
| @@ -0,0 +1,41 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.metadata.IPage; | ||
| 8 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 9 | +import org.opengauss.admin.common.core.page.TableDataInfo; | ||
| 10 | +import org.opengauss.admin.common.enums.ResponseCode; | ||
| 11 | +import org.opengauss.admin.common.utils.ServletUtils; | ||
| 12 | +import org.opengauss.admin.common.utils.StringUtils; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * wuyuebin | ||
| 16 | + * 2023/5/29 09:14 | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | +public class BaseController { | ||
| 20 | + protected Page startPage() { | ||
| 21 | + Page page = new Page(); | ||
| 22 | + Integer pageNum = ServletUtils.getParameterToInt("pageNum"); | ||
| 23 | + Integer pageSize = ServletUtils.getParameterToInt("pageSize"); | ||
| 24 | + if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) { | ||
| 25 | + page.setCurrent((long) pageNum); | ||
| 26 | + page.setSize((long) pageSize); | ||
| 27 | + page.setOptimizeCountSql(false); | ||
| 28 | + page.setMaxLimit(500L); | ||
| 29 | + } | ||
| 30 | + return page; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + protected TableDataInfo getDataTable(IPage<?> page) { | ||
| 34 | + TableDataInfo rspData = new TableDataInfo(); | ||
| 35 | + rspData.setCode(ResponseCode.SUCCESS.code()); | ||
| 36 | + rspData.setMsg(ResponseCode.SUCCESS.msg()); | ||
| 37 | + rspData.setRows(page.getRecords()); | ||
| 38 | + rspData.setTotal(page.getTotal()); | ||
| 39 | + return rspData; | ||
| 40 | + } | ||
| 41 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/EnvironmentController.java+49-0
| @@ -0,0 +1,49 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 8 | +import org.opengauss.plugin.alertcenter.service.EnvironmentService; | ||
| 9 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 10 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 11 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 12 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 13 | +import org.springframework.web.bind.annotation.RestController; | ||
| 14 | +import java.util.List; | ||
| 15 | +import java.util.Map; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * wuyuebin | ||
| 19 | + * 2023/5/29 17:36 | ||
| 20 | + * | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +public class EnvironmentController { | ||
| 25 | + | ||
| 26 | + private EnvironmentService environmentService; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + public AjaxResult cluster() { | ||
| 30 | + List cluster = environmentService.cluster(); | ||
| 31 | + return AjaxResult.success(cluster); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + public AjaxResult checkPrometheus() { | ||
| 36 | + environmentService.checkPrometheus(); | ||
| 37 | + return AjaxResult.success(); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * type 分 alert和 notify,alert表示查询告警内容常驻参数,notify表示通知内容的常驻参数 | ||
| 42 | + * 返回常驻参数 | ||
| 43 | + */ | ||
| 44 | + | ||
| 45 | + public AjaxResult getAlertContentParam( String type) { | ||
| 46 | + Map<String, Map<String, String>> map = environmentService.getAlertContentParam(type); | ||
| 47 | + return AjaxResult.success(map); | ||
| 48 | + } | ||
| 49 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/NotifyConfigController.java+48-0
| @@ -0,0 +1,48 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.NotifyConfig; | ||
| 9 | +import org.opengauss.plugin.alertcenter.model.NotifyConfigReq; | ||
| 10 | +import org.opengauss.plugin.alertcenter.service.NotifyConfigService; | ||
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 12 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 13 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 14 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 15 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 16 | +import org.springframework.web.bind.annotation.RestController; | ||
| 17 | + | ||
| 18 | +import java.util.List; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * wuyuebin | ||
| 22 | + * 2023/6/1 01:48 | ||
| 23 | + * | ||
| 24 | + */ | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +public class NotifyConfigController { | ||
| 28 | + | ||
| 29 | + private NotifyConfigService notifyConfigService; | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + public AjaxResult getAllList() { | ||
| 33 | + List<NotifyConfig> list = notifyConfigService.getAllList(); | ||
| 34 | + return AjaxResult.success(list); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + public AjaxResult saveList( List<NotifyConfig> list) { | ||
| 39 | + notifyConfigService.saveList(list); | ||
| 40 | + return AjaxResult.success(); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + public AjaxResult testConfig( NotifyConfigReq notifyConfigReq) { | ||
| 45 | + notifyConfigService.testConfig(notifyConfigReq); | ||
| 46 | + return AjaxResult.success(); | ||
| 47 | + } | ||
| 48 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/NotifyTemplateController.java+63-0
| @@ -0,0 +1,63 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.admin.common.core.page.TableDataInfo; | ||
| 10 | +import org.opengauss.plugin.alertcenter.entity.NotifyTemplate; | ||
| 11 | +import org.opengauss.plugin.alertcenter.service.NotifyTemplateService; | ||
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 13 | +import org.springframework.validation.annotation.Validated; | ||
| 14 | +import org.springframework.web.bind.annotation.DeleteMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 16 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 17 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 18 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 19 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 20 | +import org.springframework.web.bind.annotation.RestController; | ||
| 21 | +import java.util.List; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * wuyuebin | ||
| 25 | + * 2023/5/31 10:20 | ||
| 26 | + * | ||
| 27 | + */ | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +public class NotifyTemplateController extends BaseController { | ||
| 31 | + | ||
| 32 | + private NotifyTemplateService notifyTemplateService; | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + public TableDataInfo getListPage(String notifyTemplateName, String notifyTemplateType) { | ||
| 36 | + Page page = notifyTemplateService.getListPage(notifyTemplateName, notifyTemplateType, startPage()); | ||
| 37 | + return getDataTable(page); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + public AjaxResult getList(String notifyTemplateType) { | ||
| 42 | + List<NotifyTemplate> list = notifyTemplateService.getList(notifyTemplateType); | ||
| 43 | + return AjaxResult.success(list); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + public AjaxResult getById( Long id) { | ||
| 48 | + NotifyTemplate notifyTemplate = notifyTemplateService.getById(id); | ||
| 49 | + return AjaxResult.success(notifyTemplate); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + | ||
| 53 | + public AjaxResult saveTemplate( NotifyTemplate notifyTemplate) { | ||
| 54 | + notifyTemplateService.saveTemplate(notifyTemplate); | ||
| 55 | + return AjaxResult.success(); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + public AjaxResult delById( Long id) { | ||
| 60 | + notifyTemplateService.delById(id); | ||
| 61 | + return AjaxResult.success(); | ||
| 62 | + } | ||
| 63 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/controller/NotifyWayController.java+64-0
| @@ -0,0 +1,64 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.controller; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import org.opengauss.admin.common.core.domain.AjaxResult; | ||
| 9 | +import org.opengauss.admin.common.core.page.TableDataInfo; | ||
| 10 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 11 | +import org.opengauss.plugin.alertcenter.service.NotifyWayService; | ||
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 13 | +import org.springframework.web.bind.annotation.DeleteMapping; | ||
| 14 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 16 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 17 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 18 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 19 | +import org.springframework.web.bind.annotation.RestController; | ||
| 20 | + | ||
| 21 | +import javax.validation.Valid; | ||
| 22 | +import java.util.List; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * wuyuebin | ||
| 26 | + * 2023/5/25 15:49 | ||
| 27 | + * | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +public class NotifyWayController extends BaseController { | ||
| 32 | + | ||
| 33 | + private NotifyWayService notifyWayService; | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + public TableDataInfo getListPage(String name, String notifyType) { | ||
| 37 | + Page page = notifyWayService.getListPage(name, notifyType, startPage()); | ||
| 38 | + return getDataTable(page); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + public AjaxResult getList(String notifyType) { | ||
| 43 | + List<NotifyWay> notifyWayList = notifyWayService.getList(notifyType); | ||
| 44 | + return AjaxResult.success(notifyWayList); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + public AjaxResult getById( Long id) { | ||
| 49 | + NotifyWay notifyWay = notifyWayService.getById(id); | ||
| 50 | + return AjaxResult.success(notifyWay); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + public AjaxResult saveNotifyWay( NotifyWay notifyWay) { | ||
| 55 | + notifyWayService.saveNotifyWay(notifyWay); | ||
| 56 | + return AjaxResult.success(); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + public AjaxResult delById( Long id) { | ||
| 61 | + notifyWayService.delById(id); | ||
| 62 | + return AjaxResult.success(); | ||
| 63 | + } | ||
| 64 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/AlertClusterNodeConfDto.java+25-0
| @@ -0,0 +1,25 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 8 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 9 | +import lombok.Data; | ||
| 10 | +import lombok.experimental.Accessors; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * wuyuebin | ||
| 14 | + * 2023/5/22 10:36 | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +public class AlertClusterNodeConfDto { | ||
| 20 | + private String clusterNodeId; // 实例ID | ||
| 21 | + private String nodeName; | ||
| 22 | + | ||
| 23 | + private Long templateId; | ||
| 24 | + private String templateName; | ||
| 25 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/AlertContentParamDto.java+53-0
| @@ -0,0 +1,53 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.config.annotation.AlertContentParam; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/2 23:39 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class AlertContentParamDto { | ||
| 19 | + | ||
| 20 | + preVal = "test/127.0.0.1:5432(MASTER)", | ||
| 21 | + group = {"alert", "notify"}) | ||
| 22 | + private String nodeName; | ||
| 23 | + | ||
| 24 | + preVal = "centos", | ||
| 25 | + group = {"alert", "notify"}) | ||
| 26 | + private String hostname; | ||
| 27 | + | ||
| 28 | + preVal = "127.0.0.1", | ||
| 29 | + group = {"alert", "notify"}) | ||
| 30 | + private String hostIp; | ||
| 31 | + | ||
| 32 | + preVal = "5432", | ||
| 33 | + group = {"alert", "notify"}) | ||
| 34 | + private String port; | ||
| 35 | + | ||
| 36 | + preVal = "2023-01-01 00:00:00", | ||
| 37 | + group = {"alert", "notify"}) | ||
| 38 | + private String alertTime; | ||
| 39 | + | ||
| 40 | + preVal = "alerting", | ||
| 41 | + isI18nPreVal = true, | ||
| 42 | + group = {"alert", "notify"}) | ||
| 43 | + private String alertStatus; | ||
| 44 | + | ||
| 45 | + preVal = "serious", | ||
| 46 | + isI18nPreVal = true, | ||
| 47 | + group = {"alert", "notify"}) | ||
| 48 | + private String level; | ||
| 49 | + | ||
| 50 | + preVal = "The CPU usage rate is over 90%.", | ||
| 51 | + group = {"notify"}) | ||
| 52 | + private String content; | ||
| 53 | +} | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertRecord; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/17 10:44 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class AlertRecordDto extends AlertRecord { | ||
| 19 | + private String clusterNodeName; | ||
| 20 | + private String clusterId; | ||
| 21 | + private String nodeRole; | ||
| 22 | + private String hostIpAndPort; | ||
| 23 | +} | ||
| @@ -0,0 +1,45 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 8 | +import lombok.Data; | ||
| 9 | +import lombok.experimental.Accessors; | ||
| 10 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 11 | + | ||
| 12 | +import java.time.LocalDateTime; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * wuyuebin | ||
| 16 | + * 2023/5/18 19:06 | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +public class AlertRelationDto { | ||
| 22 | + private String name; | ||
| 23 | + | ||
| 24 | + private Number[][] datas; | ||
| 25 | + | ||
| 26 | + private String limitValue; | ||
| 27 | + | ||
| 28 | + private String unit; | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + private LocalDateTime startTime; | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + private LocalDateTime endTime; | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + private LocalDateTime minTime; | ||
| 41 | + | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + private LocalDateTime maxTime; | ||
| 45 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/AlertRuleConfigDto.java+53-0
| @@ -0,0 +1,53 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 8 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 9 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 10 | +import lombok.Data; | ||
| 11 | + | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * wuyuebin | ||
| 16 | + * 2023/4/28 01:28 | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | +public class AlertRuleConfigDto { | ||
| 21 | + private List<Group> groups; | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + public static class Group { | ||
| 25 | + private String name; | ||
| 26 | + private List<Rule> rules; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + public static class Rule { | ||
| 30 | + private String alert; | ||
| 31 | + private String expr; | ||
| 32 | + | ||
| 33 | + private String aliasFor; | ||
| 34 | + private Labels labels; | ||
| 35 | + private Annotations annotations; | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + public static class Labels { | ||
| 39 | + private String level; | ||
| 40 | + | ||
| 41 | + private Long templateId; | ||
| 42 | + | ||
| 43 | + private Long templateRuleId; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + public static class Annotations { | ||
| 48 | + private String summary; | ||
| 49 | + private String description; | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | +} | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertRule; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/15 17:37 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class AlertRuleDto extends AlertRule { | ||
| 19 | + private String ruleExpDesc; | ||
| 20 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/AlertStatisticsDto.java+26-0
| @@ -0,0 +1,26 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * wuyuebin | ||
| 12 | + * 2023/4/14 14:50 | ||
| 13 | + * | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +public class AlertStatisticsDto { | ||
| 18 | + private Integer totalNum = 0; | ||
| 19 | + private Integer unReadNum = 0; | ||
| 20 | + private Integer readNum = 0; | ||
| 21 | + private Integer firingNum = 0; | ||
| 22 | + private Integer recoverNum = 0; | ||
| 23 | + private Integer seriousNum = 0; | ||
| 24 | + private Integer warnNum = 0; | ||
| 25 | + private Integer infoNum = 0; | ||
| 26 | +} | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/5/15 18:48 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +public class AlertTemplateDto extends AlertTemplate { | ||
| 21 | + List<AlertTemplateRuleDto> templateRuleDtoList; | ||
| 22 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/AlertTemplateRuleDto.java+43-0
| @@ -0,0 +1,43 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import cn.hutool.core.util.StrUtil; | ||
| 9 | +import lombok.Data; | ||
| 10 | +import lombok.experimental.Accessors; | ||
| 11 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 12 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 13 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 14 | + | ||
| 15 | +import java.util.List; | ||
| 16 | +import java.util.stream.Collectors; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * wuyuebin | ||
| 20 | + * 2023/5/13 16:18 | ||
| 21 | + * | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class AlertTemplateRuleDto extends AlertTemplateRule { | ||
| 26 | + private String ruleExpDesc; | ||
| 27 | + | ||
| 28 | + public void buildRuleExpDesc() { | ||
| 29 | + this.ruleExpDesc = this.getAlertRuleItemList().stream().map(item -> { | ||
| 30 | + List<String> paramVals = | ||
| 31 | + item.getItemParamList().stream().filter(item0 -> item0.getItemId().equals(item.getId())).map( | ||
| 32 | + item0 -> item0.getParamValue()).collect(Collectors.toList()); | ||
| 33 | + return "[" + item.getRuleMark() + "]:" + MessageSourceUtil.get(item.getRuleExpName()) | ||
| 34 | + + (CollectionUtil.isNotEmpty(paramVals) | ||
| 35 | + ? "(" + paramVals.stream().collect(Collectors.joining(CommonConstants.DELIMITER)) + ")" : "") + " " | ||
| 36 | + + (item.getAction().equals("normal") | ||
| 37 | + ? MessageSourceUtil.get("rule.ruleItem.normalAction") + " " + item.getOperate() + item.getLimitValue() | ||
| 38 | + + (StrUtil.isNotBlank(item.getUnit()) ? item.getUnit() : "") : item.getAction().equals( | ||
| 39 | + "increase") ? MessageSourceUtil.get("rule.ruleItem.increaseAction") : MessageSourceUtil.get( | ||
| 40 | + "rule.ruleItem.decreaseAction")); | ||
| 41 | + }).collect(Collectors.joining("<br/>")); | ||
| 42 | + } | ||
| 43 | +} | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/6/1 00:55 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class NotifyWayDto extends NotifyWay { | ||
| 19 | + private String notifyTemplateName; | ||
| 20 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/PrometheusConfigDto.java+116-0
| @@ -0,0 +1,116 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/4/27 17:21 | ||
| 16 | + * alerting: | ||
| 17 | + * alertmanagers: | ||
| 18 | + * - static_configs: | ||
| 19 | + * - targets: | ||
| 20 | + * - alertmanager: 9093 | ||
| 21 | + * global: | ||
| 22 | + * evaluation_interval: 15s | ||
| 23 | + * scrape_interval: 15s | ||
| 24 | + * rule_files: null | ||
| 25 | + * scrape_configs: | ||
| 26 | + * - job_name: prometheus | ||
| 27 | + * static_configs: | ||
| 28 | + * - targets: | ||
| 29 | + * - localhost:9090 | ||
| 30 | + */ | ||
| 31 | + | ||
| 32 | +public class PrometheusConfigDto { | ||
| 33 | + private Global global; | ||
| 34 | + private Alert alerting; | ||
| 35 | + | ||
| 36 | + private List<String> ruleFiles; | ||
| 37 | + | ||
| 38 | + private List<Job> scrapeConfigs; | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + public static class Global { | ||
| 42 | + | ||
| 43 | + private String scrapeInterval; | ||
| 44 | + | ||
| 45 | + private String evaluationInterval; | ||
| 46 | + | ||
| 47 | + private String scrapeTimeout; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + public static class Alert { | ||
| 52 | + private List<Alertmanager> alertmanagers; | ||
| 53 | + | ||
| 54 | + | ||
| 55 | + public static class Alertmanager { | ||
| 56 | + | ||
| 57 | + private String apiVersion; | ||
| 58 | + | ||
| 59 | + private String pathPrefix; | ||
| 60 | + private String scheme = "http"; | ||
| 61 | + | ||
| 62 | + private List<Conf> staticConfigs; | ||
| 63 | + | ||
| 64 | + private Boolean isFollowRedirects; | ||
| 65 | + | ||
| 66 | + private Boolean isEnableHttp2; | ||
| 67 | + private String timeout; | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + public static class Conf { | ||
| 71 | + private List<String> targets; | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + public static class Job { | ||
| 78 | + | ||
| 79 | + private String jobName; | ||
| 80 | + | ||
| 81 | + private List<Conf> staticConfigs; | ||
| 82 | + | ||
| 83 | + private Boolean isHonorTimestamps; | ||
| 84 | + | ||
| 85 | + private String scrapeInterval; | ||
| 86 | + | ||
| 87 | + private String scrapeTimeout; | ||
| 88 | + | ||
| 89 | + private String metricsPath; | ||
| 90 | + private String scheme; | ||
| 91 | + | ||
| 92 | + private Boolean isFollowRedirects; | ||
| 93 | + | ||
| 94 | + private Boolean isEnableHttp2; | ||
| 95 | + | ||
| 96 | + | ||
| 97 | + public static class Conf { | ||
| 98 | + private List<String> targets; | ||
| 99 | + private Map<String, String> labels; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + | ||
| 103 | + public int hashCode() { | ||
| 104 | + return jobName.hashCode(); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + | ||
| 108 | + public boolean equals(Object obj) { | ||
| 109 | + if (!(obj instanceof Job)) { | ||
| 110 | + return false; | ||
| 111 | + } | ||
| 112 | + Job job = (Job) obj; | ||
| 113 | + return job.getJobName().equals(this.jobName); | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | +} | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertConfig; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/6/10 11:08 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +public class PrometheusEnvDto { | ||
| 21 | + private String promIp; | ||
| 22 | + private Integer hostPort; | ||
| 23 | + private Integer promPort; | ||
| 24 | + private String promUsername; | ||
| 25 | + private String promPasswd; | ||
| 26 | + private String path; | ||
| 27 | + private List<AlertConfig> configList; | ||
| 28 | + private List<AlertConfig> delConfigList; | ||
| 29 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/dto/RuleItemPropertyDto.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.dto; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import org.opengauss.plugin.alertcenter.config.properties.RuleItemProperty; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * wuyuebin | ||
| 12 | + * 2023/5/29 11:07 | ||
| 13 | + * | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +public class RuleItemPropertyDto extends RuleItemProperty { | ||
| 17 | + private String i18nName; | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/entity/AlertClusterNodeConf.java+34-0
| @@ -0,0 +1,34 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 10 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 11 | +import lombok.Data; | ||
| 12 | +import lombok.experimental.Accessors; | ||
| 13 | + | ||
| 14 | +import java.sql.Timestamp; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * wuyuebin | ||
| 18 | + * 2023/4/26 16:11 | ||
| 19 | + * 实例告警配置类 | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +public class AlertClusterNodeConf { | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + private Long id; | ||
| 28 | + private String clusterNodeId; | ||
| 29 | + | ||
| 30 | + private Long templateId; | ||
| 31 | + private Timestamp updateTime; | ||
| 32 | + private Timestamp createTime; | ||
| 33 | + private Integer isDeleted; | ||
| 34 | +} | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 8 | +import lombok.Data; | ||
| 9 | +import lombok.experimental.Accessors; | ||
| 10 | + | ||
| 11 | +import javax.validation.constraints.NotBlank; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/6/6 16:13 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +public class AlertConfig { | ||
| 22 | + private Long id; | ||
| 23 | + | ||
| 24 | + private String alertIp; | ||
| 25 | + | ||
| 26 | + private String alertPort; | ||
| 27 | +} | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 11 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 12 | +import lombok.Data; | ||
| 13 | +import lombok.experimental.Accessors; | ||
| 14 | + | ||
| 15 | +import java.time.LocalDateTime; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * wuyuebin | ||
| 19 | + * 2023/4/14 10:52 | ||
| 20 | + * | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class AlertRecord { | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + private Long id; | ||
| 29 | + private String clusterNodeId; | ||
| 30 | + | ||
| 31 | + private Long templateId; | ||
| 32 | + private String templateName; | ||
| 33 | + | ||
| 34 | + private Long templateRuleId; | ||
| 35 | + private String templateRuleName; | ||
| 36 | + private String templateRuleType; | ||
| 37 | + private String level; | ||
| 38 | + private String notifyWayIds; | ||
| 39 | + private String notifyWayNames; | ||
| 40 | + private Integer alertStatus; | ||
| 41 | + | ||
| 42 | + private LocalDateTime startTime; | ||
| 43 | + | ||
| 44 | + private LocalDateTime endTime; | ||
| 45 | + private Long duration; | ||
| 46 | + private String alertContent; | ||
| 47 | + private Integer recordStatus; | ||
| 48 | + | ||
| 49 | + private LocalDateTime createTime; | ||
| 50 | + | ||
| 51 | + private LocalDateTime updateTime; | ||
| 52 | + private Integer isDeleted; | ||
| 53 | +} | ||
| @@ -0,0 +1,58 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 10 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 11 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 12 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 13 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 14 | +import lombok.Data; | ||
| 15 | +import lombok.experimental.Accessors; | ||
| 16 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 17 | + | ||
| 18 | +import java.sql.Timestamp; | ||
| 19 | +import java.time.LocalDateTime; | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * wuyuebin | ||
| 24 | + * 2023/5/9 10:04 | ||
| 25 | + * | ||
| 26 | + */ | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +public class AlertRule { | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + private Long id; | ||
| 35 | + private String alertDesc; | ||
| 36 | + private String notifyWayIds; | ||
| 37 | + private String alertNotify; | ||
| 38 | + private Timestamp silenceEndTime; | ||
| 39 | + private Timestamp silenceStartTime; | ||
| 40 | + private Integer isSilence; | ||
| 41 | + private Integer isRepeat; | ||
| 42 | + private String notifyDurationUnit; | ||
| 43 | + private Integer notifyDuration; | ||
| 44 | + private String ruleContent; | ||
| 45 | + private String ruleExpComb; | ||
| 46 | + private String ruleType; | ||
| 47 | + private String level; | ||
| 48 | + private String ruleName; | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + private LocalDateTime updateTime; | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + private LocalDateTime createTime; | ||
| 55 | + private Integer isDeleted; | ||
| 56 | + | ||
| 57 | + private List<AlertRuleItem> alertRuleItemList; | ||
| 58 | +} | ||
| @@ -0,0 +1,54 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 10 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 11 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 12 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 13 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 14 | +import lombok.Data; | ||
| 15 | +import lombok.experimental.Accessors; | ||
| 16 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 17 | + | ||
| 18 | +import java.time.LocalDateTime; | ||
| 19 | +import java.util.List; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * wuyuebin | ||
| 23 | + * 2023/5/9 11:19 | ||
| 24 | + * | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +public class AlertRuleItem { | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + private Long id; | ||
| 34 | + | ||
| 35 | + private Long ruleId; | ||
| 36 | + private String ruleMark; | ||
| 37 | + private String ruleExpName; | ||
| 38 | + private String action; | ||
| 39 | + private String operate; | ||
| 40 | + private String limitValue; | ||
| 41 | + private String unit; | ||
| 42 | + private String ruleExp; | ||
| 43 | + private String ruleExpParam; | ||
| 44 | + private String ruleItemDesc; | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + private LocalDateTime updateTime; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + private LocalDateTime createTime; | ||
| 51 | + private Integer isDeleted; | ||
| 52 | + | ||
| 53 | + private List<AlertRuleItemParam> itemParamList; | ||
| 54 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/entity/AlertRuleItemParam.java+44-0
| @@ -0,0 +1,44 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 11 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 12 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 13 | +import lombok.Data; | ||
| 14 | +import lombok.experimental.Accessors; | ||
| 15 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 16 | + | ||
| 17 | +import java.time.LocalDateTime; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * wuyuebin | ||
| 21 | + * 2023/5/29 01:27 | ||
| 22 | + * | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +public class AlertRuleItemParam { | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + private Long id; | ||
| 32 | + | ||
| 33 | + private Long itemId; | ||
| 34 | + private String paramName; | ||
| 35 | + private String paramValue; | ||
| 36 | + private String paramOrder; | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + private LocalDateTime updateTime; | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + private LocalDateTime createTime; | ||
| 43 | + private Integer isDeleted; | ||
| 44 | +} | ||
| @@ -0,0 +1,38 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 11 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 12 | +import lombok.Data; | ||
| 13 | +import lombok.experimental.Accessors; | ||
| 14 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 15 | + | ||
| 16 | +import java.time.LocalDateTime; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * wuyuebin | ||
| 20 | + * 2023/4/28 02:25 | ||
| 21 | + * | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +public class AlertTemplate { | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + private Long id; | ||
| 30 | + private String templateName; | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + private LocalDateTime updateTime; | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + private LocalDateTime createTime; | ||
| 37 | + private Integer isDeleted; | ||
| 38 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/entity/AlertTemplateRule.java+83-0
| @@ -0,0 +1,83 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 10 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 11 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 12 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 13 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 14 | +import lombok.Data; | ||
| 15 | +import lombok.experimental.Accessors; | ||
| 16 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 17 | + | ||
| 18 | +import javax.validation.Valid; | ||
| 19 | +import javax.validation.constraints.NotBlank; | ||
| 20 | +import javax.validation.constraints.NotNull; | ||
| 21 | +import javax.validation.constraints.Size; | ||
| 22 | +import java.time.LocalDateTime; | ||
| 23 | +import java.util.List; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * wuyuebin | ||
| 27 | + * 2023/4/28 02:29 | ||
| 28 | + * | ||
| 29 | + */ | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +public class AlertTemplateRule { | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + private Long id; | ||
| 38 | + | ||
| 39 | + private Long templateId; | ||
| 40 | + private String alertDesc; | ||
| 41 | + | ||
| 42 | + private String notifyWayIds; | ||
| 43 | + | ||
| 44 | + private String alertNotify; | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + private LocalDateTime silenceEndTime; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + private LocalDateTime silenceStartTime; | ||
| 51 | + | ||
| 52 | + private Integer isSilence; | ||
| 53 | + | ||
| 54 | + private Integer isRepeat; | ||
| 55 | + | ||
| 56 | + private String notifyDurationUnit; | ||
| 57 | + | ||
| 58 | + private Integer notifyDuration; | ||
| 59 | + | ||
| 60 | + private String ruleContent; | ||
| 61 | + | ||
| 62 | + private String ruleExpComb; | ||
| 63 | + | ||
| 64 | + private String ruleType; | ||
| 65 | + | ||
| 66 | + private String level; | ||
| 67 | + | ||
| 68 | + private String ruleName; | ||
| 69 | + | ||
| 70 | + private Long ruleId; | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + private LocalDateTime updateTime; | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + private LocalDateTime createTime; | ||
| 77 | + private Integer isDeleted; | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + | ||
| 82 | + private List<AlertTemplateRuleItem> alertRuleItemList; | ||
| 83 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/entity/AlertTemplateRuleItem.java+62-0
| @@ -0,0 +1,62 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 10 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 11 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 12 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 13 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 14 | +import lombok.Data; | ||
| 15 | +import lombok.experimental.Accessors; | ||
| 16 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 17 | + | ||
| 18 | +import javax.validation.constraints.NotBlank; | ||
| 19 | +import java.time.LocalDateTime; | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * wuyuebin | ||
| 24 | + * 2023/4/28 02:36 | ||
| 25 | + * | ||
| 26 | + */ | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +public class AlertTemplateRuleItem { | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + private Long id; | ||
| 35 | + | ||
| 36 | + private Long templateRuleId; | ||
| 37 | + | ||
| 38 | + private Long ruleItemId; | ||
| 39 | + | ||
| 40 | + private String ruleMark; | ||
| 41 | + | ||
| 42 | + private String ruleExpName; | ||
| 43 | + | ||
| 44 | + private String action; | ||
| 45 | + | ||
| 46 | + private String operate; | ||
| 47 | + | ||
| 48 | + private String limitValue; | ||
| 49 | + private String unit; | ||
| 50 | + private String ruleExp; | ||
| 51 | + private String ruleExpParam; | ||
| 52 | + private String ruleItemDesc; | ||
| 53 | + | ||
| 54 | + | ||
| 55 | + private LocalDateTime updateTime; | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + private LocalDateTime createTime; | ||
| 59 | + private Integer isDeleted; | ||
| 60 | + | ||
| 61 | + private List<AlertTemplateRuleItemParam> itemParamList; | ||
| 62 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/entity/AlertTemplateRuleItemParam.java+44-0
| @@ -0,0 +1,44 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 11 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 12 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 13 | +import lombok.Data; | ||
| 14 | +import lombok.experimental.Accessors; | ||
| 15 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 16 | + | ||
| 17 | +import java.time.LocalDateTime; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * wuyuebin | ||
| 21 | + * 2023/5/29 01:27 | ||
| 22 | + * | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +public class AlertTemplateRuleItemParam { | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + private Long id; | ||
| 32 | + | ||
| 33 | + private Long itemId; | ||
| 34 | + private String paramName; | ||
| 35 | + private String paramValue; | ||
| 36 | + private String paramOrder; | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + private LocalDateTime updateTime; | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + private LocalDateTime createTime; | ||
| 43 | + private Integer isDeleted; | ||
| 44 | +} | ||
| @@ -0,0 +1,38 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.IdType; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 10 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 11 | +import lombok.Data; | ||
| 12 | +import lombok.experimental.Accessors; | ||
| 13 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class NctigbaEnv { | ||
| 19 | + | ||
| 20 | + String id; | ||
| 21 | + String hostid; | ||
| 22 | + Type type; | ||
| 23 | + String username; | ||
| 24 | + String path; | ||
| 25 | + Integer port; | ||
| 26 | + String nodeid; | ||
| 27 | + | ||
| 28 | + OpsHostEntity host; | ||
| 29 | + | ||
| 30 | + public enum Type { | ||
| 31 | + PROMETHEUS, NODE_EXPORTER, OPENGAUSS_EXPORTER, | ||
| 32 | + ELASTICSEARCH, FILEBEAT, | ||
| 33 | + AGENT, | ||
| 34 | + PROMETHEUS_PKG, NODE_EXPORTER_PKG, OPENGAUSS_EXPORTER_PKG, | ||
| 35 | + ELASTICSEARCH_PKG, FILEBEAT_PKG, | ||
| 36 | + AGENT_PKG, | ||
| 37 | + } | ||
| 38 | +} | ||
| @@ -0,0 +1,71 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 9 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 10 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 11 | +import lombok.Data; | ||
| 12 | +import lombok.experimental.Accessors; | ||
| 13 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 14 | + | ||
| 15 | +import javax.validation.constraints.NotBlank; | ||
| 16 | +import javax.validation.constraints.NotNull; | ||
| 17 | +import java.time.LocalDateTime; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * wuyuebin | ||
| 21 | + * 2023/5/7 14:01 | ||
| 22 | + * | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +public class NotifyConfig { | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + private Long id; | ||
| 30 | + | ||
| 31 | + private String type; | ||
| 32 | + | ||
| 33 | + private String email; | ||
| 34 | + | ||
| 35 | + private String sender; | ||
| 36 | + | ||
| 37 | + private String sever; | ||
| 38 | + | ||
| 39 | + private Integer port; | ||
| 40 | + | ||
| 41 | + private String account; | ||
| 42 | + | ||
| 43 | + private String passwd; | ||
| 44 | + | ||
| 45 | + private String agentId; | ||
| 46 | + | ||
| 47 | + private String appKey; | ||
| 48 | + | ||
| 49 | + private String secret; | ||
| 50 | + | ||
| 51 | + private Integer enable; | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + private LocalDateTime createTime; | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + private LocalDateTime updateTime; | ||
| 58 | + private Integer isDeleted; | ||
| 59 | + | ||
| 60 | + public interface DefaultGroup { | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public interface EmailGroup { | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + public interface WeComGroup { | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public interface DingTalkGroup { | ||
| 70 | + } | ||
| 71 | +} | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 11 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 12 | +import lombok.Data; | ||
| 13 | +import lombok.experimental.Accessors; | ||
| 14 | + | ||
| 15 | +import java.time.LocalDateTime; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * wuyuebin | ||
| 19 | + * 2023/5/6 14:19 | ||
| 20 | + * | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class NotifyMessage { | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + private Long id; | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + private Long recordId; | ||
| 32 | + | ||
| 33 | + private String messageType; | ||
| 34 | + | ||
| 35 | + private String title; | ||
| 36 | + | ||
| 37 | + private String content; | ||
| 38 | + | ||
| 39 | + private String email; | ||
| 40 | + | ||
| 41 | + private String personId; | ||
| 42 | + | ||
| 43 | + private String deptId; | ||
| 44 | + | ||
| 45 | + private String webhook; | ||
| 46 | + | ||
| 47 | + private Integer status; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + private LocalDateTime createTime; | ||
| 51 | + | ||
| 52 | + private LocalDateTime updateTime; | ||
| 53 | + | ||
| 54 | + private Integer isDeleted; | ||
| 55 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/entity/NotifyTemplate.java+54-0
| @@ -0,0 +1,54 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 11 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 12 | +import lombok.Data; | ||
| 13 | +import lombok.experimental.Accessors; | ||
| 14 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 15 | + | ||
| 16 | +import javax.validation.constraints.NotBlank; | ||
| 17 | +import java.time.LocalDateTime; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * wuyuebin | ||
| 21 | + * 2023/5/6 14:27 | ||
| 22 | + * | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +public class NotifyTemplate { | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + private Long id; | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + private String notifyTemplateName; | ||
| 34 | + | ||
| 35 | + private String notifyTemplateDesc; | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + private String notifyTitle; | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + private String notifyContent; | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + private String notifyTemplateType; | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + private LocalDateTime createTime; | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + private LocalDateTime updateTime; | ||
| 52 | + | ||
| 53 | + private Integer isDeleted = 0; | ||
| 54 | +} | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.entity; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 9 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 10 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 11 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 12 | +import lombok.Data; | ||
| 13 | +import lombok.experimental.Accessors; | ||
| 14 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 15 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 16 | + | ||
| 17 | +import javax.validation.constraints.NotBlank; | ||
| 18 | +import javax.validation.constraints.NotNull; | ||
| 19 | +import java.time.LocalDateTime; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * wuyuebin | ||
| 23 | + * 2023/5/9 11:24 | ||
| 24 | + * | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +public class NotifyWay { | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + private Long id; | ||
| 33 | + | ||
| 34 | + private String name; | ||
| 35 | + | ||
| 36 | + private String notifyType; | ||
| 37 | + private String phone; | ||
| 38 | + private String email; | ||
| 39 | + private String personId; | ||
| 40 | + private String deptId; | ||
| 41 | + | ||
| 42 | + | ||
| 43 | + private Long notifyTemplateId; | ||
| 44 | + | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + private LocalDateTime createTime; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + private LocalDateTime updateTime; | ||
| 51 | + | ||
| 52 | + private Integer isDeleted = CommonConstants.IS_NOT_DELETE; | ||
| 53 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/listener/PluginListener.java+61-0
| @@ -0,0 +1,61 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.listener; | ||
| 6 | + | ||
| 7 | +import com.gitee.starblues.spring.MainApplicationContext; | ||
| 8 | +import com.gitee.starblues.spring.SpringBeanFactory; | ||
| 9 | +import org.opengauss.admin.common.core.vo.MenuVo; | ||
| 10 | +import org.opengauss.admin.system.plugin.facade.MenuFacade; | ||
| 11 | +import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
| 12 | +import org.springframework.context.ApplicationEvent; | ||
| 13 | +import org.springframework.context.ApplicationListener; | ||
| 14 | +import org.springframework.context.event.ContextClosedEvent; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * wuyuebin | ||
| 18 | + * 2023/4/13 09:57 | ||
| 19 | + * | ||
| 20 | + */ | ||
| 21 | +public class PluginListener implements ApplicationListener<ApplicationEvent> { | ||
| 22 | + private final String pluginId = "alert-center"; | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + public void onApplicationEvent(ApplicationEvent event) { | ||
| 26 | + if (event instanceof ApplicationReadyEvent) { | ||
| 27 | + MainApplicationContext context = ((ApplicationReadyEvent) event).getApplicationContext().getBean( | ||
| 28 | + MainApplicationContext.class); | ||
| 29 | + SpringBeanFactory factory = context.getSpringBeanFactory(); | ||
| 30 | + MenuFacade menuFacade = factory.getBean(MenuFacade.class); | ||
| 31 | + if (menuFacade != null) { | ||
| 32 | + MenuVo firstMenu = menuFacade.savePluginMenu(pluginId, "监控告警", "Alert Center", 6, "alert"); | ||
| 33 | + menuFacade.savePluginMenu(pluginId, "告警记录", "Alert Record", 22, "vem/alert/alertRecord", | ||
| 34 | + firstMenu.getMenuId()); | ||
| 35 | + menuFacade.savePluginRoute(pluginId, "告警详细", "Alert Record Detail", "vem/alert/recordDetail", | ||
| 36 | + firstMenu.getMenuId()); | ||
| 37 | + menuFacade.savePluginMenu(pluginId, "告警配置", "Alert Config", 23, "vem/alert/AlertClusterNodeConf", | ||
| 38 | + firstMenu.getMenuId()); | ||
| 39 | + menuFacade.savePluginMenu(pluginId, "告警模板", "Alert Template", 24, "vem/alert/alertTemplate", | ||
| 40 | + firstMenu.getMenuId()); | ||
| 41 | + menuFacade.savePluginMenu(pluginId, "告警规则", "Alert Rule", 25, "vem/alert/alertRule", | ||
| 42 | + firstMenu.getMenuId()); | ||
| 43 | + MenuVo secondMenu = menuFacade.savePluginMenu(pluginId, "通知配置", "Notify Configuration", 7, | ||
| 44 | + "notify"); | ||
| 45 | + menuFacade.savePluginMenu(pluginId, "通知模板", "Notify Template", 26, "vem/notify/notifyTemplate", | ||
| 46 | + secondMenu.getMenuId()); | ||
| 47 | + menuFacade.savePluginMenu(pluginId, "通知方式", "Notify Way", 27, "vem/notify/notifyWay", | ||
| 48 | + secondMenu.getMenuId()); | ||
| 49 | + } | ||
| 50 | + } | ||
| 51 | + if (event instanceof ContextClosedEvent) { | ||
| 52 | + MainApplicationContext context = ((ContextClosedEvent) event).getApplicationContext().getBean( | ||
| 53 | + MainApplicationContext.class); | ||
| 54 | + SpringBeanFactory factory = context.getSpringBeanFactory(); | ||
| 55 | + MenuFacade menuFacade = factory.getBean(MenuFacade.class); | ||
| 56 | + if (menuFacade != null) { | ||
| 57 | + menuFacade.deletePluginMenu(pluginId); | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertClusterNodeConfMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertClusterNodeConf; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/4/26 16:45 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertClusterNodeConfMapper extends BaseMapper<AlertClusterNodeConf> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertConfigMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertConfig; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/6/6 16:14 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertConfigMapper extends BaseMapper<AlertConfig> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertRecordMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertRecord; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/2 10:23 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertRecordMapper extends BaseMapper<AlertRecord> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertRuleItemMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertRuleItem; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/9 11:30 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertRuleItemMapper extends BaseMapper<AlertRuleItem> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertRuleItemParamMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertRuleItemParam; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/6/5 16:49 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertRuleItemParamMapper extends BaseMapper<AlertRuleItemParam> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertRuleMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertRule; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/9 10:07 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertRuleMapper extends BaseMapper<AlertRule> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertTemplateMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/4/28 02:42 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertTemplateMapper extends BaseMapper<AlertTemplate> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertTemplateRuleItemMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/4/28 02:44 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertTemplateRuleItemMapper extends BaseMapper<AlertTemplateRuleItem> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertTemplateRuleItemParamMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItemParam; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/6/5 16:49 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertTemplateRuleItemParamMapper extends BaseMapper<AlertTemplateRuleItemParam> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/AlertTemplateRuleMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/4/28 02:43 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface AlertTemplateRuleMapper extends BaseMapper<AlertTemplateRule> { | ||
| 18 | +} | ||
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/SearchMapper.java→plugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/NctigbaEnvMapper.java+8-14
| @@ -1,19 +1,13 @@ | |||
| 1 | -package com.nctigba.observability.instance.mapper; | 1 | +/* |
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 2 | 6 | ||
| 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 7 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 4 | -import com.nctigba.observability.instance.entity.Searc; | ||
| 5 | - | ||
| 6 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | +import org.opengauss.plugin.alertcenter.entity.NctigbaEnv; | ||
| 7 | 10 | ||
| 8 | -/** | ||
| 9 | - * <p> | ||
| 10 | - * Mapper interface | ||
| 11 | - * </p> | ||
| 12 | - * | ||
| 13 | - * auto | ||
| 14 | - * 2022-09-05 | ||
| 15 | - */ | ||
| 16 | 11 | ||
| 17 | -public interface SearchMapper extends BaseMapper<Searc> { | 12 | +public interface NctigbaEnvMapper extends BaseMapper<NctigbaEnv> { |
| 18 | - | 13 | +} |
| 19 | -} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/NotifyConfigMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.NotifyConfig; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/7 14:06 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface NotifyConfigMapper extends BaseMapper<NotifyConfig> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/NotifyMessageMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.NotifyMessage; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/6 16:08 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface NotifyMessageMapper extends BaseMapper<NotifyMessage> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/NotifyTemplateMapper.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.NotifyTemplate; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/6 15:55 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public interface NotifyTemplateMapper extends BaseMapper<NotifyTemplate> { | ||
| 18 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/mapper/NotifyWayMapper.java+27-0
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.mapper; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 8 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 9 | +import com.baomidou.mybatisplus.core.toolkit.Constants; | ||
| 10 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 11 | +import org.apache.ibatis.annotations.Mapper; | ||
| 12 | +import org.apache.ibatis.annotations.Param; | ||
| 13 | +import org.apache.ibatis.annotations.Select; | ||
| 14 | +import org.opengauss.plugin.alertcenter.dto.NotifyWayDto; | ||
| 15 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * wuyuebin | ||
| 19 | + * 2023/5/9 11:35 | ||
| 20 | + * | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | +public interface NotifyWayMapper extends BaseMapper<NotifyWay> { | ||
| 24 | + | ||
| 25 | + + "on t1.notify_template_id = t2.id ${ew.customSqlSegment}") | ||
| 26 | + Page<NotifyWayDto> selectDtoPage(Page page, QueryWrapper queryWrapper); | ||
| 27 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/AlertClusterNodeAndTemplateReq.java+31-0
| @@ -0,0 +1,31 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | + | ||
| 10 | +import javax.validation.Valid; | ||
| 11 | +import javax.validation.constraints.NotBlank; | ||
| 12 | +import javax.validation.constraints.NotNull; | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * wuyuebin | ||
| 17 | + * 2023/5/23 18:30 | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +public class AlertClusterNodeAndTemplateReq { | ||
| 23 | + | ||
| 24 | + private String clusterNodeIds; | ||
| 25 | + | ||
| 26 | + private String templateName; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + private List<AlertTemplateRuleReq> templateRuleReqList; | ||
| 31 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/AlertClusterNodeConfReq.java+23-0
| @@ -0,0 +1,23 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +import javax.validation.constraints.NotBlank; | ||
| 10 | +import javax.validation.constraints.NotNull; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * wuyuebin | ||
| 14 | + * 2023/4/26 16:40 | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +public class AlertClusterNodeConfReq { | ||
| 19 | + | ||
| 20 | + private String clusterNodeIds; // 实例nodeId,多个,逗号分隔 | ||
| 21 | + | ||
| 22 | + private Long templateId; // 告警模板ID | ||
| 23 | +} | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * wuyuebin | ||
| 11 | + * 2023/4/14 14:55 | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +public class AlertRecordReq { | ||
| 16 | + private String clusterNodeId; | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 平台处理get请求时,无法将string(yyyy-MM-dd HH:mm:ss)参数转化为日期 | ||
| 20 | + */ | ||
| 21 | + private String startTime; // yyyy-MM-dd HH:mm:ss | ||
| 22 | + | ||
| 23 | + private String endTime; // yyyy-MM-dd HH:mm:ss | ||
| 24 | + private String recordStatus; // 多个,逗号分隔 | ||
| 25 | + private String alertStatus; // 多个,逗号分隔 | ||
| 26 | + private String alertLevel; // 多个,逗号分隔 | ||
| 27 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/AlertStatisticsReq.java+24-0
| @@ -0,0 +1,24 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * wuyuebin | ||
| 11 | + * 2023/4/14 14:56 | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +public class AlertStatisticsReq { | ||
| 16 | + private String clusterNodeId; | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 平台处理get请求时,无法将string(yyyy-MM-dd HH:mm:ss)参数转化为日期 | ||
| 20 | + */ | ||
| 21 | + private String startTime; // yyyy-MM-dd HH:mm:ss | ||
| 22 | + | ||
| 23 | + private String endTime; // yyyy-MM-dd HH:mm:ss | ||
| 24 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/AlertTemplateReq.java+30-0
| @@ -0,0 +1,30 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +import javax.validation.Valid; | ||
| 10 | +import javax.validation.constraints.NotBlank; | ||
| 11 | +import javax.validation.constraints.NotNull; | ||
| 12 | +import javax.validation.constraints.Size; | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * wuyuebin | ||
| 17 | + * 2023/5/17 00:07 | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | +public class AlertTemplateReq { | ||
| 22 | + private Long id; | ||
| 23 | + | ||
| 24 | + private String templateName; | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + private List<AlertTemplateRuleReq> templateRuleReqList; | ||
| 30 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/AlertTemplateRuleReq.java+21-0
| @@ -0,0 +1,21 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +import javax.validation.constraints.NotNull; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/5/17 00:10 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public class AlertTemplateRuleReq { | ||
| 18 | + private Long templateRuleId; | ||
| 19 | + | ||
| 20 | + private Long ruleId; | ||
| 21 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/NotifyConfigReq.java+20-0
| @@ -0,0 +1,20 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.NotifyConfig; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/6/2 03:09 | ||
| 14 | + * | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class NotifyConfigReq extends NotifyConfig { | ||
| 19 | + private Long notifyWayId; | ||
| 20 | +} | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.AllArgsConstructor; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +public class ResInfo { | ||
| 13 | + private int exitStatus; | ||
| 14 | + private String outRes; | ||
| 15 | + private String errRes; | ||
| 16 | + | ||
| 17 | + public ResInfo() { | ||
| 18 | + this.exitStatus = -2147483648; | ||
| 19 | + } | ||
| 20 | +} | ||
| @@ -0,0 +1,19 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model; | ||
| 6 | + | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * wuyuebin | ||
| 11 | + * 2023/5/9 09:58 | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +public class RuleReq { | ||
| 16 | + private String ruleName; | ||
| 17 | + private String ruleType; | ||
| 18 | + private String level; | ||
| 19 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/api/AlertApiReq.java+29-0
| @@ -0,0 +1,29 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model.api; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/4/30 01:56 | ||
| 16 | + * prometheus推送的告警信息 | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | +public class AlertApiReq { | ||
| 20 | + private AlertLabels labels; | ||
| 21 | + | ||
| 22 | + private LocalDateTime startsAt; | ||
| 23 | + | ||
| 24 | + private LocalDateTime endsAt; | ||
| 25 | + | ||
| 26 | + private Map annotations; | ||
| 27 | + | ||
| 28 | + private String generatorURL; | ||
| 29 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/model/api/AlertLabels.java+25-0
| @@ -0,0 +1,25 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.model.api; | ||
| 6 | + | ||
| 7 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 8 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 9 | +import lombok.Data; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * wuyuebin | ||
| 13 | + * 2023/4/30 01:59 | ||
| 14 | + * prometheus推送的告警信息额外信息 | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +public class AlertLabels { | ||
| 18 | + private String alertname; | ||
| 19 | + private String instance; // 对应cluster_node_id | ||
| 20 | + private String level; | ||
| 21 | + | ||
| 22 | + private Long templateId; | ||
| 23 | + | ||
| 24 | + private Long templateRuleId; | ||
| 25 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/schedule/AlertSchedule.java+51-0
| @@ -0,0 +1,51 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.schedule; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 9 | +import lombok.extern.slf4j.Slf4j; | ||
| 10 | +import org.opengauss.plugin.alertcenter.entity.NotifyMessage; | ||
| 11 | +import org.opengauss.plugin.alertcenter.mapper.NotifyMessageMapper; | ||
| 12 | +import org.opengauss.plugin.alertcenter.service.EmailService; | ||
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 14 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 15 | +import org.springframework.stereotype.Component; | ||
| 16 | + | ||
| 17 | +import java.util.List; | ||
| 18 | +import java.util.stream.Collectors; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * wuyuebin | ||
| 22 | + * 2023/5/6 16:43 | ||
| 23 | + * | ||
| 24 | + */ | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +public class AlertSchedule { | ||
| 28 | + | ||
| 29 | + private NotifyMessageMapper notifyMessageMapper; | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + private EmailService emailService; | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + public void alertNotifySchedule() { | ||
| 36 | + List<NotifyMessage> notifyMessages = notifyMessageMapper.selectList( | ||
| 37 | + Wrappers.<NotifyMessage>lambdaQuery().eq(NotifyMessage::getStatus, 0).in(NotifyMessage::getIsDeleted, | ||
| 38 | + 0)); | ||
| 39 | + if (CollectionUtil.isEmpty(notifyMessages)) { | ||
| 40 | + return; | ||
| 41 | + } | ||
| 42 | + List<NotifyMessage> emailMessages = notifyMessages.stream().filter( | ||
| 43 | + item -> item.getMessageType().equals("email")).collect(Collectors.toList()); | ||
| 44 | + List<NotifyMessage> weComMessages = notifyMessages.stream().filter( | ||
| 45 | + item -> item.getMessageType().equals("WeCom")).collect(Collectors.toList()); | ||
| 46 | + List<NotifyMessage> dingTalkMessages = notifyMessages.stream().filter( | ||
| 47 | + item -> item.getMessageType().equals("DingTalk")).collect(Collectors.toList()); | ||
| 48 | + | ||
| 49 | + emailService.send(emailMessages); | ||
| 50 | + } | ||
| 51 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertApiService.java+214-0
| @@ -0,0 +1,214 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import cn.hutool.core.util.StrUtil; | ||
| 9 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 10 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 11 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; | ||
| 13 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterNodeEntity; | ||
| 14 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 15 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 16 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 17 | +import org.opengauss.admin.system.service.ops.IOpsClusterNodeService; | ||
| 18 | +import org.opengauss.admin.system.service.ops.IOpsClusterService; | ||
| 19 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 20 | +import org.opengauss.plugin.alertcenter.dto.AlertContentParamDto; | ||
| 21 | +import org.opengauss.plugin.alertcenter.entity.AlertRecord; | ||
| 22 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 23 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 24 | +import org.opengauss.plugin.alertcenter.entity.NotifyMessage; | ||
| 25 | +import org.opengauss.plugin.alertcenter.entity.NotifyTemplate; | ||
| 26 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 27 | +import org.opengauss.plugin.alertcenter.mapper.AlertRecordMapper; | ||
| 28 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateMapper; | ||
| 29 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleMapper; | ||
| 30 | +import org.opengauss.plugin.alertcenter.mapper.NotifyMessageMapper; | ||
| 31 | +import org.opengauss.plugin.alertcenter.mapper.NotifyTemplateMapper; | ||
| 32 | +import org.opengauss.plugin.alertcenter.mapper.NotifyWayMapper; | ||
| 33 | +import org.opengauss.plugin.alertcenter.model.api.AlertApiReq; | ||
| 34 | +import org.opengauss.plugin.alertcenter.model.api.AlertLabels; | ||
| 35 | +import org.opengauss.plugin.alertcenter.utils.TextParser; | ||
| 36 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 37 | +import org.springframework.stereotype.Service; | ||
| 38 | +import org.springframework.transaction.annotation.Transactional; | ||
| 39 | +import org.springframework.util.CollectionUtils; | ||
| 40 | + | ||
| 41 | +import java.time.Duration; | ||
| 42 | +import java.time.LocalDateTime; | ||
| 43 | +import java.time.format.DateTimeFormatter; | ||
| 44 | +import java.util.Arrays; | ||
| 45 | +import java.util.List; | ||
| 46 | +import java.util.stream.Collectors; | ||
| 47 | + | ||
| 48 | +/** | ||
| 49 | + * wuyuebin | ||
| 50 | + * 2023/5/2 10:05 | ||
| 51 | + * | ||
| 52 | + */ | ||
| 53 | + | ||
| 54 | + | ||
| 55 | +public class AlertApiService { | ||
| 56 | + | ||
| 57 | + private AlertRecordMapper alertRecordMapper; | ||
| 58 | + | ||
| 59 | + private AlertTemplateMapper templateMapper; | ||
| 60 | + | ||
| 61 | + private AlertTemplateRuleMapper templateRuleMapper; | ||
| 62 | + | ||
| 63 | + private NotifyWayMapper notifyWayMapper; | ||
| 64 | + | ||
| 65 | + private NotifyTemplateMapper notifyTemplateMapper; | ||
| 66 | + | ||
| 67 | + private NotifyMessageMapper notifyMessageMapper; | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + private IOpsClusterService clusterService; | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + private IOpsClusterNodeService clusterNodeService; | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + private HostFacade hostFacade; | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + public void alerts(List<AlertApiReq> alertApiReqList) { | ||
| 80 | + for (AlertApiReq alertApiReq : alertApiReqList) { | ||
| 81 | + AlertLabels labels = alertApiReq.getLabels(); | ||
| 82 | + Long templateRuleId = labels.getTemplateRuleId(); | ||
| 83 | + AlertTemplateRule alertTemplateRule = templateRuleMapper.selectById(templateRuleId); | ||
| 84 | + if (alertTemplateRule == null) { | ||
| 85 | + return; | ||
| 86 | + } | ||
| 87 | + String notifyWayIds = alertTemplateRule.getNotifyWayIds(); | ||
| 88 | + String notifyWayNames = ""; | ||
| 89 | + if (StrUtil.isNotBlank(notifyWayIds)) { | ||
| 90 | + List<NotifyWay> notifyWays = notifyWayMapper.selectBatchIds( | ||
| 91 | + Arrays.asList(notifyWayIds.split(CommonConstants.DELIMITER))); | ||
| 92 | + if (CollectionUtil.isNotEmpty(notifyWays)) { | ||
| 93 | + notifyWayNames = notifyWays.stream().map(item -> item.getName()).collect( | ||
| 94 | + Collectors.joining(CommonConstants.DELIMITER)); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + String clusterNodeId = labels.getInstance(); | ||
| 98 | + AlertContentParamDto contentParamDto = setAndGetAlertContentParamDto(clusterNodeId, | ||
| 99 | + alertApiReq.getStartsAt(), labels.getLevel()); | ||
| 100 | + | ||
| 101 | + AlertRecord alertRecord = saveAndGetRecord(alertApiReq, notifyWayNames, alertTemplateRule, contentParamDto); | ||
| 102 | + contentParamDto.setContent(alertRecord.getAlertContent()); | ||
| 103 | + // 添加消息 | ||
| 104 | + Integer isRepeat = alertTemplateRule.getIsRepeat(); // 是否重复告警 | ||
| 105 | + if (isRepeat == CommonConstants.IS_NOT_REPEAT) { | ||
| 106 | + Long count = notifyMessageMapper.selectCount( | ||
| 107 | + Wrappers.<NotifyMessage>lambdaQuery().eq(NotifyMessage::getRecordId, alertRecord.getId())); | ||
| 108 | + if (count > 0) { | ||
| 109 | + continue; | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + Integer isSilence = alertTemplateRule.getIsSilence(); // 是否静默 | ||
| 113 | + LocalDateTime now = LocalDateTime.now(); | ||
| 114 | + if (isSilence == CommonConstants.IS_SILENCE && now.isAfter(alertTemplateRule.getSilenceStartTime()) | ||
| 115 | + && now.isBefore(alertTemplateRule.getSilenceEndTime())) { | ||
| 116 | + continue; | ||
| 117 | + } | ||
| 118 | + saveNotifyMessage(notifyWayIds, contentParamDto, alertRecord.getId()); | ||
| 119 | + } | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + private AlertRecord saveAndGetRecord( | ||
| 123 | + AlertApiReq alertApiReq, String notifyWayNames, AlertTemplateRule alertTemplateRule, | ||
| 124 | + AlertContentParamDto contentParamDto) { | ||
| 125 | + String clusterNodeId = alertApiReq.getLabels().getInstance(); | ||
| 126 | + Long templateId = alertApiReq.getLabels().getTemplateId(); | ||
| 127 | + List<AlertRecord> alertRecords = alertRecordMapper.selectList(Wrappers.<AlertRecord>lambdaQuery() | ||
| 128 | + .eq(AlertRecord::getClusterNodeId, clusterNodeId).eq(AlertRecord::getTemplateId, templateId) | ||
| 129 | + .eq(AlertRecord::getTemplateRuleId, alertTemplateRule.getId()).eq(AlertRecord::getStartTime, | ||
| 130 | + alertApiReq.getStartsAt()) | ||
| 131 | + .orderByDesc(AlertRecord::getUpdateTime)); | ||
| 132 | + AlertRecord alertRecord = null; | ||
| 133 | + if (CollectionUtils.isEmpty(alertRecords)) { | ||
| 134 | + alertRecord = new AlertRecord(); | ||
| 135 | + AlertTemplate alertTemplate = templateMapper.selectById(templateId); | ||
| 136 | + alertRecord.setClusterNodeId(clusterNodeId).setTemplateId(templateId).setTemplateRuleId( | ||
| 137 | + alertTemplateRule.getId()).setStartTime(alertApiReq.getStartsAt()).setEndTime( | ||
| 138 | + alertApiReq.getEndsAt()).setCreateTime(LocalDateTime.now()); | ||
| 139 | + alertRecord.setDuration( | ||
| 140 | + Duration.between(alertRecord.getStartTime(), alertRecord.getEndTime()).toSeconds()); | ||
| 141 | + alertRecord.setTemplateName(alertTemplate.getTemplateName()).setTemplateRuleName( | ||
| 142 | + alertTemplateRule.getRuleName()) | ||
| 143 | + .setTemplateRuleType(alertTemplateRule.getRuleType()).setLevel(alertTemplateRule.getLevel()) | ||
| 144 | + .setNotifyWayIds(alertTemplateRule.getNotifyWayIds()).setNotifyWayNames(notifyWayNames); | ||
| 145 | + String ruleContent = alertTemplateRule.getRuleContent(); | ||
| 146 | + TextParser textParser = new TextParser(); | ||
| 147 | + alertRecord.setAlertContent(textParser.parse(ruleContent, contentParamDto)); | ||
| 148 | + alertRecordMapper.insert(alertRecord); | ||
| 149 | + } else { | ||
| 150 | + alertRecord = alertRecords.get(0); | ||
| 151 | + if (alertRecord.getAlertStatus() == CommonConstants.RECOVER_STATUS) { | ||
| 152 | + return alertRecord; | ||
| 153 | + } | ||
| 154 | + alertRecord.setNotifyWayIds(alertTemplateRule.getNotifyWayIds()).setNotifyWayNames(notifyWayNames); | ||
| 155 | + alertRecord.setAlertStatus(alertRecord.getEndTime().equals( | ||
| 156 | + alertApiReq.getEndsAt()) ? CommonConstants.RECOVER_STATUS : CommonConstants.FIRING_STATUS); | ||
| 157 | + alertRecord.setEndTime(alertApiReq.getEndsAt()); | ||
| 158 | + alertRecord.setDuration( | ||
| 159 | + Duration.between(alertRecord.getStartTime(), alertRecord.getEndTime()).toSeconds()); | ||
| 160 | + alertRecord.setUpdateTime(LocalDateTime.now()); | ||
| 161 | + alertRecordMapper.updateById(alertRecord); | ||
| 162 | + } | ||
| 163 | + return alertRecord; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + private AlertContentParamDto setAndGetAlertContentParamDto( | ||
| 167 | + String clusterNodeId, LocalDateTime alertTime, String level) { | ||
| 168 | + OpsClusterNodeEntity opsClusterNodeEntity = clusterNodeService.getById(clusterNodeId); | ||
| 169 | + if (opsClusterNodeEntity == null) { | ||
| 170 | + throw new ServiceException("cluster node is not found"); | ||
| 171 | + } | ||
| 172 | + OpsHostEntity opsHost = hostFacade.getById(opsClusterNodeEntity.getHostId()); | ||
| 173 | + if (opsHost == null) { | ||
| 174 | + throw new ServiceException("host is not found"); | ||
| 175 | + } | ||
| 176 | + OpsClusterEntity opsClusterEntity = clusterService.getById(opsClusterNodeEntity.getClusterId()); | ||
| 177 | + if (opsClusterEntity == null) { | ||
| 178 | + throw new ServiceException("cluster is not found"); | ||
| 179 | + } | ||
| 180 | + AlertContentParamDto contentParamDto = new AlertContentParamDto(); | ||
| 181 | + String nodeName = | ||
| 182 | + opsClusterEntity.getClusterId() + "/" + opsHost.getPublicIp() + ":" + opsClusterEntity.getPort() | ||
| 183 | + + "(" + opsClusterNodeEntity.getClusterRole() + ")"; | ||
| 184 | + contentParamDto.setHostname(opsHost.getHostname()).setNodeName(nodeName).setPort( | ||
| 185 | + opsClusterEntity.getPort() != null ? opsHost.getPort().toString() : "").setHostIp( | ||
| 186 | + opsHost.getPublicIp()).setAlertTime( | ||
| 187 | + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(alertTime)).setLevel( | ||
| 188 | + level); | ||
| 189 | + return contentParamDto; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + private void saveNotifyMessage(String notifyWayIds, AlertContentParamDto contentParamDto, Long alertRecordId) { | ||
| 193 | + if (StrUtil.isBlank(notifyWayIds)) { | ||
| 194 | + return; | ||
| 195 | + } | ||
| 196 | + String[] notifyWayIdArr = notifyWayIds.split(CommonConstants.DELIMITER); | ||
| 197 | + for (String notifyWayId : notifyWayIdArr) { | ||
| 198 | + NotifyMessage notifyMessage = new NotifyMessage(); | ||
| 199 | + NotifyWay notifyWay = notifyWayMapper.selectById(Integer.valueOf(notifyWayId)); | ||
| 200 | + Long notifyTemplateId = notifyWay.getNotifyTemplateId(); | ||
| 201 | + NotifyTemplate notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId); | ||
| 202 | + notifyMessage.setMessageType(notifyWay.getNotifyType()); | ||
| 203 | + notifyMessage.setTitle(notifyTemplate.getNotifyTitle()); | ||
| 204 | + String content = new TextParser().parse(notifyTemplate.getNotifyContent(), contentParamDto); | ||
| 205 | + notifyMessage.setContent(content); | ||
| 206 | + notifyMessage.setEmail(notifyWay.getEmail()); | ||
| 207 | + notifyMessage.setPersonId(notifyWay.getPersonId()); | ||
| 208 | + notifyMessage.setDeptId(notifyWay.getDeptId()); | ||
| 209 | + notifyMessage.setCreateTime(LocalDateTime.now()); | ||
| 210 | + notifyMessage.setRecordId(alertRecordId); | ||
| 211 | + notifyMessageMapper.insert(notifyMessage); | ||
| 212 | + } | ||
| 213 | + } | ||
| 214 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertClusterNodeConfService.java+27-0
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 8 | +import org.opengauss.plugin.alertcenter.dto.AlertClusterNodeConfDto; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertClusterNodeConf; | ||
| 10 | +import org.opengauss.plugin.alertcenter.model.AlertClusterNodeAndTemplateReq; | ||
| 11 | +import org.opengauss.plugin.alertcenter.model.AlertClusterNodeConfReq; | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * wuyuebin | ||
| 16 | + * 2023/5/22 10:46 | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | +public interface AlertClusterNodeConfService extends IService<AlertClusterNodeConf> { | ||
| 20 | + void saveClusterNodeConf(AlertClusterNodeConfReq alertClusterNodeConfReq); | ||
| 21 | + | ||
| 22 | + AlertClusterNodeConf getByClusterNodeId(String clusterNodeId); | ||
| 23 | + | ||
| 24 | + void saveAlertTemplateAndConfig(AlertClusterNodeAndTemplateReq clusterNodeAndTemplateReq); | ||
| 25 | + | ||
| 26 | + List<AlertClusterNodeConfDto> getList(); | ||
| 27 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertConfigService.java+17-0
| @@ -0,0 +1,17 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.AlertConfig; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * wuyuebin | ||
| 12 | + * 2023/6/6 17:18 | ||
| 13 | + * | ||
| 14 | + */ | ||
| 15 | +public interface AlertConfigService extends IService<AlertConfig> { | ||
| 16 | + void saveAlertConf(AlertConfig alertConfig); | ||
| 17 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertRecordService.java+35-0
| @@ -0,0 +1,35 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 9 | +import org.opengauss.plugin.alertcenter.dto.AlertRecordDto; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.AlertRelationDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.dto.AlertStatisticsDto; | ||
| 12 | +import org.opengauss.plugin.alertcenter.entity.AlertRecord; | ||
| 13 | +import org.opengauss.plugin.alertcenter.model.AlertRecordReq; | ||
| 14 | +import org.opengauss.plugin.alertcenter.model.AlertStatisticsReq; | ||
| 15 | + | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * wuyuebin | ||
| 20 | + * 2023/5/17 10:35 | ||
| 21 | + * | ||
| 22 | + */ | ||
| 23 | +public interface AlertRecordService extends IService<AlertRecord> { | ||
| 24 | + Page<AlertRecordDto> getListPage(AlertRecordReq alertRecordReq, Page page); | ||
| 25 | + | ||
| 26 | + AlertStatisticsDto alertRecordStatistics(AlertStatisticsReq alertStatisticsReq); | ||
| 27 | + | ||
| 28 | + String markAsRead(String ids); | ||
| 29 | + | ||
| 30 | + AlertRecordDto getById(Long id); | ||
| 31 | + | ||
| 32 | + List<AlertRelationDto> getRelationData(Long id); | ||
| 33 | + | ||
| 34 | + String markAsUnread(String ids); | ||
| 35 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertRuleService.java+29-0
| @@ -0,0 +1,29 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 9 | +import org.opengauss.plugin.alertcenter.dto.AlertRuleDto; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.RuleItemPropertyDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.entity.AlertRule; | ||
| 12 | +import org.opengauss.plugin.alertcenter.model.RuleReq; | ||
| 13 | + | ||
| 14 | +import java.util.List; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * wuyuebin | ||
| 18 | + * 2023/5/9 10:08 | ||
| 19 | + * | ||
| 20 | + */ | ||
| 21 | +public interface AlertRuleService extends IService<AlertRule> { | ||
| 22 | + Page<AlertRuleDto> getRulePage(RuleReq ruleReq, Page page); | ||
| 23 | + | ||
| 24 | + AlertRule getRuleById(Long id); | ||
| 25 | + | ||
| 26 | + List<RuleItemPropertyDto> getRuleItemProperties(); | ||
| 27 | + | ||
| 28 | + List<AlertRuleDto> getRuleList(); | ||
| 29 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertTemplateRuleItemParamService.java+16-0
| @@ -0,0 +1,16 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItemParam; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * wuyuebin | ||
| 12 | + * 2023/6/5 19:24 | ||
| 13 | + * | ||
| 14 | + */ | ||
| 15 | +public interface AlertTemplateRuleItemParamService extends IService<AlertTemplateRuleItemParam> { | ||
| 16 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertTemplateRuleItemService.java+19-0
| @@ -0,0 +1,19 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * wuyuebin | ||
| 14 | + * 2023/5/24 10:40 | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | +public interface AlertTemplateRuleItemService extends IService<AlertTemplateRuleItem> { | ||
| 18 | + void saveOrUpdateList(List<AlertTemplateRuleItem> templateRuleItems); | ||
| 19 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertTemplateRuleService.java+24-0
| @@ -0,0 +1,24 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 8 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateRuleDto; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/5/24 10:31 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | +public interface AlertTemplateRuleService extends IService<AlertTemplateRule> { | ||
| 19 | + AlertTemplateRule getTemplateRule(Long templateRuleId); | ||
| 20 | + | ||
| 21 | + AlertTemplateRuleDto saveTemplateRule(AlertTemplateRule alertTemplateRule); | ||
| 22 | + | ||
| 23 | + List<AlertTemplateRuleDto> getDtoListByTemplateId(Long templateId); | ||
| 24 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/AlertTemplateService.java+35-0
| @@ -0,0 +1,35 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 9 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateDto; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateRuleDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 12 | +import org.opengauss.plugin.alertcenter.model.AlertTemplateReq; | ||
| 13 | + | ||
| 14 | +import java.util.List; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * wuyuebin | ||
| 18 | + * 2023/5/12 11:40 | ||
| 19 | + * | ||
| 20 | + */ | ||
| 21 | +public interface AlertTemplateService extends IService<AlertTemplate> { | ||
| 22 | + Page<AlertTemplate> getTemplatePage(String templateName, Page page); | ||
| 23 | + | ||
| 24 | + Page<AlertTemplateRuleDto> getTemplateRulePage(Long templateId, String ruleName, Page page); | ||
| 25 | + | ||
| 26 | + AlertTemplateDto getTemplate(Long id); | ||
| 27 | + | ||
| 28 | + AlertTemplate saveTemplate(AlertTemplateReq templateReq); | ||
| 29 | + | ||
| 30 | + List<AlertTemplate> getTemplateList(); | ||
| 31 | + | ||
| 32 | + List<AlertTemplateRuleDto> getTemplateRuleListById(Long templateId); | ||
| 33 | + | ||
| 34 | + void delTemplate(Long id); | ||
| 35 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/EmailService.java+183-0
| @@ -0,0 +1,183 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 9 | +import jakarta.mail.Authenticator; | ||
| 10 | +import jakarta.mail.Message; | ||
| 11 | +import jakarta.mail.MessagingException; | ||
| 12 | +import jakarta.mail.PasswordAuthentication; | ||
| 13 | +import jakarta.mail.Session; | ||
| 14 | +import jakarta.mail.Transport; | ||
| 15 | +import jakarta.mail.internet.AddressException; | ||
| 16 | +import jakarta.mail.internet.InternetAddress; | ||
| 17 | +import jakarta.mail.internet.MimeMessage; | ||
| 18 | +import jakarta.mail.internet.MimeUtility; | ||
| 19 | +import lombok.extern.slf4j.Slf4j; | ||
| 20 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 21 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 22 | +import org.opengauss.plugin.alertcenter.entity.NotifyConfig; | ||
| 23 | +import org.opengauss.plugin.alertcenter.entity.NotifyMessage; | ||
| 24 | +import org.opengauss.plugin.alertcenter.mapper.NotifyConfigMapper; | ||
| 25 | +import org.opengauss.plugin.alertcenter.mapper.NotifyMessageMapper; | ||
| 26 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 27 | +import org.springframework.stereotype.Service; | ||
| 28 | + | ||
| 29 | +import java.io.UnsupportedEncodingException; | ||
| 30 | +import java.util.List; | ||
| 31 | +import java.util.Properties; | ||
| 32 | +import java.util.stream.Stream; | ||
| 33 | + | ||
| 34 | +/** | ||
| 35 | + * wuyuebin | ||
| 36 | + * 2023/5/7 13:24 | ||
| 37 | + * | ||
| 38 | + */ | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +public class EmailService { | ||
| 42 | + | ||
| 43 | + private NotifyConfigMapper notifyConfigMapper; | ||
| 44 | + | ||
| 45 | + | ||
| 46 | + private NotifyMessageMapper notifyMessageMapper; | ||
| 47 | + | ||
| 48 | + private Properties applyProperties(NotifyConfig notifyConfig) { | ||
| 49 | + Properties properties = new Properties(); | ||
| 50 | + // 邮件服务器 | ||
| 51 | + properties.setProperty("mail.smtp.host", notifyConfig.getSever()); | ||
| 52 | + // 端口号 | ||
| 53 | + properties.setProperty("mail.smtp.port", notifyConfig.getPort() + ""); | ||
| 54 | + // 需要身份验证 | ||
| 55 | + properties.setProperty("mail.smtp.auth", "true"); | ||
| 56 | + // 发送邮件协议 | ||
| 57 | + properties.setProperty("mail.transport.protocol", "smtp"); | ||
| 58 | + properties.setProperty("mail.user", notifyConfig.getSender()); | ||
| 59 | + properties.setProperty("mail.from", notifyConfig.getAccount()); | ||
| 60 | + return properties; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public void send(NotifyMessage notifyMessage) { | ||
| 64 | + if (notifyMessage == null) { | ||
| 65 | + return; | ||
| 66 | + } | ||
| 67 | + List<NotifyConfig> emailConfigList = notifyConfigMapper.selectList( | ||
| 68 | + Wrappers.<NotifyConfig>lambdaQuery().eq(NotifyConfig::getEnable, 1).eq(NotifyConfig::getType, "email")); | ||
| 69 | + if (CollectionUtil.isEmpty(emailConfigList)) { | ||
| 70 | + return; | ||
| 71 | + } | ||
| 72 | + NotifyConfig notifyConfig = emailConfigList.get(0); | ||
| 73 | + Properties properties = this.applyProperties(notifyConfig); | ||
| 74 | + try { | ||
| 75 | + Session session = Session.getInstance(properties, new Authenticator() { | ||
| 76 | + | ||
| 77 | + protected PasswordAuthentication getPasswordAuthentication() { | ||
| 78 | + return new PasswordAuthentication(notifyConfig.getAccount(), notifyConfig.getPasswd()); | ||
| 79 | + } | ||
| 80 | + }); | ||
| 81 | + MimeMessage mimeMessage = new MimeMessage(session); | ||
| 82 | + String[] receiverArr = notifyMessage.getEmail().split(","); | ||
| 83 | + InternetAddress[] addresses = Stream.of(receiverArr).map(item -> { | ||
| 84 | + try { | ||
| 85 | + return new InternetAddress(item); | ||
| 86 | + } catch (AddressException e) { | ||
| 87 | + throw new ServiceException("receiver exception:" + e.getMessage()); | ||
| 88 | + } | ||
| 89 | + }).toArray(InternetAddress[]::new); | ||
| 90 | + mimeMessage.setFrom(new InternetAddress( | ||
| 91 | + MimeUtility.encodeWord(notifyConfig.getSender()) + " <" + notifyConfig.getAccount() + ">")); | ||
| 92 | + mimeMessage.setRecipients(Message.RecipientType.TO, addresses); | ||
| 93 | + mimeMessage.setSubject(notifyMessage.getTitle()); | ||
| 94 | + mimeMessage.setContent( | ||
| 95 | + "<div style='white-space: pre-line;'> " + notifyMessage.getContent().replaceAll( | ||
| 96 | + CommonConstants.LINE_FEED, "<br/>") + "</div>", "text/html;charset=UTF-8"); | ||
| 97 | + Transport.send(mimeMessage); | ||
| 98 | + notifyMessage.setStatus(1); | ||
| 99 | + notifyMessageMapper.updateById(notifyMessage); | ||
| 100 | + } catch (MessagingException | UnsupportedEncodingException | ServiceException e) { | ||
| 101 | + notifyMessage.setStatus(2); | ||
| 102 | + notifyMessageMapper.updateById(notifyMessage); | ||
| 103 | + log.error("the email send fail:", e); | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public void send(List<NotifyMessage> notifyMessageList) { | ||
| 108 | + if (CollectionUtil.isEmpty(notifyMessageList)) { | ||
| 109 | + return; | ||
| 110 | + } | ||
| 111 | + List<NotifyConfig> emailConfigList = notifyConfigMapper.selectList( | ||
| 112 | + Wrappers.<NotifyConfig>lambdaQuery().eq(NotifyConfig::getEnable, 1).eq(NotifyConfig::getType, "email")); | ||
| 113 | + if (CollectionUtil.isEmpty(emailConfigList)) { | ||
| 114 | + return; | ||
| 115 | + } | ||
| 116 | + NotifyConfig notifyConfig = emailConfigList.get(0); | ||
| 117 | + Properties properties = this.applyProperties(notifyConfig); | ||
| 118 | + for (NotifyMessage notifyMessage : notifyMessageList) { | ||
| 119 | + try { | ||
| 120 | + Session session = Session.getInstance(properties, new Authenticator() { | ||
| 121 | + | ||
| 122 | + protected PasswordAuthentication getPasswordAuthentication() { | ||
| 123 | + return new PasswordAuthentication(notifyConfig.getAccount(), notifyConfig.getPasswd()); | ||
| 124 | + } | ||
| 125 | + }); | ||
| 126 | + MimeMessage mimeMessage = new MimeMessage(session); | ||
| 127 | + String[] receiverArr = notifyMessage.getEmail().split(","); | ||
| 128 | + InternetAddress[] addresses = Stream.of(receiverArr).map(item -> { | ||
| 129 | + try { | ||
| 130 | + return new InternetAddress(item); | ||
| 131 | + } catch (AddressException e) { | ||
| 132 | + throw new ServiceException("receiver exception:" + e.getMessage()); | ||
| 133 | + } | ||
| 134 | + }).toArray(InternetAddress[]::new); | ||
| 135 | + mimeMessage.setFrom(new InternetAddress( | ||
| 136 | + MimeUtility.encodeWord(notifyConfig.getSender()) + " <" + notifyConfig.getAccount() + ">")); | ||
| 137 | + mimeMessage.setRecipients(Message.RecipientType.TO, addresses); | ||
| 138 | + mimeMessage.setSubject(notifyMessage.getTitle()); | ||
| 139 | + mimeMessage.setContent( | ||
| 140 | + "<div style='white-space: pre-line;'> " + notifyMessage.getContent().replaceAll( | ||
| 141 | + CommonConstants.LINE_FEED, "<br/>") + "</div>", "text/html;charset=UTF-8"); | ||
| 142 | + Transport.send(mimeMessage); | ||
| 143 | + notifyMessage.setStatus(1); | ||
| 144 | + notifyMessageMapper.updateById(notifyMessage); | ||
| 145 | + } catch (MessagingException | UnsupportedEncodingException | ServiceException e) { | ||
| 146 | + notifyMessage.setStatus(2); | ||
| 147 | + notifyMessageMapper.updateById(notifyMessage); | ||
| 148 | + log.error("the email send fail:", e); | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + public void sendTest(NotifyConfig notifyConfig, String receiver, String title, String content) { | ||
| 154 | + Properties properties = this.applyProperties(notifyConfig); | ||
| 155 | + try { | ||
| 156 | + Session session = Session.getInstance(properties, new Authenticator() { | ||
| 157 | + | ||
| 158 | + protected PasswordAuthentication getPasswordAuthentication() { | ||
| 159 | + return new PasswordAuthentication(notifyConfig.getAccount(), notifyConfig.getPasswd()); | ||
| 160 | + } | ||
| 161 | + }); | ||
| 162 | + MimeMessage mimeMessage = new MimeMessage(session); | ||
| 163 | + String[] receiverArr = receiver.split(","); | ||
| 164 | + InternetAddress[] addresses = Stream.of(receiverArr).map(item -> { | ||
| 165 | + try { | ||
| 166 | + return new InternetAddress(item); | ||
| 167 | + } catch (AddressException e) { | ||
| 168 | + throw new ServiceException("receiver exception:" + e.getMessage()); | ||
| 169 | + } | ||
| 170 | + }).toArray(InternetAddress[]::new); | ||
| 171 | + mimeMessage.setFrom(new InternetAddress( | ||
| 172 | + MimeUtility.encodeWord(notifyConfig.getSender()) + " <" + notifyConfig.getAccount() + ">")); | ||
| 173 | + mimeMessage.setRecipients(Message.RecipientType.TO, addresses); | ||
| 174 | + mimeMessage.setSubject(title); | ||
| 175 | + mimeMessage.setContent( | ||
| 176 | + "<div style='white-space: pre-line;'> " + content.replaceAll(CommonConstants.LINE_FEED, "<br/>") | ||
| 177 | + + "</div>", "text/html;charset=UTF-8"); | ||
| 178 | + Transport.send(mimeMessage); | ||
| 179 | + } catch (MessagingException | UnsupportedEncodingException | ServiceException e) { | ||
| 180 | + throw new ServiceException("test sentTest exception:" + e.getMessage()); | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/EnvironmentService.java+73-0
| @@ -0,0 +1,73 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 9 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 10 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 11 | +import org.opengauss.admin.system.plugin.facade.OpsFacade; | ||
| 12 | +import org.opengauss.plugin.alertcenter.config.annotation.AlertContentParam; | ||
| 13 | +import org.opengauss.plugin.alertcenter.dto.AlertContentParamDto; | ||
| 14 | +import org.opengauss.plugin.alertcenter.entity.NctigbaEnv; | ||
| 15 | +import org.opengauss.plugin.alertcenter.mapper.NctigbaEnvMapper; | ||
| 16 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 18 | +import org.springframework.stereotype.Service; | ||
| 19 | + | ||
| 20 | +import java.lang.reflect.Field; | ||
| 21 | +import java.util.Arrays; | ||
| 22 | +import java.util.HashMap; | ||
| 23 | +import java.util.List; | ||
| 24 | +import java.util.Map; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * wuyuebin | ||
| 28 | + * 2023/6/16 15:42 | ||
| 29 | + * | ||
| 30 | + */ | ||
| 31 | + | ||
| 32 | +public class EnvironmentService { | ||
| 33 | + | ||
| 34 | + private NctigbaEnvMapper envMapper; | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + private OpsFacade opsFacade; | ||
| 39 | + | ||
| 40 | + public List cluster() { | ||
| 41 | + return opsFacade.listCluster(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public void checkPrometheus() { | ||
| 45 | + List<NctigbaEnv> env = envMapper | ||
| 46 | + .selectList(Wrappers.<NctigbaEnv>lambdaQuery().eq(NctigbaEnv::getType, NctigbaEnv.Type.PROMETHEUS)); | ||
| 47 | + if (CollectionUtil.isEmpty(env)) { | ||
| 48 | + throw new ServiceException("the promethues is uninstall"); | ||
| 49 | + } | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public Map<String, Map<String, String>> getAlertContentParam(String type) { | ||
| 53 | + MessageSourceUtil.reset(); | ||
| 54 | + Map<String, Map<String, String>> map = new HashMap<>(); | ||
| 55 | + Class<AlertContentParamDto> clazz = AlertContentParamDto.class; | ||
| 56 | + Field[] declaredFields = clazz.getDeclaredFields(); | ||
| 57 | + for (Field field : declaredFields) { | ||
| 58 | + if (field.isAnnotationPresent(AlertContentParam.class)) { | ||
| 59 | + Map<String, String> param = new HashMap<>(); | ||
| 60 | + AlertContentParam annotation = field.getAnnotation(AlertContentParam.class); | ||
| 61 | + List<String> groups = Arrays.asList(annotation.group()); | ||
| 62 | + if (!groups.contains(type)) { | ||
| 63 | + continue; | ||
| 64 | + } | ||
| 65 | + boolean isI18nPreVal = annotation.isI18nPreVal(); | ||
| 66 | + param.put("name", MessageSourceUtil.get(annotation.name())); | ||
| 67 | + param.put("preVal", isI18nPreVal ? MessageSourceUtil.get(annotation.preVal()) : annotation.preVal()); | ||
| 68 | + map.put(field.getName(), param); | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + return map; | ||
| 72 | + } | ||
| 73 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/NotifyConfigService.java+24-0
| @@ -0,0 +1,24 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.NotifyConfig; | ||
| 9 | +import org.opengauss.plugin.alertcenter.model.NotifyConfigReq; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/6/1 01:46 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | +public interface NotifyConfigService extends IService<NotifyConfig> { | ||
| 19 | + List<NotifyConfig> getAllList(); | ||
| 20 | + | ||
| 21 | + void saveList(List<NotifyConfig> list); | ||
| 22 | + | ||
| 23 | + void testConfig(NotifyConfigReq notifyConfigReq); | ||
| 24 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/NotifyTemplateService.java+26-0
| @@ -0,0 +1,26 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.NotifyTemplate; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/5/31 10:16 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | +public interface NotifyTemplateService extends IService<NotifyTemplate> { | ||
| 19 | + Page getListPage(String notifyTemplateName, String notifyTemplateType, Page page); | ||
| 20 | + | ||
| 21 | + void saveTemplate(NotifyTemplate notifyTemplate); | ||
| 22 | + | ||
| 23 | + void delById(Long id); | ||
| 24 | + | ||
| 25 | + List<NotifyTemplate> getList(String notifyTemplateType); | ||
| 26 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/NotifyWayService.java+28-0
| @@ -0,0 +1,28 @@ | |||
| 1 | + | ||
| 2 | +/* | ||
| 3 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 4 | + */ | ||
| 5 | + | ||
| 6 | +package org.opengauss.plugin.alertcenter.service; | ||
| 7 | + | ||
| 8 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 9 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 10 | +import org.opengauss.plugin.alertcenter.dto.NotifyWayDto; | ||
| 11 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 12 | + | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * wuyuebin | ||
| 17 | + * 2023/5/25 15:52 | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | +public interface NotifyWayService extends IService<NotifyWay> { | ||
| 21 | + List<NotifyWay> getList(String notifyType); | ||
| 22 | + | ||
| 23 | + Page<NotifyWayDto> getListPage(String name, String notifyType, Page page); | ||
| 24 | + | ||
| 25 | + void saveNotifyWay(NotifyWay notifyWay); | ||
| 26 | + | ||
| 27 | + void delById(Long id); | ||
| 28 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/PrometheusService.java+516-0
| @@ -0,0 +1,516 @@ | |||
| 1 | + | ||
| 2 | +/* | ||
| 3 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 4 | + */ | ||
| 5 | + | ||
| 6 | +package org.opengauss.plugin.alertcenter.service; | ||
| 7 | + | ||
| 8 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 9 | +import cn.hutool.core.io.FileUtil; | ||
| 10 | +import cn.hutool.core.util.StrUtil; | ||
| 11 | +import cn.hutool.http.HttpUtil; | ||
| 12 | +import cn.hutool.json.JSONArray; | ||
| 13 | +import cn.hutool.json.JSONObject; | ||
| 14 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 15 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 16 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 17 | +import lombok.extern.slf4j.Slf4j; | ||
| 18 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 19 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostUserEntity; | ||
| 20 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 21 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 22 | +import org.opengauss.admin.system.plugin.facade.HostUserFacade; | ||
| 23 | +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; | ||
| 24 | +import org.opengauss.plugin.alertcenter.config.properties.AlertProperty; | ||
| 25 | +import org.opengauss.plugin.alertcenter.config.properties.AlertmanagerProperty; | ||
| 26 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 27 | +import org.opengauss.plugin.alertcenter.dto.AlertRuleConfigDto; | ||
| 28 | +import org.opengauss.plugin.alertcenter.dto.PrometheusConfigDto; | ||
| 29 | +import org.opengauss.plugin.alertcenter.dto.PrometheusEnvDto; | ||
| 30 | +import org.opengauss.plugin.alertcenter.entity.AlertClusterNodeConf; | ||
| 31 | +import org.opengauss.plugin.alertcenter.entity.AlertConfig; | ||
| 32 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 33 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 34 | +import org.opengauss.plugin.alertcenter.entity.NctigbaEnv; | ||
| 35 | +import org.opengauss.plugin.alertcenter.mapper.AlertClusterNodeConfMapper; | ||
| 36 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemMapper; | ||
| 37 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleMapper; | ||
| 38 | +import org.opengauss.plugin.alertcenter.mapper.NctigbaEnvMapper; | ||
| 39 | +import org.opengauss.plugin.alertcenter.utils.SshSession; | ||
| 40 | +import org.opengauss.plugin.alertcenter.utils.YamlUtil; | ||
| 41 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 42 | +import org.springframework.stereotype.Service; | ||
| 43 | +import org.springframework.util.CollectionUtils; | ||
| 44 | + | ||
| 45 | +import java.io.File; | ||
| 46 | +import java.io.IOException; | ||
| 47 | +import java.math.BigDecimal; | ||
| 48 | +import java.nio.file.Files; | ||
| 49 | +import java.time.Instant; | ||
| 50 | +import java.time.LocalDateTime; | ||
| 51 | +import java.time.ZoneOffset; | ||
| 52 | +import java.util.ArrayList; | ||
| 53 | +import java.util.Arrays; | ||
| 54 | +import java.util.Collection; | ||
| 55 | +import java.util.HashMap; | ||
| 56 | +import java.util.List; | ||
| 57 | +import java.util.Map; | ||
| 58 | +import java.util.stream.Collectors; | ||
| 59 | + | ||
| 60 | +/** | ||
| 61 | + * wuyuebin | ||
| 62 | + * 2023/5/19 09:50 | ||
| 63 | + * 用于请求prometheus数据或者修改其配置 | ||
| 64 | + */ | ||
| 65 | + | ||
| 66 | + | ||
| 67 | +public class PrometheusService { | ||
| 68 | + | ||
| 69 | + private AlertTemplateRuleMapper alertTemplateRuleMapper; | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + private AlertTemplateRuleItemMapper alertTemplateRuleItemMapper; | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + private NctigbaEnvMapper envMapper; | ||
| 76 | + | ||
| 77 | + | ||
| 78 | + private AlertProperty alertProperty; | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + private AlertConfigService alertConfigService; | ||
| 82 | + | ||
| 83 | + | ||
| 84 | + | ||
| 85 | + private EncryptionUtils encryptionUtils; | ||
| 86 | + | ||
| 87 | + | ||
| 88 | + | ||
| 89 | + private HostFacade hostFacade; | ||
| 90 | + | ||
| 91 | + | ||
| 92 | + | ||
| 93 | + private HostUserFacade hostUserFacade; | ||
| 94 | + | ||
| 95 | + | ||
| 96 | + private AlertClusterNodeConfMapper clusterNodeConfMapper; | ||
| 97 | + | ||
| 98 | + private PrometheusEnvDto prometheusEnvDto; | ||
| 99 | + | ||
| 100 | + private ObjectMapper objectMapper = new ObjectMapper(); | ||
| 101 | + | ||
| 102 | + private void initPrometheusEnvDto() { | ||
| 103 | + List<AlertConfig> alertConfigs = alertConfigService.list(); | ||
| 104 | + if (prometheusEnvDto == null) { | ||
| 105 | + prometheusEnvDto = new PrometheusEnvDto(); | ||
| 106 | + } | ||
| 107 | + prometheusEnvDto.setConfigList(alertConfigs); | ||
| 108 | + NctigbaEnv promEnv = envMapper.selectOne( | ||
| 109 | + Wrappers.<NctigbaEnv>lambdaQuery().eq(NctigbaEnv::getType, NctigbaEnv.Type.PROMETHEUS)); | ||
| 110 | + if (promEnv == null) { | ||
| 111 | + throw new ServiceException("uninstall the prometheus"); | ||
| 112 | + } | ||
| 113 | + if (StrUtil.isBlank(promEnv.getPath())) { | ||
| 114 | + throw new ServiceException("uninstall the prometheus"); | ||
| 115 | + } | ||
| 116 | + if (StrUtil.isBlank(promEnv.getHostid())) { | ||
| 117 | + throw new ServiceException("host id is unknown"); | ||
| 118 | + } | ||
| 119 | + OpsHostEntity promeHost = hostFacade.getById(promEnv.getHostid()); | ||
| 120 | + List<OpsHostUserEntity> hostUserList = hostUserFacade.listHostUserByHostId(promEnv.getHostid()); | ||
| 121 | + if (CollectionUtil.isEmpty(hostUserList)) { | ||
| 122 | + throw new ServiceException("host user is null"); | ||
| 123 | + } | ||
| 124 | + List<OpsHostUserEntity> promUserList = hostUserList.stream().filter( | ||
| 125 | + item -> item.getUsername().equals(promEnv.getUsername())).collect(Collectors.toList()); | ||
| 126 | + if (CollectionUtil.isEmpty(promUserList)) { | ||
| 127 | + throw new ServiceException("the host user Prometheus is not exist"); | ||
| 128 | + } | ||
| 129 | + OpsHostUserEntity promUser = promUserList.get(0); | ||
| 130 | + // The code comments need to be uncommented in the development environment: encryptionUtils.refreshKeyPair() | ||
| 131 | + prometheusEnvDto.setPromIp(promeHost.getPublicIp()).setHostPort(promeHost.getPort()).setPromPort( | ||
| 132 | + promEnv.getPort()).setPromUsername(promUser.getUsername()).setPromPasswd( | ||
| 133 | + encryptionUtils.decrypt(promUser.getPassword())).setPath(promEnv.getPath()); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + private PrometheusConfigDto getPromConfig() { | ||
| 137 | + // String promYmlStr = session.execute("cat " + promEnv.getPath() + CommonConstants.PROMETHEUS_YML); | ||
| 138 | + String promYmlStr = ""; | ||
| 139 | + String url = "http://" + prometheusEnvDto.getPromIp() + ":" + prometheusEnvDto.getPromPort() + "/api/v1/status" | ||
| 140 | + + "/config"; | ||
| 141 | + String result = HttpUtil.get(url); | ||
| 142 | + if (StrUtil.isNotBlank(result)) { | ||
| 143 | + JSONObject resultJson = new JSONObject(result); | ||
| 144 | + String status = resultJson.getStr("status", ""); | ||
| 145 | + if (status.equals("success")) { | ||
| 146 | + JSONObject data = resultJson.getJSONObject("data"); | ||
| 147 | + promYmlStr = data.getStr("yaml"); | ||
| 148 | + } | ||
| 149 | + } | ||
| 150 | + HashMap map = YamlUtil.loadAs(promYmlStr, HashMap.class); | ||
| 151 | + if (map == null) { | ||
| 152 | + throw new NullPointerException("the prometheus config is null"); | ||
| 153 | + } | ||
| 154 | + return objectMapper.convertValue(map, PrometheusConfigDto.class); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + private void updatePromConfig(SshSession session, PrometheusConfigDto config) throws IOException { | ||
| 158 | + List<String> ruleFilesConf = config.getRuleFiles(); | ||
| 159 | + String ruleFilePrefix = alertProperty.getRuleFilePrefix(); | ||
| 160 | + String ruleFileSuffix = alertProperty.getRuleFileSuffix(); | ||
| 161 | + String ruleFilePath = | ||
| 162 | + prometheusEnvDto.getPath() + CommonConstants.SLASH + ruleFilePrefix + "*" + ruleFileSuffix; | ||
| 163 | + boolean isConfigChange = false; | ||
| 164 | + if (CollectionUtils.isEmpty(ruleFilesConf)) { | ||
| 165 | + ruleFilesConf = new ArrayList<>(); | ||
| 166 | + config.setRuleFiles(ruleFilesConf); | ||
| 167 | + ruleFilesConf.add(ruleFilePath); | ||
| 168 | + isConfigChange = true; | ||
| 169 | + } | ||
| 170 | + if (!ruleFilesConf.contains(ruleFilePath)) { | ||
| 171 | + ruleFilesConf.add(ruleFilePath); | ||
| 172 | + isConfigChange = true; | ||
| 173 | + } | ||
| 174 | + isConfigChange |= checkAndUpdatePromAlertConfig(config); | ||
| 175 | + | ||
| 176 | + if (isConfigChange) { | ||
| 177 | + uploadFileConfig(session, config); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + private boolean checkAndUpdatePromAlertConfig(PrometheusConfigDto config) { | ||
| 182 | + PrometheusConfigDto.Alert alerting = config.getAlerting(); | ||
| 183 | + if (alerting == null) { | ||
| 184 | + alerting = new PrometheusConfigDto.Alert(); | ||
| 185 | + } | ||
| 186 | + AlertmanagerProperty alertmanagerPro = alertProperty.getAlertmanager(); | ||
| 187 | + String apiVersion = alertmanagerPro.getApiVersion(); | ||
| 188 | + String pathPrefix = alertmanagerPro.getPathPrefix(); | ||
| 189 | + List<PrometheusConfigDto.Alert.Alertmanager.Conf> staticConfigs = new ArrayList<>(); | ||
| 190 | + PrometheusConfigDto.Alert.Alertmanager.Conf confNew = new PrometheusConfigDto.Alert.Alertmanager.Conf(); | ||
| 191 | + List<String> targets = prometheusEnvDto.getConfigList().stream().map( | ||
| 192 | + item -> item.getAlertIp() + ":" + item.getAlertPort()).collect(Collectors.toList()); | ||
| 193 | + confNew.setTargets(targets); | ||
| 194 | + staticConfigs.add(confNew); | ||
| 195 | + PrometheusConfigDto.Alert.Alertmanager alertmanagerNew = new PrometheusConfigDto.Alert.Alertmanager(); | ||
| 196 | + alertmanagerNew.setPathPrefix(pathPrefix); | ||
| 197 | + alertmanagerNew.setApiVersion(apiVersion); | ||
| 198 | + alertmanagerNew.setStaticConfigs(staticConfigs); | ||
| 199 | + alertmanagerNew.setScheme("http"); | ||
| 200 | + alertmanagerNew.setIsFollowRedirects(true); | ||
| 201 | + alertmanagerNew.setTimeout("10s"); | ||
| 202 | + alertmanagerNew.setIsEnableHttp2(true); | ||
| 203 | + List<PrometheusConfigDto.Alert.Alertmanager> alertmanagers = alerting.getAlertmanagers(); | ||
| 204 | + if (CollectionUtils.isEmpty(alertmanagers)) { | ||
| 205 | + alertmanagers = new ArrayList<PrometheusConfigDto.Alert.Alertmanager>(); | ||
| 206 | + alertmanagers.add(alertmanagerNew); | ||
| 207 | + return true; | ||
| 208 | + } else { | ||
| 209 | + PrometheusConfigDto.Alert.Alertmanager alertmanager = alertmanagers.get(0); | ||
| 210 | + if (!alertmanager.toString().equals(alertmanagerNew.toString())) { | ||
| 211 | + List<PrometheusConfigDto.Alert.Alertmanager.Conf> staticConfigs0 = alertmanager.getStaticConfigs(); | ||
| 212 | + if (CollectionUtil.isNotEmpty(staticConfigs0)) { | ||
| 213 | + List<String> targets0 = staticConfigs0.get(0).getTargets(); | ||
| 214 | + List<String> delTargets = CollectionUtil.isNotEmpty( | ||
| 215 | + prometheusEnvDto.getDelConfigList()) ? prometheusEnvDto.getDelConfigList().stream().map( | ||
| 216 | + item -> item.getAlertIp() + ":" + item.getAlertPort()).collect( | ||
| 217 | + Collectors.toList()) : new ArrayList<>(); | ||
| 218 | + targets0 = targets0.stream().filter( | ||
| 219 | + item -> !delTargets.contains(item) || !targets.contains(item)).collect(Collectors.toList()); | ||
| 220 | + targets.addAll(targets0); | ||
| 221 | + } | ||
| 222 | + alertmanagers.set(0, alertmanagerNew); | ||
| 223 | + return true; | ||
| 224 | + } | ||
| 225 | + } | ||
| 226 | + return false; | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + private void uploadFileConfig(SshSession session, Object config) throws IOException { | ||
| 230 | + HashMap configMap = objectMapper.convertValue(config, HashMap.class); | ||
| 231 | + File prometheusConfigFile = File.createTempFile("prom", ".tmp"); | ||
| 232 | + FileUtil.appendUtf8String(YamlUtil.dump(configMap), prometheusConfigFile); | ||
| 233 | + session.execute("rm " + prometheusEnvDto.getPath() + CommonConstants.PROMETHEUS_YML); | ||
| 234 | + session.upload(prometheusConfigFile.getAbsolutePath(), | ||
| 235 | + prometheusEnvDto.getPath() + CommonConstants.PROMETHEUS_YML); | ||
| 236 | + Files.delete(prometheusConfigFile.toPath()); | ||
| 237 | + String res = HttpUtil.post( | ||
| 238 | + "http://" + prometheusEnvDto.getPromIp() + ":" + +prometheusEnvDto.getPromPort() + "/-/reload", ""); | ||
| 239 | + log.info(res); | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + public void initPrometheusConfig() { | ||
| 243 | + try { | ||
| 244 | + initPrometheusEnvDto(); | ||
| 245 | + List<AlertConfig> alertConfigs = prometheusEnvDto.getConfigList(); | ||
| 246 | + if (CollectionUtil.isEmpty(alertConfigs)) { | ||
| 247 | + return; | ||
| 248 | + } | ||
| 249 | + SshSession session = SshSession.connect(prometheusEnvDto.getPromIp(), prometheusEnvDto.getHostPort(), | ||
| 250 | + prometheusEnvDto.getPromUsername(), prometheusEnvDto.getPromPasswd()); | ||
| 251 | + PrometheusConfigDto config = getPromConfig(); | ||
| 252 | + updatePromConfig(session, config); | ||
| 253 | + session.close(); | ||
| 254 | + } catch (IOException e) { | ||
| 255 | + log.error("init prometheus configuration fail: ", e); | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + /** | ||
| 260 | + * Get data from a Prometheus server based on promQL and time | ||
| 261 | + * | ||
| 262 | + * url http://IP:9090/api/v1/query_range? | ||
| 263 | + * port 9090 | ||
| 264 | + * query query=promQL &start=1683316800 &end=1683489600 &step=691 | ||
| 265 | + * | ||
| 266 | + * step = Math.max(Math.floor(60 * 60 * 1000 / 250000), 1) | ||
| 267 | + * 默认1个小时,this.props.options.range=60 * 60 * 1000 | ||
| 268 | + * | ||
| 269 | + * startTime startTime = endTime - this.props.options.range / 1000 | ||
| 270 | + * endTime end = this.getEndTime().valueOf() / 1000 | ||
| 271 | + * {"status":"success","data":{"resultType":"matrix", | ||
| 272 | + * "result":[{"metric":{"instance":"6bd124fa-4a28-4f29-82a9-a81c880a5b32"}, | ||
| 273 | + * "values":[[1683472020,"1.5090909090907871"],[1683472365,"1.418181818182191"], | ||
| 274 | + * [1683472710,"1.418181818182191"],[1683473055,"1.5090909090907871"],[1683473400,"1.4909090909085592"],[ | ||
| 275 | + * 1683473745,"1.3454545454549844"],[1683474090,"1.3272727272727707"],[1683474435,"1.5454545454535662"], | ||
| 276 | + * [1683474780,"1.2181818181819466"],[1683475125,"1.2545454545463883"],[1683475470,"1.399999999999153"], | ||
| 277 | + * [1683475815,"1.87272727272682"],[1683476160,"1.836363636364041"],[1683476505,"100"],[1683476850,"100"], | ||
| 278 | + * [1683477195,"1.45454545454578"],[1683477540,"1.5636363636374284"],[1683477885,"1.5454545454535662"], | ||
| 279 | + * [1683478230,"1.3272727272735807"],[1683478575,"1.7454545454546206"],[1683478920,"1.472727272728008"], | ||
| 280 | + * [1683479265,"1.4909090909085592"]]}]}} | ||
| 281 | + */ | ||
| 282 | + public Number[][] queryRange( | ||
| 283 | + String url, String port, String query, LocalDateTime startTime, | ||
| 284 | + LocalDateTime endTime) { | ||
| 285 | + Instant startInstant = startTime.toInstant(ZoneOffset.of("+8")); | ||
| 286 | + Instant endInstant = endTime.toInstant(ZoneOffset.of("+8")); | ||
| 287 | + int step = Math.max(Long.valueOf((endInstant.toEpochMilli() - startInstant.toEpochMilli()) / 250000).intValue(), | ||
| 288 | + 1); | ||
| 289 | + long start = startInstant.getEpochSecond(); | ||
| 290 | + long end = endInstant.getEpochSecond(); | ||
| 291 | + Map<String, Object> paramMap = new HashMap<>(); | ||
| 292 | + paramMap.put("query", query); | ||
| 293 | + paramMap.put("start", start); | ||
| 294 | + paramMap.put("end", end); | ||
| 295 | + paramMap.put("step", step); | ||
| 296 | + String httpUrl = "http://" + url + ":" + port + "/api/v1/query_range"; | ||
| 297 | + String res = HttpUtil.get(httpUrl, paramMap); | ||
| 298 | + if (StrUtil.isBlank(res)) { | ||
| 299 | + return new Number[0][0]; | ||
| 300 | + } | ||
| 301 | + JSONObject resJson = new JSONObject(res); | ||
| 302 | + if (!resJson.getStr("status", "").equals("success")) { | ||
| 303 | + return new Number[0][0]; | ||
| 304 | + } | ||
| 305 | + JSONObject data = resJson.getJSONObject("data"); | ||
| 306 | + if (data == null) { | ||
| 307 | + return new Number[0][0]; | ||
| 308 | + } | ||
| 309 | + JSONArray result = data.getJSONArray("result"); | ||
| 310 | + if (CollectionUtil.isEmpty(result)) { | ||
| 311 | + return new Number[0][0]; | ||
| 312 | + } | ||
| 313 | + JSONObject metricInfo = result.getJSONObject(0); | ||
| 314 | + if (metricInfo == null) { | ||
| 315 | + return new Number[0][0]; | ||
| 316 | + } | ||
| 317 | + JSONArray values = metricInfo.getJSONArray("values"); | ||
| 318 | + Number[][] dataResult = new Number[values.size()][2]; | ||
| 319 | + for (int i = 0; i < values.size(); i++) { | ||
| 320 | + JSONArray valArr = values.getJSONArray(i); | ||
| 321 | + dataResult[i][0] = valArr.getLong(0) * 1000; | ||
| 322 | + dataResult[i][1] = valArr.getBigDecimal(1).setScale(2, BigDecimal.ROUND_HALF_UP); | ||
| 323 | + } | ||
| 324 | + return dataResult; | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + public void updateRuleConfig(Collection<Long> templateIdList) { | ||
| 328 | + if (CollectionUtil.isEmpty(templateIdList)) { | ||
| 329 | + return; | ||
| 330 | + } | ||
| 331 | + initPrometheusEnvDto(); | ||
| 332 | + try { | ||
| 333 | + SshSession session = SshSession.connect(prometheusEnvDto.getPromIp(), prometheusEnvDto.getHostPort(), | ||
| 334 | + prometheusEnvDto.getPromUsername(), prometheusEnvDto.getPromPasswd()); | ||
| 335 | + for (Long templateId : templateIdList) { | ||
| 336 | + updateRuleConfig(session, templateId); | ||
| 337 | + } | ||
| 338 | + session.close(); | ||
| 339 | + } catch (IOException e) { | ||
| 340 | + log.error(e.getMessage(), e); | ||
| 341 | + throw new ServiceException("update the alert rule fail"); | ||
| 342 | + } | ||
| 343 | + } | ||
| 344 | + | ||
| 345 | + | ||
| 346 | + public void updateRuleConfig(Long templateId) { | ||
| 347 | + if (templateId == null) { | ||
| 348 | + return; | ||
| 349 | + } | ||
| 350 | + // 更新prometheus规则配置文件 | ||
| 351 | + try { | ||
| 352 | + initPrometheusEnvDto(); | ||
| 353 | + SshSession session = SshSession.connect(prometheusEnvDto.getPromIp(), prometheusEnvDto.getHostPort(), | ||
| 354 | + prometheusEnvDto.getPromUsername(), prometheusEnvDto.getPromPasswd()); | ||
| 355 | + updateRuleConfig(session, templateId); | ||
| 356 | + session.close(); | ||
| 357 | + } catch (IOException e) { | ||
| 358 | + log.error(e.getMessage(), e); | ||
| 359 | + throw new ServiceException("update the alert rule fail"); | ||
| 360 | + } | ||
| 361 | + } | ||
| 362 | + | ||
| 363 | + private void updateRuleConfig(SshSession session, Long templateId) throws IOException { | ||
| 364 | + List<AlertClusterNodeConf> alertClusterNodeConfs = clusterNodeConfMapper.selectList( | ||
| 365 | + Wrappers.<AlertClusterNodeConf>lambdaQuery().eq(AlertClusterNodeConf::getTemplateId, templateId).eq( | ||
| 366 | + AlertClusterNodeConf::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 367 | + | ||
| 368 | + AlertRuleConfigDto config = getAlertRuleConfigDto(session, templateId, alertClusterNodeConfs); | ||
| 369 | + String instances = alertClusterNodeConfs.stream().map(item -> item.getClusterNodeId()).collect( | ||
| 370 | + Collectors.joining("|")); | ||
| 371 | + List<AlertTemplateRule> alertTemplateRules = alertTemplateRuleMapper.selectList( | ||
| 372 | + Wrappers.<AlertTemplateRule>lambdaQuery().eq(AlertTemplateRule::getTemplateId, templateId)); | ||
| 373 | + if (checkAndUpdateRuleConfig(instances, config, alertTemplateRules)) { | ||
| 374 | + uploadFileConfig(session, config); | ||
| 375 | + } | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + private AlertRuleConfigDto getAlertRuleConfigDto( | ||
| 379 | + SshSession session, Long templateId, | ||
| 380 | + List<AlertClusterNodeConf> alertClusterNodeConfs) throws IOException { | ||
| 381 | + String ruleDir = alertProperty.getRuleFilePrefix().endsWith(CommonConstants.SLASH) | ||
| 382 | + ? alertProperty.getRuleFilePrefix().substring(0, | ||
| 383 | + alertProperty.getRuleFilePrefix().length() - 1) : alertProperty.getRuleFilePrefix(); | ||
| 384 | + | ||
| 385 | + String dirFileStr = session.execute("ls " + prometheusEnvDto.getPath()); | ||
| 386 | + String[] dirFileArr = dirFileStr.split(CommonConstants.LINE_FEED); | ||
| 387 | + String dir = prometheusEnvDto.getPath() + CommonConstants.SLASH + alertProperty.getRuleFilePrefix(); | ||
| 388 | + AlertRuleConfigDto config = new AlertRuleConfigDto(); | ||
| 389 | + if (!Arrays.asList(dirFileArr).contains(ruleDir)) { | ||
| 390 | + if (CollectionUtil.isEmpty(alertClusterNodeConfs)) { | ||
| 391 | + return config; | ||
| 392 | + } | ||
| 393 | + session.execute("mkdir " + dir); | ||
| 394 | + } | ||
| 395 | + String ruleFileStr = session.execute("ls " + dir); | ||
| 396 | + String fileName = "rule_template_" + templateId + alertProperty.getRuleFileSuffix(); | ||
| 397 | + String path = dir + fileName; | ||
| 398 | + if (StrUtil.isBlank(ruleFileStr)) { | ||
| 399 | + if (CollectionUtil.isEmpty(alertClusterNodeConfs)) { | ||
| 400 | + return config; | ||
| 401 | + } | ||
| 402 | + session.execute("touch " + path); | ||
| 403 | + } else { | ||
| 404 | + String[] ruleFileArr = ruleFileStr.split(CommonConstants.LINE_FEED); | ||
| 405 | + if (Arrays.asList(ruleFileArr).contains(fileName)) { | ||
| 406 | + if (CollectionUtil.isEmpty(alertClusterNodeConfs)) { | ||
| 407 | + // delete rule_template_xxx.yml | ||
| 408 | + session.execute("rm -f " + path); | ||
| 409 | + HttpUtil.post("http://" + prometheusEnvDto.getPromIp() + ":" + +prometheusEnvDto.getPromPort() | ||
| 410 | + + "/-/reload", ""); | ||
| 411 | + return config; | ||
| 412 | + } | ||
| 413 | + } else { | ||
| 414 | + session.execute("touch " + path); | ||
| 415 | + } | ||
| 416 | + } | ||
| 417 | + | ||
| 418 | + String ruleYmlStr = session.execute("cat " + path); | ||
| 419 | + Map map = YamlUtil.loadAs(ruleYmlStr, HashMap.class); | ||
| 420 | + if (map != null) { | ||
| 421 | + config = objectMapper.convertValue(map, AlertRuleConfigDto.class); | ||
| 422 | + } | ||
| 423 | + return config; | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + private boolean checkAndUpdateRuleConfig( | ||
| 427 | + String instances, AlertRuleConfigDto config, | ||
| 428 | + List<AlertTemplateRule> alertTemplateRules) { | ||
| 429 | + List<AlertRuleConfigDto.Group> groups = config.getGroups(); | ||
| 430 | + if (groups == null) { | ||
| 431 | + groups = new ArrayList<>(); | ||
| 432 | + config.setGroups(groups); | ||
| 433 | + } | ||
| 434 | + boolean isConfigChange = false; | ||
| 435 | + for (AlertTemplateRule alertTemplateRule : alertTemplateRules) { | ||
| 436 | + AlertRuleConfigDto.Group groupNew = templateRuleToPromRuleGroup(alertTemplateRule, instances); | ||
| 437 | + if (groups.size() == 0) { | ||
| 438 | + groups.add(groupNew); | ||
| 439 | + isConfigChange = true; | ||
| 440 | + continue; | ||
| 441 | + } | ||
| 442 | + List<String> groupNames = groups.stream().map(item -> item.getName()).collect(Collectors.toList()); | ||
| 443 | + if (!groupNames.contains(groupNew.getName())) { | ||
| 444 | + groups.add(groupNew); | ||
| 445 | + isConfigChange = true; | ||
| 446 | + continue; | ||
| 447 | + } | ||
| 448 | + for (int i = 0; i < groups.size(); i++) { | ||
| 449 | + AlertRuleConfigDto.Group group = groups.get(i); | ||
| 450 | + if (group.getName().equals(groupNew.getName()) && !group.toString().equals(groupNew.toString())) { | ||
| 451 | + groups.set(i, groupNew); | ||
| 452 | + isConfigChange = true; | ||
| 453 | + break; | ||
| 454 | + } | ||
| 455 | + } | ||
| 456 | + } | ||
| 457 | + return isConfigChange; | ||
| 458 | + } | ||
| 459 | + | ||
| 460 | + private AlertRuleConfigDto.Group templateRuleToPromRuleGroup( | ||
| 461 | + AlertTemplateRule alertTemplateRule, | ||
| 462 | + String instances) { | ||
| 463 | + List<AlertTemplateRuleItem> alertTemplateRuleItems = alertTemplateRuleItemMapper.selectList( | ||
| 464 | + Wrappers.<AlertTemplateRuleItem>lambdaQuery().eq(AlertTemplateRuleItem::getTemplateRuleId, | ||
| 465 | + alertTemplateRule.getId())); | ||
| 466 | + String ruleExpComb = alertTemplateRule.getRuleExpComb(); | ||
| 467 | + for (AlertTemplateRuleItem alertTemplateRuleItem : alertTemplateRuleItems) { | ||
| 468 | + ruleExpComb = ruleExpComb.replace(alertTemplateRuleItem.getRuleMark(), | ||
| 469 | + alertTemplateRuleItem.getRuleExp() + " " + alertTemplateRuleItem.getOperate() | ||
| 470 | + + alertTemplateRuleItem.getLimitValue()); | ||
| 471 | + } | ||
| 472 | + ruleExpComb = ruleExpComb.replaceAll("\\$\\{instances\\}", instances); | ||
| 473 | + AlertRuleConfigDto.Group groupNew = new AlertRuleConfigDto.Group(); | ||
| 474 | + String name = "rule_" + alertTemplateRule.getId(); | ||
| 475 | + groupNew.setName(name); | ||
| 476 | + AlertRuleConfigDto.Group.Rule rule = new AlertRuleConfigDto.Group.Rule(); | ||
| 477 | + rule.setAliasFor(alertTemplateRule.getNotifyDuration() + alertTemplateRule.getNotifyDurationUnit()); | ||
| 478 | + rule.setAlert(name); | ||
| 479 | + rule.setExpr(ruleExpComb); | ||
| 480 | + AlertRuleConfigDto.Group.Rule.Labels labels = new AlertRuleConfigDto.Group.Rule.Labels(); | ||
| 481 | + labels.setLevel(alertTemplateRule.getLevel()); | ||
| 482 | + labels.setTemplateId(alertTemplateRule.getTemplateId()); | ||
| 483 | + labels.setTemplateRuleId(alertTemplateRule.getId()); | ||
| 484 | + rule.setLabels(labels); | ||
| 485 | + AlertRuleConfigDto.Group.Rule.Annotations annotations = new AlertRuleConfigDto.Group.Rule.Annotations(); | ||
| 486 | + annotations.setSummary(alertTemplateRule.getRuleName()); | ||
| 487 | + annotations.setDescription( | ||
| 488 | + StrUtil.isBlank(alertTemplateRule.getAlertDesc()) ? "" : alertTemplateRule.getAlertDesc()); | ||
| 489 | + rule.setAnnotations(annotations); | ||
| 490 | + List<AlertRuleConfigDto.Group.Rule> rules = new ArrayList<>(); | ||
| 491 | + rules.add(rule); | ||
| 492 | + groupNew.setRules(rules); | ||
| 493 | + return groupNew; | ||
| 494 | + } | ||
| 495 | + | ||
| 496 | + public void updateAlertConfig(AlertConfig alertConfig, List<AlertConfig> delAlertConfigList) { | ||
| 497 | + try { | ||
| 498 | + if (StrUtil.isBlank(alertConfig.getAlertIp()) && StrUtil.isBlank(alertConfig.getAlertPort())) { | ||
| 499 | + throw new ServiceException("The alert IP or the alert Port is not empty!"); | ||
| 500 | + } | ||
| 501 | + initPrometheusEnvDto(); | ||
| 502 | + List<AlertConfig> configList = new ArrayList<>(); | ||
| 503 | + configList.add(alertConfig); | ||
| 504 | + prometheusEnvDto.setConfigList(configList).setDelConfigList(delAlertConfigList); | ||
| 505 | + | ||
| 506 | + SshSession session = SshSession.connect(prometheusEnvDto.getPromIp(), prometheusEnvDto.getHostPort(), | ||
| 507 | + prometheusEnvDto.getPromUsername(), prometheusEnvDto.getPromPasswd()); | ||
| 508 | + PrometheusConfigDto config = getPromConfig(); | ||
| 509 | + updatePromConfig(session, config); | ||
| 510 | + session.close(); | ||
| 511 | + } catch (IOException | NullPointerException e) { | ||
| 512 | + log.error(e.getMessage(), e); | ||
| 513 | + throw new ServiceException("update the alert config fail"); | ||
| 514 | + } | ||
| 515 | + } | ||
| 516 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertClusterNodeConfServiceImpl.java+186-0
| @@ -0,0 +1,186 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.bean.BeanUtil; | ||
| 8 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 9 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 10 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 11 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 12 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; | ||
| 13 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterNodeEntity; | ||
| 14 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 15 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 16 | +import org.opengauss.admin.system.service.ops.IOpsClusterNodeService; | ||
| 17 | +import org.opengauss.admin.system.service.ops.IOpsClusterService; | ||
| 18 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 19 | +import org.opengauss.plugin.alertcenter.dto.AlertClusterNodeConfDto; | ||
| 20 | +import org.opengauss.plugin.alertcenter.entity.AlertClusterNodeConf; | ||
| 21 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 22 | +import org.opengauss.plugin.alertcenter.mapper.AlertClusterNodeConfMapper; | ||
| 23 | +import org.opengauss.plugin.alertcenter.mapper.AlertConfigMapper; | ||
| 24 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateMapper; | ||
| 25 | +import org.opengauss.plugin.alertcenter.mapper.NctigbaEnvMapper; | ||
| 26 | +import org.opengauss.plugin.alertcenter.model.AlertClusterNodeAndTemplateReq; | ||
| 27 | +import org.opengauss.plugin.alertcenter.model.AlertClusterNodeConfReq; | ||
| 28 | +import org.opengauss.plugin.alertcenter.model.AlertTemplateReq; | ||
| 29 | +import org.opengauss.plugin.alertcenter.service.AlertClusterNodeConfService; | ||
| 30 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateService; | ||
| 31 | +import org.opengauss.plugin.alertcenter.service.PrometheusService; | ||
| 32 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 33 | +import org.springframework.stereotype.Service; | ||
| 34 | +import org.springframework.transaction.annotation.Transactional; | ||
| 35 | + | ||
| 36 | +import java.sql.Timestamp; | ||
| 37 | +import java.util.ArrayList; | ||
| 38 | +import java.util.Arrays; | ||
| 39 | +import java.util.HashSet; | ||
| 40 | +import java.util.List; | ||
| 41 | +import java.util.Set; | ||
| 42 | +import java.util.stream.Collectors; | ||
| 43 | + | ||
| 44 | +/** | ||
| 45 | + * wuyuebin | ||
| 46 | + * 2023/4/26 16:43 | ||
| 47 | + * | ||
| 48 | + */ | ||
| 49 | + | ||
| 50 | +public class AlertClusterNodeConfServiceImpl | ||
| 51 | + extends ServiceImpl<AlertClusterNodeConfMapper, AlertClusterNodeConf> | ||
| 52 | + implements AlertClusterNodeConfService { | ||
| 53 | + | ||
| 54 | + private AlertTemplateMapper templateMapper; | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + private NctigbaEnvMapper envMapper; | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + | ||
| 61 | + private IOpsClusterService clusterService; | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + | ||
| 65 | + private IOpsClusterNodeService clusterNodeService; | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + | ||
| 69 | + private HostFacade hostFacade; | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + private PrometheusService prometheusService; | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + private AlertTemplateService templateService; | ||
| 76 | + | ||
| 77 | + | ||
| 78 | + private AlertConfigMapper alertConfigMapper; | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + public void saveClusterNodeConf(AlertClusterNodeConfReq alertClusterNodeConfReq) { | ||
| 82 | + Long templateId = alertClusterNodeConfReq.getTemplateId(); | ||
| 83 | + String clusterNodeIds = alertClusterNodeConfReq.getClusterNodeIds(); | ||
| 84 | + String[] clusterNodeIdArr = clusterNodeIds.split(CommonConstants.DELIMITER); | ||
| 85 | + List<String> notNeedToUpdatedNodeIdList = new ArrayList<>(); | ||
| 86 | + Set<Long> needUpdatedTemplateIdSet = new HashSet<>(); | ||
| 87 | + // 检查是否已经配置模板 | ||
| 88 | + List<AlertClusterNodeConf> oldAlertClusterNodeConfList = this.baseMapper.selectList( | ||
| 89 | + Wrappers.<AlertClusterNodeConf>lambdaQuery().in(AlertClusterNodeConf::getClusterNodeId, | ||
| 90 | + clusterNodeIdArr).eq(AlertClusterNodeConf::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 91 | + if (CollectionUtil.isNotEmpty(oldAlertClusterNodeConfList)) { | ||
| 92 | + // remove the relation between the cluster node and the template | ||
| 93 | + List<AlertClusterNodeConf> delConfList = oldAlertClusterNodeConfList.stream().filter( | ||
| 94 | + item -> !item.getTemplateId().equals(templateId)).map(item -> { | ||
| 95 | + item.setIsDeleted(CommonConstants.IS_DELETE); | ||
| 96 | + return item; | ||
| 97 | + }).collect(Collectors.toList()); | ||
| 98 | + if (CollectionUtil.isNotEmpty(delConfList)) { | ||
| 99 | + Set<Long> set = delConfList.stream().map(item -> item.getTemplateId()).collect(Collectors.toSet()); | ||
| 100 | + needUpdatedTemplateIdSet.addAll(set); | ||
| 101 | + this.saveOrUpdateBatch(delConfList); | ||
| 102 | + } | ||
| 103 | + // get the cluster node which is not need to update | ||
| 104 | + List<String> nodeIdList = oldAlertClusterNodeConfList.stream().filter( | ||
| 105 | + item -> item.getTemplateId().equals(templateId)).map(item -> item.getClusterNodeId()).collect( | ||
| 106 | + Collectors.toList()); | ||
| 107 | + notNeedToUpdatedNodeIdList.addAll(nodeIdList); | ||
| 108 | + } | ||
| 109 | + List<AlertClusterNodeConf> alertClusterNodeConfList = Arrays.stream(clusterNodeIdArr).filter( | ||
| 110 | + item -> !notNeedToUpdatedNodeIdList.contains(item)).map( | ||
| 111 | + item -> new AlertClusterNodeConf().setClusterNodeId(item) | ||
| 112 | + .setTemplateId(alertClusterNodeConfReq.getTemplateId()) | ||
| 113 | + .setCreateTime(new Timestamp(System.currentTimeMillis())).setIsDeleted( | ||
| 114 | + CommonConstants.IS_NOT_DELETE)).collect(Collectors.toList()); | ||
| 115 | + | ||
| 116 | + if (CollectionUtil.isEmpty(alertClusterNodeConfList)) { | ||
| 117 | + return; | ||
| 118 | + } | ||
| 119 | + needUpdatedTemplateIdSet.add(templateId); | ||
| 120 | + // 保存数据库 | ||
| 121 | + this.saveBatch(alertClusterNodeConfList); | ||
| 122 | + // 更新prometheus规则配置文件 | ||
| 123 | + prometheusService.updateRuleConfig(needUpdatedTemplateIdSet); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + | ||
| 127 | + public AlertClusterNodeConf getByClusterNodeId(String clusterNodeId) { | ||
| 128 | + List<AlertClusterNodeConf> alertClusterNodeConfs = this.baseMapper.selectList( | ||
| 129 | + Wrappers.<AlertClusterNodeConf>lambdaQuery().eq(AlertClusterNodeConf::getClusterNodeId, | ||
| 130 | + clusterNodeId).eq(AlertClusterNodeConf::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 131 | + if (CollectionUtil.isEmpty(alertClusterNodeConfs)) { | ||
| 132 | + return new AlertClusterNodeConf(); | ||
| 133 | + } | ||
| 134 | + return alertClusterNodeConfs.get(0); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + public void saveAlertTemplateAndConfig(AlertClusterNodeAndTemplateReq clusterNodeAndTemplateReq) { | ||
| 140 | + AlertTemplateReq templateReq = new AlertTemplateReq(); | ||
| 141 | + BeanUtil.copyProperties(clusterNodeAndTemplateReq, templateReq); | ||
| 142 | + AlertTemplate alertTemplate = templateService.saveTemplate(templateReq); | ||
| 143 | + AlertClusterNodeConfReq alertClusterNodeConfReq = new AlertClusterNodeConfReq(); | ||
| 144 | + alertClusterNodeConfReq.setTemplateId(alertTemplate.getId()); | ||
| 145 | + alertClusterNodeConfReq.setClusterNodeIds(clusterNodeAndTemplateReq.getClusterNodeIds()); | ||
| 146 | + this.saveClusterNodeConf(alertClusterNodeConfReq); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + | ||
| 150 | + public List<AlertClusterNodeConfDto> getList() { | ||
| 151 | + List<AlertClusterNodeConfDto> dtoList = new ArrayList<>(); | ||
| 152 | + List<OpsClusterNodeEntity> list = clusterNodeService.list(); | ||
| 153 | + Set<String> hostIdSet = list.stream().map(item -> item.getHostId()).collect(Collectors.toSet()); | ||
| 154 | + List<OpsHostEntity> opsHostEntities = hostFacade.listByIds(hostIdSet); | ||
| 155 | + List<String> clusterIdList = list.stream().map(item -> item.getClusterId()).collect(Collectors.toList()); | ||
| 156 | + List<OpsClusterEntity> opsClusterEntities = clusterService.listByIds(clusterIdList); | ||
| 157 | + List<String> nodeIdList = list.stream().map(item -> item.getClusterNodeId()).collect(Collectors.toList()); | ||
| 158 | + List<AlertClusterNodeConf> alertClusterNodeConfs = this.baseMapper.selectList( | ||
| 159 | + Wrappers.<AlertClusterNodeConf>lambdaQuery().in(CollectionUtil.isNotEmpty(nodeIdList), | ||
| 160 | + AlertClusterNodeConf::getClusterNodeId, nodeIdList).eq(AlertClusterNodeConf::getIsDeleted, | ||
| 161 | + CommonConstants.IS_NOT_DELETE)); | ||
| 162 | + for (OpsClusterNodeEntity clusterNode : list) { | ||
| 163 | + OpsHostEntity opsHostEntity = | ||
| 164 | + opsHostEntities.stream().filter( | ||
| 165 | + item -> item.getHostId().equals(clusterNode.getHostId())).findFirst().get(); | ||
| 166 | + OpsClusterEntity opsClusterEntity = | ||
| 167 | + opsClusterEntities.stream().filter( | ||
| 168 | + item -> item.getClusterId().equals(clusterNode.getClusterId())).findFirst().get(); | ||
| 169 | + String nodeName = opsClusterEntity.getClusterId() + "/" + opsHostEntity.getPublicIp() + ":" | ||
| 170 | + + opsClusterEntity.getPort() + "(" + clusterNode.getClusterRole() + ")"; | ||
| 171 | + AlertClusterNodeConfDto clusterNodeConfDto = new AlertClusterNodeConfDto(); | ||
| 172 | + clusterNodeConfDto.setClusterNodeId(clusterNode.getClusterNodeId()).setNodeName(nodeName); | ||
| 173 | + List<AlertClusterNodeConf> clusterNodeConfs = alertClusterNodeConfs.stream().filter( | ||
| 174 | + item -> item.getClusterNodeId().equals(clusterNode.getClusterNodeId())).collect( | ||
| 175 | + Collectors.toList()); | ||
| 176 | + if (CollectionUtil.isNotEmpty(clusterNodeConfs)) { | ||
| 177 | + AlertClusterNodeConf alertClusterNodeConf = clusterNodeConfs.get(0); | ||
| 178 | + AlertTemplate alertTemplate = templateMapper.selectById(alertClusterNodeConf.getTemplateId()); | ||
| 179 | + clusterNodeConfDto.setTemplateId(alertClusterNodeConf.getTemplateId()).setTemplateName( | ||
| 180 | + alertTemplate.getTemplateName()); | ||
| 181 | + } | ||
| 182 | + dtoList.add(clusterNodeConfDto); | ||
| 183 | + } | ||
| 184 | + return dtoList; | ||
| 185 | + } | ||
| 186 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertConfigServiceImpl.java+40-0
| @@ -0,0 +1,40 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 9 | +import org.opengauss.plugin.alertcenter.entity.AlertConfig; | ||
| 10 | +import org.opengauss.plugin.alertcenter.mapper.AlertConfigMapper; | ||
| 11 | +import org.opengauss.plugin.alertcenter.service.AlertConfigService; | ||
| 12 | +import org.opengauss.plugin.alertcenter.service.PrometheusService; | ||
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 14 | +import org.springframework.stereotype.Service; | ||
| 15 | +import org.springframework.transaction.annotation.Transactional; | ||
| 16 | + | ||
| 17 | +import java.util.List; | ||
| 18 | +import java.util.stream.Collectors; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * wuyuebin | ||
| 22 | + * 2023/6/6 17:18 | ||
| 23 | + * | ||
| 24 | + */ | ||
| 25 | + | ||
| 26 | +public class AlertConfigServiceImpl extends ServiceImpl<AlertConfigMapper, AlertConfig> implements AlertConfigService { | ||
| 27 | + | ||
| 28 | + private PrometheusService prometheusService; | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + public void saveAlertConf(AlertConfig alertConfig) { | ||
| 33 | + List<AlertConfig> list = this.list(); | ||
| 34 | + if (CollectionUtil.isNotEmpty(list)) { | ||
| 35 | + this.removeBatchByIds(list.stream().map(item -> item.getId()).collect(Collectors.toList())); | ||
| 36 | + } | ||
| 37 | + this.saveOrUpdate(alertConfig); | ||
| 38 | + prometheusService.updateAlertConfig(alertConfig, list); | ||
| 39 | + } | ||
| 40 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertRecordServiceImpl.java+329-0
| @@ -0,0 +1,329 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.bean.BeanUtil; | ||
| 8 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 9 | +import cn.hutool.core.util.StrUtil; | ||
| 10 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 11 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 12 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 13 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 14 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 15 | +import com.gitee.starblues.bootstrap.annotation.AutowiredType; | ||
| 16 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterEntity; | ||
| 17 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsClusterNodeEntity; | ||
| 18 | +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; | ||
| 19 | +import org.opengauss.admin.system.plugin.facade.HostFacade; | ||
| 20 | +import org.opengauss.admin.system.service.ops.IOpsClusterNodeService; | ||
| 21 | +import org.opengauss.admin.system.service.ops.IOpsClusterService; | ||
| 22 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 23 | +import org.opengauss.plugin.alertcenter.dto.AlertRecordDto; | ||
| 24 | +import org.opengauss.plugin.alertcenter.dto.AlertRelationDto; | ||
| 25 | +import org.opengauss.plugin.alertcenter.dto.AlertStatisticsDto; | ||
| 26 | +import org.opengauss.plugin.alertcenter.entity.AlertRecord; | ||
| 27 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 28 | +import org.opengauss.plugin.alertcenter.entity.NctigbaEnv; | ||
| 29 | +import org.opengauss.plugin.alertcenter.mapper.AlertRecordMapper; | ||
| 30 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemMapper; | ||
| 31 | +import org.opengauss.plugin.alertcenter.mapper.NctigbaEnvMapper; | ||
| 32 | +import org.opengauss.plugin.alertcenter.model.AlertRecordReq; | ||
| 33 | +import org.opengauss.plugin.alertcenter.model.AlertStatisticsReq; | ||
| 34 | +import org.opengauss.plugin.alertcenter.service.AlertRecordService; | ||
| 35 | +import org.opengauss.plugin.alertcenter.service.PrometheusService; | ||
| 36 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 37 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 38 | +import org.springframework.stereotype.Service; | ||
| 39 | + | ||
| 40 | +import java.time.LocalDateTime; | ||
| 41 | +import java.time.format.DateTimeFormatter; | ||
| 42 | +import java.util.ArrayList; | ||
| 43 | +import java.util.List; | ||
| 44 | +import java.util.Map; | ||
| 45 | +import java.util.stream.Collectors; | ||
| 46 | + | ||
| 47 | +import static org.opengauss.plugin.alertcenter.constant.CommonConstants.FIRING_STATUS; | ||
| 48 | +import static org.opengauss.plugin.alertcenter.constant.CommonConstants.READ_STATUS; | ||
| 49 | +import static org.opengauss.plugin.alertcenter.constant.CommonConstants.UNREAD_STATUS; | ||
| 50 | + | ||
| 51 | +/** | ||
| 52 | + * wuyuebin | ||
| 53 | + * 2023/5/17 10:35 | ||
| 54 | + * | ||
| 55 | + */ | ||
| 56 | + | ||
| 57 | +public class AlertRecordServiceImpl extends ServiceImpl<AlertRecordMapper, AlertRecord> implements AlertRecordService { | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + private IOpsClusterService clusterService; | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + private IOpsClusterNodeService clusterNodeService; | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + private HostFacade hostFacade; | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + private AlertTemplateRuleItemMapper templateRuleItemMapper; | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + private PrometheusService prometheusService; | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + private NctigbaEnvMapper envMapper; | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + public Page<AlertRecordDto> getListPage(AlertRecordReq alertRecordReq, Page page) { | ||
| 81 | + LocalDateTime startTime = StrUtil.isNotBlank(alertRecordReq.getStartTime()) ? LocalDateTime.parse( | ||
| 82 | + alertRecordReq.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null; | ||
| 83 | + LocalDateTime endTime = StrUtil.isNotBlank(alertRecordReq.getEndTime()) ? LocalDateTime.parse( | ||
| 84 | + alertRecordReq.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null; | ||
| 85 | + String clusterNodeId = alertRecordReq.getClusterNodeId(); | ||
| 86 | + Page<AlertRecord> recordPage = this.baseMapper.selectPage(page, Wrappers.<AlertRecord>lambdaQuery() | ||
| 87 | + .eq(StrUtil.isNotBlank(clusterNodeId), AlertRecord::getClusterNodeId, clusterNodeId) | ||
| 88 | + .in(StrUtil.isNotBlank(alertRecordReq.getAlertStatus()), AlertRecord::getAlertStatus, | ||
| 89 | + alertRecordReq.getAlertStatus().split(CommonConstants.DELIMITER)) | ||
| 90 | + .in(StrUtil.isNotBlank(alertRecordReq.getRecordStatus()), AlertRecord::getRecordStatus, | ||
| 91 | + alertRecordReq.getRecordStatus().split(CommonConstants.DELIMITER)) | ||
| 92 | + .in(StrUtil.isNotBlank(alertRecordReq.getAlertLevel()), AlertRecord::getLevel, | ||
| 93 | + alertRecordReq.getAlertLevel().split(CommonConstants.DELIMITER)) | ||
| 94 | + .ge(startTime != null, AlertRecord::getStartTime, startTime) | ||
| 95 | + .le(endTime != null, AlertRecord::getEndTime, endTime).orderByDesc(AlertRecord::getId)); | ||
| 96 | + List<AlertRecord> records = recordPage.getRecords(); | ||
| 97 | + Page<AlertRecordDto> recordDtoPage = new Page<>(); | ||
| 98 | + recordDtoPage.setTotal(recordPage.getTotal()).setCurrent(recordPage.getCurrent()).setSize(recordPage.getSize()); | ||
| 99 | + if (CollectionUtil.isEmpty(records)) { | ||
| 100 | + recordDtoPage.setRecords(new ArrayList<>()); | ||
| 101 | + return recordDtoPage; | ||
| 102 | + } | ||
| 103 | + List<String> clusterNodeIdList = records.stream().map(item -> clusterNodeId).collect(Collectors.toList()); | ||
| 104 | + List<OpsClusterNodeEntity> opsClusterNodeEntities = clusterNodeService.listByIds(clusterNodeIdList); | ||
| 105 | + List<String> hostIds = opsClusterNodeEntities.stream().map(item -> item.getHostId()).collect( | ||
| 106 | + Collectors.toList()); | ||
| 107 | + List<String> clusterIds = opsClusterNodeEntities.stream().map(item -> item.getClusterId()).collect( | ||
| 108 | + Collectors.toList()); | ||
| 109 | + List<OpsHostEntity> opsHostEntities = hostFacade.listByIds(hostIds); | ||
| 110 | + List<OpsClusterEntity> opsClusterEntities = clusterService.listByIds(clusterIds); | ||
| 111 | + | ||
| 112 | + List<AlertRecordDto> list = new ArrayList<>(); | ||
| 113 | + for (AlertRecord record : records) { | ||
| 114 | + list.add(alertRecordToDto(record, opsClusterNodeEntities, opsHostEntities, opsClusterEntities)); | ||
| 115 | + } | ||
| 116 | + recordDtoPage.setRecords(list); | ||
| 117 | + return recordDtoPage; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + private AlertRecordDto alertRecordToDto( | ||
| 121 | + AlertRecord record, List<OpsClusterNodeEntity> opsClusterNodeEntities, | ||
| 122 | + List<OpsHostEntity> opsHostEntities, List<OpsClusterEntity> opsClusterEntities) { | ||
| 123 | + AlertRecordDto alertRecordDto = new AlertRecordDto(); | ||
| 124 | + BeanUtil.copyProperties(record, alertRecordDto); | ||
| 125 | + String clusterNodeId0 = record.getClusterNodeId(); | ||
| 126 | + OpsClusterNodeEntity opsClusterNodeEntity = opsClusterNodeEntities.stream().filter( | ||
| 127 | + item -> item.getClusterNodeId().equals(clusterNodeId0)).findFirst().get(); | ||
| 128 | + OpsHostEntity opsHostEntity = opsHostEntities.stream().filter( | ||
| 129 | + item -> item.getHostId().equals(opsClusterNodeEntity.getHostId())).findFirst().get(); | ||
| 130 | + OpsClusterEntity opsClusterEntity = opsClusterEntities.stream().filter( | ||
| 131 | + item -> item.getClusterId().equals(opsClusterNodeEntity.getClusterId())).findFirst().get(); | ||
| 132 | + String nodeName = opsClusterEntity.getClusterId() + "/" + opsHostEntity.getPublicIp() + ":" | ||
| 133 | + + opsClusterEntity.getPort() + "(" + opsClusterNodeEntity.getClusterRole() + ")"; | ||
| 134 | + alertRecordDto.setClusterNodeName(nodeName).setClusterId(opsClusterEntity.getClusterId()).setHostIpAndPort( | ||
| 135 | + opsHostEntity.getPublicIp() + ":" + opsClusterEntity.getPort()).setNodeRole( | ||
| 136 | + opsClusterNodeEntity.getClusterRole().name()); | ||
| 137 | + return alertRecordDto; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + | ||
| 141 | + public AlertStatisticsDto alertRecordStatistics(AlertStatisticsReq alertStatisticsReq) { | ||
| 142 | + LocalDateTime startTime = StrUtil.isNotBlank(alertStatisticsReq.getStartTime()) ? LocalDateTime.parse( | ||
| 143 | + alertStatisticsReq.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null; | ||
| 144 | + LocalDateTime endTime = StrUtil.isNotBlank(alertStatisticsReq.getEndTime()) ? LocalDateTime.parse( | ||
| 145 | + alertStatisticsReq.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null; | ||
| 146 | + Long total = this.baseMapper.selectCount( | ||
| 147 | + Wrappers.<AlertRecord>lambdaQuery().eq(StrUtil.isNotBlank(alertStatisticsReq.getClusterNodeId()), | ||
| 148 | + AlertRecord::getClusterNodeId, alertStatisticsReq.getClusterNodeId()) | ||
| 149 | + .ge(startTime != null, AlertRecord::getStartTime, startTime) | ||
| 150 | + .le(endTime != null, AlertRecord::getEndTime, endTime)); | ||
| 151 | + | ||
| 152 | + AlertStatisticsDto alertStatisticsDto = new AlertStatisticsDto(); | ||
| 153 | + alertStatisticsDto.setTotalNum(total.intValue()); | ||
| 154 | + AlertStatisticsDto statusCountStatistics = setAndGetAlertStatusCount(alertStatisticsReq.getClusterNodeId(), | ||
| 155 | + startTime, endTime); | ||
| 156 | + alertStatisticsDto.setFiringNum(statusCountStatistics.getFiringNum()).setRecoverNum( | ||
| 157 | + statusCountStatistics.getRecoverNum()); | ||
| 158 | + | ||
| 159 | + AlertStatisticsDto recordStatusCountStatistics = | ||
| 160 | + setAndGetRecordStatusCount(alertStatisticsReq.getClusterNodeId(), startTime, endTime); | ||
| 161 | + alertStatisticsDto.setUnReadNum(recordStatusCountStatistics.getUnReadNum()).setReadNum( | ||
| 162 | + recordStatusCountStatistics.getReadNum()); | ||
| 163 | + | ||
| 164 | + AlertStatisticsDto levelCountStatistics = setAndGetLevelCount(alertStatisticsReq.getClusterNodeId(), | ||
| 165 | + startTime, endTime); | ||
| 166 | + alertStatisticsDto.setSeriousNum(levelCountStatistics.getSeriousNum()).setWarnNum( | ||
| 167 | + levelCountStatistics.getWarnNum()).setInfoNum(levelCountStatistics.getInfoNum()); | ||
| 168 | + | ||
| 169 | + return alertStatisticsDto; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + private AlertStatisticsDto setAndGetAlertStatusCount( | ||
| 173 | + String clusterNodeId, LocalDateTime startTime, | ||
| 174 | + LocalDateTime endTime) { | ||
| 175 | + QueryWrapper<AlertRecord> queryWrapper = new QueryWrapper<>(); | ||
| 176 | + queryWrapper.select("alert_status as alertStatus,count(1) count").eq( | ||
| 177 | + StrUtil.isNotBlank(clusterNodeId), "cluster_node_id", clusterNodeId) | ||
| 178 | + .ge(startTime != null, "start_time", startTime) | ||
| 179 | + .le(endTime != null, "end_time", endTime).groupBy("alert_status"); | ||
| 180 | + List<Map<String, Object>> alertStatusMaps = this.listMaps(queryWrapper); | ||
| 181 | + AlertStatisticsDto alertStatisticsDto = new AlertStatisticsDto(); | ||
| 182 | + for (Map<String, Object> alertStatusMap : alertStatusMaps) { | ||
| 183 | + int count = 0; | ||
| 184 | + if (alertStatusMap.get("count") instanceof Long) { | ||
| 185 | + count = ((Long) alertStatusMap.get("count")).intValue(); | ||
| 186 | + } | ||
| 187 | + if (alertStatusMap.get("alertstatus").equals(FIRING_STATUS)) { | ||
| 188 | + alertStatisticsDto.setFiringNum(count); | ||
| 189 | + } else { | ||
| 190 | + alertStatisticsDto.setRecoverNum(count); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + return alertStatisticsDto; | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + private AlertStatisticsDto setAndGetRecordStatusCount( | ||
| 197 | + String clusterNodeId, LocalDateTime startTime, | ||
| 198 | + LocalDateTime endTime) { | ||
| 199 | + QueryWrapper<AlertRecord> queryWrapper = new QueryWrapper<>(); | ||
| 200 | + queryWrapper.select("record_status as recordStatus,count(1) count").eq( | ||
| 201 | + StrUtil.isNotBlank(clusterNodeId), "cluster_node_id", | ||
| 202 | + clusterNodeId) | ||
| 203 | + .ge(startTime != null, "start_time", startTime) | ||
| 204 | + .le(endTime != null, "end_time", endTime).groupBy("record_status"); | ||
| 205 | + List<Map<String, Object>> recordStatusMaps = this.listMaps(queryWrapper); | ||
| 206 | + AlertStatisticsDto alertStatisticsDto = new AlertStatisticsDto(); | ||
| 207 | + for (Map<String, Object> recordStatusMap : recordStatusMaps) { | ||
| 208 | + int count = 0; | ||
| 209 | + if (recordStatusMap.get("count") instanceof Long) { | ||
| 210 | + count = ((Long) recordStatusMap.get("count")).intValue(); | ||
| 211 | + } | ||
| 212 | + if (recordStatusMap.get("recordstatus").equals(FIRING_STATUS)) { | ||
| 213 | + alertStatisticsDto.setUnReadNum(count); | ||
| 214 | + } else { | ||
| 215 | + alertStatisticsDto.setReadNum(count); | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + return alertStatisticsDto; | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + private AlertStatisticsDto setAndGetLevelCount( | ||
| 222 | + String clusterNodeId, LocalDateTime startTime, | ||
| 223 | + LocalDateTime endTime) { | ||
| 224 | + QueryWrapper<AlertRecord> queryWrapper = new QueryWrapper<>(); | ||
| 225 | + queryWrapper.select("level ,count(1) count").eq(StrUtil.isNotBlank(clusterNodeId), | ||
| 226 | + "cluster_node_id", clusterNodeId) | ||
| 227 | + .ge(startTime != null, "start_time", startTime) | ||
| 228 | + .le(endTime != null, "end_time", endTime).groupBy("level"); | ||
| 229 | + List<Map<String, Object>> levelMaps = this.listMaps(queryWrapper); | ||
| 230 | + AlertStatisticsDto alertStatisticsDto = new AlertStatisticsDto(); | ||
| 231 | + for (Map<String, Object> levelMap : levelMaps) { | ||
| 232 | + int count = 0; | ||
| 233 | + if (levelMap.get("count") instanceof Long) { | ||
| 234 | + count = ((Long) levelMap.get("count")).intValue(); | ||
| 235 | + } | ||
| 236 | + if (levelMap.get("level").equals(CommonConstants.SERIOUS)) { | ||
| 237 | + alertStatisticsDto.setSeriousNum(count); | ||
| 238 | + } else if (levelMap.get("level").equals(CommonConstants.WARN)) { | ||
| 239 | + alertStatisticsDto.setWarnNum(count); | ||
| 240 | + } else { | ||
| 241 | + alertStatisticsDto.setInfoNum(count); | ||
| 242 | + } | ||
| 243 | + } | ||
| 244 | + return alertStatisticsDto; | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + | ||
| 248 | + public String markAsRead(String ids) { | ||
| 249 | + String[] idArr = ids.split(CommonConstants.DELIMITER); | ||
| 250 | + LambdaUpdateWrapper<AlertRecord> updateWrapper = new LambdaUpdateWrapper<>(); | ||
| 251 | + updateWrapper.in(AlertRecord::getId, idArr); | ||
| 252 | + updateWrapper.set(AlertRecord::getRecordStatus, READ_STATUS).set(AlertRecord::getUpdateTime, | ||
| 253 | + LocalDateTime.now()); | ||
| 254 | + update(null, updateWrapper); | ||
| 255 | + return "success"; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + | ||
| 259 | + public AlertRecordDto getById(Long id) { | ||
| 260 | + AlertRecordDto alertRecordDto = new AlertRecordDto(); | ||
| 261 | + AlertRecord alertRecord = this.baseMapper.selectById(id); | ||
| 262 | + if (alertRecord == null) { | ||
| 263 | + return alertRecordDto; | ||
| 264 | + } | ||
| 265 | + BeanUtil.copyProperties(alertRecord, alertRecordDto); | ||
| 266 | + String clusterNodeId = alertRecordDto.getClusterNodeId(); | ||
| 267 | + OpsHostEntity opsHostEntity = new OpsHostEntity(); | ||
| 268 | + OpsClusterEntity opsClusterEntity = new OpsClusterEntity(); | ||
| 269 | + OpsClusterNodeEntity opsClusterNodeEntity = clusterNodeService.getById(clusterNodeId); | ||
| 270 | + if (opsClusterNodeEntity == null) { | ||
| 271 | + opsClusterNodeEntity = new OpsClusterNodeEntity(); | ||
| 272 | + } | ||
| 273 | + if (StrUtil.isNotBlank(opsClusterNodeEntity.getHostId())) { | ||
| 274 | + opsHostEntity = hostFacade.getById(opsClusterNodeEntity.getHostId()); | ||
| 275 | + } | ||
| 276 | + if (StrUtil.isNotBlank(opsClusterNodeEntity.getClusterId())) { | ||
| 277 | + opsClusterEntity = clusterService.getById(opsClusterNodeEntity.getClusterId()); | ||
| 278 | + } | ||
| 279 | + String nodeName = | ||
| 280 | + opsClusterEntity.getClusterId() + "/" + opsHostEntity.getPublicIp() + ":" + opsClusterEntity.getPort() | ||
| 281 | + + "(" + opsClusterNodeEntity.getClusterRole() + ")"; | ||
| 282 | + alertRecordDto.setClusterNodeName(nodeName).setHostIpAndPort( | ||
| 283 | + opsHostEntity.getPublicIp() + ":" + opsClusterEntity.getPort()).setClusterId( | ||
| 284 | + opsClusterEntity.getClusterId()).setNodeRole(opsClusterNodeEntity.getClusterRole().name()); | ||
| 285 | + return alertRecordDto; | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + | ||
| 289 | + public List<AlertRelationDto> getRelationData(Long id) { | ||
| 290 | + MessageSourceUtil.reset(); | ||
| 291 | + AlertRecord alertRecord = this.baseMapper.selectById(id); | ||
| 292 | + Long templateRuleId = alertRecord.getTemplateRuleId(); | ||
| 293 | + List<AlertTemplateRuleItem> templateRuleItems = templateRuleItemMapper.selectList( | ||
| 294 | + Wrappers.<AlertTemplateRuleItem>lambdaQuery().eq(AlertTemplateRuleItem::getTemplateRuleId, | ||
| 295 | + templateRuleId)); | ||
| 296 | + List<AlertRelationDto> relationDtoList = new ArrayList<>(); | ||
| 297 | + NctigbaEnv promEnv = envMapper | ||
| 298 | + .selectOne(Wrappers.<NctigbaEnv>lambdaQuery().eq(NctigbaEnv::getType, NctigbaEnv.Type.PROMETHEUS)); | ||
| 299 | + OpsHostEntity opsHostEntity = hostFacade.getById(promEnv.getHostid()); | ||
| 300 | + for (AlertTemplateRuleItem templateRuleItem : templateRuleItems) { | ||
| 301 | + AlertRelationDto relationDto = new AlertRelationDto(); | ||
| 302 | + relationDto.setName(MessageSourceUtil.get(templateRuleItem.getRuleExpName())).setUnit( | ||
| 303 | + templateRuleItem.getUnit()).setStartTime(alertRecord.getStartTime()).setEndTime( | ||
| 304 | + alertRecord.getEndTime()); | ||
| 305 | + // 向前推30分钟,向后推30分钟 | ||
| 306 | + LocalDateTime minTime = alertRecord.getStartTime().minusMinutes(30L); | ||
| 307 | + LocalDateTime maxTime = alertRecord.getEndTime().plusMinutes(30L); | ||
| 308 | + relationDto.setMinTime(minTime).setMaxTime(maxTime); | ||
| 309 | + String ruleExp = templateRuleItem.getRuleExp(); | ||
| 310 | + ruleExp = ruleExp.replace("${instances}", alertRecord.getClusterNodeId()); | ||
| 311 | + Number[][] datas = prometheusService.queryRange(opsHostEntity.getPublicIp(), promEnv.getPort().toString(), | ||
| 312 | + ruleExp, minTime, maxTime); | ||
| 313 | + relationDto.setDatas(datas).setLimitValue(templateRuleItem.getLimitValue()); | ||
| 314 | + relationDtoList.add(relationDto); | ||
| 315 | + } | ||
| 316 | + return relationDtoList; | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + | ||
| 320 | + public String markAsUnread(String ids) { | ||
| 321 | + String[] idArr = ids.split(CommonConstants.DELIMITER); | ||
| 322 | + LambdaUpdateWrapper<AlertRecord> updateWrapper = new LambdaUpdateWrapper<>(); | ||
| 323 | + updateWrapper.in(AlertRecord::getId, idArr); | ||
| 324 | + updateWrapper.set(AlertRecord::getRecordStatus, UNREAD_STATUS).set(AlertRecord::getUpdateTime, | ||
| 325 | + LocalDateTime.now()); | ||
| 326 | + update(null, updateWrapper); | ||
| 327 | + return "success"; | ||
| 328 | + } | ||
| 329 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertRuleServiceImpl.java+177-0
| @@ -0,0 +1,177 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.bean.BeanUtil; | ||
| 8 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 9 | +import cn.hutool.core.util.StrUtil; | ||
| 10 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 11 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 12 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 13 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 14 | +import org.opengauss.plugin.alertcenter.config.properties.AlertProperty; | ||
| 15 | +import org.opengauss.plugin.alertcenter.config.properties.RuleItemProperty; | ||
| 16 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 17 | +import org.opengauss.plugin.alertcenter.dto.AlertRuleDto; | ||
| 18 | +import org.opengauss.plugin.alertcenter.dto.RuleItemPropertyDto; | ||
| 19 | +import org.opengauss.plugin.alertcenter.entity.AlertRule; | ||
| 20 | +import org.opengauss.plugin.alertcenter.entity.AlertRuleItem; | ||
| 21 | +import org.opengauss.plugin.alertcenter.entity.AlertRuleItemParam; | ||
| 22 | +import org.opengauss.plugin.alertcenter.mapper.AlertRuleItemMapper; | ||
| 23 | +import org.opengauss.plugin.alertcenter.mapper.AlertRuleItemParamMapper; | ||
| 24 | +import org.opengauss.plugin.alertcenter.mapper.AlertRuleMapper; | ||
| 25 | +import org.opengauss.plugin.alertcenter.model.RuleReq; | ||
| 26 | +import org.opengauss.plugin.alertcenter.service.AlertRuleService; | ||
| 27 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 28 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 29 | +import org.springframework.stereotype.Service; | ||
| 30 | + | ||
| 31 | +import java.util.ArrayList; | ||
| 32 | +import java.util.List; | ||
| 33 | +import java.util.stream.Collectors; | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | + * wuyuebin | ||
| 37 | + * 2023/5/9 10:13 | ||
| 38 | + * | ||
| 39 | + */ | ||
| 40 | + | ||
| 41 | +public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements AlertRuleService { | ||
| 42 | + | ||
| 43 | + private AlertProperty alertProperty; | ||
| 44 | + | ||
| 45 | + private AlertRuleItemMapper alertRuleItemMapper; | ||
| 46 | + | ||
| 47 | + private AlertRuleItemParamMapper ruleItemParamMapper; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + public Page<AlertRuleDto> getRulePage(RuleReq ruleReq, Page page) { | ||
| 51 | + MessageSourceUtil.reset(); | ||
| 52 | + Page<AlertRuleDto> ruleDtoPage = new Page<>(); | ||
| 53 | + Page<AlertRule> alertRulePage = this.baseMapper.selectPage(page, Wrappers.<AlertRule>lambdaQuery() | ||
| 54 | + .like(StrUtil.isNotBlank(ruleReq.getRuleName()), AlertRule::getRuleName, ruleReq.getRuleName()) | ||
| 55 | + .eq(StrUtil.isNotBlank(ruleReq.getRuleType()), AlertRule::getRuleType, ruleReq.getRuleType()) | ||
| 56 | + .eq(StrUtil.isNotBlank(ruleReq.getLevel()), AlertRule::getLevel, ruleReq.getLevel()).orderByDesc( | ||
| 57 | + AlertRule::getId)); | ||
| 58 | + ruleDtoPage.setSize(alertRulePage.getSize()).setTotal(alertRulePage.getTotal()).setCurrent( | ||
| 59 | + alertRulePage.getCurrent()); | ||
| 60 | + List<AlertRule> records = alertRulePage.getRecords(); | ||
| 61 | + if (CollectionUtil.isEmpty(records)) { | ||
| 62 | + ruleDtoPage.setRecords(new ArrayList<>()); | ||
| 63 | + return ruleDtoPage; | ||
| 64 | + } | ||
| 65 | + List<Long> ruleIdList = records.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 66 | + List<AlertRuleItem> alertRuleItems = alertRuleItemMapper.selectList( | ||
| 67 | + Wrappers.<AlertRuleItem>lambdaQuery().in(AlertRuleItem::getRuleId, ruleIdList).eq( | ||
| 68 | + AlertRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 69 | + List<Long> itemIdList = alertRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 70 | + List<AlertRuleItemParam> itemParamList = ruleItemParamMapper.selectList( | ||
| 71 | + Wrappers.<AlertRuleItemParam>lambdaQuery().in(AlertRuleItemParam::getItemId, itemIdList).eq( | ||
| 72 | + AlertRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 73 | + List<AlertRuleDto> list = new ArrayList<>(); | ||
| 74 | + for (AlertRule record : records) { | ||
| 75 | + AlertRuleDto ruleDto = new AlertRuleDto(); | ||
| 76 | + BeanUtil.copyProperties(record, ruleDto); | ||
| 77 | + List<AlertRuleItem> ruleItems = alertRuleItems.stream().filter( | ||
| 78 | + item -> item.getRuleId().equals(record.getId())).collect(Collectors.toList()); | ||
| 79 | + String ruleExpDesc = ruleItems.stream().map(item -> { | ||
| 80 | + List<String> paramVals = itemParamList.stream().filter( | ||
| 81 | + item0 -> item0.getItemId().equals(item.getId())).map(item0 -> item0.getParamValue()).collect( | ||
| 82 | + Collectors.toList()); | ||
| 83 | + return "[" + item.getRuleMark() + "]:" + MessageSourceUtil.get(item.getRuleExpName()) | ||
| 84 | + + (CollectionUtil.isNotEmpty(paramVals) | ||
| 85 | + ? "(" + paramVals.stream().collect(Collectors.joining(CommonConstants.DELIMITER)) + ")" : "") | ||
| 86 | + + " " + (item.getAction().equals("normal") | ||
| 87 | + ? MessageSourceUtil.get("rule.ruleItem.normalAction") + " " + item.getOperate() | ||
| 88 | + + item.getLimitValue() + (StrUtil.isNotBlank( | ||
| 89 | + item.getUnit()) ? item.getUnit() : "") : item.getAction().equals( | ||
| 90 | + "increase") ? MessageSourceUtil.get("rule.ruleItem.increaseAction") : MessageSourceUtil.get( | ||
| 91 | + "rule.ruleItem.decreaseAction")); | ||
| 92 | + }).collect(Collectors.joining("<br/>")); | ||
| 93 | + ruleDto.setRuleExpDesc(ruleExpDesc); | ||
| 94 | + list.add(ruleDto); | ||
| 95 | + } | ||
| 96 | + ruleDtoPage.setRecords(list); | ||
| 97 | + return ruleDtoPage; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + | ||
| 101 | + public AlertRule getRuleById(Long id) { | ||
| 102 | + MessageSourceUtil.reset(); | ||
| 103 | + AlertRule alertRule = this.baseMapper.selectById(id); | ||
| 104 | + if (alertRule == null) { | ||
| 105 | + throw new ServiceException("the rule is not found"); | ||
| 106 | + } | ||
| 107 | + alertRule.setRuleName(MessageSourceUtil.get(alertRule.getRuleName())); | ||
| 108 | + List<AlertRuleItem> alertRuleItems = alertRuleItemMapper.selectList( | ||
| 109 | + Wrappers.<AlertRuleItem>lambdaQuery().eq(AlertRuleItem::getRuleId, id)); | ||
| 110 | + List<Long> itemIdList = alertRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 111 | + List<AlertRuleItemParam> itemParamList = ruleItemParamMapper.selectList( | ||
| 112 | + Wrappers.<AlertRuleItemParam>lambdaQuery().in(AlertRuleItemParam::getItemId, itemIdList).eq( | ||
| 113 | + AlertRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 114 | + for (AlertRuleItem alertRuleItem : alertRuleItems) { | ||
| 115 | + List<AlertRuleItemParam> params = itemParamList.stream().filter( | ||
| 116 | + item -> item.getItemId().equals(alertRuleItem.getId())).collect(Collectors.toList()); | ||
| 117 | + alertRuleItem.setItemParamList(params); | ||
| 118 | + } | ||
| 119 | + alertRule.setAlertRuleItemList(alertRuleItems); | ||
| 120 | + return alertRule; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + | ||
| 124 | + public List<RuleItemPropertyDto> getRuleItemProperties() { | ||
| 125 | + MessageSourceUtil.reset(); | ||
| 126 | + List<RuleItemPropertyDto> ruleItemDtoList = new ArrayList<>(); | ||
| 127 | + List<RuleItemProperty> ruleItems = alertProperty.getRuleItems(); | ||
| 128 | + for (RuleItemProperty ruleItem : ruleItems) { | ||
| 129 | + RuleItemPropertyDto ruleItemPropertyDto = new RuleItemPropertyDto(); | ||
| 130 | + BeanUtil.copyProperties(ruleItem, ruleItemPropertyDto); | ||
| 131 | + String name = ruleItemPropertyDto.getName(); | ||
| 132 | + ruleItemPropertyDto.setI18nName(MessageSourceUtil.get(name)); | ||
| 133 | + ruleItemDtoList.add(ruleItemPropertyDto); | ||
| 134 | + } | ||
| 135 | + return ruleItemDtoList; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + public List<AlertRuleDto> getRuleList() { | ||
| 140 | + MessageSourceUtil.reset(); | ||
| 141 | + List<AlertRule> alertRules = | ||
| 142 | + this.baseMapper.selectList(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getIsDeleted, | ||
| 143 | + CommonConstants.IS_NOT_DELETE).orderByDesc(AlertRule::getId)); | ||
| 144 | + List<Long> ruleIdList = alertRules.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 145 | + List<AlertRuleItem> alertRuleItems = alertRuleItemMapper.selectList( | ||
| 146 | + Wrappers.<AlertRuleItem>lambdaQuery().in(AlertRuleItem::getRuleId, ruleIdList).eq( | ||
| 147 | + AlertRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 148 | + List<Long> itemIdList = alertRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 149 | + List<AlertRuleItemParam> itemParamList = ruleItemParamMapper.selectList( | ||
| 150 | + Wrappers.<AlertRuleItemParam>lambdaQuery().in(AlertRuleItemParam::getItemId, itemIdList).eq( | ||
| 151 | + AlertRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 152 | + List<AlertRuleDto> list = new ArrayList<>(); | ||
| 153 | + for (AlertRule alertRule : alertRules) { | ||
| 154 | + AlertRuleDto ruleDto = new AlertRuleDto(); | ||
| 155 | + BeanUtil.copyProperties(alertRule, ruleDto); | ||
| 156 | + List<AlertRuleItem> ruleItems = alertRuleItems.stream().filter( | ||
| 157 | + item -> item.getRuleId().equals(alertRule.getId())).collect(Collectors.toList()); | ||
| 158 | + String ruleExpDesc = ruleItems.stream().map(item -> { | ||
| 159 | + List<String> paramVals = itemParamList.stream().filter( | ||
| 160 | + item0 -> item0.getItemId().equals(item.getId())).map(item0 -> item0.getParamValue()).collect( | ||
| 161 | + Collectors.toList()); | ||
| 162 | + return "[" + item.getRuleMark() + "]:" + MessageSourceUtil.get(item.getRuleExpName()) | ||
| 163 | + + (CollectionUtil.isNotEmpty(paramVals) | ||
| 164 | + ? "(" + paramVals.stream().collect(Collectors.joining(CommonConstants.DELIMITER)) + ")" : "") | ||
| 165 | + + " " + (item.getAction().equals("normal") | ||
| 166 | + ? MessageSourceUtil.get("rule.ruleItem.normalAction") + " " + item.getOperate() | ||
| 167 | + + item.getLimitValue() + (StrUtil.isNotBlank( | ||
| 168 | + item.getUnit()) ? item.getUnit() : "") : item.getAction().equals( | ||
| 169 | + "increase") ? MessageSourceUtil.get("rule.ruleItem.increaseAction") : MessageSourceUtil.get( | ||
| 170 | + "rule.ruleItem.decreaseAction")); | ||
| 171 | + }).collect(Collectors.joining("<br/>")); | ||
| 172 | + ruleDto.setRuleExpDesc(ruleExpDesc); | ||
| 173 | + list.add(ruleDto); | ||
| 174 | + } | ||
| 175 | + return list; | ||
| 176 | + } | ||
| 177 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertTemplateRuleItemParamServiceImpl.java+22-0
| @@ -0,0 +1,22 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItemParam; | ||
| 9 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemParamMapper; | ||
| 10 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleItemParamService; | ||
| 11 | +import org.springframework.stereotype.Service; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/6/5 19:25 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | +public class AlertTemplateRuleItemParamServiceImpl | ||
| 20 | + extends ServiceImpl<AlertTemplateRuleItemParamMapper, AlertTemplateRuleItemParam> | ||
| 21 | + implements AlertTemplateRuleItemParamService { | ||
| 22 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertTemplateRuleItemServiceImpl.java+27-0
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 8 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 9 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemMapper; | ||
| 10 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleItemService; | ||
| 11 | +import org.springframework.stereotype.Service; | ||
| 12 | + | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * wuyuebin | ||
| 17 | + * 2023/5/24 10:40 | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | +public class AlertTemplateRuleItemServiceImpl extends ServiceImpl<AlertTemplateRuleItemMapper, AlertTemplateRuleItem> | ||
| 22 | + implements AlertTemplateRuleItemService { | ||
| 23 | + | ||
| 24 | + public void saveOrUpdateList(List<AlertTemplateRuleItem> templateRuleItems) { | ||
| 25 | + this.saveOrUpdateBatch(templateRuleItems); | ||
| 26 | + } | ||
| 27 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertTemplateRuleServiceImpl.java+155-0
| @@ -0,0 +1,155 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.bean.BeanUtil; | ||
| 8 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 9 | +import cn.hutool.core.util.StrUtil; | ||
| 10 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 11 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 12 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 13 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 14 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateRuleDto; | ||
| 15 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 16 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 17 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItemParam; | ||
| 18 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemMapper; | ||
| 19 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemParamMapper; | ||
| 20 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleMapper; | ||
| 21 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleItemParamService; | ||
| 22 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleItemService; | ||
| 23 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleService; | ||
| 24 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 25 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 26 | +import org.springframework.stereotype.Service; | ||
| 27 | + | ||
| 28 | +import java.time.LocalDateTime; | ||
| 29 | +import java.util.ArrayList; | ||
| 30 | +import java.util.List; | ||
| 31 | +import java.util.stream.Collectors; | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * wuyuebin | ||
| 35 | + * 2023/5/24 10:32 | ||
| 36 | + * | ||
| 37 | + */ | ||
| 38 | + | ||
| 39 | +public class AlertTemplateRuleServiceImpl extends ServiceImpl<AlertTemplateRuleMapper, AlertTemplateRule> | ||
| 40 | + implements AlertTemplateRuleService { | ||
| 41 | + | ||
| 42 | + private AlertTemplateRuleItemMapper alertTemplateRuleItemMapper; | ||
| 43 | + | ||
| 44 | + private AlertTemplateRuleItemService templateRuleItemService; | ||
| 45 | + | ||
| 46 | + private AlertTemplateRuleItemParamMapper ruleItemParamMapper; | ||
| 47 | + | ||
| 48 | + private AlertTemplateRuleItemParamService ruleItemParamService; | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + public AlertTemplateRule getTemplateRule(Long templateRuleId) { | ||
| 52 | + AlertTemplateRule alertTemplateRule = this.baseMapper.selectById(templateRuleId); | ||
| 53 | + if (alertTemplateRule == null) { | ||
| 54 | + throw new ServiceException("the rule is not found"); | ||
| 55 | + } | ||
| 56 | + List<AlertTemplateRuleItem> alertTemplateRuleItems = alertTemplateRuleItemMapper.selectList( | ||
| 57 | + Wrappers.<AlertTemplateRuleItem>lambdaQuery().eq(AlertTemplateRuleItem::getTemplateRuleId, | ||
| 58 | + alertTemplateRule.getId())); | ||
| 59 | + List<Long> itemIdList = alertTemplateRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 60 | + List<AlertTemplateRuleItemParam> itemParamList = ruleItemParamMapper.selectList( | ||
| 61 | + Wrappers.<AlertTemplateRuleItemParam>lambdaQuery().in(AlertTemplateRuleItemParam::getItemId, | ||
| 62 | + itemIdList).eq(AlertTemplateRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 63 | + for (AlertTemplateRuleItem alertRuleItem : alertTemplateRuleItems) { | ||
| 64 | + List<AlertTemplateRuleItemParam> params = itemParamList.stream().filter( | ||
| 65 | + item -> item.getItemId().equals(alertRuleItem.getId())).collect(Collectors.toList()); | ||
| 66 | + alertRuleItem.setItemParamList(params); | ||
| 67 | + } | ||
| 68 | + alertTemplateRule.setAlertRuleItemList(alertTemplateRuleItems); | ||
| 69 | + return alertTemplateRule; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + public AlertTemplateRuleDto saveTemplateRule(AlertTemplateRule alertTemplateRule) { | ||
| 74 | + MessageSourceUtil.reset(); | ||
| 75 | + AlertTemplateRuleDto templateRuleDto = new AlertTemplateRuleDto(); | ||
| 76 | + if (alertTemplateRule.getId() == null) { | ||
| 77 | + alertTemplateRule.setCreateTime(LocalDateTime.now()); | ||
| 78 | + } else { | ||
| 79 | + alertTemplateRule.setUpdateTime(LocalDateTime.now()); | ||
| 80 | + } | ||
| 81 | + this.saveOrUpdate(alertTemplateRule); | ||
| 82 | + List<AlertTemplateRuleItem> templateRuleItemList = alertTemplateRule.getAlertRuleItemList(); | ||
| 83 | + if (CollectionUtil.isEmpty(templateRuleItemList)) { | ||
| 84 | + BeanUtil.copyProperties(alertTemplateRule, templateRuleDto); | ||
| 85 | + return templateRuleDto; | ||
| 86 | + } | ||
| 87 | + for (AlertTemplateRuleItem templateRuleItem : templateRuleItemList) { | ||
| 88 | + templateRuleItem.setTemplateRuleId(alertTemplateRule.getId()); | ||
| 89 | + if (templateRuleItem.getId() == null) { | ||
| 90 | + templateRuleItem.setCreateTime(LocalDateTime.now()); | ||
| 91 | + } else { | ||
| 92 | + templateRuleItem.setUpdateTime(LocalDateTime.now()); | ||
| 93 | + } | ||
| 94 | + templateRuleItemService.saveOrUpdate(templateRuleItem); | ||
| 95 | + List<AlertTemplateRuleItemParam> itemParamList = templateRuleItem.getItemParamList(); | ||
| 96 | + if (CollectionUtil.isEmpty(itemParamList)) { | ||
| 97 | + continue; | ||
| 98 | + } | ||
| 99 | + for (AlertTemplateRuleItemParam itemParam : itemParamList) { | ||
| 100 | + itemParam.setItemId(templateRuleItem.getId()); | ||
| 101 | + if (itemParam.getId() == null) { | ||
| 102 | + itemParam.setCreateTime(LocalDateTime.now()); | ||
| 103 | + } else { | ||
| 104 | + itemParam.setUpdateTime(LocalDateTime.now()); | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + ruleItemParamService.saveOrUpdateBatch(itemParamList); | ||
| 108 | + } | ||
| 109 | + BeanUtil.copyProperties(alertTemplateRule, templateRuleDto); | ||
| 110 | + templateRuleDto.buildRuleExpDesc(); | ||
| 111 | + return templateRuleDto; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + | ||
| 115 | + public List<AlertTemplateRuleDto> getDtoListByTemplateId(Long templateId) { | ||
| 116 | + MessageSourceUtil.reset(); | ||
| 117 | + List<AlertTemplateRule> alertRules = | ||
| 118 | + this.baseMapper.selectList( | ||
| 119 | + Wrappers.<AlertTemplateRule>lambdaQuery().eq(AlertTemplateRule::getTemplateId, templateId).eq( | ||
| 120 | + AlertTemplateRule::getIsDeleted, CommonConstants.IS_NOT_DELETE).orderByDesc( | ||
| 121 | + AlertTemplateRule::getId)); | ||
| 122 | + List<Long> ruleIdList = alertRules.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 123 | + List<AlertTemplateRuleItem> alertRuleItems = alertTemplateRuleItemMapper.selectList( | ||
| 124 | + Wrappers.<AlertTemplateRuleItem>lambdaQuery().in(AlertTemplateRuleItem::getTemplateRuleId, | ||
| 125 | + ruleIdList).eq(AlertTemplateRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 126 | + List<Long> itemIdList = alertRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 127 | + List<AlertTemplateRuleItemParam> itemParamList = ruleItemParamMapper.selectList( | ||
| 128 | + Wrappers.<AlertTemplateRuleItemParam>lambdaQuery().in(AlertTemplateRuleItemParam::getItemId, | ||
| 129 | + itemIdList).eq(AlertTemplateRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 130 | + List<AlertTemplateRuleDto> list = new ArrayList<>(); | ||
| 131 | + for (AlertTemplateRule alertRule : alertRules) { | ||
| 132 | + AlertTemplateRuleDto ruleDto = new AlertTemplateRuleDto(); | ||
| 133 | + BeanUtil.copyProperties(alertRule, ruleDto); | ||
| 134 | + List<AlertTemplateRuleItem> ruleItems = alertRuleItems.stream().filter( | ||
| 135 | + item -> item.getTemplateRuleId().equals(alertRule.getId())).collect(Collectors.toList()); | ||
| 136 | + String ruleExpDesc = ruleItems.stream().map(item -> { | ||
| 137 | + List<String> paramVals = itemParamList.stream().filter( | ||
| 138 | + item0 -> item0.getItemId().equals(item.getId())).map(item0 -> item0.getParamValue()).collect( | ||
| 139 | + Collectors.toList()); | ||
| 140 | + return "[" + item.getRuleMark() + "]:" + MessageSourceUtil.get(item.getRuleExpName()) | ||
| 141 | + + (CollectionUtil.isNotEmpty(paramVals) | ||
| 142 | + ? "(" + paramVals.stream().collect(Collectors.joining(CommonConstants.DELIMITER)) + ")" : "") | ||
| 143 | + + " " + (item.getAction().equals("normal") | ||
| 144 | + ? MessageSourceUtil.get("rule.ruleItem.normalAction") + " " + item.getOperate() | ||
| 145 | + + item.getLimitValue() + (StrUtil.isNotBlank( | ||
| 146 | + item.getUnit()) ? item.getUnit() : "") : item.getAction().equals( | ||
| 147 | + "increase") ? MessageSourceUtil.get("rule.ruleItem.increaseAction") : MessageSourceUtil.get( | ||
| 148 | + "rule.ruleItem.decreaseAction")); | ||
| 149 | + }).collect(Collectors.joining("<br/>")); | ||
| 150 | + ruleDto.setRuleExpDesc(ruleExpDesc); | ||
| 151 | + list.add(ruleDto); | ||
| 152 | + } | ||
| 153 | + return list; | ||
| 154 | + } | ||
| 155 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/AlertTemplateServiceImpl.java+314-0
| @@ -0,0 +1,314 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.bean.BeanUtil; | ||
| 8 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 9 | +import cn.hutool.core.util.StrUtil; | ||
| 10 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 11 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 12 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 13 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 14 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 15 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 16 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateDto; | ||
| 17 | +import org.opengauss.plugin.alertcenter.dto.AlertTemplateRuleDto; | ||
| 18 | +import org.opengauss.plugin.alertcenter.entity.AlertClusterNodeConf; | ||
| 19 | +import org.opengauss.plugin.alertcenter.entity.AlertRule; | ||
| 20 | +import org.opengauss.plugin.alertcenter.entity.AlertRuleItem; | ||
| 21 | +import org.opengauss.plugin.alertcenter.entity.AlertRuleItemParam; | ||
| 22 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplate; | ||
| 23 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 24 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItem; | ||
| 25 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRuleItemParam; | ||
| 26 | +import org.opengauss.plugin.alertcenter.mapper.AlertRuleItemMapper; | ||
| 27 | +import org.opengauss.plugin.alertcenter.mapper.AlertRuleItemParamMapper; | ||
| 28 | +import org.opengauss.plugin.alertcenter.mapper.AlertRuleMapper; | ||
| 29 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateMapper; | ||
| 30 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemMapper; | ||
| 31 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleItemParamMapper; | ||
| 32 | +import org.opengauss.plugin.alertcenter.mapper.AlertTemplateRuleMapper; | ||
| 33 | +import org.opengauss.plugin.alertcenter.model.AlertTemplateReq; | ||
| 34 | +import org.opengauss.plugin.alertcenter.model.AlertTemplateRuleReq; | ||
| 35 | +import org.opengauss.plugin.alertcenter.service.AlertClusterNodeConfService; | ||
| 36 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleItemParamService; | ||
| 37 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleService; | ||
| 38 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateService; | ||
| 39 | +import org.opengauss.plugin.alertcenter.service.PrometheusService; | ||
| 40 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 41 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 42 | +import org.springframework.stereotype.Service; | ||
| 43 | +import org.springframework.transaction.annotation.Transactional; | ||
| 44 | + | ||
| 45 | +import java.time.LocalDateTime; | ||
| 46 | +import java.util.ArrayList; | ||
| 47 | +import java.util.List; | ||
| 48 | +import java.util.stream.Collectors; | ||
| 49 | + | ||
| 50 | +/** | ||
| 51 | + * wuyuebin | ||
| 52 | + * 2023/5/12 11:55 | ||
| 53 | + * | ||
| 54 | + */ | ||
| 55 | + | ||
| 56 | +public class AlertTemplateServiceImpl extends ServiceImpl<AlertTemplateMapper, AlertTemplate> | ||
| 57 | + implements AlertTemplateService { | ||
| 58 | + | ||
| 59 | + private AlertRuleMapper alertRuleMapper; | ||
| 60 | + | ||
| 61 | + private AlertRuleItemMapper alertRuleItemMapper; | ||
| 62 | + | ||
| 63 | + private AlertRuleItemParamMapper ruleItemParamMapper; | ||
| 64 | + | ||
| 65 | + private AlertTemplateRuleMapper alertTemplateRuleMapper; | ||
| 66 | + | ||
| 67 | + private AlertTemplateRuleItemMapper alertTemplateRuleItemMapper; | ||
| 68 | + | ||
| 69 | + private PrometheusService prometheusService; | ||
| 70 | + | ||
| 71 | + private AlertTemplateRuleService templateRuleService; | ||
| 72 | + | ||
| 73 | + private AlertTemplateRuleItemParamMapper tRuleItemParamMapper; | ||
| 74 | + | ||
| 75 | + private AlertTemplateRuleItemParamService templateRuleItemParamService; | ||
| 76 | + | ||
| 77 | + | ||
| 78 | + private AlertClusterNodeConfService nodeConfService; | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + public Page<AlertTemplate> getTemplatePage(String templateName, Page page) { | ||
| 82 | + return this.baseMapper.selectPage(page, | ||
| 83 | + Wrappers.<AlertTemplate>lambdaQuery().like(StrUtil.isNotBlank(templateName), | ||
| 84 | + AlertTemplate::getTemplateName, templateName).eq(AlertTemplate::getIsDeleted, | ||
| 85 | + CommonConstants.IS_NOT_DELETE).orderByDesc(AlertTemplate::getId)); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + | ||
| 89 | + public Page<AlertTemplateRuleDto> getTemplateRulePage(Long templateId, String ruleName, Page page) { | ||
| 90 | + MessageSourceUtil.reset(); | ||
| 91 | + Page<AlertTemplateRuleDto> ruleDtoPage = new Page<>(); | ||
| 92 | + Page<AlertTemplateRule> rulePage = alertTemplateRuleMapper.selectPage(page, | ||
| 93 | + Wrappers.<AlertTemplateRule>lambdaQuery().eq(AlertTemplateRule::getTemplateId, templateId).like( | ||
| 94 | + StrUtil.isNotBlank(ruleName), AlertTemplateRule::getRuleName, ruleName).eq( | ||
| 95 | + AlertTemplateRule::getIsDeleted, CommonConstants.IS_NOT_DELETE).orderByDesc( | ||
| 96 | + AlertTemplateRule::getId)); | ||
| 97 | + ruleDtoPage.setSize(rulePage.getSize()).setTotal(rulePage.getTotal()).setCurrent(rulePage.getCurrent()); | ||
| 98 | + List<AlertTemplateRule> records = rulePage.getRecords(); | ||
| 99 | + if (CollectionUtil.isEmpty(records)) { | ||
| 100 | + ruleDtoPage.setRecords(new ArrayList<>()); | ||
| 101 | + return ruleDtoPage; | ||
| 102 | + } | ||
| 103 | + List<Long> ruleIdList = records.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 104 | + List<AlertTemplateRuleItem> alertTemplateRuleItems = alertTemplateRuleItemMapper.selectList( | ||
| 105 | + Wrappers.<AlertTemplateRuleItem>lambdaQuery().in(AlertTemplateRuleItem::getTemplateRuleId, | ||
| 106 | + ruleIdList).eq(AlertTemplateRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 107 | + List<Long> itemIdList = alertTemplateRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 108 | + List<AlertTemplateRuleItemParam> itemParamList = tRuleItemParamMapper.selectList( | ||
| 109 | + Wrappers.<AlertTemplateRuleItemParam>lambdaQuery().in(AlertTemplateRuleItemParam::getItemId, | ||
| 110 | + itemIdList).eq(AlertTemplateRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 111 | + List<AlertTemplateRuleDto> ruleDtoList = new ArrayList<>(); | ||
| 112 | + for (AlertTemplateRule record : records) { | ||
| 113 | + AlertTemplateRuleDto ruleDto = new AlertTemplateRuleDto(); | ||
| 114 | + BeanUtil.copyProperties(record, ruleDto); | ||
| 115 | + List<AlertTemplateRuleItem> templateRuleItems = alertTemplateRuleItems.stream().filter( | ||
| 116 | + item -> item.getTemplateRuleId().equals(record.getId())).collect(Collectors.toList()); | ||
| 117 | + String ruleExpDesc = templateRuleItems.stream().map(item -> { | ||
| 118 | + List<String> paramVals = itemParamList.stream().filter( | ||
| 119 | + item0 -> item0.getItemId().equals(item.getId())).map(item0 -> item0.getParamValue()).collect( | ||
| 120 | + Collectors.toList()); | ||
| 121 | + return "[" + item.getRuleMark() + "]:" + MessageSourceUtil.get(item.getRuleExpName()) | ||
| 122 | + + (CollectionUtil.isNotEmpty(paramVals) | ||
| 123 | + ? "(" + paramVals.stream().collect(Collectors.joining(CommonConstants.DELIMITER)) + ")" : "") | ||
| 124 | + + " " + (item.getAction().equals("normal") | ||
| 125 | + ? MessageSourceUtil.get("rule.ruleItem.normalAction") + " " + item.getOperate() | ||
| 126 | + + item.getLimitValue() + (StrUtil.isNotBlank( | ||
| 127 | + item.getUnit()) ? item.getUnit() : "") : item.getAction().equals( | ||
| 128 | + "increase") ? MessageSourceUtil.get("rule.ruleItem.increaseAction") : MessageSourceUtil.get( | ||
| 129 | + "rule.ruleItem.decreaseAction")); | ||
| 130 | + }).collect(Collectors.joining("<br/>")); | ||
| 131 | + ruleDto.setRuleExpDesc(ruleExpDesc); | ||
| 132 | + ruleDtoList.add(ruleDto); | ||
| 133 | + } | ||
| 134 | + ruleDtoPage.setRecords(ruleDtoList); | ||
| 135 | + return ruleDtoPage; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + | ||
| 140 | + public AlertTemplateDto getTemplate(Long id) { | ||
| 141 | + AlertTemplate alertTemplate = this.baseMapper.selectById(id); | ||
| 142 | + AlertTemplateDto templateDto = new AlertTemplateDto(); | ||
| 143 | + BeanUtil.copyProperties(alertTemplate, templateDto); | ||
| 144 | + List<AlertTemplateRuleDto> ruleDtoList = templateRuleService.getDtoListByTemplateId(id); | ||
| 145 | + templateDto.setTemplateRuleDtoList(ruleDtoList); | ||
| 146 | + return templateDto; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + | ||
| 150 | + | ||
| 151 | + public AlertTemplate saveTemplate(AlertTemplateReq templateReq) { | ||
| 152 | + AlertTemplate alertTemplate = null; | ||
| 153 | + if (templateReq.getId() != null) { | ||
| 154 | + alertTemplate = this.baseMapper.selectById(templateReq.getId()); | ||
| 155 | + } | ||
| 156 | + if (alertTemplate == null) { | ||
| 157 | + alertTemplate = new AlertTemplate(); | ||
| 158 | + BeanUtil.copyProperties(templateReq, alertTemplate); | ||
| 159 | + alertTemplate.setCreateTime(LocalDateTime.now()).setIsDeleted(0); | ||
| 160 | + } else { | ||
| 161 | + alertTemplate.setTemplateName(templateReq.getTemplateName()).setUpdateTime( | ||
| 162 | + LocalDateTime.now()).setIsDeleted(0); | ||
| 163 | + } | ||
| 164 | + saveOrUpdate(alertTemplate); | ||
| 165 | + | ||
| 166 | + List<AlertTemplateRuleReq> templateRuleReqList = templateReq.getTemplateRuleReqList(); | ||
| 167 | + List<Long> templateRuleIds = templateRuleReqList.stream().map(item -> item.getTemplateRuleId()).filter( | ||
| 168 | + item -> item != null).collect(Collectors.toList()); | ||
| 169 | + // 删除不需要的规则 | ||
| 170 | + List<AlertTemplateRule> alertTemplateRules = alertTemplateRuleMapper.selectList( | ||
| 171 | + Wrappers.<AlertTemplateRule>lambdaQuery().eq(AlertTemplateRule::getTemplateId, | ||
| 172 | + alertTemplate.getId()).notIn(CollectionUtil.isNotEmpty(templateRuleIds), | ||
| 173 | + AlertTemplateRule::getId, templateRuleIds)); | ||
| 174 | + alertTemplateRules.forEach(item -> { | ||
| 175 | + item.setIsDeleted(CommonConstants.IS_DELETE); | ||
| 176 | + alertTemplateRuleMapper.updateById(item); | ||
| 177 | + alertTemplateRuleItemMapper.update(null, | ||
| 178 | + new LambdaUpdateWrapper<AlertTemplateRuleItem>().set(AlertTemplateRuleItem::getIsDeleted, | ||
| 179 | + CommonConstants.IS_DELETE).set(AlertTemplateRuleItem::getUpdateTime, LocalDateTime.now()) | ||
| 180 | + .eq(AlertTemplateRuleItem::getTemplateRuleId, item.getId()) | ||
| 181 | + .eq(AlertTemplateRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 182 | + }); | ||
| 183 | + for (AlertTemplateRuleReq alertTemplateRuleReq : templateRuleReqList) { | ||
| 184 | + updateByAlertTemplateRuleReq(alertTemplateRuleReq, alertTemplate.getId()); | ||
| 185 | + } | ||
| 186 | + return alertTemplate; | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + private void updateByAlertTemplateRuleReq(AlertTemplateRuleReq alertTemplateRuleReq, Long templateId) { | ||
| 190 | + if (alertTemplateRuleReq.getTemplateRuleId() == null) { | ||
| 191 | + AlertRule alertRule = alertRuleMapper.selectById(alertTemplateRuleReq.getRuleId()); | ||
| 192 | + AlertTemplateRule alertTemplateRule = new AlertTemplateRule(); | ||
| 193 | + BeanUtil.copyProperties(alertRule, alertTemplateRule); | ||
| 194 | + alertTemplateRule.setId(null).setTemplateId(templateId).setRuleId( | ||
| 195 | + alertRule.getId()).setIsDeleted(0).setCreateTime(LocalDateTime.now()).setUpdateTime(null); | ||
| 196 | + alertTemplateRuleMapper.insert(alertTemplateRule); | ||
| 197 | + List<AlertRuleItem> alertRuleItems = alertRuleItemMapper.selectList( | ||
| 198 | + Wrappers.<AlertRuleItem>lambdaQuery().eq(AlertRuleItem::getRuleId, alertRule.getId()).eq( | ||
| 199 | + AlertRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 200 | + for (AlertRuleItem alertRuleItem : alertRuleItems) { | ||
| 201 | + AlertTemplateRuleItem templateRuleItem = new AlertTemplateRuleItem(); | ||
| 202 | + BeanUtil.copyProperties(alertRuleItem, templateRuleItem); | ||
| 203 | + templateRuleItem.setId(null).setTemplateRuleId(alertTemplateRule.getId()).setRuleItemId( | ||
| 204 | + alertRuleItem.getId()).setIsDeleted(0).setCreateTime(LocalDateTime.now()).setUpdateTime(null); | ||
| 205 | + alertTemplateRuleItemMapper.insert(templateRuleItem); | ||
| 206 | + List<AlertRuleItemParam> itemParamList = ruleItemParamMapper.selectList( | ||
| 207 | + Wrappers.<AlertRuleItemParam>lambdaQuery().eq(AlertRuleItemParam::getItemId, | ||
| 208 | + alertRuleItem.getId()).eq(AlertRuleItemParam::getIsDeleted, | ||
| 209 | + CommonConstants.IS_NOT_DELETE)); | ||
| 210 | + if (CollectionUtil.isEmpty(itemParamList)) { | ||
| 211 | + continue; | ||
| 212 | + } | ||
| 213 | + List<AlertTemplateRuleItemParam> tItemParamList = new ArrayList<>(); | ||
| 214 | + for (AlertRuleItemParam alertRuleItemParam : itemParamList) { | ||
| 215 | + AlertTemplateRuleItemParam tRuleItemParam = new AlertTemplateRuleItemParam(); | ||
| 216 | + BeanUtil.copyProperties(alertRuleItemParam, tRuleItemParam); | ||
| 217 | + tRuleItemParam.setId(null).setItemId(templateRuleItem.getId()).setCreateTime( | ||
| 218 | + LocalDateTime.now()).setIsDeleted(CommonConstants.IS_NOT_DELETE); | ||
| 219 | + tItemParamList.add(tRuleItemParam); | ||
| 220 | + } | ||
| 221 | + templateRuleItemParamService.saveBatch(tItemParamList); | ||
| 222 | + } | ||
| 223 | + } else { | ||
| 224 | + AlertTemplateRule alertTemplateRule = alertTemplateRuleMapper.selectById( | ||
| 225 | + alertTemplateRuleReq.getTemplateRuleId()); | ||
| 226 | + alertTemplateRule.setTemplateId(templateId); | ||
| 227 | + alertTemplateRuleMapper.updateById(alertTemplateRule); | ||
| 228 | + } | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + | ||
| 232 | + public List<AlertTemplate> getTemplateList() { | ||
| 233 | + return this.baseMapper.selectList(Wrappers.<AlertTemplate>lambdaQuery().eq(AlertTemplate::getIsDeleted, | ||
| 234 | + CommonConstants.IS_NOT_DELETE).orderByDesc(AlertTemplate::getId)); | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + | ||
| 238 | + public List<AlertTemplateRuleDto> getTemplateRuleListById(Long templateId) { | ||
| 239 | + MessageSourceUtil.reset(); | ||
| 240 | + List<AlertTemplateRuleDto> ruleDtoList = new ArrayList<>(); | ||
| 241 | + List<AlertTemplateRule> templateRuleList = | ||
| 242 | + alertTemplateRuleMapper.selectList( | ||
| 243 | + Wrappers.<AlertTemplateRule>lambdaQuery().eq(AlertTemplateRule::getTemplateId, templateId).eq( | ||
| 244 | + AlertTemplateRule::getIsDeleted, CommonConstants.IS_NOT_DELETE).orderByDesc( | ||
| 245 | + AlertTemplateRule::getId)); | ||
| 246 | + if (CollectionUtil.isEmpty(templateRuleList)) { | ||
| 247 | + return ruleDtoList; | ||
| 248 | + } | ||
| 249 | + List<Long> ruleIdList = templateRuleList.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 250 | + List<AlertTemplateRuleItem> alertTemplateRuleItems = alertTemplateRuleItemMapper.selectList( | ||
| 251 | + Wrappers.<AlertTemplateRuleItem>lambdaQuery().in(AlertTemplateRuleItem::getTemplateRuleId, | ||
| 252 | + ruleIdList).eq(AlertTemplateRuleItem::getIsDeleted, 0)); | ||
| 253 | + List<Long> itemIdList = alertTemplateRuleItems.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 254 | + List<AlertTemplateRuleItemParam> itemParamList = tRuleItemParamMapper.selectList( | ||
| 255 | + Wrappers.<AlertTemplateRuleItemParam>lambdaQuery().in(AlertTemplateRuleItemParam::getItemId, | ||
| 256 | + itemIdList).eq(AlertTemplateRuleItemParam::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 257 | + for (AlertTemplateRule templateRule : templateRuleList) { | ||
| 258 | + AlertTemplateRuleDto ruleDto = new AlertTemplateRuleDto(); | ||
| 259 | + BeanUtil.copyProperties(templateRule, ruleDto); | ||
| 260 | + List<AlertTemplateRuleItem> templateRuleItems = alertTemplateRuleItems.stream().filter( | ||
| 261 | + item -> item.getTemplateRuleId().equals(templateRule.getId())).collect(Collectors.toList()); | ||
| 262 | + String ruleExpDesc = templateRuleItems.stream().map(item -> { | ||
| 263 | + List<String> paramVals = itemParamList.stream().filter( | ||
| 264 | + item0 -> item0.getItemId().equals(item.getId())).map(item0 -> item0.getParamValue()).collect( | ||
| 265 | + Collectors.toList()); | ||
| 266 | + return "[" + item.getRuleMark() + "]:" + MessageSourceUtil.get(item.getRuleExpName()) | ||
| 267 | + + (CollectionUtil.isNotEmpty(paramVals) | ||
| 268 | + ? "(" + paramVals.stream().collect(Collectors.joining(CommonConstants.DELIMITER)) + ")" : "") | ||
| 269 | + + " " + (item.getAction().equals("normal") | ||
| 270 | + ? MessageSourceUtil.get("rule.ruleItem.normalAction") + " " + item.getOperate() | ||
| 271 | + + item.getLimitValue() + (StrUtil.isNotBlank( | ||
| 272 | + item.getUnit()) ? item.getUnit() : "") : item.getAction().equals( | ||
| 273 | + "increase") ? MessageSourceUtil.get("rule.ruleItem.increaseAction") : MessageSourceUtil.get( | ||
| 274 | + "rule.ruleItem.decreaseAction")); | ||
| 275 | + }).collect(Collectors.joining("<br/>")); | ||
| 276 | + ruleDto.setRuleExpDesc(ruleExpDesc); | ||
| 277 | + ruleDtoList.add(ruleDto); | ||
| 278 | + } | ||
| 279 | + return ruleDtoList; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + | ||
| 283 | + public void delTemplate(Long id) { | ||
| 284 | + MessageSourceUtil.reset(); | ||
| 285 | + // 查看是否被引用 | ||
| 286 | + List<AlertClusterNodeConf> nodeConfList = nodeConfService.list( | ||
| 287 | + Wrappers.<AlertClusterNodeConf>lambdaQuery().eq(AlertClusterNodeConf::getTemplateId, id).eq( | ||
| 288 | + AlertClusterNodeConf::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 289 | + if (CollectionUtil.isNotEmpty(nodeConfList)) { | ||
| 290 | + throw new ServiceException(MessageSourceUtil.get("templateIsUsed")); | ||
| 291 | + } | ||
| 292 | + LambdaUpdateWrapper<AlertTemplate> updateWrapper = new LambdaUpdateWrapper<>(); | ||
| 293 | + updateWrapper.set(AlertTemplate::getIsDeleted, CommonConstants.IS_DELETE).set(AlertTemplate::getUpdateTime, | ||
| 294 | + LocalDateTime.now()).eq(AlertTemplate::getId, id).eq(AlertTemplate::getIsDeleted, | ||
| 295 | + CommonConstants.IS_NOT_DELETE); | ||
| 296 | + this.baseMapper.update(null, updateWrapper); | ||
| 297 | + List<AlertTemplateRule> templateRuleList = alertTemplateRuleMapper.selectList( | ||
| 298 | + Wrappers.<AlertTemplateRule>lambdaQuery().eq(AlertTemplateRule::getTemplateId, id).eq( | ||
| 299 | + AlertTemplateRule::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 300 | + alertTemplateRuleMapper.update(null, | ||
| 301 | + new LambdaUpdateWrapper<AlertTemplateRule>().set(AlertTemplateRule::getIsDeleted, 1).set( | ||
| 302 | + AlertTemplateRule::getUpdateTime, LocalDateTime.now()).eq(AlertTemplateRule::getTemplateId, | ||
| 303 | + id).eq(AlertTemplateRule::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 304 | + List<Long> templateRuleIds = templateRuleList.stream().map(item -> item.getId()).collect(Collectors.toList()); | ||
| 305 | + if (CollectionUtil.isEmpty(templateRuleIds)) { | ||
| 306 | + return; | ||
| 307 | + } | ||
| 308 | + alertTemplateRuleItemMapper.update(null, | ||
| 309 | + new LambdaUpdateWrapper<AlertTemplateRuleItem>().set(AlertTemplateRuleItem::getIsDeleted, | ||
| 310 | + CommonConstants.IS_DELETE).set(AlertTemplateRuleItem::getUpdateTime, LocalDateTime.now()).in( | ||
| 311 | + AlertTemplateRuleItem::getTemplateRuleId, templateRuleIds).eq( | ||
| 312 | + AlertTemplateRuleItem::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 313 | + } | ||
| 314 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/NotifyConfigServiceImpl.java+126-0
| @@ -0,0 +1,126 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import cn.hutool.core.util.StrUtil; | ||
| 9 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 10 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 11 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 13 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 14 | +import org.opengauss.plugin.alertcenter.entity.NotifyConfig; | ||
| 15 | +import org.opengauss.plugin.alertcenter.entity.NotifyTemplate; | ||
| 16 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 17 | +import org.opengauss.plugin.alertcenter.mapper.NotifyConfigMapper; | ||
| 18 | +import org.opengauss.plugin.alertcenter.mapper.NotifyTemplateMapper; | ||
| 19 | +import org.opengauss.plugin.alertcenter.mapper.NotifyWayMapper; | ||
| 20 | +import org.opengauss.plugin.alertcenter.model.NotifyConfigReq; | ||
| 21 | +import org.opengauss.plugin.alertcenter.service.EmailService; | ||
| 22 | +import org.opengauss.plugin.alertcenter.service.NotifyConfigService; | ||
| 23 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 24 | +import org.springframework.stereotype.Service; | ||
| 25 | +import org.springframework.validation.BeanPropertyBindingResult; | ||
| 26 | +import org.springframework.validation.Errors; | ||
| 27 | +import org.springframework.validation.SmartValidator; | ||
| 28 | + | ||
| 29 | +import java.time.LocalDateTime; | ||
| 30 | +import java.util.ArrayList; | ||
| 31 | +import java.util.List; | ||
| 32 | +import java.util.Map; | ||
| 33 | +import java.util.Set; | ||
| 34 | +import java.util.stream.Collectors; | ||
| 35 | + | ||
| 36 | +/** | ||
| 37 | + * wuyuebin | ||
| 38 | + * 2023/6/1 01:46 | ||
| 39 | + * | ||
| 40 | + */ | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +public class NotifyConfigServiceImpl extends ServiceImpl<NotifyConfigMapper, NotifyConfig> | ||
| 44 | + implements NotifyConfigService { | ||
| 45 | + | ||
| 46 | + private EmailService emailService; | ||
| 47 | + | ||
| 48 | + private NotifyWayMapper notifyWayMapper; | ||
| 49 | + | ||
| 50 | + private NotifyTemplateMapper notifyTemplateMapper; | ||
| 51 | + | ||
| 52 | + private SmartValidator smartValidator; | ||
| 53 | + | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + public List<NotifyConfig> getAllList() { | ||
| 57 | + List<NotifyConfig> notifyConfigList = new ArrayList<>(); | ||
| 58 | + List<NotifyConfig> list = this.list( | ||
| 59 | + Wrappers.<NotifyConfig>lambdaQuery().eq(NotifyConfig::getIsDeleted, CommonConstants.IS_NOT_DELETE)); | ||
| 60 | + Map<String, List<NotifyConfig>> map = list.stream().collect(Collectors.groupingBy(NotifyConfig::getType)); | ||
| 61 | + map.forEach((key, val) -> { | ||
| 62 | + if (CollectionUtil.isNotEmpty(val)) { | ||
| 63 | + notifyConfigList.add(val.get(0)); | ||
| 64 | + } | ||
| 65 | + }); | ||
| 66 | + return notifyConfigList; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + public void saveList(List<NotifyConfig> list) { | ||
| 71 | + if (CollectionUtil.isEmpty(list)) { | ||
| 72 | + throw new ServiceException("the notify config list is empty"); | ||
| 73 | + } | ||
| 74 | + // validate | ||
| 75 | + for (NotifyConfig notifyConfig : list) { | ||
| 76 | + Errors errors = new BeanPropertyBindingResult(notifyConfig, "notifyConfig"); | ||
| 77 | + smartValidator.validate(notifyConfig, errors, NotifyConfig.DefaultGroup.class); | ||
| 78 | + if (errors.hasErrors()) { | ||
| 79 | + throw new ServiceException(StrUtil.join(",", errors.getAllErrors())); | ||
| 80 | + } | ||
| 81 | + if (notifyConfig.getType().equals(CommonConstants.EMAIL) | ||
| 82 | + && notifyConfig.getEnable() == CommonConstants.ENABLE) { | ||
| 83 | + smartValidator.validate(notifyConfig, errors, NotifyConfig.EmailGroup.class); | ||
| 84 | + } | ||
| 85 | + if (notifyConfig.getType().equals(CommonConstants.WE_COM) | ||
| 86 | + && notifyConfig.getEnable() == CommonConstants.ENABLE) { | ||
| 87 | + smartValidator.validate(notifyConfig, errors, NotifyConfig.WeComGroup.class); | ||
| 88 | + } | ||
| 89 | + if (notifyConfig.getType().equals(CommonConstants.DING_TALK) | ||
| 90 | + && notifyConfig.getEnable() == CommonConstants.ENABLE) { | ||
| 91 | + smartValidator.validate(notifyConfig, errors, NotifyConfig.DingTalkGroup.class); | ||
| 92 | + } | ||
| 93 | + if (errors.hasErrors()) { | ||
| 94 | + throw new ServiceException(StrUtil.join(",", errors.getAllErrors())); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + Set<String> typeSet = list.stream().map(item -> item.getType()).collect(Collectors.toSet()); | ||
| 99 | + List<NotifyConfig> oldList = this.list( | ||
| 100 | + Wrappers.<NotifyConfig>lambdaQuery().in(NotifyConfig::getType, typeSet).eq(NotifyConfig::getIsDeleted, | ||
| 101 | + CommonConstants.IS_NOT_DELETE)); | ||
| 102 | + for (NotifyConfig notifyConfig : list) { | ||
| 103 | + String type = notifyConfig.getType(); | ||
| 104 | + List<NotifyConfig> list0 = oldList.stream().filter(item -> item.getType().equals(type)).collect( | ||
| 105 | + Collectors.toList()); | ||
| 106 | + if (CollectionUtil.isEmpty(list0)) { | ||
| 107 | + notifyConfig.setCreateTime(LocalDateTime.now()); | ||
| 108 | + continue; | ||
| 109 | + } | ||
| 110 | + notifyConfig.setId(list0.get(0).getId()).setUpdateTime(LocalDateTime.now()); | ||
| 111 | + } | ||
| 112 | + this.saveOrUpdateBatch(list); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + | ||
| 116 | + public void testConfig(NotifyConfigReq notifyConfigReq) { | ||
| 117 | + NotifyWay notifyWay = notifyWayMapper.selectById(notifyConfigReq.getNotifyWayId()); | ||
| 118 | + NotifyTemplate notifyTemplate = notifyTemplateMapper.selectById(notifyWay.getNotifyTemplateId()); | ||
| 119 | + if (notifyConfigReq.getType().equals(CommonConstants.EMAIL)) { | ||
| 120 | + emailService.sendTest(notifyConfigReq, notifyWay.getEmail(), notifyTemplate.getNotifyTitle(), | ||
| 121 | + notifyTemplate.getNotifyContent()); | ||
| 122 | + } else { | ||
| 123 | + throw new ServiceException("test fail"); | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/NotifyTemplateServiceImpl.java+81-0
| @@ -0,0 +1,81 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import cn.hutool.core.util.StrUtil; | ||
| 9 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 10 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 11 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 12 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 13 | +import lombok.extern.slf4j.Slf4j; | ||
| 14 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 15 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 16 | +import org.opengauss.plugin.alertcenter.entity.NotifyTemplate; | ||
| 17 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 18 | +import org.opengauss.plugin.alertcenter.mapper.NotifyTemplateMapper; | ||
| 19 | +import org.opengauss.plugin.alertcenter.service.NotifyTemplateService; | ||
| 20 | +import org.opengauss.plugin.alertcenter.service.NotifyWayService; | ||
| 21 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 22 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 23 | +import org.springframework.stereotype.Service; | ||
| 24 | + | ||
| 25 | +import java.time.LocalDateTime; | ||
| 26 | +import java.util.List; | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * wuyuebin | ||
| 30 | + * 2023/5/31 10:18 | ||
| 31 | + * | ||
| 32 | + */ | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +public class NotifyTemplateServiceImpl extends ServiceImpl<NotifyTemplateMapper, NotifyTemplate> | ||
| 36 | + implements NotifyTemplateService { | ||
| 37 | + | ||
| 38 | + private NotifyWayService notifyWayService; | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + public Page getListPage(String notifyTemplateName, String notifyTemplateType, Page page) { | ||
| 42 | + return this.page(page, | ||
| 43 | + Wrappers.<NotifyTemplate>lambdaQuery().like(StrUtil.isNotBlank(notifyTemplateName), | ||
| 44 | + NotifyTemplate::getNotifyTemplateName, notifyTemplateName).eq( | ||
| 45 | + StrUtil.isNotBlank(notifyTemplateType), NotifyTemplate::getNotifyTemplateType, | ||
| 46 | + notifyTemplateType).eq(NotifyTemplate::getIsDeleted, CommonConstants.IS_NOT_DELETE).orderByDesc( | ||
| 47 | + NotifyTemplate::getId)); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + public void saveTemplate(NotifyTemplate notifyTemplate) { | ||
| 52 | + if (notifyTemplate.getId() == null) { | ||
| 53 | + notifyTemplate.setCreateTime(LocalDateTime.now()); | ||
| 54 | + } else { | ||
| 55 | + notifyTemplate.setUpdateTime(LocalDateTime.now()); | ||
| 56 | + } | ||
| 57 | + this.saveOrUpdate(notifyTemplate); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + | ||
| 61 | + public void delById(Long id) { | ||
| 62 | + MessageSourceUtil.reset(); | ||
| 63 | + List<NotifyWay> list = notifyWayService.list( | ||
| 64 | + Wrappers.<NotifyWay>lambdaQuery().eq(NotifyWay::getNotifyTemplateId, id).eq(NotifyWay::getIsDeleted, | ||
| 65 | + CommonConstants.IS_NOT_DELETE)); | ||
| 66 | + if (CollectionUtil.isNotEmpty(list)) { | ||
| 67 | + throw new ServiceException(MessageSourceUtil.get("notifyTemplateIsUsed")); | ||
| 68 | + } | ||
| 69 | + LambdaUpdateWrapper<NotifyTemplate> updateWrapper = new LambdaUpdateWrapper<>(); | ||
| 70 | + updateWrapper.set(NotifyTemplate::getIsDeleted, CommonConstants.IS_DELETE).set(NotifyTemplate::getUpdateTime, | ||
| 71 | + LocalDateTime.now()).eq(NotifyTemplate::getId, id); | ||
| 72 | + this.update(null, updateWrapper); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + public List<NotifyTemplate> getList(String notifyTemplateType) { | ||
| 77 | + return this.list(Wrappers.<NotifyTemplate>lambdaQuery().eq(NotifyTemplate::getIsDeleted, | ||
| 78 | + CommonConstants.IS_NOT_DELETE).eq(StrUtil.isNotBlank(notifyTemplateType), | ||
| 79 | + NotifyTemplate::getNotifyTemplateType, notifyTemplateType).orderByDesc(NotifyTemplate::getId)); | ||
| 80 | + } | ||
| 81 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/service/impl/NotifyWayServiceImpl.java+91-0
| @@ -0,0 +1,91 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.service.impl; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 8 | +import cn.hutool.core.util.StrUtil; | ||
| 9 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 10 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 11 | +import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 12 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 13 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 14 | +import lombok.extern.slf4j.Slf4j; | ||
| 15 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 16 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 17 | +import org.opengauss.plugin.alertcenter.dto.NotifyWayDto; | ||
| 18 | +import org.opengauss.plugin.alertcenter.entity.AlertRule; | ||
| 19 | +import org.opengauss.plugin.alertcenter.entity.AlertTemplateRule; | ||
| 20 | +import org.opengauss.plugin.alertcenter.entity.NotifyWay; | ||
| 21 | +import org.opengauss.plugin.alertcenter.mapper.NotifyWayMapper; | ||
| 22 | +import org.opengauss.plugin.alertcenter.service.AlertRuleService; | ||
| 23 | +import org.opengauss.plugin.alertcenter.service.AlertTemplateRuleService; | ||
| 24 | +import org.opengauss.plugin.alertcenter.service.NotifyWayService; | ||
| 25 | +import org.opengauss.plugin.alertcenter.utils.MessageSourceUtil; | ||
| 26 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 27 | +import org.springframework.stereotype.Service; | ||
| 28 | + | ||
| 29 | +import java.time.LocalDateTime; | ||
| 30 | +import java.util.List; | ||
| 31 | + | ||
| 32 | +/** | ||
| 33 | + * wuyuebin | ||
| 34 | + * 2023/5/25 15:54 | ||
| 35 | + * | ||
| 36 | + */ | ||
| 37 | + | ||
| 38 | + | ||
| 39 | +public class NotifyWayServiceImpl extends ServiceImpl<NotifyWayMapper, NotifyWay> | ||
| 40 | + implements NotifyWayService { | ||
| 41 | + | ||
| 42 | + private AlertRuleService ruleService; | ||
| 43 | + | ||
| 44 | + private AlertTemplateRuleService templateRuleService; | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + public Page<NotifyWayDto> getListPage(String name, String notifyType, Page page) { | ||
| 48 | + QueryWrapper<NotifyWay> ew = | ||
| 49 | + Wrappers.<NotifyWay>query().like(StrUtil.isNotBlank(name), "t1.name", name).eq( | ||
| 50 | + StrUtil.isNotBlank(notifyType), "t1.notify_type", notifyType).eq("t1.is_deleted", | ||
| 51 | + CommonConstants.IS_NOT_DELETE).orderByDesc("t1.id"); | ||
| 52 | + return this.baseMapper.selectDtoPage(page, ew); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + public List<NotifyWay> getList(String notifyType) { | ||
| 57 | + return this.baseMapper.selectList(Wrappers.<NotifyWay>lambdaQuery().eq(NotifyWay::getIsDeleted, | ||
| 58 | + CommonConstants.IS_NOT_DELETE).eq(StrUtil.isNotBlank(notifyType), NotifyWay::getNotifyType, | ||
| 59 | + notifyType).orderByDesc(NotifyWay::getId)); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + public void saveNotifyWay(NotifyWay notifyWay) { | ||
| 64 | + if (notifyWay.getId() == null) { | ||
| 65 | + notifyWay.setCreateTime(LocalDateTime.now()); | ||
| 66 | + } else { | ||
| 67 | + notifyWay.setUpdateTime(LocalDateTime.now()); | ||
| 68 | + } | ||
| 69 | + this.saveOrUpdate(notifyWay); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + public void delById(Long id) { | ||
| 74 | + MessageSourceUtil.reset(); | ||
| 75 | + List<AlertRule> ruleList = ruleService.list( | ||
| 76 | + Wrappers.<AlertRule>query().eq("is_deleted", CommonConstants.IS_NOT_DELETE).and( | ||
| 77 | + wrapper -> wrapper.gt("position('" + id + ",' in notify_way_ids)", 0).or().gt( | ||
| 78 | + "position('," + id + "' in notify_way_ids)", 0))); | ||
| 79 | + List<AlertTemplateRule> templateRuleList = templateRuleService.list( | ||
| 80 | + Wrappers.<AlertTemplateRule>query().eq("is_deleted", CommonConstants.IS_NOT_DELETE).and( | ||
| 81 | + wrapper -> wrapper.gt("position('" + id + ",' in notify_way_ids)", 0).or().gt( | ||
| 82 | + "position('," + id + "' in notify_way_ids)", 0))); | ||
| 83 | + if (CollectionUtil.isNotEmpty(ruleList) || CollectionUtil.isNotEmpty(templateRuleList)) { | ||
| 84 | + throw new ServiceException(MessageSourceUtil.get("notifyWayIsUsed")); | ||
| 85 | + } | ||
| 86 | + LambdaUpdateWrapper<NotifyWay> queryWrapper = new LambdaUpdateWrapper<>(); | ||
| 87 | + queryWrapper.set(NotifyWay::getIsDeleted, CommonConstants.IS_DELETE).eq(NotifyWay::getId, id).eq( | ||
| 88 | + NotifyWay::getIsDeleted, CommonConstants.IS_NOT_DELETE); | ||
| 89 | + this.update(queryWrapper); | ||
| 90 | + } | ||
| 91 | +} | ||
| @@ -0,0 +1,75 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.utils; | ||
| 6 | + | ||
| 7 | +import org.apache.commons.lang3.StringUtils; | ||
| 8 | +import org.slf4j.Logger; | ||
| 9 | +import org.slf4j.LoggerFactory; | ||
| 10 | + | ||
| 11 | +import java.io.BufferedReader; | ||
| 12 | +import java.io.IOException; | ||
| 13 | +import java.io.InputStreamReader; | ||
| 14 | +import java.net.URL; | ||
| 15 | +import java.net.URLConnection; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * General http sending method | ||
| 19 | + * | ||
| 20 | + * xielibo | ||
| 21 | + */ | ||
| 22 | +public class HttpUtils { | ||
| 23 | + private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * Send a request for the GET method to the specified URL | ||
| 27 | + * | ||
| 28 | + * url URL | ||
| 29 | + * param Request parameters, which should be in the form of name1=value1&name2=value2. | ||
| 30 | + * Response result of the remote resource represented | ||
| 31 | + */ | ||
| 32 | + public static String sendGet(String url, String param) { | ||
| 33 | + return sendGet(url, param, "UTF-8"); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * Send a request for the GET method to the specified URL | ||
| 38 | + * | ||
| 39 | + * url URL | ||
| 40 | + * param Request parameters, which should be in the form of name1=value1&name2=value2. | ||
| 41 | + * contentType Encoding type | ||
| 42 | + * Response result of the remote resource represented | ||
| 43 | + */ | ||
| 44 | + public static String sendGet(String url, String param, String contentType) { | ||
| 45 | + StringBuilder result = new StringBuilder(); | ||
| 46 | + BufferedReader in = null; | ||
| 47 | + try { | ||
| 48 | + String urlNameString = StringUtils.isEmpty(param) ? url : url + "?" + param; | ||
| 49 | + log.info("sendGet - {}", urlNameString); | ||
| 50 | + URL realUrl = new URL(urlNameString); | ||
| 51 | + URLConnection connection = realUrl.openConnection(); | ||
| 52 | + connection.setRequestProperty("accept", "*/*"); | ||
| 53 | + connection.setRequestProperty("connection", "Keep-Alive"); | ||
| 54 | + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); | ||
| 55 | + connection.connect(); | ||
| 56 | + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); | ||
| 57 | + String line; | ||
| 58 | + while ((line = in.readLine()) != null) { | ||
| 59 | + result.append(line); | ||
| 60 | + } | ||
| 61 | + log.info("recv - {}", result); | ||
| 62 | + } catch (IOException e) { | ||
| 63 | + log.error("use HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); | ||
| 64 | + } finally { | ||
| 65 | + try { | ||
| 66 | + if (in != null) { | ||
| 67 | + in.close(); | ||
| 68 | + } | ||
| 69 | + } catch (IOException e) { | ||
| 70 | + log.error("use in.close Exception, url=" + url + ",param=" + param, e); | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + return result.toString(); | ||
| 74 | + } | ||
| 75 | +} | ||
Aplugins/alert-center/src/main/java/org/opengauss/plugin/alertcenter/utils/MessageSourceUtil.java+71-0
| @@ -0,0 +1,71 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.utils; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.util.StrUtil; | ||
| 8 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 9 | +import org.springframework.context.MessageSource; | ||
| 10 | +import org.springframework.http.HttpHeaders; | ||
| 11 | +import org.springframework.stereotype.Component; | ||
| 12 | +import org.springframework.web.context.request.RequestContextHolder; | ||
| 13 | +import org.springframework.web.context.request.ServletRequestAttributes; | ||
| 14 | + | ||
| 15 | +import javax.servlet.http.HttpServletRequest; | ||
| 16 | +import java.util.Locale; | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +public class MessageSourceUtil { | ||
| 20 | + private static MessageSource messageSource; | ||
| 21 | + private static final ThreadLocal<Locale> LOC = new ThreadLocal<>(); | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + public void setMessageSource(MessageSource messageSource) { | ||
| 25 | + MessageSourceUtil.messageSource = messageSource; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public static void set(String language) { | ||
| 29 | + Locale locale; | ||
| 30 | + if (StrUtil.isBlank(language)) { | ||
| 31 | + locale = Locale.CHINA; | ||
| 32 | + } else { | ||
| 33 | + String[] str = language.split("_"); | ||
| 34 | + locale = new Locale(str[0], str[1]); | ||
| 35 | + } | ||
| 36 | + LOC.set(locale); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public static void set(Locale locale) { | ||
| 40 | + LOC.set(locale); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public static String get(String key) { | ||
| 44 | + return messageSource.getMessage(key, null, key, getLocale()); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public static void reset() { | ||
| 48 | + LOC.remove(); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + private static Locale getLocale() { | ||
| 52 | + if (LOC.get() != null) { | ||
| 53 | + return LOC.get(); | ||
| 54 | + } | ||
| 55 | + String language = null; | ||
| 56 | + if (RequestContextHolder.currentRequestAttributes() instanceof ServletRequestAttributes) { | ||
| 57 | + final HttpServletRequest request = | ||
| 58 | + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); | ||
| 59 | + language = request.getHeader(HttpHeaders.CONTENT_LANGUAGE); | ||
| 60 | + } | ||
| 61 | + Locale locale; | ||
| 62 | + if (language == null || language.isBlank()) { | ||
| 63 | + locale = Locale.CHINA; | ||
| 64 | + } else { | ||
| 65 | + String[] str = language.split("_"); | ||
| 66 | + locale = new Locale(str[0], str[1]); | ||
| 67 | + } | ||
| 68 | + LOC.set(locale); | ||
| 69 | + return locale; | ||
| 70 | + } | ||
| 71 | +} | ||
| @@ -0,0 +1,142 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.utils; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.thread.ThreadUtil; | ||
| 8 | +import lombok.extern.slf4j.Slf4j; | ||
| 9 | +import org.apache.sshd.client.SshClient; | ||
| 10 | +import org.apache.sshd.client.channel.ChannelExec; | ||
| 11 | +import org.apache.sshd.client.channel.ChannelShell; | ||
| 12 | +import org.apache.sshd.client.channel.ClientChannelEvent; | ||
| 13 | +import org.apache.sshd.client.future.ConnectFuture; | ||
| 14 | +import org.apache.sshd.client.session.ClientSession; | ||
| 15 | +import org.apache.sshd.sftp.client.SftpClientFactory; | ||
| 16 | +import org.apache.sshd.sftp.client.fs.SftpFileSystem; | ||
| 17 | +import org.apache.sshd.sftp.client.fs.SftpPath; | ||
| 18 | +import org.opengauss.admin.common.exception.base.BaseException; | ||
| 19 | +import org.opengauss.plugin.alertcenter.constant.CommonConstants; | ||
| 20 | + | ||
| 21 | +import java.io.ByteArrayInputStream; | ||
| 22 | +import java.io.ByteArrayOutputStream; | ||
| 23 | +import java.io.IOException; | ||
| 24 | +import java.io.InputStream; | ||
| 25 | +import java.io.OutputStream; | ||
| 26 | +import java.nio.file.Files; | ||
| 27 | +import java.nio.file.Paths; | ||
| 28 | +import java.nio.file.StandardCopyOption; | ||
| 29 | +import java.text.MessageFormat; | ||
| 30 | +import java.util.EnumSet; | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +public class SshSession implements AutoCloseable { | ||
| 34 | + private static final int SESSION_TIMEOUT = 10000; | ||
| 35 | + | ||
| 36 | + private static final int CHANNEL_TIMEOUT = 1000 * 60 * 5; | ||
| 37 | + | ||
| 38 | + private static SshClient cli; | ||
| 39 | + | ||
| 40 | + private ClientSession session; | ||
| 41 | + | ||
| 42 | + public enum Command { | ||
| 43 | + ARCH("arch"), CD("cd {0}"), LS("ls {0}"), STAT("stat {0}"), WGET("wget {0}"), TAR("tar zxf {0}"), | ||
| 44 | + UNZIP("unzip {0}"), APPEND_FILE(""), | ||
| 45 | + CHECK_USER("cat /etc/passwd | awk -F \":\" \"'{print $1}\"|grep {0} | wc -l"), | ||
| 46 | + CREATE_USER("useradd omm && echo ''{0} ALL=(ALL) ALL'' >> /etc/sudoers"), CHANGE_PASSWORD("passwd {1}"), | ||
| 47 | + PS("ps -ef|grep {0} |grep -v grep |grep {1,number,#}|awk '''{print $2}''"), KILL("kill -9 {0}"); | ||
| 48 | + | ||
| 49 | + private String cmd; | ||
| 50 | + | ||
| 51 | + Command(String cmd) { | ||
| 52 | + this.cmd = cmd; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public String parse(String... args) { | ||
| 56 | + return MessageFormat.format(cmd, args); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + private SshSession(String host, Integer port, String username, String password) throws IOException { | ||
| 61 | + ConnectFuture cf = getClient().connect(username, host, port); | ||
| 62 | + session = cf.verify().getSession(); | ||
| 63 | + | ||
| 64 | + try { | ||
| 65 | + session.addPasswordIdentity(password); | ||
| 66 | + session.auth().verify(SESSION_TIMEOUT); | ||
| 67 | + } catch (IOException e) { | ||
| 68 | + throw new BaseException(username + " password error"); | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + public String execute(Command command) throws IOException { | ||
| 74 | + return execute(command.cmd, null); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + public String execute(String command) throws IOException { | ||
| 78 | + return execute(command, null); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + public String execute(String command, OutputStream os) throws IOException { | ||
| 82 | + log.info("exec:" + command); | ||
| 83 | + ChannelExec ec = session.createExecChannel(command); | ||
| 84 | + if (os == null) { | ||
| 85 | + os = new ByteArrayOutputStream(); | ||
| 86 | + } | ||
| 87 | + ec.setOut(os); | ||
| 88 | + ec.setErr(os); | ||
| 89 | + ec.open(); | ||
| 90 | + ec.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), CHANNEL_TIMEOUT); | ||
| 91 | + for (int i = 0; i < 100 && ec.getExitStatus() == null; i++) { | ||
| 92 | + ThreadUtil.sleep(100L); | ||
| 93 | + } | ||
| 94 | + if (ec.getExitStatus() != null && ec.getExitStatus() != 0) { | ||
| 95 | + throw new BaseException(command + " " + CommonConstants.LINE_FEED + " " + os.toString().trim()); | ||
| 96 | + } | ||
| 97 | + return os.toString().trim(); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + public void executeNoWait(String command) throws IOException { | ||
| 101 | + log.info("execC:" + command); | ||
| 102 | + ChannelShell channelShell = session.createShellChannel(); | ||
| 103 | + String command0 = command + CommonConstants.LINE_FEED + "exit" + CommonConstants.LINE_FEED; | ||
| 104 | + channelShell.setIn(new ByteArrayInputStream(command0.getBytes())); | ||
| 105 | + ByteArrayOutputStream os = new ByteArrayOutputStream(); | ||
| 106 | + channelShell.setOut(os); | ||
| 107 | + channelShell.setErr(os); | ||
| 108 | + channelShell.open(); | ||
| 109 | + channelShell.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), CHANNEL_TIMEOUT); | ||
| 110 | + log.info(os.toString()); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + private static final synchronized SshClient getClient() { | ||
| 114 | + if (cli == null) { | ||
| 115 | + cli = SshClient.setUpDefaultClient(); | ||
| 116 | + cli.start(); | ||
| 117 | + } | ||
| 118 | + return cli; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + public synchronized void upload(InputStream in, String target) throws IOException { | ||
| 122 | + SftpFileSystem sf = SftpClientFactory.instance().createSftpFileSystem(session); | ||
| 123 | + SftpPath path = sf.getDefaultDir().resolve(target); | ||
| 124 | + Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + public synchronized void upload(String source, String target) throws IOException { | ||
| 128 | + log.info("from:{},to:{}", source, target); | ||
| 129 | + SftpFileSystem sf = SftpClientFactory.instance().createSftpFileSystem(session); | ||
| 130 | + SftpPath path = sf.getDefaultDir().resolve(target); | ||
| 131 | + Files.copy(Paths.get(source), path, StandardCopyOption.REPLACE_EXISTING); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + public static SshSession connect(String host, Integer port, String username, String password) throws IOException { | ||
| 135 | + return new SshSession(host, port, username, password); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + public void close() throws IOException { | ||
| 140 | + session.close(); | ||
| 141 | + } | ||
| 142 | +} | ||
| @@ -0,0 +1,68 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.utils; | ||
| 6 | + | ||
| 7 | +import cn.hutool.core.bean.BeanUtil; | ||
| 8 | +import cn.hutool.core.util.StrUtil; | ||
| 9 | +import org.opengauss.admin.common.exception.ServiceException; | ||
| 10 | + | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * wuyuebin | ||
| 15 | + * 2023/5/2 22:25 | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | +public class TextParser { | ||
| 19 | + private String paramOpen = "${"; | ||
| 20 | + private String paramClose = "}"; | ||
| 21 | + | ||
| 22 | + public TextParser() { | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public TextParser(String paramOpen, String paramClose) { | ||
| 26 | + this.paramOpen = paramOpen; | ||
| 27 | + this.paramClose = paramClose; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public String parse(String text, Map<String, Object> paramMap) { | ||
| 31 | + if (StrUtil.isBlank(text)) { | ||
| 32 | + return ""; | ||
| 33 | + } | ||
| 34 | + int start = text.indexOf(this.paramOpen); | ||
| 35 | + if (start == -1) { | ||
| 36 | + return text; | ||
| 37 | + } else { | ||
| 38 | + char[] src = text.toCharArray(); | ||
| 39 | + int offset = 0; | ||
| 40 | + StringBuilder builder = new StringBuilder(); | ||
| 41 | + | ||
| 42 | + do { | ||
| 43 | + builder.append(src, offset, start - offset); | ||
| 44 | + offset = start + this.paramOpen.length(); | ||
| 45 | + | ||
| 46 | + int end = text.indexOf(this.paramClose, offset); | ||
| 47 | + if (end == -1) { | ||
| 48 | + throw new ServiceException("text parser error"); | ||
| 49 | + } | ||
| 50 | + String paramName = text.substring(offset, end); | ||
| 51 | + Object paramVal = paramMap.getOrDefault(paramName, ""); | ||
| 52 | + builder.append(paramVal); | ||
| 53 | + offset = end + this.paramClose.length(); | ||
| 54 | + start = text.indexOf(this.paramOpen, offset); | ||
| 55 | + } while (start > -1); | ||
| 56 | + | ||
| 57 | + if (offset < src.length) { | ||
| 58 | + builder.append(src, offset, src.length - offset); | ||
| 59 | + } | ||
| 60 | + return builder.toString(); | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + public String parse(String text, Object obj) { | ||
| 65 | + Map<String, Object> paramMap = BeanUtil.beanToMap(obj); | ||
| 66 | + return parse(text, paramMap); | ||
| 67 | + } | ||
| 68 | +} | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.alertcenter.utils; | ||
| 6 | + | ||
| 7 | +import org.yaml.snakeyaml.Yaml; | ||
| 8 | +import org.yaml.snakeyaml.introspector.Property; | ||
| 9 | +import org.yaml.snakeyaml.nodes.NodeTuple; | ||
| 10 | +import org.yaml.snakeyaml.nodes.Tag; | ||
| 11 | +import org.yaml.snakeyaml.representer.Representer; | ||
| 12 | + | ||
| 13 | +public class YamlUtil { | ||
| 14 | + public static Yaml get() { | ||
| 15 | + return new Yaml(new Representer() { | ||
| 16 | + | ||
| 17 | + protected NodeTuple representJavaBeanProperty( | ||
| 18 | + Object javaBean, Property property, Object propertyValue, | ||
| 19 | + Tag customTag) { | ||
| 20 | + return propertyValue == null ? null | ||
| 21 | + : super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); | ||
| 22 | + } | ||
| 23 | + }); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public static <T> T loadAs(String yaml, Class<T> type) { | ||
| 27 | + return get().loadAs(yaml, type); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public static String dump(Object obj) { | ||
| 31 | + return get().dumpAsMap(obj); | ||
| 32 | + } | ||
| 33 | +} | ||
| @@ -0,0 +1,30 @@ | |||
| 1 | +spring: | ||
| 2 | + autoconfigure: | ||
| 3 | + exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration | ||
| 4 | + datasource: | ||
| 5 | + dynamic: | ||
| 6 | + primary: master | ||
| 7 | + datasource: | ||
| 8 | + master: | ||
| 9 | + url: jdbc:opengauss://192.168.110.32:7001/postgres?currentSchema=public | ||
| 10 | +# url: jdbc:opengauss://192.168.56.51:26000/postgres?currentSchema=public | ||
| 11 | + driverClassName: org.opengauss.Driver | ||
| 12 | + username: scott | ||
| 13 | + password: Test@1234 | ||
| 14 | + type: com.alibaba.druid.pool.DruidDataSource | ||
| 15 | +# driver-class-name: org.opengauss.Driver | ||
| 16 | +# url: jdbc:opengauss://192.168.110.31:5432/postgres?currentSchema=public | ||
| 17 | +# username: scott | ||
| 18 | +# password: Test@1234 | ||
| 19 | + druid: | ||
| 20 | + test-while-idle: false | ||
| 21 | + test-on-borrow: true | ||
| 22 | + validation-query: "select 1" | ||
| 23 | + validation-query-timeout: 10000 | ||
| 24 | + connection-error-retry-attempts: 0 | ||
| 25 | + break-after-acquire-failure: true | ||
| 26 | + max-wait: 3000 | ||
| 27 | + | ||
| 28 | +mybatis-plus: | ||
| 29 | + # 搜索指定包别名 | ||
| 30 | + typeAliasesPackage: org.opengauss.plugin.alertcenter.entity,org.opengauss.admin.common.core.domain.entity | ||
| @@ -0,0 +1,94 @@ | |||
| 1 | +## Spring配置 | ||
| 2 | +context: | ||
| 3 | + listener: | ||
| 4 | + classes: org.opengauss.plugin.alertcenter.listener.PluginListener | ||
| 5 | +#server: | ||
| 6 | +# servlet: | ||
| 7 | +# context-path: /alertCenter/api/v1 | ||
| 8 | +spring: | ||
| 9 | + servlet: | ||
| 10 | + multipart: | ||
| 11 | + max-file-size: 20MB #单个文件最大为20M | ||
| 12 | + max-request-size: 20MB #单次请求文件总数大小为20M | ||
| 13 | + sql: | ||
| 14 | + init: | ||
| 15 | + mode: always | ||
| 16 | + data-locations: classpath:db/observability-alert.sql | ||
| 17 | + continue-on-error: true | ||
| 18 | + profiles: | ||
| 19 | + active: '@profiles.active@' | ||
| 20 | + resources: | ||
| 21 | + static-locations: classpath:resources,file:D://static | ||
| 22 | + datasource: | ||
| 23 | + dynamic: | ||
| 24 | + strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 | ||
| 25 | + jackson: | ||
| 26 | + time-zone: GMT+8 | ||
| 27 | + date-format: yyyy-MM-dd HH:mm:ss | ||
| 28 | + serialization: | ||
| 29 | + indent_output: true | ||
| 30 | + fail_on_empty_beans: false | ||
| 31 | + deserialization: | ||
| 32 | + fail_on_unknown_properties: true | ||
| 33 | + parser: | ||
| 34 | + allow_unquoted_control_chars: true | ||
| 35 | + allow_single_quotes: true | ||
| 36 | +server.compression: | ||
| 37 | + enabled: true | ||
| 38 | + mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain | ||
| 39 | +mybatis-plus: | ||
| 40 | + # 搜索指定包别名 | ||
| 41 | + typeAliasesPackage: org.opengauss.plugin.alertcenter.entity | ||
| 42 | + # 配置mapper的扫描,找到所有的mapper.xml映射文件 | ||
| 43 | + mapperLocations: classpath*:mapper/*.xml | ||
| 44 | + # 加载全局的配置文件 | ||
| 45 | + configuration: | ||
| 46 | + mapUnderscoreToCamelCase: true | ||
| 47 | + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl | ||
| 48 | + | ||
| 49 | +alert: | ||
| 50 | + rule-file-prefix: rules/ | ||
| 51 | + rule-file-suffix: .yml | ||
| 52 | + alertmanager: #prometheus推送的完整路径是 /plugins/alert-center/alertCenter/api/v1/alerts | ||
| 53 | + path-prefix: /plugins/alert-center/alertCenter | ||
| 54 | + api-version: v1 | ||
| 55 | + ruleItems: | ||
| 56 | + - name: cpuUsage | ||
| 57 | + unit: "%" | ||
| 58 | + ruleExps: | ||
| 59 | + - type: normal | ||
| 60 | + exp: (1- avg(rate(node_cpu_seconds_total{mode=\"idle\",instance=~\"${instances}\"}[5m])) by(instance)) * 100 | ||
| 61 | + - type: trend | ||
| 62 | + exp: avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\",instance=~\"${instances}\"}[5m] offset 15s)) - avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\",instance=~\"${instances}\"}[5m])) | ||
| 63 | + - name: memoryUsage | ||
| 64 | + unit: "%" | ||
| 65 | + ruleExps: | ||
| 66 | + - type: normal | ||
| 67 | + exp: 100 * (1 - (node_memory_MemFree_bytes + node_memory_Cached_bytes + node_memory_Buffers_bytes) / node_memory_MemTotal_bytes{instance=~\"${instances}\"}) | ||
| 68 | + - type: trend | ||
| 69 | + exp: (node_memory_MemFree_bytes offset 15s + node_memory_Cached_bytes offset 15s + node_memory_Buffers_bytes offset 15s) / node_memory_MemTotal_bytes{instance=~\"${instances}\"} - (node_memory_MemFree_bytes + node_memory_Cached_bytes + node_memory_Buffers_bytes) / node_memory_MemTotal_bytes{instance=~\"${instances}\"} | ||
| 70 | + - name: diskUsage | ||
| 71 | + unit: MB | ||
| 72 | + ruleExps: | ||
| 73 | + - type: normal | ||
| 74 | + exp: (node_filesystem_size_bytes{device=~\"${filesystemPath}\",instance=~\"${instances}\"} - node_filesystem_free_bytes) /1024/1024 | ||
| 75 | + - type: trend | ||
| 76 | + exp: node_filesystem_free_bytes{device=~\"${filesystemPath}\",instance=~\"${instances}\"} offset 15s - node_filesystem_free_bytes{device=~\"${filesystemPath}\",instance=~\"${instances}\"} | ||
| 77 | + params: | ||
| 78 | + paramName: filesystemPath | ||
| 79 | + paramValue: | ||
| 80 | + paramOrder: 1 | ||
| 81 | + - name: diskWriteRate | ||
| 82 | + unit: MB/s | ||
| 83 | + ruleExps: | ||
| 84 | + - type: normal | ||
| 85 | + exp: sum(rate(node_disk_written_bytes_total{instance=~\"${instances}\"}[2m])) by (instance) /1024/1024 | ||
| 86 | + - type: trend | ||
| 87 | + exp: sum(rate(node_disk_written_bytes_total{instance=~\"${instances}\"}[2m])) by (instance) - sum(rate(node_disk_written_bytes_total{instance=~\"${instances}\"}[5m] offset 15s)) by (instance) | ||
| 88 | + - name: diskReadRate | ||
| 89 | + unit: MB/s | ||
| 90 | + ruleExps: | ||
| 91 | + - type: normal | ||
| 92 | + exp: sum(rate(node_disk_read_bytes_total{instance=~\"${instances}\"}[2m])) by (instance) /1024/1024 | ||
| 93 | + - type: trend | ||
| 94 | + exp: sum(rate(node_disk_read_bytes_total{instance=~\"${instances}\"}[2m])) by (instance) - sum(rate(node_disk_read_bytes_total{instance=~\"${instances}\"}[5m] offset 15s)) by (instance) | ||
| @@ -0,0 +1,547 @@ | |||
| 1 | +CREATE OR REPLACE FUNCTION create_sequences_not_exists() RETURNS integer AS 'BEGIN | ||
| 2 | + | ||
| 3 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_rule_id'' ) | ||
| 4 | +THEN | ||
| 5 | +CREATE SEQUENCE "public"."sq_alert_rule_id" | ||
| 6 | +INCREMENT 1 | ||
| 7 | +MINVALUE 1 | ||
| 8 | +MAXVALUE 9223372036854775807 | ||
| 9 | +START 20 | ||
| 10 | +CACHE 1; | ||
| 11 | +END IF; | ||
| 12 | + | ||
| 13 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_rule_item_id'' ) | ||
| 14 | +THEN | ||
| 15 | +CREATE SEQUENCE "public"."sq_alert_rule_item_id" | ||
| 16 | +INCREMENT 1 | ||
| 17 | +MINVALUE 1 | ||
| 18 | +MAXVALUE 9223372036854775807 | ||
| 19 | +START 20 | ||
| 20 | +CACHE 1; | ||
| 21 | +END IF; | ||
| 22 | + | ||
| 23 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_rule_item_param_id'' ) | ||
| 24 | +THEN | ||
| 25 | +CREATE SEQUENCE "public"."sq_alert_rule_item_param_id" | ||
| 26 | +INCREMENT 1 | ||
| 27 | +MINVALUE 1 | ||
| 28 | +MAXVALUE 9223372036854775807 | ||
| 29 | +START 20 | ||
| 30 | +CACHE 1; | ||
| 31 | +END IF; | ||
| 32 | + | ||
| 33 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_notify_way_id'' ) | ||
| 34 | +THEN | ||
| 35 | +CREATE SEQUENCE "public"."sq_notify_way_id" | ||
| 36 | +INCREMENT 1 | ||
| 37 | +MINVALUE 1 | ||
| 38 | +MAXVALUE 9223372036854775807 | ||
| 39 | +START 20 | ||
| 40 | +CACHE 1; | ||
| 41 | +END IF; | ||
| 42 | + | ||
| 43 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_template_id'' ) | ||
| 44 | +THEN | ||
| 45 | +CREATE SEQUENCE "public"."sq_alert_template_id" | ||
| 46 | +INCREMENT 1 | ||
| 47 | +MINVALUE 1 | ||
| 48 | +MAXVALUE 9223372036854775807 | ||
| 49 | +START 20 | ||
| 50 | +CACHE 1; | ||
| 51 | +END IF; | ||
| 52 | + | ||
| 53 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_template_rule_id'' ) | ||
| 54 | +THEN | ||
| 55 | +CREATE SEQUENCE "public"."sq_alert_template_rule_id" | ||
| 56 | +INCREMENT 1 | ||
| 57 | +MINVALUE 2 | ||
| 58 | +MAXVALUE 9223372036854775807 | ||
| 59 | +START 20 | ||
| 60 | +CACHE 1; | ||
| 61 | +END IF; | ||
| 62 | + | ||
| 63 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_template_rule_item_id'' ) | ||
| 64 | +THEN | ||
| 65 | +CREATE SEQUENCE "public"."sq_alert_template_rule_item_id" | ||
| 66 | +INCREMENT 1 | ||
| 67 | +MINVALUE 2 | ||
| 68 | +MAXVALUE 9223372036854775807 | ||
| 69 | +START 20 | ||
| 70 | +CACHE 1; | ||
| 71 | +END IF; | ||
| 72 | + | ||
| 73 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_template_rule_item_param_id'' ) | ||
| 74 | +THEN | ||
| 75 | +CREATE SEQUENCE "public"."sq_alert_template_rule_item_param_id" | ||
| 76 | +INCREMENT 1 | ||
| 77 | +MINVALUE 2 | ||
| 78 | +MAXVALUE 9223372036854775807 | ||
| 79 | +START 20 | ||
| 80 | +CACHE 1; | ||
| 81 | +END IF; | ||
| 82 | + | ||
| 83 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_host_template_id'' ) | ||
| 84 | +THEN | ||
| 85 | +CREATE SEQUENCE "public"."sq_alert_host_template_id" | ||
| 86 | +INCREMENT 1 | ||
| 87 | +MINVALUE 2 | ||
| 88 | +MAXVALUE 9223372036854775807 | ||
| 89 | +START 20 | ||
| 90 | +CACHE 1; | ||
| 91 | +END IF; | ||
| 92 | + | ||
| 93 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_record_id'' ) | ||
| 94 | +THEN | ||
| 95 | +CREATE SEQUENCE "public"."sq_alert_record_id" | ||
| 96 | +INCREMENT 1 | ||
| 97 | +MINVALUE 1 | ||
| 98 | +MAXVALUE 9223372036854775807 | ||
| 99 | +START 1 | ||
| 100 | +CACHE 1; | ||
| 101 | +END IF; | ||
| 102 | + | ||
| 103 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_notify_template_id'' ) | ||
| 104 | +THEN | ||
| 105 | +CREATE SEQUENCE "public"."sq_notify_template_id" | ||
| 106 | +INCREMENT 1 | ||
| 107 | +MINVALUE 1 | ||
| 108 | +MAXVALUE 9223372036854775807 | ||
| 109 | +START 20 | ||
| 110 | +CACHE 1; | ||
| 111 | +END IF; | ||
| 112 | + | ||
| 113 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_notify_message_id'' ) | ||
| 114 | +THEN | ||
| 115 | +CREATE SEQUENCE "public"."sq_notify_message_id" | ||
| 116 | +INCREMENT 1 | ||
| 117 | +MINVALUE 1 | ||
| 118 | +MAXVALUE 9223372036854775807 | ||
| 119 | +START 1 | ||
| 120 | +CACHE 1; | ||
| 121 | +END IF; | ||
| 122 | + | ||
| 123 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_cluster_node_conf_id'' ) | ||
| 124 | +THEN | ||
| 125 | +CREATE SEQUENCE "public"."sq_alert_cluster_node_conf_id" | ||
| 126 | +INCREMENT 1 | ||
| 127 | +MINVALUE 1 | ||
| 128 | +MAXVALUE 9223372036854775807 | ||
| 129 | +START 1 | ||
| 130 | +CACHE 1; | ||
| 131 | +END IF; | ||
| 132 | + | ||
| 133 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_template_notify_conf_id'' ) | ||
| 134 | +THEN | ||
| 135 | +CREATE SEQUENCE "public"."sq_alert_template_notify_conf_id" | ||
| 136 | +INCREMENT 1 | ||
| 137 | +MINVALUE 1 | ||
| 138 | +MAXVALUE 9223372036854775807 | ||
| 139 | +START 20 | ||
| 140 | +CACHE 1; | ||
| 141 | +END IF; | ||
| 142 | + | ||
| 143 | +IF NOT EXISTS (SELECT 1 FROM information_schema.sequences WHERE sequence_schema=''public'' AND sequence_name=''sq_alert_config_id'' ) | ||
| 144 | +THEN | ||
| 145 | +CREATE SEQUENCE "public"."sq_alert_config_id" | ||
| 146 | +INCREMENT 1 | ||
| 147 | +MINVALUE 1 | ||
| 148 | +MAXVALUE 9223372036854775807 | ||
| 149 | +START 20 | ||
| 150 | +CACHE 1; | ||
| 151 | +END IF; | ||
| 152 | + | ||
| 153 | +RETURN 0; | ||
| 154 | +END;' | ||
| 155 | +LANGUAGE plpgsql; | ||
| 156 | + | ||
| 157 | +SELECT create_sequences_not_exists(); | ||
| 158 | +DROP FUNCTION create_sequences_not_exists; | ||
| 159 | + | ||
| 160 | +CREATE TABLE IF NOT EXISTS "public"."alert_rule" ( | ||
| 161 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_rule_id'::regclass), | ||
| 162 | + "rule_name" varchar(50) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 163 | + "level" varchar(20) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 164 | + "rule_type" varchar(20) COLLATE "pg_catalog"."default", | ||
| 165 | + "rule_exp_comb" varchar(100) COLLATE "pg_catalog"."default", | ||
| 166 | + "rule_content" text COLLATE "pg_catalog"."default", | ||
| 167 | + "notify_duration" int, | ||
| 168 | + "notify_duration_unit" char(1) COLLATE "pg_catalog"."default", | ||
| 169 | + "is_repeat" int1, | ||
| 170 | + "is_silence" int1, | ||
| 171 | + "silence_start_time" timestamp(6), | ||
| 172 | + "silence_end_time" timestamp(6), | ||
| 173 | + "alert_notify" varchar(20) COLLATE "pg_catalog"."default", | ||
| 174 | + "notify_way_ids" text COLLATE "pg_catalog"."default", | ||
| 175 | + "alert_desc" text COLLATE "pg_catalog"."default", | ||
| 176 | + "is_deleted" int1 DEFAULT 0, | ||
| 177 | + "create_time" timestamp(6), | ||
| 178 | + "update_time" timestamp(6) | ||
| 179 | + ); | ||
| 180 | +COMMENT ON COLUMN "public"."alert_rule"."id" IS '规则ID'; | ||
| 181 | +COMMENT ON COLUMN "public"."alert_rule"."rule_name" IS '规则名称'; | ||
| 182 | +COMMENT ON COLUMN "public"."alert_rule"."level" IS '告警等级,serous:严重,warn:警告,info:提示'; | ||
| 183 | +COMMENT ON COLUMN "public"."alert_rule"."rule_type" IS '规则类型,index为指标,log为日志'; | ||
| 184 | +COMMENT ON COLUMN "public"."alert_rule"."rule_exp_comb" IS '组合表达式'; | ||
| 185 | +COMMENT ON COLUMN "public"."alert_rule"."rule_content" IS '规则内容'; | ||
| 186 | +COMMENT ON COLUMN "public"."alert_rule"."notify_duration" IS '通知评估时长,表示告警持续多久通知'; | ||
| 187 | +COMMENT ON COLUMN "public"."alert_rule"."notify_duration_unit" IS '通知评估时长单位,s表示秒,m表示分,h表示小时,d表示天'; | ||
| 188 | +COMMENT ON COLUMN "public"."alert_rule"."is_repeat" IS '是否重复通知,0否,1是'; | ||
| 189 | +COMMENT ON COLUMN "public"."alert_rule"."is_silence" IS '是否静默,0为否,1为是'; | ||
| 190 | +COMMENT ON COLUMN "public"."alert_rule"."silence_start_time" IS '静默开始时间'; | ||
| 191 | +COMMENT ON COLUMN "public"."alert_rule"."silence_end_time" IS '静默结束时间'; | ||
| 192 | +COMMENT ON COLUMN "public"."alert_rule"."alert_notify" IS '告警通知,firing为告警,recover为告警恢复,两个可以同时存在,用逗号分隔'; | ||
| 193 | +COMMENT ON COLUMN "public"."alert_rule"."notify_way" IS '通知方式,message、email、WeCom、DingTalk'; | ||
| 194 | +COMMENT ON COLUMN "public"."alert_rule"."alert_desc" IS '告警描述'; | ||
| 195 | +COMMENT ON COLUMN "public"."alert_rule"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 196 | +COMMENT ON COLUMN "public"."alert_rule"."create_time" IS '创建时间'; | ||
| 197 | +COMMENT ON COLUMN "public"."alert_rule"."update_time" IS '更新时间'; | ||
| 198 | +COMMENT ON TABLE "public"."alert_rule" IS '告警规则表'; | ||
| 199 | + | ||
| 200 | + | ||
| 201 | +CREATE TABLE IF NOT EXISTS "public"."alert_rule_item" ( | ||
| 202 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_rule_item_id'::regclass), | ||
| 203 | + "rule_id" int8 NOT NULL, | ||
| 204 | + "rule_mark" char(1) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 205 | + "rule_exp_name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 206 | + "action" varchar(50) COLLATE "pg_catalog"."default", | ||
| 207 | + "operate" varchar(20) COLLATE "pg_catalog"."default", | ||
| 208 | + "limit_value" REAL , | ||
| 209 | + "unit" varchar(20) COLLATE "pg_catalog"."default", | ||
| 210 | + "rule_exp" varchar(200) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 211 | + "rule_exp_param" varchar(500) COLLATE "pg_catalog"."default", | ||
| 212 | + "rule_item_desc" text COLLATE "pg_catalog"."default", | ||
| 213 | + "is_deleted" int1 DEFAULT 0, | ||
| 214 | + "create_time" timestamp(6), | ||
| 215 | + "update_time" timestamp(6) | ||
| 216 | + ); | ||
| 217 | +COMMENT ON COLUMN "public"."alert_rule_item"."id" IS '规则项ID'; | ||
| 218 | +COMMENT ON COLUMN "public"."alert_rule_item"."rule_id" IS '规则ID'; | ||
| 219 | +COMMENT ON COLUMN "public"."alert_rule_item"."rule_mark" IS '规则标记,A B C ……'; | ||
| 220 | +COMMENT ON COLUMN "public"."alert_rule_item"."rule_exp_name" IS '规则表达式名称'; | ||
| 221 | +COMMENT ON COLUMN "public"."alert_rule_item"."action" IS 'normal:连续发生,increase:持续增长,decrease:持续减少'; | ||
| 222 | +COMMENT ON COLUMN "public"."alert_rule_item"."operate" IS '操作符,<、 <=、 = 、>、 >='; | ||
| 223 | +COMMENT ON COLUMN "public"."alert_rule_item"."limit_value" IS '阈值'; | ||
| 224 | +COMMENT ON COLUMN "public"."alert_rule_item"."unit" IS '单位'; | ||
| 225 | +COMMENT ON COLUMN "public"."alert_rule_item"."rule_exp" IS '规则表达式'; | ||
| 226 | +COMMENT ON COLUMN "public"."alert_rule_item"."rule_exp_param" IS '规则表达式参数,json'; | ||
| 227 | +COMMENT ON COLUMN "public"."alert_rule_item"."rule_item_desc" IS '描述'; | ||
| 228 | +COMMENT ON COLUMN "public"."alert_rule_item"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 229 | +COMMENT ON COLUMN "public"."alert_rule_item"."create_time" IS '创建时间'; | ||
| 230 | +COMMENT ON COLUMN "public"."alert_rule_item"."update_time" IS '更新时间'; | ||
| 231 | +COMMENT ON TABLE "public"."alert_rule_item" IS '告警规则项表'; | ||
| 232 | + | ||
| 233 | +CREATE TABLE IF NOT EXISTS "public"."alert_rule_item_param" ( | ||
| 234 | + id int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_rule_item_param_id'::regclass), | ||
| 235 | + item_id bigint NOT NULL, | ||
| 236 | + param_name varchar(20) COLLATE "pg_catalog"."default", | ||
| 237 | + param_value varchar(100) COLLATE "pg_catalog"."default", | ||
| 238 | + "param_order" int default 0, | ||
| 239 | + is_deleted tinyint DEFAULT 0, | ||
| 240 | + create_time timestamp(6), | ||
| 241 | + update_time timestamp(6) | ||
| 242 | +); | ||
| 243 | + | ||
| 244 | +CREATE TABLE IF NOT EXISTS "public"."notify_way" ( | ||
| 245 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_notify_way_id'::regclass), | ||
| 246 | + "name" varchar(50) COLLATE "pg_catalog"."default", | ||
| 247 | + "notify_type" varchar(20) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 248 | + "phone" text COLLATE "pg_catalog"."default", | ||
| 249 | + "email" text COLLATE "pg_catalog"."default", | ||
| 250 | + "person_id" text COLLATE "pg_catalog"."default", | ||
| 251 | + "dept_id" text COLLATE "pg_catalog"."default", | ||
| 252 | + "notify_template_id" int8 NOT NULL, | ||
| 253 | + "is_deleted" int1 DEFAULT 0, | ||
| 254 | + "create_time" timestamp(6), | ||
| 255 | + "update_time" timestamp(6) | ||
| 256 | + ); | ||
| 257 | +COMMENT ON COLUMN "public"."notify_way"."id" IS '通知方式ID'; | ||
| 258 | +COMMENT ON COLUMN "public"."notify_way"."name" IS '通知方式名称'; | ||
| 259 | +COMMENT ON COLUMN "public"."notify_way"."notify_type" IS '通知方式,message、email、WeCom、DingTalk'; | ||
| 260 | +COMMENT ON COLUMN "public"."notify_way"."phone" IS '手机号'; | ||
| 261 | +COMMENT ON COLUMN "public"."notify_way"."email" IS '邮箱'; | ||
| 262 | +COMMENT ON COLUMN "public"."notify_way"."person_id" IS '企业微信或者钉钉用户ID'; | ||
| 263 | +COMMENT ON COLUMN "public"."notify_way"."dept_id" IS '企业微信或者钉钉部门ID'; | ||
| 264 | +COMMENT ON COLUMN "public"."notify_way"."notify_template_id" IS '通知模板ID'; | ||
| 265 | +COMMENT ON COLUMN "public"."notify_way"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 266 | +COMMENT ON COLUMN "public"."notify_way"."create_time" IS '创建时间'; | ||
| 267 | +COMMENT ON COLUMN "public"."notify_way"."update_time" IS '更新时间'; | ||
| 268 | +COMMENT ON TABLE "public"."notify_way" IS '通知方式'; | ||
| 269 | + | ||
| 270 | + | ||
| 271 | +CREATE TABLE IF NOT EXISTS "public"."alert_template" ( | ||
| 272 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_template_id'::regclass), -- | ||
| 273 | + "template_name" varchar(50) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 274 | + "is_deleted" int1 DEFAULT 0, | ||
| 275 | + "create_time" timestamp(6), | ||
| 276 | + "update_time" timestamp(6) | ||
| 277 | + ); | ||
| 278 | +COMMENT ON COLUMN "public"."alert_template"."id" IS '告警模板ID'; | ||
| 279 | +COMMENT ON COLUMN "public"."alert_template"."template_name" IS 'template_name'; | ||
| 280 | +COMMENT ON COLUMN "public"."alert_template"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 281 | +COMMENT ON COLUMN "public"."alert_template"."create_time" IS '创建时间'; | ||
| 282 | +COMMENT ON COLUMN "public"."alert_template"."update_time" IS '更新时间'; | ||
| 283 | +COMMENT ON TABLE "public"."alert_template" IS '告警模板'; | ||
| 284 | + | ||
| 285 | + | ||
| 286 | +CREATE TABLE IF NOT EXISTS "public"."alert_template_rule" ( | ||
| 287 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_template_rule_id'::regclass), | ||
| 288 | + "template_id" int8, | ||
| 289 | + "rule_id" int8 NOT NULL, | ||
| 290 | + "rule_name" varchar(50) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 291 | + "level" varchar(20) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 292 | + "rule_type" varchar(20) COLLATE "pg_catalog"."default", | ||
| 293 | + "rule_exp_comb" varchar(100) COLLATE "pg_catalog"."default", | ||
| 294 | + "rule_content" text COLLATE "pg_catalog"."default", | ||
| 295 | + "notify_duration" int4, | ||
| 296 | + "notify_duration_unit" char(1) COLLATE "pg_catalog"."default", | ||
| 297 | + "is_repeat" int1, | ||
| 298 | + "is_silence" int1, | ||
| 299 | + "silence_start_time" timestamp(6), | ||
| 300 | + "silence_end_time" timestamp(6), | ||
| 301 | + "alert_notify" varchar(20) COLLATE "pg_catalog"."default", | ||
| 302 | + "notify_way_ids" text COLLATE "pg_catalog"."default", | ||
| 303 | + "alert_desc" text COLLATE "pg_catalog"."default", | ||
| 304 | + "is_deleted" int1 DEFAULT 0, | ||
| 305 | + "create_time" timestamp(6), | ||
| 306 | + "update_time" timestamp(6) | ||
| 307 | + ); | ||
| 308 | +COMMENT ON COLUMN "public"."alert_template_rule"."id" IS '模板规则ID'; | ||
| 309 | +COMMENT ON COLUMN "public"."alert_template_rule"."template_id" IS '模板ID'; | ||
| 310 | +COMMENT ON COLUMN "public"."alert_template_rule"."rule_id" IS '规则ID'; | ||
| 311 | +COMMENT ON COLUMN "public"."alert_template_rule"."rule_name" IS '规则名称'; | ||
| 312 | +COMMENT ON COLUMN "public"."alert_template_rule"."level" IS '告警等级,serous:严重,warn:警告,info:提示'; | ||
| 313 | +COMMENT ON COLUMN "public"."alert_template_rule"."rule_type" IS '规则类型,index为指标,log为日志'; | ||
| 314 | +COMMENT ON COLUMN "public"."alert_template_rule"."rule_exp_comb" IS '组合表达式'; | ||
| 315 | +COMMENT ON COLUMN "public"."alert_template_rule"."rule_content" IS '规则内容'; | ||
| 316 | +COMMENT ON COLUMN "public"."alert_template_rule"."notify_duration" IS '通知评估时长,表示告警持续多久通知'; | ||
| 317 | +COMMENT ON COLUMN "public"."alert_template_rule"."notify_duration_unit" IS '通知评估时长单位,s表示秒,m表示分,h表示小时,d表示天'; | ||
| 318 | +COMMENT ON COLUMN "public"."alert_template_rule"."is_repeat" IS '是否重复通知,0否,1是'; | ||
| 319 | +COMMENT ON COLUMN "public"."alert_template_rule"."is_silence" IS '是否静默,0为否,1为是'; | ||
| 320 | +COMMENT ON COLUMN "public"."alert_template_rule"."silence_start_time" IS '静默开始时间'; | ||
| 321 | +COMMENT ON COLUMN "public"."alert_template_rule"."silence_end_time" IS '静默结束时间'; | ||
| 322 | +COMMENT ON COLUMN "public"."alert_template_rule"."alert_notify" IS '告警通知,firing为告警,recover为告警恢复,两个可以同时存在,用逗号分隔'; | ||
| 323 | +COMMENT ON COLUMN "public"."alert_template_rule"."notify_way" IS '通知方式,message、email、WeCom、DingTalk'; | ||
| 324 | +COMMENT ON COLUMN "public"."alert_template_rule"."alert_desc" IS '告警描述'; | ||
| 325 | +COMMENT ON COLUMN "public"."alert_template_rule"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 326 | +COMMENT ON COLUMN "public"."alert_template_rule"."create_time" IS '创建时间'; | ||
| 327 | +COMMENT ON COLUMN "public"."alert_template_rule"."update_time" IS '更新时间'; | ||
| 328 | +COMMENT ON TABLE "public"."alert_template_rule" IS '告警模板规则表'; | ||
| 329 | + | ||
| 330 | +CREATE TABLE IF NOT EXISTS "public"."alert_template_rule_item" ( | ||
| 331 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_template_rule_item_id'::regclass), | ||
| 332 | + "template_rule_id" int8 NOT NULL, | ||
| 333 | + "rule_item_id" int8 NOT NULL, | ||
| 334 | + "rule_mark" char(1) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 335 | + "rule_exp_name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 336 | + "action" varchar(50) COLLATE "pg_catalog"."default", | ||
| 337 | + "operate" varchar(20) COLLATE "pg_catalog"."default", | ||
| 338 | + "limit_value" REAL , | ||
| 339 | + "unit" varchar(20) COLLATE "pg_catalog"."default", | ||
| 340 | + "rule_exp" varchar(200) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 341 | + "rule_exp_param" varchar(500) COLLATE "pg_catalog"."default", | ||
| 342 | + "rule_item_desc" text COLLATE "pg_catalog"."default", | ||
| 343 | + "is_deleted" int1 DEFAULT 0, | ||
| 344 | + "create_time" timestamp(6), | ||
| 345 | + "update_time" timestamp(6) | ||
| 346 | + ); | ||
| 347 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."id" IS '告警模板规则项ID'; | ||
| 348 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."template_rule_id" IS '告警模板规则ID'; | ||
| 349 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."rule_item_id" IS '规则项ID'; | ||
| 350 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."rule_mark" IS '规则标记,A B C ……'; | ||
| 351 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."rule_exp_name" IS '规则表达式名称'; | ||
| 352 | +COMMENT ON COLUMN "public"."alert_rule_item"."action" IS 'normal:连续发生,increase:持续增长,decrease:持续减少'; | ||
| 353 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."operate" IS '操作符,<、 <=、 = 、>、 >='; | ||
| 354 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."limit_value" IS '阈值'; | ||
| 355 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."unit" IS '单位'; | ||
| 356 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."rule_exp" IS '规则表达式'; | ||
| 357 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."rule_exp_param" IS '规则表达式参数,json'; | ||
| 358 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."rule_item_desc" IS '描述'; | ||
| 359 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 360 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."create_time" IS '创建时间'; | ||
| 361 | +COMMENT ON COLUMN "public"."alert_template_rule_item"."update_time" IS '更新时间'; | ||
| 362 | +COMMENT ON TABLE "public"."alert_template_rule_item" IS '告警模板规则项表'; | ||
| 363 | + | ||
| 364 | +CREATE TABLE alert_template_rule_item_param ( | ||
| 365 | + id int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_template_rule_item_param_id'::regclass), | ||
| 366 | + param_name varchar(20) COLLATE "pg_catalog"."default", | ||
| 367 | + param_value varchar(100) COLLATE "pg_catalog"."default", | ||
| 368 | + "param_order" int default 0, | ||
| 369 | + is_deleted tinyint DEFAULT 0, | ||
| 370 | + create_time timestamp(6), | ||
| 371 | + update_time timestamp(6) | ||
| 372 | +); | ||
| 373 | + | ||
| 374 | +CREATE TABLE IF NOT EXISTS "public"."alert_cluster_node_conf" ( | ||
| 375 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_cluster_node_conf_id'::regclass), | ||
| 376 | + "cluster_node_id" varchar(50) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 377 | +-- "host_id" int8 NOT NULL, | ||
| 378 | + "template_id" int8 NOT NULL, | ||
| 379 | + "is_deleted" int1 DEFAULT 0, | ||
| 380 | + "create_time" timestamp(6), | ||
| 381 | + "update_time" timestamp(6) | ||
| 382 | + ); | ||
| 383 | +COMMENT ON COLUMN "public"."alert_cluster_node_conf"."id" IS '告警配置ID'; | ||
| 384 | +COMMENT ON COLUMN "public"."alert_cluster_node_conf"."cluster_node_id" IS '实例ID'; | ||
| 385 | +COMMENT ON COLUMN "public"."alert_cluster_node_conf"."template_id" IS '告警模板ID'; | ||
| 386 | +COMMENT ON COLUMN "public"."alert_cluster_node_conf"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 387 | +COMMENT ON COLUMN "public"."alert_cluster_node_conf"."create_time" IS '创建时间'; | ||
| 388 | +COMMENT ON COLUMN "public"."alert_cluster_node_conf"."update_time" IS '更新时间'; | ||
| 389 | +COMMENT ON TABLE "public"."alert_cluster_node_conf" IS '实例告警配置'; | ||
| 390 | + | ||
| 391 | +CREATE TABLE IF NOT EXISTS "public"."alert_record" ( | ||
| 392 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_record_id'::regclass), | ||
| 393 | + "cluster_node_id" varchar(50) COLLATE "pg_catalog"."default" NOT NULL, | ||
| 394 | +-- "host_id" int8 NOT NULL, | ||
| 395 | + "template_id" int8 NOT NULL, | ||
| 396 | + "template_name" varchar(100) COLLATE "pg_catalog"."default", | ||
| 397 | + "template_rule_id" int8 NOT NULL, | ||
| 398 | + "template_rule_name" varchar(100) COLLATE "pg_catalog"."default", | ||
| 399 | + "template_rule_type" varchar(50) COLLATE "pg_catalog"."default", | ||
| 400 | + "level" varchar(50) COLLATE "pg_catalog"."default", | ||
| 401 | + "alert_content" text COLLATE "pg_catalog"."default" NOT NULL, | ||
| 402 | + "notify_way_ids" text COLLATE "pg_catalog"."default", | ||
| 403 | + "notify_way_names" text COLLATE "pg_catalog"."default", | ||
| 404 | + "start_time" timestamp(6), | ||
| 405 | + "end_time" timestamp(6), | ||
| 406 | + "duration" int8, | ||
| 407 | + "alert_status" int1 DEFAULT 0, | ||
| 408 | + "record_status" int1 DEFAULT 0, | ||
| 409 | + "is_deleted" int1 DEFAULT 0, | ||
| 410 | + "create_time" timestamp(6), | ||
| 411 | + "update_time" timestamp(6) | ||
| 412 | + ); | ||
| 413 | +COMMENT ON COLUMN "public"."alert_record"."id" IS '告警记录ID'; | ||
| 414 | +COMMENT ON COLUMN "public"."alert_record"."cluster_node_id" IS '实例ID'; | ||
| 415 | +COMMENT ON COLUMN "public"."alert_record"."template_id" IS '告警模板ID'; | ||
| 416 | +COMMENT ON COLUMN "public"."alert_record"."template_rule_id" IS '告警模板规则ID'; | ||
| 417 | +COMMENT ON COLUMN "public"."alert_record"."alert_content" IS '告警内容'; | ||
| 418 | +COMMENT ON COLUMN "public"."alert_record"."start_time" IS '告警开始时间'; | ||
| 419 | +COMMENT ON COLUMN "public"."alert_record"."end_time" IS '告警结束时间'; | ||
| 420 | +COMMENT ON COLUMN "public"."alert_record"."duration" IS '持续时间'; | ||
| 421 | +COMMENT ON COLUMN "public"."alert_record"."alert_status" IS '告警状态,告警中:0,已结束:1'; | ||
| 422 | +COMMENT ON COLUMN "public"."alert_record"."record_status" IS '信息状态,未读:0,已读:1'; | ||
| 423 | +COMMENT ON COLUMN "public"."alert_record"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 424 | +COMMENT ON COLUMN "public"."alert_record"."create_time" IS '创建时间'; | ||
| 425 | +COMMENT ON COLUMN "public"."alert_record"."update_time" IS '更新时间'; | ||
| 426 | +COMMENT ON TABLE "public"."alert_record" IS '告警记录'; | ||
| 427 | + | ||
| 428 | +CREATE TABLE IF NOT EXISTS "public"."notify_template" ( | ||
| 429 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_notify_template_id'::regclass), | ||
| 430 | + "notify_template_name" varchar(100) COLLATE "pg_catalog"."default", | ||
| 431 | + "notify_template_desc" varchar(200) COLLATE "pg_catalog"."default", | ||
| 432 | + "notify_title" varchar(100) COLLATE "pg_catalog"."default", | ||
| 433 | + "notify_content" text COLLATE "pg_catalog"."default" NOT NULL, | ||
| 434 | + "notify_template_type" varchar(50) COLLATE "pg_catalog"."default", | ||
| 435 | + "is_deleted" int1 DEFAULT 0, | ||
| 436 | + "create_time" timestamp(6), | ||
| 437 | + "update_time" timestamp(6) | ||
| 438 | + ); | ||
| 439 | +COMMENT ON COLUMN "public"."notify_template"."id" IS '通知模板ID'; | ||
| 440 | +COMMENT ON COLUMN "public"."notify_template"."notify_template_name" IS '模板名称'; | ||
| 441 | +COMMENT ON COLUMN "public"."notify_template"."notify_template_desc" IS '模板描述'; | ||
| 442 | +COMMENT ON COLUMN "public"."notify_template"."notify_title" IS '消息主题'; | ||
| 443 | +COMMENT ON COLUMN "public"."notify_template"."notify_content" IS '消息内容'; | ||
| 444 | +COMMENT ON COLUMN "public"."notify_template"."notify_template_type" IS 'email、WeCom、DingTalk'; | ||
| 445 | +COMMENT ON COLUMN "public"."notify_template"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 446 | +COMMENT ON COLUMN "public"."notify_template"."create_time" IS '创建时间'; | ||
| 447 | +COMMENT ON COLUMN "public"."notify_template"."update_time" IS '更新时间'; | ||
| 448 | +COMMENT ON TABLE "public"."notify_template" IS '通知模板'; | ||
| 449 | + | ||
| 450 | + | ||
| 451 | +CREATE TABLE IF NOT EXISTS "public"."notify_config" ( | ||
| 452 | + "id" int8 NOT NULL PRIMARY KEY, | ||
| 453 | + "type" varchar(20) COLLATE "pg_catalog"."default", | ||
| 454 | + "email" varchar(100) COLLATE "pg_catalog"."default", | ||
| 455 | + "sender" varchar(50) COLLATE "pg_catalog"."default", | ||
| 456 | + "sever" varchar(100) COLLATE "pg_catalog"."default", | ||
| 457 | + "port" int4, | ||
| 458 | + "account" varchar(50) COLLATE "pg_catalog"."default", | ||
| 459 | + "passwd" varchar(100) COLLATE "pg_catalog"."default", | ||
| 460 | + "agent_id" varchar(100) COLLATE "pg_catalog"."default", | ||
| 461 | + "app_key" varchar(100) COLLATE "pg_catalog"."default", | ||
| 462 | + "secret" text COLLATE "pg_catalog"."default", | ||
| 463 | + "enable" int1 DEFAULT 0, | ||
| 464 | + "is_deleted" int1 DEFAULT 0, | ||
| 465 | + "create_time" timestamp(6), | ||
| 466 | + "update_time" timestamp(6) | ||
| 467 | + ); | ||
| 468 | +COMMENT ON COLUMN "public"."notify_config"."type" IS '发送方式'; | ||
| 469 | +COMMENT ON COLUMN "public"."notify_config"."email" IS '发信邮箱'; | ||
| 470 | +COMMENT ON COLUMN "public"."notify_config"."sender" IS '发信人'; | ||
| 471 | +COMMENT ON COLUMN "public"."notify_config"."sever" IS '服务器'; | ||
| 472 | +COMMENT ON COLUMN "public"."notify_config"."port" IS 'SMTP端口号'; | ||
| 473 | +COMMENT ON COLUMN "public"."notify_config"."account" IS 'SMTP账号'; | ||
| 474 | +COMMENT ON COLUMN "public"."notify_config"."passwd" IS 'SMTP密码'; | ||
| 475 | +COMMENT ON COLUMN "public"."notify_config"."agent_id" IS '应用ID'; | ||
| 476 | +COMMENT ON COLUMN "public"."notify_config"."app_key" IS '企业微信的企业ID或者钉钉的appKey'; | ||
| 477 | +COMMENT ON COLUMN "public"."notify_config"."enable" IS '是否启动,0未启动,1启动'; | ||
| 478 | +COMMENT ON COLUMN "public"."notify_config"."secret" IS '密钥'; | ||
| 479 | +COMMENT ON TABLE "public"."notify_config" IS '通知渠道'; | ||
| 480 | + | ||
| 481 | + | ||
| 482 | +CREATE TABLE IF NOT EXISTS "public"."notify_message" ( | ||
| 483 | + "id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_notify_message_id'::regclass), | ||
| 484 | + "record_id" int8 NOT NULL, | ||
| 485 | + "message_type" varchar(50) COLLATE "pg_catalog"."default", | ||
| 486 | + "title" varchar(100) COLLATE "pg_catalog"."default", | ||
| 487 | + "content" text COLLATE "pg_catalog"."default" NOT NULL, | ||
| 488 | + "email" varchar(100) COLLATE "pg_catalog"."default", | ||
| 489 | + "person_id" varchar(100) COLLATE "pg_catalog"."default", | ||
| 490 | + "dept_id" varchar(100) COLLATE "pg_catalog"."default", | ||
| 491 | + "webhook" text COLLATE "pg_catalog"."default", | ||
| 492 | + "status" int1 DEFAULT 0, | ||
| 493 | + "is_deleted" int1 DEFAULT 0, | ||
| 494 | + "create_time" timestamp(6), | ||
| 495 | + "update_time" timestamp(6) | ||
| 496 | + ); | ||
| 497 | +COMMENT ON COLUMN "public"."notify_message"."id" IS '消息ID'; | ||
| 498 | +COMMENT ON COLUMN "public"."notify_message"."record_id" IS '告警记录ID'; | ||
| 499 | +COMMENT ON COLUMN "public"."notify_message"."message_type" IS 'email WeCom DingTalk'; | ||
| 500 | +COMMENT ON COLUMN "public"."notify_message"."title" IS '消息主题'; | ||
| 501 | +COMMENT ON COLUMN "public"."notify_message"."content" IS '消息内容'; | ||
| 502 | +COMMENT ON COLUMN "public"."notify_message"."email" IS '收件邮箱,当message_type为email时,不为空'; | ||
| 503 | +COMMENT ON COLUMN "public"."notify_message"."person_id" IS '用户ID,当message_type为WeCom或DingTalk时,有用'; | ||
| 504 | +COMMENT ON COLUMN "public"."notify_message"."dept_id" IS '部门ID,当message_type为WeCom或DingTalk时,有用'; | ||
| 505 | +COMMENT ON COLUMN "public"."notify_message"."webhook" IS 'WeCom或者DingTalk提供webhook'; | ||
| 506 | +COMMENT ON COLUMN "public"."notify_message"."status" IS '消息发送状态,0为未发送,1为发送成功,2为发送失败'; | ||
| 507 | +COMMENT ON COLUMN "public"."notify_message"."is_deleted" IS '是否删除,0未删除,1删除'; | ||
| 508 | +COMMENT ON COLUMN "public"."notify_message"."create_time" IS '创建时间'; | ||
| 509 | +COMMENT ON COLUMN "public"."notify_message"."update_time" IS '更新时间'; | ||
| 510 | +COMMENT ON TABLE "public"."notify_message" IS '通知消息'; | ||
| 511 | + | ||
| 512 | +CREATE TABLE IF NOT EXISTS "public"."alert_config" ( | ||
| 513 | +"id" int8 NOT NULL PRIMARY KEY DEFAULT nextval('sq_alert_config_id'::regclass), | ||
| 514 | +"alert_ip" varchar(20) COLLATE "pg_catalog"."default", | ||
| 515 | +"alert_port" varchar(10) COLLATE "pg_catalog"."default" | ||
| 516 | +); | ||
| 517 | + | ||
| 518 | +INSERT INTO public.alert_rule (id,rule_name,level,rule_type,rule_exp_comb,rule_content,notify_duration,notify_duration_unit,is_repeat,is_silence,silence_start_time,silence_end_time,alert_notify,notify_way_ids,alert_desc,is_deleted,create_time,update_time) | ||
| 519 | + VALUES (1,'CPU使用率过高','warn','index','A','$'||'{nodeName}的CPU使用率超过90%',2,'m',1,0,null,null,'firing,recover','1',null,0,'2023-04-26 08:30:22.02',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| 520 | +INSERT INTO public.alert_rule_item (id,rule_id,rule_mark,rule_exp_name,operate,limit_value,unit,rule_exp,rule_item_desc,is_deleted,create_time,update_time,action) | ||
| 521 | + VALUES (1,1,'A','cpuUsage','>=',90,'%','100 - avg(rate(node_cpu_seconds_total{mode="idle",instance=~"$'||'{instances}"}[5m])) by(instance) * 100','CPU使用率大于等于90%',0,'2023-06-05 15:45:20.02',null,'normal') ON DUPLICATE KEY UPDATE NOTHING; | ||
| 522 | + | ||
| 523 | +INSERT INTO public.alert_rule (id,rule_name,level,rule_type,rule_exp_comb,rule_content,notify_duration,notify_duration_unit,is_repeat,is_silence,silence_start_time,silence_end_time,alert_notify,notify_way_ids,alert_desc,is_deleted,create_time,update_time) | ||
| 524 | + VALUES (2,'内存使用率过高','serious','index','A','$'||'{nodeName}的内存使用率超过90%',2,'m',1,0,null,null,'firing,recover','1','内存使用率过高',0,'2023-06-05 15:45:20.02',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| 525 | +INSERT INTO public.alert_rule_item (id,rule_id,rule_mark,rule_exp_name,operate,limit_value,unit,rule_exp,rule_item_desc,is_deleted,create_time,update_time,action) | ||
| 526 | + VALUES (2,2,'A','memoryUsage','>=',90,'%','100 * (1 - (node_memory_MemFree_bytes + node_memory_Cached_bytes + node_memory_Buffers_bytes) / node_memory_MemTotal_bytes{instance=~"$'||'{instances}"})','内存使用率大于等于90%',0,'2023-06-05 15:45:20.02',null,'normal') ON DUPLICATE KEY UPDATE NOTHING; | ||
| 527 | + | ||
| 528 | +INSERT INTO public.alert_rule (id,rule_name,level,rule_type,rule_exp_comb,rule_content,notify_duration,notify_duration_unit,is_repeat,is_silence,silence_start_time,silence_end_time,alert_notify,notify_way_ids,alert_desc,is_deleted,create_time,update_time) | ||
| 529 | + VALUES (3,'磁盘使用量过高','serious','index','A','$'||'{nodeName}的磁盘(/dev/vda1)使用量超过15GB',2,'m',1,0,null,null,'firing,recover','1','磁盘使用量过高',0,'2023-06-05 15:45:20.02',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| 530 | +INSERT INTO public.alert_rule_item (id,rule_id,rule_mark,rule_exp_name,operate,limit_value,unit,rule_exp,rule_item_desc,is_deleted,create_time,update_time,action) | ||
| 531 | + VALUES (3,3,'A','diskUsage','>=',15360,'MB','(node_filesystem_size_bytes{device=~"/dev/vda1",instance="$' || '{instances}"} - node_filesystem_free_bytes) /1024/1024','内存使用率大于等于90%',0,'2023-06-05 15:45:20.02',null,'normal') ON DUPLICATE KEY UPDATE NOTHING; | ||
| 532 | +insert into public.alert_rule_item_param(id,item_id,param_name,param_value,param_order,is_deleted,create_time) values(1,3,'filesystemPath','/dev/vda1',1,0,'2023-06-05 15:45:20.02'); | ||
| 533 | + | ||
| 534 | +INSERT INTO public.alert_rule (id,rule_name,level,rule_type,rule_exp_comb,rule_content,notify_duration,notify_duration_unit,is_repeat,is_silence,silence_start_time,silence_end_time,alert_notify,notify_way_ids,alert_desc,is_deleted,create_time,update_time) | ||
| 535 | + VALUES (4,'磁盘写速率过高','serious','index','A','$'||'{nodeName}的磁盘写速率大于等于100MB/s',2,'m',1,0,null,null,'firing','1','磁盘写速率过高',0,'2023-06-05 15:45:20.02',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| 536 | +INSERT INTO public.alert_rule_item (id,rule_id,rule_mark,rule_exp_name,operate,limit_value,unit,rule_exp,rule_item_desc,is_deleted,create_time,update_time,action) | ||
| 537 | + VALUES (4,4,'A','diskWriteRate','>=',100,'MB/s','sum(rate(node_disk_written_bytes_total{instance=~"$' || '{instances}"}[2m])) by (instance) /1024/1024','磁盘写速率大于等于100MB/s',0,'2023-06-05 15:45:20.02',null,'normal') ON DUPLICATE KEY UPDATE NOTHING; | ||
| 538 | + | ||
| 539 | +INSERT INTO public.alert_rule (id,rule_name,level,rule_type,rule_exp_comb,rule_content,notify_duration,notify_duration_unit,is_repeat,is_silence,silence_start_time,silence_end_time,alert_notify,notify_way_ids,alert_desc,is_deleted,create_time,update_time) | ||
| 540 | + VALUES (5,'磁盘读速率过高','serious','index','A','$'||'{nodeName}的磁盘读速率大于等于100MB/s',2,'m',1,0,null,null,'firing','1','磁盘读速率过高',0,'2023-06-05 15:45:20.02',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| 541 | +INSERT INTO public.alert_rule_item (id,rule_id,rule_mark,rule_exp_name,operate,limit_value,unit,rule_exp,rule_item_desc,is_deleted,create_time,update_time,action) | ||
| 542 | + VALUES (5,5,'A','diskReadRate','>=',100,'MB/s','sum(rate(node_disk_read_bytes_total{instance=~"$'||'{instances}"}[2m])) by (instance) /1024/1024','磁盘读速率大于等于100MB/s',0,'2023-06-05 15:45:20.02',null,'normal') ON DUPLICATE KEY UPDATE NOTHING; | ||
| 543 | + | ||
| 544 | +INSERT INTO public.notify_template (id,notify_template_name,notify_template_desc,notify_title,notify_content,notify_template_type,is_deleted,create_time,update_time) | ||
| 545 | +VALUES (1,'通用告警模板',null,'告警信息','告警时间:$'||'{alertTime}'||chr(10)||'告警等级:$'||'{level}'||chr(10)||'告警实例:$'||'{nodeName}'||chr(10)||'主机IP:$'||'{hostIp}'||chr(10)||'告警内容:$'||'{content}'||chr(10),'email',0,'2023-04-26 08:30:22.02',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| 546 | +INSERT INTO public.notify_way (id,name,notify_type,phone,email,person_id,dept_id,message_template_id,is_deleted,create_time,update_time) | ||
| 547 | +VALUES (1,'通用告警方式','email',null,'xxxx@xxx.com',null,null,1,0,'2023-05-24 11:25:38.073319',null) ON DUPLICATE KEY UPDATE NOTHING; | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | +cpuUsage=CPU Usage | ||
| 2 | +memoryUsage=Memory Usage | ||
| 3 | +diskUsage=Disk Usage | ||
| 4 | +diskWriteRate=Disk Write Rate | ||
| 5 | +diskReadRate=Disk Read Rate | ||
| 6 | +rule.ruleItem.normalAction=keep happening | ||
| 7 | +rule.ruleItem.increaseAction=keep increasing | ||
| 8 | +rule.ruleItem.decreaseAction=keep decreasing | ||
| 9 | +templateIsUsed=The rule template is used,it can't be deleted.Please go to the Alert Config to remove the template before deleting it. | ||
| 10 | +notifyTemplateIsUsed=The notify template is used,it can't be deleted.Please go to the notify way module to remove the template before deleting it. | ||
| 11 | +notifyWayIsUsed=The notify template is used,it can't be deleted.it can't be deleted.Please go to the alert rule module or \ | ||
| 12 | + the alert template module to remove the notify way before deleting it. | ||
| 13 | +alertContentParam.nodeName=cluster node name | ||
| 14 | +alertContentParam.hostname=hostname | ||
| 15 | +alertContentParam.hostIp=host IP | ||
| 16 | +alertContentParam.port=database port | ||
| 17 | +alertContentParam.alertTime=alert time | ||
| 18 | +alertContentParam.alertStatus=alert status | ||
| 19 | +alertContentParam.level=alert level | ||
| 20 | +alertContentParam.content=alert content | ||
| 21 | +alerting=firing | ||
| 22 | +alerted=recover | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | +cpuUsage=Usage of CPU | ||
| 2 | +memoryUsage=Memory Usage | ||
| 3 | +diskUsage=Disk Usage | ||
| 4 | +diskWriteRate=Disk Write Rate | ||
| 5 | +diskReadRate=Disk Read Rate | ||
| 6 | +rule.ruleItem.normalAction=keep happening | ||
| 7 | +rule.ruleItem.increaseAction=keep increasing | ||
| 8 | +rule.ruleItem.decreaseAction=keep decreasing | ||
| 9 | +templateIsUsed=The rule template is used,it can't be deleted.Please go to the Alert Config to remove the template before deleting it. | ||
| 10 | +notifyTemplateIsUsed=The notify template is used,it can't be deleted.Please go to the notify way module to remove the template before deleting it. | ||
| 11 | +notifyWayIsUsed=The notify template is used,it can't be deleted.it can't be deleted.Please go to the alert rule module or \ | ||
| 12 | + the alert template module to remove the notify way before deleting it. | ||
| 13 | +alertContentParam.nodeName=cluster node name | ||
| 14 | +alertContentParam.hostname=hostname | ||
| 15 | +alertContentParam.hostIp=host IP | ||
| 16 | +alertContentParam.port=database port | ||
| 17 | +alertContentParam.alertTime=alert time | ||
| 18 | +alertContentParam.alertStatus=alert status | ||
| 19 | +alertContentParam.level=alert level | ||
| 20 | +alertContentParam.content=alert content | ||
| 21 | +alerting=firing | ||
| 22 | +alerted=recover | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | +cpuUsage=CPU使用率 | ||
| 2 | +memoryUsage=内存使用率 | ||
| 3 | +diskUsage=磁盘使用量 | ||
| 4 | +diskWriteRate=磁盘的写速率 | ||
| 5 | +diskReadRate=磁盘的读速率 | ||
| 6 | +rule.ruleItem.normalAction=持续发生 | ||
| 7 | +rule.ruleItem.increaseAction=持续增长 | ||
| 8 | +rule.ruleItem.decreaseAction=持续下降 | ||
| 9 | +templateIsUsed=模板正被使用,无法删除,需要到告警配置中解除该模板,才能删除 | ||
| 10 | +notifyTemplateIsUsed=通知模板正被使用,无法删除,需要到通知方式模块中解除该模板,才能删除 | ||
| 11 | +notifyWayIsUsed=该通知方式正在被使用,无法删除,需要到告警规则模块或者告警模板模块解除该通知方式,才能删除 | ||
| 12 | +alertContentParam.nodeName=节点名称 | ||
| 13 | +alertContentParam.hostname=主机名称 | ||
| 14 | +alertContentParam.hostIp=主机IP | ||
| 15 | +alertContentParam.port=数据库端口号 | ||
| 16 | +alertContentParam.alertTime=告警时间 | ||
| 17 | +alertContentParam.alertStatus=告警状态 | ||
| 18 | +alertContentParam.level=告警级别 | ||
| 19 | +alertContentParam.content=告警内容 | ||
| 20 | +alerting=告警中 | ||
| 21 | +alerted=告警结束 | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +# 开发环境配置 | ||
| 2 | +ENV = 'development' | ||
| 3 | + | ||
| 4 | +# 开发环境 | ||
| 5 | +VITE_BASE_URL = 'http://localhost:8080' | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +# 生产环境配置 | ||
| 2 | +ENV = 'production' | ||
| 3 | + | ||
| 4 | +# 生产环境 | ||
| 5 | +VITE_BASE_URL = 'http://10.10.9.221' | ||
| @@ -0,0 +1,57 @@ | |||
| 1 | +{ | ||
| 2 | + "globals": { | ||
| 3 | + "EffectScope": true, | ||
| 4 | + "computed": true, | ||
| 5 | + "createApp": true, | ||
| 6 | + "customRef": true, | ||
| 7 | + "defineAsyncComponent": true, | ||
| 8 | + "defineComponent": true, | ||
| 9 | + "effectScope": true, | ||
| 10 | + "getCurrentInstance": true, | ||
| 11 | + "getCurrentScope": true, | ||
| 12 | + "h": true, | ||
| 13 | + "inject": true, | ||
| 14 | + "isProxy": true, | ||
| 15 | + "isReactive": true, | ||
| 16 | + "isReadonly": true, | ||
| 17 | + "isRef": true, | ||
| 18 | + "markRaw": true, | ||
| 19 | + "nextTick": true, | ||
| 20 | + "onActivated": true, | ||
| 21 | + "onBeforeMount": true, | ||
| 22 | + "onBeforeUnmount": true, | ||
| 23 | + "onBeforeUpdate": true, | ||
| 24 | + "onDeactivated": true, | ||
| 25 | + "onErrorCaptured": true, | ||
| 26 | + "onMounted": true, | ||
| 27 | + "onRenderTracked": true, | ||
| 28 | + "onRenderTriggered": true, | ||
| 29 | + "onScopeDispose": true, | ||
| 30 | + "onServerPrefetch": true, | ||
| 31 | + "onUnmounted": true, | ||
| 32 | + "onUpdated": true, | ||
| 33 | + "provide": true, | ||
| 34 | + "reactive": true, | ||
| 35 | + "readonly": true, | ||
| 36 | + "ref": true, | ||
| 37 | + "resolveComponent": true, | ||
| 38 | + "shallowReactive": true, | ||
| 39 | + "shallowReadonly": true, | ||
| 40 | + "shallowRef": true, | ||
| 41 | + "toRaw": true, | ||
| 42 | + "toRef": true, | ||
| 43 | + "toRefs": true, | ||
| 44 | + "triggerRef": true, | ||
| 45 | + "unref": true, | ||
| 46 | + "useAttrs": true, | ||
| 47 | + "useCssModule": true, | ||
| 48 | + "useCssVars": true, | ||
| 49 | + "useRoute": true, | ||
| 50 | + "useRouter": true, | ||
| 51 | + "useSlots": true, | ||
| 52 | + "watch": true, | ||
| 53 | + "watchEffect": true, | ||
| 54 | + "watchPostEffect": true, | ||
| 55 | + "watchSyncEffect": true | ||
| 56 | + } | ||
| 57 | +} | ||
| @@ -0,0 +1,35 @@ | |||
| 1 | +{ | ||
| 2 | + "env": { | ||
| 3 | + "browser": true, | ||
| 4 | + "es2021": true | ||
| 5 | + }, | ||
| 6 | + "extends": [ | ||
| 7 | + "plugin:vue/vue3-essential", | ||
| 8 | + "standard", | ||
| 9 | + "./.eslintrc-auto-import.json" | ||
| 10 | + ], | ||
| 11 | + "parserOptions": { | ||
| 12 | + "ecmaVersion": "latest", | ||
| 13 | + "parser": "@typescript-eslint/parser", | ||
| 14 | + "sourceType": "module" | ||
| 15 | + }, | ||
| 16 | + "plugins": [ | ||
| 17 | + "vue", | ||
| 18 | + "@typescript-eslint" | ||
| 19 | + ], | ||
| 20 | + "rules": { | ||
| 21 | + "prefer-regex-literals": 0, | ||
| 22 | + "vue/multi-word-component-names": 0, | ||
| 23 | + "no-control-regex": 0, | ||
| 24 | + "indent": ["error", 4], | ||
| 25 | + "quotes": 0, | ||
| 26 | + "comma-dangle": 0, | ||
| 27 | + "semi": 0, | ||
| 28 | + "dot-notation": 0, | ||
| 29 | + "space-before-function-paren": 0, | ||
| 30 | + "prefer-const": 0, | ||
| 31 | + "no-trailing-spaces": 0, | ||
| 32 | + "func-call-spacing": 0 | ||
| 33 | + }, | ||
| 34 | + "ignorePatterns": ["src/**/*.d.ts"] | ||
| 35 | +} | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | +# Logs | ||
| 2 | +logs | ||
| 3 | +*.log | ||
| 4 | +npm-debug.log* | ||
| 5 | +yarn-debug.log* | ||
| 6 | +yarn-error.log* | ||
| 7 | +pnpm-debug.log* | ||
| 8 | +lerna-debug.log* | ||
| 9 | + | ||
| 10 | +node_modules | ||
| 11 | +dist | ||
| 12 | +dist-ssr | ||
| 13 | +*.local | ||
| 14 | + | ||
| 15 | +# Editor directories and files | ||
| 16 | +.vscode/* | ||
| 17 | +!.vscode/extensions.json | ||
| 18 | +.idea | ||
| 19 | +.DS_Store | ||
| 20 | +*.suo | ||
| 21 | +*.ntvs* | ||
| 22 | +*.njsproj | ||
| 23 | +*.sln | ||
| 24 | +*.sw? | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +{ | ||
| 2 | + "printWidth": 120, | ||
| 3 | + "singleQuote": true, | ||
| 4 | + "semi": false, | ||
| 5 | + "tabWidth": 4 | ||
| 6 | +} | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +# Vue 3 + TypeScript + Vite | ||
| 2 | + | ||
| 3 | +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. | ||
| 4 | + | ||
| 5 | +## Recommended IDE Setup | ||
| 6 | + | ||
| 7 | +- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) | ||
| 8 | + | ||
| 9 | +## Type Support For `.vue` Imports in TS | ||
| 10 | + | ||
| 11 | +Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps: | ||
| 12 | + | ||
| 13 | +1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled. | ||
| 14 | +2. Reload the VS Code window by running `Developer: Reload Window` from the command palette. | ||
| 15 | + | ||
| 16 | +You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471). | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | + | ||
| 2 | +<html lang="en" class="dark"> | ||
| 3 | + <head> | ||
| 4 | + <meta charset="UTF-8" /> | ||
| 5 | + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
| 6 | + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| 7 | + <title>一体化平台</title> | ||
| 8 | + </head> | ||
| 9 | + <body> | ||
| 10 | + <div id="app"></div> | ||
| 11 | + <script type="module" src="/src/main.ts"></script> | ||
| 12 | + <script type="module"> | ||
| 13 | + document.getElementById('app').style.height = | ||
| 14 | + import.meta.env.MODE === 'production' ? 'calc(100vh - 170px)' : '100%'; | ||
| 15 | + </script> | ||
| 16 | + </body> | ||
| 17 | +</html> | ||
| @@ -0,0 +1,67 @@ | |||
| 1 | +{ | ||
| 2 | + "name": "plugin-vem", | ||
| 3 | + "private": true, | ||
| 4 | + "version": "0.0.0", | ||
| 5 | + "type": "module", | ||
| 6 | + "scripts": { | ||
| 7 | + "dev": "vite --host 0.0.0.0", | ||
| 8 | + "build": "vue-tsc --noEmit && vite build", | ||
| 9 | + "buildNoTest": "vite build", | ||
| 10 | + "buildDev": "vite build --mode development", | ||
| 11 | + "preview": "vite preview", | ||
| 12 | + "lint": "eslint --ext .ts,.vue --fix src && vue-tsc --noEmit" | ||
| 13 | + }, | ||
| 14 | + "dependencies": { | ||
| 15 | + "@element-plus/icons-vue": "^2.0.9", | ||
| 16 | + "@vueuse/core": "^9.0.0", | ||
| 17 | + "axios": "^0.27.2", | ||
| 18 | + "cron-parser": "^4.6.0", | ||
| 19 | + "dayjs": "^1.11.5", | ||
| 20 | + "echarts": "^5.4.0", | ||
| 21 | + "element-plus": "^2.2.15", | ||
| 22 | + "jsencrypt": "^3.0.0-rc.1", | ||
| 23 | + "lodash-es": "^4.17.21", | ||
| 24 | + "md5": "^2.3.0", | ||
| 25 | + "moment": "^2.29.4", | ||
| 26 | + "monaco-editor": "^0.34.0", | ||
| 27 | + "p-limit": "^4.0.0", | ||
| 28 | + "pinia": "^2.0.16", | ||
| 29 | + "pinia-plugin-persistedstate": "^1.6.3", | ||
| 30 | + "sql-formatter": "^8.2.0", | ||
| 31 | + "uuid": "^8.3.2", | ||
| 32 | + "vis": "^4.21.0-EOL", | ||
| 33 | + "vue": "^3.2.37", | ||
| 34 | + "vue-grid-layout": "^3.0.0-beta1", | ||
| 35 | + "vue-i18n": "9", | ||
| 36 | + "vue-request": "2.0.0-rc.3", | ||
| 37 | + "vue-router": "^4.1.2" | ||
| 38 | + }, | ||
| 39 | + "devDependencies": { | ||
| 40 | + "@types/lodash-es": "^4.17.6", | ||
| 41 | + "@types/md5": "^2.3.2", | ||
| 42 | + "@types/node": "^18.6.1", | ||
| 43 | + "@types/uuid": "^8.3.4", | ||
| 44 | + "@types/vis": "^4.21.24", | ||
| 45 | + "@typescript-eslint/eslint-plugin": "^5.31.0", | ||
| 46 | + "@typescript-eslint/parser": "^5.31.0", | ||
| 47 | + "@vitejs/plugin-vue": "^3.0.0", | ||
| 48 | + "css-loader": "^6.7.1", | ||
| 49 | + "eslint": "^8.0.1", | ||
| 50 | + "eslint-config-prettier": "^8.5.0", | ||
| 51 | + "eslint-config-standard": "^17.0.0", | ||
| 52 | + "eslint-plugin-import": "^2.25.2", | ||
| 53 | + "eslint-plugin-n": "^15.0.0", | ||
| 54 | + "eslint-plugin-prettier": "^4.2.1", | ||
| 55 | + "eslint-plugin-promise": "^6.0.0", | ||
| 56 | + "eslint-plugin-vue": "^9.3.0", | ||
| 57 | + "prettier": "^2.7.1", | ||
| 58 | + "sass": "^1.54.0", | ||
| 59 | + "style-loader": "^3.3.1", | ||
| 60 | + "typescript": "^4.6.4", | ||
| 61 | + "unplugin-auto-import": "^0.10.1", | ||
| 62 | + "unplugin-vue-components": "^0.21.1", | ||
| 63 | + "vite": "^3.0.0", | ||
| 64 | + "vite-plugin-svg-icons": "^2.0.1", | ||
| 65 | + "vue-tsc": "^0.38.4" | ||
| 66 | + } | ||
| 67 | +} | ||
| @@ -0,0 +1,183 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import zhCn from "element-plus/lib/locale/lang/zh-cn"; | ||
| 3 | +import en from "element-plus/lib/locale/lang/en"; | ||
| 4 | +import { useDark, useToggle } from "@vueuse/core"; | ||
| 5 | +import { useWindowStore } from "./store/window"; | ||
| 6 | +import router from './router'; | ||
| 7 | +import { i18n } from './i18n' | ||
| 8 | +import { useMonitorStore } from "./store/monitor"; | ||
| 9 | +import { useAlertConfigStore } from "./store/alertConfig"; | ||
| 10 | +import AlertConfig from "@/components/AlertConfig.vue"; | ||
| 11 | +import { checkPrometheus } from "./api/environment"; | ||
| 12 | +import { getAlertConf } from "./api/alertConfig" | ||
| 13 | +import { fa } from "element-plus/es/locale"; | ||
| 14 | + | ||
| 15 | +const observabilitySign = 'alert-center'; | ||
| 16 | + | ||
| 17 | +const themeBool = ref<boolean>(false) | ||
| 18 | + | ||
| 19 | +const isDark = useDark({ | ||
| 20 | + // 存储到localStorage/sessionStorage中的Key 根据自己的需求更改 | ||
| 21 | + storageKey: 'theme', | ||
| 22 | + // 暗黑class名字 | ||
| 23 | + valueDark: 'dark', | ||
| 24 | + // 高亮class名字 | ||
| 25 | + valueLight: 'light', | ||
| 26 | +}) | ||
| 27 | + | ||
| 28 | +useToggle(isDark); | ||
| 29 | + | ||
| 30 | +const collapse = ref(false) | ||
| 31 | +const isFromObservability = ref<boolean>(false); | ||
| 32 | +const mainDiv = ref<HTMLDivElement | null>(); | ||
| 33 | +const windowStore = useWindowStore(); | ||
| 34 | +const monitorStore = useMonitorStore(); | ||
| 35 | +const alertConfigEnv = useAlertConfigStore(); | ||
| 36 | + | ||
| 37 | +// wujie frame special params | ||
| 38 | +const getWujieParam = () => { | ||
| 39 | + // @ts-ignore | ||
| 40 | + if (window.$wujie) { | ||
| 41 | + // @ts-ignore | ||
| 42 | + const { id } = window.$wujie.props; | ||
| 43 | + if (typeof id === 'string' && id !== '') { | ||
| 44 | + monitorStore.instanceId = id; | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +const dealUrlTo = () => { | ||
| 50 | + let urlTo = '/vem'; | ||
| 51 | + const curUrl = window.location.href; | ||
| 52 | + if (curUrl.indexOf(observabilitySign) > -1) { | ||
| 53 | + isFromObservability.value = true; | ||
| 54 | + if (curUrl.indexOf('/vem') > -1) { | ||
| 55 | + urlTo = curUrl.slice(curUrl.indexOf('/vem')); | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + router.replace(urlTo); | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +const onThemeChange = (bool: boolean, themeType: string) => { | ||
| 62 | + themeBool.value = bool; | ||
| 63 | + localStorage.setItem("theme", themeType) | ||
| 64 | + windowStore.setTheme(themeType); | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +const wujieInit = () => { | ||
| 68 | + if (localStorage.getItem("locale") === "en-US") { | ||
| 69 | + i18n.global.locale.value = 'en'; | ||
| 70 | + } else { | ||
| 71 | + i18n.global.locale.value = 'zhCn'; | ||
| 72 | + } | ||
| 73 | + if (localStorage.getItem("opengauss-theme") === "dark") { | ||
| 74 | + onThemeChange(false, 'dark'); | ||
| 75 | + } else { | ||
| 76 | + onThemeChange(true, 'auto'); | ||
| 77 | + } | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +onMounted(async () => { | ||
| 81 | + new ResizeObserver(() => { | ||
| 82 | + windowStore.setMainHeight(mainDiv.value!.clientHeight); | ||
| 83 | + windowStore.setMainWidth(mainDiv.value!.clientWidth); | ||
| 84 | + }).observe(mainDiv.value!); | ||
| 85 | + dealUrlTo(); | ||
| 86 | + getWujieParam(); | ||
| 87 | + | ||
| 88 | + // @ts-ignore | ||
| 89 | + const wujie = window.$wujie; | ||
| 90 | + // Judge whether it is a plug-in environment or a local environment through wujie | ||
| 91 | + if (wujie) { | ||
| 92 | + localStorage.setItem("INSTANCE_CURRENT_MODE", "wujie") | ||
| 93 | + | ||
| 94 | + // init theme and language | ||
| 95 | + wujieInit(); | ||
| 96 | + | ||
| 97 | + // Monitoring platform theme changes | ||
| 98 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 99 | + if (val === 'dark') { | ||
| 100 | + onThemeChange(false, 'dark'); | ||
| 101 | + } else { | ||
| 102 | + onThemeChange(true, 'auto'); | ||
| 103 | + } | ||
| 104 | + }) | ||
| 105 | + | ||
| 106 | + // Monitoring platform language change | ||
| 107 | + wujie?.bus.$on('opengauss-locale-change', (val: string) => { | ||
| 108 | + if (val === "en-US") { | ||
| 109 | + i18n.global.locale.value = 'en'; | ||
| 110 | + } else { | ||
| 111 | + i18n.global.locale.value = 'zhCn'; | ||
| 112 | + } | ||
| 113 | + }) | ||
| 114 | + } else { | ||
| 115 | + // local default | ||
| 116 | + localStorage.setItem("INSTANCE_CURRENT_MODE", "local") | ||
| 117 | + } | ||
| 118 | + if (!alertConfigEnv.isInstall || !alertConfigEnv.isConfig) { | ||
| 119 | + if (!alertConfigEnv.isInstall) { | ||
| 120 | + await checkPrometheus().then(async (res: any) => { | ||
| 121 | + if (res && res.code === 200) { | ||
| 122 | + alertConfigEnv.isInstall = true | ||
| 123 | + } else { | ||
| 124 | + alertConfigEnv.isInstall = false | ||
| 125 | + } | ||
| 126 | + }).catch(() => { | ||
| 127 | + alertConfigEnv.isInstall = false | ||
| 128 | + }) | ||
| 129 | + } | ||
| 130 | + if (!alertConfigEnv.isConfig) { | ||
| 131 | + await getAlertConf().then(async (res: any) => { | ||
| 132 | + if (res && res.code === 200 && res.data && res.data.alertIp && res.data.alertPort) { | ||
| 133 | + alertConfigEnv.isConfig = true | ||
| 134 | + } else { | ||
| 135 | + alertConfigEnv.isConfig = false | ||
| 136 | + } | ||
| 137 | + }).catch(() => { | ||
| 138 | + alertConfigEnv.isConfig = false | ||
| 139 | + }) | ||
| 140 | + } | ||
| 141 | + alertConfigEnv.showMain = alertConfigEnv.isInstall && alertConfigEnv.isConfig | ||
| 142 | + } | ||
| 143 | +}) | ||
| 144 | +</script> | ||
| 145 | + | ||
| 146 | +<template> | ||
| 147 | + <el-config-provider size="small" :locale="$i18n.locale === 'zhCn' ? zhCn : en"> | ||
| 148 | + <div class="container"> | ||
| 149 | + <aside v-if="!isFromObservability"> | ||
| 150 | + <my-menu :collapse="collapse" /> | ||
| 151 | + </aside> | ||
| 152 | + <div class="main" ref="mainDiv"> | ||
| 153 | + <div class="page" v-if="alertConfigEnv.showMain"><router-view /> | ||
| 154 | + </div> | ||
| 155 | + <AlertConfig class="page" v-else /> | ||
| 156 | + </div> | ||
| 157 | + </div> | ||
| 158 | + </el-config-provider> | ||
| 159 | +</template> | ||
| 160 | + | ||
| 161 | +<style scoped lang="scss"> | ||
| 162 | +.container { | ||
| 163 | + /* height: calc(100% - var(--vem-header-height)); */ | ||
| 164 | + height: 100%; | ||
| 165 | + overflow: hidden; | ||
| 166 | + display: flex; | ||
| 167 | + flex-flow: row nowrap; | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +.main { | ||
| 171 | + flex: 1; | ||
| 172 | + min-width: 0; | ||
| 173 | + background-color: var(--el-bg-color); | ||
| 174 | + display: flex; | ||
| 175 | + flex-direction: column; | ||
| 176 | +} | ||
| 177 | + | ||
| 178 | +.page { | ||
| 179 | + padding: 16px; | ||
| 180 | + height: calc(100% - var(--vem-header-height)); | ||
| 181 | + overflow: auto; | ||
| 182 | +} | ||
| 183 | +</style> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +import request from '@/request'; | ||
| 2 | + | ||
| 3 | +export async function getAlertConf(): Promise<any> { | ||
| 4 | + return request.get("/alertCenter/api/v1/alertConf") | ||
| 5 | +} | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +import request from "@/request"; | ||
| 2 | + | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +import request from '@/request'; | ||
| 2 | + | ||
| 3 | +export async function checkPrometheus(): Promise<any> { | ||
| 4 | + return request.get("/alertCenter/api/v1/environment/checkPrometheus") | ||
| 5 | +} | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +$--charts-1: #246cff; | ||
| 5 | +$--charts-2: #37c461; | ||
| 6 | +$--charts-3: #ffbe00; | ||
| 7 | +$--charts-4: #ff7200; | ||
| 8 | +$--charts-5: #3dc7ff; | ||
| 9 | +$--charts-6: #d13fd9; | ||
| 10 | +$--charts-7: #975fe4; | ||
| 11 | +$--charts-8: #465d86; | ||
| 12 | +$--charts-9: #00abaa; | ||
| 13 | +$--charts-10: #9ae75d; | ||
| 14 | +$--charts-11: #f08bb4; | ||
| 15 | + | ||
| 16 | +$--charts-extend-1: #cdddfd; | ||
| 17 | +$--charts-extend-2: #cdf3e4; | ||
| 18 | +$--charts-extend-3: #fcebb9; | ||
| 19 | +$--charts-extend-4: #ffd4c7; | ||
| 20 | +$--charts-extend-5: #d3eef9; | ||
| 21 | +$--charts-extend-6: #edb2f0; | ||
| 22 | +$--charts-extend-7: #decfea; | ||
| 23 | +$--charts-extend-8: #ced4de; | ||
| 24 | +$--charts-extend-9: #bbdede; | ||
| 25 | +$--charts-extend-10: #d7f5be; | ||
| 26 | +$--charts-extend-11: #ffe0ed; | ||
| 27 | + | ||
| 28 | +:export { | ||
| 29 | + chartColors: $--charts-1, $--charts-2, $--charts-3, $--charts-4, $--charts-5, $--charts-7, $--charts-8, $--charts-9, | ||
| 30 | + $--charts-6, $--charts-10, $--charts-11, $--charts-extend-1, $--charts-extend-2, $--charts-extend-3, | ||
| 31 | + $--charts-extend-4, $--charts-extend-5, $--charts-extend-6, $--charts-extend-7, $--charts-extend-8, | ||
| 32 | + $--charts-extend-9, $--charts-extend-10, $--charts-extend-11; | ||
| 33 | +} | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +$og-primary-color: #5c5c5c; | ||
| 5 | +$og-sub-primary-color: #0093ff; | ||
| 6 | +$og-success-color: #52c41a; | ||
| 7 | +$og-error-color: #ff4d4f; | ||
| 8 | +$og-border-color: #4a4a4a; | ||
| 9 | +$og-sub-border-color: #bcbcbc; | ||
| 10 | +$og-button-border-color: #353535; | ||
| 11 | +$og-text-color: #d4d4d4; | ||
| 12 | +$og-disabled-text-color: #b3b3b3; | ||
| 13 | +$og-background-color: #212121; | ||
| 14 | +$og-sub-background-color: #424242; | ||
| 15 | +$og-hover-background-color: #323e43; | ||
| 16 | +$og-menu-color: #cfcfcf; | ||
| 17 | +$og-button-active-color: #7d7d7d; | ||
| 18 | +$og-content-color: #303030; | ||
| 19 | + | ||
| 20 | +$og-sub-text-color: #00bcd4; | ||
| 21 | +$og-svg-fill-color: #00bcd4; | ||
| 22 | + | ||
| 23 | +$--primary-6: #e41d1d; | ||
| 24 | +$--primary-5: #e94842; | ||
| 25 | +$--primary-7: #be1118; | ||
| 26 | +$--primary-4: #fac4bc; | ||
| 27 | +$--primary-3: #f49c92; | ||
| 28 | +$--primary-2: #f49c92; | ||
| 29 | +$--primary-1: #ffece8; | ||
| @@ -0,0 +1,240 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +@use 'sass:math'; | ||
| 5 | +@use './color.scss' as *; | ||
| 6 | +@use 'sass:map'; | ||
| 7 | + | ||
| 8 | +// page-header | ||
| 9 | +.page-header { | ||
| 10 | + display: flex; | ||
| 11 | + flex-direction: row; | ||
| 12 | + align-items: center; | ||
| 13 | + padding-bottom: 7px; | ||
| 14 | + border-bottom: 1px solid var(--border-1); | ||
| 15 | + | ||
| 16 | + .icon { | ||
| 17 | + width: 4px; | ||
| 18 | + height: 14px; | ||
| 19 | + background: var(--primary-6); | ||
| 20 | + border-radius: 1px; | ||
| 21 | + margin-right: 4px; | ||
| 22 | + } | ||
| 23 | + .title { | ||
| 24 | + font-family: 'Source Han Sans CN'; | ||
| 25 | + font-style: normal; | ||
| 26 | + font-weight: 700; | ||
| 27 | + font-size: 16px; | ||
| 28 | + line-height: 22px; | ||
| 29 | + height: 22px; | ||
| 30 | + /* identical to box height, or 138% */ | ||
| 31 | + letter-spacing: -0.01px; | ||
| 32 | + color: var(--text-1); | ||
| 33 | + } | ||
| 34 | + .seperator { | ||
| 35 | + margin: 0px 16px; | ||
| 36 | + width: 18px; | ||
| 37 | + height: 0px; | ||
| 38 | + border: 1px solid var(--border-1); | ||
| 39 | + transform: rotate(90deg); | ||
| 40 | + } | ||
| 41 | + .cluster-title { | ||
| 42 | + height: 22px; | ||
| 43 | + font-family: 'Source Han Sans CN'; | ||
| 44 | + font-style: normal; | ||
| 45 | + font-weight: 400; | ||
| 46 | + font-size: 14px; | ||
| 47 | + line-height: 22px; | ||
| 48 | + color: var(--text-1); | ||
| 49 | + } | ||
| 50 | + .instance-info { | ||
| 51 | + margin-left: 4px; | ||
| 52 | + } | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +// card margin bottom | ||
| 56 | +.card-margin-bottom { | ||
| 57 | + margin-bottom: 16px; | ||
| 58 | +} | ||
| 59 | +.card-links { | ||
| 60 | + .el-link { | ||
| 61 | + margin-right: 10px; | ||
| 62 | + } | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +// tabs in card | ||
| 66 | +.card-tabs { | ||
| 67 | + &.el-tabs { | ||
| 68 | + --el-tabs-header-height: 32px; | ||
| 69 | + > .el-tabs__header { | ||
| 70 | + .el-tabs__item { | ||
| 71 | + padding: 0px 16px ; | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +// table in card | ||
| 78 | +.table-in-card { | ||
| 79 | + padding: 0px 16px; | ||
| 80 | + .el-table--border { | ||
| 81 | + border: 1px solid rgba(22, 93, 255, 0.4); | ||
| 82 | + } | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +// text in card | ||
| 86 | +.text-in-card { | ||
| 87 | + padding: 8px 16px; | ||
| 88 | + .text-row { | ||
| 89 | + display: flex; | ||
| 90 | + flex-direction: row; | ||
| 91 | + .label { | ||
| 92 | + width: 115px; | ||
| 93 | + text-align: right; | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | +} | ||
| 97 | + | ||
| 98 | +// normal grid header | ||
| 99 | +.grid-header { | ||
| 100 | + background: var(--background-color-2) ; | ||
| 101 | + .cell { | ||
| 102 | + line-height: 22px ; | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +// grid header when grid is in card | ||
| 107 | +.grid-header-in-card { | ||
| 108 | + background: var(--background-color-3) ; | ||
| 109 | + .cell { | ||
| 110 | + line-height: 22px ; | ||
| 111 | + } | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +.table-link { | ||
| 115 | + color: var(--link-6); | ||
| 116 | + cursor: pointer; | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +.el-tabs__item.is-disabled { | ||
| 120 | + cursor: auto ; | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +// table | ||
| 124 | +.normal-table { | ||
| 125 | + .operate-btns { | ||
| 126 | + display: flex; | ||
| 127 | + justify-content: space-around; | ||
| 128 | + } | ||
| 129 | +} | ||
| 130 | +.search-form { | ||
| 131 | + display: flex; | ||
| 132 | + justify-content: flex-end; | ||
| 133 | + align-items: center; | ||
| 134 | + margin-bottom: 20px; | ||
| 135 | + .search-time-range { | ||
| 136 | + width: 300px; | ||
| 137 | + } | ||
| 138 | + .filter { | ||
| 139 | + display: flex; | ||
| 140 | + align-items: center; | ||
| 141 | + } | ||
| 142 | + .filter:not(:last-child) { | ||
| 143 | + margin-right: 15px; | ||
| 144 | + } | ||
| 145 | + .seperator { | ||
| 146 | + margin: auto; | ||
| 147 | + } | ||
| 148 | +} | ||
| 149 | +.search-form-multirow { | ||
| 150 | + .row { | ||
| 151 | + display: flex; | ||
| 152 | + justify-content: flex-end; | ||
| 153 | + align-items: center; | ||
| 154 | + .search-time-range { | ||
| 155 | + width: 300px; | ||
| 156 | + } | ||
| 157 | + .filter { | ||
| 158 | + display: flex; | ||
| 159 | + align-items: center; | ||
| 160 | + } | ||
| 161 | + .filter:not(:last-child) { | ||
| 162 | + margin-right: 15px; | ||
| 163 | + } | ||
| 164 | + .seperator { | ||
| 165 | + margin: auto; | ||
| 166 | + } | ||
| 167 | + margin-bottom: 10px; | ||
| 168 | + } | ||
| 169 | + margin-bottom: 10px; | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +.refresh-bar { | ||
| 173 | + &-container { | ||
| 174 | + position: absolute; | ||
| 175 | + right: 0px; | ||
| 176 | + top: 0px; | ||
| 177 | + display: flex; | ||
| 178 | + margin-bottom: 10px; | ||
| 179 | + justify-content: end; | ||
| 180 | + overflow: hidden; | ||
| 181 | + font-size: 12px; | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + &-filter { | ||
| 185 | + font-size: 12px; | ||
| 186 | + width: 600px; | ||
| 187 | + z-index: 10; | ||
| 188 | + padding-right: 16px; | ||
| 189 | + display: flex; | ||
| 190 | + align-items: center; | ||
| 191 | + padding: 0 10px; | ||
| 192 | + height: 30px; | ||
| 193 | + > div:not(:last-of-type), | ||
| 194 | + > span, | ||
| 195 | + > button { | ||
| 196 | + margin-right: 4px; | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + :deep(.el-button .el-icon svg) { | ||
| 200 | + color: var(--el-color-icon-refresh-color); | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + :deep(.el-select .el-input.is-focus .el-input__wrapper) { | ||
| 204 | + box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset ; | ||
| 205 | + } | ||
| 206 | + :deep(.el-select-dropdown__item.selected) { | ||
| 207 | + color: var(--el-color-tabbar-active) ; | ||
| 208 | + } | ||
| 209 | + :deep(.el-range-editor.is-active) { | ||
| 210 | + box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset ; | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + :deep(.el-range-input) { | ||
| 215 | + background-color: var(--el-bg-color); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + :deep(.el-date-editor--datetimerange) { | ||
| 219 | + width: 100px; | ||
| 220 | + background-color: var(--el-bg-color); | ||
| 221 | + } | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +.refresh-button.el-button.el-button--primary { | ||
| 225 | + background-color: var(--button-1-background) ; | ||
| 226 | + border: 1px solid var(--button-1-border) ; | ||
| 227 | + color: var(--button-1-color) ; | ||
| 228 | + padding: 5px ; | ||
| 229 | +} | ||
| 230 | + | ||
| 231 | +.divider { | ||
| 232 | + height: 24px; | ||
| 233 | + width: 1px; | ||
| 234 | + margin: 0 8px ; | ||
| 235 | + background-color: var(--el-color-divider-border-color); | ||
| 236 | +} | ||
| 237 | + | ||
| 238 | +.gap-row { | ||
| 239 | + margin-bottom: 16px; | ||
| 240 | +} | ||
| @@ -0,0 +1,121 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +@use 'sass:math'; | ||
| 5 | +@use './color.scss' as *; | ||
| 6 | +@use 'sass:map'; | ||
| 7 | + | ||
| 8 | +html.dark { | ||
| 9 | + --hw-primary-1: #424242; | ||
| 10 | + --el-color-tabbar-active: #d4d4d4; | ||
| 11 | + --el-color-button-small-bg: #232324; | ||
| 12 | + --el-color-button-small-border: #5c5c5c; | ||
| 13 | + --el-color-card-header-color: #424242; | ||
| 14 | + --el-color--col-border-color: #4a4a4a; | ||
| 15 | + --el-color-line-text-color: #d4d4d4; | ||
| 16 | + --el-color-icon-refresh-color: #fff; | ||
| 17 | + --el-color-table-row-bg-color: #4e575a; | ||
| 18 | + --el-color-divider-border-color: #807f80; | ||
| 19 | + | ||
| 20 | + --el-color-primary: #409eff; | ||
| 21 | + --el-color-success: #67c23a; | ||
| 22 | + --el-bg-color: #232324; | ||
| 23 | + --el-bg-color-og: #212121; | ||
| 24 | + --el-bg-color-og-hover: #ffffff; | ||
| 25 | + --el-bg-color-sub: #424242; | ||
| 26 | + --el-bg-color-sub-white: #232324; | ||
| 27 | + --el-bg-color-page: #303030; | ||
| 28 | + --el-bg-color-overlay: #303030; | ||
| 29 | + --el-color-primary: #909399; | ||
| 30 | + --el-color-success: #67c23a; | ||
| 31 | + --el-color-warning: #e6a23c; | ||
| 32 | + --el-color-danger: #f56c6c; | ||
| 33 | + --el-color-error: #f56c6c; | ||
| 34 | + --el-color-info: #909399; | ||
| 35 | + --el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72); | ||
| 36 | + --el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72); | ||
| 37 | + --el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72); | ||
| 38 | + --el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000, 0px 8px 16px -8px #000000; | ||
| 39 | + --el-text-color-og: #d4d4d4; | ||
| 40 | + --el-text-color-primary: #e5eaf3; | ||
| 41 | + --el-text-color-regular: #cfd3dc; | ||
| 42 | + --el-text-color-secondary: #a3a6ad; | ||
| 43 | + --el-text-color-placeholder: #8d9095; | ||
| 44 | + --el-text-color-disabled: #6c6e72; | ||
| 45 | + --el-border-color-darker: #636466; | ||
| 46 | + --el-border-color-dark: #58585b; | ||
| 47 | + --el-border-color: #4c4d4f; | ||
| 48 | + --el-border-color-light: #414243; | ||
| 49 | + --el-border-color-lighter: #363637; | ||
| 50 | + --el-border-color-extra-light: #2b2b2c; | ||
| 51 | + --el-fill-color-darker: #424243; | ||
| 52 | + --el-fill-color-dark: #39393a; | ||
| 53 | + --el-fill-color: #303030; | ||
| 54 | + --el-fill-color-light: #262727; | ||
| 55 | + --el-fill-color-lighter: #1d1d1d; | ||
| 56 | + --el-fill-color-extra-light: #191919; | ||
| 57 | + --el-fill-color-blank: transparent; | ||
| 58 | + --el-mask-color: rgba(0, 0, 0, 0.8); | ||
| 59 | + --el-mask-color-extra-light: rgba(0, 0, 0, 0.3); | ||
| 60 | + --el-button-color-small: #5c5c5c; | ||
| 61 | + --el-table-cell: #909399; | ||
| 62 | + --el-button-text-color: #ffffff; | ||
| 63 | + --el-og-border-color: #4a4a4a; | ||
| 64 | + | ||
| 65 | + --color-text-1: #ffffff; | ||
| 66 | + --color-text-2: rgb(79, 91, 107); | ||
| 67 | + --color-text-3: rgb(134, 143, 156); | ||
| 68 | + --el-dialog-background-color: rgb(42, 42, 43); | ||
| 69 | + --primary-6: rgb(252, 239, 146); | ||
| 70 | + --main-background-color: rgb(35, 35, 36); | ||
| 71 | + --color-neutral-2: rgb(52, 52, 53); | ||
| 72 | + --color-fill-2: var(--color-neutral-2); | ||
| 73 | + --color-text-2: hsla(0, 0%, 100%, 0.7); | ||
| 74 | + --gray-9: rgb(223, 223, 223); | ||
| 75 | + --color-secondary: rgba(223, 223, 223, 0.08); | ||
| 76 | + --color-primary-light-1: rgba(252, 239, 146, 0.2); | ||
| 77 | + --el-color-primary: var(--primary-6); | ||
| 78 | + --el-color-primary-light-3: var(--primary-6); | ||
| 79 | + --el-menu-text-color: #cfcfcf; | ||
| 80 | + --el-menu-hover-text-color: #cfcfcf; | ||
| 81 | + --el-menu-bg-color: #212121; | ||
| 82 | + --el-menu-hover-bg-color: #323e43; | ||
| 83 | + --el-table-cell-center-background: #424242; | ||
| 84 | + --el-color-primary-light-3: var(--primary-6); | ||
| 85 | + --color-bg-2: #232324; | ||
| 86 | +} | ||
| 87 | + | ||
| 88 | +:root.dark { | ||
| 89 | + --el-menu-active-color: #cfcfcf; | ||
| 90 | + --el-menu-text-color: #cfcfcf; | ||
| 91 | + --el-menu-hover-text-color: #cfcfcf; | ||
| 92 | + --el-menu-bg-color: #212121; | ||
| 93 | + --el-menu-hover-bg-color: #323e43; | ||
| 94 | + | ||
| 95 | + --el-dialog-background-color: rgb(42, 42, 43); | ||
| 96 | + --primary-6: rgb(252, 239, 146); | ||
| 97 | + --main-background-color: rgb(35, 35, 36); | ||
| 98 | + --color-neutral-2: rgb(52, 52, 53); | ||
| 99 | + --color-fill-2: var(--color-neutral-2); | ||
| 100 | + --color-text-2: hsla(0, 0%, 100%, 0.7); | ||
| 101 | + --gray-9: rgb(223, 223, 223); | ||
| 102 | + --color-secondary: rgba(223, 223, 223, 0.08); | ||
| 103 | + --color-primary-light-1: rgba(252, 239, 146, 0.2); | ||
| 104 | + --el-color-primary: var(--primary-6); | ||
| 105 | + --el-color-primary-light-3: var(--primary-6); | ||
| 106 | + --el-table-cell-center-background: #424242; | ||
| 107 | + --el-color-primary-light-3: var(--primary-6); | ||
| 108 | + --color-bg-2: #232324; | ||
| 109 | + | ||
| 110 | + // dashboardv2 | ||
| 111 | + --color-1: #FFFFFF; | ||
| 112 | + --border-1: #484849; | ||
| 113 | + --border-2: #2ba1fa; | ||
| 114 | + --background-color-1: #484949; | ||
| 115 | + --background-color-2: #2e2d2f; | ||
| 116 | + --background-color-3: #484949; | ||
| 117 | + --text-1: #f5f6f6; | ||
| 118 | + --button-1-color: #ffffff; | ||
| 119 | + --button-1-background: #232324; | ||
| 120 | + --button-1-border: #484949; | ||
| 121 | +} | ||
| @@ -0,0 +1,255 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +@use 'sass:math'; | ||
| 5 | +@use './color.scss' as *; | ||
| 6 | +@use 'sass:map'; | ||
| 7 | + | ||
| 8 | +html, | ||
| 9 | +body { | ||
| 10 | + margin: 0; | ||
| 11 | + padding: 0; | ||
| 12 | + height: 100%; | ||
| 13 | + font-size: 14px; | ||
| 14 | + position: relative; | ||
| 15 | +} | ||
| 16 | +::-webkit-scrollbar { | ||
| 17 | + width: 0; | ||
| 18 | + height: 20px; | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +.el-pagination.is-background { | ||
| 22 | + .el-pager li:not(.is-disabled) { | ||
| 23 | + border: 1px solid $og-sub-border-color ; | ||
| 24 | + &.is-active { | ||
| 25 | + color: $og-sub-primary-color ; | ||
| 26 | + border-color: $og-sub-primary-color ; | ||
| 27 | + } | ||
| 28 | + &:hover { | ||
| 29 | + border-color: $og-sub-primary-color ; | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + &.el-pagination--small .el-pager li { | ||
| 33 | + min-width: 32px ; | ||
| 34 | + } | ||
| 35 | +} | ||
| 36 | +.el-overlay, | ||
| 37 | +.el-message, | ||
| 38 | +.el-popper { | ||
| 39 | + z-index: 10000000 ; | ||
| 40 | +} | ||
| 41 | +.el-dialog { | ||
| 42 | + .el-dialog__header { | ||
| 43 | + border-bottom: 1px solid $og-sub-border-color ; | ||
| 44 | + margin-right: 0px ; | ||
| 45 | + padding-top: 10px ; | ||
| 46 | + font-size: 14px ; | ||
| 47 | + } | ||
| 48 | + .el-dialog__title { | ||
| 49 | + font-size: 14px ; | ||
| 50 | + } | ||
| 51 | + .el-dialog__headerbtn { | ||
| 52 | + top: -2px ; | ||
| 53 | + } | ||
| 54 | + .el-dialog__footer { | ||
| 55 | + border-top: 1px solid $og-sub-border-color ; | ||
| 56 | + padding-bottom: 10px ; | ||
| 57 | + } | ||
| 58 | +} | ||
| 59 | +.el-menu-item.is-active { | ||
| 60 | + background-color: var(--el-bg-color-og-hover) ; | ||
| 61 | + border-right: 2px solid $og-primary-color ; | ||
| 62 | + color: var(--el-text-og-regular); | ||
| 63 | +} | ||
| 64 | +.el-menu--collapse .el-sub-menu__title { | ||
| 65 | + span, | ||
| 66 | + .el-sub-menu__icon-arrow { | ||
| 67 | + display: none ; | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | +.el-popper:focus { | ||
| 71 | + outline: none ; | ||
| 72 | +} | ||
| 73 | +#app { | ||
| 74 | + height: 100%; | ||
| 75 | + --vem-header-height: 30px; | ||
| 76 | + --og-sub-text-color: #{$og-sub-text-color}; | ||
| 77 | + color: var(--el-text-color-regular); | ||
| 78 | +} | ||
| 79 | +:root { | ||
| 80 | + --el-bg-color-overlay: $og-background-color; | ||
| 81 | + --el-color-primary: $og-primary-color; | ||
| 82 | + --el-text-color-primary: var(--el-text-color-og); | ||
| 83 | + @for $i from 1 through 9 { | ||
| 84 | + --el-color-primary-light-#{$i}: #{mix(#fff, #732fcb, math.percentage(math.div($i, 10)))}; | ||
| 85 | + } | ||
| 86 | +} | ||
| 87 | +.el-picker-panel .el-button { | ||
| 88 | + background-color: var(--el-bg-color-sub) ; | ||
| 89 | + border-color: $og-button-active-color ; | ||
| 90 | + color: var(--el-table-cell) ; | ||
| 91 | +} | ||
| 92 | +.el-button { | ||
| 93 | + height: auto ; | ||
| 94 | + &:active { | ||
| 95 | + background-color: $og-button-active-color ; | ||
| 96 | + border-color: $og-button-active-color ; | ||
| 97 | + } | ||
| 98 | + &.is-text:not(.is-disabled).is-has-bg { | ||
| 99 | + background-color: transparent ; | ||
| 100 | + padding: 0 ; | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | +.el-picker-panel__link-btn { | ||
| 104 | + color: var(--el-button-text-color) ; | ||
| 105 | +} | ||
| 106 | +.el-button.is-text { | ||
| 107 | + color: var(--el-button-text-color) ; | ||
| 108 | +} | ||
| 109 | +.el-tabs__header { | ||
| 110 | + background-color: var(--el-bg-color-sub-white) ; | ||
| 111 | +} | ||
| 112 | +.el-tabs__item { | ||
| 113 | + padding: 0 16px ; | ||
| 114 | + font-size: 14px ; | ||
| 115 | + color: var(--el-text-color-og) ; | ||
| 116 | +} | ||
| 117 | +.el-tabs__active-bar { | ||
| 118 | + background-color: var(--primary-6) ; | ||
| 119 | + height: 3px ; | ||
| 120 | +} | ||
| 121 | +.is-active { | ||
| 122 | + color: var(--primary-6) ; | ||
| 123 | +} | ||
| 124 | +.el-input__inner { | ||
| 125 | + color: var(--el-text-color-og) ; | ||
| 126 | +} | ||
| 127 | +.el-progress { | ||
| 128 | + &-bar__inner { | ||
| 129 | + background-color: $og-sub-primary-color ; | ||
| 130 | + } | ||
| 131 | +} | ||
| 132 | +.el-range-editor.is-disabled { | ||
| 133 | + border-color: $og-border-color ; | ||
| 134 | +} | ||
| 135 | +// 弹窗loading | ||
| 136 | +.el-loading-spinner .el-loading-text { | ||
| 137 | + color: $og-sub-primary-color ; | ||
| 138 | +} | ||
| 139 | +.el-loading-spinner .path { | ||
| 140 | + stroke: $og-sub-primary-color ; | ||
| 141 | +} | ||
| 142 | +.el-button--small { | ||
| 143 | +// background-color: var(--el-button-color-small) !important; | ||
| 144 | + border: none ; | ||
| 145 | + color: var(--el-text-color-og); | ||
| 146 | +} | ||
| 147 | +.sql-popover-tip { | ||
| 148 | + max-width: 300px ; | ||
| 149 | + color: var(--el-text-color-og) ; | ||
| 150 | +} | ||
| 151 | +.el-picker-panel__icon-btn .el-icon { | ||
| 152 | + color: var(--el-text-color-og); | ||
| 153 | +} | ||
| 154 | +.in-active-path .el-cascader-node__label { | ||
| 155 | + color: var(--el-color-tabbar-active) ; | ||
| 156 | +} | ||
| 157 | +.el-cascader .el-input.is-focus { | ||
| 158 | + border: none ; | ||
| 159 | +} | ||
| 160 | +.el-cascader .el-input.is-focus .el-input__wrapper { | ||
| 161 | + border: none ; | ||
| 162 | + box-shadow: 0 0 0 1px var(--hw-primary-1, var(--hw-primary-1)) inset ; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +.el-select-dropdown__item.selected { | ||
| 166 | + color: var(--el-color-tabbar-active) ; | ||
| 167 | +} | ||
| 168 | +.el-cascader-panel .in-active-path .el-icon svg { | ||
| 169 | + color: var(--hw-primary-1); | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +// textarea | ||
| 173 | +.el-textarea__inner { | ||
| 174 | + background-color: var(--color-fill-2) ; | ||
| 175 | +} | ||
| 176 | +.el-textarea__inner:focus { | ||
| 177 | + background-color: var(--main-background-color) ; | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +.el-table .cell { | ||
| 181 | + color: var(--color-1) ; | ||
| 182 | +} | ||
| 183 | +.el-input__wrapper.is-active { | ||
| 184 | + background-color: var(--main-background-color) ; | ||
| 185 | +} | ||
| 186 | +.el-input__wrapper.is-active .el-range-input { | ||
| 187 | + background-color: var(--main-background-color) ; | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +// pagination | ||
| 191 | +.el-pagination { | ||
| 192 | + display: flex; | ||
| 193 | + justify-content: flex-end; | ||
| 194 | +} | ||
| 195 | +.el-pagination.is-background .el-pager li:not(.is-disabled) { | ||
| 196 | + border: 0 ; | ||
| 197 | + background-color: rgb(255, 255, 255, 0); | ||
| 198 | +} | ||
| 199 | +.el-pagination.is-background .el-pager li:not(.is-disabled).is-active { | ||
| 200 | + color: var(--primary-6) ; | ||
| 201 | + background-color: var(--color-primary-light-1) ; | ||
| 202 | +} | ||
| 203 | +.btn-prev { | ||
| 204 | + background-color: rgb(255, 255, 255, 0) ; | ||
| 205 | +} | ||
| 206 | +.btn-next { | ||
| 207 | + background-color: rgb(255, 255, 255, 0) ; | ||
| 208 | +} | ||
| 209 | + | ||
| 210 | +// el-link | ||
| 211 | +.el-link { | ||
| 212 | + font-size: 12px ; | ||
| 213 | +} | ||
| 214 | +// table | ||
| 215 | +.table-wrapper-table-id { | ||
| 216 | + color: var(--primary-6) ; | ||
| 217 | + cursor: pointer; | ||
| 218 | +} | ||
| 219 | + | ||
| 220 | +// check-box | ||
| 221 | +// .el-checkbox__inner::after { | ||
| 222 | +// border-color: var(--color-bg-2) !important; | ||
| 223 | +// } | ||
| 224 | + | ||
| 225 | +// button for message box | ||
| 226 | +.el-message-box__btns .el-button.el-button--primary { | ||
| 227 | + color: var(--color-bg-2) ; | ||
| 228 | + background-color: var(--primary-6) ; | ||
| 229 | +} | ||
| 230 | +.el-message-box__btns .el-button.el-button--primary.search-button { | ||
| 231 | + color: var(--primary-6) ; | ||
| 232 | + background-color: rgb(255, 255, 255, 0) ; | ||
| 233 | + border: 1px solid var(--primary-6) ; | ||
| 234 | +} | ||
| 235 | + | ||
| 236 | +// Element Button Reset | ||
| 237 | +// .el-button { | ||
| 238 | +// font-size: 14px !important; | ||
| 239 | +// padding: 8px 16px !important; | ||
| 240 | +// border: 1px solid var(--button-1-border) !important; | ||
| 241 | +// border-radius: 2px; | ||
| 242 | +// font-weight: 400 !important; | ||
| 243 | +// color: var(--button-1-color) !important; | ||
| 244 | +// background-color: var(--button-1-background) !important; | ||
| 245 | +// } | ||
| 246 | +// .el-button.el-button--primary { | ||
| 247 | +// color: var(--color-bg-2) !important; | ||
| 248 | +// background-color: var(--primary-6) !important; | ||
| 249 | +// } | ||
| 250 | +// .el-button.el-button--primary.search-button { | ||
| 251 | +// color: var(--primary-6) !important; | ||
| 252 | +// background-color: rgb(255, 255, 255, 0) !important; | ||
| 253 | +// border: 1px solid var(--primary-6) !important; | ||
| 254 | +// } | ||
| 255 | + | ||
| @@ -0,0 +1,46 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +@use 'sass:math'; | ||
| 5 | +@use './color.scss' as *; | ||
| 6 | +@use 'sass:map'; | ||
| 7 | + | ||
| 8 | +.el-link.el-link--primary { | ||
| 9 | + color: var(--primary-6) ; | ||
| 10 | +} | ||
| 11 | +:deep(.el-pagination) { | ||
| 12 | + display: flex; | ||
| 13 | + justify-content: flex-end; | ||
| 14 | +} | ||
| 15 | +.deleteBtn { | ||
| 16 | + color: #d4d4d4; | ||
| 17 | +} | ||
| 18 | +.deleteBtn-icon { | ||
| 19 | + position: relative; | ||
| 20 | + top: 2px; | ||
| 21 | + right: 5px; | ||
| 22 | +} | ||
| 23 | +:deep(.el-range-editor--small.el-input__wrapper) { | ||
| 24 | + width: 240px; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +.dialog { | ||
| 28 | + &:deep(.el-dialog .el-dialog__header) { | ||
| 29 | + text-align: center; | ||
| 30 | + } | ||
| 31 | + &:deep(.el-form-item--small .el-form-item__label) { | ||
| 32 | + width: 110px; | ||
| 33 | + } | ||
| 34 | + &:deep(.el-dialog .el-dialog__footer) { | ||
| 35 | + border: none ; | ||
| 36 | + } | ||
| 37 | + .form-textarea { | ||
| 38 | + width: 100%; | ||
| 39 | + &:deep(.el-textarea__inner) { | ||
| 40 | + height: 100px; | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + .option-wrap { | ||
| 44 | + margin-right: 20px; | ||
| 45 | + } | ||
| 46 | +} | ||
| @@ -0,0 +1,111 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 3 | + */ | ||
| 4 | +@use 'sass:math'; | ||
| 5 | +@use './color.scss' as *; | ||
| 6 | +@use 'sass:map'; | ||
| 7 | + | ||
| 8 | +@forward 'element-plus/theme-chalk/src/common/var.scss' with ( | ||
| 9 | + $bg-color: ( | ||
| 10 | + '': #fefefe, | ||
| 11 | + 'page': #fefefe, | ||
| 12 | + 'overlay': #fefefe, | ||
| 13 | + ) | ||
| 14 | +); | ||
| 15 | + | ||
| 16 | +html { | ||
| 17 | + --hw-primary-1: #e41d1d; | ||
| 18 | + --el-color-tabbar-active: #e41d1d; | ||
| 19 | + --el-color-button-small-bg: #fff; | ||
| 20 | + --el-color-button-small-border: #e41d1d; | ||
| 21 | + --el-color-card-header-color: #f7f8fa; | ||
| 22 | + --el-color--col-border-color: #ddd; | ||
| 23 | + --el-color-line-text-color: #868f9c; | ||
| 24 | + --el-color-icon-refresh-color: #868f9c; | ||
| 25 | + --el-color-table-row-bg-color: #f7f8fa; | ||
| 26 | + --el-color-divider-border-color: #ddd; | ||
| 27 | + | ||
| 28 | + --el-bg-color-sub: #ddd; | ||
| 29 | + --el-bg-color-sub-white: #fff; | ||
| 30 | + --el-bg-color-og: #fefefe; | ||
| 31 | + --el-bg-color-og-hover: #ccc; | ||
| 32 | + --el-text-color-og: #333; | ||
| 33 | + --el-button-color-small: #ddd; | ||
| 34 | + --el-table-cell: #333; | ||
| 35 | + --el-color-primary: var(--primary-6); | ||
| 36 | + --el-button-text-color: #333; | ||
| 37 | + --el-og-border-color: #d9d9d9; | ||
| 38 | + | ||
| 39 | + --primary-5: #e94842; | ||
| 40 | + --primary-7: #be1118; | ||
| 41 | + --primary-4: #fac4bc; | ||
| 42 | + --primary-3: #f49c92; | ||
| 43 | + --primary-2: #f49c92; | ||
| 44 | + --primary-1: #ffece8; | ||
| 45 | + --color-hw-text-1: #ffffff; | ||
| 46 | + --color-hw-text-2: #1d212a; | ||
| 47 | + --color-hw-text-3: #4e5a6a; | ||
| 48 | + --color-hw-text-4: #4e5a6a; | ||
| 49 | + --color-hw-text-5: #868f9c; | ||
| 50 | + --color-hw-text-6: #f2f3f5; | ||
| 51 | + --warning-6: #ff7d01; | ||
| 52 | + --success-6: #00b429; | ||
| 53 | + --link-6: #e41d1d; | ||
| 54 | + --color-text-1: rgb(28, 32, 41); | ||
| 55 | + --color-text-3: rgb(134, 143, 156); | ||
| 56 | + --dark-primary-6: #e41d1d; | ||
| 57 | + --dark-link-6: #e41d1d; | ||
| 58 | + --el-bg-color-sub: rgb(247, 248, 250); | ||
| 59 | + --el-bg-color-og: rgb(254, 254, 254); | ||
| 60 | + | ||
| 61 | + --color-1: #4E5969; | ||
| 62 | + --border-1: #eaebee; | ||
| 63 | + --border-2: #165dff; | ||
| 64 | + --background-color-1: #ffffff; | ||
| 65 | + --background-color-2: #F7F7F7; | ||
| 66 | + --background-color-3: #f4faff; | ||
| 67 | + --text-1: #1d2129; | ||
| 68 | + --button-1-color: #4e5969; | ||
| 69 | + --button-1-background: #ffffff; | ||
| 70 | + --button-1-border: #d9d9d9; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +:root { | ||
| 74 | + --el-menu-active-color: #333; | ||
| 75 | + --el-menu-text-color: #333; | ||
| 76 | + --el-menu-bg-color: #eee; | ||
| 77 | + --el-menu-item-height: 40px; | ||
| 78 | + --el-menu-sub-item-height: 40px; | ||
| 79 | + --el-menu-horizontal-sub-item-height: 36px; | ||
| 80 | + --el-menu-item-font-size: var(--el-font-size-base); | ||
| 81 | + --el-menu-item-hover-fill: var(--el-color-primary-light-9); | ||
| 82 | + --el-menu-border-color: var(--el-border-color); | ||
| 83 | + --el-menu-base-level-padding: 20px; | ||
| 84 | + --el-menu-level-padding: 20px; | ||
| 85 | + --el-menu-icon-width: 24px; | ||
| 86 | + | ||
| 87 | + --primary-6: #e41d1d; | ||
| 88 | + --el-dialog-background-color: rgb(255, 255, 255); | ||
| 89 | + --main-background-color: #ffffff; | ||
| 90 | + --color-neutral-2: rgb(242, 243, 245); | ||
| 91 | + --color-fill-2: var(--color-neutral-2); | ||
| 92 | + --color-text-2: rgb(79, 91, 107); | ||
| 93 | + --color-secondary: var(--color-neutral-2); | ||
| 94 | + --color-primary-light-1: #ffece8; | ||
| 95 | + --el-color-primary: var(--primary-6); | ||
| 96 | + --el-color-primary-light-3: var(--primary-6); | ||
| 97 | + --el-table-cell-center-background: #ffffff; | ||
| 98 | + --color-bg-2: #fff; | ||
| 99 | + | ||
| 100 | + // dashboardv2 | ||
| 101 | + --color-1: #4E5969; | ||
| 102 | + --border-1: #eaebee; | ||
| 103 | + --border-2: #165dff; | ||
| 104 | + --background-color-1: #ffffff; | ||
| 105 | + --background-color-2: #F7F7F7; | ||
| 106 | + --background-color-3: #f4faff; | ||
| 107 | + --text-1: #1d2129; | ||
| 108 | + --button-1-color: #4e5969; | ||
| 109 | + --button-1-background: #ffffff; | ||
| 110 | + --button-1-border: #d9d9d9; | ||
| 111 | +} | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="8" height="6" viewBox="0 0 8 6" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path fill-rule="evenodd" clip-rule="evenodd" d="M4.59649 5.33556C4.1891 5.61949 3.6246 5.57975 3.26119 5.21634L0.306018 2.26117C-0.102006 1.85315 -0.102006 1.19161 0.306018 0.783586C0.714042 0.375561 1.37558 0.375561 1.7836 0.783586L3.99999 2.99997L6.2164 0.783557C6.62442 0.375533 7.28596 0.375533 7.69398 0.783557C8.10201 1.19158 8.10201 1.85312 7.69398 2.26114L4.73881 5.21632C4.73389 5.22123 4.72894 5.22609 4.72395 5.23089C4.68365 5.26964 4.64101 5.30453 4.59649 5.33556Z" fill="#BCBCBC"/> | ||
| 3 | +</svg> | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | +<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<rect width="32" height="32" rx="4" fill="#424242"/> | ||
| 3 | +<path d="M12.1375 19.0591C9.955 17.8764 8.5 15.7229 8.5 13.2631C8.5 9.528 11.8563 6.5 16 6.5C20.1438 6.5 23.5 9.528 23.5 13.2631C23.5 15.7229 22.0431 17.8764 19.8625 19.0591C19.7406 19.6647 19.4481 20.2133 19.03 20.6693H12.97C12.5473 20.2118 12.2594 19.6563 12.1356 19.0591H12.1375ZM21.3569 13.9061C21.3649 12.5484 20.8051 11.2433 19.8007 10.2774C18.7962 9.31149 17.4292 8.76392 16 8.75497C15.5256 8.75497 15.2856 8.97049 15.2856 9.39798C15.2856 9.50485 15.5256 9.71859 16 9.71859C18.2875 9.71859 20.2863 11.5229 20.2863 13.9061C20.2863 14.013 20.5263 14.2285 20.9988 14.2285C21.1169 14.2285 21.3569 14.013 21.3569 13.9079V13.9061ZM12.7862 22.2777C12.7862 21.9232 13.105 21.6364 13.4988 21.6364H18.5013C18.895 21.6364 19.2137 21.9214 19.2137 22.2777C19.2137 22.6339 18.895 22.9225 18.5013 22.9225H13.4988C13.4075 22.9248 13.3166 22.9101 13.2314 22.879C13.1461 22.8479 13.0682 22.8012 13.002 22.7415C12.9358 22.6817 12.8827 22.6102 12.8456 22.5309C12.8086 22.4516 12.7884 22.3662 12.7862 22.2794V22.2777ZM18.88 23.8896C18.355 24.8426 17.2619 25.4998 16 25.4998C15.4111 25.5059 14.8317 25.3592 14.3241 25.0754C13.8166 24.7917 13.4003 24.3817 13.12 23.8896H18.88Z" fill="#177DDC"/> | ||
| 4 | +</svg> | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | +<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<rect width="32" height="32" rx="4" fill="#424242"/> | ||
| 3 | +<path d="M12.1375 19.0591C9.955 17.8764 8.5 15.7229 8.5 13.2631C8.5 9.528 11.8563 6.5 16 6.5C20.1438 6.5 23.5 9.528 23.5 13.2631C23.5 15.7229 22.0431 17.8764 19.8625 19.0591C19.7406 19.6647 19.4481 20.2133 19.03 20.6693H12.97C12.5473 20.2118 12.2594 19.6563 12.1356 19.0591H12.1375ZM21.3569 13.9061C21.3649 12.5484 20.8051 11.2433 19.8007 10.2774C18.7962 9.31149 17.4292 8.76392 16 8.75497C15.5256 8.75497 15.2856 8.97049 15.2856 9.39798C15.2856 9.50485 15.5256 9.71859 16 9.71859C18.2875 9.71859 20.2863 11.5229 20.2863 13.9061C20.2863 14.013 20.5263 14.2285 20.9988 14.2285C21.1169 14.2285 21.3569 14.013 21.3569 13.9079V13.9061ZM12.7862 22.2777C12.7862 21.9232 13.105 21.6364 13.4988 21.6364H18.5013C18.895 21.6364 19.2137 21.9214 19.2137 22.2777C19.2137 22.6339 18.895 22.9225 18.5013 22.9225H13.4988C13.4075 22.9248 13.3166 22.9101 13.2314 22.879C13.1461 22.8479 13.0682 22.8012 13.002 22.7415C12.9358 22.6817 12.8827 22.6102 12.8456 22.5309C12.8086 22.4516 12.7884 22.3662 12.7862 22.2794V22.2777ZM18.88 23.8896C18.355 24.8426 17.2619 25.4998 16 25.4998C15.4111 25.5059 14.8317 25.3592 14.3241 25.0754C13.8166 24.7917 13.4003 24.3817 13.12 23.8896H18.88Z" fill="#BCBCBC"/> | ||
| 4 | +</svg> | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<circle cx="4" cy="4" r="4" fill="#B8B8B8"/> | ||
| 3 | +</svg> | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<circle cx="4" cy="4" r="4" fill="#FF7D00"/> | ||
| 3 | +</svg> | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<circle cx="4" cy="4" r="4" fill="#F53F3F"/> | ||
| 3 | +</svg> | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M33.75 32.5H6.25C5.91848 32.5 5.60054 32.3683 5.36612 32.1339C5.1317 31.8995 5 31.5815 5 31.25V8.75C5 8.41848 5.1317 8.10054 5.36612 7.86612C5.60054 7.6317 5.91848 7.5 6.25 7.5H33.75C34.0815 7.5 34.3995 7.6317 34.6339 7.86612C34.8683 8.10054 35 8.41848 35 8.75V31.25C35 31.5815 34.8683 31.8995 34.6339 32.1339C34.3995 32.3683 34.0815 32.5 33.75 32.5ZM7.5 30H32.5V10H7.5V30Z"/> | ||
| 3 | +<path d="M11.875 5H13.125V8.75H11.875V5ZM16.875 5H18.125V8.75H16.875V5ZM21.875 5H23.125V8.75H21.875V5ZM26.875 5H28.125V8.75H26.875V5ZM11.875 31.25H13.125V35H11.875V31.25ZM16.875 31.25H18.125V35H16.875V31.25ZM21.875 31.25H23.125V35H21.875V31.25ZM26.875 31.25H28.125V35H26.875V31.25ZM33.75 26.875H37.5V28.125H33.75V26.875ZM33.75 21.875H37.5V23.125H33.75V21.875ZM33.75 16.875H37.5V18.125H33.75V16.875ZM33.75 11.875H37.5V13.125H33.75V11.875Z"/> | ||
| 4 | +<path d="M2.5 26.875H6.25V28.125H2.5V26.875ZM2.5 21.875H6.25V23.125H2.5V21.875ZM2.5 16.875H6.25V18.125H2.5V16.875ZM2.5 11.875H6.25V13.125H2.5V11.875Z"/> | ||
| 5 | +<path d="M13.8323 20.2387L15.7711 20.8249C15.6411 21.3699 15.4348 21.8224 15.1561 22.1874C14.8773 22.5524 14.5286 22.8274 14.1136 23.0124C13.6986 23.1974 13.1698 23.2912 12.5286 23.2912C11.7511 23.2912 11.1148 23.1787 10.6223 22.9524C10.1286 22.7274 9.70359 22.3299 9.34609 21.7612C8.98859 21.1924 8.80859 20.4624 8.80859 19.5749C8.80859 18.3912 9.12359 17.4812 9.75359 16.8449C10.3836 16.2087 11.2748 15.8887 12.4261 15.8887C13.3286 15.8887 14.0361 16.0712 14.5523 16.4362C15.0686 16.8012 15.4523 17.3612 15.7023 18.1162L13.7498 18.5487C13.7035 18.3789 13.6309 18.2174 13.5348 18.0699C13.4166 17.9055 13.2611 17.7714 13.0811 17.6787C12.8948 17.586 12.6891 17.5393 12.4811 17.5424C11.9798 17.5424 11.5961 17.7437 11.3286 18.1474C11.1273 18.4462 11.0261 18.9162 11.0261 19.5562C11.0261 20.3499 11.1473 20.8937 11.3873 21.1874C11.6273 21.4812 11.9673 21.6287 12.4036 21.6287C12.8273 21.6287 13.1473 21.5099 13.3636 21.2724C13.5798 21.0349 13.7348 20.6912 13.8323 20.2387ZM16.8361 16.0099H20.5123C21.3136 16.0099 21.9111 16.1999 22.3111 16.5812C22.7086 16.9624 22.9098 17.5037 22.9098 18.2074C22.9098 18.9299 22.6923 19.4949 22.2586 19.9012C21.8248 20.3074 21.1623 20.5112 20.2686 20.5112H19.0573V23.1674H16.8361V16.0099ZM19.0573 19.0624H19.5998C20.0261 19.0624 20.3261 18.9887 20.4986 18.8399C20.5819 18.7708 20.6484 18.6838 20.6933 18.5852C20.7381 18.4867 20.76 18.3794 20.7573 18.2712C20.7573 18.0462 20.6823 17.8562 20.5323 17.6999C20.3823 17.5437 20.1011 17.4649 19.6873 17.4649H19.0573V19.0624ZM28.7248 16.0099H30.9323V20.2749C30.9323 20.6974 30.8661 21.0974 30.7348 21.4724C30.6058 21.844 30.3937 22.1813 30.1148 22.4587C29.8664 22.719 29.5638 22.9216 29.2286 23.0524C28.7986 23.2112 28.2823 23.2899 27.6811 23.2899C27.3 23.2869 26.9194 23.2623 26.5411 23.2162C26.1311 23.1674 25.7861 23.0712 25.5098 22.9262C25.2336 22.7812 24.9786 22.5762 24.7511 22.3099C24.538 22.0709 24.3775 21.7899 24.2798 21.4849C24.1544 21.0929 24.0854 20.6851 24.0748 20.2737V16.0087H26.2836V20.3749C26.2836 20.7649 26.3911 21.0699 26.6086 21.2899C26.8248 21.5087 27.1248 21.6187 27.5098 21.6187C27.8911 21.6187 28.1898 21.5112 28.4061 21.2949C28.6236 21.0787 28.7311 20.7724 28.7311 20.3749V16.0099H28.7248Z"/> | ||
| 6 | +</svg> | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +<svg width="25" height="24" viewBox="0 0 25 24" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M20.75 22.5H4.25C4.05109 22.5 3.86032 22.421 3.71967 22.2803C3.57902 22.1397 3.5 21.9489 3.5 21.75V2.25C3.5 2.05109 3.57902 1.86032 3.71967 1.71967C3.86032 1.57902 4.05109 1.5 4.25 1.5H20.75C20.9489 1.5 21.1397 1.57902 21.2803 1.71967C21.421 1.86032 21.5 2.05109 21.5 2.25V21.75C21.5 21.9489 21.421 22.1397 21.2803 22.2803C21.1397 22.421 20.9489 22.5 20.75 22.5ZM5 21H20V3H5V21Z"/> | ||
| 3 | +<path d="M16.25 4.5H17.75V7.5H16.25V4.5ZM13.25 4.5H14.75V7.5H13.25V4.5ZM10.25 4.5H11.75V7.5H10.25V4.5ZM7.25 4.5H8.75V7.5H7.25V4.5Z"/> | ||
| 4 | +<path d="M17.75 19.5H7.25C7.05109 19.5 6.86032 19.421 6.71967 19.2803C6.57902 19.1397 6.5 18.9489 6.5 18.75V9.75C6.5 9.55109 6.57902 9.36032 6.71967 9.21967C6.86032 9.07902 7.05109 9 7.25 9H17.75C17.9489 9 18.1397 9.07902 18.2803 9.21967C18.421 9.36032 18.5 9.55109 18.5 9.75V18.75C18.5 18.9489 18.421 19.1397 18.2803 19.2803C18.1397 19.421 17.9489 19.5 17.75 19.5ZM8 18H17V10.5H8V18Z"/> | ||
| 5 | +<path d="M11.7267 11.7891C11.8362 11.8049 11.8909 11.8829 11.8909 12.0239C11.8752 12.1649 11.8129 12.2346 11.7034 12.2346H10.9302C10.8364 12.7349 10.7194 13.1564 10.5784 13.5006H11.3284C11.5782 13.5321 11.7109 13.6491 11.7267 13.8531V16.6424C11.7267 16.8456 11.6097 16.9469 11.3749 16.9469H10.4374C10.1869 16.9469 10.0624 16.8209 10.0624 16.5719V14.6031C10.0309 14.6504 10.0227 14.6646 10.0392 14.6504C10.0128 14.7066 9.97256 14.7551 9.92217 14.7914C9.82842 14.8694 9.73467 14.8619 9.64092 14.7681C9.53142 14.6586 9.50742 14.5581 9.57042 14.4644C10.0392 13.9641 10.3204 13.2224 10.4142 12.2376H9.89817C9.75792 12.2189 9.68742 12.1409 9.68742 11.9999C9.71817 11.8589 9.80442 11.7891 9.94542 11.7891H11.7267ZM10.6722 13.9454C10.5627 13.9296 10.5079 13.9926 10.5079 14.1329V16.3364C10.4922 16.4616 10.5552 16.5156 10.6954 16.5006H11.1642C11.2579 16.5006 11.2969 16.4534 11.2812 16.3596V14.1329C11.2812 13.9919 11.2264 13.9296 11.1169 13.9454H10.6722ZM15.0312 11.7659C15.1557 11.7659 15.2262 11.8364 15.2419 11.9766C15.2262 12.1326 15.1557 12.2114 15.0312 12.2114H13.7419V12.6569H14.6562C14.9059 12.6726 15.0387 12.7979 15.0544 13.0319V14.6031C15.0387 14.8521 14.9134 14.9856 14.6794 15.0006H13.7652C13.7022 15.5009 13.5852 15.8759 13.4127 16.1256C13.7719 16.3604 14.3277 16.5239 15.0777 16.6176C15.2187 16.6491 15.2877 16.7339 15.2877 16.8756C15.2719 17.0166 15.1857 17.0864 15.0297 17.0864C14.3613 17.0351 13.7129 16.8347 13.1322 16.4999C12.8472 16.7363 12.5217 16.919 12.1714 17.0391C11.9997 17.1014 11.8744 17.0624 11.7964 16.9221C11.7334 16.7811 11.7807 16.6731 11.9374 16.5936C12.2809 16.4841 12.5472 16.3514 12.7347 16.1954C12.5779 16.0859 12.3904 15.8751 12.1722 15.5624C12.0942 15.4371 12.1017 15.3276 12.1954 15.2339C12.3364 15.1559 12.4534 15.1709 12.5472 15.2811C12.7654 15.5624 12.9297 15.7499 13.0399 15.8436C13.1809 15.5939 13.2657 15.3126 13.2979 14.9999H12.4999C12.1714 14.9999 12.0079 14.8439 12.0079 14.5311V13.0544C12.0079 12.7889 12.1557 12.6561 12.4534 12.6561H13.2972V12.2106H12.1954C12.0702 12.2106 12.0079 12.1326 12.0079 11.9759C12.0079 11.8349 12.0702 11.7651 12.1954 11.7651L15.0312 11.7659ZM12.4294 13.6409H13.2964V13.0559H12.5929C12.4677 13.0401 12.4129 13.1031 12.4287 13.2434V13.6409H12.4294ZM12.4294 14.4374C12.4137 14.5626 12.4767 14.6174 12.6169 14.6016H13.2964V14.0391H12.4294V14.4374ZM13.7419 13.6409H14.6329V13.2186C14.6487 13.0934 14.5932 13.0394 14.4687 13.0544H13.7419V13.6409ZM13.7419 14.0391V14.6016H14.4687C14.5932 14.6016 14.6479 14.5394 14.6329 14.4141V14.0391H13.7419Z"/> | ||
| 6 | +</svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1661421275650" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4653" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M960.041 254.408c20.628-20.593 20.628-51.482 0-72.075l-118.61-118.41c-20.628-20.592-51.569-20.592-72.197 0l-92.83 92.672L872.37 352.23l87.67-97.822zM47.258 779.53v195.64H243.22l567.266-571.458-195.963-195.635L47.258 779.53z m0 0" p-id="4654" fill="#00c8db"></path></svg> | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M9 0.75C11.4742 0.815 13.5348 1.67104 15.1819 3.31813C16.829 4.96521 17.685 7.02583 17.75 9.5C17.685 11.9742 16.829 14.0348 15.1819 15.6819C13.5348 17.329 11.4742 18.185 9 18.25C6.52583 18.185 4.46521 17.329 2.81813 15.6819C1.17104 14.0348 0.315 11.9742 0.25 9.5C0.315 7.02583 1.17104 4.96521 2.81813 3.31813C4.46521 1.67104 6.52583 0.815 9 0.75ZM10.3088 6.12125C10.6475 6.12125 10.9275 6.02042 11.1488 5.81875C11.37 5.61708 11.4806 5.34687 11.4806 5.00812C11.4806 4.66937 11.37 4.39917 11.1488 4.1975C10.9275 3.99583 10.6508 3.895 10.3188 3.895C9.98667 3.895 9.71 3.99583 9.48875 4.1975C9.2675 4.39917 9.15687 4.66937 9.15687 5.00812C9.15687 5.34687 9.2675 5.61708 9.48875 5.81875C9.71 6.02042 9.98354 6.12125 10.3094 6.12125H10.3088ZM10.5431 13.1525C10.5431 13.0742 10.5496 12.97 10.5625 12.84C10.5754 12.71 10.5754 12.5863 10.5625 12.4688L9.5275 13.66C9.42333 13.7771 9.31583 13.8683 9.205 13.9338C9.09417 13.9992 8.99979 14.0188 8.92188 13.9925C8.80479 13.9404 8.75271 13.8492 8.76562 13.7188L10.4844 8.30875C10.5494 7.94417 10.4908 7.63167 10.3088 7.37125C10.1267 7.11083 9.83375 6.95458 9.43 6.9025C8.97417 6.91542 8.47604 7.1075 7.93563 7.47875C7.39521 7.85 6.92313 8.32208 6.51937 8.895V9.18813C6.50646 9.31854 6.50646 9.44229 6.51937 9.55937L7.55438 8.36812C7.65854 8.25104 7.76604 8.15979 7.87687 8.09438C7.98771 8.02896 8.07562 8.00937 8.14062 8.03562C8.27104 8.10062 8.31667 8.20479 8.2775 8.34812L6.57812 13.7387C6.48688 14.0642 6.5325 14.354 6.715 14.6081C6.8975 14.8623 7.21646 15.0348 7.67188 15.1256C8.32312 15.1127 8.87 14.924 9.3125 14.5594C9.755 14.1948 10.1652 13.726 10.5431 13.1531V13.1525Z" fill="#0093FF"/> | ||
| 3 | +</svg> | ||
| @@ -0,0 +1 @@ | |||
| 1 | +<svg t="1662350667724" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1671" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M573.44 481.0752h-8.8064l33.9968 188.928c22.3232-7.8848 42.8032-19.968 60.928-35.84-18.6368-22.3232-33.4848-47.5136-45.1584-74.0352l35.84-4.608c9.728 19.968 20.992 38.1952 33.9968 53.5552 26.5216-32.1536 46.592-74.9568 60.928-128.512L573.44 481.0752z m135.4752 153.088c20.48 17.7152 43.7248 30.72 69.8368 38.6048l16.2816 5.12-9.728 34.9184-16.2816-5.12c-31.232-9.728-60.0064-26.112-84.6848-47.9232-22.8352 20.48-49.7664 36.352-79.1552 46.08l22.8352 127.488H492.032l-18.1248 83.3536h426.8032c19.968 0 36.352-16.2816 36.352-36.352V263.168c0-19.968-16.2816-36.352-36.352-36.352H519.4752L547.84 385.024l-0.9216-0.512 3.2768 17.2032 0.512-2.3552 7.8848 45.1584h87.9616v-36.352h67.9936v36.352h113.5616v36.352h-47.5136c-15.872 63.8976-40.0384 115.0976-71.68 153.2928zM454.7584 832.9216H123.8016C83.7632 832.9216 51.2 800.3584 51.2 760.32V143.5648c0-40.448 32.5632-72.6016 72.6016-72.6016h363.008l22.3232 119.6032H900.096c40.0384 0 72.6016 32.5632 72.6016 72.6016v617.1648c0 40.0384-32.5632 72.6016-72.6016 72.6016H428.6464l26.112-120.0128zM283.4432 553.6768v-38.1952h-71.68v-56.32h66.56v-37.6832h-66.56v-47.9232h71.68V335.872H169.8816v217.8048h113.5616z m175.0016 0V444.7232c0-19.5584-4.608-34.9184-13.5168-45.568s-22.3232-15.872-40.0384-15.872c-10.24 0-19.5584 1.8432-27.4432 6.0416-7.8848 4.1984-14.4384 10.752-18.6368 18.6368h-2.3552l-5.632-21.4016h-31.6416v167.1168h40.96v-78.6432c0-19.5584 2.7648-33.4848 7.8848-42.3936 5.12-8.3968 13.5168-12.5952 25.088-12.5952 8.3968 0 14.4384 2.7648 18.6368 8.8064 3.6864 6.0416 6.0416 14.848 6.0416 27.0336v97.792h40.6528z" fill="#bcbcbc" p-id="1672"></path></svg> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +<svg width="31" height="30" viewBox="0 0 31 30" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M27.083 16.875H4.58301C4.33437 16.875 4.09591 16.7762 3.9201 16.6004C3.74428 16.4246 3.64551 16.1861 3.64551 15.9375V2.8125C3.64551 2.56386 3.74428 2.3254 3.9201 2.14959C4.09591 1.97377 4.33437 1.875 4.58301 1.875H27.083C27.3316 1.875 27.5701 1.97377 27.7459 2.14959C27.9217 2.3254 28.0205 2.56386 28.0205 2.8125V15.9375C28.0205 16.1861 27.9217 16.4246 27.7459 16.6004C27.5701 16.7762 27.3316 16.875 27.083 16.875ZM5.52051 15H26.1455V3.75H5.52051V15ZM27.083 28.125H4.58301C4.33437 28.125 4.09591 28.0262 3.9201 27.8504C3.74428 27.6746 3.64551 27.4361 3.64551 27.1875V19.6875C3.64551 19.4389 3.74428 19.2004 3.9201 19.0246C4.09591 18.8488 4.33437 18.75 4.58301 18.75H27.083C27.3316 18.75 27.5701 18.8488 27.7459 19.0246C27.9217 19.2004 28.0205 19.4389 28.0205 19.6875V27.1875C28.0205 27.4361 27.9217 27.6746 27.7459 27.8504C27.5701 28.0262 27.3316 28.125 27.083 28.125ZM5.52051 26.25H26.1455V20.625H5.52051V26.25Z"/> | ||
| 3 | +<path d="M9.27051 28.125C9.02187 28.125 8.78341 28.0262 8.6076 27.8504C8.43178 27.6746 8.33301 27.4361 8.33301 27.1875V23.9062C8.33301 23.6576 8.43178 23.4192 8.6076 23.2433C8.78341 23.0675 9.02187 22.9688 9.27051 22.9688C9.51915 22.9688 9.7576 23.0675 9.93342 23.2433C10.1092 23.4192 10.208 23.6576 10.208 23.9062V27.1875C10.208 27.4361 10.1092 27.6746 9.93342 27.8504C9.7576 28.0262 9.51915 28.125 9.27051 28.125ZM13.958 28.125C13.7094 28.125 13.4709 28.0262 13.2951 27.8504C13.1193 27.6746 13.0205 27.4361 13.0205 27.1875V23.9062C13.0205 23.6576 13.1193 23.4192 13.2951 23.2433C13.4709 23.0675 13.7094 22.9688 13.958 22.9688C14.2066 22.9688 14.4451 23.0675 14.6209 23.2433C14.7967 23.4192 14.8955 23.6576 14.8955 23.9062V27.1875C14.8955 27.4361 14.7967 27.6746 14.6209 27.8504C14.4451 28.0262 14.2066 28.125 13.958 28.125ZM18.6455 28.125C18.3969 28.125 18.1584 28.0262 17.9826 27.8504C17.8068 27.6746 17.708 27.4361 17.708 27.1875V23.9203C17.708 23.6717 17.8068 23.4332 17.9826 23.2574C18.1584 23.0816 18.3969 22.9828 18.6455 22.9828C18.8941 22.9828 19.1326 23.0816 19.3084 23.2574C19.4842 23.4332 19.583 23.6717 19.583 23.9203V27.1875C19.583 27.4361 19.4842 27.6746 19.3084 27.8504C19.1326 28.0262 18.8941 28.125 18.6455 28.125ZM23.333 28.125C23.0844 28.125 22.8459 28.0262 22.6701 27.8504C22.4943 27.6746 22.3955 27.4361 22.3955 27.1875V23.9203C22.3955 23.6717 22.4943 23.4332 22.6701 23.2574C22.8459 23.0816 23.0844 22.9828 23.333 22.9828C23.5816 22.9828 23.8201 23.0816 23.9959 23.2574C24.1717 23.4332 24.2705 23.6717 24.2705 23.9203V27.1875C24.2705 27.4361 24.1717 27.6746 23.9959 27.8504C23.8201 28.0262 23.5816 28.125 23.333 28.125Z"/> | ||
| 4 | +<path d="M9.27051 7.5H14.8955V11.25H9.27051V7.5Z"/> | ||
| 5 | +</svg> | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +<svg width="25" height="24" viewBox="0 0 25 24" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M18.5002 22.5H6.50018C6.30127 22.5 6.1105 22.421 5.96985 22.2803C5.8292 22.1397 5.75018 21.9489 5.75018 21.75V2.25C5.75018 2.05109 5.8292 1.86032 5.96985 1.71967C6.1105 1.57902 6.30127 1.5 6.50018 1.5H18.5002C18.6991 1.5 18.8899 1.57902 19.0305 1.71967C19.1712 1.86032 19.2502 2.05109 19.2502 2.25V21.75C19.2502 21.9489 19.1712 22.1397 19.0305 22.2803C18.8899 22.421 18.6991 22.5 18.5002 22.5ZM7.25018 21H17.7502V3H7.25018V21ZM3.00293 4.536H4.50293V19.464H3.00293V4.536Z"/> | ||
| 3 | +<path d="M8.88184 10.3261H16.0803V11.7331H8.88184V10.3261ZM8.88184 5.91162H16.0803V7.33212H8.88184V5.91162Z"/> | ||
| 4 | +<path d="M11 17.25C11 17.6478 11.158 18.0294 11.4393 18.3107C11.7206 18.592 12.1022 18.75 12.5 18.75C12.8978 18.75 13.2794 18.592 13.5607 18.3107C13.842 18.0294 14 17.6478 14 17.25C14 16.8522 13.842 16.4706 13.5607 16.1893C13.2794 15.908 12.8978 15.75 12.5 15.75C12.1022 15.75 11.7206 15.908 11.4393 16.1893C11.158 16.4706 11 16.8522 11 17.25Z"/> | ||
| 5 | +<path d="M20.4971 4.53613H21.9971V19.4641H20.4971V4.53613Z"/> | ||
| 6 | +</svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1660533823595" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2349" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m192 472c0 4.4-3.6 8-8 8H544v152c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V544H328c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h152V328c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v152h152c4.4 0 8 3.6 8 8v48z" p-id="2350" fill="#00c8db"></path></svg> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +<svg width="25" height="24" viewBox="0 0 25 24" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M23.3008 14.7197H17.9808C17.6208 14.7197 17.3008 14.9597 17.2208 15.2797L16.3408 18.1197H8.66078L7.78078 15.2797C7.66078 14.9597 7.38078 14.7197 7.02078 14.7197H1.70078C1.46078 14.7197 1.30078 14.8797 1.30078 15.1197V21.3197C1.30078 22.1997 2.02078 22.9197 2.90078 22.9197H22.1008C22.9808 22.9197 23.7008 22.1997 23.7008 21.3197V15.1197C23.7008 14.9197 23.5408 14.7197 23.3008 14.7197Z"/> | ||
| 3 | +<path d="M23.7002 14.8801L21.0202 2.00008C20.9002 1.48008 20.4202 1.08008 19.9002 1.08008H5.14016C4.58016 1.08008 4.10016 1.48008 4.02016 2.00008L1.30016 14.8801C1.26016 15.0801 1.30016 15.2801 1.42016 15.4801C1.54016 15.6401 1.70016 15.7601 1.90016 15.8001H2.06016C2.22016 15.8001 2.34016 15.7601 2.50016 15.6801C2.66016 15.5601 2.78016 15.4001 2.82016 15.2001L5.42016 2.64008H19.5402L22.1802 15.2001C22.2602 15.6001 22.7002 15.8801 23.1002 15.8001C23.3002 15.7601 23.4602 15.6401 23.5802 15.4801C23.7002 15.2801 23.7402 15.0801 23.7002 14.8801Z"/> | ||
| 4 | +<path d="M15.26 9.00047L13.3 10.9605V6.24047C13.3 5.80047 12.94 5.48047 12.54 5.48047C12.1 5.48047 11.78 5.84047 11.78 6.24047V10.9605L9.82 9.00047C9.5 8.68047 9.02 8.68047 8.74 9.00047C8.42 9.32047 8.42 9.80047 8.74 10.0805L12.02 13.3605C12.1 13.4405 12.18 13.4805 12.26 13.5205C12.3 13.5205 12.34 13.5605 12.38 13.5605H12.78C12.82 13.5605 12.86 13.5205 12.9 13.5205C12.98 13.4805 13.06 13.4405 13.14 13.3605L16.42 10.0805C16.74 9.76047 16.74 9.28047 16.42 9.00047C16.02 8.68047 15.54 8.68047 15.26 9.00047Z"/> | ||
| 5 | +</svg> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +<svg width="25" height="24" viewBox="0 0 25 24" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M23.2998 14.7202H17.9798C17.6198 14.7202 17.2998 14.9602 17.2198 15.2802L16.3398 18.1202H8.65981L7.77981 15.2802C7.65981 14.9602 7.37981 14.7202 7.01981 14.7202H1.6998C1.4598 14.7202 1.2998 14.8802 1.2998 15.1202V21.3202C1.2998 22.2002 2.0198 22.9202 2.8998 22.9202H22.0998C22.9798 22.9202 23.6998 22.2002 23.6998 21.3202V15.1202C23.6998 14.9202 23.5398 14.7202 23.2998 14.7202Z"/> | ||
| 3 | +<path d="M23.7002 14.8801L21.0202 2.00008C20.9002 1.48008 20.4202 1.08008 19.9002 1.08008H5.14016C4.58016 1.08008 4.10016 1.48008 4.02016 2.00008L1.30016 14.8801C1.26016 15.0801 1.30016 15.2801 1.42016 15.4801C1.54016 15.6401 1.70016 15.7601 1.90016 15.8001H2.06016C2.22016 15.8001 2.34016 15.7601 2.50016 15.6801C2.66016 15.5601 2.78016 15.4001 2.82016 15.2001L5.42016 2.64008H19.5402L22.1802 15.2001C22.2602 15.6001 22.7002 15.8801 23.1002 15.8001C23.3002 15.7601 23.4602 15.6401 23.5802 15.4801C23.7002 15.2801 23.7402 15.0801 23.7002 14.8801Z"/> | ||
| 4 | +<path d="M9.89918 10.0401L11.8592 8.08006L11.8592 12.8001C11.8592 13.2401 12.2192 13.5601 12.6192 13.5601C13.0592 13.5601 13.3792 13.2001 13.3792 12.8001L13.3792 8.08006L15.3392 10.0401C15.6592 10.3601 16.1392 10.3601 16.4192 10.0401C16.7392 9.72006 16.7392 9.24006 16.4192 8.96006L13.1392 5.68006C13.0592 5.60006 12.9792 5.56006 12.8992 5.52006C12.8592 5.52006 12.8192 5.48006 12.7792 5.48006L12.3792 5.48006C12.3392 5.48006 12.2992 5.52006 12.2592 5.52006C12.1792 5.56006 12.0992 5.60006 12.0192 5.68006L8.73918 8.96006C8.41918 9.28006 8.41918 9.76006 8.73918 10.0401C9.13918 10.3601 9.61918 10.3601 9.89918 10.0401Z"/> | ||
| 5 | +</svg> | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path d="M9 1.125C11.2268 1.1835 13.0813 1.95394 14.5637 3.43631C16.0461 4.91869 16.8165 6.77325 16.875 9C16.8165 11.2268 16.0461 13.0813 14.5637 14.5637C13.0813 16.0461 11.2268 16.8165 9 16.875C6.77325 16.8165 4.91869 16.0461 3.43631 14.5637C1.95394 13.0813 1.1835 11.2268 1.125 9C1.1835 6.77325 1.95394 4.91869 3.43631 3.43631C4.91869 1.95394 6.77325 1.1835 9 1.125ZM10.1779 5.95913C10.4827 5.95913 10.7347 5.86837 10.9339 5.68687C11.133 5.50537 11.2326 5.26219 11.2326 4.95731C11.2326 4.65244 11.133 4.40925 10.9339 4.22775C10.7347 4.04625 10.4858 3.9555 10.1869 3.9555C9.888 3.9555 9.639 4.04625 9.43987 4.22775C9.24075 4.40925 9.14119 4.65244 9.14119 4.95731C9.14119 5.26219 9.24075 5.50537 9.43987 5.68687C9.639 5.86837 9.88519 5.95913 10.1784 5.95913H10.1779ZM10.3888 12.2872C10.3888 12.2168 10.3946 12.123 10.4062 12.006C10.4179 11.889 10.4179 11.7776 10.4062 11.6719L9.47475 12.744C9.381 12.8494 9.28425 12.9315 9.1845 12.9904C9.08475 13.0492 8.99981 13.0669 8.92969 13.0433C8.82431 12.9964 8.77744 12.9143 8.78906 12.7969L10.3359 7.92788C10.3944 7.59975 10.3418 7.3185 10.1779 7.08413C10.014 6.84975 9.75037 6.70913 9.387 6.66225C8.97675 6.67387 8.52844 6.84675 8.04206 7.18087C7.55569 7.515 7.13081 7.93987 6.76744 8.4555V8.71931C6.75581 8.83669 6.75581 8.94806 6.76744 9.05344L7.69894 7.98131C7.79269 7.87594 7.88944 7.79381 7.98919 7.73494C8.08894 7.67606 8.16806 7.65844 8.22656 7.68206C8.34394 7.74056 8.385 7.83431 8.34975 7.96331L6.82031 12.8149C6.73819 13.1077 6.77925 13.3686 6.9435 13.5973C7.10775 13.8261 7.39481 13.9813 7.80469 14.0631C8.39081 14.0514 8.883 13.8816 9.28125 13.5534C9.6795 13.2253 10.0487 12.8034 10.3888 12.2878V12.2872Z" fill="#165DFF"/> | ||
| 3 | +</svg> | ||
| @@ -0,0 +1 @@ | |||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> | ||
| @@ -0,0 +1 @@ | |||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1659077409267" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14079" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M504.109851 16.453128c-278.332339 0-503.966321 225.632974-503.966321 503.966321S225.776505 1024.384762 504.109851 1024.384762s503.966321-225.632974 503.966321-503.966321S782.44219 16.453128 504.109851 16.453128zM242.706054 566.655409l0.04734-94.679771 525.432441 0-0.017123 94.679771L242.706054 566.655409z" p-id="14080" fill="#f7777a"></path></svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1659077382374" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13110" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M512.260431 5.116531C231.865323 5.116531 4.636089 232.376465 4.636089 512.740874c0 280.33371 227.229235 507.624343 507.624343 507.624343 280.396131 0 507.625366-227.291656 507.624343-507.624343C1019.885797 232.376465 792.656563 5.116531 512.260431 5.116531zM691.775968 647.330198c12.393261 12.393261 12.393261 32.502251 0 44.893466-12.391215 12.393261-32.531927 12.393261-44.923142 0L512.446673 557.790906l-135.333268 135.332245c-12.516058 12.485359-32.718169 12.485359-45.235251 0-12.516058-12.485359-12.516058-32.718169 0-45.205575L467.211423 512.555655 332.745918 378.119827c-12.393261-12.362562-12.393261-32.469506 0-44.833091 12.392238-12.393261 32.531927-12.393261 44.86379 0l134.465504 134.404106 136.325875-136.324852c12.516058-12.486382 32.718169-12.486382 45.234227 0 12.516058 12.486382 12.516058 32.718169 0 45.203528l-136.324852 136.355551L691.775968 647.330198z" p-id="13111" fill="#ff8a52"></path></svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1659077038907" class="icon" viewBox="0 0 1026 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4484" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.390625" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M1004.657 801.716 602.263 91.599c-49.213-86.817-129.646-86.817-178.866 0L21.004 801.716c-49.207 86.906-8.949 157.798 89.388 157.798l804.877 0C1013.606 959.514 1053.825 888.622 1004.657 801.716zM544.635 832.216l-63.649 0 0-63.649 63.649 0L544.635 832.216zM544.635 641.27l-63.649 0L480.986 259.377l63.649 0L544.635 641.27z" p-id="4485" fill="#ffcc00"></path></svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1659077306393" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10197" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M1024 512A512 512 0 1 1 512 0a512 512 0 0 1 512 512z m-482.210909 114.269091l15.127273-380.974546a44.916364 44.916364 0 0 0-89.832728 0l15.127273 380.974546c0 10.472727 13.730909 18.618182 29.789091 18.618182s29.323636-8.145455 29.789091-18.618182zM512 712.145455a46.545455 46.545455 0 1 0 46.545455 46.545454 46.545455 46.545455 0 0 0-46.545455-46.545454z" p-id="10198" fill="#36c3fb"></path></svg> | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +<svg t="1661420616981" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1618" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); } | ||
| 2 | +</style></defs><path d="M916.8 194.9a3.9 3.9 0 0 0-5.6 0L375.9 730.1l-263.1-263a3.9 3.9 0 0 0-5.6 0l-45.3 45.3a4 4 0 0 0 0 5.6l265.9 265.9 45.3 45.2a3.9 3.9 0 0 0 5.6 0l45.3-45.2 538.1-538.1a4.2 4.2 0 0 0 0-5.7z" p-id="1619" fill="#00c8db"></path></svg> | ||
| @@ -0,0 +1,57 @@ | |||
| 1 | +// Generated by 'unplugin-auto-import' | ||
| 2 | +export {} | ||
| 3 | +declare global { | ||
| 4 | + const EffectScope: typeof import('vue')['EffectScope'] | ||
| 5 | + const computed: typeof import('vue')['computed'] | ||
| 6 | + const createApp: typeof import('vue')['createApp'] | ||
| 7 | + const customRef: typeof import('vue')['customRef'] | ||
| 8 | + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] | ||
| 9 | + const defineComponent: typeof import('vue')['defineComponent'] | ||
| 10 | + const effectScope: typeof import('vue')['effectScope'] | ||
| 11 | + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] | ||
| 12 | + const getCurrentScope: typeof import('vue')['getCurrentScope'] | ||
| 13 | + const h: typeof import('vue')['h'] | ||
| 14 | + const inject: typeof import('vue')['inject'] | ||
| 15 | + const isProxy: typeof import('vue')['isProxy'] | ||
| 16 | + const isReactive: typeof import('vue')['isReactive'] | ||
| 17 | + const isReadonly: typeof import('vue')['isReadonly'] | ||
| 18 | + const isRef: typeof import('vue')['isRef'] | ||
| 19 | + const markRaw: typeof import('vue')['markRaw'] | ||
| 20 | + const nextTick: typeof import('vue')['nextTick'] | ||
| 21 | + const onActivated: typeof import('vue')['onActivated'] | ||
| 22 | + const onBeforeMount: typeof import('vue')['onBeforeMount'] | ||
| 23 | + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] | ||
| 24 | + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] | ||
| 25 | + const onDeactivated: typeof import('vue')['onDeactivated'] | ||
| 26 | + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] | ||
| 27 | + const onMounted: typeof import('vue')['onMounted'] | ||
| 28 | + const onRenderTracked: typeof import('vue')['onRenderTracked'] | ||
| 29 | + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] | ||
| 30 | + const onScopeDispose: typeof import('vue')['onScopeDispose'] | ||
| 31 | + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] | ||
| 32 | + const onUnmounted: typeof import('vue')['onUnmounted'] | ||
| 33 | + const onUpdated: typeof import('vue')['onUpdated'] | ||
| 34 | + const provide: typeof import('vue')['provide'] | ||
| 35 | + const reactive: typeof import('vue')['reactive'] | ||
| 36 | + const readonly: typeof import('vue')['readonly'] | ||
| 37 | + const ref: typeof import('vue')['ref'] | ||
| 38 | + const resolveComponent: typeof import('vue')['resolveComponent'] | ||
| 39 | + const shallowReactive: typeof import('vue')['shallowReactive'] | ||
| 40 | + const shallowReadonly: typeof import('vue')['shallowReadonly'] | ||
| 41 | + const shallowRef: typeof import('vue')['shallowRef'] | ||
| 42 | + const toRaw: typeof import('vue')['toRaw'] | ||
| 43 | + const toRef: typeof import('vue')['toRef'] | ||
| 44 | + const toRefs: typeof import('vue')['toRefs'] | ||
| 45 | + const triggerRef: typeof import('vue')['triggerRef'] | ||
| 46 | + const unref: typeof import('vue')['unref'] | ||
| 47 | + const useAttrs: typeof import('vue')['useAttrs'] | ||
| 48 | + const useCssModule: typeof import('vue')['useCssModule'] | ||
| 49 | + const useCssVars: typeof import('vue')['useCssVars'] | ||
| 50 | + const useRoute: typeof import('vue-router')['useRoute'] | ||
| 51 | + const useRouter: typeof import('vue-router')['useRouter'] | ||
| 52 | + const useSlots: typeof import('vue')['useSlots'] | ||
| 53 | + const watch: typeof import('vue')['watch'] | ||
| 54 | + const watchEffect: typeof import('vue')['watchEffect'] | ||
| 55 | + const watchPostEffect: typeof import('vue')['watchPostEffect'] | ||
| 56 | + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] | ||
| 57 | +} | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | +// generated by unplugin-vue-components | ||
| 2 | +// We suggest you to commit this file into source control | ||
| 3 | +// Read more: https://github.com/vuejs/core/pull/3399 | ||
| 4 | +import '@vue/runtime-core' | ||
| 5 | + | ||
| 6 | +export {} | ||
| 7 | + | ||
| 8 | +declare module '@vue/runtime-core' { | ||
| 9 | + export interface GlobalComponents { | ||
| 10 | + AlertConfig: typeof import('./components/AlertConfig.vue')['default'] | ||
| 11 | + ClusterCascader: typeof import('./components/ClusterCascader.vue')['default'] | ||
| 12 | + ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] | ||
| 13 | + ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ||
| 14 | + ElButton: typeof import('element-plus/es')['ElButton'] | ||
| 15 | + ElCard: typeof import('element-plus/es')['ElCard'] | ||
| 16 | + ElCascader: typeof import('element-plus/es')['ElCascader'] | ||
| 17 | + ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | ||
| 18 | + ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] | ||
| 19 | + ElCol: typeof import('element-plus/es')['ElCol'] | ||
| 20 | + ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] | ||
| 21 | + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] | ||
| 22 | + ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] | ||
| 23 | + ElDialog: typeof import('element-plus/es')['ElDialog'] | ||
| 24 | + ElDivider: typeof import('element-plus/es')['ElDivider'] | ||
| 25 | + ElForm: typeof import('element-plus/es')['ElForm'] | ||
| 26 | + ElFormItem: typeof import('element-plus/es')['ElFormItem'] | ||
| 27 | + ElIcon: typeof import('element-plus/es')['ElIcon'] | ||
| 28 | + ElInput: typeof import('element-plus/es')['ElInput'] | ||
| 29 | + ElMenu: typeof import('element-plus/es')['ElMenu'] | ||
| 30 | + ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] | ||
| 31 | + ElOption: typeof import('element-plus/es')['ElOption'] | ||
| 32 | + ElPagination: typeof import('element-plus/es')['ElPagination'] | ||
| 33 | + ElPopover: typeof import('element-plus/es')['ElPopover'] | ||
| 34 | + ElRadio: typeof import('element-plus/es')['ElRadio'] | ||
| 35 | + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] | ||
| 36 | + ElRow: typeof import('element-plus/es')['ElRow'] | ||
| 37 | + ElSelect: typeof import('element-plus/es')['ElSelect'] | ||
| 38 | + ElSpace: typeof import('element-plus/es')['ElSpace'] | ||
| 39 | + ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] | ||
| 40 | + ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ||
| 41 | + ElTable: typeof import('element-plus/es')['ElTable'] | ||
| 42 | + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] | ||
| 43 | + ElTabPane: typeof import('element-plus/es')['ElTabPane'] | ||
| 44 | + ElTabs: typeof import('element-plus/es')['ElTabs'] | ||
| 45 | + ElTag: typeof import('element-plus/es')['ElTag'] | ||
| 46 | + Machines: typeof import('./components/Machines.vue')['default'] | ||
| 47 | + MonacoEditor: typeof import('./components/MonacoEditor.vue')['default'] | ||
| 48 | + MyBar: typeof import('./components/MyBar.vue')['default'] | ||
| 49 | + MyBarLine: typeof import('./components/MyBarLine.vue')['default'] | ||
| 50 | + MyBreadcrumb: typeof import('./layout/MyBreadcrumb.vue')['default'] | ||
| 51 | + MyCard: typeof import('./components/MyCard.vue')['default'] | ||
| 52 | + MyDatePicker: typeof import('./components/MyDatePicker.vue')['default'] | ||
| 53 | + MyHeader: typeof import('./layout/MyHeader.vue')['default'] | ||
| 54 | + MyLine: typeof import('./components/MyLine.vue')['default'] | ||
| 55 | + MyMenu: typeof import('./layout/MyMenu.vue')['default'] | ||
| 56 | + MyMessage: typeof import('./components/MyMessage.vue')['default'] | ||
| 57 | + MyOperator: typeof import('./components/MyOperator.vue')['default'] | ||
| 58 | + MyPie: typeof import('./components/MyPie.vue')['default'] | ||
| 59 | + MyProgress: typeof import('./components/MyProgress.vue')['default'] | ||
| 60 | + MyTable: typeof import('./components/MyTable.vue')['default'] | ||
| 61 | + Proxies: typeof import('./components/Proxies.vue')['default'] | ||
| 62 | + RouterLink: typeof import('vue-router')['RouterLink'] | ||
| 63 | + RouterView: typeof import('vue-router')['RouterView'] | ||
| 64 | + SvgIcon: typeof import('./components/SvgIcon.vue')['default'] | ||
| 65 | + } | ||
| 66 | +} | ||
| @@ -0,0 +1,87 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('app.setAlertConfig') }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 8 | + <el-form-item :label="$t('AlertClusterNodeConf.alertIp')"> | ||
| 9 | + <el-input v-model="formData.alertIp" :disabled="!alertConfigEnv.isInstall"></el-input> | ||
| 10 | + </el-form-item> | ||
| 11 | + <el-form-item :label="$t('AlertClusterNodeConf.alertPort')"> | ||
| 12 | + <el-input v-model="formData.alertPort" :disabled="!alertConfigEnv.isInstall"></el-input> | ||
| 13 | + </el-form-item> | ||
| 14 | + <el-form-item :label="$t('AlertClusterNodeConf.interfaceAddr')"> | ||
| 15 | + <span>{{ 'http://' + (formData.alertIp ? formData.alertIp : 'IP') + ':' + (formData.alertPort ? | ||
| 16 | + formData.alertPort : 'port') + '/plugins/alert-center/alertCenter/api/v1/alerts' }}</span> | ||
| 17 | + </el-form-item> | ||
| 18 | + </el-form> | ||
| 19 | + <el-row> | ||
| 20 | + <el-button :disabled="!alertConfigEnv.isInstall" type="primary" @click="confirm">{{ t('app.confirm') }}</el-button> | ||
| 21 | + </el-row> | ||
| 22 | + <el-dialog v-model="dialogVisible" :title="t('app.tip')" width="30%"> | ||
| 23 | + <span v-if="!alertConfigEnv.isInstall"> | ||
| 24 | + {{ t('app.uninstallTip') }} | ||
| 25 | + </span> | ||
| 26 | + <span v-if="!alertConfigEnv.isConfig"> | ||
| 27 | + {{ t('app.disConfigTip') }} | ||
| 28 | + </span> | ||
| 29 | + <template #footer> | ||
| 30 | + <span class="dialog-footer"> | ||
| 31 | + <el-button type="primary" @click="closeTip"> | ||
| 32 | + {{ t('app.confirm') }} | ||
| 33 | + </el-button> | ||
| 34 | + </span> | ||
| 35 | + </template> | ||
| 36 | + </el-dialog> | ||
| 37 | + | ||
| 38 | + </div> | ||
| 39 | +</template> | ||
| 40 | + | ||
| 41 | +<script setup lang='ts'> | ||
| 42 | +import "element-plus/es/components/message-box/style/index"; | ||
| 43 | +import { useRequest } from "vue-request"; | ||
| 44 | +import request from "@/request"; | ||
| 45 | +import { ElMessage } from "element-plus"; | ||
| 46 | +import { useI18n } from "vue-i18n"; | ||
| 47 | +import { useAlertConfigStore } from "@/store/alertConfig"; | ||
| 48 | + | ||
| 49 | +const { t } = useI18n(); | ||
| 50 | +const dialogVisible = ref<boolean>(false) | ||
| 51 | + | ||
| 52 | +const alertConfigEnv = useAlertConfigStore(); | ||
| 53 | +const formData = ref<any>({ | ||
| 54 | + id: '', | ||
| 55 | + alertIp: '', | ||
| 56 | + alertPort: '' | ||
| 57 | +}) | ||
| 58 | + | ||
| 59 | +const confirm = () => { | ||
| 60 | + request.post(`/alertCenter/api/v1/alertConf`, formData.value).then((res: any) => { | ||
| 61 | + if (res && res.code === 200) { | ||
| 62 | + ElMessage({ | ||
| 63 | + message: t('app.saveSuccess'), | ||
| 64 | + type: 'success' | ||
| 65 | + }) | ||
| 66 | + alertConfigEnv.isConfig = true | ||
| 67 | + alertConfigEnv.showMain = true | ||
| 68 | + } else { | ||
| 69 | + ElMessage({ | ||
| 70 | + message: t('app.saveFail'), | ||
| 71 | + type: 'error' | ||
| 72 | + }) | ||
| 73 | + } | ||
| 74 | + }) | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +const closeTip = () => { | ||
| 78 | + dialogVisible.value = false | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +onMounted(() => { | ||
| 82 | + if (!alertConfigEnv.showMain) { | ||
| 83 | + dialogVisible.value = true | ||
| 84 | + } | ||
| 85 | +}) | ||
| 86 | +</script> | ||
| 87 | +<style scoped lang='scss'></style> | ||
| @@ -0,0 +1,108 @@ | |||
| 1 | +<template> | ||
| 2 | + <div class="filter"> | ||
| 3 | + <span>{{ props.title }} </span> | ||
| 4 | + <el-cascader v-model="cluster" :options="clusterList" @change="getClusterValue" style="max-width: 200px" :style="{ width: width ? width + 'px' : 'auto' }" :clearable="!notClearable" /> | ||
| 5 | + </div> | ||
| 6 | +</template> | ||
| 7 | + | ||
| 8 | +<script lang="ts" setup> | ||
| 9 | +import ogRequest from "../request"; | ||
| 10 | +import { useRequest } from "vue-request"; | ||
| 11 | + | ||
| 12 | +type Rer = | ||
| 13 | + | [ | ||
| 14 | + { | ||
| 15 | + [propName: string]: string | number; | ||
| 16 | + } | ||
| 17 | + ] | ||
| 18 | + | undefined; | ||
| 19 | +const props = withDefaults( | ||
| 20 | + defineProps<{ | ||
| 21 | + title?: string; | ||
| 22 | + width?: string; | ||
| 23 | + instanceValueKey?: string; | ||
| 24 | + notClearable?: boolean; | ||
| 25 | + clusterOnly?: boolean; | ||
| 26 | + autoSelectFirst?: boolean; // now only support one level | ||
| 27 | + }>(), | ||
| 28 | + { | ||
| 29 | + title: "", | ||
| 30 | + width: "", | ||
| 31 | + instanceValueKey: "nodeId", | ||
| 32 | + notClearable: false, | ||
| 33 | + clusterOnly: false, | ||
| 34 | + autoSelectFirst: false, | ||
| 35 | + } | ||
| 36 | +); | ||
| 37 | +const emit = defineEmits(["getCluster", "loaded"]); | ||
| 38 | + | ||
| 39 | +const cluster = ref<Array<any>>([]); | ||
| 40 | +const clusterList = ref<Array<any>>([]); | ||
| 41 | + | ||
| 42 | +const treeTransform = (arr: any) => { | ||
| 43 | + let obj: any = []; | ||
| 44 | + if (arr instanceof Array) { | ||
| 45 | + arr.forEach((item) => { | ||
| 46 | + obj.push({ | ||
| 47 | + label: item.clusterId ? item.clusterId : item.azName + "_" + item.publicIp, | ||
| 48 | + value: item.clusterId ? item.clusterId : item[props.instanceValueKey], | ||
| 49 | + children: props.clusterOnly ? null : treeTransform(item.clusterNodes), | ||
| 50 | + nodeId: item.nodeId ? item.nodeId : null, | ||
| 51 | + }); | ||
| 52 | + }); | ||
| 53 | + if (props.autoSelectFirst && obj.length > 0) { | ||
| 54 | + if (props.clusterOnly) cluster.value = [obj[0].value]; | ||
| 55 | + else if (obj[0].children.length > 0) cluster.value = [obj[0].value, obj[0].children[0].value]; | ||
| 56 | + emit("getCluster", cluster.value); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + return obj; | ||
| 60 | +}; | ||
| 61 | +const getClusterValue = (val: string[]) => { | ||
| 62 | + if (val == null) emit("getCluster", []); | ||
| 63 | + else emit("getCluster", val); | ||
| 64 | +}; | ||
| 65 | +const setNodeId = (val: string) => { | ||
| 66 | + if (val === "" || val === null || val === undefined) return; | ||
| 67 | + nextTick(() => { | ||
| 68 | + if (clusterList.value.length <= 0) return; | ||
| 69 | + for (let p1 = 0; p1 < clusterList.value.length; p1++) { | ||
| 70 | + const clusterTemp = clusterList.value[p1]; | ||
| 71 | + for (let p2 = 0; p2 < clusterTemp.children.length; p2++) { | ||
| 72 | + const node = clusterTemp.children[p2]; | ||
| 73 | + if (node.nodeId === val) { | ||
| 74 | + cluster.value = [clusterTemp.value, node.value]; | ||
| 75 | + emit("getCluster", cluster.value); | ||
| 76 | + return; | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + }); | ||
| 81 | +}; | ||
| 82 | +defineExpose({ setNodeId }); | ||
| 83 | + | ||
| 84 | +onMounted(() => { | ||
| 85 | + clusterData(); | ||
| 86 | +}); | ||
| 87 | +const { data: rer, run: clusterData } = useRequest( | ||
| 88 | + () => { | ||
| 89 | + return ogRequest.get("/observability/v1/topsql/cluster", ""); | ||
| 90 | + }, | ||
| 91 | + { manual: true } | ||
| 92 | +); | ||
| 93 | + | ||
| 94 | +watch(rer, (rer: Rer) => { | ||
| 95 | + if (rer && Object.keys(rer).length) { | ||
| 96 | + clusterList.value = treeTransform(rer); | ||
| 97 | + emit("loaded", rer); | ||
| 98 | + } | ||
| 99 | +}); | ||
| 100 | +</script> | ||
| 101 | + | ||
| 102 | +<style lang="scss" scoped> | ||
| 103 | +.filter { | ||
| 104 | + display: flex; | ||
| 105 | + flex-wrap: nowrap; | ||
| 106 | + align-items: center; | ||
| 107 | +} | ||
| 108 | +</style> | ||
| @@ -0,0 +1,54 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-select v-model="machineValue" @change="selectMachine" :clearable="!notClearable" :style="{ width: width ? width + 'px' : 'auto' }"> | ||
| 4 | + <el-option v-for="item in machineList" :key="item.hostId" :label="item.privateIp + '(' + item.publicIp + ')'" :value="item.hostId" /> | ||
| 5 | + </el-select> | ||
| 6 | + </div> | ||
| 7 | +</template> | ||
| 8 | + | ||
| 9 | +<script lang="ts" setup> | ||
| 10 | +import restRequest from "../request/restful"; | ||
| 11 | +import { useRequest } from "vue-request"; | ||
| 12 | + | ||
| 13 | +const props = withDefaults( | ||
| 14 | + defineProps<{ | ||
| 15 | + width?: string; | ||
| 16 | + notClearable?: boolean; | ||
| 17 | + autoSelectFirst?: boolean; | ||
| 18 | + }>(), | ||
| 19 | + { | ||
| 20 | + width: "", | ||
| 21 | + notClearable: false, | ||
| 22 | + autoSelectFirst: false, | ||
| 23 | + } | ||
| 24 | +); | ||
| 25 | +const emit = defineEmits(["change", "loaded"]); | ||
| 26 | + | ||
| 27 | +const machineValue = ref<any>(); | ||
| 28 | +const machineList = ref<Array<any>>([]); | ||
| 29 | + | ||
| 30 | +const selectMachine = (val: string[]) => { | ||
| 31 | + emit("change", machineValue); | ||
| 32 | +}; | ||
| 33 | + | ||
| 34 | +onMounted(() => { | ||
| 35 | + clusterData(); | ||
| 36 | +}); | ||
| 37 | +const { data: rer, run: clusterData } = useRequest( | ||
| 38 | + () => { | ||
| 39 | + return restRequest.get("/observability/v1/environment/hosts", ""); | ||
| 40 | + }, | ||
| 41 | + { manual: true } | ||
| 42 | +); | ||
| 43 | + | ||
| 44 | +watch(rer, (rer) => { | ||
| 45 | + if (rer.length) { | ||
| 46 | + machineList.value = rer; | ||
| 47 | + emit("loaded"); | ||
| 48 | + if (props.autoSelectFirst && machineList.value.length > 0) { | ||
| 49 | + machineValue.value = machineList.value[0].hostId; | ||
| 50 | + emit("change", machineValue.value); | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | +}); | ||
| 54 | +</script> | ||
| @@ -0,0 +1,142 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import * as monaco from "monaco-editor"; | ||
| 3 | +import { format } from "sql-formatter"; | ||
| 4 | +import { uuid } from "../shared"; | ||
| 5 | + | ||
| 6 | +const id = 'monaco_' + uuid() | ||
| 7 | +const props = withDefaults( | ||
| 8 | + defineProps<{ | ||
| 9 | + modelValue: string; | ||
| 10 | + /** | ||
| 11 | + * enable editor readOnly | ||
| 12 | + */ | ||
| 13 | + readOnly?: boolean; | ||
| 14 | + sqlFormatter?: boolean; | ||
| 15 | + height?: number | string; | ||
| 16 | + /** | ||
| 17 | + * enable editor to resize height | ||
| 18 | + */ | ||
| 19 | + resize?: boolean; | ||
| 20 | + }>(), | ||
| 21 | + { | ||
| 22 | + readOnly: true, | ||
| 23 | + sqlFormatter: true, | ||
| 24 | + height: '100%', | ||
| 25 | + } | ||
| 26 | +); | ||
| 27 | +const myEmit = defineEmits<{(event: 'update:modelValue', text: string): void}>() | ||
| 28 | + | ||
| 29 | +let editor:monaco.editor.IStandaloneCodeEditor; | ||
| 30 | +const queryText = ref(props.modelValue) | ||
| 31 | +if (props.sqlFormatter && props.modelValue) { | ||
| 32 | + let text = format(props.modelValue); | ||
| 33 | + let index = 0; | ||
| 34 | + while ((index = text.indexOf("$", index + 1)) > -1) { | ||
| 35 | + text = | ||
| 36 | + text.slice(0, index).trimEnd() + | ||
| 37 | + "$" + | ||
| 38 | + text.slice(index + 1).trimStart(); | ||
| 39 | + } | ||
| 40 | + queryText.value = text; | ||
| 41 | +} | ||
| 42 | +watch(() => props.modelValue, v => { | ||
| 43 | + const pos = editor.getPosition()! | ||
| 44 | + editor.setValue(v) | ||
| 45 | + editor.setPosition(pos) | ||
| 46 | +}) | ||
| 47 | +onMounted(() => { | ||
| 48 | + nextTick(() => { | ||
| 49 | + editor = monaco.editor.create( | ||
| 50 | + document.getElementById(id) as HTMLElement, | ||
| 51 | + { | ||
| 52 | + value: queryText.value, | ||
| 53 | + language: "sql", | ||
| 54 | + readOnly: props.readOnly, | ||
| 55 | + wordWrap: "on", | ||
| 56 | + lineNumbersMinChars: 3, | ||
| 57 | + rulers: [0], | ||
| 58 | + overviewRulerBorder: false, | ||
| 59 | + scrollbar: { | ||
| 60 | + useShadows: false, | ||
| 61 | + verticalScrollbarSize: 5, | ||
| 62 | + }, | ||
| 63 | + renderLineHighlight: "gutter", | ||
| 64 | + scrollBeyondLastLine: false, | ||
| 65 | + autoIndent: 'keep', | ||
| 66 | + folding: true, | ||
| 67 | + foldingStrategy: "indentation", | ||
| 68 | + minimap: { | ||
| 69 | + enabled: false, | ||
| 70 | + }, | ||
| 71 | + formatOnType: true, | ||
| 72 | + fontSize: 12, | ||
| 73 | + theme: 'vs-dark', | ||
| 74 | + } | ||
| 75 | + ); | ||
| 76 | + editor.onDidChangeModelContent(() => { | ||
| 77 | + myEmit('update:modelValue', editor.getValue()) | ||
| 78 | + }) | ||
| 79 | + if (props.resize && window && 'ResizeObserver' in window) { | ||
| 80 | + const resizeObserver = new ResizeObserver(entries => { | ||
| 81 | + for (const entry of entries) { | ||
| 82 | + editor?.layout({ ...editor?.getLayoutInfo(), height: entry.contentRect.height }) | ||
| 83 | + } | ||
| 84 | + }) | ||
| 85 | + resizeObserver.observe(document.getElementById(id)!) | ||
| 86 | + } | ||
| 87 | + }) | ||
| 88 | +}) | ||
| 89 | +watch(() => props.height, height => { | ||
| 90 | + editor?.layout({ ...editor?.getLayoutInfo(), height: Number.parseFloat(`${height}`) }) | ||
| 91 | +}) | ||
| 92 | +</script> | ||
| 93 | + | ||
| 94 | +<template> | ||
| 95 | + <div | ||
| 96 | + class="monaco-container" | ||
| 97 | + :id="id" | ||
| 98 | + :style="{ | ||
| 99 | + height: ['%', 'px'].includes(`${props.height}`) ? props.height : `${props.height}px`, | ||
| 100 | + width: '100%', | ||
| 101 | + resize: props.resize ? 'vertical' : 'none', | ||
| 102 | + }" | ||
| 103 | + ></div> | ||
| 104 | +</template> | ||
| 105 | + | ||
| 106 | +<style scoped lang="scss"> | ||
| 107 | + | ||
| 108 | +.monaco-container { | ||
| 109 | + border: none !important; | ||
| 110 | + overflow: hidden; | ||
| 111 | + margin: 0!important; | ||
| 112 | +} | ||
| 113 | +:deep(.monaco-editor .view-ruler) { | ||
| 114 | + display: none; | ||
| 115 | +} | ||
| 116 | +:deep(.monaco-editor .margin) { | ||
| 117 | + width: 1px; | ||
| 118 | + background-color: var(--el-bg-color-og); | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +:deep(.monaco-editor .margin-view-overlays) { | ||
| 122 | + background-color: var(--el-bg-color-og); | ||
| 123 | + border-right: 1px solid var(--el-color--col-border-color); | ||
| 124 | + width: 34px !important; | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +:deep(.monaco-editor .margin-view-overlays div) { | ||
| 128 | + color: var(--el-text-color-og); | ||
| 129 | +} | ||
| 130 | + | ||
| 131 | +:deep(.monaco-editor .monaco-editor-background) { | ||
| 132 | + background-color: var(--el-bg-color-og); | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +:deep(.monaco-editor .current-line-margin) { | ||
| 136 | + border: none !important; | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +:deep(.monaco-editor .view-lines .mtk1) { | ||
| 140 | + color: var(--el-text-color-og); | ||
| 141 | +} | ||
| 142 | +</style> | ||
| @@ -0,0 +1,155 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import * as echarts from "echarts/core"; | ||
| 3 | +import { GridComponent, GridComponentOption, TooltipComponent, TooltipComponentOption, LegendComponent, TitleComponent, ToolboxComponent, VisualMapComponent } from "echarts/components"; | ||
| 4 | +import { BarSeriesOption, BarChart } from "echarts/charts"; | ||
| 5 | +import { UniversalTransition } from 'echarts/features'; | ||
| 6 | +import { CanvasRenderer } from "echarts/renderers"; | ||
| 7 | +import { useEventListener } from "@vueuse/core"; | ||
| 8 | +import { uuid } from "../shared"; | ||
| 9 | +import { YAXisOption } from "echarts/types/dist/shared"; | ||
| 10 | +import { OptionDataValue } from 'echarts/types/src/util/types' | ||
| 11 | + | ||
| 12 | +export type LineData = { | ||
| 13 | + name: string, | ||
| 14 | + nameGap?: number, | ||
| 15 | + data: any[], | ||
| 16 | + unit?: string, // unit | ||
| 17 | + min?: number, | ||
| 18 | + max?: number, | ||
| 19 | + interval?: number, | ||
| 20 | + stack:string, | ||
| 21 | + } | ||
| 22 | +type EchartsOption = echarts.ComposeOption< | ||
| 23 | + GridComponentOption | TooltipComponentOption | BarSeriesOption | ||
| 24 | +>; | ||
| 25 | +echarts.use([ | ||
| 26 | + CanvasRenderer, | ||
| 27 | + UniversalTransition, | ||
| 28 | + GridComponent, | ||
| 29 | + TooltipComponent, | ||
| 30 | + ToolboxComponent, | ||
| 31 | + TitleComponent, | ||
| 32 | + BarChart, | ||
| 33 | + VisualMapComponent, | ||
| 34 | + LegendComponent | ||
| 35 | +]); | ||
| 36 | +const domId = uuid(); | ||
| 37 | +let myChart: echarts.ECharts | ||
| 38 | +const props = withDefaults(defineProps<{ | ||
| 39 | + // xAxis Data | ||
| 40 | + xData?: string[], | ||
| 41 | + yData?: string[], | ||
| 42 | + // yAxis Line Data | ||
| 43 | + data?: LineData[], | ||
| 44 | + maxData?:number, | ||
| 45 | + showNum?:boolean, | ||
| 46 | + title?:string, | ||
| 47 | + unit?: string, | ||
| 48 | + scatterUnit?: string, | ||
| 49 | + // yAxis Scatter Data | ||
| 50 | + // LineChart use areaStyle | ||
| 51 | + areaStyle?: boolean, | ||
| 52 | + // chart colors | ||
| 53 | + color?: string[], | ||
| 54 | + theme?: 'dark' | 'light', | ||
| 55 | +}>(), { | ||
| 56 | + xData: () => [], | ||
| 57 | + yData: () => [], | ||
| 58 | + data: () => [], | ||
| 59 | + maxData: 10, | ||
| 60 | + unit: '', | ||
| 61 | + scatterUnit: '', | ||
| 62 | + areaStyle: false, | ||
| 63 | + color: () => ['#37D4D1', '#00C7F9', '#0D86E2', '#425ADD', '#E64A19', '#9CCC65', '#A97526', '#2830FF', '#8B00E1', '#0F866A'], | ||
| 64 | + theme: 'dark', | ||
| 65 | +}); | ||
| 66 | +const renderChart = () => { | ||
| 67 | + let seriesData: Array<BarSeriesOption> = []; | ||
| 68 | + let yAxisData: Array<YAXisOption> = []; | ||
| 69 | + props.data.forEach(({ name, data, unit, interval, ...item }) => { | ||
| 70 | + let obj: BarSeriesOption = { | ||
| 71 | + type: 'bar', | ||
| 72 | + name, | ||
| 73 | + data, | ||
| 74 | + barWidth: 60, | ||
| 75 | + emphasis: { | ||
| 76 | + focus: 'series' | ||
| 77 | + }, | ||
| 78 | + tooltip: { | ||
| 79 | + valueFormatter: function (value: OptionDataValue | OptionDataValue[]) { | ||
| 80 | + return value + ` ${unit}`; | ||
| 81 | + } | ||
| 82 | + }, | ||
| 83 | + ...item | ||
| 84 | + } | ||
| 85 | + seriesData.push(obj) | ||
| 86 | + yAxisData.push({ | ||
| 87 | + type: 'value', | ||
| 88 | + // name, | ||
| 89 | + axisLabel: { | ||
| 90 | + formatter: `{value} ${unit}`, | ||
| 91 | + color: '#d4d4d4' | ||
| 92 | + }, | ||
| 93 | + nameTextStyle: { | ||
| 94 | + color: '#d4d4d4' | ||
| 95 | + }, | ||
| 96 | + splitLine: { | ||
| 97 | + lineStyle: { | ||
| 98 | + color: '#888888' | ||
| 99 | + } | ||
| 100 | + }, | ||
| 101 | + }) | ||
| 102 | + }) | ||
| 103 | + const chartDom = document.getElementById(domId); | ||
| 104 | + if (!myChart) { | ||
| 105 | + myChart = echarts.init(chartDom!); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + const option: EchartsOption = { | ||
| 109 | + tooltip: { | ||
| 110 | + trigger: 'axis', | ||
| 111 | + axisPointer: { | ||
| 112 | + type: 'shadow' | ||
| 113 | + } | ||
| 114 | + }, | ||
| 115 | + legend: { | ||
| 116 | + textStyle: { | ||
| 117 | + color: '#D4D4D4' | ||
| 118 | + }, | ||
| 119 | + }, | ||
| 120 | + grid: { | ||
| 121 | + left: '3%', | ||
| 122 | + right: '4%', | ||
| 123 | + bottom: '3%', | ||
| 124 | + containLabel: true | ||
| 125 | + }, | ||
| 126 | + xAxis: { | ||
| 127 | + type: 'category', | ||
| 128 | + axisLine: { | ||
| 129 | + lineStyle: { | ||
| 130 | + color: '#D4D4D4' | ||
| 131 | + } | ||
| 132 | + }, | ||
| 133 | + data: props.xData, | ||
| 134 | + }, | ||
| 135 | + yAxis: yAxisData, | ||
| 136 | + series: seriesData | ||
| 137 | + } | ||
| 138 | + myChart.setOption(option) | ||
| 139 | +} | ||
| 140 | +onMounted(() => { | ||
| 141 | + renderChart(); | ||
| 142 | +}) | ||
| 143 | + | ||
| 144 | +watch(() => props.data, () => { | ||
| 145 | + nextTick(renderChart) | ||
| 146 | +}, { deep: true }) | ||
| 147 | + | ||
| 148 | +useEventListener(window, "resize", () => { | ||
| 149 | + myChart?.resize(); | ||
| 150 | +}); | ||
| 151 | +</script> | ||
| 152 | + | ||
| 153 | +<template> | ||
| 154 | + <div :id="domId" ref="loadRef" style="width: 100%; height: 100%;"></div> | ||
| 155 | +</template> | ||
| @@ -0,0 +1,177 @@ | |||
| 1 | +<script lang="ts" setup> | ||
| 2 | +import { uuid } from "../shared"; | ||
| 3 | +import * as echarts from "echarts/core"; | ||
| 4 | +import { GridComponent, GridComponentOption, TooltipComponent, TooltipComponentOption, LegendComponent, TitleComponent, ToolboxComponent } from "echarts/components"; | ||
| 5 | +import { useEventListener } from "@vueuse/core"; | ||
| 6 | +import { LineChart, LineSeriesOption, BarSeriesOption, BarChart } from "echarts/charts"; | ||
| 7 | +import { UniversalTransition } from 'echarts/features'; | ||
| 8 | +import { CanvasRenderer } from "echarts/renderers"; | ||
| 9 | +import { OptionDataValue } from 'echarts/types/src/util/types' | ||
| 10 | +import { YAXisOption } from "echarts/types/dist/shared"; | ||
| 11 | + | ||
| 12 | +export type LineData = { | ||
| 13 | + name: string, | ||
| 14 | + nameGap?: number, | ||
| 15 | + data: any[], | ||
| 16 | + unit?: string, // unit | ||
| 17 | + type: 'line' | 'bar', | ||
| 18 | + min?: number, | ||
| 19 | + max?: number, | ||
| 20 | + interval?: number, | ||
| 21 | + barWidth?:number, | ||
| 22 | + yAxisIndex?:number, | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + type EchartsOption = echarts.ComposeOption< | ||
| 26 | + GridComponentOption | TooltipComponentOption | LineSeriesOption | BarSeriesOption | ||
| 27 | + > | ||
| 28 | + | ||
| 29 | +echarts.use([ | ||
| 30 | + CanvasRenderer, | ||
| 31 | + LineChart, | ||
| 32 | + BarChart, | ||
| 33 | + UniversalTransition, | ||
| 34 | + GridComponent, | ||
| 35 | + TooltipComponent, | ||
| 36 | + LegendComponent, | ||
| 37 | + TitleComponent, | ||
| 38 | + ToolboxComponent | ||
| 39 | +]); | ||
| 40 | + | ||
| 41 | +const props = withDefaults(defineProps<{ | ||
| 42 | + // xAxis Data | ||
| 43 | + xData?: string[], | ||
| 44 | + // yAxis Bar Data | Line Data | ||
| 45 | + data: LineData[], | ||
| 46 | + // yAxis Line Data | ||
| 47 | + lineData?: LineData[], | ||
| 48 | + // yAxis Bar Data | ||
| 49 | + barData?: LineData[], | ||
| 50 | + // LineChart use areaStyle | ||
| 51 | + areaStyle?: boolean, | ||
| 52 | + // chart colors | ||
| 53 | + color?: string[], | ||
| 54 | + // yAxis Line Name | ||
| 55 | + lineName?: string, | ||
| 56 | + // yAxis Line NameGap | ||
| 57 | + lineNameGap?: number, | ||
| 58 | + }>(), { | ||
| 59 | + xData: () => ['10:00', '11:00', '12:00', '13:00'], | ||
| 60 | + data: () => [], | ||
| 61 | + areaStyle: false, | ||
| 62 | + color: () => ['#37D4D1', '#00C7F9', '#0D86E2', '#425ADD', '#E64A19', '#9CCC65', '#A97526', '#2830FF', '#8B00E1', '#0F866A'], | ||
| 63 | +}) | ||
| 64 | + | ||
| 65 | +const domId = uuid(); | ||
| 66 | +let myChart: echarts.ECharts; | ||
| 67 | +const renderChart = () => { | ||
| 68 | + let seriesData: Array<LineSeriesOption | BarSeriesOption> = []; | ||
| 69 | + let yAxisData: Array<YAXisOption> = []; | ||
| 70 | + props.data.forEach(({ name, type, data, unit, min, max, interval, ...item }) => { | ||
| 71 | + let obj: LineSeriesOption | BarSeriesOption = { | ||
| 72 | + name, | ||
| 73 | + data, | ||
| 74 | + type, | ||
| 75 | + tooltip: { | ||
| 76 | + valueFormatter: function (value: OptionDataValue | OptionDataValue[]) { | ||
| 77 | + return value + ` ${unit}`; | ||
| 78 | + } | ||
| 79 | + }, | ||
| 80 | + ...item | ||
| 81 | + } | ||
| 82 | + if (type === 'line') obj.yAxisIndex = 1 | ||
| 83 | + seriesData.push(obj) | ||
| 84 | + yAxisData.push({ | ||
| 85 | + type: 'value', | ||
| 86 | + name, | ||
| 87 | + min, | ||
| 88 | + max, | ||
| 89 | + interval, | ||
| 90 | + axisLabel: { | ||
| 91 | + formatter: `{value} ${unit}`, | ||
| 92 | + color: '#d4d4d4' | ||
| 93 | + }, | ||
| 94 | + nameTextStyle: { | ||
| 95 | + color: '#d4d4d4' | ||
| 96 | + }, | ||
| 97 | + splitLine: { | ||
| 98 | + lineStyle: { | ||
| 99 | + color: '#888888' | ||
| 100 | + } | ||
| 101 | + }, | ||
| 102 | + }) | ||
| 103 | + }) | ||
| 104 | + const chartDom = document.getElementById(domId); | ||
| 105 | + myChart = echarts.init(chartDom!); | ||
| 106 | + const option: EchartsOption = { | ||
| 107 | + tooltip: { | ||
| 108 | + trigger: 'axis', | ||
| 109 | + axisPointer: { | ||
| 110 | + type: 'cross', | ||
| 111 | + crossStyle: { | ||
| 112 | + color: '#999' | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + }, | ||
| 116 | + toolbox: { | ||
| 117 | + left: '55%', | ||
| 118 | + feature: { | ||
| 119 | + dataView: { show: true, readOnly: false, title: '数据视图' }, | ||
| 120 | + magicType: { show: true, type: ['line', 'bar'], title: { line: '切换为折线图', bar: '切换为柱状图' } }, | ||
| 121 | + restore: { show: true, title: '还原' }, | ||
| 122 | + saveAsImage: { show: true, title: '下载图片' } | ||
| 123 | + }, | ||
| 124 | + iconStyle: { | ||
| 125 | + borderColor: '#d4d4d4', | ||
| 126 | + shadowColor: 'orange' | ||
| 127 | + } | ||
| 128 | + }, | ||
| 129 | + legend: { | ||
| 130 | + left: '30%', | ||
| 131 | + data: [{ | ||
| 132 | + name: 'Slow SQL', | ||
| 133 | + textStyle: { | ||
| 134 | + color: '#d4d4d4' | ||
| 135 | + } | ||
| 136 | + }, { | ||
| 137 | + name: 'cpu', | ||
| 138 | + textStyle: { | ||
| 139 | + color: '#d4d4d4' | ||
| 140 | + } | ||
| 141 | + }] | ||
| 142 | + }, | ||
| 143 | + xAxis: { | ||
| 144 | + type: 'category', | ||
| 145 | + axisTick: { show: false }, | ||
| 146 | + axisLine: { | ||
| 147 | + lineStyle: { | ||
| 148 | + color: '#d4d4d4' | ||
| 149 | + } | ||
| 150 | + }, | ||
| 151 | + axisPointer: { | ||
| 152 | + type: 'shadow' | ||
| 153 | + }, | ||
| 154 | + data: props.xData, | ||
| 155 | + }, | ||
| 156 | + yAxis: yAxisData, | ||
| 157 | + // series: props.data | ||
| 158 | + series: seriesData | ||
| 159 | + } | ||
| 160 | + myChart.setOption(option); | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +// onMounted(() => { | ||
| 164 | +// renderChart(); | ||
| 165 | +// }) | ||
| 166 | +watch(() => props.data, () => { | ||
| 167 | + nextTick(renderChart) | ||
| 168 | +}, { deep: true }) | ||
| 169 | +useEventListener(window, "resize", () => { | ||
| 170 | + myChart?.resize(); | ||
| 171 | +}); | ||
| 172 | + | ||
| 173 | +</script> | ||
| 174 | + | ||
| 175 | + <template> | ||
| 176 | + <div :id="domId" style="width: 100%;height: 100%;"></div> | ||
| 177 | + </template> | ||
| @@ -0,0 +1,229 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { useDebounceFn } from '@vueuse/core'; | ||
| 3 | +import { useWidthOverflow } from '../hooks/dom'; | ||
| 4 | + | ||
| 5 | +const props = withDefaults(defineProps<{ | ||
| 6 | + title: string, | ||
| 7 | + legend?: { color: string, name: string }[], | ||
| 8 | + bodyPadding?: boolean, | ||
| 9 | + height?: string | number, | ||
| 10 | + collapse?: boolean, | ||
| 11 | + skipBodyHeight?: boolean, // do not set body height | ||
| 12 | + // enable resize bodyHeight | ||
| 13 | + resize?: boolean, | ||
| 14 | + maxBodyHeight?: string, | ||
| 15 | + overflowHidden?: boolean, | ||
| 16 | + withTable?: boolean, | ||
| 17 | +}>(), { | ||
| 18 | + bodyPadding: true, | ||
| 19 | + maxBodyHeight: 'unset', | ||
| 20 | + overflowHidden: true, | ||
| 21 | + withTable: false, | ||
| 22 | +}) | ||
| 23 | +const hidden = ref(props.overflowHidden ? 'hidden' : 'unset') | ||
| 24 | +const padding = ref(props.bodyPadding ? "24px 16px" : "0px"); | ||
| 25 | +const withTableBorderRadius = ref(props.withTable ? '8px 8px 0 0' : '8px'); | ||
| 26 | +const bodyRef = ref<HTMLDivElement>() | ||
| 27 | +const bodyHeight = ref(`calc(100% - ${props.bodyPadding ? 90 : 42}px)`) | ||
| 28 | +const minBodyHeight = ref(bodyHeight.value) | ||
| 29 | +// unset transition animation when resize body height | ||
| 30 | +onMounted(() => { | ||
| 31 | + nextTick(() => { | ||
| 32 | + if (!props.skipBodyHeight && bodyRef && bodyRef.value) { | ||
| 33 | + bodyHeight.value = `${bodyRef.value.offsetHeight + (props.bodyPadding && !props.collapse ? 48 : 0)}px` | ||
| 34 | + } | ||
| 35 | + if (bodyRef && bodyRef.value && props.resize && window && 'ResizeObserver' in window) { | ||
| 36 | + const resizeObserver = new ResizeObserver(entries => { | ||
| 37 | + for (const entry of entries) { | ||
| 38 | + if (!collapsing.value) { | ||
| 39 | + bodyHeight.value = `${entry.contentRect.height}px` | ||
| 40 | + if (minBodyHeight.value.startsWith('calc')) { | ||
| 41 | + minBodyHeight.value = bodyHeight.value | ||
| 42 | + } | ||
| 43 | + myEmit('resize-body-height', entry.contentRect.height) | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | + }) | ||
| 47 | + resizeObserver.observe(bodyRef.value) | ||
| 48 | + } | ||
| 49 | + }) | ||
| 50 | +}) | ||
| 51 | +const myEmit = defineEmits<{ | ||
| 52 | + (event: 'resize-body-height', height: number): void | ||
| 53 | +}>() | ||
| 54 | +// ctl height | ||
| 55 | +const height = computed(() => { | ||
| 56 | + if (!props.height) { | ||
| 57 | + return '100%' | ||
| 58 | + } | ||
| 59 | + return (["%", "px"].includes(`${props.height}`)) ? props.height : `${props.height}px` | ||
| 60 | +}); | ||
| 61 | +// ctl collapse | ||
| 62 | +const isCollapse = ref(false) | ||
| 63 | +// skip ResizeObserver event when collapsing | ||
| 64 | +const collapsing = ref(false) | ||
| 65 | +const resetCollapsing = useDebounceFn(() => { | ||
| 66 | + collapsing.value = false | ||
| 67 | + if (bodyRef && bodyRef.value) { | ||
| 68 | + bodyRef.value.style.transition = 'unset' | ||
| 69 | + bodyRef.value.style.minHeight = isCollapse.value ? '0px' : minBodyHeight.value | ||
| 70 | + } | ||
| 71 | +}, 500) | ||
| 72 | +const toggleCollapse = () => { | ||
| 73 | + collapsing.value = true | ||
| 74 | + if (bodyRef && bodyRef.value) { | ||
| 75 | + bodyRef.value.style.transition = 'height 0.5s cubic-bezier(0.23, 1, 0.32, 1)' | ||
| 76 | + bodyRef.value.style.minHeight = !isCollapse.value ? '0px' : minBodyHeight.value | ||
| 77 | + } | ||
| 78 | + isCollapse.value = !isCollapse.value | ||
| 79 | + resetCollapsing() | ||
| 80 | +} | ||
| 81 | +const extraRef = ref() | ||
| 82 | +const dropdownRef = ref() | ||
| 83 | +const { overflow, isFinish, trigger } = useWidthOverflow(extraRef, dropdownRef) | ||
| 84 | +defineExpose({ | ||
| 85 | + trigger | ||
| 86 | +}) | ||
| 87 | +</script> | ||
| 88 | + | ||
| 89 | +<template> | ||
| 90 | +<div class="og-card"> | ||
| 91 | + <div class="og-card-header"> | ||
| 92 | + <span class="og-card-header--title"> | ||
| 93 | + <svg-icon | ||
| 94 | + v-if="props.collapse" | ||
| 95 | + name="arrow" | ||
| 96 | + :class="{'is-collapse': isCollapse}" | ||
| 97 | + @click="toggleCollapse" | ||
| 98 | + /> | ||
| 99 | + {{ props.title }} | ||
| 100 | + </span> | ||
| 101 | + <slot name="extra"> | ||
| 102 | + <div | ||
| 103 | + ref="extraRef" | ||
| 104 | + class="og-card-header--extra" | ||
| 105 | + :style="{justifyContent: overflow || !isFinish ? 'flex-start' : 'flex-end'}" | ||
| 106 | + > | ||
| 107 | + <el-dropdown ref="dropdownRef" :hide-on-click="false" :max-height="200"> | ||
| 108 | + <div></div> | ||
| 109 | + <template #dropdown> | ||
| 110 | + <el-dropdown-menu> | ||
| 111 | + <el-dropdown-item v-for="l in props.legend" :key="l.name"> | ||
| 112 | + <div class="hover"> | ||
| 113 | + <div :style="{ background: l.color }" class="rect"></div> | ||
| 114 | + <span :title="l.name">{{ l.name }}</span> | ||
| 115 | + </div> | ||
| 116 | + </el-dropdown-item> | ||
| 117 | + </el-dropdown-menu> | ||
| 118 | + </template> | ||
| 119 | + </el-dropdown> | ||
| 120 | + <div v-for="l in props.legend" :key="l.name"> | ||
| 121 | + <div :style="{ background: l.color }" class="rect"></div> | ||
| 122 | + <span :title="l.name">{{ l.name }}</span> | ||
| 123 | + </div> | ||
| 124 | + </div> | ||
| 125 | + <!-- <span v-show="overflow">...</span> --> | ||
| 126 | + </slot> | ||
| 127 | + </div> | ||
| 128 | + <div | ||
| 129 | + class="og-card-body" | ||
| 130 | + :class="{'is-collapse': isCollapse}" | ||
| 131 | + ref="bodyRef" | ||
| 132 | + :style="{ | ||
| 133 | + resize: props.resize ? 'vertical' : 'none', | ||
| 134 | + }" | ||
| 135 | + > | ||
| 136 | + <div> | ||
| 137 | + <slot /> | ||
| 138 | + </div> | ||
| 139 | + </div> | ||
| 140 | +</div> | ||
| 141 | +</template> | ||
| 142 | + | ||
| 143 | +<style scoped lang="scss"> | ||
| 144 | +.og-card { | ||
| 145 | + box-sizing: border-box; | ||
| 146 | + height: v-bind(height); | ||
| 147 | + border: 1px solid var(--el-og-border-color); | ||
| 148 | + border-radius: v-bind(withTableBorderRadius); | ||
| 149 | + overflow: v-bind(hidden); | ||
| 150 | + &-header { | ||
| 151 | + display: flex; | ||
| 152 | + overflow: hidden; | ||
| 153 | + background-color: var(--el-color-card-header-color); | ||
| 154 | + justify-content: space-between; | ||
| 155 | + padding: 0 16px; | ||
| 156 | + align-items: center; | ||
| 157 | + min-width: 0; | ||
| 158 | + height: 39px; | ||
| 159 | + border-bottom: 1px solid var(--el-og-border-color); | ||
| 160 | + &--title { | ||
| 161 | + font-weight: 700; | ||
| 162 | + font-size: 16px; | ||
| 163 | + flex-shrink: 0; | ||
| 164 | + > svg { | ||
| 165 | + position: relative; | ||
| 166 | + top: -2px; | ||
| 167 | + margin-right: 12px; | ||
| 168 | + transition: transform var(--el-transition-duration); | ||
| 169 | + &.is-collapse { | ||
| 170 | + transform: rotate(-90deg); | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + &--extra { | ||
| 175 | + position: relative; | ||
| 176 | + display: flex; | ||
| 177 | + margin-left: 16px; | ||
| 178 | + overflow: hidden; | ||
| 179 | + flex: 1; | ||
| 180 | + min-width: 0; | ||
| 181 | + align-items: center; | ||
| 182 | + font-size: 12px; | ||
| 183 | + height: 40px; | ||
| 184 | + > div { | ||
| 185 | + display: flex; | ||
| 186 | + flex-shrink: 0; | ||
| 187 | + margin-right: 12px; | ||
| 188 | + min-width: 0; | ||
| 189 | + > span { | ||
| 190 | + margin-left: 4px; | ||
| 191 | + } | ||
| 192 | + &:last-of-type { | ||
| 193 | + margin-right: 0; | ||
| 194 | + } | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + } | ||
| 198 | + &-body { | ||
| 199 | + box-sizing: border-box; | ||
| 200 | + height: v-bind(bodyHeight); | ||
| 201 | + min-height: v-bind(minBodyHeight); | ||
| 202 | + max-height: v-bind(maxBodyHeight); | ||
| 203 | + overflow: v-bind(hidden); | ||
| 204 | + background-color: var(--el-bg-color-og); | ||
| 205 | + border-radius: 0 0 8px 8px; | ||
| 206 | + will-change: height; | ||
| 207 | + > div { | ||
| 208 | + box-sizing: border-box; | ||
| 209 | + padding: v-bind(padding); | ||
| 210 | + height: v-bind(bodyHeight); | ||
| 211 | + } | ||
| 212 | + &.is-collapse { | ||
| 213 | + height: 0!important; | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | +} | ||
| 217 | +.hover { | ||
| 218 | + display: flex; | ||
| 219 | + align-items: center; | ||
| 220 | + > span { | ||
| 221 | + margin-left: 4px; | ||
| 222 | + } | ||
| 223 | +} | ||
| 224 | +.rect { | ||
| 225 | + width: 16px; | ||
| 226 | + height: 16px; | ||
| 227 | + flex-shrink: 0; | ||
| 228 | +} | ||
| 229 | +</style> | ||
| @@ -0,0 +1,103 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import dayjs from 'dayjs'; | ||
| 3 | +import utc from 'dayjs/plugin/utc'; | ||
| 4 | +import timezone from 'dayjs/plugin/timezone'; | ||
| 5 | + | ||
| 6 | +dayjs.extend(utc); | ||
| 7 | +dayjs.extend(timezone); | ||
| 8 | + | ||
| 9 | +interface ShortcutsConfigObj { | ||
| 10 | + text: string; | ||
| 11 | + value: number; | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +const props = withDefaults( | ||
| 15 | + defineProps<{ | ||
| 16 | + modelValue: any | any[]; | ||
| 17 | + type: any; | ||
| 18 | + showShortcuts?: boolean, | ||
| 19 | + startPlaceholder?: string; | ||
| 20 | + endPlaceholder?: string; | ||
| 21 | + valueFormatToISO?: boolean; // 是否处理为ISO8601 格式字符串 '2020-04-02T08:02:17-05:00' | ||
| 22 | + shortcutsConfig?: any[]; | ||
| 23 | + }>(), | ||
| 24 | + { | ||
| 25 | + startPlaceholder: '', | ||
| 26 | + endPlaceholder: '', | ||
| 27 | + showShortcuts: true, | ||
| 28 | + valueFormatToISO: false, | ||
| 29 | + shortcutsConfig: () => [] | ||
| 30 | + } | ||
| 31 | +); | ||
| 32 | +const myEmit = defineEmits<{ | ||
| 33 | + (event: 'change', value: any | any[]): void; | ||
| 34 | + (event: 'update:modelValue', value: any | any[]): void; | ||
| 35 | +}>(); | ||
| 36 | + | ||
| 37 | +const getShortcutsConfig = () => { | ||
| 38 | + const { showShortcuts, type, shortcutsConfig } = props; | ||
| 39 | + let shortcutsArr: any[] = []; | ||
| 40 | + if ((type === 'datetimerange' || type === 'daterange') && showShortcuts) { | ||
| 41 | + shortcutsConfig.forEach((item: ShortcutsConfigObj) => { | ||
| 42 | + shortcutsArr.push({ | ||
| 43 | + text: item.text, | ||
| 44 | + value: (() => { | ||
| 45 | + const end = new Date(); | ||
| 46 | + const start = new Date(); | ||
| 47 | + start.setTime(start.getTime() - 3600 * 1000 * item.value); | ||
| 48 | + return [start, end]; | ||
| 49 | + })() | ||
| 50 | + }) | ||
| 51 | + }) | ||
| 52 | + } | ||
| 53 | + return shortcutsArr; | ||
| 54 | +} | ||
| 55 | +const shortcuts = getShortcutsConfig(); | ||
| 56 | + | ||
| 57 | +const dateValue = computed({ | ||
| 58 | + get: () => props.modelValue, | ||
| 59 | + set: val => { | ||
| 60 | + let value; | ||
| 61 | + if (val && props.valueFormatToISO) { | ||
| 62 | + value = Array.isArray(val) ? val.map(item => dayjs(item).tz(dayjs.tz.guess()).format()) : dayjs(val).tz(dayjs.tz.guess()).format(); | ||
| 63 | + } else if (val && !props.valueFormatToISO) { | ||
| 64 | + let fmt: string; | ||
| 65 | + switch (props.type) { | ||
| 66 | + case 'date': | ||
| 67 | + case 'daterange': | ||
| 68 | + fmt = 'YYYY-MM-DD' | ||
| 69 | + break; | ||
| 70 | + case 'datetime': | ||
| 71 | + case 'datetimerange': | ||
| 72 | + fmt = 'YYYY-MM-DD HH:mm:ss'; | ||
| 73 | + break; | ||
| 74 | + case 'year': | ||
| 75 | + fmt = 'YYYY'; | ||
| 76 | + break; | ||
| 77 | + case 'month': | ||
| 78 | + fmt = 'YYYY-MM'; | ||
| 79 | + break; | ||
| 80 | + default: | ||
| 81 | + fmt = 'YYYY-MM-DD'; | ||
| 82 | + break; | ||
| 83 | + } | ||
| 84 | + value = Array.isArray(val) ? val.map(item => dayjs(item).format(fmt)) : dayjs(val).format(fmt); | ||
| 85 | + } else { | ||
| 86 | + value = Array.isArray(val) ? [] : null; | ||
| 87 | + } | ||
| 88 | + myEmit('update:modelValue', value); | ||
| 89 | + myEmit('change', value); | ||
| 90 | + } | ||
| 91 | +}) | ||
| 92 | +</script> | ||
| 93 | + | ||
| 94 | +<template> | ||
| 95 | + <el-date-picker | ||
| 96 | + v-bind="$attrs" | ||
| 97 | + v-model="dateValue" | ||
| 98 | + :type="type" | ||
| 99 | + :shortcuts="shortcuts" | ||
| 100 | + :start-placeholder="startPlaceholder" | ||
| 101 | + :end-placeholder="endPlaceholder" | ||
| 102 | + /> | ||
| 103 | +</template> | ||
| @@ -0,0 +1,306 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import * as echarts from "echarts/core"; | ||
| 3 | +import { | ||
| 4 | + GridComponent, | ||
| 5 | + GridComponentOption, | ||
| 6 | + TooltipComponent, | ||
| 7 | + TooltipComponentOption, | ||
| 8 | + ToolboxComponent, | ||
| 9 | + ToolboxComponentOption, | ||
| 10 | + BrushComponent, | ||
| 11 | + BrushComponentOption, | ||
| 12 | + TitleComponent, | ||
| 13 | + TitleComponentOption, | ||
| 14 | + DataZoomComponent, | ||
| 15 | + DataZoomComponentOption, | ||
| 16 | +} from "echarts/components"; | ||
| 17 | +import { LineChart, LineSeriesOption, ScatterChart, ScatterSeriesOption, BarChart, BarSeriesOption } from "echarts/charts"; | ||
| 18 | +import { UniversalTransition } from 'echarts/features'; | ||
| 19 | +import { CanvasRenderer } from "echarts/renderers"; | ||
| 20 | +import { uuid } from "../shared"; | ||
| 21 | +import { useEventListener, useIntersectionObserver } from "@vueuse/core"; | ||
| 22 | +import moment from "moment"; | ||
| 23 | +import { useI18n } from 'vue-i18n'; | ||
| 24 | +import { useDataZoom } from "../hooks/echarts"; | ||
| 25 | +import { storeToRefs } from "pinia"; | ||
| 26 | +import { useMonitorStore } from "../store/monitor"; | ||
| 27 | + | ||
| 28 | +export interface LineData { | ||
| 29 | + name: string, | ||
| 30 | + data: any[], | ||
| 31 | + [other: string]: any, | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +type EchartsOption = echarts.ComposeOption< | ||
| 35 | + GridComponentOption | TooltipComponentOption | LineSeriesOption | ScatterSeriesOption | | ||
| 36 | + ToolboxComponentOption | BrushComponentOption | TitleComponentOption | BarSeriesOption | | ||
| 37 | + DataZoomComponentOption | ||
| 38 | +> | ||
| 39 | +echarts.use([ | ||
| 40 | + CanvasRenderer, | ||
| 41 | + LineChart, | ||
| 42 | + UniversalTransition, | ||
| 43 | + GridComponent, | ||
| 44 | + TooltipComponent, | ||
| 45 | + ScatterChart, | ||
| 46 | + ToolboxComponent, | ||
| 47 | + BrushComponent, | ||
| 48 | + TitleComponent, | ||
| 49 | + BarChart, | ||
| 50 | + DataZoomComponent, | ||
| 51 | +]); | ||
| 52 | + | ||
| 53 | +const { t } = useI18n(); | ||
| 54 | + | ||
| 55 | +const props = withDefaults(defineProps<{ | ||
| 56 | + // xAxis Data | ||
| 57 | + xData?: string[], | ||
| 58 | + // yAxis Line Data | ||
| 59 | + data?: LineData[], | ||
| 60 | + unit?: string, | ||
| 61 | + scatterUnit?: string, | ||
| 62 | + // yAxis Scatter Data | ||
| 63 | + scatterData?: LineData, | ||
| 64 | + // LineChart use areaStyle | ||
| 65 | + areaStyle?: boolean, | ||
| 66 | + // chart colors | ||
| 67 | + color?: string[], | ||
| 68 | + theme?: 'dark' | 'light', | ||
| 69 | + /** | ||
| 70 | + * enable brush for select range time, the value is uuid | ||
| 71 | + */ | ||
| 72 | + brush?: string, | ||
| 73 | + /** | ||
| 74 | + * brush default select range | ||
| 75 | + */ | ||
| 76 | + defaultBrushArea?: string[], | ||
| 77 | + /** | ||
| 78 | + * bar chart | ||
| 79 | + */ | ||
| 80 | + bar?: boolean, | ||
| 81 | + stack?: boolean, | ||
| 82 | + enterable?: boolean, | ||
| 83 | + translate?: boolean, | ||
| 84 | + countByDataTimePicker: boolean, | ||
| 85 | + | ||
| 86 | +}>(), { | ||
| 87 | + xData: () => [], | ||
| 88 | + data: () => [], | ||
| 89 | + unit: '', | ||
| 90 | + scatterUnit: '', | ||
| 91 | + areaStyle: false, | ||
| 92 | + color: () => ['#37D4D1', '#00C7F9', '#0D86E2', '#425ADD', '#E64A19', '#9CCC65', '#A97526', '#2830FF', '#8B00E1', '#0F866A'], | ||
| 93 | + theme: 'dark', | ||
| 94 | + translate: true, | ||
| 95 | + countByDataTimePicker: true, | ||
| 96 | +}) | ||
| 97 | +const { brushRange, tab } = storeToRefs(useMonitorStore()) | ||
| 98 | +const domId = uuid(); | ||
| 99 | +let myChart: echarts.ECharts | ||
| 100 | +const renderChart = () => { | ||
| 101 | + let data: Array<LineSeriesOption | ScatterSeriesOption | BarSeriesOption> = []; | ||
| 102 | + props.data.forEach(d => { | ||
| 103 | + const o: Record<string, any> = { | ||
| 104 | + type: 'line', | ||
| 105 | + symbol: "none", | ||
| 106 | + yAxisIndex: 0, | ||
| 107 | + zlevel: 1, | ||
| 108 | + areaStyle: props.areaStyle ? {} : undefined, | ||
| 109 | + ...d, | ||
| 110 | + } | ||
| 111 | + if (props.bar) { | ||
| 112 | + o.type = 'bar' | ||
| 113 | + o['stack'] = 'total' | ||
| 114 | + o['barMaxWidth'] = 12 | ||
| 115 | + } | ||
| 116 | + if (props.stack) { | ||
| 117 | + o['stack'] = 'total' | ||
| 118 | + } | ||
| 119 | + data.push(o) | ||
| 120 | + }) | ||
| 121 | + if (props.scatterData) { | ||
| 122 | + data.push({ | ||
| 123 | + type: 'scatter', | ||
| 124 | + symbol: "circle", | ||
| 125 | + symbolSize: 6, | ||
| 126 | + yAxisIndex: 1, | ||
| 127 | + zlevel: 1, | ||
| 128 | + ...props.scatterData, | ||
| 129 | + }) | ||
| 130 | + } | ||
| 131 | + const chartDom = document.getElementById(domId); | ||
| 132 | + if (!myChart || myChart.isDisposed()) { | ||
| 133 | + myChart = echarts.init(chartDom!); | ||
| 134 | + } | ||
| 135 | + const option: EchartsOption = { | ||
| 136 | + title: { | ||
| 137 | + show: props.data?.length === 0 && (!props.scatterData || props.scatterData?.data?.length === 0), | ||
| 138 | + text: t('sql.isHasData'), | ||
| 139 | + left: 'center', | ||
| 140 | + top: 'center', | ||
| 141 | + textStyle: { | ||
| 142 | + color: props.theme === 'dark' ? '#ddd' : '#AEB3BC', | ||
| 143 | + } | ||
| 144 | + }, | ||
| 145 | + color: props.color, | ||
| 146 | + grid: { | ||
| 147 | + left: 15, | ||
| 148 | + right: 15, | ||
| 149 | + top: 25, | ||
| 150 | + bottom: 10, | ||
| 151 | + containLabel: true, | ||
| 152 | + }, | ||
| 153 | + tooltip: { | ||
| 154 | + trigger: 'axis', | ||
| 155 | + confine: true, | ||
| 156 | + enterable: props.enterable, | ||
| 157 | + backgroundColor: '#212121', | ||
| 158 | + borderColor: '#4a4a4a', | ||
| 159 | + formatter: params => { | ||
| 160 | + let str = `<div style="${props.enterable ? 'max-height: 155px;' : ''}overflow: auto;color: #D4D4D4">`; | ||
| 161 | + if (Array.isArray(params)) { | ||
| 162 | + params.forEach((p, i) => { | ||
| 163 | + const seriesName = props.translate ? t(`metric.${p.seriesName}`) : p.seriesName; | ||
| 164 | + if (i === 0) { | ||
| 165 | + str += p.name | ||
| 166 | + } | ||
| 167 | + str += `<div style="display: flex;justify-content: space-between;"><div style="margin-right: 24px;">${p.marker} ${seriesName} </div>${p.data}</div>` | ||
| 168 | + }) | ||
| 169 | + } else { | ||
| 170 | + const seriesName = props.translate ? t(`metric.${params.seriesName}`) : params.seriesName; | ||
| 171 | + str += `${params.name}<div style="display: flex;justify-content: space-between;"><div style="margin-right: 24px;">${params.marker} ${seriesName}</div>${params.data}</div>` | ||
| 172 | + } | ||
| 173 | + str += '</div>' | ||
| 174 | + return str | ||
| 175 | + } | ||
| 176 | + }, | ||
| 177 | + toolbox: { | ||
| 178 | + right: -1000, | ||
| 179 | + feature: { | ||
| 180 | + dataZoom: { yAxisIndex: false }, | ||
| 181 | + brush: { show: false } | ||
| 182 | + } | ||
| 183 | + }, | ||
| 184 | + brush: { | ||
| 185 | + brushStyle: { | ||
| 186 | + borderWidth: 0, | ||
| 187 | + color: props.theme === 'dark' ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)', | ||
| 188 | + }, | ||
| 189 | + transformable: !props.defaultBrushArea, | ||
| 190 | + outOfBrush: props.scatterData && props.defaultBrushArea && props.xData.length > 0 | ||
| 191 | + ? { | ||
| 192 | + color: props.scatterData.itemStyle.color | ||
| 193 | + } | ||
| 194 | + : undefined | ||
| 195 | + }, | ||
| 196 | + xAxis: { | ||
| 197 | + type: 'category', | ||
| 198 | + boundaryGap: false, | ||
| 199 | + axisTick: { show: false }, | ||
| 200 | + axisLine: { | ||
| 201 | + lineStyle: { | ||
| 202 | + color: props.theme === 'dark' ? '#D4D4D4' : '#e0e0e0' | ||
| 203 | + } | ||
| 204 | + }, | ||
| 205 | + axisLabel: { | ||
| 206 | + color: props.theme === 'dark' ? '#D4D4D4' : '#868F9C', | ||
| 207 | + formatter: v => moment(new Date(v)).format("HH:mm") | ||
| 208 | + }, | ||
| 209 | + data: props.xData, | ||
| 210 | + }, | ||
| 211 | + yAxis: props.scatterData | ||
| 212 | + ? [ | ||
| 213 | + { | ||
| 214 | + type: 'value', | ||
| 215 | + axisLabel: { | ||
| 216 | + color: props.theme === 'dark' ? '#D4D4D4' : '#868F9C', | ||
| 217 | + formatter: `{value}${props.unit}` | ||
| 218 | + }, | ||
| 219 | + splitLine: { | ||
| 220 | + lineStyle: { color: props.theme === 'dark' ? '#4a4a4a' : '#e0e0e0' } | ||
| 221 | + } | ||
| 222 | + }, | ||
| 223 | + { | ||
| 224 | + type: 'value', | ||
| 225 | + axisLabel: { | ||
| 226 | + color: props.theme === 'dark' ? '#D4D4D4' : '#868F9C', | ||
| 227 | + formatter: `{value}${props.scatterUnit}` | ||
| 228 | + }, | ||
| 229 | + splitLine: { show: false } | ||
| 230 | + } | ||
| 231 | + ] | ||
| 232 | + : { | ||
| 233 | + type: 'value', | ||
| 234 | + axisLabel: { | ||
| 235 | + color: props.theme === 'dark' ? '#D4D4D4' : '#868F9C', | ||
| 236 | + formatter: `{value}${props.unit}` | ||
| 237 | + }, | ||
| 238 | + splitLine: { | ||
| 239 | + lineStyle: { color: props.theme === 'dark' ? '#4a4a4a' : '#e0e0e0' } | ||
| 240 | + } | ||
| 241 | + }, | ||
| 242 | + series: data.length > 0 ? data : [] | ||
| 243 | + } | ||
| 244 | + myChart.setOption(option, true) | ||
| 245 | + if (!props.countByDataTimePicker && Array.isArray(props.defaultBrushArea) && props.defaultBrushArea.length === 2 && props.xData.length > 0) { | ||
| 246 | + console.log("defaultBrushArea", props.defaultBrushArea); | ||
| 247 | + nextTick(() => { | ||
| 248 | + let interval = (moment(props.defaultBrushArea![1]).valueOf() - moment(props.defaultBrushArea![0]).valueOf()) / 1000; | ||
| 249 | + const startIndexPosi = myChart.convertToPixel({ xAxisIndex: 0 }, 0); | ||
| 250 | + const endIndexPosi = myChart.convertToPixel({ xAxisIndex: 0 }, props.xData.length - 1); | ||
| 251 | + let range: any[] = []; | ||
| 252 | + if (interval <= 120) { | ||
| 253 | + const startIndex = props.xData?.length === 3 ? 1 : props.xData.indexOf(props.defaultBrushArea![0]) | ||
| 254 | + const r = myChart.convertToPixel({ xAxisIndex: 0 }, startIndex) | ||
| 255 | + const allWidth = endIndexPosi - startIndexPosi; | ||
| 256 | + const width = interval / 120 * allWidth; | ||
| 257 | + const start = Math.round(r - width / 2); | ||
| 258 | + const end = Math.round(r + width / 2); | ||
| 259 | + range = [start, end] | ||
| 260 | + } else { | ||
| 261 | + range = [startIndexPosi, endIndexPosi] | ||
| 262 | + } | ||
| 263 | + myChart.dispatchAction({ | ||
| 264 | + type: 'brush', | ||
| 265 | + areas: [ | ||
| 266 | + { | ||
| 267 | + brushType: 'lineX', | ||
| 268 | + range, | ||
| 269 | + } | ||
| 270 | + ] | ||
| 271 | + }) | ||
| 272 | + }) | ||
| 273 | + } | ||
| 274 | + if (props.brush) { | ||
| 275 | + useDataZoom(myChart) | ||
| 276 | + } | ||
| 277 | + if (brushRange.value.length > 0 && tab.value === 0) { | ||
| 278 | + myChart.dispatchAction({ type: 'dataZoom', start: 0, end: 100 }) | ||
| 279 | + } | ||
| 280 | +} | ||
| 281 | +// lazy load | ||
| 282 | +const myEmit = defineEmits<{ | ||
| 283 | + (event: 'load'): void, | ||
| 284 | +}>() | ||
| 285 | +const loadRef = ref<HTMLDivElement>() | ||
| 286 | +const { stop } = useIntersectionObserver( | ||
| 287 | + loadRef, | ||
| 288 | + ([{ isIntersecting }]) => { | ||
| 289 | + if (isIntersecting) { | ||
| 290 | + myEmit('load') | ||
| 291 | + nextTick(renderChart) | ||
| 292 | + stop() | ||
| 293 | + } | ||
| 294 | + } | ||
| 295 | +) | ||
| 296 | +watch(() => props.data, () => { | ||
| 297 | + nextTick(renderChart) | ||
| 298 | +}, { deep: true }) | ||
| 299 | +useEventListener(window, "resize", () => { | ||
| 300 | + myChart?.resize(); | ||
| 301 | +}); | ||
| 302 | +</script> | ||
| 303 | + | ||
| 304 | +<template> | ||
| 305 | +<div :id="domId" ref="loadRef" style="width: 100%; height: 100%;"></div> | ||
| 306 | +</template> | ||
| @@ -0,0 +1,71 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { WarningFilled, CircleCloseFilled } from '@element-plus/icons-vue' | ||
| 3 | + | ||
| 4 | +const props = withDefaults(defineProps<{ | ||
| 5 | + type: string; | ||
| 6 | + tip?: Error | undefined | string; | ||
| 7 | + defaultTip?: string; | ||
| 8 | +}>(), { | ||
| 9 | + type: 'info', | ||
| 10 | + tip: undefined, | ||
| 11 | + defaultTip: '', | ||
| 12 | +}) | ||
| 13 | + | ||
| 14 | +const baseColor = ref(''); | ||
| 15 | + | ||
| 16 | +const finalTip = ref<Error | undefined | string >(); | ||
| 17 | + | ||
| 18 | +onMounted(() => { | ||
| 19 | + switch (props.type) { | ||
| 20 | + case 'info': | ||
| 21 | + baseColor.value = '#0093FF'; | ||
| 22 | + break; | ||
| 23 | + case 'error': | ||
| 24 | + baseColor.value = '#ff4d4f99'; | ||
| 25 | + break; | ||
| 26 | + default: | ||
| 27 | + baseColor.value = '#FFF' | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + finalTip.value = props.tip !== undefined ? props.tip : props.defaultTip | ||
| 31 | +}) | ||
| 32 | + | ||
| 33 | +</script> | ||
| 34 | + | ||
| 35 | +<template> | ||
| 36 | + <div class="message-error"> | ||
| 37 | + <div class="message-error-info" :style="{ border: `1px solid ${baseColor}` }"> | ||
| 38 | + <el-icon :color="baseColor" size="18px" v-if="props.type === 'info'"> | ||
| 39 | + <WarningFilled /> | ||
| 40 | + </el-icon> | ||
| 41 | + <el-icon :color="baseColor" size="18px" v-if="props.type === 'error'"> | ||
| 42 | + <CircleCloseFilled /> | ||
| 43 | + </el-icon> | ||
| 44 | + <p> | ||
| 45 | + {{ finalTip }} | ||
| 46 | + </p> | ||
| 47 | + </div> | ||
| 48 | + </div> | ||
| 49 | +</template> | ||
| 50 | + | ||
| 51 | +<style scoped lang="scss"> | ||
| 52 | +.message-error { | ||
| 53 | + display: flex; | ||
| 54 | + justify-content: center; | ||
| 55 | + | ||
| 56 | + &-info { | ||
| 57 | + display: flex; | ||
| 58 | + align-items: center; | ||
| 59 | + max-width: 60%; | ||
| 60 | + padding: 4px 20px; | ||
| 61 | + border: 1px solid #0093FF; | ||
| 62 | + | ||
| 63 | + &>p { | ||
| 64 | + margin: 0 0 0 10px; | ||
| 65 | + line-height: 24px; | ||
| 66 | + color: var(--el-text-color-og); | ||
| 67 | + font-size: 12px; | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | +} | ||
| 71 | +</style> | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | +<template> | ||
| 2 | + <div class="operator"> | ||
| 3 | + <div class="left"><slot name="left" /></div> | ||
| 4 | + <div class="right"><slot name="right" /></div> | ||
| 5 | + </div> | ||
| 6 | +</template> | ||
| 7 | + | ||
| 8 | +<style scoped lang="scss"> | ||
| 9 | + .operator { | ||
| 10 | + display: flex; | ||
| 11 | + justify-content: space-between; | ||
| 12 | + align-items: center; | ||
| 13 | + margin-bottom: 16px; | ||
| 14 | + .left { | ||
| 15 | + display: flex; | ||
| 16 | + } | ||
| 17 | + .right { | ||
| 18 | + display: flex; | ||
| 19 | + justify-content: flex-end; | ||
| 20 | + gap: 12px; | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | +</style> | ||
| @@ -0,0 +1,178 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import * as echarts from 'echarts/core'; | ||
| 3 | +import { | ||
| 4 | + TooltipComponent, | ||
| 5 | + TooltipComponentOption, | ||
| 6 | + LegendComponent, | ||
| 7 | + LegendComponentOption, | ||
| 8 | + GridComponentOption, | ||
| 9 | + TitleComponent, | ||
| 10 | + TitleComponentOption | ||
| 11 | +} from 'echarts/components'; | ||
| 12 | +import { PieChart, PieSeriesOption } from 'echarts/charts'; | ||
| 13 | +import { LabelLayout } from 'echarts/features'; | ||
| 14 | +import { CanvasRenderer } from 'echarts/renderers'; | ||
| 15 | +import { uuid } from '../shared'; | ||
| 16 | +import { useDebounceFn, useEventListener, useIntersectionObserver } from '@vueuse/core'; | ||
| 17 | + | ||
| 18 | +echarts.use([ | ||
| 19 | + TooltipComponent, | ||
| 20 | + LegendComponent, | ||
| 21 | + PieChart, | ||
| 22 | + CanvasRenderer, | ||
| 23 | + LabelLayout, | ||
| 24 | + TitleComponent | ||
| 25 | +]); | ||
| 26 | + | ||
| 27 | +const colorArray: Array<string> = [ | ||
| 28 | + '#37D4D1', | ||
| 29 | + '#00C7F9', | ||
| 30 | + '#0D86E2', | ||
| 31 | + '#425ADD', | ||
| 32 | + '#8B00E1', | ||
| 33 | + '#9CCC65', | ||
| 34 | + '#A97526', | ||
| 35 | + '#2830FF', | ||
| 36 | + '#E64A19', | ||
| 37 | + '#0F866A', | ||
| 38 | + '#5CDF73', | ||
| 39 | + '#FEEC21' | ||
| 40 | +] | ||
| 41 | + | ||
| 42 | +type EChartsOption = echarts.ComposeOption< | ||
| 43 | + TooltipComponentOption | LegendComponentOption | PieSeriesOption | GridComponentOption | TitleComponentOption | ||
| 44 | +>; | ||
| 45 | + | ||
| 46 | +const props = withDefaults( | ||
| 47 | + defineProps<{ | ||
| 48 | + smooth?: boolean | ||
| 49 | + areaColor?: echarts.graphic.LinearGradient, | ||
| 50 | + radius?: [string, string] | ||
| 51 | + center?: [string, string] | ||
| 52 | + data: {value: number, name: string}[], | ||
| 53 | + text?: string, | ||
| 54 | + height?: string, | ||
| 55 | + showLegend?: boolean, | ||
| 56 | + color?: Array<string>, | ||
| 57 | + theme?: string | ||
| 58 | + }>(), | ||
| 59 | + { | ||
| 60 | + smooth: true, | ||
| 61 | + radius: () => ['50%', '70%'], | ||
| 62 | + center: () => ['30%', '50%'], | ||
| 63 | + data: () => [], | ||
| 64 | + text: '总数', | ||
| 65 | + height: '100px', | ||
| 66 | + showLegend: true, | ||
| 67 | + theme: 'dark' | ||
| 68 | + } | ||
| 69 | +); | ||
| 70 | + | ||
| 71 | +const domId = uuid() | ||
| 72 | +const percent2num = (percent: string) => Number.parseFloat(percent) / 100 | ||
| 73 | +const position = reactive({ left: '0', top: '0', lineLength: '0' }) | ||
| 74 | +const calcPosition = (chartDom: HTMLElement) => { | ||
| 75 | + const cs = getComputedStyle(chartDom.parentNode as Element) | ||
| 76 | + const paddingLeft = Number.parseFloat(cs.getPropertyValue('padding-left')) | ||
| 77 | + const paddingTop = Number.parseFloat(cs.getPropertyValue('padding-top')) | ||
| 78 | + const base = chartDom.offsetWidth > chartDom.offsetHeight ? chartDom.offsetHeight : chartDom.offsetWidth | ||
| 79 | + const radius = base * percent2num(props.radius[1]) * 0.5 | ||
| 80 | + position.left = chartDom.offsetWidth * percent2num(props.center[0]) - radius + paddingLeft + 'px' | ||
| 81 | + position.top = chartDom.offsetHeight * percent2num(props.center[1]) - radius + paddingTop + 'px' | ||
| 82 | + position.lineLength = radius * 2 + 'px' | ||
| 83 | +} | ||
| 84 | +const renderChart = () => { | ||
| 85 | + const chartDom = document.getElementById(domId); | ||
| 86 | + if (chartDom) { | ||
| 87 | + const instance = echarts.getInstanceByDom(chartDom) | ||
| 88 | + instance && instance.dispose() | ||
| 89 | + } | ||
| 90 | + const myChart = echarts.init(chartDom!); | ||
| 91 | + const option: EChartsOption = { | ||
| 92 | + legend: { | ||
| 93 | + show: props.showLegend, | ||
| 94 | + icon: "rect", | ||
| 95 | + type: "scroll", | ||
| 96 | + pageIconSize: 10, | ||
| 97 | + pageTextStyle: { | ||
| 98 | + fontSize: 10, | ||
| 99 | + }, | ||
| 100 | + textStyle: { | ||
| 101 | + color: '#D4D4D4' | ||
| 102 | + }, | ||
| 103 | + itemHeight: 10, | ||
| 104 | + itemGap: 10, | ||
| 105 | + orient: 'vertical', | ||
| 106 | + selectedMode: false, | ||
| 107 | + right: '10%', | ||
| 108 | + bottom: '5%', | ||
| 109 | + }, | ||
| 110 | + color: props.color ? props.color : colorArray, | ||
| 111 | + series: [ | ||
| 112 | + { | ||
| 113 | + name: 'dbtypes', | ||
| 114 | + type: 'pie', | ||
| 115 | + radius: props.radius, | ||
| 116 | + center: props.center, | ||
| 117 | + avoidLabelOverlap: true, | ||
| 118 | + label: { | ||
| 119 | + show: false | ||
| 120 | + }, | ||
| 121 | + itemStyle: { | ||
| 122 | + borderColor: props.theme === 'dark' ? '#4A4A4A' : '#fff', | ||
| 123 | + borderWidth: 1 | ||
| 124 | + }, | ||
| 125 | + minAngle: 10, | ||
| 126 | + data: props.data | ||
| 127 | + } | ||
| 128 | + ] | ||
| 129 | + }; | ||
| 130 | + myChart.setOption(option); | ||
| 131 | +} | ||
| 132 | +// lazy load | ||
| 133 | +const loadRef = ref<HTMLDivElement>() | ||
| 134 | +const { stop } = useIntersectionObserver( | ||
| 135 | + loadRef, | ||
| 136 | + ([{ isIntersecting }]) => { | ||
| 137 | + if (isIntersecting) { | ||
| 138 | + nextTick(renderChart) | ||
| 139 | + stop() | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | +) | ||
| 143 | +watch(() => props.data, () => { | ||
| 144 | + nextTick(renderChart) | ||
| 145 | +}, { deep: true }) | ||
| 146 | + | ||
| 147 | +useEventListener(window, 'resize', useDebounceFn(() => { | ||
| 148 | + const chartDom = document.getElementById(domId); | ||
| 149 | + if (chartDom) { | ||
| 150 | + const instance = echarts.getInstanceByDom(chartDom) | ||
| 151 | + instance && instance.resize() | ||
| 152 | + calcPosition(chartDom) | ||
| 153 | + } | ||
| 154 | +}, 500)) | ||
| 155 | +</script> | ||
| 156 | + | ||
| 157 | +<template> | ||
| 158 | +<div ref="loadRef" :id="domId" style="width: 100%; height: 100%;position: relative;"></div> | ||
| 159 | +<!-- <div class="text"> | ||
| 160 | + <div style="font-size: 20px;">{{ props.data.reduce((acc, cur) => acc + cur.value, 0) }}</div> | ||
| 161 | + <div style="font-size: 12px;">{{ props.text }}</div> | ||
| 162 | +</div> --> | ||
| 163 | +</template> | ||
| 164 | + | ||
| 165 | +<style scoped> | ||
| 166 | +.text { | ||
| 167 | + position: relative; | ||
| 168 | + left: v-bind('position.left'); | ||
| 169 | + top: v-bind('position.top'); | ||
| 170 | + width: v-bind('position.lineLength'); | ||
| 171 | + height: v-bind('position.lineLength'); | ||
| 172 | + text-align: center; | ||
| 173 | + display: flex; | ||
| 174 | + flex-direction: column; | ||
| 175 | + justify-content: center; | ||
| 176 | + align-items: center; | ||
| 177 | +} | ||
| 178 | +</style> | ||
| @@ -0,0 +1,146 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | + | ||
| 3 | +type optionType = { label: string, value: number, total?: boolean, color?: string, hide?: boolean } | ||
| 4 | + | ||
| 5 | +const props = withDefaults(defineProps<{ | ||
| 6 | + data: Array<optionType>; | ||
| 7 | + width?: string; | ||
| 8 | + height?: string; | ||
| 9 | + text?: string; | ||
| 10 | + onlyOne?: boolean | ||
| 11 | + fixTotal?: number | ||
| 12 | + fixColor?: string[] | ||
| 13 | +}>(), { | ||
| 14 | + width: '70%', | ||
| 15 | + height: '15px', | ||
| 16 | + onlyOne: false, | ||
| 17 | +}); | ||
| 18 | + | ||
| 19 | +const progressData = reactive<{ | ||
| 20 | + line: Array<{ percentage: string, backgroundColor: string }> | ||
| 21 | + isHasTotal: boolean, | ||
| 22 | + totalBackgroundColor: string, | ||
| 23 | + contentData: Array<optionType> | ||
| 24 | +}>({ | ||
| 25 | + line: [], | ||
| 26 | + isHasTotal: false, | ||
| 27 | + totalBackgroundColor: '', | ||
| 28 | + contentData: [] | ||
| 29 | +}); | ||
| 30 | + | ||
| 31 | +onMounted(() => { | ||
| 32 | + let curTotal = 0; | ||
| 33 | + let isHasTotal = false; | ||
| 34 | + props.data.forEach(item => { | ||
| 35 | + if (item.total) { | ||
| 36 | + isHasTotal = true; | ||
| 37 | + progressData.isHasTotal = true; | ||
| 38 | + curTotal = item.value | ||
| 39 | + } | ||
| 40 | + }); | ||
| 41 | + | ||
| 42 | + let tempProgressData = props.data; | ||
| 43 | + if (!isHasTotal) { | ||
| 44 | + curTotal = props.data.reduce((sum: number, item: optionType) => sum + item.value, 0); | ||
| 45 | + } else { | ||
| 46 | + tempProgressData = props.data.filter((item) => { | ||
| 47 | + if (item.total) { | ||
| 48 | + progressData.isHasTotal = true; | ||
| 49 | + progressData.totalBackgroundColor = item.color || ''; | ||
| 50 | + return false; | ||
| 51 | + } | ||
| 52 | + return true | ||
| 53 | + }); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + progressData.line = tempProgressData.map((item) => { | ||
| 57 | + const percentage = `${(item.value / curTotal * 100).toFixed(2)}%`; | ||
| 58 | + return { | ||
| 59 | + percentage, | ||
| 60 | + backgroundColor: item.color || '' | ||
| 61 | + } | ||
| 62 | + }) | ||
| 63 | + | ||
| 64 | + progressData.contentData = props.onlyOne ? [props.data[0]] : props.data; | ||
| 65 | +}); | ||
| 66 | + | ||
| 67 | +</script> | ||
| 68 | + | ||
| 69 | +<template> | ||
| 70 | + <div class="my-progress" :style="{ height: props.height, width: props.width }"> | ||
| 71 | + <el-tooltip | ||
| 72 | + effect="light" | ||
| 73 | + placement="right" | ||
| 74 | + > | ||
| 75 | + <template #content> | ||
| 76 | + <div class="my-progress-content" v-for="(item, index) in progressData.contentData" :key="index"> | ||
| 77 | + <div class="my-progress-content-item" v-show="!item.hide"> | ||
| 78 | + <div | ||
| 79 | + class="my-progress-content-legend" | ||
| 80 | + :style="{ | ||
| 81 | + backgroundColor: props.fixColor ? props.fixColor[index] : item.color | ||
| 82 | + }" | ||
| 83 | + /> | ||
| 84 | + <div class="my-progress-content-label">{{ item.label }}</div> | ||
| 85 | + </div> | ||
| 86 | + <p class="my-progress-content-label" v-show="!item.hide">{{ index === 1 ? props.fixTotal || item.value : item.value }}</p> | ||
| 87 | + </div> | ||
| 88 | + </template> | ||
| 89 | + <div | ||
| 90 | + class="my-progress-line" | ||
| 91 | + :style="{ | ||
| 92 | + backgroundColor: progressData.isHasTotal ? progressData.totalBackgroundColor : 'transparent' | ||
| 93 | + }" | ||
| 94 | + > | ||
| 95 | + <div | ||
| 96 | + v-for="(item, index) in progressData.line" | ||
| 97 | + :key="index" | ||
| 98 | + :style="{ | ||
| 99 | + height: props.height, | ||
| 100 | + width: item.percentage, | ||
| 101 | + backgroundColor: item.backgroundColor | ||
| 102 | + }" | ||
| 103 | + /> | ||
| 104 | + </div> | ||
| 105 | + </el-tooltip> | ||
| 106 | + <div class="my-progress-text" v-if="props.text !== undefined">{{ props.text }}</div> | ||
| 107 | + </div> | ||
| 108 | +</template> | ||
| 109 | + | ||
| 110 | +<style scoped lang="scss"> | ||
| 111 | +.my-progress { | ||
| 112 | + width: 100%; | ||
| 113 | + | ||
| 114 | + &-line { | ||
| 115 | + width: 80%; | ||
| 116 | + display: flex; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + &-content { | ||
| 120 | + display: flex; | ||
| 121 | + align-items: center; | ||
| 122 | + justify-content: space-between; | ||
| 123 | + width: 160px; | ||
| 124 | + | ||
| 125 | + &-item { | ||
| 126 | + display: flex; | ||
| 127 | + align-items: center; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + &-legend { | ||
| 131 | + width: 16px; | ||
| 132 | + height: 4px; | ||
| 133 | + margin-right: 6px; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + &-label { | ||
| 137 | + font-size: 12px; | ||
| 138 | + color: #D4D4D4; | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + &-text { | ||
| 143 | + font-size: 12px; | ||
| 144 | + } | ||
| 145 | +} | ||
| 146 | +</style> | ||
| @@ -0,0 +1,149 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { useDebounceFn, useEventListener } from "@vueuse/core"; | ||
| 3 | +import { ElTable } from "element-plus"; | ||
| 4 | +import { useRequest } from "vue-request"; | ||
| 5 | +import ogRequest from "../request"; | ||
| 6 | + | ||
| 7 | +const props = withDefaults( | ||
| 8 | + defineProps<{ | ||
| 9 | + api: string; | ||
| 10 | + post?: boolean; | ||
| 11 | + maxHeight?: string | number; | ||
| 12 | + extra?: Record<string, any>; | ||
| 13 | + flag?: boolean; | ||
| 14 | + formatter?: (d: any) => void; | ||
| 15 | + frontPagination?: boolean | ||
| 16 | + }>(), | ||
| 17 | + {} | ||
| 18 | +); | ||
| 19 | + | ||
| 20 | +const state = reactive({ | ||
| 21 | + data: [] as any[], | ||
| 22 | + total: 0, | ||
| 23 | + page: 1, | ||
| 24 | + size: 10, | ||
| 25 | +}); | ||
| 26 | +const maxHeight = ref(props.maxHeight || 500); | ||
| 27 | + | ||
| 28 | +const myEmit = defineEmits<{(event: 'load-data', data: unknown[]): void}>() | ||
| 29 | +const multipleTableRef = ref<InstanceType<typeof ElTable>>() | ||
| 30 | +const toggleRowSelection = (row: any, selected: boolean, prop: string) => { | ||
| 31 | + nextTick(() => { | ||
| 32 | + multipleTableRef.value!.toggleRowSelection(state.data.find(d => d[prop] === row[prop]), selected) | ||
| 33 | + }) | ||
| 34 | +} | ||
| 35 | +defineExpose({ toggleRowSelection }) | ||
| 36 | + | ||
| 37 | +interface TableData { | ||
| 38 | + list: any[], | ||
| 39 | + total: number, | ||
| 40 | +} | ||
| 41 | +const { run, data } = useRequest(() => { | ||
| 42 | + const payload = { | ||
| 43 | + page: state.page, | ||
| 44 | + pageSize: state.size, | ||
| 45 | + ...(props.extra || {}), | ||
| 46 | + sortKey: sortKey.value, | ||
| 47 | + sortOrder: sortOrder.value, | ||
| 48 | + } | ||
| 49 | + if (props.post) { | ||
| 50 | + return ogRequest.post<TableData>(props.api, payload) | ||
| 51 | + } else { | ||
| 52 | + return ogRequest.get<TableData>(props.api, payload) | ||
| 53 | + } | ||
| 54 | +}, { manual: true, debounceInterval: 200 }); | ||
| 55 | +watch(data, d => { | ||
| 56 | + state.data = d?.list.map(item => { | ||
| 57 | + if (props.formatter) { | ||
| 58 | + props.formatter(item) | ||
| 59 | + } | ||
| 60 | + const r = { ...item } | ||
| 61 | + if (r.children && Array.isArray(r.children)) { | ||
| 62 | + r["__vem_id"] = Math.random().toString(36).slice(2); | ||
| 63 | + r.children.forEach( | ||
| 64 | + (c: any) => | ||
| 65 | + (c["__vem_id"] = Math.random().toString(36).slice(2)) | ||
| 66 | + ); | ||
| 67 | + } | ||
| 68 | + return r; | ||
| 69 | + })!; | ||
| 70 | + state.total = d?.total!; | ||
| 71 | + myEmit('load-data', d?.list || []) | ||
| 72 | +}) | ||
| 73 | +const top = ref(0); | ||
| 74 | +useEventListener( | ||
| 75 | + window, | ||
| 76 | + "resize", | ||
| 77 | + useDebounceFn( | ||
| 78 | + () => (maxHeight.value = document.body.clientHeight - top.value - 60), | ||
| 79 | + 500 | ||
| 80 | + ) | ||
| 81 | +); | ||
| 82 | +onMounted(() => { | ||
| 83 | + if (!props.maxHeight) { | ||
| 84 | + const topRect = document | ||
| 85 | + .querySelector(".z-table") | ||
| 86 | + ?.getBoundingClientRect() as DOMRect; | ||
| 87 | + top.value = topRect.top; | ||
| 88 | + maxHeight.value = document.body.clientHeight - topRect.top - 60; | ||
| 89 | + state.size = Math.max(Number.parseInt(`${maxHeight.value / 32}`) - 1, 10) | ||
| 90 | + } | ||
| 91 | + run(); | ||
| 92 | +}); | ||
| 93 | +if (!props.frontPagination) { | ||
| 94 | + watch(() => state.page, run); | ||
| 95 | + if (props.extra) { | ||
| 96 | + watch(() => props.extra, run, { deep: true }); | ||
| 97 | + } | ||
| 98 | + watch(() => props.flag, run); | ||
| 99 | +} | ||
| 100 | +const _data = computed(() => { | ||
| 101 | + if (!props.frontPagination) { | ||
| 102 | + return state.data | ||
| 103 | + } | ||
| 104 | + return state.data.filter((d, i) => i >= (state.page - 1) * state.size && i < state.page * state.size) | ||
| 105 | +}) | ||
| 106 | + | ||
| 107 | +// sort | ||
| 108 | +const sortKey = ref('') | ||
| 109 | +const sortOrder = ref('') | ||
| 110 | +const handleSortChange = (cell: {prop: string | null, order: 'ascending' | 'descending' | null}) => { | ||
| 111 | + sortKey.value = cell.prop || '' | ||
| 112 | + sortOrder.value = cell.order || '' | ||
| 113 | + run() | ||
| 114 | +} | ||
| 115 | +</script> | ||
| 116 | + | ||
| 117 | +<template> | ||
| 118 | +<el-table | ||
| 119 | + ref="multipleTableRef" | ||
| 120 | + v-bind="$attrs" | ||
| 121 | + class="z-table" | ||
| 122 | + :data="_data" | ||
| 123 | + :max-height="maxHeight" | ||
| 124 | + :style="{ 'max-height': `${maxHeight}px` }" | ||
| 125 | + row-key="__vem_id" | ||
| 126 | + border | ||
| 127 | + @sort-change="handleSortChange" | ||
| 128 | +> | ||
| 129 | + <slot /> | ||
| 130 | +</el-table> | ||
| 131 | +<el-pagination | ||
| 132 | + v-model:currentPage="state.page" | ||
| 133 | + v-model:pageSize="state.size" | ||
| 134 | + :total="state.total" | ||
| 135 | + class="pagination" | ||
| 136 | + layout="total,prev,pager,next" | ||
| 137 | + hide-on-single-page | ||
| 138 | + background | ||
| 139 | + small | ||
| 140 | +/> | ||
| 141 | +</template> | ||
| 142 | + | ||
| 143 | +<style scoped> | ||
| 144 | +.pagination { | ||
| 145 | + margin-top: 16px; | ||
| 146 | + display: flex; | ||
| 147 | + justify-content: flex-end; | ||
| 148 | +} | ||
| 149 | +</style> | ||
| @@ -0,0 +1,54 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-select v-model="machineValue" @change="selectMachine" :clearable="!notClearable" :style="{ width: width ? width + 'px' : 'auto' }"> | ||
| 4 | + <el-option v-for="item in machineList" :key="item.hostId" :label="item.privateIp + '(' + item.publicIp + ')'" :value="item.hostId" /> | ||
| 5 | + </el-select> | ||
| 6 | + </div> | ||
| 7 | +</template> | ||
| 8 | + | ||
| 9 | +<script lang="ts" setup> | ||
| 10 | +import ogRequest from "../request"; | ||
| 11 | +import { useRequest } from "vue-request"; | ||
| 12 | + | ||
| 13 | +const props = withDefaults( | ||
| 14 | + defineProps<{ | ||
| 15 | + width?: string; | ||
| 16 | + notClearable?: boolean; | ||
| 17 | + autoSelectFirst?: boolean; | ||
| 18 | + }>(), | ||
| 19 | + { | ||
| 20 | + width: "", | ||
| 21 | + notClearable: false, | ||
| 22 | + autoSelectFirst: false, | ||
| 23 | + } | ||
| 24 | +); | ||
| 25 | +const emit = defineEmits(["change", "loaded"]); | ||
| 26 | + | ||
| 27 | +const machineValue = ref<any>(); | ||
| 28 | +const machineList = ref<Array<any>>([]); | ||
| 29 | + | ||
| 30 | +const selectMachine = (val: string[]) => { | ||
| 31 | + emit("change", machineValue); | ||
| 32 | +}; | ||
| 33 | + | ||
| 34 | +onMounted(() => { | ||
| 35 | + clusterData(); | ||
| 36 | +}); | ||
| 37 | +const { data: rer, run: clusterData } = useRequest( | ||
| 38 | + () => { | ||
| 39 | + return ogRequest.get("/observability/v1/environment/prometheus", ""); | ||
| 40 | + }, | ||
| 41 | + { manual: true } | ||
| 42 | +); | ||
| 43 | + | ||
| 44 | +watch(rer, (rer) => { | ||
| 45 | + if (rer && rer.data && Object.keys(rer.data).length) { | ||
| 46 | + machineList.value = rer.data.rows; | ||
| 47 | + emit("loaded"); | ||
| 48 | + if (props.autoSelectFirst && machineList.value.length > 0) { | ||
| 49 | + machineValue.value = machineList.value[0].hostId; | ||
| 50 | + emit("change", machineValue.value); | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | +}); | ||
| 54 | +</script> | ||
| @@ -0,0 +1,31 @@ | |||
| 1 | +<template> | ||
| 2 | + <svg | ||
| 3 | + aria-hidden="true" | ||
| 4 | + style="vertical-align: middle; cursor: pointer;" | ||
| 5 | + :class="$style.icon" | ||
| 6 | + :fill="color" | ||
| 7 | + > | ||
| 8 | + <use :href="symbolId" /> | ||
| 9 | + </svg> | ||
| 10 | +</template> | ||
| 11 | + | ||
| 12 | +<script setup lang="ts"> | ||
| 13 | +const props = withDefaults( | ||
| 14 | + defineProps<{ | ||
| 15 | + prefix?: string; | ||
| 16 | + name: string; | ||
| 17 | + color?: string; | ||
| 18 | + }>(), | ||
| 19 | + { | ||
| 20 | + prefix: "icon", | ||
| 21 | + } | ||
| 22 | +); | ||
| 23 | +const symbolId = computed(() => `#${props.prefix}-${props.name}`); | ||
| 24 | +</script> | ||
| 25 | + | ||
| 26 | +<style scoped module> | ||
| 27 | +.icon { | ||
| 28 | + width: 14px; | ||
| 29 | + height: 14px; | ||
| 30 | +} | ||
| 31 | +</style> | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +const props = withDefaults( | ||
| 3 | + defineProps<{ | ||
| 4 | + content: string | ||
| 5 | + id: string | ||
| 6 | + resolve:() => void | ||
| 7 | + }>(), | ||
| 8 | + {} | ||
| 9 | +); | ||
| 10 | +const visible = ref(true) | ||
| 11 | +const close = () => document.getElementById(props.id)?.remove() | ||
| 12 | +const confirm = () => { | ||
| 13 | + props.resolve() | ||
| 14 | + visible.value = false | ||
| 15 | +} | ||
| 16 | +</script> | ||
| 17 | + | ||
| 18 | +<template> | ||
| 19 | +<el-dialog | ||
| 20 | + :width="400" | ||
| 21 | + v-model="visible" | ||
| 22 | + :close-on-click-modal="false" | ||
| 23 | + custom-class="del-dialog" | ||
| 24 | + center | ||
| 25 | + draggable | ||
| 26 | + @close="close" | ||
| 27 | +> | ||
| 28 | + <template #header></template> | ||
| 29 | + <div class="del-text">确认删除</div> | ||
| 30 | + <div class="content-text">{{props.content}}</div> | ||
| 31 | + <template #footer> | ||
| 32 | + <el-button style="padding: 5px 20px;" type="primary" @click="confirm">确定</el-button> | ||
| 33 | + <el-button style="padding: 5px 20px;" @click="() => visible = false">取消</el-button> | ||
| 34 | + </template> | ||
| 35 | +</el-dialog> | ||
| 36 | +</template> | ||
| 37 | + | ||
| 38 | +<style> | ||
| 39 | +.del-dialog .el-dialog__header { | ||
| 40 | + display: none; | ||
| 41 | +} | ||
| 42 | +</style> | ||
| 43 | +<style scoped> | ||
| 44 | +.del-text { | ||
| 45 | + text-align: center; | ||
| 46 | + font-weight: bold; | ||
| 47 | + font-size: 16px; | ||
| 48 | + margin-bottom: 20px; | ||
| 49 | +} | ||
| 50 | +.content-text { | ||
| 51 | + text-align: center; | ||
| 52 | +} | ||
| 53 | +</style> | ||
| @@ -0,0 +1,120 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +const props = withDefaults( | ||
| 3 | + defineProps<{ | ||
| 4 | + id: string | ||
| 5 | + resolve:(value: unknown[]) => void | ||
| 6 | + api: string | ||
| 7 | + post?: boolean | ||
| 8 | + width?: number | ||
| 9 | + title?: string | ||
| 10 | + filter?: any | ||
| 11 | + selections?: unknown[] | ||
| 12 | + uid: string | ||
| 13 | + type: 'radio' | 'selection' | ||
| 14 | + }>(), | ||
| 15 | + { | ||
| 16 | + width: 700, | ||
| 17 | + title: '选择项', | ||
| 18 | + post: false, | ||
| 19 | + type: 'radio', | ||
| 20 | + selections: () => ([]) | ||
| 21 | + } | ||
| 22 | +); | ||
| 23 | + | ||
| 24 | +const multipleTableRef = ref() | ||
| 25 | +let cacheData: string[] = [] | ||
| 26 | +let cacheList: unknown[] = [] | ||
| 27 | +const loadData = (data: unknown[]) => { | ||
| 28 | + cacheList = data | ||
| 29 | + cacheData = data.map((d: any) => d[props.uid]) | ||
| 30 | + selections.value.forEach((s: any) => { | ||
| 31 | + if (cacheData.includes(s[props.uid])) { | ||
| 32 | + multipleTableRef.value!.toggleRowSelection(s, true, props.uid) | ||
| 33 | + } | ||
| 34 | + }) | ||
| 35 | +} | ||
| 36 | +const selections = ref<unknown[]>(props.selections) | ||
| 37 | +const selectionChange = (rows: unknown[]) => { | ||
| 38 | + const dbids = selections.value.map((s: any) => s[props.uid]) | ||
| 39 | + const selectedDbids: string[] = [] | ||
| 40 | + rows.forEach((r: any) => { | ||
| 41 | + selectedDbids.push(r[props.uid]) | ||
| 42 | + if (!dbids.includes(r[props.uid])) { | ||
| 43 | + selections.value.push(r) | ||
| 44 | + } | ||
| 45 | + }) | ||
| 46 | + const removeDbids = cacheData.filter(key => !selectedDbids.includes(key)) | ||
| 47 | + selections.value = selections.value.filter((s: any) => !removeDbids.includes(s[props.uid])) | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +const radio = ref('') | ||
| 51 | + | ||
| 52 | +const visible = ref(true) | ||
| 53 | +const close = () => document.getElementById(props.id)?.remove() | ||
| 54 | +const confirm = () => { | ||
| 55 | + if (props.type === 'selection') { | ||
| 56 | + props.resolve(selections.value) | ||
| 57 | + } else { | ||
| 58 | + props.resolve([cacheList.find((l: any) => l[props.uid] === radio.value)]) | ||
| 59 | + } | ||
| 60 | + visible.value = false | ||
| 61 | +} | ||
| 62 | +</script> | ||
| 63 | + | ||
| 64 | +<template> | ||
| 65 | +<el-dialog | ||
| 66 | + :width="$props.width" | ||
| 67 | + :title="$props.title" | ||
| 68 | + v-model="visible" | ||
| 69 | + custom-class="nodes-dialog" | ||
| 70 | + :close-on-click-modal="false" | ||
| 71 | + draggable | ||
| 72 | + @close="close" | ||
| 73 | +> | ||
| 74 | + <div class="flex-end" style="margin-bottom: 10px;"> | ||
| 75 | + <slot></slot> | ||
| 76 | + </div> | ||
| 77 | + <my-table | ||
| 78 | + ref="multipleTableRef" | ||
| 79 | + :api="$props.api" | ||
| 80 | + :max-height="360" | ||
| 81 | + :extra="$props.filter" | ||
| 82 | + @selection-change="selectionChange" | ||
| 83 | + @load-data="loadData" | ||
| 84 | + :post="$props.post" | ||
| 85 | + > | ||
| 86 | + <el-table-column v-if="$props.type === 'radio'" width="50" align="center"> | ||
| 87 | + <template #default="{row}"> | ||
| 88 | + <el-radio v-model="radio" :label="row[$props.uid]"></el-radio> | ||
| 89 | + </template> | ||
| 90 | + </el-table-column> | ||
| 91 | + <el-table-column v-if="$props.type === 'selection'" width="50" align="center" type="selection"></el-table-column> | ||
| 92 | + <slot name="column"></slot> | ||
| 93 | + </my-table> | ||
| 94 | + <template #footer> | ||
| 95 | + <el-button style="padding: 5px 20px;" @click="() => visible = false">取消</el-button> | ||
| 96 | + <el-button style="padding: 5px 20px;" type="primary" @click="confirm">确定</el-button> | ||
| 97 | + </template> | ||
| 98 | +</el-dialog> | ||
| 99 | +</template> | ||
| 100 | + | ||
| 101 | +<style> | ||
| 102 | +.nodes-dialog .el-dialog__footer { | ||
| 103 | + border-top: 1px solid #eee; | ||
| 104 | + padding-bottom: 10px; | ||
| 105 | +} | ||
| 106 | +.nodes-dialog .el-dialog__header { | ||
| 107 | + border-bottom: 1px solid #eee; | ||
| 108 | + margin-right: 0px; | ||
| 109 | + padding-top: 10px; | ||
| 110 | +} | ||
| 111 | +.nodes-dialog .el-dialog__header .el-dialog__title { | ||
| 112 | + font-size: 14px; | ||
| 113 | +} | ||
| 114 | +.nodes-dialog .el-dialog__headerbtn { | ||
| 115 | + top: -2px; | ||
| 116 | +} | ||
| 117 | +.nodes-dialog .el-radio .el-radio__label { | ||
| 118 | + display: none; | ||
| 119 | +} | ||
| 120 | +</style> | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +import { uuid } from "../shared"; | ||
| 2 | +import DelModalVue from "./DelModal.vue"; | ||
| 3 | + | ||
| 4 | +/** | ||
| 5 | + * delete comfirm | ||
| 6 | + * content delete tip | ||
| 7 | + * void | ||
| 8 | + */ | ||
| 9 | +export const useDelConfirm = (content: string) => { | ||
| 10 | + return new Promise((resolve) => { | ||
| 11 | + const el = document.createElement('div'); | ||
| 12 | + el.id = 'del_' + uuid() | ||
| 13 | + document.body.appendChild(el) | ||
| 14 | + createApp(DelModalVue, { id: el.id, resolve, content }).mount(`#${el.id}`) | ||
| 15 | + }) | ||
| 16 | +} | ||
| @@ -0,0 +1,46 @@ | |||
| 1 | +import { useEventListener } from "@vueuse/core"; | ||
| 2 | +import { Ref } from "vue"; | ||
| 3 | + | ||
| 4 | +/** | ||
| 5 | + * is dom element overflow | ||
| 6 | + * targetRef Ref<dom> | ||
| 7 | + * dropdownRef element-plus dropdownRef | ||
| 8 | + * is overflow | ||
| 9 | + */ | ||
| 10 | +export const useWidthOverflow = (targetRef: Ref<HTMLElement>, dropdownRef: Ref<any>) => { | ||
| 11 | + const overflow = ref(false) | ||
| 12 | + const isFinish = ref(false) | ||
| 13 | + const stopWatch = watch(targetRef, t => { | ||
| 14 | + if (t) { | ||
| 15 | + overflow.value = t.scrollWidth > t.offsetWidth | ||
| 16 | + isFinish.value = true | ||
| 17 | + useEventListener(t, 'mouseenter', (e: MouseEvent) => { | ||
| 18 | + if (dropdownRef && dropdownRef.value) { | ||
| 19 | + // const l = t.getBoundingClientRect().left - document.querySelector('#app')!.getBoundingClientRect().left | ||
| 20 | + // dropdownRef.value.$el.style.left = e.pageX - l + 'px' | ||
| 21 | + dropdownRef.value.$el.style.left = '300px' | ||
| 22 | + if (overflow.value) { | ||
| 23 | + dropdownRef.value.handleOpen() | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | + }) | ||
| 27 | + useEventListener(t, 'mouseleave', (e: MouseEvent) => { | ||
| 28 | + if (dropdownRef && dropdownRef.value) { | ||
| 29 | + dropdownRef.value.handleClose() | ||
| 30 | + } | ||
| 31 | + }) | ||
| 32 | + stopWatch() | ||
| 33 | + } | ||
| 34 | + }, { immediate: true }) | ||
| 35 | + const trigger = () => { | ||
| 36 | + isFinish.value = false | ||
| 37 | + overflow.value = false | ||
| 38 | + if (targetRef && targetRef.value) { | ||
| 39 | + targetRef.value.style.justifyContent = 'flex-start'; | ||
| 40 | + overflow.value = targetRef.value.scrollWidth > targetRef.value.offsetWidth | ||
| 41 | + isFinish.value = true | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | + useEventListener(window, 'resize', trigger) | ||
| 45 | + return { overflow, isFinish, trigger } | ||
| 46 | +} | ||
| @@ -0,0 +1,133 @@ | |||
| 1 | +import { EChartsOption } from "echarts"; | ||
| 2 | +import { ECharts } from "echarts/core"; | ||
| 3 | +import { Ref } from "vue"; | ||
| 4 | +import { useMonitorStore } from "../store/monitor"; | ||
| 5 | + | ||
| 6 | +type XAxisType = EChartsOption['XAXisOption'] & { data: string[] } | ||
| 7 | + | ||
| 8 | +const monitorStore = useMonitorStore() | ||
| 9 | + | ||
| 10 | +export const brushMap = reactive<Record<string, any>>({}) | ||
| 11 | +const toggleBrush = (brushType: string | boolean, uuid: string) => { | ||
| 12 | + brushMap[uuid]['chart']?.dispatchAction({ | ||
| 13 | + type: 'takeGlobalCursor', | ||
| 14 | + key: 'brush', | ||
| 15 | + brushOption: { | ||
| 16 | + brushType, | ||
| 17 | + } | ||
| 18 | + }) | ||
| 19 | + brushMap[uuid]['range'].start = '' | ||
| 20 | + brushMap[uuid]['range'].end = '' | ||
| 21 | +} | ||
| 22 | +const addBrushEvent = (uuid: string) => { | ||
| 23 | + const ev = (params: any) => { | ||
| 24 | + if (brushMap[uuid]['chart']?.containPixel('grid', [params.offsetX, params.offsetY])) { | ||
| 25 | + toggleBrush('lineX', uuid) | ||
| 26 | + brushMap[uuid]['chart']?.getZr().off('mousedown', ev) | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | + brushMap[uuid]['chart']?.getZr().off('mousedown', ev) | ||
| 30 | + brushMap[uuid]['chart']?.getZr().on('mousedown', ev) | ||
| 31 | +} | ||
| 32 | +export const useClearBrushSelect = (uuid: string) => { | ||
| 33 | + brushMap[uuid]['chart']?.dispatchAction({ | ||
| 34 | + type: 'brush', | ||
| 35 | + command: 'clear', | ||
| 36 | + areas: [] | ||
| 37 | + }) | ||
| 38 | + // toggleBrush(false, uuid) | ||
| 39 | + addBrushEvent(uuid) | ||
| 40 | +} | ||
| 41 | +export const useRange = (uuid: string) => { | ||
| 42 | + const range = ref({ start: '', end: '' }) | ||
| 43 | + watch(() => brushMap[uuid], m => { | ||
| 44 | + if (m) { | ||
| 45 | + range.value = m['range'] | ||
| 46 | + } | ||
| 47 | + }) | ||
| 48 | + return range | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +/** | ||
| 52 | + * brush select range | ||
| 53 | + * myChart echarts instance | ||
| 54 | + * uuid uuid | ||
| 55 | + * range | ||
| 56 | + */ | ||
| 57 | +export const useRangeXAixsByBrush = (myChart: ECharts, uuid: string) => { | ||
| 58 | + brushMap[uuid] = Object.create(null) | ||
| 59 | + brushMap[uuid]['range'] = shallowReactive({ | ||
| 60 | + start: '', | ||
| 61 | + end: '' | ||
| 62 | + }) | ||
| 63 | + brushMap[uuid]['chart'] = myChart | ||
| 64 | + addBrushEvent(uuid) | ||
| 65 | + const brushEnd = (params: any) => { | ||
| 66 | + const option = myChart.getOption() as EChartsOption | ||
| 67 | + const xAxis = option.xAxis as XAxisType | XAxisType[] | ||
| 68 | + const xData = Array.isArray(xAxis) ? xAxis[0].data : xAxis.data | ||
| 69 | + if (params.areas[0]) { | ||
| 70 | + brushMap[uuid]['range'].start = xData[myChart.convertFromPixel({ xAxisIndex: 0 }, params.areas[0].range[0])] | ||
| 71 | + brushMap[uuid]['range'].end = xData[myChart.convertFromPixel({ xAxisIndex: 0 }, params.areas[0].range[1])] | ||
| 72 | + if (monitorStore.tab === 0) { | ||
| 73 | + monitorStore.filters[0].rangeTime = -1 | ||
| 74 | + monitorStore.filters[0].time = [new Date(brushMap[uuid]['range'].start), new Date(brushMap[uuid]['range'].end)] | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + myChart.off('brushEnd', brushEnd) | ||
| 79 | + myChart.on('brushEnd', brushEnd) | ||
| 80 | + return brushMap[uuid]['range'] | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +const toggleDataZoomBrush = (myChart: ECharts, a: boolean) => { | ||
| 84 | + myChart.dispatchAction({ | ||
| 85 | + type: 'takeGlobalCursor', | ||
| 86 | + key: 'dataZoomSelect', | ||
| 87 | + dataZoomSelectActive: a | ||
| 88 | + }) | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +const toggleDataZoomSelect = (myChart: ECharts, a: boolean) => { | ||
| 92 | + toggleDataZoomBrush(myChart, a); | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +const watchBrush = (myChart: ECharts) => { | ||
| 96 | + const startBrush = (params: { offsetX: number, offsetY: number }) => { | ||
| 97 | + if (myChart.containPixel('grid', [params.offsetX, params.offsetY])) { | ||
| 98 | + toggleDataZoomSelect(myChart, true) | ||
| 99 | + myChart.getZr().off('mousedown', startBrush) | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + myChart.getZr().off('mousedown', startBrush) | ||
| 103 | + myChart.getZr().on('mousedown', startBrush) | ||
| 104 | +} | ||
| 105 | +const addZoomEvent = (myChart: ECharts, inZoom: Ref<boolean>) => { | ||
| 106 | + myChart.on('datazoom', (params: any) => { | ||
| 107 | + toggleDataZoomBrush(myChart, false) | ||
| 108 | + watchBrush(myChart) | ||
| 109 | + if (params.startValue !== undefined) { | ||
| 110 | + return | ||
| 111 | + } | ||
| 112 | + if (params.batch && params.batch[0].start === 0 && params.batch[0].end === 0) { | ||
| 113 | + return | ||
| 114 | + } | ||
| 115 | + if (params.start !== undefined && params.start === 0 && params.end === 100) { | ||
| 116 | + return | ||
| 117 | + } | ||
| 118 | + inZoom.value = true | ||
| 119 | + const start = params.batch[0].startValue | ||
| 120 | + const end = params.batch[0].endValue | ||
| 121 | + const option = myChart.getOption() as any | ||
| 122 | + monitorStore.timeRange = [option.xAxis[0].data[start], option.xAxis[0].data[end]] | ||
| 123 | + monitorStore.brushRange = [start, end] | ||
| 124 | + }) | ||
| 125 | +} | ||
| 126 | +export const useDataZoom = (myChart: ECharts) => { | ||
| 127 | + const inZoom = ref(false) | ||
| 128 | + watchBrush(myChart) | ||
| 129 | + addZoomEvent(myChart, inZoom) | ||
| 130 | + return { | ||
| 131 | + inZoom, | ||
| 132 | + } | ||
| 133 | +} | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | +import { ComputedGetter, Ref } from "vue" | ||
| 2 | + | ||
| 3 | +export const useIntervalTime = (cb: Function, timeFn: ComputedGetter<number> | Ref<number>) => { | ||
| 4 | + const timer = ref<number>() | ||
| 5 | + timer.value = setInterval(cb, typeof timeFn === 'function' ? timeFn() : timeFn.value) | ||
| 6 | + watch(timeFn, t => { | ||
| 7 | + if (timer.value) { | ||
| 8 | + clearInterval(timer.value) | ||
| 9 | + timer.value = setInterval(cb, t) | ||
| 10 | + } | ||
| 11 | + }) | ||
| 12 | + onBeforeUnmount(() => { | ||
| 13 | + if (timer.value) { | ||
| 14 | + clearInterval(timer.value) | ||
| 15 | + } | ||
| 16 | + }) | ||
| 17 | +} | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { i18n, LocaleType } from '.'; | ||
| 3 | + | ||
| 4 | +const changeLang = (locale: LocaleType) => { | ||
| 5 | + i18n.global.locale.value = locale | ||
| 6 | +} | ||
| 7 | +</script> | ||
| 8 | + | ||
| 9 | +<template> | ||
| 10 | + <el-dropdown> | ||
| 11 | + <svg-icon name="lang" style="width: 20px;height: 20px;" /> | ||
| 12 | + <template #dropdown> | ||
| 13 | + <el-dropdown-menu> | ||
| 14 | + <el-dropdown-item | ||
| 15 | + v-for="locale in $i18n.availableLocales" | ||
| 16 | + :key="`locale-${locale}`" | ||
| 17 | + @click="changeLang(locale as LocaleType)" | ||
| 18 | + > | ||
| 19 | + {{ locale === 'en' ? 'en' : 'zhCn' }} | ||
| 20 | + </el-dropdown-item> | ||
| 21 | + </el-dropdown-menu> | ||
| 22 | + </template> | ||
| 23 | + </el-dropdown> | ||
| 24 | +</template> | ||
| @@ -0,0 +1,210 @@ | |||
| 1 | +export default { | ||
| 2 | + app: { | ||
| 3 | + name: 'WorkBench', | ||
| 4 | + menuName: 'Monitor', | ||
| 5 | + refresh: 'refresh', | ||
| 6 | + autoRefresh: 'refresh', | ||
| 7 | + custom: 'Custom', | ||
| 8 | + startDate: 'Start Date', | ||
| 9 | + endDate: 'End Date', | ||
| 10 | + to: 'To', | ||
| 11 | + running: 'running', | ||
| 12 | + disconnect: 'disconnect', | ||
| 13 | + unknown: 'unknown', | ||
| 14 | + query: 'query', | ||
| 15 | + delete: 'delete', | ||
| 16 | + cancel: 'cancel', | ||
| 17 | + confirm: 'confirm', | ||
| 18 | + add: 'add', | ||
| 19 | + edit: 'edit', | ||
| 20 | + operate: 'operate', | ||
| 21 | + view: 'view', | ||
| 22 | + download: 'download', | ||
| 23 | + reset: 'Reset', | ||
| 24 | + back: 'Back', | ||
| 25 | + preview: 'Preview', | ||
| 26 | + queryFail: 'Query failed', | ||
| 27 | + saveSuccess: 'Save successful', | ||
| 28 | + saveFail: 'Save failed', | ||
| 29 | + testSuccess: 'Test successful', | ||
| 30 | + testFail: 'Test failed', | ||
| 31 | + delSuccess: 'Deletion successful', | ||
| 32 | + delFail: 'Deletion failed', | ||
| 33 | + selecteDataTip: 'Please select a piece of data', | ||
| 34 | + selectDatasTip: 'Please select the datas', | ||
| 35 | + tip: 'Tip', | ||
| 36 | + setAlertConfig: 'Set up the Alert interface', | ||
| 37 | + selectUpdateDataTip: 'Please select the data first before editing', | ||
| 38 | + deleteTip: 'Are you sure you want to delete this data?', | ||
| 39 | + keepOneData: 'Please keep at least one piece of data', | ||
| 40 | + uninstallTip: 'Before using the Alert Center module and the Notify Configuration module, you need to install Prometheus. Please go to "Intelligent OPS - Instance Monitoring " to install the server Prometheus. Otherwise, it will not be available.', | ||
| 41 | + disConfigTip: 'Before using the Alert Center module and the Notify Configuration module, set up the alert interface first.', | ||
| 42 | + }, | ||
| 43 | + alertRule: { | ||
| 44 | + title: 'alert rule', | ||
| 45 | + alertTitle: 'alert rule', | ||
| 46 | + notifyTitle: 'Notify rule', | ||
| 47 | + addTitle: 'add rule', | ||
| 48 | + detailTitle: 'rule detail', | ||
| 49 | + editTitle: 'edit rule', | ||
| 50 | + ruleName: 'Rule Name', | ||
| 51 | + ruleType: 'Rule Type', | ||
| 52 | + level: 'level', | ||
| 53 | + index: 'index', | ||
| 54 | + ruleItem: 'alert rule', | ||
| 55 | + ruleExpComb: 'alert rule combination', | ||
| 56 | + ruleContent: 'alert content', | ||
| 57 | + notifyDuration: 'statistical duration', | ||
| 58 | + alertDesc: 'alert description', | ||
| 59 | + repeat: 'duplicate', | ||
| 60 | + silence: 'silence', | ||
| 61 | + silenceTime: 'silence time', | ||
| 62 | + alertNotify: 'alert notify', | ||
| 63 | + notifyWay: 'notify way', | ||
| 64 | + second: 'second', | ||
| 65 | + minute: 'minute', | ||
| 66 | + hour: 'hour', | ||
| 67 | + day: 'day', | ||
| 68 | + log: 'log', | ||
| 69 | + serious: 'serious', | ||
| 70 | + warn: 'warn', | ||
| 71 | + info: 'info', | ||
| 72 | + ruleNamePlaceholder: 'select the rule name please', | ||
| 73 | + selectRuleType: 'select the rule type please', | ||
| 74 | + selectLevelType: 'select the level please', | ||
| 75 | + isRepeat: 'Yes', | ||
| 76 | + isNotRepeat: 'No', | ||
| 77 | + isSilence: 'Yes', | ||
| 78 | + isNotSilence: 'No', | ||
| 79 | + to: 'to', | ||
| 80 | + firing: 'firing', | ||
| 81 | + recover: 'recover', | ||
| 82 | + and: 'and', | ||
| 83 | + or: 'or', | ||
| 84 | + table: ['ruleName', 'ruleType', 'level', 'isRepeat', 'isSilence', 'alertNotify', 'alertContent', 'operate', '告警规则', '规则组合'], | ||
| 85 | + ruleItemNum: 'number', | ||
| 86 | + ruleItemExp: 'rule expression', | ||
| 87 | + normalAction: 'keeping happen', | ||
| 88 | + increaseAction: 'keeping increase', | ||
| 89 | + decreaseAction: 'keeping decrease', | ||
| 90 | + alertContentTitle: 'Alert content description', | ||
| 91 | + alertContentTip: 'The main purpose of the alert content is to notify the user, and it supports configuring parameters using ${xxx} to represent the parameters. For example, the alert content is "In the last minute, the CPU usage rate of ${nodeName} has been greater than 90%", where ${nodeName} is a parameter. The configurable parameters are as follows:' | ||
| 92 | + }, | ||
| 93 | + alertTemplate: { | ||
| 94 | + title: 'alert template', | ||
| 95 | + addTitle: 'add template', | ||
| 96 | + editTitle: 'edit template', | ||
| 97 | + detailTitle: 'template detail', | ||
| 98 | + templateName: 'template name', | ||
| 99 | + selectRule: 'select the rule', | ||
| 100 | + templateNamePlaceholder: 'Please enter template name', | ||
| 101 | + table: ['template name', 'operate'], | ||
| 102 | + }, | ||
| 103 | + alertRecord: { | ||
| 104 | + title: 'alert record', | ||
| 105 | + alertTotal: 'total number of alert', | ||
| 106 | + alerting: 'firing', | ||
| 107 | + alerted: 'recover', | ||
| 108 | + unread: 'unread', | ||
| 109 | + read: 'read', | ||
| 110 | + markAsRead: 'mark as read', | ||
| 111 | + markAsUnread: 'mark as unread', | ||
| 112 | + recordStatus: 'record status', | ||
| 113 | + alertStatus: 'alert status', | ||
| 114 | + level: 'alert level', | ||
| 115 | + recordStatusTip: 'Alert handling statistics', | ||
| 116 | + alertStatusTip: 'Alert status statistics', | ||
| 117 | + levelTip: 'Alert level statistics', | ||
| 118 | + cluster: 'cluster/instance', | ||
| 119 | + alertTimeRange: 'alert time range', | ||
| 120 | + startTimePlaceholder: 'start time', | ||
| 121 | + endTimePlaceholder: 'end time', | ||
| 122 | + table: ['instance', 'IP', 'datasoure type', 'alert template', 'alert rule', 'rule type', 'alert level', 'start time', 'end time', 'duration(sec)', 'alert status', 'notify way', 'record status', 'operate'], | ||
| 123 | + tableDataSelectTip: 'Please select at least one data', | ||
| 124 | + detailTitle: 'alert detail', | ||
| 125 | + alertInstance: 'alert instance', | ||
| 126 | + alertRule: 'alert rule', | ||
| 127 | + alertContent: 'alert content', | ||
| 128 | + alertRelationView: 'related view', | ||
| 129 | + clusterName: 'cluster name', | ||
| 130 | + IPAndPort: 'IP and port', | ||
| 131 | + nodeRole: 'cluster node role', | ||
| 132 | + }, | ||
| 133 | + AlertClusterNodeConf: { | ||
| 134 | + title: 'alert configuration', | ||
| 135 | + confBtn: 'configuration', | ||
| 136 | + table: ['cluster/instance', 'datasoure type', 'IP', 'alert template', 'operate'], | ||
| 137 | + detailTitle: 'alert template config', | ||
| 138 | + selectedInstance: 'selected instances', | ||
| 139 | + alertTemplateTab: 'select alert template', | ||
| 140 | + alertRuleTab: 'select alert rule', | ||
| 141 | + generateTip1: 'The system will generate a default template name for the selected rules:"', | ||
| 142 | + generateTip2: '".You can also customize and modify the name.', | ||
| 143 | + setInterface: 'set alert interface', | ||
| 144 | + alertIp: 'Interface IP', | ||
| 145 | + alertPort: 'Interface Port', | ||
| 146 | + interfaceAddr: 'Full interface', | ||
| 147 | + nodeNamePlaceholder: 'Please input cluster/instance name' | ||
| 148 | + }, | ||
| 149 | + notifyTemplate: { | ||
| 150 | + title: 'notify template', | ||
| 151 | + addTitle: 'add template', | ||
| 152 | + editTitle: 'edit template', | ||
| 153 | + detailTitle: 'template detail', | ||
| 154 | + templateNamePlaceholder: 'Please enter the name of the notify template', | ||
| 155 | + templateTypePlaceholder: 'Please enter the type of the notify template', | ||
| 156 | + templateDescPlaceholder: 'Please enter the description of the notify template', | ||
| 157 | + notifyTitlePlaceholder: 'Please enter the title', | ||
| 158 | + notifyContentPlaceholder: 'Please enter the notify content', | ||
| 159 | + templateName: 'template name', | ||
| 160 | + templateType: 'template type', | ||
| 161 | + notifyTitle: 'notify title', | ||
| 162 | + notifyContent: 'notify content', | ||
| 163 | + templateDesc: 'template description', | ||
| 164 | + email: 'email', | ||
| 165 | + WeCom: 'WeCom', | ||
| 166 | + DingTalk: 'DingTalk', | ||
| 167 | + previewContent: 'message preview', | ||
| 168 | + notifyContentTitle: 'notify content description', | ||
| 169 | + notifyContentTip: 'The message content mainly wraps the alert content, adds additional content, and finally sends the wrapped alert content to the user. It supports configuring parameters using ${xxx} to represent the parameters. The configurable parameter meanings are as follows:' | ||
| 170 | + }, | ||
| 171 | + notifyWay: { | ||
| 172 | + title: 'notify way', | ||
| 173 | + addTitle: 'add notify way', | ||
| 174 | + editTitle: 'edit notify way', | ||
| 175 | + detailTile: 'notify way detail', | ||
| 176 | + namePlaceholder: 'Please enter the name of the notify way', | ||
| 177 | + name: 'name', | ||
| 178 | + notifyType: 'notify type', | ||
| 179 | + notifyTarget: 'notify target', | ||
| 180 | + personId: 'person ID', | ||
| 181 | + deptId: 'department ID', | ||
| 182 | + emailPlaceholder: 'Please enter email address(es). If there are multiple email addresses, please separate them with commas', | ||
| 183 | + personIdPlaceholder: 'Please enter person ID(s). If there are multiple person, please separate them with commas. Either person ID or department ID is required (or both).', | ||
| 184 | + deptIdPlaceholder: 'Please enter department ID(s). If there are multiple department, please separate them with commas. Either person ID or department ID is required (or both).', | ||
| 185 | + templatePlaceholder: 'Please select a notify template', | ||
| 186 | + emailTemplate: 'email template', | ||
| 187 | + WeComTemplate: 'WeCom template', | ||
| 188 | + DingTalkTemplate: 'DingTalk template', | ||
| 189 | + existOneOfTargetTip: 'Either person ID or department ID is required (or both)', | ||
| 190 | + }, | ||
| 191 | + notifyConfig: { | ||
| 192 | + title: 'notify config', | ||
| 193 | + emailConfig: 'eamil config', | ||
| 194 | + weComConfig: 'WeCom config', | ||
| 195 | + dingTalkConfig: 'DingTalk config', | ||
| 196 | + senderEmail: 'sender email address', | ||
| 197 | + sender: 'sender', | ||
| 198 | + sever: 'server', | ||
| 199 | + port: 'SMTP port', | ||
| 200 | + account: 'SMTP account', | ||
| 201 | + passwd: 'SMTP password', | ||
| 202 | + agentId: 'agent ID', | ||
| 203 | + weComAppKey: 'WeCom appKey', | ||
| 204 | + weComSecret: 'WeCom secret', | ||
| 205 | + appKey: 'appKey', | ||
| 206 | + dingSecret: 'app secret', | ||
| 207 | + inputTip: 'Pleasse input', | ||
| 208 | + test: 'test', | ||
| 209 | + } | ||
| 210 | +} | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | +import { createI18n } from 'vue-i18n'; | ||
| 2 | +import zhCn from './zhCn'; | ||
| 3 | +import en from './en'; | ||
| 4 | + | ||
| 5 | +export type LocaleType = "zhCn" | "en" | ||
| 6 | + | ||
| 7 | +export const i18n = createI18n({ | ||
| 8 | + legacy: false, | ||
| 9 | + locale: 'zhCn', | ||
| 10 | + messages: { | ||
| 11 | + zhCn, | ||
| 12 | + en, | ||
| 13 | + }, | ||
| 14 | +}) | ||
| @@ -0,0 +1,210 @@ | |||
| 1 | +export default { | ||
| 2 | + app: { | ||
| 3 | + name: '一体化平台', | ||
| 4 | + menuName: '监控告警', | ||
| 5 | + refresh: '刷新', | ||
| 6 | + autoRefresh: '自动刷新', | ||
| 7 | + custom: '自定义', | ||
| 8 | + startDate: '开始日期', | ||
| 9 | + endDate: '结束日期', | ||
| 10 | + to: '至', | ||
| 11 | + running: '运行中', | ||
| 12 | + disconnect: '连接异常', | ||
| 13 | + unknown: '未知', | ||
| 14 | + query: '查询', | ||
| 15 | + delete: '删除', | ||
| 16 | + cancel: '取消', | ||
| 17 | + confirm: '确定', | ||
| 18 | + add: '新增', | ||
| 19 | + edit: '编辑', | ||
| 20 | + operate: '操作', | ||
| 21 | + view: '查看', | ||
| 22 | + download: '下载', | ||
| 23 | + reset: '重置', | ||
| 24 | + back: '返回', | ||
| 25 | + preview: '预览', | ||
| 26 | + queryFail: '查询失败', | ||
| 27 | + saveSuccess: '保存成功', | ||
| 28 | + saveFail: '保存失败', | ||
| 29 | + delSuccess: '删除成功', | ||
| 30 | + delFail: '删除失败', | ||
| 31 | + testSuccess: '测试成功', | ||
| 32 | + testFail: '测试失败', | ||
| 33 | + selecteDataTip: '请选择一个数据', | ||
| 34 | + selectDatasTip: '请选择数据', | ||
| 35 | + tip: '提示', | ||
| 36 | + setAlertConfig: '设置告警接口', | ||
| 37 | + selectUpdateDataTip: '请先勾选数据,再进行编辑', | ||
| 38 | + deleteTip: '确定删除该数据吗?', | ||
| 39 | + keepOneData: '至少保留一个数据', | ||
| 40 | + uninstallTip: '在监控告警模块和通知配置模块使用前,需要先安装prometheus,请到“智能运维——实例监控”中安装服务端prometheus,否则将无法使用。', | ||
| 41 | + disConfigTip: '在监控告警模块和通知配置模块使用前,先设置告警接口', | ||
| 42 | + }, | ||
| 43 | + alertRule: { | ||
| 44 | + title: '告警规则', | ||
| 45 | + alertTitle: '告警规则', | ||
| 46 | + notifyTitle: '通知规则', | ||
| 47 | + addTitle: '新增规则', | ||
| 48 | + editTitle: '编辑规则', | ||
| 49 | + detailTitle: '规则详细', | ||
| 50 | + ruleName: '规则名称', | ||
| 51 | + ruleType: '规则类型', | ||
| 52 | + level: '告警级别', | ||
| 53 | + ruleItem: '告警规则', | ||
| 54 | + ruleExpComb: '告警规则组合', | ||
| 55 | + ruleContent: '告警内容', | ||
| 56 | + notifyDuration: '统计周期', | ||
| 57 | + alertDesc: '告警描述', | ||
| 58 | + repeat: '是否重复通知', | ||
| 59 | + silence: '是否静默', | ||
| 60 | + silenceTime: '静默时间', | ||
| 61 | + alertNotify: '告警通知', | ||
| 62 | + notifyWay: '通知方式', | ||
| 63 | + second: '秒', | ||
| 64 | + minute: '分', | ||
| 65 | + hour: '时', | ||
| 66 | + day: '天', | ||
| 67 | + index: '指标', | ||
| 68 | + log: '日志', | ||
| 69 | + serious: '严重', | ||
| 70 | + warn: '警告', | ||
| 71 | + info: '提示', | ||
| 72 | + ruleNamePlaceholder: '请输入规则名称', | ||
| 73 | + selectRuleType: '请选择规则类型', | ||
| 74 | + selectLevelType: '请选择告警级别', | ||
| 75 | + isRepeat: '是', | ||
| 76 | + isNotRepeat: '否', | ||
| 77 | + isSilence: '是', | ||
| 78 | + isNotSilence: '否', | ||
| 79 | + to: '至', | ||
| 80 | + firing: '告警时', | ||
| 81 | + recover: '告警恢复时', | ||
| 82 | + and: '和', | ||
| 83 | + or: '或', | ||
| 84 | + table: ['规则名称', '规则类型', '告警级别', '是否重复告警', '静默设置', '告警通知', '告警内容', '操作', '告警规则', '规则组合'], | ||
| 85 | + ruleItemNum: '编号', | ||
| 86 | + ruleItemExp: '规则表达式', | ||
| 87 | + normalAction: '持续发生', | ||
| 88 | + increaseAction: '持续增长', | ||
| 89 | + decreaseAction: '持续下降', | ||
| 90 | + alertContentTitle: '告警内容说明', | ||
| 91 | + alertContentTip: '告警内容主用来通知用户,它支持配置参数,用${xxx}来表示参数。比如:告警内容为“最近一分钟,${nodeName}的CPU使用率一直大于90%”,其中${nodeName}为参数。可配置参数如下:', | ||
| 92 | + }, | ||
| 93 | + alertTemplate: { | ||
| 94 | + title: '告警模板', | ||
| 95 | + addTitle: '新增模板', | ||
| 96 | + editTitle: '编辑模板', | ||
| 97 | + detailTitle: '模板详细', | ||
| 98 | + templateName: '模板名称', | ||
| 99 | + templateNamePlaceholder: '请输入模板名称', | ||
| 100 | + selectRule: '选择规则', | ||
| 101 | + table: ['模板名称', '操作'], | ||
| 102 | + }, | ||
| 103 | + alertRecord: { | ||
| 104 | + title: '告警记录', | ||
| 105 | + alertTotal: '告警总数', | ||
| 106 | + alerting: '告警中', | ||
| 107 | + alerted: '已结束', | ||
| 108 | + unread: '未读', | ||
| 109 | + read: '已读', | ||
| 110 | + markAsRead: '标记为已读', | ||
| 111 | + markAsUnread: '标记为未读', | ||
| 112 | + recordStatus: '信息状态', | ||
| 113 | + alertStatus: '告警状态', | ||
| 114 | + level: '告警等级', | ||
| 115 | + recordStatusTip: '告警处理统计', | ||
| 116 | + alertStatusTip: '告警状态统计', | ||
| 117 | + levelTip: '告警级别统计', | ||
| 118 | + cluster: '集群/实例', | ||
| 119 | + alertTimeRange: '告警时间范围', | ||
| 120 | + startTimePlaceholder: '开始时间', | ||
| 121 | + endTimePlaceholder: '结束时间', | ||
| 122 | + table: ['实例名称', '主机IP', '数据库类型', '告警模板', '告警规则', '规则类型', '告警等级', '开始时间', '结束时间', '持续时间(秒)', '告警状态', '通知方式', '信息状态', '操作'], | ||
| 123 | + tableDataSelectTip: '至少选择一个数据', | ||
| 124 | + detailTitle: '告警详细', | ||
| 125 | + alertInstance: '告警对象', | ||
| 126 | + alertRule: '告警规则', | ||
| 127 | + alertContent: '告警内容', | ||
| 128 | + alertRelationView: '关联视图', | ||
| 129 | + clusterName: '集群名称', | ||
| 130 | + IPAndPort: '实例IP与端口', | ||
| 131 | + nodeRole: '实例角色', | ||
| 132 | + }, | ||
| 133 | + AlertClusterNodeConf: { | ||
| 134 | + title: '告警配置', | ||
| 135 | + confBtn: '配置', | ||
| 136 | + table: ['集群/实例', '数据库类型', '主机IP', '告警模板', '操作'], | ||
| 137 | + detailTitle: '告警模板配置', | ||
| 138 | + selectedInstance: '已选实例', | ||
| 139 | + alertTemplateTab: '选择告警模板', | ||
| 140 | + alertRuleTab: '选择告警规则', | ||
| 141 | + generateTip1: '系统将为已选的规则生成默认的模板名称:“', | ||
| 142 | + generateTip2: '”。您也可以自定义修改名称:', | ||
| 143 | + setInterface: '设置告警接口', | ||
| 144 | + alertIp: '接口IP', | ||
| 145 | + alertPort: '接口端口', | ||
| 146 | + interfaceAddr: '完整接口', | ||
| 147 | + nodeNamePlaceholder: '请输入集群/实例名称', | ||
| 148 | + }, | ||
| 149 | + notifyTemplate: { | ||
| 150 | + title: '通知模板', | ||
| 151 | + addTitle: '新增模板', | ||
| 152 | + editTitle: '修改模板', | ||
| 153 | + detailTitle: '模板详细', | ||
| 154 | + templateNamePlaceholder: '请输入通知模板名称', | ||
| 155 | + templateTypePlaceholder: '请输入通知模板类型', | ||
| 156 | + templateDescPlaceholder: '请输入通知模板描述', | ||
| 157 | + notifyTitlePlaceholder: '请输入主题', | ||
| 158 | + notifyContentPlaceholder: '请输入通知内容', | ||
| 159 | + templateName: '模板名称', | ||
| 160 | + templateType: '模板类型', | ||
| 161 | + notifyTitle: '通知主题', | ||
| 162 | + notifyContent: '通知内容', | ||
| 163 | + templateDesc: '模板描述', | ||
| 164 | + email: '邮箱', | ||
| 165 | + WeCom: '企业微信', | ||
| 166 | + DingTalk: '钉钉', | ||
| 167 | + previewContent: '消息预览', | ||
| 168 | + notifyContentTitle: '消息内容说明', | ||
| 169 | + notifyContentTip: '消息内容主要将告警内容进行包装,添加额外内容,最终将包装的告警内容发送给用户。它支持配置参数,用${xxx}来表示参数。可配置的参数含义如下:' | ||
| 170 | + }, | ||
| 171 | + notifyWay: { | ||
| 172 | + title: '通知方式', | ||
| 173 | + addTitle: '新增通知方式', | ||
| 174 | + editTitle: '编辑通知方式', | ||
| 175 | + detailTile: '通知方式详细', | ||
| 176 | + namePlaceholder: '请输入通知方式名称', | ||
| 177 | + name: '通知方式名称', | ||
| 178 | + notifyType: '发送方式', | ||
| 179 | + notifyTarget: '发送目标', | ||
| 180 | + personId: '用户ID', | ||
| 181 | + deptId: '部门ID', | ||
| 182 | + emailPlaceholder: '请输入邮箱地址,存在多个邮箱地址,可以用逗号分隔。', | ||
| 183 | + personIdPlaceholder: '请输入用户ID,存在多个用户,可以用逗号分隔。用户ID和部门ID,至少有一个必填', | ||
| 184 | + deptIdPlaceholder: '请输入部门ID,存在多个部门,可以用逗号分隔。用户ID和部门ID,至少有一个必填', | ||
| 185 | + templatePlaceholder: '请选择通知模板', | ||
| 186 | + emailTemplate: '邮箱模板', | ||
| 187 | + WeComTemplate: '企业微信模板', | ||
| 188 | + DingTalkTemplate: '钉钉模板', | ||
| 189 | + existOneOfTargetTip: '用户ID和部门ID,至少有一个必填', | ||
| 190 | + }, | ||
| 191 | + notifyConfig: { | ||
| 192 | + title: '通知渠道', | ||
| 193 | + emailConfig: '邮箱配置', | ||
| 194 | + weComConfig: '企业微信配置', | ||
| 195 | + dingTalkConfig: '钉钉配置', | ||
| 196 | + senderEmail: '发件邮箱', | ||
| 197 | + sender: '发件人', | ||
| 198 | + sever: '服务器', | ||
| 199 | + port: 'SMTP端口号', | ||
| 200 | + account: 'SMTP账号', | ||
| 201 | + passwd: 'SMTP密码', | ||
| 202 | + agentId: '应用ID', | ||
| 203 | + weComAppKey: '企业ID', | ||
| 204 | + weComSecret: '企业密钥', | ||
| 205 | + appKey: 'appKey', | ||
| 206 | + dingSecret: 'app密钥', | ||
| 207 | + inputTip: '请输入', | ||
| 208 | + test: '测试', | ||
| 209 | + } | ||
| 210 | +} | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { routes } from '../router/index'; | ||
| 3 | + | ||
| 4 | +const route = useRoute() | ||
| 5 | +const hasComponents: Record<string, string> = {} | ||
| 6 | +for (const r of routes) { | ||
| 7 | + if (r.component) { | ||
| 8 | + hasComponents[r.meta?.title!] = r.path | ||
| 9 | + } | ||
| 10 | + if (r.children && r.children.length > 0) { | ||
| 11 | + for (const child of r.children) { | ||
| 12 | + if (child.component) { | ||
| 13 | + hasComponents[child.meta?.title!] = child.path | ||
| 14 | + } | ||
| 15 | + } | ||
| 16 | + } | ||
| 17 | +} | ||
| 18 | +const paths = computed(() => { | ||
| 19 | + const arr: { title?: string, path?: string }[] = [] | ||
| 20 | + for (const r of routes) { | ||
| 21 | + if (r.path === route.path) { | ||
| 22 | + arr.push({ title: r.meta?.title }) | ||
| 23 | + return arr | ||
| 24 | + } | ||
| 25 | + if (r.children && r.children.length > 0) { | ||
| 26 | + for (const child of r.children) { | ||
| 27 | + let isWithithParamPath = false; | ||
| 28 | + if (child.path.includes('/:')) { | ||
| 29 | + isWithithParamPath = route.path.includes(child.path.slice(0, child.path.indexOf('/:'))) | ||
| 30 | + } | ||
| 31 | + if ((child.path === route.path || isWithithParamPath) && child.meta?.breadcrumb) { | ||
| 32 | + child.meta.breadcrumb.forEach(title => { | ||
| 33 | + arr.push(hasComponents[title] ? { title, path: hasComponents[title] } : { title }) | ||
| 34 | + }) | ||
| 35 | + arr.push({ title: child.meta.title }) | ||
| 36 | + return arr | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + return arr; | ||
| 42 | +}) | ||
| 43 | +</script> | ||
| 44 | + | ||
| 45 | +<template> | ||
| 46 | +<el-breadcrumb> | ||
| 47 | + <el-breadcrumb-item v-for="p in paths" :key="p.title" :to="p.path">{{ $t(p.title!) }}</el-breadcrumb-item> | ||
| 48 | +</el-breadcrumb> | ||
| 49 | +</template> | ||
| 50 | + | ||
| 51 | +<style scoped lang="scss"> | ||
| 52 | + :deep(.el-breadcrumb__inner.is-link, .el-breadcrumb__inner a) { | ||
| 53 | + // color: $og-text-color; | ||
| 54 | + font-weight: 400; | ||
| 55 | + } | ||
| 56 | + :deep(.el-breadcrumb__inner.is-link:hover, .el-breadcrumb__inner a:hover) { | ||
| 57 | + text-decoration: underline; | ||
| 58 | + } | ||
| 59 | + :deep(.el-breadcrumb__item:last-of-type .el-breadcrumb__inner) { | ||
| 60 | + font-weight: 700; | ||
| 61 | + } | ||
| 62 | +</style> | ||
| @@ -0,0 +1,70 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { Fold, Expand } from '@element-plus/icons-vue'; | ||
| 3 | +import Lang from '../i18n/Lang.vue'; | ||
| 4 | + | ||
| 5 | +const props = withDefaults(defineProps<{ | ||
| 6 | + showIcon: boolean | ||
| 7 | +}>(), { | ||
| 8 | + showIcon: true | ||
| 9 | +}) | ||
| 10 | +const themeText = ref("dark") | ||
| 11 | +const collapse = ref(false) | ||
| 12 | +const myEmit = defineEmits<{ | ||
| 13 | + (event: 'collapse', collapse: boolean): void, | ||
| 14 | + (event: 'changeTheme'): void | ||
| 15 | +}>() | ||
| 16 | +const emitCollapse = (c: boolean) => { | ||
| 17 | + myEmit('collapse', c) | ||
| 18 | + collapse.value = c | ||
| 19 | +} | ||
| 20 | +const onChangeTheme = () => { | ||
| 21 | + myEmit('changeTheme') | ||
| 22 | + themeText.value = themeText.value === 'dark' ? 'light' : 'dark'; | ||
| 23 | +} | ||
| 24 | +</script> | ||
| 25 | + | ||
| 26 | +<template> | ||
| 27 | + <div class="header-container"> | ||
| 28 | + <div class="left"> | ||
| 29 | + <el-icon :size="18" v-if="collapse && props.showIcon" style="cursor: pointer;" @click="() => emitCollapse(false)"><Expand /></el-icon> | ||
| 30 | + <el-icon :size="18" v-if="!collapse && props.showIcon" style="cursor: pointer;" @click="() => emitCollapse(true)"><Fold /></el-icon> | ||
| 31 | + <my-breadcrumb class="bread" /> | ||
| 32 | + </div> | ||
| 33 | + <div class="right"> | ||
| 34 | + <span class="header-change-theme" @click.stop="onChangeTheme()">{{ themeText }}</span> | ||
| 35 | + <Lang /> | ||
| 36 | + </div> | ||
| 37 | + </div> | ||
| 38 | +</template> | ||
| 39 | + | ||
| 40 | +<style scoped lang="scss"> | ||
| 41 | +.header-container { | ||
| 42 | + height: var(--vem-header-height); | ||
| 43 | + background-color: var(--el-bg-color-sub); | ||
| 44 | + font-size: 16px; | ||
| 45 | + padding: 0 16px; | ||
| 46 | + letter-spacing: 1px; | ||
| 47 | + display: flex; | ||
| 48 | + align-items: center; | ||
| 49 | + justify-content: space-between; | ||
| 50 | + flex-wrap: nowrap; | ||
| 51 | + flex-shrink: 0; | ||
| 52 | +} | ||
| 53 | +.left { | ||
| 54 | + display: flex; | ||
| 55 | + align-items: center; | ||
| 56 | +} | ||
| 57 | +.right { | ||
| 58 | + display: flex; | ||
| 59 | + align-items: center; | ||
| 60 | +} | ||
| 61 | +.bread { | ||
| 62 | + margin-left: 10px; | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +.header-change-theme { | ||
| 66 | + font-size: 12px; | ||
| 67 | + margin-right: 20px; | ||
| 68 | + cursor: pointer; | ||
| 69 | +} | ||
| 70 | +</style> | ||
| @@ -0,0 +1,92 @@ | |||
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { RouteRecordRaw } from 'vue-router'; | ||
| 3 | +import _ from 'lodash-es'; | ||
| 4 | +import { routes } from '../router/index'; | ||
| 5 | + | ||
| 6 | +const props = withDefaults(defineProps<{ | ||
| 7 | + collapse: boolean | ||
| 8 | +}>(), {}) | ||
| 9 | + | ||
| 10 | +const route = useRoute(); | ||
| 11 | + | ||
| 12 | +type appDataType = { | ||
| 13 | + curRoutes: Array<RouteRecordRaw> | ||
| 14 | +} | ||
| 15 | +const appData = reactive<appDataType>({ | ||
| 16 | + curRoutes: [] | ||
| 17 | +}); | ||
| 18 | + | ||
| 19 | +const deatRoute = (r: Array<RouteRecordRaw>) => { | ||
| 20 | + return r.filter(item => !item.meta?.hidden).map(m => { | ||
| 21 | + if (Array.isArray(m.children)) { | ||
| 22 | + m.children = deatRoute(m.children); | ||
| 23 | + } | ||
| 24 | + return m; | ||
| 25 | + }); | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +onMounted(() => { | ||
| 29 | + appData.curRoutes = deatRoute(_.cloneDeep(routes)); | ||
| 30 | +}); | ||
| 31 | +</script> | ||
| 32 | + | ||
| 33 | +<template> | ||
| 34 | +<div class="logo" v-if="!props.collapse">{{ $t('app.name') }}</div> | ||
| 35 | +<el-menu | ||
| 36 | + class="vem-menu" | ||
| 37 | + :default-active="route.path" | ||
| 38 | + router | ||
| 39 | + :collapse="props.collapse" | ||
| 40 | + :collapse-transition="false" | ||
| 41 | + :style="{width: collapse ? 'auto' : '200px'}" | ||
| 42 | +> | ||
| 43 | + <div v-for="route in appData.curRoutes" :key="route.path"> | ||
| 44 | + <el-sub-menu v-if="route.children && route.children.length > 0" :index="route.path"> | ||
| 45 | + <template #title> | ||
| 46 | + <svg-icon | ||
| 47 | + :name="route.meta?.icon!" | ||
| 48 | + style="margin-right: 6px" | ||
| 49 | + /> | ||
| 50 | + <span>{{ $t(route.meta?.title!) }}</span> | ||
| 51 | + </template> | ||
| 52 | + <el-menu-item v-for="sub in route.children" :key="sub.path" :index="sub.path"> | ||
| 53 | + {{ $t(sub.meta?.title!) }} | ||
| 54 | + </el-menu-item> | ||
| 55 | + </el-sub-menu> | ||
| 56 | + <el-menu-item v-else :index="route.path"> | ||
| 57 | + <svg-icon | ||
| 58 | + :name="route.meta?.icon!" | ||
| 59 | + style="margin-right: 6px" | ||
| 60 | + /> | ||
| 61 | + <template #title>{{ $t(route.meta?.title!) }}</template> | ||
| 62 | + </el-menu-item> | ||
| 63 | + </div> | ||
| 64 | +</el-menu> | ||
| 65 | +</template> | ||
| 66 | + | ||
| 67 | +<style scoped lang="scss"> | ||
| 68 | +.logo { | ||
| 69 | + width: auto; | ||
| 70 | + height: 60px; | ||
| 71 | + // color: $og-text-color; | ||
| 72 | + line-height: 60px; | ||
| 73 | + text-align: center; | ||
| 74 | + font-size: 18px; | ||
| 75 | + font-weight: bold; | ||
| 76 | + background-color: var(--el-menu-bg-color); | ||
| 77 | +} | ||
| 78 | +.vem-menu { | ||
| 79 | + overflow-y: auto; | ||
| 80 | + overflow-x: hidden; | ||
| 81 | + height: 100%; | ||
| 82 | + border-right: 0; | ||
| 83 | +} | ||
| 84 | +.vem-menu.el-menu--collapse .el-sub-menu__title { | ||
| 85 | + span { | ||
| 86 | + display: none; | ||
| 87 | + } | ||
| 88 | + .el-sub-menu__icon-arrow { | ||
| 89 | + display: none!important; | ||
| 90 | + } | ||
| 91 | +} | ||
| 92 | +</style> | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | +import { createApp } from "vue"; | ||
| 2 | +import 'element-plus/theme-chalk/src/message.scss' | ||
| 3 | +import 'element-plus/theme-chalk/src/table.scss' | ||
| 4 | +import 'element-plus/theme-chalk/el-loading.css' | ||
| 5 | +import 'element-plus/theme-chalk/el-message.css' | ||
| 6 | +import 'element-plus/theme-chalk/dark/css-vars.css'; | ||
| 7 | +import '@/assets/style/dark.scss' | ||
| 8 | +import '@/assets/style/reset.scss'; | ||
| 9 | +import '@/assets/style/common.scss'; | ||
| 10 | +import App from "./App.vue"; | ||
| 11 | +import { createPinia } from "pinia"; | ||
| 12 | +import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; | ||
| 13 | +import "virtual:svg-icons-register"; | ||
| 14 | +import router from "./router"; | ||
| 15 | +import { vLoading } from "element-plus"; | ||
| 16 | +import { i18n } from './i18n' | ||
| 17 | + | ||
| 18 | +const pinia = createPinia(); | ||
| 19 | +pinia.use(piniaPluginPersistedstate); | ||
| 20 | +const app = createApp(App) | ||
| 21 | +app.directive('loading', vLoading) | ||
| 22 | +app.use(i18n).use(router).use(pinia).mount("#app"); | ||
| @@ -0,0 +1,99 @@ | |||
| 1 | +import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; | ||
| 2 | +import { ElMessage } from "element-plus"; | ||
| 3 | + | ||
| 4 | +const observabilityBaseURL = process.env.mode === 'production' ? '/plugins/alert-center' : ''; | ||
| 5 | +// const observabilityBaseURL ='/plugins/observability-instance-zh25'; | ||
| 6 | +interface ApiResponse<T = any> { | ||
| 7 | + code: string | number; | ||
| 8 | + data: T; | ||
| 9 | + error: any; | ||
| 10 | + msg: string; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +const handleData = <T>(res: AxiosResponse<ApiResponse<T>, any>) => { | ||
| 14 | + if (res.status === 200 && res.data) { | ||
| 15 | + return Promise.resolve(res.data) | ||
| 16 | + } else { | ||
| 17 | + ElMessage.error(res?.data.msg || "请求错误") | ||
| 18 | + return Promise.reject(res?.data.msg || "请求错误") | ||
| 19 | + } | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +export class Request { | ||
| 23 | + constructor(config?: AxiosRequestConfig) { | ||
| 24 | + if (config) { | ||
| 25 | + for (const key in config) { | ||
| 26 | + if (key in axios.defaults) { | ||
| 27 | + // @ts-ignore | ||
| 28 | + axios.defaults[key] = config[key] | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + async get<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 35 | + try { | ||
| 36 | + return handleData<T>(await axios.get<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config })) | ||
| 37 | + } catch (error) { | ||
| 38 | + const err = error as AxiosError<any> | ||
| 39 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 40 | + return Promise.reject(err.response.data.msg) | ||
| 41 | + } | ||
| 42 | + return Promise.reject(error) | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + async delete<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 47 | + try { | ||
| 48 | + return handleData<T>(await axios.delete<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config })) | ||
| 49 | + } catch (error) { | ||
| 50 | + const err = error as AxiosError<any> | ||
| 51 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 52 | + return Promise.reject(err.response.data.msg) | ||
| 53 | + } | ||
| 54 | + return Promise.reject(error) | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + async post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 59 | + try { | ||
| 60 | + return handleData<T>(await axios.post<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 61 | + } catch (error) { | ||
| 62 | + const err = error as AxiosError<any> | ||
| 63 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 64 | + return Promise.reject(err.response.data.msg) | ||
| 65 | + } | ||
| 66 | + return Promise.reject(error) | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + async put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 71 | + try { | ||
| 72 | + return handleData<T>(await axios.put<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 73 | + } catch (error) { | ||
| 74 | + const err = error as AxiosError<any> | ||
| 75 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 76 | + return Promise.reject(err.response.data.msg) | ||
| 77 | + } | ||
| 78 | + return Promise.reject(error) | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + async patch<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 83 | + try { | ||
| 84 | + return handleData<T>(await axios.patch<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 85 | + } catch (error) { | ||
| 86 | + const err = error as AxiosError<any> | ||
| 87 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 88 | + return Promise.reject(err.response.data.msg) | ||
| 89 | + } | ||
| 90 | + return Promise.reject(error) | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +const ogRequest = new Request({ | ||
| 96 | + baseURL: import.meta.env.VITE_BASE_URL | ||
| 97 | +}) | ||
| 98 | + | ||
| 99 | +export default ogRequest | ||
| @@ -0,0 +1,170 @@ | |||
| 1 | +import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; | ||
| 2 | + | ||
| 3 | +const observabilityBaseURL = process.env.mode === 'production' ? '/plugins/alert-center' : ''; | ||
| 4 | +// const observabilityBaseURL ='/plugins/observability-instance-zh25'; | ||
| 5 | + | ||
| 6 | +interface ApiResponse<T = any> { | ||
| 7 | + code: string | number; | ||
| 8 | + data: T; | ||
| 9 | + error: any; | ||
| 10 | + msg: string; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +const handleData = <T>(res: AxiosResponse<ApiResponse<T>, any>) => { | ||
| 14 | + if (res.data && (res.data.code === "200" || res.data.code === 200)) { | ||
| 15 | + return Promise.resolve(res.data) | ||
| 16 | + } else { | ||
| 17 | + return Promise.reject(res?.data) | ||
| 18 | + } | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +export class Request { | ||
| 22 | + constructor(config?: AxiosRequestConfig) { | ||
| 23 | + if (config) { | ||
| 24 | + for (const key in config) { | ||
| 25 | + if (key in axios.defaults) { | ||
| 26 | + // @ts-ignore | ||
| 27 | + axios.defaults[key] = config[key] | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + async getNative<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 34 | + const token = localStorage.getItem("opengauss-token"); | ||
| 35 | + if (token) { | ||
| 36 | + if (!config) { | ||
| 37 | + config = {}; | ||
| 38 | + } | ||
| 39 | + if (!config.headers) { | ||
| 40 | + config.headers = {}; | ||
| 41 | + } | ||
| 42 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 43 | + } | ||
| 44 | + try { | ||
| 45 | + return await axios.get<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config }) | ||
| 46 | + } catch (error) { | ||
| 47 | + const err = error as AxiosError<any> | ||
| 48 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 49 | + return Promise.reject(err.response.data.msg) | ||
| 50 | + } | ||
| 51 | + return Promise.reject(error) | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + async get<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 56 | + const token = localStorage.getItem("opengauss-token"); | ||
| 57 | + if (token) { | ||
| 58 | + if (!config) { | ||
| 59 | + config = {}; | ||
| 60 | + } | ||
| 61 | + if (!config.headers) { | ||
| 62 | + config.headers = {}; | ||
| 63 | + } | ||
| 64 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 65 | + } | ||
| 66 | + try { | ||
| 67 | + return handleData<T>(await axios.get<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config })) | ||
| 68 | + } catch (error) { | ||
| 69 | + const err = error as AxiosError<any> | ||
| 70 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 71 | + return Promise.reject(err.response.data.msg) | ||
| 72 | + } | ||
| 73 | + return Promise.reject(error) | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + async delete<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 78 | + const token = localStorage.getItem("opengauss-token"); | ||
| 79 | + if (token) { | ||
| 80 | + if (!config) { | ||
| 81 | + config = {}; | ||
| 82 | + } | ||
| 83 | + if (!config.headers) { | ||
| 84 | + config.headers = {}; | ||
| 85 | + } | ||
| 86 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 87 | + } | ||
| 88 | + try { | ||
| 89 | + return handleData<T>(await axios.delete<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config })) | ||
| 90 | + } catch (error) { | ||
| 91 | + const err = error as AxiosError<any> | ||
| 92 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 93 | + return Promise.reject(err.response.data.msg) | ||
| 94 | + } | ||
| 95 | + return Promise.reject(error) | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + async post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 100 | + const token = localStorage.getItem("opengauss-token"); | ||
| 101 | + if (token) { | ||
| 102 | + if (!config) { | ||
| 103 | + config = {}; | ||
| 104 | + } | ||
| 105 | + if (!config.headers) { | ||
| 106 | + config.headers = {}; | ||
| 107 | + } | ||
| 108 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 109 | + } | ||
| 110 | + try { | ||
| 111 | + return handleData<T>(await axios.post<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 112 | + } catch (error) { | ||
| 113 | + const err = error as AxiosError<any> | ||
| 114 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 115 | + return Promise.reject(err.response.data.msg) | ||
| 116 | + } | ||
| 117 | + return Promise.reject(error) | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + async put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 122 | + const token = localStorage.getItem("opengauss-token"); | ||
| 123 | + if (token) { | ||
| 124 | + if (!config) { | ||
| 125 | + config = {}; | ||
| 126 | + } | ||
| 127 | + if (!config.headers) { | ||
| 128 | + config.headers = {}; | ||
| 129 | + } | ||
| 130 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 131 | + } | ||
| 132 | + try { | ||
| 133 | + return handleData<T>(await axios.put<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 134 | + } catch (error) { | ||
| 135 | + const err = error as AxiosError<any> | ||
| 136 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 137 | + return Promise.reject(err.response.data.msg) | ||
| 138 | + } | ||
| 139 | + return Promise.reject(error) | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + async patch<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 144 | + const token = localStorage.getItem("opengauss-token"); | ||
| 145 | + if (token) { | ||
| 146 | + if (!config) { | ||
| 147 | + config = {}; | ||
| 148 | + } | ||
| 149 | + if (!config.headers) { | ||
| 150 | + config.headers = {}; | ||
| 151 | + } | ||
| 152 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 153 | + } | ||
| 154 | + try { | ||
| 155 | + return handleData<T>(await axios.patch<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 156 | + } catch (error) { | ||
| 157 | + const err = error as AxiosError<any> | ||
| 158 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 159 | + return Promise.reject(err.response.data.msg) | ||
| 160 | + } | ||
| 161 | + return Promise.reject(error) | ||
| 162 | + } | ||
| 163 | + } | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +const ogRequest = new Request({ | ||
| 167 | + baseURL: import.meta.env.VITE_BASE_URL | ||
| 168 | +}) | ||
| 169 | + | ||
| 170 | +export default ogRequest | ||
| @@ -0,0 +1,124 @@ | |||
| 1 | + | ||
| 2 | +import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; | ||
| 3 | +import { ElMessage } from "element-plus"; | ||
| 4 | + | ||
| 5 | +const observabilityBaseURL = process.env.mode === 'production' ? '/plugins/alert-center' : ''; | ||
| 6 | +interface ApiResponse<T = any> { | ||
| 7 | + code: string | number; | ||
| 8 | + data: T; | ||
| 9 | + error: any; | ||
| 10 | + msg: string; | ||
| 11 | + config:{ | ||
| 12 | + url:string | ||
| 13 | + }; | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +const handleData = <T>(res: AxiosResponse<ApiResponse<T>, any>) => { | ||
| 17 | + if (res.status === 200 && res.config.url === '/getOffCpuSvg') { | ||
| 18 | + return Promise.resolve(res) | ||
| 19 | + } else { | ||
| 20 | + if (res.data && (res.data.code === "200" || res.data.code === 200)) { | ||
| 21 | + return Promise.resolve(res.data.data) | ||
| 22 | + } else { | ||
| 23 | + ElMessage.error(res?.data.msg || "请求错误") | ||
| 24 | + return Promise.reject(res?.data.msg || "请求错误") | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +export class Request { | ||
| 30 | + constructor(config?: AxiosRequestConfig) { | ||
| 31 | + if (config) { | ||
| 32 | + axios.defaults.baseURL = 'http://10.10.9.221:5000' | ||
| 33 | + for (const key in config) { | ||
| 34 | + if (key in axios.defaults) { | ||
| 35 | + // @ts-ignore | ||
| 36 | + axios.defaults[key] = config[key] | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + async get<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 43 | + axios.defaults.baseURL = 'http://10.10.9.221:5000' | ||
| 44 | + try { | ||
| 45 | + return handleData<T>(await axios.get<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config })) | ||
| 46 | + } catch (error) { | ||
| 47 | + const err = error as AxiosError<any> | ||
| 48 | + if (err.response && err.response.status === 500) { | ||
| 49 | + ElMessage.error("服务器错误,请稍后重试") | ||
| 50 | + } | ||
| 51 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 52 | + return Promise.reject(err.response.data.msg) | ||
| 53 | + } | ||
| 54 | + return Promise.reject(error) | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + async delete<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 59 | + axios.defaults.baseURL = 'http://10.10.9.221:5000' | ||
| 60 | + try { | ||
| 61 | + return handleData<T>(await axios.delete<ApiResponse<T>>(`${observabilityBaseURL}${url}`, { params, ...config })) | ||
| 62 | + } catch (error) { | ||
| 63 | + const err = error as AxiosError<any> | ||
| 64 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 65 | + return Promise.reject(err.response.data.msg) | ||
| 66 | + } | ||
| 67 | + return Promise.reject(error) | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + async post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 72 | + axios.defaults.baseURL = 'http://10.10.9.221:5000' | ||
| 73 | + try { | ||
| 74 | + return handleData<T>(await axios.post<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 75 | + } catch (error) { | ||
| 76 | + const err = error as AxiosError<any> | ||
| 77 | + if (err.response && err.response.status === 500) { | ||
| 78 | + ElMessage.error("服务器错误,请稍后重试") | ||
| 79 | + } | ||
| 80 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 81 | + return Promise.reject(err.response.data.msg) | ||
| 82 | + } | ||
| 83 | + return Promise.reject(error) | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + async put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 88 | + axios.defaults.baseURL = 'http://10.10.9.221:5000' | ||
| 89 | + try { | ||
| 90 | + return handleData<T>(await axios.put<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 91 | + } catch (error) { | ||
| 92 | + const err = error as AxiosError<any> | ||
| 93 | + if (err.response && err.response.status === 500) { | ||
| 94 | + ElMessage.error("服务器错误,请稍后重试") | ||
| 95 | + } | ||
| 96 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 97 | + return Promise.reject(err.response.data.msg) | ||
| 98 | + } | ||
| 99 | + return Promise.reject(error) | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + async patch<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 104 | + axios.defaults.baseURL = 'http://10.10.9.221:5000' | ||
| 105 | + try { | ||
| 106 | + return handleData<T>(await axios.patch<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)) | ||
| 107 | + } catch (error) { | ||
| 108 | + const err = error as AxiosError<any> | ||
| 109 | + if (err.response && err.response.status === 500) { | ||
| 110 | + ElMessage.error("服务器错误,请稍后重试") | ||
| 111 | + } | ||
| 112 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 113 | + return Promise.reject(err.response.data.msg) | ||
| 114 | + } | ||
| 115 | + return Promise.reject(error) | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +const ogRequest = new Request({ | ||
| 121 | + baseURL: import.meta.env.VITE_BASE_URL | ||
| 122 | +}) | ||
| 123 | + | ||
| 124 | +export default ogRequest | ||
| @@ -0,0 +1,175 @@ | |||
| 1 | +import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; | ||
| 2 | + | ||
| 3 | +const platformBaseURL = ""; | ||
| 4 | + | ||
| 5 | +interface ApiResponse<T = any> { | ||
| 6 | + code: string | number; | ||
| 7 | + data: T; | ||
| 8 | + error: any; | ||
| 9 | + msg: string; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +const handleData = <T>(res: AxiosResponse<ApiResponse<T>, any>) => { | ||
| 13 | + if (res.data && (res.data.code === "200" || res.data.code === 200)) { | ||
| 14 | + return Promise.resolve(res.data.data); | ||
| 15 | + } else { | ||
| 16 | + return Promise.reject(res?.data.msg || "Request Error").catch((err) => { | ||
| 17 | + console.log(err); | ||
| 18 | + }); | ||
| 19 | + } | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +const handleRESTfulData = <T>(res: AxiosResponse<T, any>) => { | ||
| 23 | + return Promise.resolve(res.data); | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +export class Request { | ||
| 27 | + constructor(config?: AxiosRequestConfig) { | ||
| 28 | + if (config) { | ||
| 29 | + for (const key in config) { | ||
| 30 | + if (key in axios.defaults) { | ||
| 31 | + // @ts-ignore | ||
| 32 | + axios.defaults[key] = config[key]; | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + async getNative<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 39 | + const token = localStorage.getItem("opengauss-token"); | ||
| 40 | + if (token) { | ||
| 41 | + if (!config) { | ||
| 42 | + config = {}; | ||
| 43 | + } | ||
| 44 | + if (!config.headers) { | ||
| 45 | + config.headers = {}; | ||
| 46 | + } | ||
| 47 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 48 | + } | ||
| 49 | + try { | ||
| 50 | + return await axios.get<ApiResponse<T>>(`${platformBaseURL}${url}`, { params, ...config }); | ||
| 51 | + } catch (error) { | ||
| 52 | + const err = error as AxiosError<any>; | ||
| 53 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 54 | + return Promise.reject(err.response.data.msg); | ||
| 55 | + } | ||
| 56 | + return Promise.reject(error); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + async get<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 61 | + const token = localStorage.getItem("opengauss-token"); | ||
| 62 | + if (token) { | ||
| 63 | + if (!config) { | ||
| 64 | + config = {}; | ||
| 65 | + } | ||
| 66 | + if (!config.headers) { | ||
| 67 | + config.headers = {}; | ||
| 68 | + } | ||
| 69 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 70 | + } | ||
| 71 | + try { | ||
| 72 | + return handleRESTfulData<T>(await axios.get<T>(`${platformBaseURL}${url}`, { params, ...config })); | ||
| 73 | + } catch (error) { | ||
| 74 | + const err = error as AxiosError<any>; | ||
| 75 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 76 | + return Promise.reject(err.response.data.msg); | ||
| 77 | + } | ||
| 78 | + return Promise.reject(error); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + async delete<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 83 | + const token = localStorage.getItem("opengauss-token"); | ||
| 84 | + if (token) { | ||
| 85 | + if (!config) { | ||
| 86 | + config = {}; | ||
| 87 | + } | ||
| 88 | + if (!config.headers) { | ||
| 89 | + config.headers = {}; | ||
| 90 | + } | ||
| 91 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 92 | + } | ||
| 93 | + try { | ||
| 94 | + return handleRESTfulData<T>(await axios.delete<T>(`${platformBaseURL}${url}`, { params, ...config })); | ||
| 95 | + } catch (error) { | ||
| 96 | + const err = error as AxiosError<any>; | ||
| 97 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 98 | + return Promise.reject(err.response.data.msg); | ||
| 99 | + } | ||
| 100 | + return Promise.reject(error); | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + async post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 105 | + const token = localStorage.getItem("opengauss-token"); | ||
| 106 | + if (token) { | ||
| 107 | + if (!config) { | ||
| 108 | + config = {}; | ||
| 109 | + } | ||
| 110 | + if (!config.headers) { | ||
| 111 | + config.headers = {}; | ||
| 112 | + } | ||
| 113 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 114 | + } | ||
| 115 | + try { | ||
| 116 | + return handleRESTfulData<T>(await axios.post<T>(`${platformBaseURL}${url}`, data, config)); | ||
| 117 | + } catch (error) { | ||
| 118 | + const err = error as AxiosError<any>; | ||
| 119 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 120 | + return Promise.reject(err.response.data.msg); | ||
| 121 | + } | ||
| 122 | + return Promise.reject(error); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + async put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 127 | + const token = localStorage.getItem("opengauss-token"); | ||
| 128 | + if (token) { | ||
| 129 | + if (!config) { | ||
| 130 | + config = {}; | ||
| 131 | + } | ||
| 132 | + if (!config.headers) { | ||
| 133 | + config.headers = {}; | ||
| 134 | + } | ||
| 135 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 136 | + } | ||
| 137 | + try { | ||
| 138 | + return handleData<T>(await axios.put<ApiResponse<T>>(`${platformBaseURL}${url}`, data, config)); | ||
| 139 | + } catch (error) { | ||
| 140 | + const err = error as AxiosError<any>; | ||
| 141 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 142 | + return Promise.reject(err.response.data.msg); | ||
| 143 | + } | ||
| 144 | + return Promise.reject(error); | ||
| 145 | + } | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + async patch<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 149 | + const token = localStorage.getItem("opengauss-token"); | ||
| 150 | + if (token) { | ||
| 151 | + if (!config) { | ||
| 152 | + config = {}; | ||
| 153 | + } | ||
| 154 | + if (!config.headers) { | ||
| 155 | + config.headers = {}; | ||
| 156 | + } | ||
| 157 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 158 | + } | ||
| 159 | + try { | ||
| 160 | + return handleData<T>(await axios.patch<ApiResponse<T>>(`${platformBaseURL}${url}`, data, config)); | ||
| 161 | + } catch (error) { | ||
| 162 | + const err = error as AxiosError<any>; | ||
| 163 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 164 | + return Promise.reject(err.response.data.msg); | ||
| 165 | + } | ||
| 166 | + return Promise.reject(error); | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +const platformRequest = new Request({ | ||
| 172 | + baseURL: import.meta.env.VITE_BASE_URL, | ||
| 173 | +}); | ||
| 174 | + | ||
| 175 | +export default platformRequest; | ||
| @@ -0,0 +1,166 @@ | |||
| 1 | +import axios, { AxiosError, AxiosRequestConfig } from "axios"; | ||
| 2 | +import { ElMessage } from "element-plus"; | ||
| 3 | + | ||
| 4 | +const observabilityBaseURL = process.env.mode === "production" ? "/plugins/alert-center" : ""; | ||
| 5 | + | ||
| 6 | +interface ApiResponse<T = any> { | ||
| 7 | + code: string | number; | ||
| 8 | + data: T; | ||
| 9 | + error: any; | ||
| 10 | + msg: string; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +const handleRESTfulData = (res: any) => { | ||
| 14 | + if (isSuccessResponse(res)) { | ||
| 15 | + return Promise.resolve(res.data); | ||
| 16 | + } else { | ||
| 17 | + ElMessage.error(res?.data.msg || "Request Error"); | ||
| 18 | + return Promise.reject(res?.data?.msg || "Request Error").catch((err) => { | ||
| 19 | + console.log(err); | ||
| 20 | + }); | ||
| 21 | + } | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +const isSuccessResponse = (res: any) => { | ||
| 25 | + if (res.status === 200) { | ||
| 26 | + if (res.data === undefined) { | ||
| 27 | + return true; | ||
| 28 | + } else if (Object.keys(res.data).length === 2 && typeof res.data.code !== 'undefined' && typeof res.data.msg !== 'undefined' && res.data.code !== 200) { | ||
| 29 | + return false; | ||
| 30 | + } else return true; | ||
| 31 | + } else return false; | ||
| 32 | +}; | ||
| 33 | + | ||
| 34 | +export class Request { | ||
| 35 | + constructor(config?: AxiosRequestConfig) { | ||
| 36 | + if (config) { | ||
| 37 | + for (const key in config) { | ||
| 38 | + if (key in axios.defaults) { | ||
| 39 | + // @ts-ignore | ||
| 40 | + axios.defaults[key] = config[key]; | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + async get<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 47 | + const token = localStorage.getItem("opengauss-token"); | ||
| 48 | + if (token) { | ||
| 49 | + if (!config) { | ||
| 50 | + config = {}; | ||
| 51 | + } | ||
| 52 | + if (!config.headers) { | ||
| 53 | + config.headers = {}; | ||
| 54 | + } | ||
| 55 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 56 | + config.headers["Content-Language"] = localStorage.getItem("locale") === "en-US" ? "en_US" : "zh_CN"; | ||
| 57 | + } | ||
| 58 | + try { | ||
| 59 | + return handleRESTfulData<T>(await axios.get<T>(`${observabilityBaseURL}${url}`, { params, ...config })); | ||
| 60 | + } catch (error) { | ||
| 61 | + const err = error as AxiosError<any>; | ||
| 62 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 63 | + return Promise.reject(err.response.data.msg); | ||
| 64 | + } | ||
| 65 | + return Promise.reject(error); | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + async delete<T = any>(url: string, params?: any, config?: AxiosRequestConfig) { | ||
| 70 | + const token = localStorage.getItem("opengauss-token"); | ||
| 71 | + if (token) { | ||
| 72 | + if (!config) { | ||
| 73 | + config = {}; | ||
| 74 | + } | ||
| 75 | + if (!config.headers) { | ||
| 76 | + config.headers = {}; | ||
| 77 | + } | ||
| 78 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 79 | + config.headers["Content-Language"] = localStorage.getItem("locale") === "en-US" ? "en_US" : "zh_CN"; | ||
| 80 | + } | ||
| 81 | + try { | ||
| 82 | + return handleRESTfulData<T>(await axios.delete<T>(`${observabilityBaseURL}${url}`, { params, ...config })); | ||
| 83 | + } catch (error) { | ||
| 84 | + const err = error as AxiosError<any>; | ||
| 85 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 86 | + return Promise.reject(err.response.data.msg); | ||
| 87 | + } | ||
| 88 | + return Promise.reject(error); | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + async post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 93 | + const token = localStorage.getItem("opengauss-token"); | ||
| 94 | + if (token) { | ||
| 95 | + if (!config) { | ||
| 96 | + config = {}; | ||
| 97 | + } | ||
| 98 | + if (!config.headers) { | ||
| 99 | + config.headers = {}; | ||
| 100 | + } | ||
| 101 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 102 | + config.headers["Content-Language"] = localStorage.getItem("locale") === "en-US" ? "en_US" : "zh_CN"; | ||
| 103 | + } | ||
| 104 | + try { | ||
| 105 | + return handleRESTfulData<T>(await axios.post<T>(`${observabilityBaseURL}${url}`, data, config)); | ||
| 106 | + } catch (error) { | ||
| 107 | + const err = error as AxiosError<any>; | ||
| 108 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 109 | + return Promise.reject(err.response.data.msg); | ||
| 110 | + } | ||
| 111 | + return Promise.reject(error); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + async put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 116 | + const token = localStorage.getItem("opengauss-token"); | ||
| 117 | + if (token) { | ||
| 118 | + if (!config) { | ||
| 119 | + config = {}; | ||
| 120 | + } | ||
| 121 | + if (!config.headers) { | ||
| 122 | + config.headers = {}; | ||
| 123 | + } | ||
| 124 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 125 | + config.headers["Content-Language"] = localStorage.getItem("locale") === "en-US" ? "en_US" : "zh_CN"; | ||
| 126 | + } | ||
| 127 | + try { | ||
| 128 | + return handleRESTfulData<T>(await axios.put<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)); | ||
| 129 | + } catch (error) { | ||
| 130 | + const err = error as AxiosError<any>; | ||
| 131 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 132 | + return Promise.reject(err.response.data.msg); | ||
| 133 | + } | ||
| 134 | + return Promise.reject(error); | ||
| 135 | + } | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + async patch<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) { | ||
| 139 | + const token = localStorage.getItem("opengauss-token"); | ||
| 140 | + if (token) { | ||
| 141 | + if (!config) { | ||
| 142 | + config = {}; | ||
| 143 | + } | ||
| 144 | + if (!config.headers) { | ||
| 145 | + config.headers = {}; | ||
| 146 | + } | ||
| 147 | + config.headers.Authorization = `Bearer ${token}`; | ||
| 148 | + config.headers["Content-Language"] = localStorage.getItem("locale") === "en-US" ? "en_US" : "zh_CN"; | ||
| 149 | + } | ||
| 150 | + try { | ||
| 151 | + return handleRESTfulData<T>(await axios.patch<ApiResponse<T>>(`${observabilityBaseURL}${url}`, data, config)); | ||
| 152 | + } catch (error) { | ||
| 153 | + const err = error as AxiosError<any>; | ||
| 154 | + if (err.response && err.response.data && err.response.data.msg) { | ||
| 155 | + return Promise.reject(err.response.data.msg); | ||
| 156 | + } | ||
| 157 | + return Promise.reject(error); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | +} | ||
| 161 | + | ||
| 162 | +const restRequest = new Request({ | ||
| 163 | + baseURL: import.meta.env.VITE_BASE_URL, | ||
| 164 | +}); | ||
| 165 | + | ||
| 166 | +export default restRequest; | ||
| @@ -0,0 +1,100 @@ | |||
| 1 | +import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router"; | ||
| 2 | + | ||
| 3 | +declare module 'vue-router' { | ||
| 4 | + // eslint-disable-next-line no-unused-vars | ||
| 5 | + interface RouteMeta { | ||
| 6 | + icon?: string; | ||
| 7 | + title: string; | ||
| 8 | + hidden?: boolean; | ||
| 9 | + breadcrumb?: string[]; | ||
| 10 | + } | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +export const routes: RouteRecordRaw[] = [ | ||
| 14 | + { | ||
| 15 | + path: "/vem", | ||
| 16 | + meta: { | ||
| 17 | + icon: "vite", | ||
| 18 | + title: 'app.menuName', | ||
| 19 | + }, | ||
| 20 | + children: [ | ||
| 21 | + { | ||
| 22 | + path: "/vem/alert/alertRecord", | ||
| 23 | + meta: { | ||
| 24 | + title: 'alertRecord.title', | ||
| 25 | + }, | ||
| 26 | + component: () => import("@/views/alert/AlertRecord/Index.vue"), | ||
| 27 | + }, | ||
| 28 | + { | ||
| 29 | + path: "/vem/alert/recordDetail", | ||
| 30 | + meta: { | ||
| 31 | + title: 'alertRecord.title', | ||
| 32 | + hidden: true | ||
| 33 | + }, | ||
| 34 | + component: () => import("@/views/alert/AlertRecord/RecordDetail.vue"), | ||
| 35 | + }, | ||
| 36 | + { | ||
| 37 | + path: "/vem/alert/AlertClusterNodeConf", | ||
| 38 | + meta: { | ||
| 39 | + title: 'AlertClusterNodeConf.title', | ||
| 40 | + }, | ||
| 41 | + component: () => import("@/views/alert/AlertClusterNodeConf/Index.vue"), | ||
| 42 | + }, | ||
| 43 | + { | ||
| 44 | + path: "/vem/alert/alertTemplate", | ||
| 45 | + meta: { | ||
| 46 | + title: 'alertTemplate.title', | ||
| 47 | + }, | ||
| 48 | + component: () => import("@/views/alert/AlertTemplate/Index.vue"), | ||
| 49 | + }, | ||
| 50 | + { | ||
| 51 | + path: "/vem/alert/alertRule", | ||
| 52 | + component: () => import("@/views/alert/AlertRule/Index.vue"), | ||
| 53 | + meta: { | ||
| 54 | + title: 'alertRule.title', | ||
| 55 | + // breadcrumb: ['app.menuName', 'dashboard.name'], | ||
| 56 | + breadcrumb: [], | ||
| 57 | + // hidden: true, | ||
| 58 | + }, | ||
| 59 | + }, | ||
| 60 | + { | ||
| 61 | + path: "/vem/notify/notifyTemplate", | ||
| 62 | + component: () => import("@/views/notify/NotifyTemplate/Index.vue"), | ||
| 63 | + meta: { | ||
| 64 | + title: 'notifyTemplate.title', | ||
| 65 | + }, | ||
| 66 | + }, | ||
| 67 | + { | ||
| 68 | + path: "/vem/notify/notifyWay", | ||
| 69 | + component: () => import("@/views/notify/NotifyWay/Index.vue"), | ||
| 70 | + meta: { | ||
| 71 | + title: 'notifyWay.title', | ||
| 72 | + }, | ||
| 73 | + }, | ||
| 74 | + // { | ||
| 75 | + // path: "/vem/sql_detail", | ||
| 76 | + // meta: { | ||
| 77 | + // icon: "vite", | ||
| 78 | + // title: 'sql.sqlDetail', | ||
| 79 | + // breadcrumb: ['app.menuName', 'dashboard.instance'], | ||
| 80 | + // hidden: true | ||
| 81 | + // }, | ||
| 82 | + // name: "SqlDetail", | ||
| 83 | + // component: () => import("@/pages/sql_detail/Index.vue"), | ||
| 84 | + // } | ||
| 85 | + ] | ||
| 86 | + }, | ||
| 87 | +]; | ||
| 88 | + | ||
| 89 | +const router = createRouter({ | ||
| 90 | + history: createWebHashHistory(), | ||
| 91 | + routes, | ||
| 92 | +}); | ||
| 93 | + | ||
| 94 | +router.beforeEach((to, from, next) => { | ||
| 95 | + if (from.path.includes(`/vem/track_detail/`) && to.path.includes(`/vem/log/track`)) { | ||
| 96 | + sessionStorage.removeItem('nodes'); | ||
| 97 | + } | ||
| 98 | + next(); | ||
| 99 | +}) | ||
| 100 | +export default router; | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | +import { defineStore } from "pinia"; | ||
| 2 | + | ||
| 3 | +interface State { | ||
| 4 | + showMain: boolean, | ||
| 5 | + isInstall: boolean, | ||
| 6 | + isConfig: boolean | ||
| 7 | + | ||
| 8 | +} | ||
| 9 | +export const useAlertConfigStore = defineStore("alertConfig", { | ||
| 10 | + state: (): State => ({ | ||
| 11 | + showMain: true, | ||
| 12 | + isInstall: false, | ||
| 13 | + isConfig: false | ||
| 14 | + }), | ||
| 15 | + actions: { | ||
| 16 | + setShow(showMain: boolean) { | ||
| 17 | + this.$state.showMain = showMain; | ||
| 18 | + }, | ||
| 19 | + setIsInstall(isInstall: boolean) { | ||
| 20 | + this.$state.isInstall = isInstall; | ||
| 21 | + }, | ||
| 22 | + setIsConifg(isConfig: boolean) { | ||
| 23 | + this.$state.isConfig = isConfig; | ||
| 24 | + }, | ||
| 25 | + | ||
| 26 | + } | ||
| 27 | +}) | ||
| @@ -0,0 +1,88 @@ | |||
| 1 | +import { defineStore } from "pinia"; | ||
| 2 | + | ||
| 3 | +interface State { | ||
| 4 | + instanceId: string, | ||
| 5 | + databaseData: Record<string, {data: string[], time: string[], name: string}[]>, | ||
| 6 | + /** | ||
| 7 | + * current tab index | ||
| 8 | + */ | ||
| 9 | + tab: number, | ||
| 10 | + filters: { | ||
| 11 | + /** | ||
| 12 | + * auto refresh interval | ||
| 13 | + */ | ||
| 14 | + refreshTime: number, | ||
| 15 | + /** | ||
| 16 | + * range time | ||
| 17 | + */ | ||
| 18 | + rangeTime: number, | ||
| 19 | + /** | ||
| 20 | + * custom range time | ||
| 21 | + */ | ||
| 22 | + time: [Date, Date] | null | ||
| 23 | + }[], | ||
| 24 | + autoRefresh: boolean, | ||
| 25 | + instanceTimeRange: [Date, Date] | null, | ||
| 26 | + /** | ||
| 27 | + * brush select | ||
| 28 | + */ | ||
| 29 | + brushRange: string[], | ||
| 30 | + timeRange: string[], | ||
| 31 | + /** | ||
| 32 | + * topsql server | ||
| 33 | + */ | ||
| 34 | + fixedRangeTime: Array<string>, | ||
| 35 | + serverData: Record<string, {data: string[], time: string[], name: string}[]>, | ||
| 36 | + promethuesStart: number, | ||
| 37 | + promethuesEnd: number, | ||
| 38 | + promethuesStep: number, | ||
| 39 | +} | ||
| 40 | +export const useMonitorStore = defineStore("monitor", { | ||
| 41 | + state: (): State => ({ | ||
| 42 | + instanceId: '', | ||
| 43 | + databaseData: {}, | ||
| 44 | + tab: 0, | ||
| 45 | + filters: [ | ||
| 46 | + { | ||
| 47 | + refreshTime: 30, | ||
| 48 | + rangeTime: 1, | ||
| 49 | + time: null | ||
| 50 | + }, | ||
| 51 | + { | ||
| 52 | + refreshTime: 30, | ||
| 53 | + rangeTime: 1, | ||
| 54 | + time: null | ||
| 55 | + }, | ||
| 56 | + { | ||
| 57 | + refreshTime: 30, | ||
| 58 | + rangeTime: 1, | ||
| 59 | + time: null | ||
| 60 | + }, | ||
| 61 | + { | ||
| 62 | + refreshTime: 30, | ||
| 63 | + rangeTime: 1, | ||
| 64 | + time: null | ||
| 65 | + }, | ||
| 66 | + ], | ||
| 67 | + autoRefresh: false, | ||
| 68 | + instanceTimeRange: null, | ||
| 69 | + brushRange: [], | ||
| 70 | + timeRange: [], | ||
| 71 | + fixedRangeTime: [], | ||
| 72 | + serverData: {}, | ||
| 73 | + promethuesStart: 0, | ||
| 74 | + promethuesEnd: 0, | ||
| 75 | + promethuesStep: 60, | ||
| 76 | + }), | ||
| 77 | + getters: { | ||
| 78 | + refreshTime: (state: State) => { | ||
| 79 | + return state.filters[state.tab].refreshTime | ||
| 80 | + }, | ||
| 81 | + rangeTime: (state: State) => { | ||
| 82 | + return state.filters[state.tab].rangeTime | ||
| 83 | + }, | ||
| 84 | + time: (state: State) => { | ||
| 85 | + return state.filters[state.tab].time | ||
| 86 | + }, | ||
| 87 | + }, | ||
| 88 | +}) | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | +import { defineStore } from 'pinia'; | ||
| 2 | + | ||
| 3 | +export const useWindowStore = defineStore('window', { | ||
| 4 | + state() { | ||
| 5 | + return { | ||
| 6 | + mainHeight: 0, | ||
| 7 | + mainWidth: 0, | ||
| 8 | + serverInfoText: '', | ||
| 9 | + theme: 'auto', // dark or auto | ||
| 10 | + } | ||
| 11 | + }, | ||
| 12 | + actions: { | ||
| 13 | + setMainHeight(height: number) { | ||
| 14 | + this.$state.mainHeight = height; | ||
| 15 | + }, | ||
| 16 | + setMainWidth(width: number) { | ||
| 17 | + this.$state.mainWidth = width; | ||
| 18 | + }, | ||
| 19 | + setServerInfoText(value: string) { | ||
| 20 | + this.$state.serverInfoText = value; | ||
| 21 | + }, | ||
| 22 | + setTheme(value: string) { | ||
| 23 | + this.$state.theme = value; | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | +}); | ||
| @@ -0,0 +1,31 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | +export function parseContent(content: string, param: any) { | ||
| 4 | + if (!content || !param) { | ||
| 5 | + return content | ||
| 6 | + } | ||
| 7 | + const paramOpen = "${"; | ||
| 8 | + const paramClose = "}"; | ||
| 9 | + let start = content.indexOf(paramOpen); | ||
| 10 | + if (start === -1) { | ||
| 11 | + return content; | ||
| 12 | + } | ||
| 13 | + let result = '' | ||
| 14 | + let offset = 0 | ||
| 15 | + while (start > -1) { | ||
| 16 | + result += content.slice(offset, start) | ||
| 17 | + offset = start + paramOpen.length | ||
| 18 | + let end = content.indexOf(paramClose, offset) | ||
| 19 | + if (end === -1) { | ||
| 20 | + return content | ||
| 21 | + } | ||
| 22 | + let paramName = content.slice(offset, end) | ||
| 23 | + let paramVal = param[paramName] || '' | ||
| 24 | + result += paramVal | ||
| 25 | + offset = end + paramClose.length | ||
| 26 | + start = content.indexOf(paramOpen, offset) | ||
| 27 | + } | ||
| 28 | + result += content.slice(offset, content.length) | ||
| 29 | + | ||
| 30 | + return result | ||
| 31 | +} | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | +import JsEncrypt from "jsencrypt"; | ||
| 2 | +import platformRequest from "../request/platform"; | ||
| 3 | + | ||
| 4 | +interface KeyValue { | ||
| 5 | + [key: string]: any; | ||
| 6 | +} | ||
| 7 | +interface Res { | ||
| 8 | + data: KeyValue; | ||
| 9 | +} | ||
| 10 | +// host password encryption | ||
| 11 | +export async function encryptPassword(pwd: string) { | ||
| 12 | + let publicKey = ""; | ||
| 13 | + const getPublicKey: KeyValue = await getEntryKey(); | ||
| 14 | + if (Number(getPublicKey.code) === 200 && getPublicKey.key) { | ||
| 15 | + const newKey = getPublicKey.key; | ||
| 16 | + publicKey = newKey; | ||
| 17 | + } | ||
| 18 | + const encryptor = new JsEncrypt(); | ||
| 19 | + encryptor.setPublicKey(publicKey); | ||
| 20 | + return encryptor.encrypt(pwd); | ||
| 21 | +} | ||
| 22 | +const getEntryKey: KeyValue = (data) => { | ||
| 23 | + return platformRequest | ||
| 24 | + .getNative("/encryption/getKey", {}) | ||
| 25 | + .then(function (res: Res) { | ||
| 26 | + return res.data; | ||
| 27 | + }) | ||
| 28 | + .catch(function (res) {}); | ||
| 29 | +}; | ||
| @@ -0,0 +1,102 @@ | |||
| 1 | +export default class WebSocketClass { | ||
| 2 | + // ws = null; | ||
| 3 | + ws: WebSocket; | ||
| 4 | + name = null; | ||
| 5 | + sessionId: null; | ||
| 6 | + instance = null; | ||
| 7 | + callback = null; | ||
| 8 | + connected = false; | ||
| 9 | + setIntervalWesocketPush = null; | ||
| 10 | + static instance: any; | ||
| 11 | + | ||
| 12 | + static getInstance(name, sessionId) { | ||
| 13 | + if (!this.instance) { | ||
| 14 | + this.instance = new WebSocketClass(name, sessionId); | ||
| 15 | + } | ||
| 16 | + return this.instance; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + constructor(name: string, sessionId, callback?) { | ||
| 20 | + this.name = name; | ||
| 21 | + this.sessionId = sessionId; | ||
| 22 | + this.instance = null; | ||
| 23 | + this.connect(name, sessionId, callback); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + connect(name: string, sessionId, callback?) { | ||
| 27 | + if (!window.WebSocket) { | ||
| 28 | + return console.log("Your browser does not support WebSocket"); | ||
| 29 | + } | ||
| 30 | + const baseURL = import.meta.env.DEV ? `${import.meta.env.VITE_WS_BASE_URL}` : `${location.protocol == "http:" ? "ws:" : "wss:"}//${location.host}`; | ||
| 31 | + const url = `${baseURL}/ws/alert-center/${sessionId}`; | ||
| 32 | + // const url = `ws://127.0.0.1:9494/ws/observability-instance/${sessionId}`; | ||
| 33 | + this.ws = new WebSocket(url); | ||
| 34 | + | ||
| 35 | + this.ws.onopen = () => { | ||
| 36 | + this.connected = true; | ||
| 37 | + // this.sendPing(); | ||
| 38 | + }; | ||
| 39 | + if (callback) this.callback = callback; | ||
| 40 | + | ||
| 41 | + this.ws.onclose = () => { | ||
| 42 | + this.connected = false; | ||
| 43 | + clearInterval(this.setIntervalWesocketPush); | ||
| 44 | + }; | ||
| 45 | + | ||
| 46 | + this.ws.onmessage = (msg: any) => { | ||
| 47 | + if (this.callback) { | ||
| 48 | + this.callback.call(this, msg.data); | ||
| 49 | + } | ||
| 50 | + }; | ||
| 51 | + | ||
| 52 | + this.ws.onerror = () => { | ||
| 53 | + if (this.ws.readyState !== 3) { | ||
| 54 | + this.connect(name, sessionId); | ||
| 55 | + } | ||
| 56 | + }; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + registerCallBack(callBack) { | ||
| 60 | + this.callback = callBack; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + unRegisterCallBack() { | ||
| 64 | + this.callback = null; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + send(data) { | ||
| 68 | + if (!!this.ws && this.ws.readyState === 3) { | ||
| 69 | + this.ws.close(); | ||
| 70 | + this.connect(this.name, this.sessionId); | ||
| 71 | + } else if (this.ws.readyState === 1) { | ||
| 72 | + this.ws.send(JSON.stringify(data)); | ||
| 73 | + } else if (this.ws.readyState === 0) { | ||
| 74 | + this.connecting(data); | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + sendPing(time = 1000 * 20, ping = "ping") { | ||
| 79 | + clearInterval(this.setIntervalWesocketPush); | ||
| 80 | + this.ws.send(ping); | ||
| 81 | + this.setIntervalWesocketPush = setInterval(() => { | ||
| 82 | + this.ws.send(ping); | ||
| 83 | + }, time); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + // When sending data but the connection is not established, it will be processed and wait for retransmission | ||
| 87 | + connecting(message: any) { | ||
| 88 | + setTimeout(() => { | ||
| 89 | + if (this.ws.readyState === 0) { | ||
| 90 | + this.connecting(message); | ||
| 91 | + } else if (this.ws.readyState === 3) { | ||
| 92 | + return; | ||
| 93 | + } else { | ||
| 94 | + this.ws.send(JSON.stringify(message)); | ||
| 95 | + } | ||
| 96 | + }, 1000); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + close() { | ||
| 100 | + this.ws.close(); | ||
| 101 | + } | ||
| 102 | +} | ||
| @@ -0,0 +1,434 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('AlertClusterNodeConf.title') }}</el-breadcrumb-item> | ||
| 5 | + <el-breadcrumb-item>{{ t('AlertClusterNodeConf.detailTitle') }}</el-breadcrumb-item> | ||
| 6 | + </el-breadcrumb> | ||
| 7 | + <el-divider /> | ||
| 8 | + <el-form label-position="right" label-width="80" size="large"> | ||
| 9 | + <el-form-item :label="$t('AlertClusterNodeConf.selectedInstance') + ':'"> | ||
| 10 | + <el-tag v-for="(item, index) in clusterNodeList0" :key="item.clusterNodeId" type="info" size="large" | ||
| 11 | + class="mx-1" style="margin-right: 5px;" effect="dark" closable @close="closeTag(index)">{{ item.nodeName | ||
| 12 | + }}</el-tag> | ||
| 13 | + </el-form-item> | ||
| 14 | + </el-form> | ||
| 15 | + <el-tabs v-model="activeName" class="node-tabs" type="border-card"> | ||
| 16 | + <el-tab-pane :label="$t('AlertClusterNodeConf.alertTemplateTab')" name="template"> | ||
| 17 | + <el-row style="min-height: 350px;"> | ||
| 18 | + <!-- style="border-right-style:solid;border-color: #E6E8EB;padding-right: 2px;" --> | ||
| 19 | + <el-col :span="4"> | ||
| 20 | + <div> | ||
| 21 | + <el-table size="small" :data="tableDatas" style="width: 100%" ref="templateTable" header-cell-class-name="grid-header" border> | ||
| 22 | + <el-table-column width="50"> | ||
| 23 | + <template #default="scope"> | ||
| 24 | + <el-radio :label="scope.$index + ''" v-model="templateIndex" | ||
| 25 | + @change="getCurrentRow(scope.row.id)"> </el-radio> | ||
| 26 | + </template> | ||
| 27 | + </el-table-column> | ||
| 28 | + <el-table-column prop="templateName" :label="$t('alertTemplate.table[0]')" /> | ||
| 29 | + </el-table> | ||
| 30 | + </div> | ||
| 31 | + </el-col> | ||
| 32 | + <el-col :span="20" style="padding-left: 5px;"> | ||
| 33 | + <el-descriptions :title="t('alertTemplate.detailTitle')"> | ||
| 34 | + | ||
| 35 | + </el-descriptions> | ||
| 36 | + <div class="template-table"> | ||
| 37 | + <el-table size="small" :data="ruleTableDatas" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 38 | + <el-table-column :label="$t('alertRule.table[0]')" prop="ruleName" | ||
| 39 | + width="140"></el-table-column> | ||
| 40 | + <el-table-column :label="$t('alertRule.table[1]')" prop="ruleType" width="100"> | ||
| 41 | + <template #default="scope"> | ||
| 42 | + <span>{{ $t(`alertRule.${scope.row.ruleType}`) }}</span> | ||
| 43 | + </template> | ||
| 44 | + </el-table-column> | ||
| 45 | + <el-table-column prop="level" :label="$t('alertRule.table[2]')" width="100"> | ||
| 46 | + <template #default="scope"> | ||
| 47 | + <span>{{ $t(`alertRule.${scope.row.level}`) }}</span> | ||
| 48 | + </template> | ||
| 49 | + </el-table-column> | ||
| 50 | + <el-table-column prop="ruleExpDesc" :label="$t('alertRule.table[8]')" min-width="200"> | ||
| 51 | + <template #default="scope"> | ||
| 52 | + <span v-html="scope.row.ruleExpDesc"></span> | ||
| 53 | + </template> | ||
| 54 | + </el-table-column> | ||
| 55 | + <el-table-column prop="ruleExpComb" :label="$t('alertRule.table[9]')"> | ||
| 56 | + </el-table-column> | ||
| 57 | + <el-table-column prop="isRepeat" :label="$t('alertRule.table[3]')" width="100"> | ||
| 58 | + <template #default="scope"> | ||
| 59 | + <span>{{ scope.row.isRepeat === 1 ? $t('alertRule.isRepeat') : | ||
| 60 | + $t('alertRule.isNotRepeat') }}</span> | ||
| 61 | + </template> | ||
| 62 | + </el-table-column> | ||
| 63 | + <el-table-column prop="isSilence" :label="$t('alertRule.table[4]')" width="200"> | ||
| 64 | + <template #default="scope"> | ||
| 65 | + <span>{{ scope.row.isSilence === 1 ? scope.row.silenceStartTime + | ||
| 66 | + $t('alertRule.to') + | ||
| 67 | + scope.row.silenceEndTime : $t('alertRule.isNotSilence') }}</span> | ||
| 68 | + </template> | ||
| 69 | + </el-table-column> | ||
| 70 | + <el-table-column prop="alertNotify" :label="$t('alertRule.table[5]')" width="120"> | ||
| 71 | + <template #default="scope"> | ||
| 72 | + <span v-text="showAlertNotify(scope.row.alertNotify)"></span> | ||
| 73 | + </template> | ||
| 74 | + </el-table-column> | ||
| 75 | + <!-- <el-table-column prop="ruleContent" :label="$t('alertRule.table[6]')" /> --> | ||
| 76 | + </el-table> | ||
| 77 | + </div> | ||
| 78 | + </el-col> | ||
| 79 | + </el-row> | ||
| 80 | + </el-tab-pane> | ||
| 81 | + <el-tab-pane :label="$t('AlertClusterNodeConf.alertRuleTab')" name="rule"> | ||
| 82 | + <el-row style="min-height: 350px;"> | ||
| 83 | + <el-table size="small" :data="ruleTableDataList" ref="ruleTable" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 84 | + <el-table-column type="selection" width="55" /> | ||
| 85 | + <el-table-column :label="$t('alertRule.table[0]')" prop="ruleName" width="140"></el-table-column> | ||
| 86 | + <el-table-column :label="$t('alertRule.table[1]')" prop="ruleType" width="100"> | ||
| 87 | + <template #default="scope"> | ||
| 88 | + <span>{{ $t(`alertRule.${scope.row.ruleType}`) }}</span> | ||
| 89 | + </template> | ||
| 90 | + </el-table-column> | ||
| 91 | + <el-table-column prop="level" :label="$t('alertRule.table[2]')" width="100"> | ||
| 92 | + <template #default="scope"> | ||
| 93 | + <span>{{ $t(`alertRule.${scope.row.level}`) }}</span> | ||
| 94 | + </template> | ||
| 95 | + </el-table-column> | ||
| 96 | + <el-table-column prop="ruleExpDesc" :label="$t('alertRule.table[8]')" min-width="200"> | ||
| 97 | + <template #default="scope"> | ||
| 98 | + <span v-html="scope.row.ruleExpDesc"></span> | ||
| 99 | + </template> | ||
| 100 | + </el-table-column> | ||
| 101 | + <el-table-column prop="ruleExpComb" :label="$t('alertRule.table[9]')"> | ||
| 102 | + </el-table-column> | ||
| 103 | + <el-table-column prop="isRepeat" :label="$t('alertRule.table[3]')" width="100"> | ||
| 104 | + <template #default="scope"> | ||
| 105 | + <span>{{ scope.row.isRepeat === 1 ? $t('alertRule.isRepeat') : | ||
| 106 | + $t('alertRule.isNotRepeat') }}</span> | ||
| 107 | + </template> | ||
| 108 | + </el-table-column> | ||
| 109 | + <el-table-column prop="isSilence" :label="$t('alertRule.table[4]')" width="200"> | ||
| 110 | + <template #default="scope"> | ||
| 111 | + <span>{{ scope.row.isSilence === 1 ? scope.row.silenceStartTime + $t('alertRule.to') + | ||
| 112 | + scope.row.silenceEndTime : $t('alertRule.isNotSilence') }}</span> | ||
| 113 | + </template> | ||
| 114 | + </el-table-column> | ||
| 115 | + <el-table-column prop="alertNotify" :label="$t('alertRule.table[5]')" width="120"> | ||
| 116 | + <template #default="scope"> | ||
| 117 | + <span v-text="showAlertNotify(scope.row.alertNotify)"></span> | ||
| 118 | + </template> | ||
| 119 | + </el-table-column> | ||
| 120 | + <el-table-column :label="$t('alertRule.table[7]')" fixed="right"> | ||
| 121 | + <template #default="scope"> | ||
| 122 | + <el-button link type="primary" size="small" @click.prevent="editRule(scope.row)"> | ||
| 123 | + {{ t('app.edit') }} | ||
| 124 | + </el-button> | ||
| 125 | + </template> | ||
| 126 | + </el-table-column> | ||
| 127 | + </el-table> | ||
| 128 | + </el-row> | ||
| 129 | + </el-tab-pane> | ||
| 130 | + </el-tabs> | ||
| 131 | + <el-row style="margin-top: 10px;"> | ||
| 132 | + <el-button type="primary" @click="confirm">{{ t('app.confirm') }}</el-button> | ||
| 133 | + <el-button @click="cancel">{{ t('app.cancel') }}</el-button> | ||
| 134 | + </el-row> | ||
| 135 | + | ||
| 136 | + <el-dialog v-model="visible" :show-close="false" width="30%"> | ||
| 137 | + <template #header="{ titleId, titleClass }"> | ||
| 138 | + <div> | ||
| 139 | + <h4 :id="titleId" :class="titleClass"> | ||
| 140 | + <InfoFilled style="width: 1em; height: 1em; margin-right: 8px" />{{ $t('app.tip') }} | ||
| 141 | + </h4> | ||
| 142 | + </div> | ||
| 143 | + </template> | ||
| 144 | + <div style="margin-bottom: 10px;" | ||
| 145 | + v-text="`${$t('AlertClusterNodeConf.generateTip1') + templateName + $t('AlertClusterNodeConf.generateTip2')}`"> | ||
| 146 | + </div> | ||
| 147 | + <el-input v-model="templateName" size="large"></el-input> | ||
| 148 | + <template #footer> | ||
| 149 | + <span> | ||
| 150 | + <el-button @click="visible = false">{{ t('app.cancel') }}</el-button> | ||
| 151 | + <el-button type="primary" @click="saveTemplateAndConfig">{{ t('app.confirm') }}</el-button> | ||
| 152 | + </span> | ||
| 153 | + </template> | ||
| 154 | + </el-dialog> | ||
| 155 | + </div> | ||
| 156 | + <div v-else> | ||
| 157 | + <TemplateRuleDetail :ruleId="editRuleId" :templateRuleId="editTemplateRuleId" :titleList="titleList" | ||
| 158 | + @updateTemplateRuleSuccess="updateTemplateRuleSuccess" @cancelUpdateTemplateRule="cancelUpdateTemplateRule" /> | ||
| 159 | + </div> | ||
| 160 | +</template> | ||
| 161 | + | ||
| 162 | +<script setup lang='ts'> | ||
| 163 | +import { InfoFilled } from "@element-plus/icons-vue"; | ||
| 164 | +import "element-plus/es/components/message-box/style/index"; | ||
| 165 | +import { useRequest } from "vue-request"; | ||
| 166 | +import request from "@/request"; | ||
| 167 | +import { i18n } from "@/i18n"; | ||
| 168 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 169 | +import { useI18n } from "vue-i18n"; | ||
| 170 | +import { ref, onMounted, nextTick } from 'vue' | ||
| 171 | +import TemplateRuleDetail from "@/views/alert/AlertTemplate/TemplateRuleDetail.vue"; | ||
| 172 | +const { t } = useI18n(); | ||
| 173 | + | ||
| 174 | +const props = withDefaults( | ||
| 175 | + defineProps<{ | ||
| 176 | + clusterNodeList: any[], | ||
| 177 | + }>(), | ||
| 178 | + { | ||
| 179 | + clusterNodeList: () => [], | ||
| 180 | + } | ||
| 181 | +); | ||
| 182 | + | ||
| 183 | +const emit = defineEmits(["updateConfigSuccess", "cancelConfig"]); | ||
| 184 | + | ||
| 185 | +const showMain = ref<boolean>(true) | ||
| 186 | +const ruleTable = ref() | ||
| 187 | +const templateTable = ref() | ||
| 188 | +const activeName = ref<string>('template') | ||
| 189 | +const templateIndex = ref<string>() | ||
| 190 | +const tableDatas = ref<any[]>([]) | ||
| 191 | +const ruleTableDatas = ref<any[]>() | ||
| 192 | +const ruleTableDataList = ref<any[]>([]) | ||
| 193 | +const currentId = ref<number>() | ||
| 194 | +const selectedData = ref<any>() | ||
| 195 | +const visible = ref<boolean>(false) | ||
| 196 | +const templateName = ref<string>('') | ||
| 197 | + | ||
| 198 | +const selectedRuleRows = ref<any[]>([]) | ||
| 199 | +const editTemplateRuleId = ref<number>() | ||
| 200 | +const editRuleId = ref<number>() | ||
| 201 | +const titleList = ref<string[]>([]) | ||
| 202 | +const clusterNodeList0 = ref<any[]>([]) | ||
| 203 | + | ||
| 204 | +const closeTag = (index: number) => { | ||
| 205 | + if (clusterNodeList0.value.length === 1) { | ||
| 206 | + ElMessage({ | ||
| 207 | + message: t('app.keepOneData'), | ||
| 208 | + type: 'warning' | ||
| 209 | + }) | ||
| 210 | + return; | ||
| 211 | + } | ||
| 212 | + clusterNodeList0.value.splice(index, 1) | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +const { data: res, run: requestData } = useRequest( | ||
| 216 | + (clusterNodeId) => { | ||
| 217 | + return request.get(`/alertCenter/api/v1/alertClusterNodeConf/clusterNode/${clusterNodeId}`) | ||
| 218 | + } | ||
| 219 | +) | ||
| 220 | + | ||
| 221 | +const { data: templateRes, run: requestTemplateData } = useRequest( | ||
| 222 | + () => { | ||
| 223 | + return request.get("/alertCenter/api/v1/alertTemplate/list") | ||
| 224 | + }, | ||
| 225 | + { manual: true } | ||
| 226 | +); | ||
| 227 | +const { data: ruleRes, run: requestRuleData } = useRequest( | ||
| 228 | + () => { | ||
| 229 | + return request.get(`/alertCenter/api/v1/alertTemplate/${currentId.value}/rule/list`) | ||
| 230 | + }, | ||
| 231 | + { manual: true } | ||
| 232 | +); | ||
| 233 | +watch(res, (res: any) => { | ||
| 234 | + if (res && res.code === 200) { | ||
| 235 | + selectedData.value = res.data || {} | ||
| 236 | + if (tableDatas.value.length > 0) { | ||
| 237 | + for (let i = 0; i < tableDatas.value.length; i++) { | ||
| 238 | + let row = tableDatas.value[i] | ||
| 239 | + if (row.id === selectedData.value.templateId) { | ||
| 240 | + templateIndex.value = i + '' | ||
| 241 | + currentId.value = row.id | ||
| 242 | + requestRuleData() | ||
| 243 | + break; | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + } | ||
| 247 | + } else { | ||
| 248 | + selectedData.value = {} | ||
| 249 | + } | ||
| 250 | +}); | ||
| 251 | +watch(templateRes, (templateRes: any) => { | ||
| 252 | + if (templateRes && templateRes.code === 200) { | ||
| 253 | + tableDatas.value = templateRes.data || [] | ||
| 254 | + if (selectedData.value && selectedData.value.id) { | ||
| 255 | + for (let i = 0; i < tableDatas.value.length; i++) { | ||
| 256 | + let row = tableDatas.value[i] | ||
| 257 | + if (row.id === selectedData.value.templateId) { | ||
| 258 | + templateIndex.value = i + '' | ||
| 259 | + currentId.value = row.id | ||
| 260 | + requestRuleData() | ||
| 261 | + break; | ||
| 262 | + } | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + } else { | ||
| 266 | + tableDatas.value = [] | ||
| 267 | + ruleTableDatas.value = [] | ||
| 268 | + } | ||
| 269 | +}); | ||
| 270 | +watch(ruleRes, (ruleRes: any) => { | ||
| 271 | + if (ruleRes && ruleRes.code === 200) { | ||
| 272 | + ruleTableDatas.value = ruleRes.data || [] | ||
| 273 | + } else { | ||
| 274 | + ruleTableDatas.value = [] | ||
| 275 | + } | ||
| 276 | +}, { deep: true }); | ||
| 277 | + | ||
| 278 | +const getCurrentRow = (id: number) => { | ||
| 279 | + if (id) { | ||
| 280 | + currentId.value = id | ||
| 281 | + requestRuleData() | ||
| 282 | + } | ||
| 283 | +} | ||
| 284 | + | ||
| 285 | +const showAlertNotify = (val: string) => { | ||
| 286 | + if (!val) { | ||
| 287 | + return '' | ||
| 288 | + } | ||
| 289 | + let arr = val.split(','); | ||
| 290 | + let result = arr.map(item => t(`alertRule.${item}`)).join(',') | ||
| 291 | + return result | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | +const { data: ruleListRes, run: requestRuleList } = useRequest( | ||
| 295 | + () => { | ||
| 296 | + return request.get(`/alertCenter/api/v1/alertRule/ruleList`) | ||
| 297 | + }, | ||
| 298 | + { manual: true } | ||
| 299 | +); | ||
| 300 | +watch(ruleListRes, (ruleListRes: any) => { | ||
| 301 | + if (ruleListRes && ruleListRes.code === 200) { | ||
| 302 | + ruleTableDataList.value = ruleListRes.data | ||
| 303 | + } else { | ||
| 304 | + ruleTableDataList.value = [] | ||
| 305 | + } | ||
| 306 | +}); | ||
| 307 | + | ||
| 308 | +const confirm = () => { | ||
| 309 | + if (activeName.value === 'template') { | ||
| 310 | + if (!currentId.value) { | ||
| 311 | + return | ||
| 312 | + } | ||
| 313 | + if (clusterNodeList0.value.length === 0) { | ||
| 314 | + ElMessage({ | ||
| 315 | + message: t('app.selecteDataTip'), | ||
| 316 | + type: 'error' | ||
| 317 | + }) | ||
| 318 | + return | ||
| 319 | + } | ||
| 320 | + let clusterNodeIds = clusterNodeList0.value.map(item => item.clusterNodeId).join(',') | ||
| 321 | + let param = { | ||
| 322 | + clusterNodeIds, | ||
| 323 | + templateId: currentId.value | ||
| 324 | + } | ||
| 325 | + request.post(`/alertCenter/api/v1/alertClusterNodeConf`, param).then((res: any) => { | ||
| 326 | + if (res && res.code === 200) { | ||
| 327 | + ElMessage({ | ||
| 328 | + message: t('app.saveSuccess'), | ||
| 329 | + type: 'success' | ||
| 330 | + }) | ||
| 331 | + emit("updateConfigSuccess") | ||
| 332 | + } | ||
| 333 | + }) | ||
| 334 | + } else if (activeName.value === 'rule') { | ||
| 335 | + const rows = ruleTable.value.getSelectionRows() || [] | ||
| 336 | + if (rows.length === 0) { | ||
| 337 | + ElMessage({ | ||
| 338 | + message: t('app.selectDatasTip'), | ||
| 339 | + type: 'error' | ||
| 340 | + }) | ||
| 341 | + return | ||
| 342 | + } | ||
| 343 | + visible.value = true | ||
| 344 | + templateName.value = t('alertTemplate.title') + rand() | ||
| 345 | + } | ||
| 346 | +} | ||
| 347 | +const cancel = () => { | ||
| 348 | + emit("cancelConfig") | ||
| 349 | +} | ||
| 350 | + | ||
| 351 | +const editRule = (ruleRow: any) => { | ||
| 352 | + selectedRuleRows.value = ruleTable.value.getSelectionRows() || [] | ||
| 353 | + // let selectedRuleIdArr = selectedRuleRows.value.map((item: any) => item.ruleId) || [] | ||
| 354 | + // if (!selectedRuleIdArr.includes(ruleRow.ruleId)) { | ||
| 355 | + // ElMessage({ | ||
| 356 | + // message: t('app.selectUpdateDataTip'), | ||
| 357 | + // type: 'warning' | ||
| 358 | + // }) | ||
| 359 | + // return; | ||
| 360 | + // } | ||
| 361 | + editTemplateRuleId.value = ruleRow.templateRuleId | ||
| 362 | + editRuleId.value = ruleRow.ruleId | ||
| 363 | + titleList.value = [t('AlertClusterNodeConf.title'), t('AlertClusterNodeConf.detailTitle'), t('alertRule.editTitle')] | ||
| 364 | + showMain.value = false | ||
| 365 | +} | ||
| 366 | +const updateTemplateRuleSuccess = (templateRule: any) => { | ||
| 367 | + for (let i = 0; i < ruleTableDataList.value.length; i++) { | ||
| 368 | + if (ruleTableDataList.value[i].ruleId === templateRule.ruleId) { | ||
| 369 | + ruleTableDataList.value[i] = templateRule | ||
| 370 | + } | ||
| 371 | + } | ||
| 372 | + showMain.value = true | ||
| 373 | + nextTick(() => { | ||
| 374 | + for (let row of selectedRuleRows.value) { | ||
| 375 | + ruleTable.value.toggleRowSelection(row, true) | ||
| 376 | + } | ||
| 377 | + }) | ||
| 378 | +} | ||
| 379 | + | ||
| 380 | +const cancelUpdateTemplateRule = () => { | ||
| 381 | + showMain.value = true | ||
| 382 | + nextTick(() => { | ||
| 383 | + for (let row of selectedRuleRows.value) { | ||
| 384 | + ruleTable.value.toggleRowSelection(row, true) | ||
| 385 | + } | ||
| 386 | + }) | ||
| 387 | +} | ||
| 388 | + | ||
| 389 | +const saveTemplateAndConfig = () => { | ||
| 390 | + const rows = ruleTable.value.getSelectionRows() | ||
| 391 | + let templateRuleReqList = rows.map((item: any) => { | ||
| 392 | + return { templateRuleId: item.templateRuleId, ruleId: item.ruleId } | ||
| 393 | + }) | ||
| 394 | + let clusterNodeIds = clusterNodeList0.value.map(item => item.clusterNodeId).join(',') | ||
| 395 | + let param = { | ||
| 396 | + templateName: templateName.value, | ||
| 397 | + templateRuleReqList, | ||
| 398 | + clusterNodeIds, | ||
| 399 | + } | ||
| 400 | + request.post(`/alertCenter/api/v1/alertClusterNodeConf/alertTemplate`, param).then((res: any) => { | ||
| 401 | + if (res && res.code === 200) { | ||
| 402 | + ElMessage({ | ||
| 403 | + message: t('app.saveSuccess'), | ||
| 404 | + type: 'success' | ||
| 405 | + }) | ||
| 406 | + visible.value = false | ||
| 407 | + activeName.value = 'template' | ||
| 408 | + emit("updateConfigSuccess") | ||
| 409 | + } | ||
| 410 | + }) | ||
| 411 | +} | ||
| 412 | + | ||
| 413 | +const rand = () => { | ||
| 414 | + return Math.floor(Math.random() * (9999 - 1000)) + 1000 | ||
| 415 | +} | ||
| 416 | + | ||
| 417 | +onMounted(() => { | ||
| 418 | + if (props.clusterNodeList && props.clusterNodeList.length === 1) { | ||
| 419 | + requestData(props.clusterNodeList[0].clusterNodeId) | ||
| 420 | + } | ||
| 421 | + clusterNodeList0.value = props.clusterNodeList | ||
| 422 | + requestTemplateData() | ||
| 423 | + requestRuleList() | ||
| 424 | +}) | ||
| 425 | + | ||
| 426 | +</script> | ||
| 427 | +<style scoped lang='scss'> | ||
| 428 | +.node-tabs>.el-tabs__content { | ||
| 429 | + padding: 32px; | ||
| 430 | + color: #6b778c; | ||
| 431 | + font-size: 32px; | ||
| 432 | + font-weight: 600; | ||
| 433 | +} | ||
| 434 | +</style> | ||
| @@ -0,0 +1,150 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('AlertClusterNodeConf.title') }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <div class="search-form"> | ||
| 8 | + <div class="filter"> | ||
| 9 | + <el-button type="primary" @click="addClusterNodeConf">{{ $t('AlertClusterNodeConf.confBtn') }}</el-button> | ||
| 10 | + <!-- <el-button type="primary" @click="setAlertConfig">{{ $t('AlertClusterNodeConf.setInterface') }}</el-button> --> | ||
| 11 | + </div> | ||
| 12 | + <div class="seperator"></div> | ||
| 13 | + <div class="search-form"> | ||
| 14 | + <div class="filter"> | ||
| 15 | + <el-input v-model="formData.nodeName" style="width: 200px" | ||
| 16 | + :placeholder="$t('AlertClusterNodeConf.nodeNamePlaceholder')"> | ||
| 17 | + <template #suffix> | ||
| 18 | + <el-button :icon="Search" @click="search" /> | ||
| 19 | + </template> | ||
| 20 | + </el-input> | ||
| 21 | + </div> | ||
| 22 | + </div> | ||
| 23 | + </div> | ||
| 24 | + <div> | ||
| 25 | + <el-table size="small" :data="tableDatas" ref="table" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 26 | + <el-table-column type="selection" width="55" /> | ||
| 27 | + <el-table-column prop="nodeName" :label="$t('AlertClusterNodeConf.table[0]')" /> | ||
| 28 | + <!-- <el-table-column prop="dbType" :label="$t('AlertClusterNodeConf.table[1]')" /> | ||
| 29 | + <el-table-column prop="hostIp" :label="$t('AlertClusterNodeConf.table[2]')" /> --> | ||
| 30 | + <el-table-column prop="templateName" :label="$t('AlertClusterNodeConf.table[3]')" /> | ||
| 31 | + <el-table-column :label="$t('AlertClusterNodeConf.table[4]')"> | ||
| 32 | + <template #default="scope"> | ||
| 33 | + <el-button link type="primary" size="small" @click="editClusterNodeConf(scope.row)">{{ | ||
| 34 | + $t('AlertClusterNodeConf.confBtn') }}</el-button> | ||
| 35 | + </template> | ||
| 36 | + </el-table-column> | ||
| 37 | + </el-table> | ||
| 38 | + <!-- <div class="pagination"> | ||
| 39 | + <el-pagination v-model:currentPage="page.currentPage" v-model:pageSize="page.pageSize" :total="page.total" | ||
| 40 | + :page-sizes="[10, 20, 30, 40]" layout="total,sizes,prev,pager,next" background small | ||
| 41 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 42 | + </div> --> | ||
| 43 | + </div> | ||
| 44 | + </div> | ||
| 45 | + <div v-else> | ||
| 46 | + <Detail :clusterNodeList="selectedDatas" @updateConfigSuccess="updateConfigSuccess" @cancelConfig="cancelConfig" /> | ||
| 47 | + </div> | ||
| 48 | +</template> | ||
| 49 | + | ||
| 50 | +<script setup lang='ts'> | ||
| 51 | +import { Search } from "@element-plus/icons-vue"; | ||
| 52 | +import "element-plus/es/components/message-box/style/index"; | ||
| 53 | +import { useRequest } from "vue-request"; | ||
| 54 | +import request from "@/request"; | ||
| 55 | +import { i18n } from "@/i18n"; | ||
| 56 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 57 | +import { useI18n } from "vue-i18n"; | ||
| 58 | +import { ref, onMounted } from 'vue' | ||
| 59 | +import Detail from "@/views/alert/AlertClusterNodeConf/Detail.vue" | ||
| 60 | +import { cloneDeep } from "lodash"; | ||
| 61 | +const { t } = useI18n(); | ||
| 62 | + | ||
| 63 | + | ||
| 64 | +const showMain = ref<boolean>(true) | ||
| 65 | + | ||
| 66 | +const formData = ref<any>({ | ||
| 67 | + nodeName: '' | ||
| 68 | +}) | ||
| 69 | +const table = ref(); | ||
| 70 | +const srcTableDatas = ref<any[]>([]) | ||
| 71 | +const tableDatas = ref<any[]>([]) | ||
| 72 | +// const page = reactive({ | ||
| 73 | +// currentPage: 1, | ||
| 74 | +// pageSize: 10, | ||
| 75 | +// total: 0, | ||
| 76 | +// }) | ||
| 77 | +const selectedDatas = ref<any[]>([]) | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +const addClusterNodeConf = () => { | ||
| 81 | + const rows = table.value.getSelectionRows() | ||
| 82 | + if (rows.length === 0) { | ||
| 83 | + ElMessage({ | ||
| 84 | + message: t('alertRecord.tableDataSelectTip'), | ||
| 85 | + type: 'warning', | ||
| 86 | + }) | ||
| 87 | + } else { | ||
| 88 | + selectedDatas.value = rows; | ||
| 89 | + showMain.value = false | ||
| 90 | + } | ||
| 91 | +} | ||
| 92 | +const editClusterNodeConf = (row: any) => { | ||
| 93 | + selectedDatas.value = [] | ||
| 94 | + selectedDatas.value.push(row) | ||
| 95 | + showMain.value = false | ||
| 96 | +} | ||
| 97 | + | ||
| 98 | +const updateConfigSuccess = () => { | ||
| 99 | + showMain.value = true | ||
| 100 | + // page.pageSize = 10 | ||
| 101 | + // page.currentPage = 1 | ||
| 102 | + requestData() | ||
| 103 | +} | ||
| 104 | +const cancelConfig = () => { | ||
| 105 | + showMain.value = true | ||
| 106 | +} | ||
| 107 | +const { data: res, run: requestData } = useRequest( | ||
| 108 | + () => { | ||
| 109 | + let params = { | ||
| 110 | + } | ||
| 111 | + return request.get("/alertCenter/api/v1/alertClusterNodeConf", params) | ||
| 112 | + }, | ||
| 113 | + { manual: true } | ||
| 114 | +) | ||
| 115 | +watch(res, (res: any) => { | ||
| 116 | + if (res && res.code === 200) { | ||
| 117 | + // tableDatas.value = res.rows || [] | ||
| 118 | + // page.total = res.total | ||
| 119 | + tableDatas.value = srcTableDatas.value = res.data || [] | ||
| 120 | + } else { | ||
| 121 | + // tableDatas.value = [] | ||
| 122 | + // page.total = 0 | ||
| 123 | + srcTableDatas.value = [] | ||
| 124 | + tableDatas.value = [] | ||
| 125 | + } | ||
| 126 | +}) | ||
| 127 | + | ||
| 128 | +const search = () => { | ||
| 129 | + if (!formData.value.nodeName) { | ||
| 130 | + tableDatas.value = cloneDeep(srcTableDatas.value) | ||
| 131 | + } else { | ||
| 132 | + tableDatas.value = srcTableDatas.value.filter(item => item.nodeName.indexOf(formData.value.nodeName) !== -1) | ||
| 133 | + } | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +// const handleSizeChange = (val: any) => { | ||
| 137 | +// page.pageSize = val | ||
| 138 | +// requestData() | ||
| 139 | +// } | ||
| 140 | +// const handleCurrentChange = (val: any) => { | ||
| 141 | +// page.currentPage = val | ||
| 142 | +// requestData() | ||
| 143 | +// } | ||
| 144 | + | ||
| 145 | +onMounted(() => { | ||
| 146 | + requestData() | ||
| 147 | +}) | ||
| 148 | +</script> | ||
| 149 | +<style scoped lang='scss'> | ||
| 150 | +</style> | ||
| @@ -0,0 +1,433 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('alertRecord.title') }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <div class="search-form"> | ||
| 8 | + <div class="filter"> | ||
| 9 | + <el-icon color="#F56C6C"> | ||
| 10 | + <Bell /> | ||
| 11 | + </el-icon> | ||
| 12 | + <span>{{ $t(`alertRecord.alertTotal`) }}:</span><span>{{ statisticsData.totalNum }}</span> | ||
| 13 | + <span style="margin-left: 20px;">{{ $t(`alertRecord.unread`) }}:</span><span>{{ statisticsData.unReadNum | ||
| 14 | + }}</span> | ||
| 15 | + <span style="margin-left: 20px;">{{ $t(`alertRecord.read`) }}:</span><span>{{ statisticsData.readNum | ||
| 16 | + }}</span> | ||
| 17 | + </div> | ||
| 18 | + <div class="seperator"></div> | ||
| 19 | + <div class="filter"> | ||
| 20 | + <span>{{ $t(`alertRecord.cluster`) }}: </span> | ||
| 21 | + <el-cascader v-model="formData.clusterNodeId" :options="clusterList" @change="changeClusterNode" clearable/> | ||
| 22 | + </div> | ||
| 23 | + <div class="filter"> | ||
| 24 | + <span class="demonstration">{{ $t(`alertRecord.alertTimeRange`) }}: </span> | ||
| 25 | + <el-date-picker v-model="alertTimeRange" type="datetimerange" range-separator="~" | ||
| 26 | + format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" | ||
| 27 | + :start-placeholder="t(`alertRecord.startTimePlaceholder`)" | ||
| 28 | + :end-placeholder="t(`alertRecord.endTimePlaceholder`)" @change="changeAlertTimeRange" /> | ||
| 29 | + </div> | ||
| 30 | + </div> | ||
| 31 | + <el-row style="width: 100%;"> | ||
| 32 | + <el-col :span="8"> | ||
| 33 | + <RecordPid :datas="recordStatusData" :title="$t('alertRecord.recordStatusTip')"></RecordPid> | ||
| 34 | + </el-col> | ||
| 35 | + <el-col :span="8"> | ||
| 36 | + <RecordPid :datas="alertStatusData" :title="$t('alertRecord.alertStatusTip')"></RecordPid> | ||
| 37 | + </el-col> | ||
| 38 | + <el-col :span="8"> | ||
| 39 | + <RecordPid :datas="levelData" :title="$t('alertRecord.levelTip')"></RecordPid> | ||
| 40 | + </el-col> | ||
| 41 | + </el-row> | ||
| 42 | + <div class="record-table"> | ||
| 43 | + <div class="search-form" style="margin-bottom: 5px !important;"> | ||
| 44 | + <div class="filter"> | ||
| 45 | + <el-button @click="markAsUnread">{{ t('alertRecord.markAsUnread') }}</el-button> | ||
| 46 | + <el-button @click="markAsRead">{{ t('alertRecord.markAsRead') }}</el-button> | ||
| 47 | + </div> | ||
| 48 | + <div class="seperator"></div> | ||
| 49 | + <div class="filter"> | ||
| 50 | + <span>{{ $t('alertRecord.recordStatus') }}: </span> | ||
| 51 | + <el-checkbox-group v-model="formData.recordStatus" @change="changeRecordStatus"> | ||
| 52 | + <el-checkbox label="0">{{ $t(`alertRecord.unread`) }}</el-checkbox> | ||
| 53 | + <el-checkbox label="1">{{ $t(`alertRecord.read`) }}</el-checkbox> | ||
| 54 | + </el-checkbox-group> | ||
| 55 | + <el-divider direction="vertical" /> | ||
| 56 | + </div> | ||
| 57 | + <div class="filter"> | ||
| 58 | + <span>{{ $t('alertRecord.alertStatus') }}: </span> | ||
| 59 | + <el-checkbox-group v-model="formData.alertStatus" @change="changeAlertStatus"> | ||
| 60 | + <el-checkbox label="0">{{ $t(`alertRecord.alerting`) }}</el-checkbox> | ||
| 61 | + <el-checkbox label="1">{{ $t(`alertRecord.alerted`) }}</el-checkbox> | ||
| 62 | + </el-checkbox-group> | ||
| 63 | + <el-divider direction="vertical" /> | ||
| 64 | + </div> | ||
| 65 | + <div class="filter"> | ||
| 66 | + <span>{{ $t('alertRecord.level') }}: </span> | ||
| 67 | + <el-checkbox-group v-model="formData.alertLevel" @change="changeLevel"> | ||
| 68 | + <el-checkbox label="serious">{{ $t(`alertRule.serious`) }}</el-checkbox> | ||
| 69 | + <el-checkbox label="warn">{{ $t(`alertRule.warn`) }}</el-checkbox> | ||
| 70 | + <el-checkbox label="info">{{ $t(`alertRule.info`) }}</el-checkbox> | ||
| 71 | + </el-checkbox-group> | ||
| 72 | + </div> | ||
| 73 | + </div> | ||
| 74 | + <el-table size="small" :data="tableDatas" style="width: 100%" ref="recordTable" | ||
| 75 | + header-cell-class-name="grid-header" border> | ||
| 76 | + <el-table-column type="selection" width="55" /> | ||
| 77 | + <el-table-column prop="clusterNodeName" min-width="150" :label="$t('alertRecord.table[0]')" /> | ||
| 78 | + <!-- <el-table-column prop="hostIp" :label="$t('alertRecord.table[1]')" /> | ||
| 79 | + <el-table-column prop="dbType" :label="$t('alertRecord.table[2]')" /> --> | ||
| 80 | + <el-table-column prop="templateName" :label="$t('alertRecord.table[3]')" /> | ||
| 81 | + <el-table-column prop="templateRuleName" :label="$t('alertRecord.table[4]')" /> | ||
| 82 | + <el-table-column prop="templateRuleType" :label="$t('alertRecord.table[5]')"> | ||
| 83 | + <template #default="scope"> | ||
| 84 | + <span>{{ $t(`alertRule.${scope.row.templateRuleType}`) }}</span> | ||
| 85 | + </template> | ||
| 86 | + </el-table-column> | ||
| 87 | + <el-table-column prop="level" :label="$t('alertRecord.table[6]')"> | ||
| 88 | + <template #default="scope"> | ||
| 89 | + <svg-icon name="circle1" style="margin-right: 2px;" v-if="scope.row.level === 'info'" /> | ||
| 90 | + <svg-icon name="circle2" style="margin-right: 2px;" v-if="scope.row.level === 'warn'" /> | ||
| 91 | + <svg-icon name="circle3" style="margin-right: 2px;" v-if="scope.row.level === 'serious'" /> | ||
| 92 | + <span>{{ $t(`alertRule.${scope.row.level}`) }}</span> | ||
| 93 | + </template> | ||
| 94 | + </el-table-column> | ||
| 95 | + <el-table-column prop="startTime" :label="$t('alertRecord.table[7]')" /> | ||
| 96 | + <el-table-column prop="endTime" :label="$t('alertRecord.table[8]')" /> | ||
| 97 | + <el-table-column prop="duration" :label="$t('alertRecord.table[9]')"> | ||
| 98 | + <template #default="scope"> | ||
| 99 | + <span>{{ durationFormat(scope.row.duration) }}</span> | ||
| 100 | + </template> | ||
| 101 | + </el-table-column> | ||
| 102 | + <el-table-column prop="alertStatus" :label="$t('alertRecord.table[10]')"> | ||
| 103 | + <template #default="scope"> | ||
| 104 | + <span v-if="scope.row.alertStatus === 0"><svg-icon name="circle3" style="margin-right: 2px;" />{{ | ||
| 105 | + $t(`alertRecord.alerting`) }}</span> | ||
| 106 | + <span v-if="scope.row.alertStatus === 1"><svg-icon name="circle1" style="margin-right: 2px;" />{{ | ||
| 107 | + $t(`alertRecord.alerted`) }}</span> | ||
| 108 | + </template> | ||
| 109 | + </el-table-column> | ||
| 110 | + <el-table-column prop="notifyWayName" :label="$t('alertRecord.table[11]')" /> | ||
| 111 | + <el-table-column prop="recordStatus" :label="$t('alertRecord.table[12]')"> | ||
| 112 | + <template #default="scope"> | ||
| 113 | + <span v-if="scope.row.recordStatus === 0">{{ $t(`alertRecord.unread`) }}</span> | ||
| 114 | + <span v-if="scope.row.recordStatus === 1">{{ $t(`alertRecord.read`) }}</span> | ||
| 115 | + </template> | ||
| 116 | + </el-table-column> | ||
| 117 | + <el-table-column :label="$t('alertRecord.table[13]')" fixed="right"> | ||
| 118 | + <template #default="scope"> | ||
| 119 | + <el-button link type="primary" size="small" @click="showDetail(scope.row.id)">{{ $t('app.view') | ||
| 120 | + }}</el-button> | ||
| 121 | + </template> | ||
| 122 | + </el-table-column> | ||
| 123 | + </el-table> | ||
| 124 | + <div class="pagination"> | ||
| 125 | + <el-pagination v-model:currentPage="page.currentPage" v-model:pageSize="page.pageSize" :total="page.total" | ||
| 126 | + :page-sizes="[10, 20, 30, 40]" layout="total,sizes,prev,pager,next" background small | ||
| 127 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 128 | + </div> | ||
| 129 | + </div> | ||
| 130 | + | ||
| 131 | + </div> | ||
| 132 | +</template> | ||
| 133 | + | ||
| 134 | +<script setup lang='ts'> | ||
| 135 | +import { Bell } from "@element-plus/icons-vue"; | ||
| 136 | +import "element-plus/es/components/message-box/style/index"; | ||
| 137 | +import { useRequest } from "vue-request"; | ||
| 138 | +import request from "@/request"; | ||
| 139 | +import { i18n } from "@/i18n"; | ||
| 140 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 141 | +import { useI18n } from "vue-i18n"; | ||
| 142 | +import RecordPid from "@/views/alert/AlertRecord/components/RecordPie.vue" | ||
| 143 | +const { t } = useI18n(); | ||
| 144 | + | ||
| 145 | +const recordTable = ref() | ||
| 146 | +const formData = ref<any>({ | ||
| 147 | + clusterNodeId: [], | ||
| 148 | + startTime: '', | ||
| 149 | + endTime: '', | ||
| 150 | + recordStatus: [], | ||
| 151 | + alertStatus: [], | ||
| 152 | + alertLevel: [] | ||
| 153 | +}) | ||
| 154 | +const clusterList = ref<Array<any>[]>([]) | ||
| 155 | +const alertTimeRange = ref<Array<any>[]>([]) | ||
| 156 | +const statisticsData = ref<any>({}) | ||
| 157 | +const recordStatusData = ref<any[]>([]) | ||
| 158 | +const alertStatusData = ref<any[]>([]) | ||
| 159 | +const levelData = ref<any[]>([]) | ||
| 160 | +const tableDatas = ref<any[]>([]) | ||
| 161 | +const page = reactive({ | ||
| 162 | + currentPage: 1, | ||
| 163 | + pageSize: 10, | ||
| 164 | + total: 0, | ||
| 165 | +}) | ||
| 166 | +const { data: statisticsRes, run: requestStatisticsData } = useRequest( | ||
| 167 | + () => { | ||
| 168 | + return request.get("/alertCenter/api/v1/alertRecord/statistics") | ||
| 169 | + }, | ||
| 170 | + { manual: true } | ||
| 171 | +); | ||
| 172 | +watch(statisticsRes, (statisticsRes: any) => { | ||
| 173 | + if (statisticsRes && statisticsRes.code === 200) { | ||
| 174 | + statisticsData.value = statisticsRes.data | ||
| 175 | + } | ||
| 176 | +}); | ||
| 177 | +const { data: pieRes, run: requestPisData } = useRequest( | ||
| 178 | + () => { | ||
| 179 | + let param = { | ||
| 180 | + clusterNodeId: formData.value.clusterNodeId && formData.value.clusterNodeId.length > 1 ? formData.value.clusterNodeId[1] : '', | ||
| 181 | + startTime: formData.value.startTime, | ||
| 182 | + endTime: formData.value.endTime | ||
| 183 | + } | ||
| 184 | + return request.get("/alertCenter/api/v1/alertRecord/statistics", param) | ||
| 185 | + }, | ||
| 186 | + { manual: true } | ||
| 187 | +); | ||
| 188 | +watch(pieRes, (pieRes: any) => { | ||
| 189 | + if (pieRes && pieRes.code === 200) { | ||
| 190 | + let data = pieRes.data | ||
| 191 | + recordStatusData.value = [{ | ||
| 192 | + name: t(`alertRecord.unread`), | ||
| 193 | + value: data.unReadNum, | ||
| 194 | + itemStyle: { | ||
| 195 | + color: '#3DC7FF' | ||
| 196 | + } | ||
| 197 | + }, { | ||
| 198 | + name: t(`alertRecord.read`), | ||
| 199 | + value: data.readNum, | ||
| 200 | + itemStyle: { | ||
| 201 | + color: '#246CFF' | ||
| 202 | + } | ||
| 203 | + }] | ||
| 204 | + alertStatusData.value = [{ | ||
| 205 | + name: t(`alertRecord.alerting`), | ||
| 206 | + value: data.firingNum, | ||
| 207 | + itemStyle: { | ||
| 208 | + color: '#246CFF' | ||
| 209 | + } | ||
| 210 | + }, { | ||
| 211 | + name: t(`alertRecord.alerted`), | ||
| 212 | + value: data.recoverNum, | ||
| 213 | + itemStyle: { | ||
| 214 | + color: '#3DC7FF' | ||
| 215 | + } | ||
| 216 | + }] | ||
| 217 | + levelData.value = [{ | ||
| 218 | + name: t(`alertRule.serious`), | ||
| 219 | + value: data.seriousNum, | ||
| 220 | + itemStyle: { | ||
| 221 | + color: '#F53F3F' | ||
| 222 | + } | ||
| 223 | + }, { | ||
| 224 | + name: t(`alertRule.warn`), | ||
| 225 | + value: data.warnNum, | ||
| 226 | + itemStyle: { | ||
| 227 | + color: '#FF7D00' | ||
| 228 | + } | ||
| 229 | + }, { | ||
| 230 | + name: t(`alertRule.info`), | ||
| 231 | + value: data.infoNum, | ||
| 232 | + itemStyle: { | ||
| 233 | + color: '#246CFF' | ||
| 234 | + } | ||
| 235 | + }] | ||
| 236 | + } | ||
| 237 | +}); | ||
| 238 | +const { data: res, run: requestData } = useRequest( | ||
| 239 | + () => { | ||
| 240 | + let params = { | ||
| 241 | + clusterNodeId: formData.value.clusterNodeId && formData.value.clusterNodeId.length > 1 ? formData.value.clusterNodeId[1] : '', | ||
| 242 | + startTime: formData.value.startTime, | ||
| 243 | + endTime: formData.value.endTime, | ||
| 244 | + recordStatus: formData.value.recordStatus && formData.value.recordStatus.length > 0 ? formData.value.recordStatus.join(',') : '', | ||
| 245 | + alertStatus: formData.value.alertStatus && formData.value.alertStatus.length > 0 ? formData.value.alertStatus.join(',') : '', | ||
| 246 | + alertLevel: formData.value.alertLevel && formData.value.alertLevel.length > 0 ? formData.value.alertLevel.join(',') : '' | ||
| 247 | + } | ||
| 248 | + params = Object.assign(params, { pageNum: page.currentPage, pageSize: page.pageSize }) | ||
| 249 | + return request.get("/alertCenter/api/v1/alertRecord", params) | ||
| 250 | + }, | ||
| 251 | + { manual: true } | ||
| 252 | +); | ||
| 253 | +watch(res, (res: any) => { | ||
| 254 | + if (res && res.code === 200) { | ||
| 255 | + tableDatas.value = res.rows | ||
| 256 | + page.total = res.total | ||
| 257 | + } | ||
| 258 | +}); | ||
| 259 | +const durationFormat = (val: any) => { | ||
| 260 | + if (typeof val === 'number') { | ||
| 261 | + if (val <= 0) { | ||
| 262 | + return '00:00:00'; | ||
| 263 | + } else { | ||
| 264 | + let hh = parseInt(val / 3600); | ||
| 265 | + let shh = val - hh * 3600; | ||
| 266 | + let ii = parseInt(shh / 60); | ||
| 267 | + let ss = shh - ii * 60; | ||
| 268 | + return (hh < 10 ? '0' + hh : hh) + ':' + (ii < 10 ? '0' + ii : ii) + ':' + (ss < 10 ? '0' + ss : ss); | ||
| 269 | + } | ||
| 270 | + } else { | ||
| 271 | + return '00:00:00'; | ||
| 272 | + } | ||
| 273 | +} | ||
| 274 | +const { data: opsClusterData } = useRequest(() => request.get("/alertCenter/api/v1/environment/cluster"), { manual: false }); | ||
| 275 | +const treeTransform = (arr: any) => { | ||
| 276 | + let obj: any = []; | ||
| 277 | + if (arr instanceof Array) { | ||
| 278 | + arr.forEach((item) => { | ||
| 279 | + obj.push({ | ||
| 280 | + label: item.clusterId ? item.clusterId : (item.azName ? item.azName + "_" : "") + item.publicIp + ":" + item.dbPort + (item.clusterRole ? "(" + item.clusterRole + ")" : ""), | ||
| 281 | + value: item.clusterId ? item.clusterId : item.nodeId, | ||
| 282 | + children: treeTransform(item.clusterNodes), | ||
| 283 | + }); | ||
| 284 | + }); | ||
| 285 | + } | ||
| 286 | + return obj; | ||
| 287 | +}; | ||
| 288 | +watch(opsClusterData, (res: any) => { | ||
| 289 | + if (res && res.code === 200) { | ||
| 290 | + clusterList.value = treeTransform(res.data); | ||
| 291 | + } | ||
| 292 | +}); | ||
| 293 | + | ||
| 294 | +const changeAlertTimeRange = () => { | ||
| 295 | + if (alertTimeRange.value && alertTimeRange.value.length === 2) { | ||
| 296 | + formData.value.startTime = alertTimeRange.value[0] | ||
| 297 | + formData.value.endTime = alertTimeRange.value[1] | ||
| 298 | + } else { | ||
| 299 | + formData.value.startTime = '' | ||
| 300 | + formData.value.endTime = '' | ||
| 301 | + } | ||
| 302 | + requestPisData() | ||
| 303 | + requestData() | ||
| 304 | +} | ||
| 305 | + | ||
| 306 | +const changeClusterNode = () => { | ||
| 307 | + requestPisData() | ||
| 308 | + requestData() | ||
| 309 | +} | ||
| 310 | + | ||
| 311 | +const changeRecordStatus = () => { | ||
| 312 | + requestData() | ||
| 313 | +} | ||
| 314 | +const changeAlertStatus = () => { | ||
| 315 | + requestData() | ||
| 316 | +} | ||
| 317 | +const changeLevel = () => { | ||
| 318 | + requestData() | ||
| 319 | +} | ||
| 320 | +const markAsUnread = () => { | ||
| 321 | + const rows = recordTable.value.getSelectionRows(); | ||
| 322 | + if (rows.length === 0) { | ||
| 323 | + ElMessage({ | ||
| 324 | + message: t('alertRecord.tableDataSelectTip'), | ||
| 325 | + type: 'warning', | ||
| 326 | + }) | ||
| 327 | + } else { | ||
| 328 | + const ids = rows.map((item: any) => item.id).join(',') | ||
| 329 | + request.post(`/alertCenter/api/v1/alertRecord/markAsUnread?ids=${ids}`).then((res: any) => { | ||
| 330 | + if (res && res.code === 200) { | ||
| 331 | + requestStatisticsData() | ||
| 332 | + requestPisData() | ||
| 333 | + requestData() | ||
| 334 | + } | ||
| 335 | + }) | ||
| 336 | + } | ||
| 337 | +} | ||
| 338 | +const markAsRead = () => { | ||
| 339 | + const rows = recordTable.value.getSelectionRows(); | ||
| 340 | + if (rows.length === 0) { | ||
| 341 | + ElMessage({ | ||
| 342 | + message: t('alertRecord.tableDataSelectTip'), | ||
| 343 | + type: 'warning', | ||
| 344 | + }) | ||
| 345 | + } else { | ||
| 346 | + const ids = rows.map((item: any) => item.id).join(',') | ||
| 347 | + request.post(`/alertCenter/api/v1/alertRecord/markAsRead?ids=${ids}`).then((res: any) => { | ||
| 348 | + if (res && res.code === 200) { | ||
| 349 | + requestStatisticsData() | ||
| 350 | + requestPisData() | ||
| 351 | + requestData() | ||
| 352 | + } | ||
| 353 | + }) | ||
| 354 | + } | ||
| 355 | +} | ||
| 356 | +const router = useRouter(); | ||
| 357 | + | ||
| 358 | +const handleSizeChange = (val: any) => { | ||
| 359 | + page.currentPage = val | ||
| 360 | + requestData() | ||
| 361 | +} | ||
| 362 | +const handleCurrentChange = (val: any) => { | ||
| 363 | + page.pageSize = val | ||
| 364 | + requestData() | ||
| 365 | +} | ||
| 366 | + | ||
| 367 | +const showDetail = (id: number) => { | ||
| 368 | + if (process.env.mode === 'production') { | ||
| 369 | + window.$wujie?.props.methods.jump({ | ||
| 370 | + name: `Static-pluginAlert-centerVemAlertRecordDetail`, | ||
| 371 | + query: { | ||
| 372 | + id, | ||
| 373 | + }, | ||
| 374 | + }); | ||
| 375 | + } else { | ||
| 376 | + router.push({ | ||
| 377 | + path: `/vem/alert/recordDetail`, | ||
| 378 | + query: { | ||
| 379 | + id, | ||
| 380 | + }, | ||
| 381 | + }); | ||
| 382 | + } | ||
| 383 | +} | ||
| 384 | + | ||
| 385 | +onMounted(() => { | ||
| 386 | + requestStatisticsData() | ||
| 387 | + requestPisData() | ||
| 388 | + requestData() | ||
| 389 | + | ||
| 390 | + const wujie = window.$wujie; | ||
| 391 | + // Judge whether it is a plug-in environment or a local environment through wujie | ||
| 392 | + if (wujie) { | ||
| 393 | + // Monitoring platform language change | ||
| 394 | + wujie?.bus.$on('opengauss-locale-change', (val: string) => { | ||
| 395 | + console.log('log-search catch locale change'); | ||
| 396 | + nextTick(() => { | ||
| 397 | + requestPisData() | ||
| 398 | + }); | ||
| 399 | + }); | ||
| 400 | + // wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 401 | + // nextTick(() => { | ||
| 402 | + // requestPisData() | ||
| 403 | + // }); | ||
| 404 | + // }); | ||
| 405 | + } | ||
| 406 | +}) | ||
| 407 | +</script> | ||
| 408 | +<style scoped lang='scss'> | ||
| 409 | +@use 'sass:math'; | ||
| 410 | +@use '@/assets/style/color.scss' as *; | ||
| 411 | +@use 'sass:map'; | ||
| 412 | + | ||
| 413 | +.record-table { | ||
| 414 | + margin-top: 17px; | ||
| 415 | + | ||
| 416 | + // border: 1px solid #D9D9D9 | ||
| 417 | + .pagination { | ||
| 418 | + margin-top: 5px; | ||
| 419 | + } | ||
| 420 | + | ||
| 421 | + .search-form { | ||
| 422 | + .el-button { | ||
| 423 | + font-size: 14px !important; | ||
| 424 | + padding: 8px 16px !important; | ||
| 425 | + border: 1px solid var(--button-1-border) !important; | ||
| 426 | + border-radius: 2px; | ||
| 427 | + font-weight: 400 !important; | ||
| 428 | + color: var(--button-1-color) !important; | ||
| 429 | + background-color: var(--button-1-background) !important; | ||
| 430 | + } | ||
| 431 | + } | ||
| 432 | +} | ||
| 433 | +</style> | ||
| @@ -0,0 +1,223 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('alertRecord.title') }}</el-breadcrumb-item> | ||
| 5 | + <el-breadcrumb-item>{{ t('alertRecord.detailTitle') }}</el-breadcrumb-item> | ||
| 6 | + </el-breadcrumb> | ||
| 7 | + <el-divider /> | ||
| 8 | + <el-row> | ||
| 9 | + <el-col :span="8"> | ||
| 10 | + <div class="record-detail"> | ||
| 11 | + <el-space wrap> | ||
| 12 | + <el-icon size="18" color="red"> | ||
| 13 | + <Bell /> | ||
| 14 | + </el-icon> | ||
| 15 | + <h5 class="title">{{ t('alertRecord.alertInstance') }}</h5> | ||
| 16 | + </el-space> | ||
| 17 | + <el-form label-position="right" label-width="120"> | ||
| 18 | + <el-form-item :label="$t('alertRecord.clusterName') + ':'" style="margin-bottom: 5px !important"> | ||
| 19 | + <span>{{ formData.clusterId }}</span> | ||
| 20 | + </el-form-item> | ||
| 21 | + <el-form-item :label="$t('alertRecord.IPAndPort') + ':'" style="margin-bottom: 5px !important"> | ||
| 22 | + <span>{{ formData.hostIpAndPort }}</span> | ||
| 23 | + </el-form-item> | ||
| 24 | + <el-form-item :label="$t('alertRecord.nodeRole') + ':'" style="margin-bottom: 5px !important"> | ||
| 25 | + <span>{{ formData.nodeRole }}</span> | ||
| 26 | + </el-form-item> | ||
| 27 | + </el-form> | ||
| 28 | + </div> | ||
| 29 | + </el-col> | ||
| 30 | + <el-col :span="8"> | ||
| 31 | + <div class="record-detail"> | ||
| 32 | + <el-space wrap> | ||
| 33 | + <el-icon size="18" color="red"> | ||
| 34 | + <Bell /> | ||
| 35 | + </el-icon> | ||
| 36 | + <h5 class="title">{{ t('alertRecord.alertRule') }}</h5> | ||
| 37 | + </el-space> | ||
| 38 | + <el-form label-position="right" label-width="120"> | ||
| 39 | + <el-form-item :label="$t('alertRule.ruleName') + ':'" style="margin-bottom: 5px !important"> | ||
| 40 | + <span>{{ formData.templateRuleName }}</span> | ||
| 41 | + </el-form-item> | ||
| 42 | + <el-form-item :label="$t('alertRecord.table[6]') + ':'" style="margin-bottom: 5px !important"> | ||
| 43 | + <span>{{ $t(`alertRule.${formData.level}`) }}</span> | ||
| 44 | + </el-form-item> | ||
| 45 | + <el-form-item :label="$t('alertRecord.table[3]') + ':'" style="margin-bottom: 5px !important"> | ||
| 46 | + <span>{{ formData.templateName }}</span> | ||
| 47 | + </el-form-item> | ||
| 48 | + <el-form-item :label="$t('alertRecord.table[11]') + ':'" style="margin-bottom: 5px !important"> | ||
| 49 | + <span>{{ formData.notifyWayName }}</span> | ||
| 50 | + </el-form-item> | ||
| 51 | + <el-form-item :label="$t('alertRecord.alertContent') + ':'" style="margin-bottom: 5px !important"> | ||
| 52 | + <span>{{ formData.alertContent }}</span> | ||
| 53 | + </el-form-item> | ||
| 54 | + </el-form> | ||
| 55 | + </div> | ||
| 56 | + </el-col> | ||
| 57 | + <el-col :span="8"> | ||
| 58 | + <div class="record-detail"> | ||
| 59 | + <el-space wrap> | ||
| 60 | + <el-icon size="18" color="red"> | ||
| 61 | + <Bell /> | ||
| 62 | + </el-icon> | ||
| 63 | + <h5 class="title">{{ t('alertRecord.alertStatus') }}</h5> | ||
| 64 | + </el-space> | ||
| 65 | + <el-form label-position="right" label-width="120"> | ||
| 66 | + <el-form-item :label="$t('alertRecord.table[7]') + ':'" style="margin-bottom: 5px !important"> | ||
| 67 | + <span>{{ formData.startTime }}</span> | ||
| 68 | + </el-form-item> | ||
| 69 | + <el-form-item :label="$t('alertRecord.table[8]') + ':'" style="margin-bottom: 5px !important"> | ||
| 70 | + <span>{{ formData.endTime }}</span> | ||
| 71 | + </el-form-item> | ||
| 72 | + <el-form-item :label="$t('alertRecord.table[9]') + ':'" style="margin-bottom: 5px !important"> | ||
| 73 | + <span>{{ durationFormat(formData.duration) }}</span> | ||
| 74 | + </el-form-item> | ||
| 75 | + <el-form-item :label="$t('alertRecord.table[12]') + ':'" style="margin-bottom: 5px !important"> | ||
| 76 | + <el-switch v-model="formData.recordStatus" :active-value="1" :inactive-value="0" | ||
| 77 | + @change="markAs" /> | ||
| 78 | + </el-form-item> | ||
| 79 | + </el-form> | ||
| 80 | + </div> | ||
| 81 | + </el-col> | ||
| 82 | + </el-row> | ||
| 83 | + <el-divider style="margin: 5px 0;" /> | ||
| 84 | + <div style="min-height: 370px;" v-if="formData.templateRuleType === 'index'"> | ||
| 85 | + <h5 class="title">{{ t('alertRecord.alertRelationView') }}</h5> | ||
| 86 | + <div v-for="(item, index) in relationDatas" style="width: 100%; height: 200px;margin-top: 20px;" :key="index"> | ||
| 87 | + <RecordLine :title="item.name" :datas="item.datas" :unit="item.unit" /> | ||
| 88 | + </div> | ||
| 89 | + </div> | ||
| 90 | + </div> | ||
| 91 | +</template> | ||
| 92 | + | ||
| 93 | +<script setup lang='ts'> | ||
| 94 | +import "element-plus/es/components/message-box/style/index"; | ||
| 95 | +import { useRequest } from "vue-request"; | ||
| 96 | +import request from "@/request"; | ||
| 97 | +import { Bell } from "@element-plus/icons-vue"; | ||
| 98 | +import { useI18n } from "vue-i18n"; | ||
| 99 | +import RecordLine from "@/views/alert/AlertRecord/components/RecordLine.vue" | ||
| 100 | +const { t } = useI18n(); | ||
| 101 | +const theme = localStorage.getItem('theme'); | ||
| 102 | +const color = ref<string>(theme === 'dark' ? '#d4d4d4' : '#1d212a') | ||
| 103 | +const background = ref<string>(theme === 'dark' ? '#303030' : '#F5F7FB') | ||
| 104 | + | ||
| 105 | +const offsetHeight = ref<number>() | ||
| 106 | +const carHeight = ref<number>() | ||
| 107 | +const formData = ref<any>({}) | ||
| 108 | +const relationDatas = ref<any[]>([]) | ||
| 109 | + | ||
| 110 | +const { data: res, run: requestData } = useRequest( | ||
| 111 | + (id: number) => { | ||
| 112 | + return request.get(`/alertCenter/api/v1/alertRecord/${id}`) | ||
| 113 | + }, | ||
| 114 | + { manual: true } | ||
| 115 | +); | ||
| 116 | +watch(res, (res: any) => { | ||
| 117 | + if (res && res.code === 200) { | ||
| 118 | + formData.value = res.data | ||
| 119 | + } | ||
| 120 | +}); | ||
| 121 | + | ||
| 122 | +const markAs = (val: any) => { | ||
| 123 | + if (formData.value.id) { | ||
| 124 | + if (val === 0) { | ||
| 125 | + request.post(`/alertCenter/api/v1/alertRecord/markAsUnread?ids=${formData.value.id}`).then((res: any) => { | ||
| 126 | + if (res && res.code === 200) { | ||
| 127 | + requestData(formData.value.id) | ||
| 128 | + } | ||
| 129 | + }) | ||
| 130 | + } | ||
| 131 | + if (val === 1) { | ||
| 132 | + request.post(`/alertCenter/api/v1/alertRecord/markAsRead?ids=${formData.value.id}`).then((res: any) => { | ||
| 133 | + if (res && res.code === 200) { | ||
| 134 | + requestData(formData.value.id) | ||
| 135 | + } | ||
| 136 | + }) | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | +} | ||
| 140 | + | ||
| 141 | +const { data: relationRes, run: requestRelationData } = useRequest( | ||
| 142 | + (id: number) => { | ||
| 143 | + return request.get(`/alertCenter/api/v1/alertRecord/${id}/relation`) | ||
| 144 | + }, | ||
| 145 | + { manual: true } | ||
| 146 | +); | ||
| 147 | +watch(relationRes, (relationRes: any) => { | ||
| 148 | + if (relationRes && relationRes.code === 200) { | ||
| 149 | + relationDatas.value = relationRes.data | ||
| 150 | + console.log(relationDatas.value) | ||
| 151 | + } | ||
| 152 | +}); | ||
| 153 | + | ||
| 154 | +const durationFormat = (val: any) => { | ||
| 155 | + if (typeof val === 'number') { | ||
| 156 | + if (val <= 0) { | ||
| 157 | + return '00:00:00'; | ||
| 158 | + } else { | ||
| 159 | + let hh = parseInt(val / 3600); | ||
| 160 | + let shh = val - hh * 3600; | ||
| 161 | + let ii = parseInt(shh / 60); | ||
| 162 | + let ss = shh - ii * 60; | ||
| 163 | + return (hh < 10 ? '0' + hh : hh) + ':' + (ii < 10 ? '0' + ii : ii) + ':' + (ss < 10 ? '0' + ss : ss); | ||
| 164 | + } | ||
| 165 | + } else { | ||
| 166 | + return '00:00:00'; | ||
| 167 | + } | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +const router = useRouter(); | ||
| 171 | +onMounted(() => { | ||
| 172 | + offsetHeight.value = document.body.offsetHeight - 50 | ||
| 173 | + carHeight.value = offsetHeight.value * 0.4 | ||
| 174 | + let _id = null | ||
| 175 | + if (window.$wujie) { | ||
| 176 | + _id = window.$wujie?.props.data.id as number; | ||
| 177 | + } else { | ||
| 178 | + let param = router.currentRoute.value.query | ||
| 179 | + _id = param.id | ||
| 180 | + } | ||
| 181 | + if (_id) { | ||
| 182 | + requestData(_id) | ||
| 183 | + requestRelationData(_id) | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + const wujie = window.$wujie; | ||
| 187 | + if (wujie) { | ||
| 188 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 189 | + nextTick(() => { | ||
| 190 | + color.value = theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 191 | + background.value = theme === 'dark' ? '#303030' : '#F5F7FB' | ||
| 192 | + }); | ||
| 193 | + }); | ||
| 194 | + } | ||
| 195 | +}) | ||
| 196 | +</script> | ||
| 197 | +<style scoped lang='scss'> | ||
| 198 | +.card-header { | ||
| 199 | + display: flex; | ||
| 200 | + justify-content: space-between; | ||
| 201 | + align-items: center; | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +.record-detail { | ||
| 205 | + background: v-bind(background); | ||
| 206 | + color: v-bind(color); | ||
| 207 | + border-radius: 2px; | ||
| 208 | + margin: 5px; | ||
| 209 | + height: 220px; | ||
| 210 | +} | ||
| 211 | + | ||
| 212 | +.title { | ||
| 213 | + font-style: 'normal'; | ||
| 214 | + font-weight: 'bold'; | ||
| 215 | + font-size: 14px; | ||
| 216 | + line-height: 22px; | ||
| 217 | + margin: 5px | ||
| 218 | +} | ||
| 219 | + | ||
| 220 | +.content { | ||
| 221 | + margin-top: 10px; | ||
| 222 | +} | ||
| 223 | +</style> | ||
| @@ -0,0 +1,90 @@ | |||
| 1 | +<template> | ||
| 2 | + <div ref="main" style="width: 100%; height: 100%;"></div> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script setup lang='ts'> | ||
| 6 | +import { ref } from 'vue' | ||
| 7 | +import * as echarts from "echarts" | ||
| 8 | +const main = ref() | ||
| 9 | +const props = withDefaults( | ||
| 10 | + defineProps<{ | ||
| 11 | + datas?: any[], | ||
| 12 | + title: string, | ||
| 13 | + unit: string, | ||
| 14 | + }>(), | ||
| 15 | + { | ||
| 16 | + title: '', | ||
| 17 | + unit: '' | ||
| 18 | + } | ||
| 19 | +); | ||
| 20 | +watch(() => props.datas, (datas) => { | ||
| 21 | + if (datas && datas.length > 0) { | ||
| 22 | + init() | ||
| 23 | + } | ||
| 24 | +}, { deep: true }) | ||
| 25 | + | ||
| 26 | +watch(() => props.title, (title) => { | ||
| 27 | + | ||
| 28 | +}) | ||
| 29 | +watch(() => props.unit, (unit) => { | ||
| 30 | + | ||
| 31 | +}) | ||
| 32 | + | ||
| 33 | +const init = () => { | ||
| 34 | + const theme = localStorage.getItem('theme'); | ||
| 35 | + let chart = echarts.init(main.value) | ||
| 36 | + const option = { | ||
| 37 | + title: { | ||
| 38 | + show: true, | ||
| 39 | + text: props.title, | ||
| 40 | + left: '40%', | ||
| 41 | + bottom: 'bottom', | ||
| 42 | + textStyle: { | ||
| 43 | + color: theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 44 | + } | ||
| 45 | + }, | ||
| 46 | + tooltip: { | ||
| 47 | + trigger: 'item' | ||
| 48 | + }, | ||
| 49 | + legend: { | ||
| 50 | + left: 'left', | ||
| 51 | + textStyle: { | ||
| 52 | + color: theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 53 | + } | ||
| 54 | + }, | ||
| 55 | + xAxis: { | ||
| 56 | + type: 'time', | ||
| 57 | + splitLine: { | ||
| 58 | + show: true | ||
| 59 | + } | ||
| 60 | + }, | ||
| 61 | + yAxis: { | ||
| 62 | + name: props.unit, | ||
| 63 | + type: 'value', | ||
| 64 | + splitLine: { | ||
| 65 | + show: true | ||
| 66 | + } | ||
| 67 | + }, | ||
| 68 | + series: [ | ||
| 69 | + { | ||
| 70 | + name: props.title, | ||
| 71 | + type: 'line', | ||
| 72 | + showSymbol: false, | ||
| 73 | + hoverAnimation: false, | ||
| 74 | + labelLine: { | ||
| 75 | + show: true, | ||
| 76 | + smooth: true | ||
| 77 | + }, | ||
| 78 | + data: props.datas | ||
| 79 | + } | ||
| 80 | + ] | ||
| 81 | + } | ||
| 82 | + chart.setOption(option) | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +onMounted(() => { | ||
| 86 | + init() | ||
| 87 | +}) | ||
| 88 | +</script> | ||
| 89 | +<style scoped lang='scss'> | ||
| 90 | +</style> | ||
| @@ -0,0 +1,120 @@ | |||
| 1 | +<template> | ||
| 2 | + <div ref="main" style="width: 100%; height: 125px;"></div> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script setup lang='ts'> | ||
| 6 | +import { ref } from 'vue' | ||
| 7 | +import * as echarts from "echarts" | ||
| 8 | +const main = ref() | ||
| 9 | +const props = withDefaults( | ||
| 10 | + defineProps<{ | ||
| 11 | + datas?: any[], | ||
| 12 | + title: string | ||
| 13 | + }>(), | ||
| 14 | + { | ||
| 15 | + title: '' | ||
| 16 | + } | ||
| 17 | +); | ||
| 18 | +watch(() => props.datas, (datas) => { | ||
| 19 | + if (datas && datas.length > 0) { | ||
| 20 | + init() | ||
| 21 | + } | ||
| 22 | +}, { deep: true }) | ||
| 23 | + | ||
| 24 | +watch(() => props.title, (title) => { | ||
| 25 | + | ||
| 26 | +}) | ||
| 27 | + | ||
| 28 | +const init = () => { | ||
| 29 | + const theme = localStorage.getItem('theme'); | ||
| 30 | + let chart = echarts.init(main.value) | ||
| 31 | + const option = { | ||
| 32 | + title: { | ||
| 33 | + show: true, | ||
| 34 | + text: props.title, | ||
| 35 | + left: '34%', | ||
| 36 | + bottom: 'bottom', | ||
| 37 | + padding: 0, | ||
| 38 | + textStyle: { | ||
| 39 | + fontWeight: 'normal', | ||
| 40 | + color: theme === 'dark' ? '#d4d4d4' : '#1d212a', | ||
| 41 | + fontSize: 14 | ||
| 42 | + } | ||
| 43 | + }, | ||
| 44 | + tooltip: { | ||
| 45 | + trigger: 'item' | ||
| 46 | + }, | ||
| 47 | + legend: { | ||
| 48 | + right: '18%', | ||
| 49 | + top: 'middle', | ||
| 50 | + orient: 'vertical', | ||
| 51 | + textStyle: { | ||
| 52 | + color: theme === 'dark' ? '#d4d4d4' : '#1d212a', | ||
| 53 | + fontSize: 11 | ||
| 54 | + }, | ||
| 55 | + formatter: function (name: string) { | ||
| 56 | + let datas = option.series[0].data | ||
| 57 | + if (datas.length === 0) { | ||
| 58 | + return `${name}: 0` | ||
| 59 | + } | ||
| 60 | + let val = '' | ||
| 61 | + for (let data of datas) { | ||
| 62 | + if (data.name === name) { | ||
| 63 | + val = data.value | ||
| 64 | + break; | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + return `${name}: ${val}` | ||
| 68 | + } | ||
| 69 | + }, | ||
| 70 | + series: [ | ||
| 71 | + { | ||
| 72 | + name: props.title, | ||
| 73 | + top: '10px', | ||
| 74 | + type: 'pie', | ||
| 75 | + radius: ['40%', '60%'], | ||
| 76 | + center: ['45%', '50%'], | ||
| 77 | + avoidLabelOverlap: false, | ||
| 78 | + label: { | ||
| 79 | + show: false, | ||
| 80 | + position: 'center' | ||
| 81 | + }, | ||
| 82 | + emphasis: { | ||
| 83 | + label: { | ||
| 84 | + show: true, | ||
| 85 | + fontSize: '14', | ||
| 86 | + fontWeight: 'bold' | ||
| 87 | + } | ||
| 88 | + }, | ||
| 89 | + labelLine: { | ||
| 90 | + show: true, | ||
| 91 | + smooth: true | ||
| 92 | + }, | ||
| 93 | + data: props.datas || [] | ||
| 94 | + } | ||
| 95 | + ] | ||
| 96 | + } | ||
| 97 | + chart.setOption(option) | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +onMounted(() => { | ||
| 101 | + const wujie = window.$wujie; | ||
| 102 | + // Judge whether it is a plug-in environment or a local environment through wujie | ||
| 103 | + if (wujie) { | ||
| 104 | + // Monitoring platform language change | ||
| 105 | + wujie?.bus.$on('opengauss-locale-change', (val: string) => { | ||
| 106 | + console.log('log-search catch locale change'); | ||
| 107 | + nextTick(() => { | ||
| 108 | + init() | ||
| 109 | + }); | ||
| 110 | + }); | ||
| 111 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 112 | + nextTick(() => { | ||
| 113 | + init() | ||
| 114 | + }); | ||
| 115 | + }); | ||
| 116 | + } | ||
| 117 | +}) | ||
| 118 | + | ||
| 119 | +</script> | ||
| 120 | +<style scoped lang='scss'></style> | ||
| @@ -0,0 +1,262 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item >{{ t('alertRule.title') }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <div class="search-form"> | ||
| 8 | + <div class="filter"> | ||
| 9 | + <span>{{ $t('alertRule.ruleType') }} </span> | ||
| 10 | + <el-select v-model="formData.ruleType" :placeholder="$t('alertRule.selectRuleType')" clearable | ||
| 11 | + @change="search"> | ||
| 12 | + <el-option v-for="item in ruleTypeList" :key="item" :value="item" :label="$t(`alertRule.${item}`)" /> | ||
| 13 | + </el-select> | ||
| 14 | + </div> | ||
| 15 | + <div class="filter"> | ||
| 16 | + <span>{{ $t('alertRule.level') }} </span> | ||
| 17 | + <el-select v-model="formData.level" :placeholder="$t('alertRule.selectLevelType')" style="max-width: 100px" | ||
| 18 | + clearable @change="search"> | ||
| 19 | + <el-option v-for="item in levelList" :key="item" :value="item" :label="$t(`alertRule.${item}`)" /> | ||
| 20 | + </el-select> | ||
| 21 | + </div> | ||
| 22 | + <div class="filter"> | ||
| 23 | + <el-input v-model="formData.ruleName" style="width: 150px" | ||
| 24 | + :placeholder="$t('alertRule.ruleNamePlaceholder')"> | ||
| 25 | + <template #suffix> | ||
| 26 | + <el-button :icon="Search" @click="search" /> | ||
| 27 | + </template> | ||
| 28 | + </el-input> | ||
| 29 | + </div> | ||
| 30 | + </div> | ||
| 31 | + <div class="alert-rule"> | ||
| 32 | + <div class="alert-record-table"> | ||
| 33 | + <el-table size="small" :data="tableDatas" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 34 | + <el-table-column :label="$t('alertRule.table[0]')" prop="ruleName" width="140"> | ||
| 35 | + <!-- <template #default="scope"> | ||
| 36 | + <el-link :underline="false" type="primary" @click="showDetail(scope.row.ruleId)">{{ | ||
| 37 | + scope.row.ruleName }}</el-link> | ||
| 38 | + </template> --> | ||
| 39 | + </el-table-column> | ||
| 40 | + <el-table-column :label="$t('alertRule.table[1]')" prop="ruleType" width="100"> | ||
| 41 | + <template #default="scope"> | ||
| 42 | + <span>{{ $t(`alertRule.${scope.row.ruleType}`) }}</span> | ||
| 43 | + </template> | ||
| 44 | + </el-table-column> | ||
| 45 | + <el-table-column prop="level" :label="$t('alertRule.table[2]')" width="100"> | ||
| 46 | + <template #default="scope"> | ||
| 47 | + <span>{{ $t(`alertRule.${scope.row.level}`) }}</span> | ||
| 48 | + </template> | ||
| 49 | + </el-table-column> | ||
| 50 | + <el-table-column prop="ruleExpDesc" :label="$t('alertRule.table[8]')" min-width="200"> | ||
| 51 | + <template #default="scope"> | ||
| 52 | + <span v-html="scope.row.ruleExpDesc"></span> | ||
| 53 | + </template> | ||
| 54 | + </el-table-column> | ||
| 55 | + <el-table-column prop="ruleExpComb" :label="$t('alertRule.table[9]')"> | ||
| 56 | + </el-table-column> | ||
| 57 | + <el-table-column prop="isRepeat" :label="$t('alertRule.table[3]')" width="100"> | ||
| 58 | + <template #default="scope"> | ||
| 59 | + <span>{{ scope.row.isRepeat === 1 ? $t('alertRule.isRepeat') : | ||
| 60 | + $t('alertRule.isNotRepeat') }}</span> | ||
| 61 | + </template> | ||
| 62 | + </el-table-column> | ||
| 63 | + <el-table-column prop="isSilence" :label="$t('alertRule.table[4]')" width="200"> | ||
| 64 | + <template #default="scope"> | ||
| 65 | + <span>{{ scope.row.isSilence === 1 ? scope.row.silenceStartTime + $t('alertRule.to') + | ||
| 66 | + scope.row.silenceEndTime : $t('alertRule.isNotSilence') }}</span> | ||
| 67 | + </template> | ||
| 68 | + </el-table-column> | ||
| 69 | + <el-table-column prop="alertNotify" :label="$t('alertRule.table[5]')" width="120"> | ||
| 70 | + <template #default="scope"> | ||
| 71 | + <span v-text="showAlertNotify(scope.row.alertNotify)"></span> | ||
| 72 | + </template> | ||
| 73 | + </el-table-column> | ||
| 74 | + <el-table-column prop="ruleContent" :label="$t('alertRule.table[6]')" min-width="200"/> | ||
| 75 | + <el-table-column :label="$t('alertRule.table[7]')" width="120" fixed="right"> | ||
| 76 | + <template #default="scope"> | ||
| 77 | + <el-button link type="primary" size="small" @click="showDetail(scope.row.ruleId)">{{ $t('app.view') | ||
| 78 | + }}</el-button> | ||
| 79 | + </template> | ||
| 80 | + </el-table-column> | ||
| 81 | + </el-table> | ||
| 82 | + <el-pagination v-model:currentPage="page.currentPage" v-model:pageSize="page.pageSize" :total="page.total" | ||
| 83 | + :page-sizes="[10, 20, 30, 40]" class="pagination" layout="total,sizes,prev,pager,next" background small | ||
| 84 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 85 | + </div> | ||
| 86 | + </div> | ||
| 87 | + </div> | ||
| 88 | + <div v-else> | ||
| 89 | + <RuleDetail :ruleId="curId" @updateRule="updateRule" @cancelRule="cancelRule" :state="state"/> | ||
| 90 | + </div> | ||
| 91 | +</template> | ||
| 92 | + | ||
| 93 | +<script setup lang="ts"> | ||
| 94 | +import { Search, Refresh, Delete } from "@element-plus/icons-vue"; | ||
| 95 | +import "element-plus/es/components/message-box/style/index"; | ||
| 96 | +import { useRequest } from "vue-request"; | ||
| 97 | +import request from "@/request"; | ||
| 98 | +import { i18n } from "@/i18n"; | ||
| 99 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 100 | +import { useI18n } from "vue-i18n"; | ||
| 101 | +import RuleDetail from "@/views/alert/AlertRule/RuleDetail.vue"; | ||
| 102 | +const { t } = useI18n(); | ||
| 103 | + | ||
| 104 | +const theme = localStorage.getItem('theme'); | ||
| 105 | +const color = ref<string>(theme === 'dark' ? '#d4d4d4' : '#1d212a') | ||
| 106 | +const background = ref<string>(theme === 'dark' ? '#303030' : '#F5F7FB') | ||
| 107 | + | ||
| 108 | +const showMain = ref<boolean>(true) | ||
| 109 | +const curId = ref<number>() | ||
| 110 | +const state = ref<string>() | ||
| 111 | +const tableDatas = ref<any[]>([]); | ||
| 112 | +const page = reactive({ | ||
| 113 | + currentPage: 1, | ||
| 114 | + pageSize: 10, | ||
| 115 | + total: 0, | ||
| 116 | +}); | ||
| 117 | +const ruleTypeList = reactive(['index', 'log']) | ||
| 118 | +const levelList = reactive(['serious', 'warn', 'info']) | ||
| 119 | +const formData = ref<any>({ | ||
| 120 | + ruleName: '', | ||
| 121 | + ruleType: '', | ||
| 122 | + level: '' | ||
| 123 | +}) | ||
| 124 | + | ||
| 125 | +const { data: ruleResult, run: requestData } = useRequest( | ||
| 126 | + () => { | ||
| 127 | + let params = {} | ||
| 128 | + params = Object.assign(params, formData.value, { pageNum: page.currentPage, pageSize: page.pageSize }) | ||
| 129 | + return request.get("/alertCenter/api/v1/alertRule", params) | ||
| 130 | + }, | ||
| 131 | + { manual: true } | ||
| 132 | +); | ||
| 133 | +watch(ruleResult, (ruleResult: any) => { | ||
| 134 | + if (ruleResult && ruleResult.code === 200) { | ||
| 135 | + tableDatas.value = ruleResult.rows || [] | ||
| 136 | + page.total = ruleResult.total | ||
| 137 | + } else { | ||
| 138 | + tableDatas.value = [] | ||
| 139 | + page.total = 0 | ||
| 140 | + const msg = t("app.queryFail"); | ||
| 141 | + ElMessage({ | ||
| 142 | + showClose: true, | ||
| 143 | + message: msg, | ||
| 144 | + type: "error", | ||
| 145 | + }); | ||
| 146 | + } | ||
| 147 | +}); | ||
| 148 | + | ||
| 149 | +const search = () => { | ||
| 150 | + page.currentPage = 1 | ||
| 151 | + page.pageSize = 10 | ||
| 152 | + requestData() | ||
| 153 | +} | ||
| 154 | +const handleSizeChange = (val: any) => { | ||
| 155 | + page.pageSize = val | ||
| 156 | + requestData() | ||
| 157 | +} | ||
| 158 | +const handleCurrentChange = (val: any) => { | ||
| 159 | + page.currentPage = val | ||
| 160 | + requestData() | ||
| 161 | +} | ||
| 162 | +const showAlertNotify = (val: string) => { | ||
| 163 | + if (!val) { | ||
| 164 | + return '' | ||
| 165 | + } | ||
| 166 | + let arr = val.split(','); | ||
| 167 | + let result = arr.map(item => t(`alertRule.${item}`)).join(',') | ||
| 168 | + return result | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +const showDetail = (id: number) => { | ||
| 172 | + curId.value = id | ||
| 173 | + state.value = "detail" | ||
| 174 | + showMain.value = false | ||
| 175 | +} | ||
| 176 | +const updateRule = () => { | ||
| 177 | + formData.value = { | ||
| 178 | + ruleName: '', | ||
| 179 | + ruleType: '', | ||
| 180 | + level: '' | ||
| 181 | + } | ||
| 182 | + search() | ||
| 183 | + curId.value = undefined | ||
| 184 | + showMain.value = true | ||
| 185 | +} | ||
| 186 | +const cancelRule = () => { | ||
| 187 | + curId.value = undefined | ||
| 188 | + showMain.value = true | ||
| 189 | +} | ||
| 190 | +onMounted(() => { | ||
| 191 | + requestData() | ||
| 192 | + | ||
| 193 | + const wujie = window.$wujie; | ||
| 194 | + if (wujie) { | ||
| 195 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 196 | + nextTick(() => { | ||
| 197 | + color.value = theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 198 | + background.value = theme === 'dark' ? '#303030' : '#F5F7FB' | ||
| 199 | + }); | ||
| 200 | + }); | ||
| 201 | + } | ||
| 202 | +}) | ||
| 203 | + | ||
| 204 | +</script> | ||
| 205 | +<style lang='scss' scoped> | ||
| 206 | +.search-form { | ||
| 207 | + .filter { | ||
| 208 | + :deep(.el-button--small) { | ||
| 209 | + background-color: v-bind(background) !important; | ||
| 210 | + color: v-bind(color) !important; | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +.alert-rule { | ||
| 216 | + &-chart { | ||
| 217 | + height: 380px; | ||
| 218 | + display: flex; | ||
| 219 | + flex-direction: column; | ||
| 220 | + align-items: flex-end; | ||
| 221 | + | ||
| 222 | + .chart-wrap { | ||
| 223 | + width: 100%; | ||
| 224 | + height: 100%; | ||
| 225 | + display: flex; | ||
| 226 | + flex-direction: column; | ||
| 227 | + justify-content: center; | ||
| 228 | + text-align: center; | ||
| 229 | + | ||
| 230 | + .chart-content { | ||
| 231 | + width: 100%; | ||
| 232 | + height: 100%; | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + .noresult-wrap { | ||
| 237 | + width: 100%; | ||
| 238 | + height: 500px; | ||
| 239 | + | ||
| 240 | + .noresult-img { | ||
| 241 | + width: 200px; | ||
| 242 | + display: block; | ||
| 243 | + margin: 20px auto; | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + .noresult-text { | ||
| 247 | + text-align: center; | ||
| 248 | + color: #707070; | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + .noResult .barLine-chart { | ||
| 253 | + display: none; | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + :deep(.el-link) { | ||
| 258 | + color: #409EFF !important; | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | +} | ||
| 262 | +</style> | ||
| @@ -0,0 +1,273 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('alertRule.title') }}</el-breadcrumb-item> | ||
| 5 | + <el-breadcrumb-item v-if="state === 'add'">{{ t('alertRule.addTitle') }}</el-breadcrumb-item> | ||
| 6 | + <el-breadcrumb-item v-if="state === 'edit'">{{ t('alertRule.editTitle') }}</el-breadcrumb-item> | ||
| 7 | + <el-breadcrumb-item v-if="state === 'detail'">{{ t('alertRule.detailTitle') }}</el-breadcrumb-item> | ||
| 8 | + </el-breadcrumb> | ||
| 9 | + <el-divider /> | ||
| 10 | + <el-descriptions :title="$t('alertRule.alertTitle')"></el-descriptions> | ||
| 11 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 12 | + <el-form-item :label="$t('alertRule.ruleName')" prop="ruleName"> | ||
| 13 | + <el-input v-model="formData.ruleName" :placeholder="$t('alertRule.ruleNamePlaceholder')" | ||
| 14 | + :disabled="disabled"></el-input> | ||
| 15 | + </el-form-item> | ||
| 16 | + <el-form-item :label="$t('alertRule.ruleType')" prop="ruleType"> | ||
| 17 | + <el-radio-group v-model="formData.ruleType" :disabled="disabled"> | ||
| 18 | + <el-radio v-for="item in ruleTypeList" :key="item" :label="item">{{ $t(`alertRule.${item}`) | ||
| 19 | + }}</el-radio> | ||
| 20 | + </el-radio-group> | ||
| 21 | + </el-form-item> | ||
| 22 | + <el-form-item :label="$t('alertRule.level')" prop="level"> | ||
| 23 | + <el-radio-group v-model="formData.level" :disabled="disabled"> | ||
| 24 | + <el-radio v-for="item in levelList" :key="item" :label="item">{{ $t(`alertRule.${item}`) }}</el-radio> | ||
| 25 | + </el-radio-group> | ||
| 26 | + </el-form-item> | ||
| 27 | + <el-form-item :label="$t('alertRule.ruleItem')" prop=""> | ||
| 28 | + <el-card class="box-card" v-for="item in formData.alertRuleItemList" :key="item.id" | ||
| 29 | + body-style="padding: 5px"> | ||
| 30 | + <span style="margin: 5px 0;">{{ $t('alertRule.ruleItemNum') }}:</span><el-input v-model="item.ruleMark" | ||
| 31 | + :disabled="disabled" style="width: 30px;margin: 5px;"></el-input> | ||
| 32 | + <span style="margin: 5px 0 10px 5px;">{{ $t('alertRule.ruleItemExp') }}:</span> | ||
| 33 | + <el-select v-model="item.ruleExpName" :disabled="disabled" style="width: 100px;margin: 5px 0 5px 5px;"> | ||
| 34 | + <el-option v-for="item0 in ruleItemExpList" :key="item0.name" :value="item0.name" | ||
| 35 | + :label="item0.i18nName" /> | ||
| 36 | + </el-select> | ||
| 37 | + <span v-if="item.itemParamList && item.itemParamList.length > 0"> | ||
| 38 | + <el-input v-model="item0.paramValue" style="width: 80px;margin: 1px;" :disabled="disabled" | ||
| 39 | + v-for="item0 in item.itemParamList" :key="item0.id"></el-input> | ||
| 40 | + </span> | ||
| 41 | + <el-select v-model="item.action" :disabled="disabled" style="width: 100px;margin: 5px;"> | ||
| 42 | + <el-option v-for="item0 in actionList" :key="item0.value" :value="item0.value" | ||
| 43 | + :label="item0.name" /> | ||
| 44 | + </el-select> | ||
| 45 | + <el-input v-model="item.operate" style="width: 50px;margin: 5px;" :disabled="disabled"></el-input> | ||
| 46 | + <el-input v-model="item.limitValue" style="width: 100px;margin: 5px;" :disabled="disabled"></el-input> | ||
| 47 | + <span style="width: 50px;margin: 5px;">{{ item.unit }}</span> | ||
| 48 | + </el-card> | ||
| 49 | + </el-form-item> | ||
| 50 | + <el-form-item :label="$t('alertRule.ruleExpComb')" prop="ruleExpComb"> | ||
| 51 | + <span v-for="item in ruleExpComb" :key="item"> | ||
| 52 | + <el-select :value="item" v-if="showLogicSelect(item)" style="width: 50px;" :disabled="disabled"> | ||
| 53 | + <el-option v-for="item in logicSymbolList" :key="item" :value="item" | ||
| 54 | + :label="$t(`alertRule.${item}`)" /> | ||
| 55 | + </el-select> | ||
| 56 | + <el-input :value="item" style="width: 50px;" v-else :disabled="disabled"></el-input> | ||
| 57 | + </span> | ||
| 58 | + </el-form-item> | ||
| 59 | + <el-form-item :label="$t('alertRule.ruleContent')" prop="ruleContent"> | ||
| 60 | + <el-input v-model="formData.ruleContent" :disabled="disabled"></el-input> | ||
| 61 | + </el-form-item> | ||
| 62 | + <el-form-item :label="$t('alertRule.notifyDuration')" prop="notifyDuration"> | ||
| 63 | + <el-input v-model="formData.notifyDuration" style="width: 100px;margin-right: 5px;" | ||
| 64 | + :disabled="disabled"></el-input> | ||
| 65 | + <el-select v-model="formData.notifyDurationUnit" :disabled="disabled" style="width: 80px;"> | ||
| 66 | + <el-option v-for="item in durationUnitList" :disabled="disabled" :key="item.name" :value="item.value" | ||
| 67 | + :label="$t(`alertRule.${item.name}`)" /> | ||
| 68 | + </el-select> | ||
| 69 | + </el-form-item> | ||
| 70 | + <el-form-item :label="$t('alertRule.alertDesc')" prop="alertDesc"> | ||
| 71 | + <el-input v-model="formData.alertDesc" :disabled="disabled"></el-input> | ||
| 72 | + </el-form-item> | ||
| 73 | + </el-form> | ||
| 74 | + <el-descriptions :title="$t('alertRule.notifyTitle')"></el-descriptions> | ||
| 75 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 76 | + <el-form-item :label="$t('alertRule.alertNotify')" prop="notifyDuration"> | ||
| 77 | + <el-checkbox-group v-model="alertNotifyList" :disabled="disabled"> | ||
| 78 | + <el-checkbox label="firing">{{ $t('alertRule.firing') }}</el-checkbox> | ||
| 79 | + <el-checkbox label="recover">{{ $t('alertRule.recover') }}</el-checkbox> | ||
| 80 | + </el-checkbox-group> | ||
| 81 | + </el-form-item> | ||
| 82 | + <el-form-item :label="$t('alertRule.repeat')" prop="isRepeat"> | ||
| 83 | + <el-radio-group v-model="isRepeat" :disabled="disabled"> | ||
| 84 | + <el-radio label="1">{{ $t('alertRule.isRepeat') }}</el-radio> | ||
| 85 | + <el-radio label="0">{{ $t('alertRule.isNotRepeat') }}</el-radio> | ||
| 86 | + </el-radio-group> | ||
| 87 | + </el-form-item> | ||
| 88 | + <el-form-item :label="$t('alertRule.silence')" prop="isSilence"> | ||
| 89 | + <el-radio-group v-model="isSilence" :disabled="disabled"> | ||
| 90 | + <el-radio label="1" key="1">{{ $t('alertRule.isSilence') }}</el-radio> | ||
| 91 | + <el-radio label="0" key="0">{{ $t('alertRule.isNotSilence') }}</el-radio> | ||
| 92 | + </el-radio-group> | ||
| 93 | + <span style="margin-left: 30px;" v-if="isSilence === 1 || isSilence === '1'">{{ $t('alertRule.silenceTime') | ||
| 94 | + }}</span> | ||
| 95 | + <span style="width: 250px;margin-left: 5px;"> | ||
| 96 | + <el-date-picker :disabled="disabled" v-if="isSilence === 1 || isSilence === '1'" v-model="silenceTimes" | ||
| 97 | + type="datetimerange" range-separator="~" format="YYYY-MM-DD HH:mm:ss" | ||
| 98 | + value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t(`alertRecord.startTimePlaceholder`)" | ||
| 99 | + :end-placeholder="t(`alertRecord.endTimePlaceholder`)" /> | ||
| 100 | + </span> | ||
| 101 | + </el-form-item> | ||
| 102 | + <el-form-item :label="$t('alertRule.notifyWay')"> | ||
| 103 | + <el-select v-model="notifyWayIdArr" multiple :disabled="disabled"> | ||
| 104 | + <el-option v-for="item in notifyWayList" :key="item.id" :value="item.id + ''" :label="item.name" /> | ||
| 105 | + </el-select> | ||
| 106 | + </el-form-item> | ||
| 107 | + </el-form> | ||
| 108 | + <el-row style="margin-top: 10px;"> | ||
| 109 | + <!-- <el-button type="primary" @click="confirm">{{ t('app.confirm') }}</el-button> --> | ||
| 110 | + <el-button type="primary" @click="cancel">{{ t('app.cancel') }}</el-button> | ||
| 111 | + </el-row> | ||
| 112 | + </div> | ||
| 113 | +</template> | ||
| 114 | + | ||
| 115 | +<script setup lang='ts'> | ||
| 116 | +import { Search, Refresh, Delete } from "@element-plus/icons-vue"; | ||
| 117 | +import "element-plus/es/components/message-box/style/index"; | ||
| 118 | +import { useRequest } from "vue-request"; | ||
| 119 | +import request from "@/request"; | ||
| 120 | +import { i18n } from "@/i18n"; | ||
| 121 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 122 | +import { useI18n } from "vue-i18n"; | ||
| 123 | +const { t } = useI18n(); | ||
| 124 | + | ||
| 125 | +const props = withDefaults( | ||
| 126 | + defineProps<{ | ||
| 127 | + ruleId: number, | ||
| 128 | + state: string, | ||
| 129 | + }>(), | ||
| 130 | + { | ||
| 131 | + state: 'detail' | ||
| 132 | + } | ||
| 133 | +); | ||
| 134 | + | ||
| 135 | +const emit = defineEmits(["updateRule", "cancelRule"]); | ||
| 136 | + | ||
| 137 | +const disabled = ref<boolean>(true) | ||
| 138 | +const ruleItemExpList = ref<any[]>() | ||
| 139 | +const actionList = ref<any[]>([{ | ||
| 140 | + name: t('alertRule.normalAction'), value: 'normal' | ||
| 141 | +}, { | ||
| 142 | + name: t('alertRule.increaseAction'), value: 'increase' | ||
| 143 | +}, { | ||
| 144 | + name: t('alertRule.decreaseAction'), value: 'decrease' | ||
| 145 | +}]) | ||
| 146 | +const logicSymbolList = ref<string[]>(['and', 'or']) | ||
| 147 | +const durationUnitList = ref<any[]>([{ | ||
| 148 | + name: 'second', | ||
| 149 | + value: 's' | ||
| 150 | +}, { | ||
| 151 | + name: 'minute', | ||
| 152 | + value: 'm' | ||
| 153 | +}, { | ||
| 154 | + name: 'hour', | ||
| 155 | + value: 'h' | ||
| 156 | +}, { | ||
| 157 | + name: 'day', | ||
| 158 | + value: 'd' | ||
| 159 | +}]) | ||
| 160 | +const notifyWayIdArr = ref<string[]>([]) | ||
| 161 | +const notifyWayList = ref<string[]>([]) | ||
| 162 | +const formData = ref<any>({ | ||
| 163 | + ruleName: '', | ||
| 164 | + ruleType: '', | ||
| 165 | + level: '', | ||
| 166 | + ruleExpComb: '', | ||
| 167 | + isRepeat: 1, | ||
| 168 | + isSilence: 0, | ||
| 169 | +}) | ||
| 170 | +const ruleTypeList = reactive(['index', 'log']) | ||
| 171 | +const levelList = reactive(['serious', 'warn', 'info']) | ||
| 172 | +const ruleExpComb = ref<string[]>([]) | ||
| 173 | +const alertNotifyList = ref<string[]>([]) | ||
| 174 | +const isRepeat = ref<string>('') | ||
| 175 | +const isSilence = ref<string>('') | ||
| 176 | +const silenceTimes = ref<any[]>([]) | ||
| 177 | +const showLogicSelect = (logicSymbol: string) => { | ||
| 178 | + return logicSymbolList.value.includes(logicSymbol) | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +const { data: ruleDetail, run: requestData } = useRequest( | ||
| 182 | + (id) => { | ||
| 183 | + return request.get(`/alertCenter/api/v1/alertRule/${id}`) | ||
| 184 | + }, | ||
| 185 | + { manual: true } | ||
| 186 | +) | ||
| 187 | +watch(ruleDetail, (ruleDetail: any) => { | ||
| 188 | + if (ruleDetail && ruleDetail.code === 200) { | ||
| 189 | + formData.value = ruleDetail.data | ||
| 190 | + if (formData.value?.ruleExpComb) { | ||
| 191 | + ruleExpComb.value = formData.value?.ruleExpComb.split(',') | ||
| 192 | + } | ||
| 193 | + if (formData.value?.alertNotify) { | ||
| 194 | + alertNotifyList.value = formData.value?.alertNotify.split(',') | ||
| 195 | + } | ||
| 196 | + if (formData.value?.isRepeat) { | ||
| 197 | + isRepeat.value = formData.value?.isRepeat + '' | ||
| 198 | + } | ||
| 199 | + if (formData.value?.isSilence) { | ||
| 200 | + isSilence.value = formData.value?.isSilence + '' | ||
| 201 | + } else { | ||
| 202 | + isSilence.value = '0' | ||
| 203 | + } | ||
| 204 | + if (formData.value.notifyWayIds) { | ||
| 205 | + notifyWayIdArr.value = formData.value.notifyWayIds.split(',') | ||
| 206 | + } | ||
| 207 | + if (formData.value.silenceStartTime && formData.value.silenceEndTime) { | ||
| 208 | + silenceTimes.value = [formData.value.silenceStartTime, formData.value.silenceEndTime] | ||
| 209 | + } | ||
| 210 | + } else { | ||
| 211 | + const msg = t("app.queryFail"); | ||
| 212 | + ElMessage({ | ||
| 213 | + showClose: true, | ||
| 214 | + message: msg, | ||
| 215 | + type: "error", | ||
| 216 | + }); | ||
| 217 | + } | ||
| 218 | +}); | ||
| 219 | + | ||
| 220 | +const cancel = () => { | ||
| 221 | + emit("cancelRule") | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +const requestNotifyWayData = () => { | ||
| 225 | + request.get(`/alertCenter/api/v1/notifyWay/list`).then((res: any) => { | ||
| 226 | + if (res && res.code === 200) { | ||
| 227 | + notifyWayList.value = res.data | ||
| 228 | + } | ||
| 229 | + }) | ||
| 230 | +} | ||
| 231 | + | ||
| 232 | +const requestRuleItemList = () => { | ||
| 233 | + request.get(`/alertCenter/api/v1/alertRule/ruleItem/properties`).then((res: any) => { | ||
| 234 | + if (res && res.code === 200) { | ||
| 235 | + ruleItemExpList.value = res.data | ||
| 236 | + } | ||
| 237 | + }) | ||
| 238 | +} | ||
| 239 | +onMounted(() => { | ||
| 240 | + requestNotifyWayData() | ||
| 241 | + requestData(props.ruleId) | ||
| 242 | + requestRuleItemList() | ||
| 243 | + if (props.state !== 'detail') { | ||
| 244 | + disabled.value = false | ||
| 245 | + } else { | ||
| 246 | + disabled.value = true | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + const wujie = window.$wujie; | ||
| 250 | + // Judge whether it is a plug-in environment or a local environment through wujie | ||
| 251 | + if (wujie) { | ||
| 252 | + // Monitoring platform language change | ||
| 253 | + wujie?.bus.$on('opengauss-locale-change', (val: string) => { | ||
| 254 | + console.log('log-search catch locale change'); | ||
| 255 | + nextTick(() => { | ||
| 256 | + actionList.value = [{ | ||
| 257 | + name: t('alertRule.normalAction'), value: 'normal' | ||
| 258 | + }, { | ||
| 259 | + name: t('alertRule.increaseAction'), value: 'increase' | ||
| 260 | + }, { | ||
| 261 | + name: t('alertRule.decreaseAction'), value: 'decrease' | ||
| 262 | + }] | ||
| 263 | + }); | ||
| 264 | + }); | ||
| 265 | + // wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 266 | + // nextTick(() => { | ||
| 267 | + // requestPisData() | ||
| 268 | + // }); | ||
| 269 | + // }); | ||
| 270 | + } | ||
| 271 | +}) | ||
| 272 | +</script> | ||
| 273 | +<style scoped lang='scss'></style> | ||
| @@ -0,0 +1,320 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('alertTemplate.title') }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <el-row> | ||
| 8 | + <el-col :span="8" class="container"> | ||
| 9 | + <el-descriptions :title="t('alertTemplate.title')"></el-descriptions> | ||
| 10 | + <div class="search-form"> | ||
| 11 | + <div class="filter"> | ||
| 12 | + <el-button type="primary" @click="addTemplate">{{ $t('app.add') }}</el-button> | ||
| 13 | + </div> | ||
| 14 | + <div class="seperator"></div> | ||
| 15 | + <div class="filter search"> | ||
| 16 | + <el-input v-model="formData.templateName" style="width: 150px" | ||
| 17 | + :placeholder="$t('alertTemplate.templateNamePlaceholder')"> | ||
| 18 | + <template #suffix> | ||
| 19 | + <el-button :icon="Search" @click="search" /> | ||
| 20 | + </template> | ||
| 21 | + </el-input> | ||
| 22 | + </div> | ||
| 23 | + </div> | ||
| 24 | + <div class="template-table"> | ||
| 25 | + <el-table size="small" :data="tableDatas" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 26 | + <el-table-column width="50"> | ||
| 27 | + <template #default="scope"> | ||
| 28 | + <el-radio :label="scope.row.id" v-model="currentId" | ||
| 29 | + @change="getCurrentRow(scope.row.id)"> </el-radio> | ||
| 30 | + </template> | ||
| 31 | + </el-table-column> | ||
| 32 | + <el-table-column prop="templateName" :label="$t('alertTemplate.table[0]')" /> | ||
| 33 | + <el-table-column :label="$t('alertTemplate.table[1]')"> | ||
| 34 | + <template #default="scope"> | ||
| 35 | + <el-button link type="primary" size="small" @click="editTemplate(scope.row.id)">{{ | ||
| 36 | + $t('app.edit') }}</el-button> | ||
| 37 | + <el-button link type="primary" size="small" @click="delTemplate(scope.row.id)">{{ | ||
| 38 | + $t('app.delete') }}</el-button> | ||
| 39 | + </template> | ||
| 40 | + </el-table-column> | ||
| 41 | + </el-table> | ||
| 42 | + <div class="pagination"> | ||
| 43 | + <el-pagination v-model:currentPage="page.currentPage" v-model:pageSize="page.pageSize" | ||
| 44 | + :total="page.total" :page-sizes="[10, 20, 30, 40]" layout="total,sizes,prev,pager,next" | ||
| 45 | + background small @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 46 | + </div> | ||
| 47 | + </div> | ||
| 48 | + </el-col> | ||
| 49 | + <el-col :span="16" class="container"> | ||
| 50 | + <el-descriptions :title="t('alertRule.title')"></el-descriptions> | ||
| 51 | + <div class="search-form"> | ||
| 52 | + <div class="filter search"> | ||
| 53 | + <el-input v-model="ruleFormData.ruleName" style="width: 150px" | ||
| 54 | + :placeholder="$t('alertRule.ruleNamePlaceholder')"> | ||
| 55 | + <template #suffix> | ||
| 56 | + <el-button :icon="Search" @click="ruleSearch" /> | ||
| 57 | + </template> | ||
| 58 | + </el-input> | ||
| 59 | + </div> | ||
| 60 | + </div> | ||
| 61 | + <div class="template-table"> | ||
| 62 | + <el-table size="small" :data="ruleTableDatas" style="width: 100%" header-cell-class-name="grid-header" | ||
| 63 | + border> | ||
| 64 | + <el-table-column :label="$t('alertRule.table[0]')" prop="ruleName" width="140"></el-table-column> | ||
| 65 | + <el-table-column :label="$t('alertRule.table[1]')" prop="ruleType" width="100"> | ||
| 66 | + <template #default="scope"> | ||
| 67 | + <span>{{ $t(`alertRule.${scope.row.ruleType}`) }}</span> | ||
| 68 | + </template> | ||
| 69 | + </el-table-column> | ||
| 70 | + <el-table-column prop="level" :label="$t('alertRule.table[2]')" width="100"> | ||
| 71 | + <template #default="scope"> | ||
| 72 | + <span>{{ $t(`alertRule.${scope.row.level}`) }}</span> | ||
| 73 | + </template> | ||
| 74 | + </el-table-column> | ||
| 75 | + <el-table-column prop="ruleExpDesc" :label="$t('alertRule.table[8]')" min-width="200"> | ||
| 76 | + <template #default="scope"> | ||
| 77 | + <span v-html="scope.row.ruleExpDesc"></span> | ||
| 78 | + </template> | ||
| 79 | + </el-table-column> | ||
| 80 | + <el-table-column prop="ruleExpComb" :label="$t('alertRule.table[9]')"> | ||
| 81 | + </el-table-column> | ||
| 82 | + <el-table-column prop="isRepeat" :label="$t('alertRule.table[3]')" width="100"> | ||
| 83 | + <template #default="scope"> | ||
| 84 | + <span>{{ scope.row.isRepeat === 1 ? $t('alertRule.isRepeat') : | ||
| 85 | + $t('alertRule.isNotRepeat') }}</span> | ||
| 86 | + </template> | ||
| 87 | + </el-table-column> | ||
| 88 | + <el-table-column prop="isSilence" :label="$t('alertRule.table[4]')" width="200"> | ||
| 89 | + <template #default="scope"> | ||
| 90 | + <span>{{ scope.row.isSilence === 1 ? scope.row.silenceStartTime + $t('alertRule.to') + | ||
| 91 | + scope.row.silenceEndTime : $t('alertRule.isNotSilence') }}</span> | ||
| 92 | + </template> | ||
| 93 | + </el-table-column> | ||
| 94 | + <el-table-column prop="alertNotify" :label="$t('alertRule.table[5]')" width="120"> | ||
| 95 | + <template #default="scope"> | ||
| 96 | + <span v-text="showAlertNotify(scope.row.alertNotify)"></span> | ||
| 97 | + </template> | ||
| 98 | + </el-table-column> | ||
| 99 | + <!-- <el-table-column prop="ruleContent" :label="$t('alertRule.table[6]')" /> --> | ||
| 100 | + </el-table> | ||
| 101 | + <div class="pagination"> | ||
| 102 | + <el-pagination v-model:currentPage="rulePage.currentPage" v-model:pageSize="rulePage.pageSize" | ||
| 103 | + :total="rulePage.total" :page-sizes="[10, 20, 30, 40]" class="pagination" | ||
| 104 | + layout="total,sizes,prev,pager,next" background small @size-change="handleRuleSizeChange" | ||
| 105 | + @current-change="handleRuleCurrentChange" /> | ||
| 106 | + </div> | ||
| 107 | + </div> | ||
| 108 | + </el-col> | ||
| 109 | + </el-row> | ||
| 110 | + </div> | ||
| 111 | + <div v-else> | ||
| 112 | + <TemplateDetail :templateId="curId" :state="state" @updateTemplate="updateTemplate" | ||
| 113 | + @cancelTemplate="cancelTemplate" /> | ||
| 114 | + </div> | ||
| 115 | +</template> | ||
| 116 | + | ||
| 117 | +<script setup lang='ts'> | ||
| 118 | +import { Search, Refresh, Delete } from "@element-plus/icons-vue"; | ||
| 119 | +import "element-plus/es/components/message-box/style/index"; | ||
| 120 | +import { useRequest } from "vue-request"; | ||
| 121 | +import request from "@/request"; | ||
| 122 | +import { i18n } from "@/i18n"; | ||
| 123 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 124 | +import { useI18n } from "vue-i18n"; | ||
| 125 | +import TemplateDetail from "@/views/alert/AlertTemplate/TemplateDetail.vue"; | ||
| 126 | +const { t } = useI18n(); | ||
| 127 | + | ||
| 128 | +const showMain = ref<boolean>(true) | ||
| 129 | +const curId = ref<number>() | ||
| 130 | +const state = ref<string>() | ||
| 131 | +const offsetHeight = ref<number>() | ||
| 132 | +const page = reactive({ | ||
| 133 | + currentPage: 1, | ||
| 134 | + pageSize: 10, | ||
| 135 | + total: 0, | ||
| 136 | +}) | ||
| 137 | +const formData = ref<any>({ | ||
| 138 | + templateName: '', | ||
| 139 | +}) | ||
| 140 | +const ruleFormData = ref<any>({ | ||
| 141 | + ruleName: '', | ||
| 142 | +}) | ||
| 143 | +const rulePage = reactive({ | ||
| 144 | + currentPage: 1, | ||
| 145 | + pageSize: 10, | ||
| 146 | + total: 0, | ||
| 147 | +}) | ||
| 148 | + | ||
| 149 | +const currentId = ref<number>() | ||
| 150 | +const tableDatas = ref<any[]>([]) | ||
| 151 | +const ruleTableDatas = ref<any[]>([]) | ||
| 152 | +const getCurrentRow = (id: number) => { | ||
| 153 | + if (id) { | ||
| 154 | + currentId.value = id | ||
| 155 | + requestRuleData() | ||
| 156 | + } | ||
| 157 | +} | ||
| 158 | +const { data: templateRes, run: requestTemplateData } = useRequest( | ||
| 159 | + () => { | ||
| 160 | + let params = {} | ||
| 161 | + params = Object.assign(params, formData.value, { pageNum: page.currentPage, pageSize: page.pageSize }) | ||
| 162 | + return request.get("/alertCenter/api/v1/alertTemplate", params) | ||
| 163 | + }, | ||
| 164 | + { manual: true } | ||
| 165 | +); | ||
| 166 | +const { data: ruleRes, run: requestRuleData } = useRequest( | ||
| 167 | + () => { | ||
| 168 | + let params = {} | ||
| 169 | + params = Object.assign(params, ruleFormData.value, { pageNum: rulePage.currentPage, pageSize: rulePage.pageSize }) | ||
| 170 | + return request.get(`/alertCenter/api/v1/alertTemplate/${currentId.value}/rule`, params) | ||
| 171 | + }, | ||
| 172 | + { manual: true } | ||
| 173 | +); | ||
| 174 | +watch(templateRes, (templateRes: any) => { | ||
| 175 | + if (templateRes && templateRes.code === 200) { | ||
| 176 | + tableDatas.value = templateRes.rows || [] | ||
| 177 | + page.total = templateRes.total | ||
| 178 | + if (tableDatas.value.length > 0) { | ||
| 179 | + currentId.value = tableDatas.value[0].id | ||
| 180 | + requestRuleData() | ||
| 181 | + } | ||
| 182 | + } else { | ||
| 183 | + tableDatas.value = [] | ||
| 184 | + page.total = 0 | ||
| 185 | + const msg = t("app.queryFail"); | ||
| 186 | + ElMessage({ | ||
| 187 | + showClose: true, | ||
| 188 | + message: msg, | ||
| 189 | + type: "error", | ||
| 190 | + }); | ||
| 191 | + } | ||
| 192 | +}); | ||
| 193 | +watch(ruleRes, (ruleRes: any) => { | ||
| 194 | + if (ruleRes && ruleRes.code === 200) { | ||
| 195 | + ruleTableDatas.value = ruleRes.rows || [] | ||
| 196 | + rulePage.total = ruleRes.total | ||
| 197 | + } else { | ||
| 198 | + ruleTableDatas.value = [] | ||
| 199 | + rulePage.total = 0 | ||
| 200 | + const msg = t("app.queryFail"); | ||
| 201 | + ElMessage({ | ||
| 202 | + showClose: true, | ||
| 203 | + message: msg, | ||
| 204 | + type: "error", | ||
| 205 | + }); | ||
| 206 | + } | ||
| 207 | +}); | ||
| 208 | +const search = () => { | ||
| 209 | + page.currentPage = 1 | ||
| 210 | + page.pageSize = 10 | ||
| 211 | + requestTemplateData() | ||
| 212 | +} | ||
| 213 | +const handleSizeChange = (val: any) => { | ||
| 214 | + page.pageSize = val | ||
| 215 | + requestTemplateData() | ||
| 216 | +} | ||
| 217 | +const handleCurrentChange = (val: any) => { | ||
| 218 | + page.currentPage = val | ||
| 219 | + requestTemplateData() | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +const ruleSearch = () => { | ||
| 223 | + rulePage.currentPage = 1 | ||
| 224 | + rulePage.pageSize = 10 | ||
| 225 | + requestRuleData() | ||
| 226 | +} | ||
| 227 | +const handleRuleSizeChange = (val: any) => { | ||
| 228 | + rulePage.pageSize = val | ||
| 229 | + requestRuleData() | ||
| 230 | +} | ||
| 231 | +const handleRuleCurrentChange = (val: any) => { | ||
| 232 | + rulePage.currentPage = val | ||
| 233 | + requestRuleData() | ||
| 234 | +} | ||
| 235 | +const showAlertNotify = (val: string) => { | ||
| 236 | + if (!val) { | ||
| 237 | + return '' | ||
| 238 | + } | ||
| 239 | + let arr = val.split(','); | ||
| 240 | + let result = arr.map(item => t(`alertRule.${item}`)).join(',') | ||
| 241 | + return result | ||
| 242 | +} | ||
| 243 | + | ||
| 244 | +const addTemplate = () => { | ||
| 245 | + state.value = 'add' | ||
| 246 | + showMain.value = false | ||
| 247 | +} | ||
| 248 | +const editTemplate = (id: number) => { | ||
| 249 | + state.value = 'edit' | ||
| 250 | + curId.value = id | ||
| 251 | + showMain.value = false | ||
| 252 | +} | ||
| 253 | +const updateTemplate = () => { | ||
| 254 | + formData.value = { | ||
| 255 | + ruleName: '' | ||
| 256 | + } | ||
| 257 | + search() | ||
| 258 | + curId.value = undefined | ||
| 259 | + showMain.value = true | ||
| 260 | +} | ||
| 261 | +const cancelTemplate = () => { | ||
| 262 | + curId.value = undefined | ||
| 263 | + showMain.value = true | ||
| 264 | +} | ||
| 265 | +const delTemplate = (id: number) => { | ||
| 266 | + ElMessageBox.confirm( | ||
| 267 | + t('app.deleteTip'), | ||
| 268 | + t('app.tip'), | ||
| 269 | + { | ||
| 270 | + confirmButtonText: t('app.confirm'), | ||
| 271 | + cancelButtonText: t('app.cancel'), | ||
| 272 | + type: 'warning', | ||
| 273 | + } | ||
| 274 | + ).then(() => { | ||
| 275 | + request.delete(`/alertCenter/api/v1/alertTemplate`, { id }).then((res: any) => { | ||
| 276 | + if (res && res.code === 200) { | ||
| 277 | + ElMessage({ | ||
| 278 | + type: 'success', | ||
| 279 | + message: t('app.delSuccess'), | ||
| 280 | + }) | ||
| 281 | + search() | ||
| 282 | + } else { | ||
| 283 | + ElMessage({ | ||
| 284 | + type: 'error', | ||
| 285 | + message: t('app.delFail') + (res && res.msg ? "," + res.msg : ""), | ||
| 286 | + }) | ||
| 287 | + } | ||
| 288 | + }).catch((res: any) => { | ||
| 289 | + ElMessage({ | ||
| 290 | + type: 'error', | ||
| 291 | + message: t('app.delFail') + (res && res.msg ? "," + res.msg : ""), | ||
| 292 | + }) | ||
| 293 | + }) | ||
| 294 | + }).catch(() => { | ||
| 295 | + | ||
| 296 | + }) | ||
| 297 | +} | ||
| 298 | +onMounted(() => { | ||
| 299 | + offsetHeight.value = document.body.offsetHeight - 110 | ||
| 300 | + requestTemplateData() | ||
| 301 | +}) | ||
| 302 | +</script> | ||
| 303 | +<style scoped lang='scss'> | ||
| 304 | +.container { | ||
| 305 | + border: #ebeef5 1px solid; | ||
| 306 | + padding: 5px; | ||
| 307 | + min-height: 600px; | ||
| 308 | +} | ||
| 309 | +.template-table { | ||
| 310 | + :deep(.el-link) { | ||
| 311 | + color: #409EFF !important; | ||
| 312 | + } | ||
| 313 | +} | ||
| 314 | + | ||
| 315 | +.pagination { | ||
| 316 | + margin-top: 5px; | ||
| 317 | + // bottom: 50px; | ||
| 318 | + // position: fixed; | ||
| 319 | +} | ||
| 320 | +</style> | ||
| @@ -0,0 +1,293 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('alertTemplate.title') }}</el-breadcrumb-item> | ||
| 5 | + <el-breadcrumb-item>{{ title }}</el-breadcrumb-item> | ||
| 6 | + </el-breadcrumb> | ||
| 7 | + <el-divider /> | ||
| 8 | + <!-- <el-descriptions :title="$t('alertRule.detailTitle')"></el-descriptions> --> | ||
| 9 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 10 | + <el-form-item :label="$t('alertTemplate.templateName')" prop="templateName"> | ||
| 11 | + <el-input v-model="formData.templateName" | ||
| 12 | + :placeholder="$t('alertTemplate.templateNamePlaceholder')"></el-input> | ||
| 13 | + </el-form-item> | ||
| 14 | + <el-form-item :label="$t('alertTemplate.selectRule')"> | ||
| 15 | + <el-table size="small" :data="tableDatas" ref="ruleTable" style="width: 100%" | ||
| 16 | + header-cell-class-name="grid-header" border> | ||
| 17 | + <el-table-column type="selection" width="55" /> | ||
| 18 | + <el-table-column :label="$t('alertRule.table[0]')" prop="ruleName" width="140"></el-table-column> | ||
| 19 | + <el-table-column :label="$t('alertRule.table[1]')" prop="ruleType" width="100"> | ||
| 20 | + <template #default="scope"> | ||
| 21 | + <span>{{ $t(`alertRule.${scope.row.ruleType}`) }}</span> | ||
| 22 | + </template> | ||
| 23 | + </el-table-column> | ||
| 24 | + <el-table-column prop="level" :label="$t('alertRule.table[2]')" width="100"> | ||
| 25 | + <template #default="scope"> | ||
| 26 | + <span>{{ $t(`alertRule.${scope.row.level}`) }}</span> | ||
| 27 | + </template> | ||
| 28 | + </el-table-column> | ||
| 29 | + <el-table-column prop="ruleExpDesc" :label="$t('alertRule.table[8]')" min-width="200"> | ||
| 30 | + <template #default="scope"> | ||
| 31 | + <span v-html="scope.row.ruleExpDesc"></span> | ||
| 32 | + </template> | ||
| 33 | + </el-table-column> | ||
| 34 | + <el-table-column prop="ruleExpComb" :label="$t('alertRule.table[9]')"> | ||
| 35 | + </el-table-column> | ||
| 36 | + <el-table-column prop="isRepeat" :label="$t('alertRule.table[3]')" width="100"> | ||
| 37 | + <template #default="scope"> | ||
| 38 | + <span>{{ scope.row.isRepeat === 1 ? $t('alertRule.isRepeat') : | ||
| 39 | + $t('alertRule.isNotRepeat') }}</span> | ||
| 40 | + </template> | ||
| 41 | + </el-table-column> | ||
| 42 | + <el-table-column prop="isSilence" :label="$t('alertRule.table[4]')" width="200"> | ||
| 43 | + <template #default="scope"> | ||
| 44 | + <span>{{ scope.row.isSilence === 1 ? scope.row.silenceStartTime + $t('alertRule.to') + | ||
| 45 | + scope.row.silenceEndTime : $t('alertRule.isNotSilence') }}</span> | ||
| 46 | + </template> | ||
| 47 | + </el-table-column> | ||
| 48 | + <el-table-column prop="alertNotify" :label="$t('alertRule.table[5]')" width="120"> | ||
| 49 | + <template #default="scope"> | ||
| 50 | + <span v-text="showAlertNotify(scope.row.alertNotify)"></span> | ||
| 51 | + </template> | ||
| 52 | + </el-table-column> | ||
| 53 | + <el-table-column :label="$t('alertRule.table[7]')" fixed="right"> | ||
| 54 | + <template #default="scope"> | ||
| 55 | + <el-button link type="primary" size="small" | ||
| 56 | + @click.prevent="edit(scope.row.templateRuleId, scope.row.ruleId)"> | ||
| 57 | + {{ t('app.edit') }} | ||
| 58 | + </el-button> | ||
| 59 | + </template> | ||
| 60 | + </el-table-column> | ||
| 61 | + <!-- <el-table-column prop="ruleContent" :label="$t('alertRule.table[6]')" /> --> | ||
| 62 | + </el-table> | ||
| 63 | + </el-form-item> | ||
| 64 | + </el-form> | ||
| 65 | + <el-row> | ||
| 66 | + <el-button type="primary" @click="confirm">{{ t('app.confirm') }}</el-button> | ||
| 67 | + <el-button @click="cancel">{{ t('app.cancel') }}</el-button> | ||
| 68 | + </el-row> | ||
| 69 | + </div> | ||
| 70 | + <div v-else> | ||
| 71 | + <TemplateRuleDetail :ruleId="editRuleId" :templateRuleId="editTemplateRuleId" :titleList="titleList" | ||
| 72 | + @updateTemplateRuleSuccess="updateTemplateRuleSuccess" @cancelUpdateTemplateRule="cancelUpdateTemplateRule" /> | ||
| 73 | + </div> | ||
| 74 | +</template> | ||
| 75 | + | ||
| 76 | +<script setup lang='ts'> | ||
| 77 | +// import { } from "@element-plus/icons-vue"; | ||
| 78 | +import "element-plus/es/components/message-box/style/index"; | ||
| 79 | +import { ref, nextTick } from 'vue' | ||
| 80 | +import { useRequest } from "vue-request"; | ||
| 81 | +import request from "@/request"; | ||
| 82 | +import { i18n } from "@/i18n"; | ||
| 83 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 84 | +import { useI18n } from "vue-i18n"; | ||
| 85 | +import type { FormInstance, FormRules } from 'element-plus' | ||
| 86 | +import TemplateRuleDetail from "@/views/alert/AlertTemplate/TemplateRuleDetail.vue"; | ||
| 87 | +const { t } = useI18n(); | ||
| 88 | +const props = withDefaults( | ||
| 89 | + defineProps<{ | ||
| 90 | + templateId: number, | ||
| 91 | + state: string, | ||
| 92 | + }>(), | ||
| 93 | + { | ||
| 94 | + state: 'add' | ||
| 95 | + } | ||
| 96 | +); | ||
| 97 | +const emit = defineEmits(["updateTemplate", "cancelTemplate"]); | ||
| 98 | + | ||
| 99 | +const title = ref<string>() | ||
| 100 | +const showMain = ref<boolean>(true) | ||
| 101 | +const ruleTable = ref(); | ||
| 102 | +const formData = ref<any>({ | ||
| 103 | + templateName: '', | ||
| 104 | + templateRuleDtoList: [] | ||
| 105 | +}) | ||
| 106 | +const tableDatas = ref<any[]>([]) | ||
| 107 | + | ||
| 108 | +const selectedRuleRows = ref<any[]>([]) | ||
| 109 | +const editTemplateRuleId = ref<number>() | ||
| 110 | +const editRuleId = ref<number>() | ||
| 111 | +const titleList = ref<string[]>([]) | ||
| 112 | + | ||
| 113 | +const formRef = ref<FormInstance>() | ||
| 114 | +const formRules = reactive<FormRules>({ | ||
| 115 | + templateName: [ | ||
| 116 | + { required: true, message: t('alertTemplate.templateNamePlaceholder'), trigger: 'blur' }, | ||
| 117 | + ] | ||
| 118 | +}) | ||
| 119 | + | ||
| 120 | +const showAlertNotify = (val: string) => { | ||
| 121 | + if (!val) { | ||
| 122 | + return '' | ||
| 123 | + } | ||
| 124 | + let arr = val.split(','); | ||
| 125 | + let result = arr.map(item => t(`alertRule.${item}`)).join(',') | ||
| 126 | + return result | ||
| 127 | +} | ||
| 128 | +const { data: ruleRes, run: requestRuleData } = useRequest( | ||
| 129 | + () => { | ||
| 130 | + return request.get(`/alertCenter/api/v1/alertRule/ruleList`) | ||
| 131 | + }, | ||
| 132 | + { manual: true } | ||
| 133 | +); | ||
| 134 | +watch(ruleRes, (ruleRes: any) => { | ||
| 135 | + if (ruleRes && ruleRes.code === 200) { | ||
| 136 | + tableDatas.value = ruleRes.data | ||
| 137 | + let selectDatas = formData.value.templateRuleDtoList || []; | ||
| 138 | + if (selectDatas.length > 0) { | ||
| 139 | + tableDatas.value = tableDatas.value.map(item => { | ||
| 140 | + let datas = selectDatas.filter((item0: any) => item0.ruleId === item.ruleId) || [] | ||
| 141 | + if (datas.length > 0) { | ||
| 142 | + nextTick(() => { | ||
| 143 | + ruleTable.value.toggleRowSelection(datas[0], true) | ||
| 144 | + }) | ||
| 145 | + return datas[0] | ||
| 146 | + } | ||
| 147 | + return item; | ||
| 148 | + }) | ||
| 149 | + } | ||
| 150 | + } else { | ||
| 151 | + tableDatas.value = [] | ||
| 152 | + } | ||
| 153 | +}); | ||
| 154 | + | ||
| 155 | +const { data: templateRes, run: requestData } = useRequest( | ||
| 156 | + (id) => { | ||
| 157 | + return request.get(`/alertCenter/api/v1/alertTemplate/${id}`) | ||
| 158 | + }, | ||
| 159 | + { manual: true } | ||
| 160 | +); | ||
| 161 | +watch(templateRes, (templateRes: any) => { | ||
| 162 | + if (templateRes && templateRes.code === 200) { | ||
| 163 | + formData.value = templateRes.data | ||
| 164 | + let selectDatas = formData.value.templateRuleDtoList || []; | ||
| 165 | + if (tableDatas.value.length > 0) { | ||
| 166 | + tableDatas.value = tableDatas.value.map(item => { | ||
| 167 | + let datas = selectDatas.filter((item0: any) => item0.ruleId === item.ruleId) || [] | ||
| 168 | + if (datas.length > 0) { | ||
| 169 | + nextTick(() => { | ||
| 170 | + ruleTable.value.toggleRowSelection(datas[0], true) | ||
| 171 | + }) | ||
| 172 | + return datas[0] | ||
| 173 | + } | ||
| 174 | + return item; | ||
| 175 | + }) | ||
| 176 | + } | ||
| 177 | + } else { | ||
| 178 | + tableDatas.value = [] | ||
| 179 | + } | ||
| 180 | +}); | ||
| 181 | + | ||
| 182 | +const confirm = () => { | ||
| 183 | + if (!formRef.value) return | ||
| 184 | + formRef.value?.validate((valid, fields) => { | ||
| 185 | + if (!valid) { | ||
| 186 | + return; | ||
| 187 | + } | ||
| 188 | + const rows = ruleTable.value.getSelectionRows() || [] | ||
| 189 | + if (rows.length === 0) { | ||
| 190 | + ElMessage({ | ||
| 191 | + message: t('app.selectDatasTip'), | ||
| 192 | + type: 'warning' | ||
| 193 | + }) | ||
| 194 | + return; | ||
| 195 | + } | ||
| 196 | + let templateRuleReqList = rows.map((item: any) => { | ||
| 197 | + return { templateRuleId: item.templateRuleId, ruleId: item.ruleId } | ||
| 198 | + }) | ||
| 199 | + let param = { | ||
| 200 | + id: formData.value.id, | ||
| 201 | + templateName: formData.value.templateName, | ||
| 202 | + templateRuleReqList | ||
| 203 | + } | ||
| 204 | + request.post(`/alertCenter/api/v1/alertTemplate`, param).then((res: any) => { | ||
| 205 | + if (res && res.code === 200) { | ||
| 206 | + ElMessage({ | ||
| 207 | + message: t('app.saveSuccess'), | ||
| 208 | + type: 'success' | ||
| 209 | + }) | ||
| 210 | + formData.value = { | ||
| 211 | + templateName: '', | ||
| 212 | + templateRuleDtoList: [] | ||
| 213 | + } | ||
| 214 | + emit("updateTemplate") | ||
| 215 | + } else { | ||
| 216 | + ElMessage({ | ||
| 217 | + message: t('app.saveFail'), | ||
| 218 | + type: 'error' | ||
| 219 | + }) | ||
| 220 | + } | ||
| 221 | + }).catch(() => { | ||
| 222 | + ElMessage({ | ||
| 223 | + message: t('app.saveFail'), | ||
| 224 | + type: 'error' | ||
| 225 | + }) | ||
| 226 | + }) | ||
| 227 | + }) | ||
| 228 | +} | ||
| 229 | +const cancel = () => { | ||
| 230 | + formData.value = { | ||
| 231 | + templateName: '', | ||
| 232 | + templateRuleDtoList: [] | ||
| 233 | + } | ||
| 234 | + emit("cancelTemplate") | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +const edit = (templateRuleId: any, ruleId: any) => { | ||
| 238 | + selectedRuleRows.value = ruleTable.value.getSelectionRows() || [] | ||
| 239 | + // let selectedRuleIdArr = selectedRuleRows.value.map((item: any) => item.ruleId) || [] | ||
| 240 | + // if (!selectedRuleIdArr.includes(ruleId)) { | ||
| 241 | + // ElMessage({ | ||
| 242 | + // message: t('app.selectUpdateDataTip'), | ||
| 243 | + // type: 'warning' | ||
| 244 | + // }) | ||
| 245 | + // return; | ||
| 246 | + // } | ||
| 247 | + editTemplateRuleId.value = templateRuleId | ||
| 248 | + editRuleId.value = ruleId | ||
| 249 | + let curTitle = title.value || '' | ||
| 250 | + titleList.value = [t('alertTemplate.title'), curTitle, t('alertRule.editTitle')] | ||
| 251 | + showMain.value = false | ||
| 252 | +} | ||
| 253 | + | ||
| 254 | +const updateTemplateRuleSuccess = (templateRule: any) => { | ||
| 255 | + for (let i = 0; i < tableDatas.value.length; i++) { | ||
| 256 | + if (tableDatas.value[i].ruleId === templateRule.ruleId) { | ||
| 257 | + tableDatas.value[i].templateRuleId = templateRule.templateRuleId | ||
| 258 | + tableDatas.value[i].level = templateRule.level | ||
| 259 | + tableDatas.value[i].ruleExpDesc = templateRule.ruleExpDesc | ||
| 260 | + tableDatas.value[i].ruleExpComb = templateRule.ruleExpComb | ||
| 261 | + tableDatas.value[i].isRepeat = templateRule.isRepeat | ||
| 262 | + tableDatas.value[i].isSilence = templateRule.isSilence | ||
| 263 | + tableDatas.value[i].isSilence = templateRule.silenceStartTime | ||
| 264 | + tableDatas.value[i].isSilence = templateRule.silenceEndTime | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + showMain.value = true | ||
| 268 | + nextTick(() => { | ||
| 269 | + for (let row of selectedRuleRows.value) { | ||
| 270 | + ruleTable.value.toggleRowSelection(row, true) | ||
| 271 | + } | ||
| 272 | + }) | ||
| 273 | +} | ||
| 274 | + | ||
| 275 | +const cancelUpdateTemplateRule = () => { | ||
| 276 | + showMain.value = true | ||
| 277 | + nextTick(() => { | ||
| 278 | + for (let row of selectedRuleRows.value) { | ||
| 279 | + ruleTable.value.toggleRowSelection(row, true) | ||
| 280 | + } | ||
| 281 | + }) | ||
| 282 | +} | ||
| 283 | + | ||
| 284 | +onMounted(() => { | ||
| 285 | + title.value = props.state === 'add' ? t('alertTemplate.addTitle') : props.state === 'edit' ? t('alertTemplate.editTitle') : t('alertTemplate.detailTitle') | ||
| 286 | + requestRuleData() | ||
| 287 | + if (props.templateId) { | ||
| 288 | + requestData(props.templateId) | ||
| 289 | + } | ||
| 290 | +}) | ||
| 291 | + | ||
| 292 | +</script> | ||
| 293 | +<style scoped lang='scss'></style> | ||
| @@ -0,0 +1,393 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item v-for="item in titleList" :key="item">{{ item }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <el-descriptions :title="$t('alertRule.alertTitle')"></el-descriptions> | ||
| 8 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 9 | + <el-form-item :label="$t('alertRule.ruleName')" prop="ruleName"> | ||
| 10 | + <el-input v-model="formData.ruleName" disabled | ||
| 11 | + :placeholder="$t('alertRule.ruleNamePlaceholder')"></el-input> | ||
| 12 | + </el-form-item> | ||
| 13 | + <el-form-item :label="$t('alertRule.ruleType')" prop="ruleType"> | ||
| 14 | + <el-radio-group v-model="formData.ruleType" disabled> | ||
| 15 | + <el-radio v-for="item in ruleTypeList" :key="item" :label="item">{{ $t(`alertRule.${item}`) | ||
| 16 | + }}</el-radio> | ||
| 17 | + </el-radio-group> | ||
| 18 | + </el-form-item> | ||
| 19 | + <el-form-item :label="$t('alertRule.level')" prop="level"> | ||
| 20 | + <el-radio-group v-model="formData.level"> | ||
| 21 | + <el-radio v-for="item in levelList" :key="item" :label="item">{{ $t(`alertRule.${item}`) }}</el-radio> | ||
| 22 | + </el-radio-group> | ||
| 23 | + </el-form-item> | ||
| 24 | + <el-form-item :label="$t('alertRule.ruleItem')"> | ||
| 25 | + <el-card class="box-card" v-for="item in formData.alertRuleItemList" :key="item.id" | ||
| 26 | + body-style="padding: 5px"> | ||
| 27 | + <span style="margin: 5px 0;">{{ $t('alertRule.ruleItemNum') }}:</span><el-input v-model="item.ruleMark" | ||
| 28 | + disabled style="width: 30px;margin: 5px;"></el-input> | ||
| 29 | + <span style="margin: 5px 0 10px 5px;">{{ $t('alertRule.ruleItemExp') }}:</span> | ||
| 30 | + <el-select v-model="item.ruleExpName" disabled style="width: 100px;margin: 5px 0 5px 5px;"> | ||
| 31 | + <el-option v-for="item0 in ruleItemExpList" :key="item0.name" :value="item0.name" | ||
| 32 | + :label="item0.i18nName" /> | ||
| 33 | + </el-select> | ||
| 34 | + <span v-if="item.itemParamList && item.itemParamList.length > 0"> | ||
| 35 | + <el-input v-model="item0.paramValue" style="width: 80px;margin: 1px;" disabled | ||
| 36 | + v-for="item0 in item.itemParamList" :key="item0.id"></el-input> | ||
| 37 | + </span> | ||
| 38 | + <el-select v-model="item.action" disabled style="width: 100px;margin: 5px;"> | ||
| 39 | + <el-option v-for="item0 in actionList" :key="item0.value" :value="item0.value" | ||
| 40 | + :label="item0.name" /> | ||
| 41 | + </el-select> | ||
| 42 | + <el-input v-model="item.operate" style="width: 50px;margin: 5px;" disabled></el-input> | ||
| 43 | + <el-input v-model="item.limitValue" style="width: 100px;margin: 5px;"></el-input> | ||
| 44 | + <span style="width: 50px;margin: 5px;">{{ item.unit }}</span> | ||
| 45 | + </el-card> | ||
| 46 | + </el-form-item> | ||
| 47 | + <el-form-item :label="$t('alertRule.ruleExpComb')" prop="ruleExpComb"> | ||
| 48 | + <span v-for="item in ruleExpComb" :key="item"> | ||
| 49 | + <el-select :value="item" v-if="showLogicSelect(item)" style="width: 50px;" disabled> | ||
| 50 | + <el-option v-for="item in logicSymbolList" :key="item" :value="item" | ||
| 51 | + :label="$t(`alertRule.${item}`)" /> | ||
| 52 | + </el-select> | ||
| 53 | + <el-input :value="item" style="width: 50px;" v-else disabled></el-input> | ||
| 54 | + </span> | ||
| 55 | + </el-form-item> | ||
| 56 | + <el-row> | ||
| 57 | + <el-col :span="15"> | ||
| 58 | + <el-form-item :label="$t('alertRule.ruleContent')" prop="ruleContent" style="margin-bottom: 0px;"> | ||
| 59 | + <el-input v-model="formData.ruleContent" @blur="preview"></el-input> | ||
| 60 | + </el-form-item> | ||
| 61 | + </el-col> | ||
| 62 | + <el-col :span="1" style="margin-bottom: 0px;"> | ||
| 63 | + <el-button @click="reset" style="display: flex;">{{ t('app.reset') }}</el-button> | ||
| 64 | + </el-col> | ||
| 65 | + <el-col :span="8" style="margin-bottom: 0px;"> | ||
| 66 | + <div class="alert-param"> | ||
| 67 | + <div class="title"><svg-icon name="tip" />{{ t('alertRule.alertContentTitle') }}</div> | ||
| 68 | + <div class="content"> | ||
| 69 | + <span>{{ t('alertRule.alertContentTip') }}</span> | ||
| 70 | + <el-row style="margin-top: 10px;"> | ||
| 71 | + <el-col :span="12" v-for="item in paramNameList" :key="item">{{ `${item}: | ||
| 72 | + ${alertContentParam[item]['name']}` }}</el-col> | ||
| 73 | + </el-row> | ||
| 74 | + </div> | ||
| 75 | + </div> | ||
| 76 | + </el-col> | ||
| 77 | + <el-col :span="15"> | ||
| 78 | + <el-form-item> | ||
| 79 | + <span>{{ previewContent }}</span> | ||
| 80 | + </el-form-item> | ||
| 81 | + </el-col> | ||
| 82 | + </el-row> | ||
| 83 | + <el-form-item :label="$t('alertRule.notifyDuration')" prop="notifyDuration"> | ||
| 84 | + <el-input v-model="formData.notifyDuration" style="width: 100px;margin-right: 5px;" disabled></el-input> | ||
| 85 | + <el-select v-model="formData.notifyDurationUnit" disabled style="width: 80px;"> | ||
| 86 | + <el-option v-for="item in durationUnitList" :key="item.name" :value="item.value" | ||
| 87 | + :label="$t(`alertRule.${item.name}`)" /> | ||
| 88 | + </el-select> | ||
| 89 | + </el-form-item> | ||
| 90 | + <el-form-item :label="$t('alertRule.alertDesc')" prop="alertDesc"> | ||
| 91 | + <el-input v-model="formData.alertDesc" style="width: 50%;"></el-input> | ||
| 92 | + </el-form-item> | ||
| 93 | + </el-form> | ||
| 94 | + <el-descriptions :title="$t('alertRule.notifyTitle')"></el-descriptions> | ||
| 95 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 96 | + <el-form-item :label="$t('alertRule.alertNotify')" prop="notifyDuration"> | ||
| 97 | + <el-checkbox-group v-model="alertNotifyList"> | ||
| 98 | + <el-checkbox label="firing">{{ $t('alertRule.firing') }}</el-checkbox> | ||
| 99 | + <el-checkbox label="recover">{{ $t('alertRule.recover') }}</el-checkbox> | ||
| 100 | + </el-checkbox-group> | ||
| 101 | + </el-form-item> | ||
| 102 | + <el-form-item :label="$t('alertRule.repeat')" prop="isRepeat"> | ||
| 103 | + <el-radio-group v-model="formData.isRepeat"> | ||
| 104 | + <el-radio :label="1">{{ $t('alertRule.isRepeat') }}</el-radio> | ||
| 105 | + <el-radio :label="0">{{ $t('alertRule.isNotRepeat') }}</el-radio> | ||
| 106 | + </el-radio-group> | ||
| 107 | + </el-form-item> | ||
| 108 | + <el-form-item :label="$t('alertRule.silence')" prop="isSilence"> | ||
| 109 | + <el-radio-group v-model="formData.isSilence"> | ||
| 110 | + <el-radio :label="1" key="1">{{ $t('alertRule.isSilence') }}</el-radio> | ||
| 111 | + <el-radio :label="0" key="0">{{ $t('alertRule.isNotSilence') }}</el-radio> | ||
| 112 | + </el-radio-group> | ||
| 113 | + <span style="margin-left: 30px;" v-if="formData.isSilence === 1 || formData.isSilence === '1'">{{ $t('alertRule.silenceTime') | ||
| 114 | + }}</span> | ||
| 115 | + <span style="width: 250px;margin-left: 5px;"> | ||
| 116 | + <el-date-picker v-if="formData.isSilence === 1 || formData.isSilence === '1'" v-model="silenceTimes" type="datetimerange" | ||
| 117 | + range-separator="~" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" | ||
| 118 | + :start-placeholder="t(`alertRecord.startTimePlaceholder`)" | ||
| 119 | + :end-placeholder="t(`alertRecord.endTimePlaceholder`)" /> | ||
| 120 | + </span> | ||
| 121 | + </el-form-item> | ||
| 122 | + <el-form-item :label="$t('alertRule.notifyWay')"> | ||
| 123 | + <el-select v-model="notifyWayIdArr" multiple> | ||
| 124 | + <el-option v-for="item in notifyWayList" :key="item.id" :value="item.id + ''" :label="item.name" /> | ||
| 125 | + </el-select> | ||
| 126 | + </el-form-item> | ||
| 127 | + </el-form> | ||
| 128 | + <el-row> | ||
| 129 | + <el-button type="primary" @click="confirm">{{ t('app.confirm') }}</el-button> | ||
| 130 | + <el-button @click="cancel">{{ t('app.cancel') }}</el-button> | ||
| 131 | + </el-row> | ||
| 132 | + </div> | ||
| 133 | +</template> | ||
| 134 | + | ||
| 135 | +<script setup lang='ts'> | ||
| 136 | +import "element-plus/es/components/message-box/style/index"; | ||
| 137 | +import { useRequest } from "vue-request"; | ||
| 138 | +import request from "@/request"; | ||
| 139 | +import { i18n } from "@/i18n"; | ||
| 140 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 141 | +import { useI18n } from "vue-i18n"; | ||
| 142 | +import SvgIcon from "@/components/SvgIcon.vue"; | ||
| 143 | +import { parseContent } from "@/utils/commonUtil" | ||
| 144 | +const { t } = useI18n(); | ||
| 145 | + | ||
| 146 | +const alertContentParam = ref<any>() | ||
| 147 | +const paramNameList = ref<any>() | ||
| 148 | +const previewContent = ref<string>() | ||
| 149 | + | ||
| 150 | +const props = withDefaults( | ||
| 151 | + defineProps<{ | ||
| 152 | + ruleId: number, | ||
| 153 | + templateRuleId: number, | ||
| 154 | + titleList: string[] | ||
| 155 | + }>(), | ||
| 156 | + { | ||
| 157 | + titleList: () => [] | ||
| 158 | + } | ||
| 159 | +); | ||
| 160 | +const emit = defineEmits(["updateTemplateRuleSuccess", "cancelUpdateTemplateRule"]); | ||
| 161 | + | ||
| 162 | +const ruleItemExpList = ref<any[]>() | ||
| 163 | +const actionList = ref<any[]>([{ | ||
| 164 | + name: t('alertRule.normalAction'), value: 'normal' | ||
| 165 | +}, { | ||
| 166 | + name: t('alertRule.increaseAction'), value: 'increase' | ||
| 167 | +}, { | ||
| 168 | + name: t('alertRule.decreaseAction'), value: 'decrease' | ||
| 169 | +}]) | ||
| 170 | +const durationUnitList = ref<any[]>([{ | ||
| 171 | + name: 'second', | ||
| 172 | + value: 's' | ||
| 173 | +}, { | ||
| 174 | + name: 'minute', | ||
| 175 | + value: 'm' | ||
| 176 | +}, { | ||
| 177 | + name: 'hour', | ||
| 178 | + value: 'h' | ||
| 179 | +}, { | ||
| 180 | + name: 'day', | ||
| 181 | + value: 'd' | ||
| 182 | +}]) | ||
| 183 | +const notifyWayIdArr = ref<string[]>([]) | ||
| 184 | +const notifyWayList = ref<string[]>([]) | ||
| 185 | +const logicSymbolList = ref<string[]>(['and', 'or']) | ||
| 186 | +const formData = ref<any>({ | ||
| 187 | + ruleName: '', | ||
| 188 | + ruleType: '', | ||
| 189 | + level: '', | ||
| 190 | + ruleExpComb: '', | ||
| 191 | + isRepeat: 1, | ||
| 192 | + isSilence: 0, | ||
| 193 | + alertRuleItemList: [] | ||
| 194 | +}) | ||
| 195 | +const ruleTypeList = reactive(['index', 'log']) | ||
| 196 | +const levelList = reactive(['serious', 'warn', 'info']) | ||
| 197 | +const ruleExpComb = ref<string[]>([]) | ||
| 198 | +const alertNotifyList = ref<string[]>([]) | ||
| 199 | +// const isRepeat = ref<string>('') | ||
| 200 | +// const isSilence = ref<string>('') | ||
| 201 | +const silenceTimes = ref<any[]>([]) | ||
| 202 | +const showLogicSelect = (logicSymbol: string) => { | ||
| 203 | + return logicSymbolList.value.includes(logicSymbol) | ||
| 204 | +} | ||
| 205 | + | ||
| 206 | +const ruleContent = ref<string>('') | ||
| 207 | +const reset = () => { | ||
| 208 | + formData.value.ruleContent = ruleContent.value | ||
| 209 | + preview() | ||
| 210 | +} | ||
| 211 | + | ||
| 212 | +const { data: ruleDetail, run: requestData } = useRequest( | ||
| 213 | + (templateRuleId, ruleId) => { | ||
| 214 | + if (templateRuleId) { | ||
| 215 | + return request.get(`/alertCenter/api/v1/alertTemplate/ruleList/${templateRuleId}`) | ||
| 216 | + } else { | ||
| 217 | + return request.get(`/alertCenter/api/v1/alertRule/${ruleId}`) | ||
| 218 | + } | ||
| 219 | + }, | ||
| 220 | + { manual: true } | ||
| 221 | +) | ||
| 222 | +watch(ruleDetail, (ruleDetail: any) => { | ||
| 223 | + if (ruleDetail && ruleDetail.code === 200) { | ||
| 224 | + formData.value = ruleDetail.data | ||
| 225 | + ruleContent.value = formData.value?.ruleContent | ||
| 226 | + if (formData.value?.ruleExpComb) { | ||
| 227 | + ruleExpComb.value = formData.value.ruleExpComb.split(',') | ||
| 228 | + } | ||
| 229 | + if (formData.value?.alertNotify) { | ||
| 230 | + alertNotifyList.value = formData.value.alertNotify.split(',') | ||
| 231 | + } | ||
| 232 | + if (formData.value.notifyWayIds) { | ||
| 233 | + notifyWayIdArr.value = formData.value.notifyWayIds.split(',') | ||
| 234 | + } | ||
| 235 | + if (formData.value.silenceStartTime && formData.value.silenceEndTime) { | ||
| 236 | + silenceTimes.value = [formData.value.silenceStartTime, formData.value.silenceEndTime] | ||
| 237 | + } | ||
| 238 | + if (alertContentParam.value && formData.value.ruleContent) { | ||
| 239 | + let param = {} | ||
| 240 | + let keys = Object.keys(alertContentParam.value); | ||
| 241 | + for (let key of keys) { | ||
| 242 | + param[key] = alertContentParam.value[key]['preVal'] | ||
| 243 | + } | ||
| 244 | + previewContent.value = parseContent(formData.value.ruleContent, param) | ||
| 245 | + } | ||
| 246 | + } else { | ||
| 247 | + const msg = t("app.queryFail"); | ||
| 248 | + ElMessage({ | ||
| 249 | + showClose: true, | ||
| 250 | + message: msg, | ||
| 251 | + type: "error", | ||
| 252 | + }); | ||
| 253 | + } | ||
| 254 | +}); | ||
| 255 | + | ||
| 256 | +const requestNotifyWayData = () => { | ||
| 257 | + request.get(`/alertCenter/api/v1/notifyWay/list`).then((res: any) => { | ||
| 258 | + if (res && res.code === 200) { | ||
| 259 | + notifyWayList.value = res.data | ||
| 260 | + } | ||
| 261 | + }) | ||
| 262 | +} | ||
| 263 | +const requestRuleItemList = () => { | ||
| 264 | + request.get(`/alertCenter/api/v1/alertRule/ruleItem/properties`).then((res: any) => { | ||
| 265 | + if (res && res.code === 200) { | ||
| 266 | + ruleItemExpList.value = res.data | ||
| 267 | + } | ||
| 268 | + }) | ||
| 269 | +} | ||
| 270 | + | ||
| 271 | +const confirm = () => { | ||
| 272 | + formData.value.ruleExpComb = ruleExpComb.value.join(',') | ||
| 273 | + formData.value.alertNotify = alertNotifyList.value.join(',') | ||
| 274 | + formData.value.notifyWayIds = notifyWayIdArr.value.join(',') | ||
| 275 | + if (silenceTimes.value.length > 0) { | ||
| 276 | + formData.value.silenceStartTime = silenceTimes.value[0] | ||
| 277 | + formData.value.silenceEndTime = silenceTimes.value[1] | ||
| 278 | + } | ||
| 279 | + if (formData.value.alertRuleItemList && formData.value.alertRuleItemList.length > 0) { | ||
| 280 | + for (let row of formData.value.alertRuleItemList) { | ||
| 281 | + if (row.ruleId) { | ||
| 282 | + row.ruleId = undefined | ||
| 283 | + } | ||
| 284 | + if (row.itemParamList && row.itemParamList.length > 0) { | ||
| 285 | + for (let row0 of row.itemParamList) { | ||
| 286 | + row0.ruleItemParamId = undefined | ||
| 287 | + row0.itemId = undefined | ||
| 288 | + } | ||
| 289 | + } | ||
| 290 | + } | ||
| 291 | + } | ||
| 292 | + request.post(`/alertCenter/api/v1/alertTemplate/templateRule`, formData.value).then((res: any) => { | ||
| 293 | + if (res && res.code === 200) { | ||
| 294 | + let data = res.data | ||
| 295 | + emit("updateTemplateRuleSuccess", data) | ||
| 296 | + } | ||
| 297 | + }) | ||
| 298 | +} | ||
| 299 | +const cancel = () => { | ||
| 300 | + emit("cancelUpdateTemplateRule") | ||
| 301 | +} | ||
| 302 | + | ||
| 303 | +const requestAlertContentParam = () => { | ||
| 304 | + request.get(`/alertCenter/api/v1/environment/alertContentParam`, { type: 'alert' }).then((res: any) => { | ||
| 305 | + if (res && res.code === 200) { | ||
| 306 | + alertContentParam.value = res.data | ||
| 307 | + paramNameList.value = Object.keys(alertContentParam.value) | ||
| 308 | + if (alertContentParam.value && formData.value.ruleContent) { | ||
| 309 | + let param = {} | ||
| 310 | + let keys = Object.keys(alertContentParam.value); | ||
| 311 | + for (let key of keys) { | ||
| 312 | + param[key] = alertContentParam.value[key]['preVal'] | ||
| 313 | + } | ||
| 314 | + previewContent.value = parseContent(formData.value.ruleContent, param) | ||
| 315 | + } | ||
| 316 | + } | ||
| 317 | + }) | ||
| 318 | +} | ||
| 319 | + | ||
| 320 | +const preview = () => { | ||
| 321 | + if (alertContentParam.value && formData.value.ruleContent) { | ||
| 322 | + let param = {} | ||
| 323 | + let keys = Object.keys(alertContentParam.value); | ||
| 324 | + for (let key of keys) { | ||
| 325 | + param[key] = alertContentParam.value[key]['preVal'] | ||
| 326 | + } | ||
| 327 | + previewContent.value = parseContent(formData.value.ruleContent, param) | ||
| 328 | + } | ||
| 329 | +} | ||
| 330 | + | ||
| 331 | +onMounted(() => { | ||
| 332 | + requestNotifyWayData() | ||
| 333 | + requestRuleItemList() | ||
| 334 | + requestAlertContentParam(); | ||
| 335 | + if (props.templateRuleId || props.ruleId) { | ||
| 336 | + requestData(props.templateRuleId, props.ruleId) | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + const wujie = window.$wujie; | ||
| 340 | + // Judge whether it is a plug-in environment or a local environment through wujie | ||
| 341 | + if (wujie) { | ||
| 342 | + // Monitoring platform language change | ||
| 343 | + wujie?.bus.$on('opengauss-locale-change', (val: string) => { | ||
| 344 | + console.log('log-search catch locale change'); | ||
| 345 | + nextTick(() => { | ||
| 346 | + actionList.value = [{ | ||
| 347 | + name: t('alertRule.normalAction'), value: 'normal' | ||
| 348 | + }, { | ||
| 349 | + name: t('alertRule.increaseAction'), value: 'increase' | ||
| 350 | + }, { | ||
| 351 | + name: t('alertRule.decreaseAction'), value: 'decrease' | ||
| 352 | + }] | ||
| 353 | + }); | ||
| 354 | + }); | ||
| 355 | + // wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 356 | + // nextTick(() => { | ||
| 357 | + // requestPisData() | ||
| 358 | + // }); | ||
| 359 | + // }); | ||
| 360 | + } | ||
| 361 | +}) | ||
| 362 | + | ||
| 363 | +</script> | ||
| 364 | +<style scoped lang='scss'> | ||
| 365 | +.alert-param { | ||
| 366 | + box-sizing: border-box; | ||
| 367 | + display: flex; | ||
| 368 | + flex-direction: column; | ||
| 369 | + position: absolute; | ||
| 370 | + align-items: flex-start; | ||
| 371 | + padding: 9px 16px; | ||
| 372 | + gap: 6px; | ||
| 373 | + // background: #F4FAFF; | ||
| 374 | + border: 1px solid #94BFFF; | ||
| 375 | + border-radius: 2px; | ||
| 376 | + | ||
| 377 | + .title { | ||
| 378 | + font-style: normal; | ||
| 379 | + font-weight: 800; | ||
| 380 | + font-size: 14px; | ||
| 381 | + line-height: 24px; | ||
| 382 | + // color: #1D2129; | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | + .content { | ||
| 386 | + font-style: normal; | ||
| 387 | + font-weight: 800; | ||
| 388 | + font-size: 12px; | ||
| 389 | + line-height: 18px; | ||
| 390 | + // color: #4E5969; | ||
| 391 | + } | ||
| 392 | +} | ||
| 393 | +</style> | ||
| @@ -0,0 +1,251 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('notifyTemplate.title') }}</el-breadcrumb-item> | ||
| 5 | + </el-breadcrumb> | ||
| 6 | + <el-divider /> | ||
| 7 | + <div class="search-form"> | ||
| 8 | + <div class="filter"> | ||
| 9 | + <el-button type="primary" @click="addTemplate">{{ $t('app.add') }}</el-button> | ||
| 10 | + </div> | ||
| 11 | + <div class="seperator"></div> | ||
| 12 | + <div class="filter"> | ||
| 13 | + <span>{{ $t('notifyTemplate.templateType') }}</span> | ||
| 14 | + <el-select v-model="formData.notifyTemplateType" style="width: 100px;margin: 5px;" @change="changeTemplateType" clearable> | ||
| 15 | + <el-option v-for="item in templateTypeList" :key="item.value" :value="item.value" :label="item.name" /> | ||
| 16 | + </el-select> | ||
| 17 | + </div> | ||
| 18 | + <div class="filter search"> | ||
| 19 | + <el-input v-model="formData.notifyTemplateName" style="width: 200px" | ||
| 20 | + :placeholder="$t('notifyTemplate.templateNamePlaceholder')"> | ||
| 21 | + <template #suffix> | ||
| 22 | + <el-button :icon="Search" @click="search" /> | ||
| 23 | + </template> | ||
| 24 | + </el-input> | ||
| 25 | + </div> | ||
| 26 | + </div> | ||
| 27 | + <div> | ||
| 28 | + <div> | ||
| 29 | + <el-table size="small" :data="tableDatas" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 30 | + <el-table-column :label="$t('notifyTemplate.templateName')" prop="notifyTemplateName" width="100"> | ||
| 31 | + </el-table-column> | ||
| 32 | + <el-table-column :label="$t('notifyTemplate.templateType')" prop="notifyTemplateType" width="100"> | ||
| 33 | + <template #default="scope"> | ||
| 34 | + <span>{{ $t(`notifyTemplate.${scope.row.notifyTemplateType}`) }}</span> | ||
| 35 | + </template> | ||
| 36 | + </el-table-column> | ||
| 37 | + <el-table-column :label="$t('notifyTemplate.notifyTitle')" prop="notifyTitle" width="100"> | ||
| 38 | + </el-table-column> | ||
| 39 | + <el-table-column :label="$t('notifyTemplate.notifyContent')" prop="notifyContent" min-width="200"> | ||
| 40 | + <template #default="scope"> | ||
| 41 | + <!-- <span style="white-space: pre-line;">{{ scope.row.notifyContent }}</span> --> | ||
| 42 | + <el-popover trigger="hover" :content="scope.row.notifyContent" | ||
| 43 | + popper-style="min-width: 200px;white-space: pre-line;" popper-class="sql-popover-tip"> | ||
| 44 | + <template #reference> | ||
| 45 | + <div style="overflow: hidden;text-overflow: ellipsis;white-space: pre-line;"> | ||
| 46 | + {{ showSubWord(scope.row.notifyContent) }}</div> | ||
| 47 | + </template> | ||
| 48 | + </el-popover> | ||
| 49 | + </template> | ||
| 50 | + </el-table-column> | ||
| 51 | + <el-table-column :label="$t('notifyTemplate.templateDesc')" prop="notifyTemplateDesc" min-width="200"> | ||
| 52 | + </el-table-column> | ||
| 53 | + <el-table-column :label="$t('app.operate')" width="120" fixed="right"> | ||
| 54 | + <template #default="scope"> | ||
| 55 | + <!-- <el-button link type="primary" size="small" @click="showDetail(scope.row.id)">{{ | ||
| 56 | + $t('app.view') | ||
| 57 | + }}</el-button> --> | ||
| 58 | + <el-button link type="primary" size="small" @click="editTemplate(scope.row.id)">{{ | ||
| 59 | + $t('app.edit') | ||
| 60 | + }}</el-button> | ||
| 61 | + <el-button link type="primary" size="small" @click="delTemplate(scope.row.id)">{{ | ||
| 62 | + $t('app.delete') | ||
| 63 | + }}</el-button> | ||
| 64 | + </template> | ||
| 65 | + </el-table-column> | ||
| 66 | + </el-table> | ||
| 67 | + <el-pagination v-model:currentPage="page.currentPage" v-model:pageSize="page.pageSize" :total="page.total" | ||
| 68 | + :page-sizes="[10, 20, 30, 40]" class="pagination" layout="total,sizes,prev,pager,next" background small | ||
| 69 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 70 | + </div> | ||
| 71 | + </div> | ||
| 72 | + </div> | ||
| 73 | + <div v-else> | ||
| 74 | + <NotifyTemplateDetail :id="curId" :state="state" @updateTemplate="updateTemplate" | ||
| 75 | + @cancelTemplate="cancelTemplate" /> | ||
| 76 | + </div> | ||
| 77 | +</template> | ||
| 78 | + | ||
| 79 | +<script setup lang='ts'> | ||
| 80 | +import { Search } from "@element-plus/icons-vue"; | ||
| 81 | +import "element-plus/es/components/message-box/style/index"; | ||
| 82 | +import { useRequest } from "vue-request"; | ||
| 83 | +import request from "@/request"; | ||
| 84 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 85 | +import { useI18n } from "vue-i18n"; | ||
| 86 | +import { cloneDeep } from 'lodash-es'; | ||
| 87 | +import NotifyTemplateDetail from "@/views/notify/NotifyTemplate/NotifyTemplateDetail.vue"; | ||
| 88 | + | ||
| 89 | +const theme = localStorage.getItem('theme'); | ||
| 90 | +const color = ref<string>(theme === 'dark' ? '#d4d4d4' : '#1d212a') | ||
| 91 | +const background = ref<string>(theme === 'dark' ? '#303030' : '#F5F7FB') | ||
| 92 | + | ||
| 93 | +const { t } = useI18n(); | ||
| 94 | +const initFormData = { | ||
| 95 | + notifyTemplateName: '', | ||
| 96 | + notifyTemplateType: '' | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +const showMain = ref<boolean>(true) | ||
| 100 | +const formData = ref<any>(cloneDeep(initFormData)); | ||
| 101 | +const tableDatas = ref<any[]>([]); | ||
| 102 | +const page = reactive({ | ||
| 103 | + currentPage: 1, | ||
| 104 | + pageSize: 10, | ||
| 105 | + total: 0, | ||
| 106 | +}); | ||
| 107 | +const templateTypeList = ref<any[]>([{ | ||
| 108 | + name: t('notifyTemplate.email'), value: 'email' | ||
| 109 | +}, { | ||
| 110 | + name: t('notifyTemplate.WeCom'), value: 'WeCom' | ||
| 111 | +}, { | ||
| 112 | + name: t('notifyTemplate.DingTalk'), value: 'DingTalk' | ||
| 113 | +}]) | ||
| 114 | +const curId = ref<number>() | ||
| 115 | +const state = ref<string>() | ||
| 116 | + | ||
| 117 | +const { data: res, run: requestData } = useRequest( | ||
| 118 | + () => { | ||
| 119 | + let params = {} | ||
| 120 | + params = Object.assign(params, formData.value, { pageNum: page.currentPage, pageSize: page.pageSize }) | ||
| 121 | + return request.get("/alertCenter/api/v1/notifyTemplate", params) | ||
| 122 | + }, | ||
| 123 | + { manual: true } | ||
| 124 | +); | ||
| 125 | +watch(res, (res: any) => { | ||
| 126 | + if (res && res.code === 200) { | ||
| 127 | + tableDatas.value = res.rows || [] | ||
| 128 | + page.total = res.total | ||
| 129 | + } else { | ||
| 130 | + tableDatas.value = [] | ||
| 131 | + page.total = 0 | ||
| 132 | + const msg = t("app.queryFail"); | ||
| 133 | + ElMessage({ | ||
| 134 | + showClose: true, | ||
| 135 | + message: msg, | ||
| 136 | + type: "error", | ||
| 137 | + }); | ||
| 138 | + } | ||
| 139 | +}); | ||
| 140 | +const search = () => { | ||
| 141 | + page.currentPage = 1 | ||
| 142 | + page.pageSize = 10 | ||
| 143 | + requestData() | ||
| 144 | +} | ||
| 145 | +const changeTemplateType = () => { | ||
| 146 | + search() | ||
| 147 | +} | ||
| 148 | +const handleSizeChange = (val: number) => { | ||
| 149 | + page.pageSize = val | ||
| 150 | + requestData() | ||
| 151 | +} | ||
| 152 | +const handleCurrentChange = (val: number) => { | ||
| 153 | + page.currentPage = val | ||
| 154 | + requestData() | ||
| 155 | +} | ||
| 156 | +const addTemplate = () => { | ||
| 157 | + state.value = 'add' | ||
| 158 | + showMain.value = false | ||
| 159 | +} | ||
| 160 | +// const showDetail = (id: number) => { | ||
| 161 | +// state.value = 'detail' | ||
| 162 | +// curId.value = id | ||
| 163 | +// showMain.value = false | ||
| 164 | +// } | ||
| 165 | +const editTemplate = (id: number) => { | ||
| 166 | + state.value = 'edit' | ||
| 167 | + curId.value = id | ||
| 168 | + showMain.value = false | ||
| 169 | +} | ||
| 170 | +const delTemplate = (id: number) => { | ||
| 171 | + ElMessageBox.confirm( | ||
| 172 | + t('app.deleteTip'), | ||
| 173 | + t('app.tip'), | ||
| 174 | + { | ||
| 175 | + confirmButtonText: t('app.confirm'), | ||
| 176 | + cancelButtonText: t('app.cancel'), | ||
| 177 | + type: 'warning', | ||
| 178 | + } | ||
| 179 | + ).then(() => { | ||
| 180 | + request.delete(`/alertCenter/api/v1/notifyTemplate/${id}`).then((res: any) => { | ||
| 181 | + if (res && res.code === 200) { | ||
| 182 | + ElMessage({ | ||
| 183 | + type: 'success', | ||
| 184 | + message: t('app.delSuccess'), | ||
| 185 | + }) | ||
| 186 | + formData.value = cloneDeep(initFormData) | ||
| 187 | + search() | ||
| 188 | + } else { | ||
| 189 | + ElMessage({ | ||
| 190 | + type: 'error', | ||
| 191 | + message: t('app.delFail') + (res && res.msg ? ',' + res.msg : ''), | ||
| 192 | + }) | ||
| 193 | + } | ||
| 194 | + }).catch((res: any) => { | ||
| 195 | + ElMessage({ | ||
| 196 | + type: 'error', | ||
| 197 | + message: t('app.delFail') + (res && res.msg ? ',' + res.msg : ''), | ||
| 198 | + }) | ||
| 199 | + }) | ||
| 200 | + }).catch(() => { | ||
| 201 | + | ||
| 202 | + }) | ||
| 203 | +} | ||
| 204 | +const updateTemplate = () => { | ||
| 205 | + formData.value = cloneDeep(initFormData) | ||
| 206 | + search() | ||
| 207 | + curId.value = undefined | ||
| 208 | + showMain.value = true | ||
| 209 | +} | ||
| 210 | +const cancelTemplate = () => { | ||
| 211 | + curId.value = undefined | ||
| 212 | + showMain.value = true | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +const showSubWord = (content: string) => { | ||
| 216 | + if (!content) { | ||
| 217 | + return '' | ||
| 218 | + } | ||
| 219 | + let contentArr = content.split('\n') | ||
| 220 | + if (contentArr.length > 1) { | ||
| 221 | + return contentArr[0] + '……' | ||
| 222 | + } else { | ||
| 223 | + return content; | ||
| 224 | + } | ||
| 225 | +} | ||
| 226 | + | ||
| 227 | +onMounted(() => { | ||
| 228 | + requestData() | ||
| 229 | + | ||
| 230 | + const wujie = window.$wujie; | ||
| 231 | + if (wujie) { | ||
| 232 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 233 | + nextTick(() => { | ||
| 234 | + color.value = theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 235 | + background.value = theme === 'dark' ? '#303030' : '#F5F7FB' | ||
| 236 | + }); | ||
| 237 | + }); | ||
| 238 | + } | ||
| 239 | +}) | ||
| 240 | + | ||
| 241 | +</script> | ||
| 242 | +<style scoped lang='scss'> | ||
| 243 | +.search-form { | ||
| 244 | + .search { | ||
| 245 | + :deep(.el-button--small) { | ||
| 246 | + background-color: v-bind(background) !important; | ||
| 247 | + color: v-bind(color) !important; | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | +} | ||
| 251 | +</style> | ||
| @@ -0,0 +1,275 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-breadcrumb separator="/"> | ||
| 4 | + <el-breadcrumb-item>{{ t('notifyTemplate.title') }}</el-breadcrumb-item> | ||
| 5 | + <el-breadcrumb-item v-if="state === 'add'">{{ t('notifyTemplate.addTitle') }}</el-breadcrumb-item> | ||
| 6 | + <el-breadcrumb-item v-if="state === 'edit'">{{ t('notifyTemplate.editTitle') }}</el-breadcrumb-item> | ||
| 7 | + <el-breadcrumb-item v-if="state === 'detail'">{{ t('notifyTemplate.detailTitle') }}</el-breadcrumb-item> | ||
| 8 | + </el-breadcrumb> | ||
| 9 | + <el-divider /> | ||
| 10 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 11 | + <el-form-item :label="$t('notifyTemplate.templateName')" prop="notifyTemplateName"> | ||
| 12 | + <el-input v-model="formData.notifyTemplateName" :placeholder="$t('notifyTemplate.templateNamePlaceholder')" | ||
| 13 | + :disabled="disabled"></el-input> | ||
| 14 | + </el-form-item> | ||
| 15 | + <el-form-item :label="$t('notifyTemplate.templateType')" prop="notifyTemplateType"> | ||
| 16 | + <el-select v-model="formData.notifyTemplateType" :disabled="disabled" style="width: 100px;margin: 5px;"> | ||
| 17 | + <el-option v-for="item in templateTypeList" :key="item.value" :value="item.value" :label="item.name" /> | ||
| 18 | + </el-select> | ||
| 19 | + </el-form-item> | ||
| 20 | + <el-form-item :label="$t('notifyTemplate.templateDesc')" prop="notifyTemplateDesc"> | ||
| 21 | + <el-input v-model="formData.notifyTemplateDesc" :placeholder="$t('notifyTemplate.templateDescPlaceholder')" | ||
| 22 | + :disabled="disabled"></el-input> | ||
| 23 | + </el-form-item> | ||
| 24 | + <el-form-item :label="$t('notifyTemplate.notifyTitle')" prop="notifyTitle"> | ||
| 25 | + <el-input v-model="formData.notifyTitle" :placeholder="$t('notifyTemplate.notifyTitlePlaceholder')" | ||
| 26 | + :disabled="disabled"></el-input> | ||
| 27 | + </el-form-item> | ||
| 28 | + <!-- <el-form-item :label="$t('notifyTemplate.notifyContent')" prop="notifyContent"> | ||
| 29 | + <el-input v-model="formData.notifyContent" type="textarea" :rows="10" | ||
| 30 | + :placeholder="$t('notifyTemplate.notifyContentPlaceholder')" :disabled="disabled"></el-input> | ||
| 31 | + </el-form-item> --> | ||
| 32 | + <el-row> | ||
| 33 | + <el-col :span="15"> | ||
| 34 | + <el-form-item :label="$t('notifyTemplate.notifyContent')" prop="notifyContent"> | ||
| 35 | + <el-input v-model="formData.notifyContent" type="textarea" :rows="10" | ||
| 36 | + :placeholder="$t('notifyTemplate.notifyContentPlaceholder')" :disabled="disabled"></el-input> | ||
| 37 | + </el-form-item> | ||
| 38 | + </el-col> | ||
| 39 | + <el-col :span="1"> | ||
| 40 | + <div style="margin: 5px 0;"> | ||
| 41 | + <el-button @click="reset">{{ t('app.reset') }}</el-button> | ||
| 42 | + </div> | ||
| 43 | + <div style="margin: 5px 0;"> | ||
| 44 | + <el-button @click="preview">{{ t('app.preview') }}</el-button> | ||
| 45 | + </div> | ||
| 46 | + </el-col> | ||
| 47 | + <el-col :span="8"> | ||
| 48 | + <div class="alert-param"> | ||
| 49 | + <div class="title"><svg-icon name="tip" />{{ t('notifyTemplate.notifyContentTitle') }}</div> | ||
| 50 | + <div class="content"> | ||
| 51 | + <span>{{ t('notifyTemplate.notifyContentTip') }}</span> | ||
| 52 | + <el-row style="margin-top: 10px;"> | ||
| 53 | + <el-col :span="12" v-for="item in paramNameList" :key="item">{{ `${item}: | ||
| 54 | + ${alertContentParam[item]['name']}` }}</el-col> | ||
| 55 | + </el-row> | ||
| 56 | + </div> | ||
| 57 | + </div> | ||
| 58 | + </el-col> | ||
| 59 | + </el-row> | ||
| 60 | + <el-row> | ||
| 61 | + <el-col :span="15"> | ||
| 62 | + <el-form-item :label="$t('notifyTemplate.previewContent')"> | ||
| 63 | + <el-input v-model="previewContent" type="textarea" :rows="10" | ||
| 64 | + :placeholder="$t('notifyTemplate.notifyContentPlaceholder')" disabled></el-input> | ||
| 65 | + </el-form-item> | ||
| 66 | + </el-col> | ||
| 67 | + </el-row> | ||
| 68 | + </el-form> | ||
| 69 | + <el-row style="margin-top: 10px;"> | ||
| 70 | + <el-button type="primary" @click="confirm" v-if="state !== 'detail'">{{ t('app.confirm') }}</el-button> | ||
| 71 | + <el-button @click="cancel">{{ t('app.cancel') }}</el-button> | ||
| 72 | + </el-row> | ||
| 73 | + </div> | ||
| 74 | +</template> | ||
| 75 | + | ||
| 76 | +<script setup lang='ts'> | ||
| 77 | +import "element-plus/es/components/message-box/style/index"; | ||
| 78 | +import { useRequest } from "vue-request"; | ||
| 79 | +import request from "@/request"; | ||
| 80 | +import { ElMessage } from "element-plus"; | ||
| 81 | +import { useI18n } from "vue-i18n"; | ||
| 82 | +import { cloneDeep } from 'lodash-es'; | ||
| 83 | +import type { FormInstance, FormRules } from 'element-plus' | ||
| 84 | +import SvgIcon from "@/components/SvgIcon.vue"; | ||
| 85 | +import { parseContent } from "@/utils/commonUtil" | ||
| 86 | + | ||
| 87 | +const alertContentParam = ref<any>() | ||
| 88 | +const paramNameList = ref<any>() | ||
| 89 | +const previewContent = ref<string>() | ||
| 90 | +const notifyContent = ref<string>('') | ||
| 91 | + | ||
| 92 | +const { t } = useI18n(); | ||
| 93 | +const props = withDefaults( | ||
| 94 | + defineProps<{ | ||
| 95 | + id: number, | ||
| 96 | + state: string, | ||
| 97 | + }>(), | ||
| 98 | + { | ||
| 99 | + state: 'detail' | ||
| 100 | + } | ||
| 101 | +) | ||
| 102 | + | ||
| 103 | +const emit = defineEmits(["updateTemplate", "cancelTemplate"]) | ||
| 104 | + | ||
| 105 | +const disabled = ref<boolean>(true) | ||
| 106 | +const initFormData = { | ||
| 107 | + id: '', | ||
| 108 | + notifyTemplateName: '', | ||
| 109 | + notifyTemplateType: '', | ||
| 110 | + notifyTemplateDesc: '', | ||
| 111 | + notifyTitle: '', | ||
| 112 | + notifyContent: '' | ||
| 113 | +} | ||
| 114 | +const formData = ref<any>(cloneDeep(initFormData)); | ||
| 115 | +const templateTypeList = ref<any[]>([{ | ||
| 116 | + name: t('notifyTemplate.email'), value: 'email' | ||
| 117 | +}, { | ||
| 118 | + name: t('notifyTemplate.WeCom'), value: 'WeCom' | ||
| 119 | +}, { | ||
| 120 | + name: t('notifyTemplate.DingTalk'), value: 'DingTalk' | ||
| 121 | +}]) | ||
| 122 | + | ||
| 123 | +const formRef = ref<FormInstance>() | ||
| 124 | +const formRules = reactive<FormRules>({ | ||
| 125 | + notifyTemplateName: [ | ||
| 126 | + { required: true, message: t('notifyTemplate.templateNamePlaceholder'), trigger: 'blur' }, | ||
| 127 | + ], | ||
| 128 | + notifyTemplateType: [ | ||
| 129 | + { required: true, message: t('notifyTemplate.templateTypePlaceholder'), trigger: 'blur' }, | ||
| 130 | + ], | ||
| 131 | + notifyTitle: [ | ||
| 132 | + { required: true, message: t('notifyTemplate.notifyTitlePlaceholder'), trigger: 'blur' }, | ||
| 133 | + ], | ||
| 134 | + notifyContent: [ | ||
| 135 | + { required: true, message: t('notifyTemplate.notifyContentPlaceholder'), trigger: 'blur' }, | ||
| 136 | + ], | ||
| 137 | + | ||
| 138 | +}) | ||
| 139 | + | ||
| 140 | +const { data: res, run: requestData } = useRequest( | ||
| 141 | + (id) => { | ||
| 142 | + return request.get(`/alertCenter/api/v1/notifyTemplate/${id}`) | ||
| 143 | + }, | ||
| 144 | + { manual: true } | ||
| 145 | +) | ||
| 146 | +watch(res, (res: any) => { | ||
| 147 | + if (res && res.code === 200) { | ||
| 148 | + formData.value = res.data | ||
| 149 | + notifyContent.value = formData.value.notifyContent | ||
| 150 | + if (alertContentParam.value && formData.value.notifyContent) { | ||
| 151 | + let param = {} | ||
| 152 | + let keys = Object.keys(alertContentParam.value); | ||
| 153 | + for (let key of keys) { | ||
| 154 | + param[key] = alertContentParam.value[key]['preVal'] | ||
| 155 | + } | ||
| 156 | + previewContent.value = parseContent(formData.value.notifyContent, param) | ||
| 157 | + } | ||
| 158 | + } else { | ||
| 159 | + const msg = t("app.queryFail"); | ||
| 160 | + ElMessage({ | ||
| 161 | + showClose: true, | ||
| 162 | + message: msg, | ||
| 163 | + type: "error", | ||
| 164 | + }); | ||
| 165 | + } | ||
| 166 | +}); | ||
| 167 | + | ||
| 168 | +const confirm = () => { | ||
| 169 | + if (!formRef) return | ||
| 170 | + formRef.value?.validate((valid, fields) => { | ||
| 171 | + if (valid) { | ||
| 172 | + request.post(`/alertCenter/api/v1/notifyTemplate`, formData.value).then((res: any) => { | ||
| 173 | + if (res && res.code === 200) { | ||
| 174 | + ElMessage({ | ||
| 175 | + message: t('app.saveSuccess'), | ||
| 176 | + type: 'success' | ||
| 177 | + }) | ||
| 178 | + formData.value = {} | ||
| 179 | + formData.value = cloneDeep(initFormData) | ||
| 180 | + emit("updateTemplate") | ||
| 181 | + } else { | ||
| 182 | + ElMessage({ | ||
| 183 | + message: t('app.saveFail'), | ||
| 184 | + type: 'error' | ||
| 185 | + }) | ||
| 186 | + } | ||
| 187 | + }).catch(() => { | ||
| 188 | + ElMessage({ | ||
| 189 | + message: t('app.saveFail'), | ||
| 190 | + type: 'error' | ||
| 191 | + }) | ||
| 192 | + }) | ||
| 193 | + } | ||
| 194 | + }) | ||
| 195 | +} | ||
| 196 | +const cancel = () => { | ||
| 197 | + formData.value = {} | ||
| 198 | + formData.value = cloneDeep(initFormData) | ||
| 199 | + emit("cancelTemplate") | ||
| 200 | +} | ||
| 201 | +const requestNotifyContentParam = () => { | ||
| 202 | + request.get(`/alertCenter/api/v1/environment/alertContentParam`, { type: 'notify' }).then((res: any) => { | ||
| 203 | + if (res && res.code === 200) { | ||
| 204 | + alertContentParam.value = res.data | ||
| 205 | + paramNameList.value = Object.keys(alertContentParam.value) | ||
| 206 | + if (alertContentParam.value && formData.value.notifyContent) { | ||
| 207 | + let param = {} | ||
| 208 | + let keys = Object.keys(alertContentParam.value); | ||
| 209 | + for (let key of keys) { | ||
| 210 | + param[key] = alertContentParam.value[key]['preVal'] | ||
| 211 | + } | ||
| 212 | + previewContent.value = parseContent(formData.value.notifyContent, param) | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + }) | ||
| 216 | +} | ||
| 217 | +const reset = () => { | ||
| 218 | + formData.value.notifyContent = notifyContent.value | ||
| 219 | + preview() | ||
| 220 | +} | ||
| 221 | +const preview = () => { | ||
| 222 | + if (alertContentParam.value && formData.value.notifyContent) { | ||
| 223 | + let param = {} | ||
| 224 | + let keys = Object.keys(alertContentParam.value); | ||
| 225 | + for (let key of keys) { | ||
| 226 | + param[key] = alertContentParam.value[key]['preVal'] | ||
| 227 | + } | ||
| 228 | + previewContent.value = parseContent(formData.value.notifyContent, param) | ||
| 229 | + } else { | ||
| 230 | + previewContent.value = '' | ||
| 231 | + } | ||
| 232 | +} | ||
| 233 | + | ||
| 234 | +onMounted(() => { | ||
| 235 | + requestNotifyContentParam() | ||
| 236 | + if (props.id) { | ||
| 237 | + requestData(props.id) | ||
| 238 | + } | ||
| 239 | + if (props.state !== 'detail') { | ||
| 240 | + disabled.value = false | ||
| 241 | + } else { | ||
| 242 | + disabled.value = true | ||
| 243 | + } | ||
| 244 | +}) | ||
| 245 | +</script> | ||
| 246 | +<style scoped lang='scss'> | ||
| 247 | +.alert-param { | ||
| 248 | + box-sizing: border-box; | ||
| 249 | + display: flex; | ||
| 250 | + flex-direction: column; | ||
| 251 | + position: absolute; | ||
| 252 | + align-items: flex-start; | ||
| 253 | + padding: 9px 16px; | ||
| 254 | + gap: 6px; | ||
| 255 | + // background: #F4FAFF; | ||
| 256 | + border: 1px solid #94BFFF; | ||
| 257 | + border-radius: 2px; | ||
| 258 | + | ||
| 259 | + .title { | ||
| 260 | + font-style: normal; | ||
| 261 | + font-weight: 800; | ||
| 262 | + font-size: 14px; | ||
| 263 | + line-height: 24px; | ||
| 264 | + // color: #1D2129; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + .content { | ||
| 268 | + font-style: normal; | ||
| 269 | + font-weight: 400; | ||
| 270 | + font-size: 12px; | ||
| 271 | + line-height: 18px; | ||
| 272 | + // color: #4E5969; | ||
| 273 | + } | ||
| 274 | +} | ||
| 275 | +</style> | ||
| @@ -0,0 +1,45 @@ | |||
| 1 | +<template> | ||
| 2 | + <el-breadcrumb separator="/"> | ||
| 3 | + <el-breadcrumb-item v-if="activeName === 'notifyWay'">{{ $t('notifyWay.title') }}</el-breadcrumb-item> | ||
| 4 | + <el-breadcrumb-item v-if="activeName === 'notifyConfig'">{{ $t('notifyConfig.title') }}</el-breadcrumb-item> | ||
| 5 | + <el-breadcrumb-item v-if="state === 'addNotifyWay'">{{ $t('notifyWay.addTitle') }}</el-breadcrumb-item> | ||
| 6 | + <el-breadcrumb-item v-if="state === 'editNotifyWay'">{{ $t('notifyWay.editTitle') }}</el-breadcrumb-item> | ||
| 7 | + <el-breadcrumb-item v-if="state === 'detailNotifyWay'">{{ $t('notifyWay.detailTitle') }}</el-breadcrumb-item> | ||
| 8 | + </el-breadcrumb> | ||
| 9 | + <el-divider /> | ||
| 10 | + <el-tabs v-model="activeName" @tab-click="handleClick"> | ||
| 11 | + <el-tab-pane :label="$t('notifyWay.title')" name="notifyWay"> | ||
| 12 | + <NotifyWay @updateState="updateState"/> | ||
| 13 | + </el-tab-pane> | ||
| 14 | + <el-tab-pane :label="$t('notifyConfig.title')" name="notifyConfig"> | ||
| 15 | + <NotifyConfig /> | ||
| 16 | + </el-tab-pane> | ||
| 17 | + </el-tabs> | ||
| 18 | +</template> | ||
| 19 | + | ||
| 20 | +<script setup lang='ts'> | ||
| 21 | +import "element-plus/es/components/message-box/style/index"; | ||
| 22 | +import { useI18n } from "vue-i18n"; | ||
| 23 | +import NotifyWay from "@/views/notify/NotifyWay/NotifyWay.vue"; | ||
| 24 | +import NotifyConfig from "@/views/notify/NotifyWay/NotifyConfig.vue"; | ||
| 25 | + | ||
| 26 | +const { t } = useI18n(); | ||
| 27 | + | ||
| 28 | +const activeName = ref<string>('notifyWay') | ||
| 29 | +const state = ref<string>('') | ||
| 30 | + | ||
| 31 | +const updateState = (val: string) => { | ||
| 32 | + state.value = val | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +const handleClick = () => { | ||
| 36 | + if (activeName.value === 'notifyConfig') { | ||
| 37 | + state.value = '' | ||
| 38 | + } | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +onMounted(() => { | ||
| 42 | +}) | ||
| 43 | + | ||
| 44 | +</script> | ||
| 45 | +<style scoped lang='scss'></style> | ||
| @@ -0,0 +1,375 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-row> | ||
| 4 | + <el-col :span="2"> | ||
| 5 | + <el-checkbox v-model="emailConfig.enable" :true-label="1" :false-label="0">{{ $t('notifyConfig.emailConfig') | ||
| 6 | + }}</el-checkbox> | ||
| 7 | + </el-col> | ||
| 8 | + <el-col :span="20" class="form-inline"> | ||
| 9 | + <el-form :inline="true" :model="emailConfig" ref="emailForm" :rules="emailRules" label-position="right" label-width="100px"> | ||
| 10 | + <el-form-item :label="$t('notifyConfig.senderEmail')" prop="email"> | ||
| 11 | + <el-input v-model="emailConfig.email" :disabled="emailConfig.enable === 0" | ||
| 12 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.senderEmail')" /> | ||
| 13 | + </el-form-item> | ||
| 14 | + <el-form-item :label="$t('notifyConfig.sender')" prop="sender"> | ||
| 15 | + <el-input v-model="emailConfig.sender" :disabled="emailConfig.enable === 0" | ||
| 16 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.sender')" /> | ||
| 17 | + </el-form-item> | ||
| 18 | + <el-form-item :label="$t('notifyConfig.sever')" prop="sever"> | ||
| 19 | + <el-input v-model="emailConfig.sever" :disabled="emailConfig.enable === 0" | ||
| 20 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.sever')" /> | ||
| 21 | + </el-form-item> | ||
| 22 | + <el-form-item :label="$t('notifyConfig.port')" prop="port"> | ||
| 23 | + <el-input v-model="emailConfig.port" :disabled="emailConfig.enable === 0" | ||
| 24 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.port')" /> | ||
| 25 | + </el-form-item> | ||
| 26 | + <el-form-item :label="$t('notifyConfig.account')" prop="account"> | ||
| 27 | + <el-input v-model="emailConfig.account" :disabled="emailConfig.enable === 0" | ||
| 28 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.account')" /> | ||
| 29 | + </el-form-item> | ||
| 30 | + <el-form-item :label="$t('notifyConfig.passwd')" prop="passwd"> | ||
| 31 | + <el-input v-model="emailConfig.passwd" :disabled="emailConfig.enable === 0" | ||
| 32 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.passwd')" /> | ||
| 33 | + </el-form-item> | ||
| 34 | + </el-form> | ||
| 35 | + </el-col> | ||
| 36 | + <el-col :span="2"> | ||
| 37 | + <el-button style="margin: 5px 10px" type="info" @click="testNotify('email')">{{ t('notifyConfig.test') | ||
| 38 | + }}</el-button> | ||
| 39 | + </el-col> | ||
| 40 | + </el-row> | ||
| 41 | + <el-row style="margin-top: 10px;"> | ||
| 42 | + <el-col :span="2"> | ||
| 43 | + <el-checkbox v-model="weComConfig.enable" :true-label="1" :false-label="0">{{ t('notifyConfig.weComConfig') | ||
| 44 | + }}</el-checkbox> | ||
| 45 | + </el-col> | ||
| 46 | + <el-col :span="20" class="form-inline"> | ||
| 47 | + <el-form :inline="true" :model="weComConfig" ref="weComForm" :rules="weComRules" label-position="right" label-width="100px"> | ||
| 48 | + <el-form-item :label="$t('notifyConfig.weComAppKey')" prop="appKey"> | ||
| 49 | + <el-input v-model="weComConfig.appKey" :disabled="weComConfig.enable === 0" | ||
| 50 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.weComAppKey')" /> | ||
| 51 | + </el-form-item> | ||
| 52 | + <el-form-item :label="$t('notifyConfig.agentId')" prop="agentId"> | ||
| 53 | + <el-input v-model="weComConfig.agentId" :disabled="weComConfig.enable === 0" | ||
| 54 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.agentId')" /> | ||
| 55 | + </el-form-item> | ||
| 56 | + <el-form-item :label="$t('notifyConfig.weComSecret')" prop="secret"> | ||
| 57 | + <el-input v-model="weComConfig.secret" :disabled="weComConfig.enable === 0" | ||
| 58 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.weComSecret')" /> | ||
| 59 | + </el-form-item> | ||
| 60 | + </el-form> | ||
| 61 | + </el-col> | ||
| 62 | + <el-col :span="2"> | ||
| 63 | + <el-button style="margin: 5px 10px" type="info">{{ t('notifyConfig.test') }}</el-button> | ||
| 64 | + </el-col> | ||
| 65 | + </el-row> | ||
| 66 | + <el-row style="margin-top: 10px;"> | ||
| 67 | + <el-col :span="2"> | ||
| 68 | + <el-checkbox v-model="dingTalkConfig.enable" :true-label="1" :false-label="0">{{ | ||
| 69 | + t('notifyConfig.dingTalkConfig') }}</el-checkbox> | ||
| 70 | + </el-col> | ||
| 71 | + <el-col :span="20" class="form-inline"> | ||
| 72 | + <el-form :inline="true" :model="dingTalkConfig" ref="dingTalkForm" :rules="dingTalkRules" label-position="right" label-width="100px"> | ||
| 73 | + <el-form-item :label="$t('notifyConfig.appKey')" prop="appKey"> | ||
| 74 | + <el-input v-model="dingTalkConfig.appKey" :disabled="dingTalkConfig.enable === 0" | ||
| 75 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.appKey')" /> | ||
| 76 | + </el-form-item> | ||
| 77 | + <el-form-item :label="$t('notifyConfig.agentId')" prop="agentId"> | ||
| 78 | + <el-input v-model="dingTalkConfig.agentId" :disabled="dingTalkConfig.enable === 0" | ||
| 79 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.agentId')" /> | ||
| 80 | + </el-form-item> | ||
| 81 | + <el-form-item :label="$t('notifyConfig.dingSecret')" prop="secret"> | ||
| 82 | + <el-input v-model="dingTalkConfig.secret" :disabled="dingTalkConfig.enable === 0" | ||
| 83 | + :placeholder="$t('notifyConfig.inputTip') + $t('notifyConfig.dingSecret')" /> | ||
| 84 | + </el-form-item> | ||
| 85 | + </el-form> | ||
| 86 | + </el-col> | ||
| 87 | + <el-col :span="2"> | ||
| 88 | + <el-button style="margin: 5px 10px" type="info">{{ t('notifyConfig.test') }}</el-button> | ||
| 89 | + </el-col> | ||
| 90 | + </el-row> | ||
| 91 | + <el-row style="margin-top: 10px;"> | ||
| 92 | + <el-button type="primary" @click="confirm">{{ t('app.confirm') }}</el-button> | ||
| 93 | + </el-row> | ||
| 94 | + <el-dialog v-model="dialogVisible" width="30%" :title="t('notifyConfig.test')" :before-close="handleClose"> | ||
| 95 | + <el-form-item :label="$t('alertRule.notifyWay')"> | ||
| 96 | + <el-select v-model="notifyWayId"> | ||
| 97 | + <el-option v-for="item in notifyWayList" :key="item.id" :value="item.id" :label="item.name" /> | ||
| 98 | + </el-select> | ||
| 99 | + </el-form-item> | ||
| 100 | + <template #footer> | ||
| 101 | + <span class="dialog-footer"> | ||
| 102 | + <el-button @click="handleClose">{{ t('app.cancel') }}</el-button> | ||
| 103 | + <el-button type="primary" @click="testNotifyConfig"> | ||
| 104 | + {{ t('app.confirm') }} | ||
| 105 | + </el-button> | ||
| 106 | + </span> | ||
| 107 | + </template> | ||
| 108 | + </el-dialog> | ||
| 109 | + </div> | ||
| 110 | +</template> | ||
| 111 | + | ||
| 112 | +<script setup lang='ts'> | ||
| 113 | +import { ElLoading } from 'element-plus' | ||
| 114 | +import "element-plus/es/components/message-box/style/index"; | ||
| 115 | +import { useRequest } from "vue-request"; | ||
| 116 | +import request from "@/request"; | ||
| 117 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 118 | +import { useI18n } from "vue-i18n"; | ||
| 119 | +import { cloneDeep } from 'lodash-es'; | ||
| 120 | +import type { FormInstance, FormRules } from 'element-plus' | ||
| 121 | +const { t } = useI18n(); | ||
| 122 | + | ||
| 123 | +const theme = localStorage.getItem('theme'); | ||
| 124 | +const color = ref<string>(theme === 'dark' ? '#d4d4d4' : '#1d212a') | ||
| 125 | +const background = ref<string>(theme === 'dark' ? '#303030' : '#F5F7FB') | ||
| 126 | + | ||
| 127 | +const baseConfig = { | ||
| 128 | + id: null, | ||
| 129 | + type: '', | ||
| 130 | + email: '', | ||
| 131 | + sender: '', | ||
| 132 | + sever: '', | ||
| 133 | + port: null, | ||
| 134 | + account: '', | ||
| 135 | + passwd: '', | ||
| 136 | + agentId: '', | ||
| 137 | + appKey: '', | ||
| 138 | + secret: '', | ||
| 139 | + enable: 0 | ||
| 140 | +} | ||
| 141 | +const emailConfig = ref<any>(Object.assign(cloneDeep(baseConfig), { type: 'email' })) | ||
| 142 | +const weComConfig = ref<any>(Object.assign(cloneDeep(baseConfig), { type: 'WeCom' })) | ||
| 143 | +const dingTalkConfig = ref<any>(Object.assign(cloneDeep(baseConfig), { type: 'DingTalk' })) | ||
| 144 | + | ||
| 145 | +const dialogVisible = ref<boolean>(false) | ||
| 146 | +const notifyWayId = ref<any>(); | ||
| 147 | +const notifyWayList = ref<any[]>([]) | ||
| 148 | +const curType = ref<any>(); | ||
| 149 | + | ||
| 150 | +const emailForm = ref<FormInstance>() | ||
| 151 | +const emailRules = reactive<FormRules>({ | ||
| 152 | + email: [ | ||
| 153 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.email'), trigger: 'blur' }, | ||
| 154 | + ], | ||
| 155 | + sender: [ | ||
| 156 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.sender'), trigger: 'blur' }, | ||
| 157 | + ], | ||
| 158 | + sever: [ | ||
| 159 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.sever'), trigger: 'blur' }, | ||
| 160 | + ], | ||
| 161 | + port: [ | ||
| 162 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.port'), trigger: 'blur' }, | ||
| 163 | + ], | ||
| 164 | + account: [ | ||
| 165 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.account'), trigger: 'blur' }, | ||
| 166 | + ], | ||
| 167 | + passwd: [ | ||
| 168 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.passwd'), trigger: 'blur' }, | ||
| 169 | + ] | ||
| 170 | +}) | ||
| 171 | +const weComForm = ref<FormInstance>() | ||
| 172 | +const weComRules = reactive<FormRules>({ | ||
| 173 | + appKey: [ | ||
| 174 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.weComAppKey'), trigger: 'blur' }, | ||
| 175 | + ], | ||
| 176 | + agentId: [ | ||
| 177 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.agentId'), trigger: 'blur' }, | ||
| 178 | + ], | ||
| 179 | + secret: [ | ||
| 180 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.weComSecret'), trigger: 'blur' }, | ||
| 181 | + ] | ||
| 182 | +}) | ||
| 183 | +const dingTalkForm = ref<FormInstance>() | ||
| 184 | +const dingTalkRules = reactive<FormRules>({ | ||
| 185 | + appKey: [ | ||
| 186 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.appKey'), trigger: 'blur' }, | ||
| 187 | + ], | ||
| 188 | + agentId: [ | ||
| 189 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.agentId'), trigger: 'blur' }, | ||
| 190 | + ], | ||
| 191 | + secret: [ | ||
| 192 | + { required: true, message: t('notifyConfig.inputTip') + t('notifyConfig.dingSecret'), trigger: 'blur' }, | ||
| 193 | + ] | ||
| 194 | +}) | ||
| 195 | + | ||
| 196 | +const { data: res, run: requestData } = useRequest( | ||
| 197 | + () => { | ||
| 198 | + return request.get("/alertCenter/api/v1/notifyConfig/list") | ||
| 199 | + }, | ||
| 200 | + { manual: true } | ||
| 201 | +); | ||
| 202 | +watch(res, (res: any) => { | ||
| 203 | + if (res && res.code === 200) { | ||
| 204 | + let list = res.data || [] | ||
| 205 | + let emailList = list.filter((item: any) => item.type === 'email') || [] | ||
| 206 | + if (emailList.length > 0) { | ||
| 207 | + emailConfig.value = emailList[0] | ||
| 208 | + } | ||
| 209 | + let weComList = list.filter((item: any) => item.type === 'WeCom') || [] | ||
| 210 | + if (weComList.length > 0) { | ||
| 211 | + weComConfig.value = weComList[0] | ||
| 212 | + } | ||
| 213 | + let dingTalkList = list.filter((item: any) => item.type === 'DingTalk') || [] | ||
| 214 | + if (dingTalkList.length > 0) { | ||
| 215 | + dingTalkConfig.value = dingTalkList[0] | ||
| 216 | + } | ||
| 217 | + } else { | ||
| 218 | + const msg = t("app.queryFail"); | ||
| 219 | + ElMessage({ | ||
| 220 | + showClose: true, | ||
| 221 | + message: msg, | ||
| 222 | + type: "error", | ||
| 223 | + }); | ||
| 224 | + } | ||
| 225 | +}); | ||
| 226 | +const requestNotifyWayData = (notifyType: string) => { | ||
| 227 | + request.get(`/alertCenter/api/v1/notifyWay/list`, { notifyType }).then((res: any) => { | ||
| 228 | + if (res && res.code === 200) { | ||
| 229 | + notifyWayList.value = res.data | ||
| 230 | + } | ||
| 231 | + }) | ||
| 232 | +} | ||
| 233 | +const testNotify = (type: string) => { | ||
| 234 | + dialogVisible.value = true | ||
| 235 | + notifyWayId.value = null | ||
| 236 | + curType.value = type | ||
| 237 | + requestNotifyWayData(type) | ||
| 238 | +} | ||
| 239 | +const loading = ref(false) // loading | ||
| 240 | +const openLoading = () => { | ||
| 241 | + loading.value = ElLoading.service({ | ||
| 242 | + lock: true, | ||
| 243 | + text: 'Loading', | ||
| 244 | + background: 'rgba(0, 0, 0, 0.7)' | ||
| 245 | + }) | ||
| 246 | +} | ||
| 247 | +const closeLoading = () => { | ||
| 248 | + loading.value.close() | ||
| 249 | +} | ||
| 250 | +const testNotifyConfig = () => { | ||
| 251 | + let param = {} | ||
| 252 | + if (curType.value === 'email') { | ||
| 253 | + param = Object.assign(param, emailConfig.value) | ||
| 254 | + } else if (curType.value === 'WeCom') { | ||
| 255 | + param = Object.assign(param, weComConfig.value) | ||
| 256 | + } else if (curType.value === 'DingTalk') { | ||
| 257 | + param = Object.assign(param, dingTalkConfig.value) | ||
| 258 | + } | ||
| 259 | + param = Object.assign(param, { notifyWayId: notifyWayId.value }) | ||
| 260 | + openLoading() | ||
| 261 | + request.post(`/alertCenter/api/v1/notifyConfig/testConfig`, param).then((res: any) => { | ||
| 262 | + if (res && res.code === 200) { | ||
| 263 | + ElMessage({ | ||
| 264 | + message: t('app.testSuccess'), | ||
| 265 | + type: 'success' | ||
| 266 | + }) | ||
| 267 | + } else { | ||
| 268 | + ElMessage({ | ||
| 269 | + message: t('app.testFail'), | ||
| 270 | + type: 'error' | ||
| 271 | + }) | ||
| 272 | + } | ||
| 273 | + closeLoading() | ||
| 274 | + }).catch(() => { | ||
| 275 | + ElMessage({ | ||
| 276 | + message: t('app.testFail'), | ||
| 277 | + type: 'error' | ||
| 278 | + }) | ||
| 279 | + closeLoading() | ||
| 280 | + }) | ||
| 281 | +} | ||
| 282 | +const handleClose = () => { | ||
| 283 | + dialogVisible.value = false | ||
| 284 | + notifyWayId.value = null | ||
| 285 | + curType.value = null | ||
| 286 | +} | ||
| 287 | + | ||
| 288 | +const confirm = async() => { | ||
| 289 | + if (emailConfig.value.enable === 1) { | ||
| 290 | + let valid = await emailForm.value?.validate(async(valid, fields) => { | ||
| 291 | + return valid | ||
| 292 | + }) | ||
| 293 | + if (!valid) { | ||
| 294 | + return | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | + if (weComConfig.value.enable === 1) { | ||
| 298 | + let valid = await weComForm.value?.validate(async(valid, fields) => { | ||
| 299 | + return valid | ||
| 300 | + }) | ||
| 301 | + if (!valid) { | ||
| 302 | + return | ||
| 303 | + } | ||
| 304 | + } | ||
| 305 | + if (dingTalkConfig.value.enable === 1) { | ||
| 306 | + let valid = await dingTalkForm.value?.validate(async(valid, fields) => { | ||
| 307 | + return valid | ||
| 308 | + }) | ||
| 309 | + if (!valid) { | ||
| 310 | + return | ||
| 311 | + } | ||
| 312 | + } | ||
| 313 | + let params = [emailConfig.value, weComConfig.value, dingTalkConfig.value] | ||
| 314 | + request.post(`/alertCenter/api/v1/notifyConfig/list`, params).then((res: any) => { | ||
| 315 | + if (res && res.code === 200) { | ||
| 316 | + ElMessage({ | ||
| 317 | + message: t('app.saveSuccess'), | ||
| 318 | + type: 'success' | ||
| 319 | + }) | ||
| 320 | + requestData() | ||
| 321 | + } else { | ||
| 322 | + ElMessage({ | ||
| 323 | + message: t('app.saveFail'), | ||
| 324 | + type: 'error' | ||
| 325 | + }) | ||
| 326 | + } | ||
| 327 | + }).catch(() => { | ||
| 328 | + ElMessage({ | ||
| 329 | + message: t('app.saveFail'), | ||
| 330 | + type: 'error' | ||
| 331 | + }) | ||
| 332 | + }) | ||
| 333 | +} | ||
| 334 | +onMounted(() => { | ||
| 335 | + requestData() | ||
| 336 | + | ||
| 337 | + const wujie = window.$wujie; | ||
| 338 | + if (wujie) { | ||
| 339 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 340 | + nextTick(() => { | ||
| 341 | + color.value = theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 342 | + background.value = theme === 'dark' ? '#303030' : '#F5F7FB' | ||
| 343 | + }); | ||
| 344 | + }); | ||
| 345 | + } | ||
| 346 | +}) | ||
| 347 | +</script> | ||
| 348 | +<style scoped lang='scss'> | ||
| 349 | +.form-inline { | ||
| 350 | + box-sizing: border-box; | ||
| 351 | + color: v-bind(color); | ||
| 352 | + background: v-bind(background); | ||
| 353 | + // background: #FBFBFB; | ||
| 354 | + | ||
| 355 | + border: 1px solid #EAEBEE; | ||
| 356 | + border-radius: 2px; | ||
| 357 | +} | ||
| 358 | + | ||
| 359 | +.el-form-item--small { | ||
| 360 | + margin: 10px; | ||
| 361 | +} | ||
| 362 | + | ||
| 363 | +.testBtn { | ||
| 364 | + box-sizing: border-box; | ||
| 365 | + justify-content: center; | ||
| 366 | + align-items: center; | ||
| 367 | + width: 60px; | ||
| 368 | + height: 32px; | ||
| 369 | + background: #FFFFFF; | ||
| 370 | + /* 边框/配置项按钮边框 */ | ||
| 371 | + border: 1px solid #D9D9D9; | ||
| 372 | + border-radius: 2px; | ||
| 373 | + margin: 5px 16px; | ||
| 374 | +} | ||
| 375 | +</style> | ||
| @@ -0,0 +1,237 @@ | |||
| 1 | +<template> | ||
| 2 | + <div v-if="showMain"> | ||
| 3 | + <div class="search-form"> | ||
| 4 | + <div class="filter"> | ||
| 5 | + <el-button type="primary" @click="addTemplate">{{ $t('app.add') }}</el-button> | ||
| 6 | + </div> | ||
| 7 | + <div class="seperator"></div> | ||
| 8 | + <div class="filter"> | ||
| 9 | + <span>{{ $t('notifyWay.notifyType') }}</span> | ||
| 10 | + <el-select v-model="formData.notifyType" style="width: 100px;margin: 5px;" | ||
| 11 | + @change="changeNotifyType" clearable> | ||
| 12 | + <el-option v-for="item in templateTypeList" :key="item.value" :value="item.value" :label="item.name" /> | ||
| 13 | + </el-select> | ||
| 14 | + </div> | ||
| 15 | + <div class="filter search"> | ||
| 16 | + <el-input v-model="formData.name" style="width: 200px" | ||
| 17 | + :placeholder="$t('notifyWay.namePlaceholder')"> | ||
| 18 | + <template #suffix> | ||
| 19 | + <el-button :icon="Search" @click="search" /> | ||
| 20 | + </template> | ||
| 21 | + </el-input> | ||
| 22 | + </div> | ||
| 23 | + </div> | ||
| 24 | + <div> | ||
| 25 | + <div> | ||
| 26 | + <el-table size="small" :data="tableDatas" style="width: 100%" header-cell-class-name="grid-header" border> | ||
| 27 | + <el-table-column :label="$t('notifyWay.name')" prop="name"> | ||
| 28 | + </el-table-column> | ||
| 29 | + <el-table-column :label="$t('notifyWay.notifyType')" prop="notifyType"> | ||
| 30 | + <template #default="scope"> | ||
| 31 | + <span>{{ $t(`notifyTemplate.${scope.row.notifyType}`) }}</span> | ||
| 32 | + </template> | ||
| 33 | + </el-table-column> | ||
| 34 | + <el-table-column :label="$t('notifyWay.notifyTarget')" min-width="200"> | ||
| 35 | + <template #default="scope"> | ||
| 36 | + <div v-if="scope.row.notifyType === 'email'">{{ scope.row.email }}</div> | ||
| 37 | + <div v-if="scope.row.notifyType === 'WeCom' || scope.row.notifyType === 'DingTalk'"> | ||
| 38 | + <div v-if="scope.row.personId">{{ $t('notifyWay.personId') + ': ' + scope.row.personId }}</div> | ||
| 39 | + <div v-if="scope.row.deptId">{{ $t('notifyWay.deptId') + ': ' + scope.row.deptId }}</div> | ||
| 40 | + </div> | ||
| 41 | + </template> | ||
| 42 | + </el-table-column> | ||
| 43 | + <el-table-column :label="$t('notifyTemplate.templateName')" prop="notifyTemplateName"> | ||
| 44 | + </el-table-column> | ||
| 45 | + <el-table-column :label="$t('app.operate')" width="120" fixed="right"> | ||
| 46 | + <template #default="scope"> | ||
| 47 | + <!-- <el-button link type="primary" size="small" @click="showDetail(scope.row.id)">{{ | ||
| 48 | + $t('app.view') | ||
| 49 | + }}</el-button> --> | ||
| 50 | + <el-button link type="primary" size="small" @click="editTemplate(scope.row.id)">{{ | ||
| 51 | + $t('app.edit') | ||
| 52 | + }}</el-button> | ||
| 53 | + <el-button link type="primary" size="small" @click="delTemplate(scope.row.id)">{{ | ||
| 54 | + $t('app.delete') | ||
| 55 | + }}</el-button> | ||
| 56 | + </template> | ||
| 57 | + </el-table-column> | ||
| 58 | + </el-table> | ||
| 59 | + <el-pagination v-model:currentPage="page.currentPage" v-model:pageSize="page.pageSize" :total="page.total" | ||
| 60 | + :page-sizes="[10, 20, 30, 40]" class="pagination" layout="total,sizes,prev,pager,next" background small | ||
| 61 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 62 | + </div> | ||
| 63 | + </div> | ||
| 64 | + </div> | ||
| 65 | + <div v-else> | ||
| 66 | + <NotifyWayDetail :id="curId" :state="state" @updateNotifyWay="updateNotifyWay" | ||
| 67 | + @cancelNotifyWay="cancelNotifyWay" /> | ||
| 68 | + </div> | ||
| 69 | +</template> | ||
| 70 | + | ||
| 71 | +<script setup lang='ts'> | ||
| 72 | +import { Search } from "@element-plus/icons-vue"; | ||
| 73 | +import "element-plus/es/components/message-box/style/index"; | ||
| 74 | +import { useRequest } from "vue-request"; | ||
| 75 | +import request from "@/request"; | ||
| 76 | +import { ElMessageBox, ElMessage } from "element-plus"; | ||
| 77 | +import { useI18n } from "vue-i18n"; | ||
| 78 | +import { cloneDeep } from 'lodash-es'; | ||
| 79 | +import NotifyWayDetail from "@/views/notify/NotifyWay/NotifyWayDetail.vue"; | ||
| 80 | + | ||
| 81 | +const emit = defineEmits(["updateState"]) | ||
| 82 | + | ||
| 83 | +const theme = localStorage.getItem('theme'); | ||
| 84 | +const color = ref<string>(theme === 'dark' ? '#d4d4d4' : '#1d212a') | ||
| 85 | +const background = ref<string>(theme === 'dark' ? '#303030' : '#F5F7FB') | ||
| 86 | + | ||
| 87 | +const { t } = useI18n(); | ||
| 88 | +const initFormData = { | ||
| 89 | + name: '', | ||
| 90 | + notifyType: '' | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +const showMain = ref<boolean>(true) | ||
| 94 | +const formData = ref<any>(cloneDeep(initFormData)); | ||
| 95 | +const tableDatas = ref<any[]>([]); | ||
| 96 | +const page = reactive({ | ||
| 97 | + currentPage: 1, | ||
| 98 | + pageSize: 10, | ||
| 99 | + total: 0, | ||
| 100 | +}); | ||
| 101 | +const templateTypeList = ref<any[]>([{ | ||
| 102 | + name: t('notifyTemplate.email'), value: 'email' | ||
| 103 | +}, { | ||
| 104 | + name: t('notifyTemplate.WeCom'), value: 'WeCom' | ||
| 105 | +}, { | ||
| 106 | + name: t('notifyTemplate.DingTalk'), value: 'DingTalk' | ||
| 107 | +}]) | ||
| 108 | +const curId = ref<number>() | ||
| 109 | +const state = ref<string>() | ||
| 110 | + | ||
| 111 | +const { data: res, run: requestData } = useRequest( | ||
| 112 | + () => { | ||
| 113 | + let params = {} | ||
| 114 | + params = Object.assign(params, formData.value, { pageNum: page.currentPage, pageSize: page.pageSize }) | ||
| 115 | + return request.get("/alertCenter/api/v1/notifyWay", params) | ||
| 116 | + }, | ||
| 117 | + { manual: true } | ||
| 118 | +); | ||
| 119 | +watch(res, (res: any) => { | ||
| 120 | + if (res && res.code === 200) { | ||
| 121 | + tableDatas.value = res.rows || [] | ||
| 122 | + page.total = res.total | ||
| 123 | + } else { | ||
| 124 | + tableDatas.value = [] | ||
| 125 | + page.total = 0 | ||
| 126 | + const msg = t("app.queryFail"); | ||
| 127 | + ElMessage({ | ||
| 128 | + showClose: true, | ||
| 129 | + message: msg, | ||
| 130 | + type: "error", | ||
| 131 | + }); | ||
| 132 | + } | ||
| 133 | +}); | ||
| 134 | +const search = () => { | ||
| 135 | + page.currentPage = 1 | ||
| 136 | + page.pageSize = 10 | ||
| 137 | + requestData() | ||
| 138 | +} | ||
| 139 | +const changeNotifyType = () => { | ||
| 140 | + search() | ||
| 141 | +} | ||
| 142 | +const handleSizeChange = (val: number) => { | ||
| 143 | + page.pageSize = val | ||
| 144 | + requestData() | ||
| 145 | +} | ||
| 146 | +const handleCurrentChange = (val: number) => { | ||
| 147 | + page.currentPage = val | ||
| 148 | + requestData() | ||
| 149 | +} | ||
| 150 | +const addTemplate = () => { | ||
| 151 | + emit('updateState', 'addNotifyWay') | ||
| 152 | + state.value = 'add' | ||
| 153 | + showMain.value = false | ||
| 154 | +} | ||
| 155 | +// const showDetail = (id: number) => { | ||
| 156 | +// state.value = 'detail' | ||
| 157 | +// curId.value = id | ||
| 158 | +// showMain.value = false | ||
| 159 | +// } | ||
| 160 | +const editTemplate = (id: number) => { | ||
| 161 | + emit('updateState', 'editNotifyWay') | ||
| 162 | + curId.value = id | ||
| 163 | + state.value = 'edit' | ||
| 164 | + showMain.value = false | ||
| 165 | +} | ||
| 166 | +const delTemplate = (id: number) => { | ||
| 167 | + ElMessageBox.confirm( | ||
| 168 | + t('app.deleteTip'), | ||
| 169 | + t('app.tip'), | ||
| 170 | + { | ||
| 171 | + confirmButtonText: t('app.confirm'), | ||
| 172 | + cancelButtonText: t('app.cancel'), | ||
| 173 | + type: 'warning', | ||
| 174 | + } | ||
| 175 | + ).then(() => { | ||
| 176 | + request.delete(`/alertCenter/api/v1/notifyWay/${id}`).then((res: any) => { | ||
| 177 | + if (res && res.code === 200) { | ||
| 178 | + ElMessage({ | ||
| 179 | + type: 'success', | ||
| 180 | + message: t('app.delSuccess'), | ||
| 181 | + }) | ||
| 182 | + formData.value = cloneDeep(initFormData) | ||
| 183 | + search() | ||
| 184 | + } else { | ||
| 185 | + ElMessage({ | ||
| 186 | + type: 'error', | ||
| 187 | + message: t('app.delFail') + (res && res.msg ? ',' + res.msg : ''), | ||
| 188 | + }) | ||
| 189 | + } | ||
| 190 | + }).catch((res: any) => { | ||
| 191 | + ElMessage({ | ||
| 192 | + type: 'error', | ||
| 193 | + message: t('app.delFail') + (res && res.msg ? ',' + res.msg : ''), | ||
| 194 | + }) | ||
| 195 | + }) | ||
| 196 | + }).catch(() => { | ||
| 197 | + | ||
| 198 | + }) | ||
| 199 | +} | ||
| 200 | +const updateNotifyWay = () => { | ||
| 201 | + formData.value = cloneDeep(initFormData) | ||
| 202 | + search() | ||
| 203 | + curId.value = undefined | ||
| 204 | + emit('updateState', '') | ||
| 205 | + showMain.value = true | ||
| 206 | +} | ||
| 207 | +const cancelNotifyWay = () => { | ||
| 208 | + curId.value = undefined | ||
| 209 | + emit('updateState', '') | ||
| 210 | + showMain.value = true | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +onMounted(() => { | ||
| 214 | + requestData() | ||
| 215 | + | ||
| 216 | + const wujie = window.$wujie; | ||
| 217 | + if (wujie) { | ||
| 218 | + wujie?.bus.$on('opengauss-theme-change', (val: string) => { | ||
| 219 | + nextTick(() => { | ||
| 220 | + color.value = theme === 'dark' ? '#d4d4d4' : '#1d212a' | ||
| 221 | + background.value = theme === 'dark' ? '#303030' : '#F5F7FB' | ||
| 222 | + }); | ||
| 223 | + }); | ||
| 224 | + } | ||
| 225 | +}) | ||
| 226 | + | ||
| 227 | +</script> | ||
| 228 | +<style scoped lang='scss'> | ||
| 229 | +.search-form { | ||
| 230 | + .search { | ||
| 231 | + :deep(.el-button--small) { | ||
| 232 | + background-color: v-bind(background) !important; | ||
| 233 | + color: v-bind(color) !important; | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | +} | ||
| 237 | +</style> | ||
| @@ -0,0 +1,218 @@ | |||
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-form :model="formData" :rules="formRules" ref="formRef" label-position="right" label-width="100px"> | ||
| 4 | + <el-form-item :label="$t('notifyWay.name')" prop="name"> | ||
| 5 | + <el-input v-model="formData.name" :placeholder="$t('notifyWay.namePlaceholder')" | ||
| 6 | + :disabled="disabled"></el-input> | ||
| 7 | + </el-form-item> | ||
| 8 | + <el-form-item :label="$t('notifyWay.notifyType')" prop="notifyType"> | ||
| 9 | + <el-select v-model="formData.notifyType" :disabled="disabled" style="margin: 5px;" | ||
| 10 | + @change="notifyTypeChange"> | ||
| 11 | + <el-option v-for="item in templateTypeList" :key="item.value" :value="item.value" :label="item.name" /> | ||
| 12 | + </el-select> | ||
| 13 | + </el-form-item> | ||
| 14 | + <el-form-item :label="$t('notifyTemplate.email')" prop="email" v-if="formData.notifyType === 'email'" | ||
| 15 | + :required="true"> | ||
| 16 | + <el-input v-model="formData.email" :placeholder="$t('notifyWay.emailPlaceholder')" | ||
| 17 | + :disabled="disabled"></el-input> | ||
| 18 | + </el-form-item> | ||
| 19 | + <el-form-item :label="$t('notifyWay.personId')" | ||
| 20 | + v-if="formData.notifyType === 'WeCom' || formData.notifyType === 'DingTalk'"> | ||
| 21 | + <el-input v-model="formData.personId" :placeholder="$t('notifyWay.personIdPlaceholder')" | ||
| 22 | + :disabled="disabled"></el-input> | ||
| 23 | + </el-form-item> | ||
| 24 | + <el-form-item :label="$t('notifyWay.deptId')" | ||
| 25 | + v-if="formData.notifyType === 'WeCom' || formData.notifyType === 'DingTalk'"> | ||
| 26 | + <el-input v-model="formData.deptId" :placeholder="$t('notifyWay.deptIdPlaceholder')" | ||
| 27 | + :disabled="disabled"></el-input> | ||
| 28 | + </el-form-item> | ||
| 29 | + <el-form-item | ||
| 30 | + :label="formData.notifyType === 'email' ? $t('notifyWay.emailTemplate') : formData.notifyType === 'WeCom' ? $t('notifyWay.WeComTemplate') : formData.notifyType === 'DingTalk' ? $t('notifyWay.DingTalkTemplate') : ''" | ||
| 31 | + prop="notifyTemplateId" v-if="formData.notifyType"> | ||
| 32 | + <el-select v-model="formData.notifyTemplateId" :disabled="disabled" style="margin: 5px;"> | ||
| 33 | + <el-option v-for="item in templateList" :key="item.id" :value="item.id" | ||
| 34 | + :label="item.notifyTemplateName" /> | ||
| 35 | + </el-select> | ||
| 36 | + </el-form-item> | ||
| 37 | + </el-form> | ||
| 38 | + <el-row style="margin-top: 10px;"> | ||
| 39 | + <el-button type="primary" @click="confirm" v-if="state !== 'detail'">{{ t('app.confirm') }}</el-button> | ||
| 40 | + <el-button @click="cancel">{{ t('app.cancel') }}</el-button> | ||
| 41 | + </el-row> | ||
| 42 | + </div> | ||
| 43 | +</template> | ||
| 44 | + | ||
| 45 | +<script setup lang='ts'> | ||
| 46 | +import "element-plus/es/components/message-box/style/index"; | ||
| 47 | +import { useRequest } from "vue-request"; | ||
| 48 | +import request from "@/request"; | ||
| 49 | +import { ElMessage } from "element-plus"; | ||
| 50 | +import { useI18n } from "vue-i18n"; | ||
| 51 | +import { cloneDeep } from 'lodash-es'; | ||
| 52 | +import type { FormInstance, FormRules } from 'element-plus' | ||
| 53 | + | ||
| 54 | +const validateEmailNotNull = (rule: any, value: any, callback: any) => { | ||
| 55 | + if (formData.value.notifyType === 'email') { | ||
| 56 | + if (!value) { | ||
| 57 | + callback(new Error(t('notifyWay.emailPlaceholder'))) | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + callback() | ||
| 61 | +} | ||
| 62 | +const { t } = useI18n(); | ||
| 63 | +const props = withDefaults( | ||
| 64 | + defineProps<{ | ||
| 65 | + id: number, | ||
| 66 | + state: string, | ||
| 67 | + }>(), | ||
| 68 | + { | ||
| 69 | + state: 'detail', | ||
| 70 | + } | ||
| 71 | +) | ||
| 72 | + | ||
| 73 | +const emit = defineEmits(["updateNotifyWay", "cancelNotifyWay"]) | ||
| 74 | + | ||
| 75 | +const disabled = ref<boolean>(true) | ||
| 76 | +const initFormData = { | ||
| 77 | + id: '', | ||
| 78 | + name: '', | ||
| 79 | + notifyType: '', | ||
| 80 | + email: '', | ||
| 81 | + personId: '', | ||
| 82 | + deptId: '', | ||
| 83 | + notifyTemplateId: null | ||
| 84 | +} | ||
| 85 | +const formData = ref<any>(cloneDeep(initFormData)); | ||
| 86 | +const templateTypeList = ref<any[]>([{ | ||
| 87 | + name: t('notifyTemplate.email'), value: 'email' | ||
| 88 | +}, { | ||
| 89 | + name: t('notifyTemplate.WeCom'), value: 'WeCom' | ||
| 90 | +}, { | ||
| 91 | + name: t('notifyTemplate.DingTalk'), value: 'DingTalk' | ||
| 92 | +}]) | ||
| 93 | +const templateList = ref<any[]>([]) | ||
| 94 | + | ||
| 95 | +const formRef = ref<FormInstance>() | ||
| 96 | +const formRules = reactive<FormRules>({ | ||
| 97 | + name: [ | ||
| 98 | + { required: true, message: t('notifyWay.namePlaceholder'), trigger: 'blur' }, | ||
| 99 | + ], | ||
| 100 | + notifyType: [ | ||
| 101 | + { required: true, message: t('notifyWay.notifyTypePlaceholder'), trigger: 'blur' }, | ||
| 102 | + ], | ||
| 103 | + email: [ | ||
| 104 | + { validator: validateEmailNotNull, message: t('notifyWay.emailPlaceholder'), trigger: 'blur' }, | ||
| 105 | + ], | ||
| 106 | + notifyTemplateId: [ | ||
| 107 | + { required: true, message: t('notifyWay.templatePlaceholder'), trigger: 'blur' }, | ||
| 108 | + ], | ||
| 109 | + | ||
| 110 | +}) | ||
| 111 | + | ||
| 112 | +const { data: res, run: requestData } = useRequest( | ||
| 113 | + (id) => { | ||
| 114 | + return request.get(`/alertCenter/api/v1/notifyWay/${id}`) | ||
| 115 | + }, | ||
| 116 | + { manual: true } | ||
| 117 | +) | ||
| 118 | +watch(res, (res: any) => { | ||
| 119 | + if (res && res.code === 200) { | ||
| 120 | + formData.value = res.data | ||
| 121 | + if (formData.value.notifyType) { | ||
| 122 | + requestTemplateData(formData.value.notifyType) | ||
| 123 | + } | ||
| 124 | + } else { | ||
| 125 | + const msg = t("app.queryFail"); | ||
| 126 | + ElMessage({ | ||
| 127 | + showClose: true, | ||
| 128 | + message: msg, | ||
| 129 | + type: "error", | ||
| 130 | + }); | ||
| 131 | + } | ||
| 132 | +}); | ||
| 133 | + | ||
| 134 | +const { data: templateRes, run: requestTemplateData } = useRequest( | ||
| 135 | + (notifyTemplateType) => { | ||
| 136 | + return request.get(`/alertCenter/api/v1/notifyTemplate/list`, { notifyTemplateType }) | ||
| 137 | + }, | ||
| 138 | + { manual: true } | ||
| 139 | +) | ||
| 140 | +watch(templateRes, (templateRes: any) => { | ||
| 141 | + if (templateRes && templateRes.code === 200) { | ||
| 142 | + templateList.value = templateRes.data || [] | ||
| 143 | + } else { | ||
| 144 | + const msg = t("app.queryFail"); | ||
| 145 | + ElMessage({ | ||
| 146 | + showClose: true, | ||
| 147 | + message: msg, | ||
| 148 | + type: "error", | ||
| 149 | + }); | ||
| 150 | + } | ||
| 151 | +}); | ||
| 152 | + | ||
| 153 | +const notifyTypeChange = () => { | ||
| 154 | + formData.notifyTemplateId = null | ||
| 155 | + if (!formData.value.notifyType) { | ||
| 156 | + templateList.value = [] | ||
| 157 | + return | ||
| 158 | + } | ||
| 159 | + formData.value.email = '' | ||
| 160 | + formData.value.personId = '' | ||
| 161 | + formData.value.deptId = '' | ||
| 162 | + requestTemplateData(formData.value.notifyType) | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +const confirm = () => { | ||
| 166 | + if (!formRef) return | ||
| 167 | + formRef.value?.validate((valid, fields) => { | ||
| 168 | + if (valid) { | ||
| 169 | + if ((formData.value.notifyType === 'WeCom' || formData.value.notifyType === 'DingTalk') && !formData.value.personId && !formData.value.deptId) { | ||
| 170 | + const msg = t("notifyWay.existOneOfTargetTip"); | ||
| 171 | + ElMessage({ | ||
| 172 | + showClose: true, | ||
| 173 | + message: msg, | ||
| 174 | + type: "error", | ||
| 175 | + }); | ||
| 176 | + return | ||
| 177 | + } | ||
| 178 | + request.post(`/alertCenter/api/v1/notifyWay`, formData.value).then((res: any) => { | ||
| 179 | + if (res && res.code === 200) { | ||
| 180 | + ElMessage({ | ||
| 181 | + message: t('app.saveSuccess'), | ||
| 182 | + type: 'success' | ||
| 183 | + }) | ||
| 184 | + formData.value = {} | ||
| 185 | + formData.value = cloneDeep(initFormData) | ||
| 186 | + emit("updateNotifyWay") | ||
| 187 | + } else { | ||
| 188 | + ElMessage({ | ||
| 189 | + message: t('app.saveFail'), | ||
| 190 | + type: 'error' | ||
| 191 | + }) | ||
| 192 | + } | ||
| 193 | + }).catch(() => { | ||
| 194 | + ElMessage({ | ||
| 195 | + message: t('app.saveFail'), | ||
| 196 | + type: 'error' | ||
| 197 | + }) | ||
| 198 | + }) | ||
| 199 | + } | ||
| 200 | + }) | ||
| 201 | +} | ||
| 202 | +const cancel = () => { | ||
| 203 | + formData.value = {} | ||
| 204 | + formData.value = cloneDeep(initFormData) | ||
| 205 | + emit("cancelNotifyWay") | ||
| 206 | +} | ||
| 207 | +onMounted(() => { | ||
| 208 | + if (props.id) { | ||
| 209 | + requestData(props.id) | ||
| 210 | + } | ||
| 211 | + if (props.state !== 'detail') { | ||
| 212 | + disabled.value = false | ||
| 213 | + } else { | ||
| 214 | + disabled.value = true | ||
| 215 | + } | ||
| 216 | +}) | ||
| 217 | +</script> | ||
| 218 | +<style scoped lang='scss'></style> | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +/// <reference types="vite/client" /> | ||
| 2 | + | ||
| 3 | +declare module "*.vue" { | ||
| 4 | + import type { DefineComponent } from "vue"; | ||
| 5 | + const component: DefineComponent<{}, {}, any>; | ||
| 6 | + export default component; | ||
| 7 | +} | ||
| 8 | +declare module 'jsencrypt' | ||
| @@ -0,0 +1,19 @@ | |||
| 1 | +{ | ||
| 2 | + "compilerOptions": { | ||
| 3 | + "target": "ESNext", | ||
| 4 | + "useDefineForClassFields": true, | ||
| 5 | + "module": "ESNext", | ||
| 6 | + "moduleResolution": "Node", | ||
| 7 | + "strict": true, | ||
| 8 | + "jsx": "preserve", | ||
| 9 | + "sourceMap": true, | ||
| 10 | + "resolveJsonModule": true, | ||
| 11 | + "isolatedModules": false, | ||
| 12 | + "esModuleInterop": true, | ||
| 13 | + "lib": ["ESNext", "DOM"], | ||
| 14 | + "skipLibCheck": true, | ||
| 15 | + "allowSyntheticDefaultImports": true | ||
| 16 | + }, | ||
| 17 | + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], | ||
| 18 | + "references": [{ "path": "./tsconfig.node.json" }] | ||
| 19 | +} | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | +{ | ||
| 2 | + "compilerOptions": { | ||
| 3 | + "composite": true, | ||
| 4 | + "module": "ESNext", | ||
| 5 | + "moduleResolution": "Node", | ||
| 6 | + "allowSyntheticDefaultImports": true | ||
| 7 | + }, | ||
| 8 | + "include": ["vite.config.ts"] | ||
| 9 | +} | ||
| @@ -0,0 +1,65 @@ | |||
| 1 | +import { defineConfig, loadEnv } from "vite"; | ||
| 2 | +import vue from "@vitejs/plugin-vue"; | ||
| 3 | +import AutoImport from "unplugin-auto-import/vite"; | ||
| 4 | +import Components from "unplugin-vue-components/vite"; | ||
| 5 | +import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; | ||
| 6 | +import { createSvgIconsPlugin } from "vite-plugin-svg-icons"; | ||
| 7 | +import { resolve } from "path"; | ||
| 8 | + | ||
| 9 | +// https://vitejs.dev/config/ | ||
| 10 | +export default defineConfig(({ command, mode }) => { | ||
| 11 | + loadEnv(mode, process.cwd()); | ||
| 12 | + return { | ||
| 13 | + base: mode === "production" ? "/static-plugin/alert-center/" : "/", | ||
| 14 | + plugins: [ | ||
| 15 | + vue(), | ||
| 16 | + AutoImport({ | ||
| 17 | + resolvers: [ElementPlusResolver()], | ||
| 18 | + imports: ["vue", "vue-router"], | ||
| 19 | + dts: "src/auto-imports.d.ts", | ||
| 20 | + eslintrc: { | ||
| 21 | + enabled: false, | ||
| 22 | + filepath: "./.eslintrc-auto-import.json", | ||
| 23 | + globalsPropValue: true, | ||
| 24 | + }, | ||
| 25 | + }), | ||
| 26 | + Components({ | ||
| 27 | + resolvers: [ | ||
| 28 | + ElementPlusResolver({ | ||
| 29 | + importStyle: "sass", | ||
| 30 | + }), | ||
| 31 | + ], | ||
| 32 | + dts: "src/components.d.ts", | ||
| 33 | + dirs: ["src/components", "src/layout"], | ||
| 34 | + }), | ||
| 35 | + createSvgIconsPlugin({ | ||
| 36 | + iconDirs: [resolve(process.cwd(), "src/assets/svg")], | ||
| 37 | + symbolId: "icon-[dir]-[name]", | ||
| 38 | + inject: "body-first", | ||
| 39 | + }), | ||
| 40 | + ], | ||
| 41 | + define: { | ||
| 42 | + "process.env": { | ||
| 43 | + mode, | ||
| 44 | + }, | ||
| 45 | + }, | ||
| 46 | + resolve: { | ||
| 47 | + alias: { | ||
| 48 | + "@": resolve(__dirname, "./src/"), | ||
| 49 | + }, | ||
| 50 | + }, | ||
| 51 | + css: { | ||
| 52 | + preprocessorOptions: { | ||
| 53 | + scss: { | ||
| 54 | + additionalData: `@use "@/assets/style/theme.scss" as *;@use "@/assets/style/color.scss" as *;`, | ||
| 55 | + }, | ||
| 56 | + }, | ||
| 57 | + }, | ||
| 58 | + server: { | ||
| 59 | + proxy: { | ||
| 60 | + // '^/alertCenter': 'http://192.168.110.32:9494/plugins/alert-center' | ||
| 61 | + '^/alertCenter': 'http://127.0.0.1:8080' | ||
| 62 | + }, | ||
| 63 | + }, | ||
| 64 | + }; | ||
| 65 | +}); | ||
| @@ -0,0 +1 @@ | |||
| 1 | +Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| @@ -0,0 +1,129 @@ | |||
| 1 | + | ||
| 2 | +<!-- | ||
| 3 | + | ||
| 4 | + Copyright (c) 2023 Huawei Technologies Co.,Ltd. | ||
| 5 | + | ||
| 6 | +--> | ||
| 7 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 8 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| 9 | + <modelVersion>4.0.0</modelVersion> | ||
| 10 | + <parent> | ||
| 11 | + <groupId>org.springframework.boot</groupId> | ||
| 12 | + <artifactId>spring-boot-starter-parent</artifactId> | ||
| 13 | + <version>2.7.11</version> | ||
| 14 | + <relativePath /> | ||
| 15 | + </parent> | ||
| 16 | + <groupId>com.nctigba</groupId> | ||
| 17 | + <artifactId>instance-exporter</artifactId> | ||
| 18 | + <version>5.0.0</version> | ||
| 19 | + <properties> | ||
| 20 | + <java.version>11</java.version> | ||
| 21 | + </properties> | ||
| 22 | + <dependencies> | ||
| 23 | + <dependency> | ||
| 24 | + <groupId>org.springframework.boot</groupId> | ||
| 25 | + <artifactId>spring-boot-starter-web</artifactId> | ||
| 26 | + </dependency> | ||
| 27 | + <dependency> | ||
| 28 | + <groupId>org.projectlombok</groupId> | ||
| 29 | + <artifactId>lombok</artifactId> | ||
| 30 | + <scope>provided</scope> | ||
| 31 | + <optional>true</optional> | ||
| 32 | + </dependency> | ||
| 33 | + <dependency> | ||
| 34 | + <groupId>cn.hutool</groupId> | ||
| 35 | + <artifactId>hutool-all</artifactId> | ||
| 36 | + <version>5.0.3</version> | ||
| 37 | + </dependency> | ||
| 38 | + <!-- https://mvnrepository.com/artifact/io.prometheus/simpleclient_httpserver --> | ||
| 39 | + <dependency> | ||
| 40 | + <groupId>io.prometheus</groupId> | ||
| 41 | + <artifactId>simpleclient_httpserver</artifactId> | ||
| 42 | + </dependency> | ||
| 43 | + <!-- https://mvnrepository.com/artifact/org.apache.sshd/sshd-scp --> | ||
| 44 | + <dependency> | ||
| 45 | + <groupId>org.apache.sshd</groupId> | ||
| 46 | + <artifactId>sshd-sftp</artifactId> | ||
| 47 | + <version>2.9.2</version> | ||
| 48 | + </dependency> | ||
| 49 | + <dependency> | ||
| 50 | + <groupId>org.opengauss</groupId> | ||
| 51 | + <artifactId>opengauss-jdbc</artifactId> | ||
| 52 | + <version>3.0.0</version> | ||
| 53 | + </dependency> | ||
| 54 | + </dependencies> | ||
| 55 | + <build> | ||
| 56 | + <plugins> | ||
| 57 | + <plugin> | ||
| 58 | + <groupId>org.springframework.boot</groupId> | ||
| 59 | + <artifactId>spring-boot-maven-plugin</artifactId> | ||
| 60 | + <configuration> | ||
| 61 | + <excludes> | ||
| 62 | + <exclude> | ||
| 63 | + <groupId>org.projectlombok</groupId> | ||
| 64 | + <artifactId>lombok</artifactId> | ||
| 65 | + </exclude> | ||
| 66 | + </excludes> | ||
| 67 | + </configuration> | ||
| 68 | + </plugin> | ||
| 69 | + <plugin> | ||
| 70 | + <artifactId>maven-dependency-plugin</artifactId> | ||
| 71 | + <executions> | ||
| 72 | + <execution> | ||
| 73 | + <phase>package</phase> | ||
| 74 | + <goals> | ||
| 75 | + <goal>copy</goal> | ||
| 76 | + </goals> | ||
| 77 | + <configuration> | ||
| 78 | + <artifactItems> | ||
| 79 | + <artifactItem> | ||
| 80 | + <groupId>${project.groupId}</groupId> | ||
| 81 | + <artifactId>${project.artifactId}</artifactId> | ||
| 82 | + <version>${project.version}</version> | ||
| 83 | + </artifactItem> | ||
| 84 | + </artifactItems> | ||
| 85 | + <outputDirectory>../src/main/resources</outputDirectory> | ||
| 86 | + <stripClassifier>true</stripClassifier> | ||
| 87 | + <stripVersion>true</stripVersion> | ||
| 88 | + </configuration> | ||
| 89 | + </execution> | ||
| 90 | + </executions> | ||
| 91 | + </plugin> | ||
| 92 | + <plugin> | ||
| 93 | + <groupId>com.mycila</groupId> | ||
| 94 | + <artifactId>license-maven-plugin</artifactId> | ||
| 95 | + <version>4.2</version> | ||
| 96 | + <executions> | ||
| 97 | + <execution> | ||
| 98 | + <phase>generate-sources</phase> | ||
| 99 | + <goals> | ||
| 100 | + <goal>format</goal> | ||
| 101 | + </goals> | ||
| 102 | + </execution> | ||
| 103 | + </executions> | ||
| 104 | + <configuration> | ||
| 105 | + <quiet>true</quiet> | ||
| 106 | + <header>../HEADER</header> | ||
| 107 | + <excludes> | ||
| 108 | + <exclude>**/*.properties</exclude> | ||
| 109 | + <exclude>*.sh</exclude> | ||
| 110 | + <exclude>*.yml</exclude> | ||
| 111 | + <exclude>.editorconfig</exclude> | ||
| 112 | + <exclude>.gitignore</exclude> | ||
| 113 | + <exclude>*.md</exclude> | ||
| 114 | + <exclude>*.xml</exclude> | ||
| 115 | + <exclude>*.html</exclude> | ||
| 116 | + <exclude>*.ts</exclude> | ||
| 117 | + <exclude>*.vue</exclude> | ||
| 118 | + <exclude>*.yaml</exclude> | ||
| 119 | + <exclude>*.scss</exclude> | ||
| 120 | + </excludes> | ||
| 121 | + <strictCheck>true</strictCheck> | ||
| 122 | + <mapping> | ||
| 123 | + <java>SLASHSTAR_STYLE</java> | ||
| 124 | + </mapping> | ||
| 125 | + </configuration> | ||
| 126 | + </plugin> | ||
| 127 | + </plugins> | ||
| 128 | + </build> | ||
| 129 | +</project> | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/Application.java+18-0
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent; | ||
| 5 | + | ||
| 6 | +import java.io.IOException; | ||
| 7 | + | ||
| 8 | +import org.springframework.boot.SpringApplication; | ||
| 9 | +import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| 10 | +import org.springframework.scheduling.annotation.EnableScheduling; | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +public class Application { | ||
| 15 | + public static void main(String[] args) throws IOException { | ||
| 16 | + SpringApplication.run(Application.class, args); | ||
| 17 | + } | ||
| 18 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/controller/Command.java+98-0
| @@ -0,0 +1,98 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.controller; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.ArrayList; | ||
| 9 | +import java.util.Arrays; | ||
| 10 | +import java.util.Collections; | ||
| 11 | +import java.util.Comparator; | ||
| 12 | +import java.util.HashMap; | ||
| 13 | +import java.util.HashSet; | ||
| 14 | +import java.util.List; | ||
| 15 | +import java.util.Map; | ||
| 16 | +import java.util.Set; | ||
| 17 | + | ||
| 18 | +import org.opengauss.plugin.agent.server.HostMetric; | ||
| 19 | +import org.opengauss.plugin.agent.util.CmdUtil; | ||
| 20 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 21 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 22 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 23 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 24 | +import org.springframework.web.bind.annotation.RestController; | ||
| 25 | + | ||
| 26 | +import cn.hutool.core.util.StrUtil; | ||
| 27 | +import lombok.AllArgsConstructor; | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | +public class Command { | ||
| 33 | + private static final String TOP = "top -b -n 1"; | ||
| 34 | + private static final String TOP_DB_PID = "netstat -nap|grep :'|grep LISTEN"; | ||
| 35 | + private static final String TOP_DB_THREAD = "top -H -bn1 -p "; | ||
| 36 | + private final HostMetric hostMetric; | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + public Object top( String sort) throws FileNotFoundException, IOException { | ||
| 40 | + List<String> header = new ArrayList<>(); | ||
| 41 | + List<Map<String, String>> top = new ArrayList<>(); | ||
| 42 | + CmdUtil.readFromCmd(TOP, (i, line) -> { | ||
| 43 | + if (i < 6) | ||
| 44 | + return; | ||
| 45 | + String[] part = StringUtil.splitByBlank(line); | ||
| 46 | + if (i == 6) { | ||
| 47 | + Collections.addAll(header, part); | ||
| 48 | + return; | ||
| 49 | + } | ||
| 50 | + Map<String, String> obj = new HashMap<String, String>(); | ||
| 51 | + for (int j = 0; j < header.size(); j++) { | ||
| 52 | + obj.put(header.get(j), part[j]); | ||
| 53 | + } | ||
| 54 | + top.add(obj); | ||
| 55 | + }); | ||
| 56 | + Set<String> pids = new HashSet<>(); | ||
| 57 | + CmdUtil.readFromCmd(TOP_DB_PID.replaceAll("'", hostMetric.getDbport().toString()), line -> { | ||
| 58 | + var part = StringUtil.splitByBlank(line); | ||
| 59 | + var pid = part[part.length - 1]; | ||
| 60 | + pid = pid.split("/")[0]; | ||
| 61 | + pids.add(pid); | ||
| 62 | + }); | ||
| 63 | + List<Map<String, String>> db_top = new ArrayList<>(); | ||
| 64 | + if (pids.size() != 0) { | ||
| 65 | + var pid = pids.iterator().next(); | ||
| 66 | + CmdUtil.readFromCmd(TOP_DB_THREAD + pid, (i, line) -> { | ||
| 67 | + if (i < 6) | ||
| 68 | + return; | ||
| 69 | + String[] part = StringUtil.splitByBlank(line); | ||
| 70 | + if (i == 6) { | ||
| 71 | + header.clear(); | ||
| 72 | + Collections.addAll(header, part); | ||
| 73 | + return; | ||
| 74 | + } | ||
| 75 | + Map<String, String> obj = new HashMap<String, String>(); | ||
| 76 | + for (int j = 0; j < header.size(); j++) { | ||
| 77 | + obj.put(header.get(j), part[j]); | ||
| 78 | + } | ||
| 79 | + db_top.add(obj); | ||
| 80 | + }); | ||
| 81 | + } | ||
| 82 | + if (StrUtil.isNotBlank(sort)) { | ||
| 83 | + var comparator = new Comparator<Map<String, String>>() { | ||
| 84 | + | ||
| 85 | + public int compare(Map<String, String> o1, Map<String, String> o2) { | ||
| 86 | + try { | ||
| 87 | + return -Double.compare(Double.parseDouble(o1.get(sort)), Double.parseDouble(o2.get(sort))); | ||
| 88 | + } catch (NumberFormatException e) { | ||
| 89 | + return -o1.get(sort).compareTo(o2.get(sort)); | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + }; | ||
| 93 | + Collections.sort(top, comparator); | ||
| 94 | + Collections.sort(db_top, comparator); | ||
| 95 | + } | ||
| 96 | + return Arrays.asList(top, db_top); | ||
| 97 | + } | ||
| 98 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/controller/Config.java+50-0
| @@ -0,0 +1,50 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.controller; | ||
| 5 | + | ||
| 6 | +import java.io.File; | ||
| 7 | +import java.io.FileInputStream; | ||
| 8 | +import java.io.FileWriter; | ||
| 9 | +import java.io.IOException; | ||
| 10 | +import java.io.InputStream; | ||
| 11 | +import java.util.HashMap; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +import org.opengauss.plugin.agent.server.HostMetric; | ||
| 15 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 16 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 17 | +import org.springframework.web.bind.annotation.RestController; | ||
| 18 | +import org.yaml.snakeyaml.Yaml; | ||
| 19 | + | ||
| 20 | +import lombok.RequiredArgsConstructor; | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class Config { | ||
| 26 | + private final HostMetric hostMetric; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + public void set(String hostId, String nodeId, Integer dbport, String username, String password) throws IOException { | ||
| 30 | + File application = new File(".", "application.yml"); | ||
| 31 | + if (!application.exists()) | ||
| 32 | + application.createNewFile(); | ||
| 33 | + try (InputStream is = new FileInputStream(application);) { | ||
| 34 | + Yaml yaml = new Yaml(); | ||
| 35 | + Map<String, Object> map = yaml.load(is); | ||
| 36 | + if (map == null) | ||
| 37 | + map = new HashMap<>(); | ||
| 38 | + map.put("conf", Map.of("hostId", hostId, "node", | ||
| 39 | + Map.of("nodeId", nodeId, "dbport", dbport, "username", username, "password", password))); | ||
| 40 | + // refresh curr config | ||
| 41 | + hostMetric.setHostId(hostId).setNodeId(nodeId).setDbport(dbport).setDbUsername(username) | ||
| 42 | + .setDbPassword(password); | ||
| 43 | + try (var writer = new FileWriter(application)) { | ||
| 44 | + writer.write(yaml.dumpAsMap(map)); | ||
| 45 | + } | ||
| 46 | + } catch (IOException e) { | ||
| 47 | + throw e; | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/Ametric.java+23-0
| @@ -0,0 +1,23 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * used by { com.nctigba.server.HttpServer} | ||
| 12 | + */ | ||
| 13 | +public interface Ametric { | ||
| 14 | + /** | ||
| 15 | + * generate metric | ||
| 16 | + * | ||
| 17 | + * dbPort TODO | ||
| 18 | + * | ||
| 19 | + * FileNotFoundException | ||
| 20 | + * IOException | ||
| 21 | + */ | ||
| 22 | + Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException; | ||
| 23 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/DBmetric.java+7-0
| @@ -0,0 +1,7 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric; | ||
| 5 | + | ||
| 6 | +public interface DBmetric extends Ametric { | ||
| 7 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/Metric.java+58-0
| @@ -0,0 +1,58 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric; | ||
| 5 | + | ||
| 6 | +import java.util.ArrayList; | ||
| 7 | +import java.util.Collections; | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +import cn.hutool.core.util.StrUtil; | ||
| 11 | +import io.prometheus.client.Collector; | ||
| 12 | +import lombok.AllArgsConstructor; | ||
| 13 | +import lombok.Data; | ||
| 14 | +import lombok.NoArgsConstructor; | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +public class Metric { | ||
| 19 | + Collector.Type type; | ||
| 20 | + String help; | ||
| 21 | + List<String> labelNames = new ArrayList<>(); | ||
| 22 | + List<Metric.values> values = new ArrayList<>(); | ||
| 23 | + | ||
| 24 | + public Metric addValue(List<String> labelValues, String value) { | ||
| 25 | + return addValue(labelValues, StrUtil.isBlank(value) ? 0 : Double.parseDouble(value)); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public Metric addValue(List<String> labelValues, double value) { | ||
| 29 | + values.add(new values(labelValues, value)); | ||
| 30 | + return this; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public Metric(Collector.Type type, List<String> labelNames) { | ||
| 34 | + this.type = type; | ||
| 35 | + this.labelNames = labelNames; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public Metric(Collector.Type type, String help, List<String> labelNames) { | ||
| 39 | + this.type = type; | ||
| 40 | + this.help = help; | ||
| 41 | + this.labelNames = labelNames; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public List<String> getLabelNames() { | ||
| 45 | + return labelNames == null ? Collections.emptyList() : labelNames; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + public static class values { | ||
| 51 | + private List<String> labelValues; | ||
| 52 | + private Double value; | ||
| 53 | + | ||
| 54 | + public List<String> getLabelValues() { | ||
| 55 | + return labelValues == null ? Collections.emptyList() : labelValues; | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/OSmetric.java+7-0
| @@ -0,0 +1,7 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric; | ||
| 5 | + | ||
| 6 | +public interface OSmetric extends Ametric { | ||
| 7 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/opengauss/OpengaussExporter.java+217-0
| @@ -0,0 +1,217 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.opengauss; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.sql.Timestamp; | ||
| 9 | +import java.util.ArrayList; | ||
| 10 | +import java.util.Collections; | ||
| 11 | +import java.util.HashMap; | ||
| 12 | +import java.util.List; | ||
| 13 | +import java.util.Map; | ||
| 14 | +import java.util.Map.Entry; | ||
| 15 | +import java.util.concurrent.TimeUnit; | ||
| 16 | + | ||
| 17 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 18 | +import org.opengauss.plugin.agent.util.DbUtil; | ||
| 19 | +import org.springframework.beans.factory.InitializingBean; | ||
| 20 | +import org.springframework.core.io.ClassPathResource; | ||
| 21 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 22 | +import org.springframework.stereotype.Service; | ||
| 23 | +import org.yaml.snakeyaml.Yaml; | ||
| 24 | + | ||
| 25 | +import org.opengauss.plugin.agent.metric.DBmetric; | ||
| 26 | +import org.opengauss.plugin.agent.metric.opengauss.OpengaussExporter.queryInstance.metricInfo.usage; | ||
| 27 | +import org.opengauss.plugin.agent.metric.opengauss.OpengaussExporter.queryInstance.query; | ||
| 28 | +import org.opengauss.plugin.agent.metric.opengauss.OpengaussExporter.queryInstance.query.state; | ||
| 29 | + | ||
| 30 | +import cn.hutool.core.bean.BeanUtil; | ||
| 31 | +import cn.hutool.core.thread.ThreadUtil; | ||
| 32 | +import cn.hutool.core.util.NumberUtil; | ||
| 33 | +import io.prometheus.client.Collector.Type; | ||
| 34 | +import lombok.AllArgsConstructor; | ||
| 35 | +import lombok.Data; | ||
| 36 | +import lombok.Getter; | ||
| 37 | +import lombok.extern.log4j.Log4j2; | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * table pg_stat_activity | ||
| 41 | + */ | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + | ||
| 45 | +public class OpengaussExporter implements DBmetric, InitializingBean { | ||
| 46 | + private static final Map<String, queryInstance> CONFIG = new HashMap<>(); | ||
| 47 | + private static Map<String, Metric> metricData = new HashMap<>(); | ||
| 48 | + | ||
| 49 | + private final DbUtil dbUtil; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * load open Gauss exporter config file | ||
| 53 | + */ | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + public void afterPropertiesSet() throws Exception { | ||
| 57 | + var in = new ClassPathResource("og_exporter.yml").getInputStream(); | ||
| 58 | + Map<String, Object> map = new Yaml().loadAs(in, Map.class); | ||
| 59 | + map.entrySet().forEach((entry) -> { | ||
| 60 | + if (entry.getValue() instanceof Map) { | ||
| 61 | + var b = BeanUtil.mapToBean((Map<?, ?>) entry.getValue(), queryInstance.class, false); | ||
| 62 | + CONFIG.put(entry.getKey(), b); | ||
| 63 | + | ||
| 64 | + } | ||
| 65 | + }); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + | ||
| 69 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 70 | + return metricData; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + public void catchMetric() { | ||
| 75 | + if (CONFIG.size() == 0) { | ||
| 76 | + return; | ||
| 77 | + } | ||
| 78 | + Map<String, Metric> all = new HashMap<>(); | ||
| 79 | + var countDown = ThreadUtil.newCountDownLatch(CONFIG.size()); | ||
| 80 | + CONFIG.entrySet().forEach(conf -> { | ||
| 81 | + ThreadUtil.execute(() -> { | ||
| 82 | + try { | ||
| 83 | + all.putAll(metric(conf)); | ||
| 84 | + } finally { | ||
| 85 | + countDown.countDown(); | ||
| 86 | + } | ||
| 87 | + }); | ||
| 88 | + }); | ||
| 89 | + try { | ||
| 90 | + countDown.await(10, TimeUnit.SECONDS); | ||
| 91 | + } catch (InterruptedException e) { | ||
| 92 | + throw new RuntimeException(e); | ||
| 93 | + } | ||
| 94 | + metricData = all; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + private Map<String, Metric> metric(Entry<String, queryInstance> conf) { | ||
| 98 | + String sql = null; | ||
| 99 | + for (query q : conf.getValue().getQuery()) { | ||
| 100 | + if (q.getStatus() == state.enable) { | ||
| 101 | + sql = q.getSql(); | ||
| 102 | + break; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + if (sql == null) { | ||
| 106 | + return Collections.emptyMap(); | ||
| 107 | + } | ||
| 108 | + // generate label names | ||
| 109 | + List<String> labelNames = conf.getValue().generateLabelNames(); | ||
| 110 | + // generate metric family | ||
| 111 | + Map<String, Metric> result = conf.getValue().generateMetricFamily(conf.getKey(), labelNames); | ||
| 112 | + // add data | ||
| 113 | + List<Map<String, Object>> r = dbUtil.query(sql); | ||
| 114 | + for (Map<String, Object> row : r) { | ||
| 115 | + // label values | ||
| 116 | + List<String> labelValues = new ArrayList<>(); | ||
| 117 | + for (String name : labelNames) { | ||
| 118 | + try { | ||
| 119 | + labelValues.add(row.get(name).toString()); | ||
| 120 | + } catch (Exception e) { | ||
| 121 | + log.debug("【labelNames】:【name】{}", name); | ||
| 122 | + log.error("labelName not found from sql:{}", name); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + // metric values | ||
| 126 | + conf.getValue().getMetrics().forEach(metric -> { | ||
| 127 | + if (metric.getUsage().getType() != null) { | ||
| 128 | + double val = 0; | ||
| 129 | + Object value = row.get(metric.getName()); | ||
| 130 | + if (value == null) { | ||
| 131 | + log.error("metric error:{}", metric.getName()); | ||
| 132 | + val = 0; | ||
| 133 | + } else if (NumberUtil.isNumber(value.toString())) { | ||
| 134 | + val = Double.parseDouble(value.toString()); | ||
| 135 | + } else { | ||
| 136 | + if (value instanceof Timestamp) | ||
| 137 | + val = ((Timestamp) value).getTime(); | ||
| 138 | + } | ||
| 139 | + result.get(conf.getKey() + "_" + metric.getName()).addValue(labelValues, val); | ||
| 140 | + } | ||
| 141 | + }); | ||
| 142 | + } | ||
| 143 | + return result; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + | ||
| 147 | + public static class queryInstance { | ||
| 148 | + private String name; | ||
| 149 | + private String desc; | ||
| 150 | + private List<query> query; | ||
| 151 | + private List<metricInfo> metrics; | ||
| 152 | + private String status; | ||
| 153 | + | ||
| 154 | + public List<String> generateLabelNames() { | ||
| 155 | + List<String> labelNames = new ArrayList<>(); | ||
| 156 | + getMetrics().forEach(metric -> { | ||
| 157 | + if (metric.getUsage() == usage.LABEL) { | ||
| 158 | + labelNames.add(metric.getName()); | ||
| 159 | + return; | ||
| 160 | + } | ||
| 161 | + }); | ||
| 162 | + return labelNames; | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + public Map<String, Metric> generateMetricFamily(String base, List<String> labelNames) { | ||
| 166 | + Map<String, Metric> result = new HashMap<>(); | ||
| 167 | + getMetrics().forEach(metric -> { | ||
| 168 | + if (metric.getUsage().getType() != null) { | ||
| 169 | + result.put(base + "_" + metric.getName(), new Metric(metric.getUsage().type, labelNames)); | ||
| 170 | + } | ||
| 171 | + }); | ||
| 172 | + return result; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + | ||
| 176 | + public static class query { | ||
| 177 | + private String name; | ||
| 178 | + private String desc; | ||
| 179 | + private String sql; | ||
| 180 | + private String version; | ||
| 181 | + private String tags; | ||
| 182 | + private Integer timeout; | ||
| 183 | + private Integer ttl; | ||
| 184 | + private state status; | ||
| 185 | + private String dbRole; | ||
| 186 | + | ||
| 187 | + public enum state { | ||
| 188 | + enable, | ||
| 189 | + disable | ||
| 190 | + } | ||
| 191 | + } | ||
| 192 | + | ||
| 193 | + | ||
| 194 | + public static class metricInfo { | ||
| 195 | + private String name; | ||
| 196 | + private String description; | ||
| 197 | + private usage usage; | ||
| 198 | + | ||
| 199 | + | ||
| 200 | + public enum usage { | ||
| 201 | + COUNTER(Type.COUNTER), | ||
| 202 | + GAUGE(Type.GAUGE), | ||
| 203 | + LABEL, | ||
| 204 | + DISCARD; | ||
| 205 | + | ||
| 206 | + private Type type; | ||
| 207 | + | ||
| 208 | + private usage() { | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + private usage(Type type) { | ||
| 212 | + this.type = type; | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/opengauss/Top.java+51-0
| @@ -0,0 +1,51 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.opengauss; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Collections; | ||
| 9 | +import java.util.HashMap; | ||
| 10 | +import java.util.HashSet; | ||
| 11 | +import java.util.Map; | ||
| 12 | +import java.util.Set; | ||
| 13 | + | ||
| 14 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 15 | +import org.opengauss.plugin.agent.util.CmdUtil; | ||
| 16 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 17 | +import org.springframework.stereotype.Service; | ||
| 18 | + | ||
| 19 | +import org.opengauss.plugin.agent.metric.DBmetric; | ||
| 20 | + | ||
| 21 | +import io.prometheus.client.Collector.Type; | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +public class Top implements DBmetric { | ||
| 25 | + private static final String COMMAND_PORT_TO_PID = "netstat -nap|grep :'|grep LISTEN"; | ||
| 26 | + private static final String COMMAND_TOP_ = "top -b -n 1|grep "; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 30 | + if (dbPort == null) | ||
| 31 | + return Collections.emptyMap(); | ||
| 32 | + Set<String> pids = new HashSet<>(); | ||
| 33 | + CmdUtil.readFromCmd(COMMAND_PORT_TO_PID.replaceAll("'", dbPort.toString()), line -> { | ||
| 34 | + var part = StringUtil.splitByBlank(line); | ||
| 35 | + var pid = part[part.length - 1]; | ||
| 36 | + pid = pid.split("/")[0]; | ||
| 37 | + pids.add(pid); | ||
| 38 | + }); | ||
| 39 | + Map<String, Metric> map = new HashMap<String, Metric>(); | ||
| 40 | + if (pids.size() == 0) | ||
| 41 | + return map; | ||
| 42 | + CmdUtil.readFromCmd(COMMAND_TOP_ + pids.iterator().next(), line -> { | ||
| 43 | + // PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND | ||
| 44 | + // 163616 omm 20 0 3133820 525420 171716 S 0.0 3.3 507:05.43 gaussdb | ||
| 45 | + var part = StringUtil.splitByBlank(line); | ||
| 46 | + map.put("top_db_cpu", new Metric(Type.GAUGE, null).addValue(null, part[8])); | ||
| 47 | + map.put("top_db_mem", new Metric(Type.GAUGE, null).addValue(null, part[9])); | ||
| 48 | + }); | ||
| 49 | + return map; | ||
| 50 | + } | ||
| 51 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/VmStat.java+56-0
| @@ -0,0 +1,56 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 12 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 13 | +import org.opengauss.plugin.agent.util.CmdUtil; | ||
| 14 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 15 | +import org.springframework.stereotype.Service; | ||
| 16 | + | ||
| 17 | +import io.prometheus.client.Collector.Type; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * <a href= | ||
| 21 | + * "https://zhuanlan.zhihu.com/p/364383421">zhuanlan.zhihu.com/p/364383421</a> | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | +public class VmStat implements OSmetric { | ||
| 25 | + private static final String[] KEYS = { | ||
| 26 | + "r", | ||
| 27 | + "b", | ||
| 28 | + "swpd", | ||
| 29 | + "free", | ||
| 30 | + "buff", | ||
| 31 | + "cache", | ||
| 32 | + "si", | ||
| 33 | + "so", | ||
| 34 | + "bi", | ||
| 35 | + "bo", | ||
| 36 | + "in", | ||
| 37 | + "cs", | ||
| 38 | + "us", | ||
| 39 | + "sy", | ||
| 40 | + "wa", | ||
| 41 | + "st" }; | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 45 | + Map<String, Metric> map = new HashMap<>(); | ||
| 46 | + CmdUtil.readFromCmd(CmdUtil.cmd("vmstat"), (index, line) -> { | ||
| 47 | + if (index < 2) | ||
| 48 | + return; | ||
| 49 | + var part = StringUtil.splitByBlank(line); | ||
| 50 | + for (int i = 0; i < part.length && i < KEYS.length; i++) { | ||
| 51 | + map.put(KEYS[i], new Metric(Type.GAUGE, null).addValue(null, part[i])); | ||
| 52 | + } | ||
| 53 | + }); | ||
| 54 | + return map; | ||
| 55 | + } | ||
| 56 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/cpu/LoadAvg.java+34-0
| @@ -0,0 +1,34 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.cpu; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 11 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 12 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | + | ||
| 15 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 16 | + | ||
| 17 | +import io.prometheus.client.Collector.Type; | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +public class LoadAvg implements OSmetric { | ||
| 21 | + | ||
| 22 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 23 | + var load1 = new Metric(Type.GAUGE, "1m load average.", null); | ||
| 24 | + var load5 = new Metric(Type.GAUGE, "5m load average.", null); | ||
| 25 | + var load15 = new Metric(Type.GAUGE, "15m load average.", null); | ||
| 26 | + FileUtil.readFileLine("/proc/loadavg", s -> { | ||
| 27 | + var part = StringUtil.splitByBlank(s); | ||
| 28 | + load1.addValue(null, part[0]); | ||
| 29 | + load5.addValue(null, part[1]); | ||
| 30 | + load15.addValue(null, part[2]); | ||
| 31 | + }); | ||
| 32 | + return Map.of("1", load1, "5", load5, "15", load15); | ||
| 33 | + } | ||
| 34 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/cpu/ProcStat.java+57-0
| @@ -0,0 +1,57 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.cpu; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Arrays; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 12 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 13 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 14 | +import org.springframework.stereotype.Service; | ||
| 15 | + | ||
| 16 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 17 | + | ||
| 18 | +import io.prometheus.client.Collector.Type; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Linux file <code>/proc/stat</code> | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | +public class ProcStat implements OSmetric { | ||
| 25 | + | ||
| 26 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 27 | + var seconds_total = new Metric(Type.COUNTER, Arrays.asList("cpu", "mode")); | ||
| 28 | + FileUtil.readFileLine("/proc/stat", s -> { | ||
| 29 | + var part = StringUtil.splitByBlank(s); | ||
| 30 | + if (part[0].equalsIgnoreCase("cpu")) | ||
| 31 | + return; | ||
| 32 | + if (part[0].startsWith("cpu")) { | ||
| 33 | + String cpuIndex = part[0].replaceAll("cpu", ""); | ||
| 34 | + for (cpuStat stat : cpuStat.values()) { | ||
| 35 | + int index = stat.ordinal() + 1; | ||
| 36 | + if (index < part.length) { | ||
| 37 | + var value = Double.parseDouble(part[index]); | ||
| 38 | + value /= 100; | ||
| 39 | + seconds_total.addValue(Arrays.asList(cpuIndex, stat.name()), value); | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + }); | ||
| 44 | + return Map.of("_seconds_total", seconds_total); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public enum cpuStat { | ||
| 48 | + user, | ||
| 49 | + nice, | ||
| 50 | + system, | ||
| 51 | + idle, | ||
| 52 | + iowait, | ||
| 53 | + irq, | ||
| 54 | + softirq, | ||
| 55 | + steal, | ||
| 56 | + } | ||
| 57 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/disk/DiskStats.java+82-0
| @@ -0,0 +1,82 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.disk; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Arrays; | ||
| 9 | +import java.util.HashMap; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 13 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 14 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 15 | +import org.springframework.stereotype.Service; | ||
| 16 | + | ||
| 17 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 18 | + | ||
| 19 | +import cn.hutool.core.util.ReUtil; | ||
| 20 | +import io.prometheus.client.Collector.Type; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * Linux 2.6 file { /proc/diskstats}<br/> | ||
| 24 | + * Linux 2.4 file { /proc/partitions} TODO | ||
| 25 | + * | ||
| 26 | + * <a href= | ||
| 27 | + * "https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats"> | ||
| 28 | + * kernel.org/doc/procfs-diskstats</a> | ||
| 29 | + * <a href= | ||
| 30 | + * "https://blog.csdn.net/qu1993/article/details/105702991">blog.csdn.net/qu1993/article/details/105702991</a> | ||
| 31 | + */ | ||
| 32 | + | ||
| 33 | +public class DiskStats implements OSmetric { | ||
| 34 | + private static final String[] KEYS = { | ||
| 35 | + "major number", | ||
| 36 | + "minor mumber", | ||
| 37 | + "device name", | ||
| 38 | + "rd_ios", // reads completed | ||
| 39 | + "rd_merges", // reads merged | ||
| 40 | + // https://unix.stackexchange.com/questions/111968/how-to-get-total-disk-read-write-in-bytes-per-hdd-device-from-proc | ||
| 41 | + "rd_sectors", // sectors read | ||
| 42 | + "rd_ticks", // time spent reading(ms) | ||
| 43 | + "wr_ios", // writes completed | ||
| 44 | + "wr_merges", // writes merged | ||
| 45 | + "wr_sectors", // sectors written | ||
| 46 | + "wr_ticks", // time spent writing(ms) | ||
| 47 | + "io_pgr", // io_now | ||
| 48 | + // io_ticks, https://zhuanlan.zhihu.com/p/604547780 | ||
| 49 | + "tot_ticks", // io_time_ms | ||
| 50 | + "rq_ticks", // weighted time spent doing IOs(ms) | ||
| 51 | + // Kernel 4.18+ | ||
| 52 | + "discards completed successfully", | ||
| 53 | + "discards merged", | ||
| 54 | + "discarded_sectors", | ||
| 55 | + "time spent discarding", | ||
| 56 | + // Kernel 5.5+ | ||
| 57 | + "flush requests completed successfully", | ||
| 58 | + "time spent flushing", }; | ||
| 59 | + | ||
| 60 | + private static final String IGNORE = "^(ram|loop|fd|(h|s|v|xv)d[a-z]|nvme\\d+n\\d+p)\\d+$"; | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 64 | + Map<String, Metric> map = new HashMap<>(); | ||
| 65 | + FileUtil.readFileLine("/proc/diskstats", line -> { | ||
| 66 | + var part = StringUtil.splitByBlank(line); | ||
| 67 | + if (ReUtil.contains(IGNORE, part[2])) | ||
| 68 | + return; | ||
| 69 | + if (map.isEmpty()) { | ||
| 70 | + var labelNames = Arrays.asList("major", "minor", "device"); | ||
| 71 | + for (int i = 3; i < KEYS.length; i++) { | ||
| 72 | + map.put(KEYS[i], new Metric(Type.COUNTER, labelNames)); | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + var labelValues = Arrays.asList(part[0], part[1], part[2]); | ||
| 76 | + for (int i = 3; i < KEYS.length; i++) { | ||
| 77 | + map.get(KEYS[i]).addValue(labelValues, i < part.length ? part[i] : null); | ||
| 78 | + } | ||
| 79 | + }); | ||
| 80 | + return map; | ||
| 81 | + } | ||
| 82 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/memory/Free.java+43-0
| @@ -0,0 +1,43 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.memory; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 12 | +import org.opengauss.plugin.agent.util.CmdUtil; | ||
| 13 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 14 | +import org.springframework.stereotype.Service; | ||
| 15 | + | ||
| 16 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 17 | + | ||
| 18 | +import io.prometheus.client.Collector.Type; | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +public class Free implements OSmetric { | ||
| 22 | + private static final String[] KEYS = { "type", "total", "used", "free", "shared", "cache", "available" }; | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 26 | + Map<String, Metric> map = new HashMap<>(); | ||
| 27 | + CmdUtil.readFromCmd(CmdUtil.cmd("free"), (index, line) -> { | ||
| 28 | + if (index == 0) { | ||
| 29 | + // total used free shared buff/cache available | ||
| 30 | + return; | ||
| 31 | + } | ||
| 32 | + var part = StringUtil.splitByBlank(line); | ||
| 33 | + // Mem: 15896504 9520972 496816 1156408 5878716 4745916 | ||
| 34 | + // Swap: 8278012 209664 8068348 | ||
| 35 | + for (int i = 1; i < part.length; i++) { | ||
| 36 | + map.put(StringUtil.removeLast(part[0]) + "_" + KEYS[i] + "_bytes", | ||
| 37 | + new Metric(Type.GAUGE, null).addValue(null, Double.parseDouble(part[i]) * 1024)); | ||
| 38 | + } | ||
| 39 | + return; | ||
| 40 | + }); | ||
| 41 | + return map; | ||
| 42 | + } | ||
| 43 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/memory/ProcMeminfo.java+41-0
| @@ -0,0 +1,41 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.memory; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 12 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 13 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 14 | +import org.springframework.stereotype.Service; | ||
| 15 | + | ||
| 16 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 17 | + | ||
| 18 | +import io.prometheus.client.Collector.Type; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Linux file <code>/proc/meminfo</code> | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | +public class ProcMeminfo implements OSmetric { | ||
| 25 | + | ||
| 26 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 27 | + var map = new HashMap<String, Metric>(); | ||
| 28 | + FileUtil.readFileLine("/proc/meminfo", line -> { | ||
| 29 | + var part = StringUtil.splitByBlank(line); | ||
| 30 | + double value = Double.parseDouble(part[1]); | ||
| 31 | + var key = StringUtil.replaceParenthesis(line); | ||
| 32 | + if (part.length == 3) { | ||
| 33 | + value *= 1024; | ||
| 34 | + key += "_bytes"; | ||
| 35 | + } | ||
| 36 | + map.put("_" + key, new Metric(Type.GAUGE, null).addValue(null, value)); | ||
| 37 | + }); | ||
| 38 | + return map; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/network/NetDev.java+111-0
| @@ -0,0 +1,111 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.network; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Arrays; | ||
| 9 | +import java.util.HashMap; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 13 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 14 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 15 | +import org.springframework.stereotype.Service; | ||
| 16 | + | ||
| 17 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 18 | + | ||
| 19 | +import cn.hutool.core.util.ReUtil; | ||
| 20 | +import cn.hutool.core.util.StrUtil; | ||
| 21 | +import io.prometheus.client.Collector.Type; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * Linux file /proc/net/dev | ||
| 25 | + * <p> | ||
| 26 | + * <strong>bytes</strong> The total number of bytes of data transmitted or | ||
| 27 | + * received by the interface. | ||
| 28 | + * </p> | ||
| 29 | + * <p> | ||
| 30 | + * <strong>packets</strong> The total number of packets of data transmitted or | ||
| 31 | + * received by the interface. | ||
| 32 | + * </p> | ||
| 33 | + * <p> | ||
| 34 | + * <strong>errs</strong> The total number of transmit or receive errors detected | ||
| 35 | + * by the device driver. | ||
| 36 | + * </p> | ||
| 37 | + * <p> | ||
| 38 | + * <strong>drop</strong> The total number of packets dropped by the device | ||
| 39 | + * driver. | ||
| 40 | + * </p> | ||
| 41 | + * <p> | ||
| 42 | + * <strong>fifo</strong> The number of FIFO buffer errors. | ||
| 43 | + * </p> | ||
| 44 | + * <p> | ||
| 45 | + * <strong>frame</strong> The number of packet framing errors. | ||
| 46 | + * </p> | ||
| 47 | + * <p> | ||
| 48 | + * <strong>colls</strong> The number of collisions detected on the interface. | ||
| 49 | + * </p> | ||
| 50 | + * <p> | ||
| 51 | + * <strong>compressed</strong> The number of compressed packets transmitted or | ||
| 52 | + * received by the device driver. (This appears to be unused in the 2.2.15 | ||
| 53 | + * kernel.) | ||
| 54 | + * </p> | ||
| 55 | + * <p> | ||
| 56 | + * <strong>carrier</strong> The number of carrier losses detected by the device | ||
| 57 | + * driver. | ||
| 58 | + * </p> | ||
| 59 | + * <p> | ||
| 60 | + * <strong>multicast</strong> The number of multicast frames transmitted or | ||
| 61 | + * received by the device driver. | ||
| 62 | + * </p> | ||
| 63 | + * | ||
| 64 | + * <a href= | ||
| 65 | + * "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/core/net-procfs.c">git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/core/net-procfs.c</a> | ||
| 66 | + */ | ||
| 67 | + | ||
| 68 | +public class NetDev implements OSmetric { | ||
| 69 | + private static final String[] KEYS = { | ||
| 70 | + "device_name", | ||
| 71 | + "receive_bytes", | ||
| 72 | + "receive_packets", | ||
| 73 | + "receive_errors", | ||
| 74 | + "receive_dropped", | ||
| 75 | + "receive_fifo", | ||
| 76 | + "receive_frame", | ||
| 77 | + "receive_compressed", | ||
| 78 | + "receive_multicast", | ||
| 79 | + "transmit_bytes", | ||
| 80 | + "transmit_packets", | ||
| 81 | + "transmit_errors", | ||
| 82 | + "transmit_dropped", | ||
| 83 | + "transmit_fifo", | ||
| 84 | + "transmit_colls", | ||
| 85 | + "transmit_carrier", | ||
| 86 | + "transmit_compressed", }; | ||
| 87 | + private static final String IGNORE = ""; | ||
| 88 | + | ||
| 89 | + | ||
| 90 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 91 | + Map<String, Metric> map = new HashMap<>(); | ||
| 92 | + FileUtil.readFileLine("/proc/net/dev", (index, line) -> { | ||
| 93 | + if (line.contains("|")) | ||
| 94 | + return; | ||
| 95 | + var part = StringUtil.splitByBlank(line); | ||
| 96 | + if (StrUtil.isNotBlank(IGNORE) && ReUtil.contains(IGNORE, part[0])) | ||
| 97 | + return; | ||
| 98 | + if (map.isEmpty()) { | ||
| 99 | + var labelNames = Arrays.asList("device"); | ||
| 100 | + for (int i = 1; i < KEYS.length; i++) { | ||
| 101 | + map.put(KEYS[i], new Metric(Type.COUNTER, labelNames)); | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + var labelValues = Arrays.asList(StringUtil.removeLast(part[0])); | ||
| 105 | + for (int i = 1; i < KEYS.length; i++) { | ||
| 106 | + map.get(KEYS[i]).addValue(labelValues, i < part.length ? part[i] : null); | ||
| 107 | + } | ||
| 108 | + }); | ||
| 109 | + return map; | ||
| 110 | + } | ||
| 111 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/network/Netstat.java+93-0
| @@ -0,0 +1,93 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.network; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.ArrayList; | ||
| 9 | +import java.util.Collections; | ||
| 10 | +import java.util.HashMap; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | +import java.util.regex.Pattern; | ||
| 14 | + | ||
| 15 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 16 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 17 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 18 | +import org.springframework.stereotype.Service; | ||
| 19 | + | ||
| 20 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 21 | + | ||
| 22 | +import cn.hutool.core.util.NumberUtil; | ||
| 23 | +import cn.hutool.core.util.ReUtil; | ||
| 24 | +import io.prometheus.client.Collector; | ||
| 25 | +import lombok.extern.log4j.Log4j2; | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +public class Netstat implements OSmetric { | ||
| 30 | + private static final Pattern PATTERN = Pattern.compile( | ||
| 31 | + "^(.*_(InErrors|InErrs)|Ip_Forwarding|Ip(6|Ext)_(InOctets|OutOctets)|Icmp6?_(InMsgs|OutMsgs)|TcpExt_(Listen.*|Syncookies.*|TCPSynRetrans|TCPTimeouts)|Tcp_(ActiveOpens|InSegs|OutSegs|OutRsts|PassiveOpens|RetransSegs|CurrEstab)|Udp6?_(InDatagrams|OutDatagrams|NoPorts|RcvbufErrors|SndbufErrors))$"); | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 35 | + var netStats = getNetStats("/proc/net/netstat"); | ||
| 36 | + var snmp = getNetStats("/proc/net/snmp"); | ||
| 37 | + var snmp6Stats = getSNMP6Stats("/proc/net/snmp6"); | ||
| 38 | + netStats.putAll(snmp); | ||
| 39 | + netStats.putAll(snmp6Stats); | ||
| 40 | + var result = new HashMap<String, Metric>(); | ||
| 41 | + netStats.forEach((key, map) -> { | ||
| 42 | + map.forEach((name, value) -> { | ||
| 43 | + String metricName = key + "_" + name; | ||
| 44 | + if (ReUtil.contains(PATTERN, metricName)) | ||
| 45 | + result.put(metricName, new Metric(Collector.Type.UNKNOWN, null).addValue(null, value)); | ||
| 46 | + }); | ||
| 47 | + }); | ||
| 48 | + return result; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + private Map<String, Map<String, Long>> getNetStats(String fileName) throws FileNotFoundException, IOException { | ||
| 52 | + Map<String, Map<String, Long>> values = new HashMap<String, Map<String, Long>>(); | ||
| 53 | + List<String> keys = new ArrayList<String>(); | ||
| 54 | + FileUtil.readFileLine(fileName, (i, line) -> { | ||
| 55 | + var part = StringUtil.splitByBlank(line); | ||
| 56 | + if (keys.isEmpty()) { | ||
| 57 | + Collections.addAll(keys, part); | ||
| 58 | + return; | ||
| 59 | + } | ||
| 60 | + try { | ||
| 61 | + var map = new HashMap<String, Long>(); | ||
| 62 | + for (int j = 1; j < part.length; j++) { | ||
| 63 | + map.put(keys.get(j), NumberUtil.parseLong(part[j])); | ||
| 64 | + } | ||
| 65 | + String key = keys.get(0); | ||
| 66 | + values.put(key.substring(0, key.length() - 1), map); | ||
| 67 | + } catch (Exception e) { | ||
| 68 | + log.error("{} error:{}", fileName, i); | ||
| 69 | + } finally { | ||
| 70 | + keys.clear(); | ||
| 71 | + } | ||
| 72 | + }); | ||
| 73 | + return values; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + private Map<String, Map<String, Long>> getSNMP6Stats(String fileName) throws FileNotFoundException, IOException { | ||
| 77 | + Map<String, Map<String, Long>> values = new HashMap<String, Map<String, Long>>(); | ||
| 78 | + FileUtil.readFileLine(fileName, line -> { | ||
| 79 | + // Expect to have "6" in metric name, skip line otherwise | ||
| 80 | + if (!line.contains("6")) | ||
| 81 | + return; | ||
| 82 | + var part = StringUtil.splitByBlank(line); | ||
| 83 | + if (part.length < 2) | ||
| 84 | + return; | ||
| 85 | + var keys = part[0].split("6"); | ||
| 86 | + var protocol = keys[0] + 6; | ||
| 87 | + if (!values.containsKey(protocol)) | ||
| 88 | + values.put(protocol, new HashMap<String, Long>()); | ||
| 89 | + values.get(protocol).put(keys[1], NumberUtil.parseLong(part[1])); | ||
| 90 | + }); | ||
| 91 | + return values; | ||
| 92 | + } | ||
| 93 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/network/SockStat.java+34-0
| @@ -0,0 +1,34 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.network; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 12 | +import org.opengauss.plugin.agent.util.FileUtil; | ||
| 13 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 14 | +import org.springframework.stereotype.Service; | ||
| 15 | + | ||
| 16 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 17 | + | ||
| 18 | +import io.prometheus.client.Collector.Type; | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +public class SockStat implements OSmetric { | ||
| 22 | + | ||
| 23 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 24 | + Map<String, Metric> map = new HashMap<>(); | ||
| 25 | + FileUtil.readFileLine("/proc/net/sockstat", line -> { | ||
| 26 | + var part = StringUtil.splitByBlank(line); | ||
| 27 | + var key = StringUtil.replaceParenthesis(part[0]) + "_"; | ||
| 28 | + for (int i = 1; i * 2 <= part.length; i++) { | ||
| 29 | + map.put(key + part[2 * i - 1], new Metric(Type.GAUGE, null).addValue(null, part[2 * i])); | ||
| 30 | + } | ||
| 31 | + }); | ||
| 32 | + return map; | ||
| 33 | + } | ||
| 34 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/metric/system/network/Socket.java+54-0
| @@ -0,0 +1,54 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.metric.system.network; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.Arrays; | ||
| 9 | +import java.util.HashMap; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 13 | +import org.opengauss.plugin.agent.util.CmdUtil; | ||
| 14 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 15 | +import org.springframework.stereotype.Service; | ||
| 16 | + | ||
| 17 | +import org.opengauss.plugin.agent.metric.OSmetric; | ||
| 18 | + | ||
| 19 | +import io.prometheus.client.Collector.Type; | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +public class Socket implements OSmetric { | ||
| 23 | + private static final String SPLIT = ","; | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + public Map<String, Metric> getMetric(Integer dbPort) throws FileNotFoundException, IOException { | ||
| 27 | + // TODO | ||
| 28 | +// try { | ||
| 29 | +// CmdUtil.readFromCmd(CmdUtil.cmd("ss -e"), line -> { | ||
| 30 | +// | ||
| 31 | +// }); | ||
| 32 | +// } catch (IOException e) { | ||
| 33 | + Map<String, Integer> counter = new HashMap<>(); | ||
| 34 | + CmdUtil.readFromCmd(CmdUtil.cmd("netstat"), (index, line) -> { | ||
| 35 | + if (index < 2) | ||
| 36 | + return; | ||
| 37 | + var part = StringUtil.splitByBlank(line); | ||
| 38 | + if (part.length < 5) | ||
| 39 | + return; | ||
| 40 | + var proto = part[0]; | ||
| 41 | + if (proto.startsWith("tcp") || proto.startsWith("udp")) { | ||
| 42 | + var key = proto + SPLIT + part[5]; | ||
| 43 | + counter.put(key, counter.getOrDefault(key, 0) + 1); | ||
| 44 | + } | ||
| 45 | + }); | ||
| 46 | +// } | ||
| 47 | + var metric = new Metric(Type.GAUGE, Arrays.asList("proto", "state")); | ||
| 48 | + counter.forEach((key, value) -> { | ||
| 49 | + var part = key.split(SPLIT); | ||
| 50 | + metric.addValue(Arrays.asList(part), value); | ||
| 51 | + }); | ||
| 52 | + return Map.of("", metric); | ||
| 53 | + } | ||
| 54 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/server/HostMetric.java+146-0
| @@ -0,0 +1,146 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.server; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.ArrayList; | ||
| 9 | +import java.util.Arrays; | ||
| 10 | +import java.util.Collections; | ||
| 11 | +import java.util.HashMap; | ||
| 12 | +import java.util.List; | ||
| 13 | +import java.util.Map; | ||
| 14 | + | ||
| 15 | +import org.opengauss.plugin.agent.metric.Ametric; | ||
| 16 | +import org.opengauss.plugin.agent.metric.DBmetric; | ||
| 17 | +import org.opengauss.plugin.agent.metric.Metric; | ||
| 18 | +import org.opengauss.plugin.agent.util.StringUtil; | ||
| 19 | +import org.springframework.beans.factory.annotation.Value; | ||
| 20 | +import org.springframework.boot.ApplicationArguments; | ||
| 21 | +import org.springframework.boot.ApplicationRunner; | ||
| 22 | +import org.springframework.core.annotation.Order; | ||
| 23 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 24 | +import org.springframework.stereotype.Component; | ||
| 25 | + | ||
| 26 | +import cn.hutool.core.util.StrUtil; | ||
| 27 | +import io.prometheus.client.Collector; | ||
| 28 | +import io.prometheus.client.Collector.MetricFamilySamples; | ||
| 29 | +import io.prometheus.client.Collector.MetricFamilySamples.Sample; | ||
| 30 | +import io.prometheus.client.CollectorRegistry; | ||
| 31 | +import io.prometheus.client.exporter.HTTPServer; | ||
| 32 | +import lombok.Data; | ||
| 33 | +import lombok.RequiredArgsConstructor; | ||
| 34 | +import lombok.experimental.Accessors; | ||
| 35 | +import lombok.extern.log4j.Log4j2; | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +public class HostMetric implements ApplicationRunner { | ||
| 44 | + private final Map<String, Ametric> collectors; | ||
| 45 | + private static final List<String> OS_LABEL_NAMES = Arrays.asList("host"); | ||
| 46 | + private static final List<String> DB_LABEL_NAMES = Arrays.asList("instanceId"); | ||
| 47 | + private static final Map<String, List<MetricFamilySamples>> CACHE = new HashMap<>(); | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + private Integer exporterPort; | ||
| 51 | + | ||
| 52 | + private String hostId; | ||
| 53 | + | ||
| 54 | + private String nodeId; | ||
| 55 | + | ||
| 56 | + private Integer dbport; | ||
| 57 | + | ||
| 58 | + private String dbUsername; | ||
| 59 | + | ||
| 60 | + private String dbPassword; | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + public void run(ApplicationArguments args) throws Exception { | ||
| 64 | + if (exporterPort == null) | ||
| 65 | + return; | ||
| 66 | + collectors.forEach((collectorName, collector) -> { | ||
| 67 | + Map<String, Metric> metric; | ||
| 68 | + try { | ||
| 69 | + metric = collector.getMetric(null); | ||
| 70 | + if (metric == null) { | ||
| 71 | + log.error("metric null:{}", collectorName); | ||
| 72 | + return; | ||
| 73 | + } | ||
| 74 | + } catch (FileNotFoundException e) { | ||
| 75 | + log.error("collector:{}", collectorName, e); | ||
| 76 | + return; | ||
| 77 | + } catch (IOException e) { | ||
| 78 | + log.error("collector:{}", collectorName, e); | ||
| 79 | + return; | ||
| 80 | + } | ||
| 81 | + CollectorRegistry.defaultRegistry.register(new Collector() { | ||
| 82 | + | ||
| 83 | + public List<MetricFamilySamples> collect() { | ||
| 84 | + return CACHE.getOrDefault(collectorName, Collections.emptyList()); | ||
| 85 | + } | ||
| 86 | + }); | ||
| 87 | + }); | ||
| 88 | + // c.unregister(cpuCollector); | ||
| 89 | + new HTTPServer.Builder().withPort(exporterPort).build(); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + private static String formatKey(String collectorName, Ametric collector, String k) { | ||
| 93 | + return StringUtil.replaceParenthesis((collector instanceof DBmetric) ? k : "agent_" + collectorName + k); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + | ||
| 97 | + public void cache() { | ||
| 98 | + try { | ||
| 99 | + collectors.forEach((collectorName, collector) -> { | ||
| 100 | + if (StrUtil.isBlank(hostId)) | ||
| 101 | + return; | ||
| 102 | + if (collector instanceof DBmetric && (StrUtil.isBlank(nodeId) || dbport == null)) | ||
| 103 | + return; | ||
| 104 | + var list = new ArrayList<MetricFamilySamples>(); | ||
| 105 | + try { | ||
| 106 | + collector.getMetric(dbport).forEach((k, v) -> { | ||
| 107 | + if (k == null) | ||
| 108 | + return; | ||
| 109 | + final String key = formatKey(collectorName, collector, k); | ||
| 110 | + var samples = new ArrayList<Sample>(); | ||
| 111 | + List<String> labelNames = new ArrayList<String>(); | ||
| 112 | + labelNames.addAll(v.getLabelNames()); | ||
| 113 | + // global label | ||
| 114 | + labelNames.addAll(OS_LABEL_NAMES); | ||
| 115 | + if (collector instanceof DBmetric) | ||
| 116 | + labelNames.addAll(DB_LABEL_NAMES); | ||
| 117 | + v.getValues().forEach(value -> { | ||
| 118 | + List<String> labelValues = new ArrayList<String>(); | ||
| 119 | + labelValues.addAll(value.getLabelValues()); | ||
| 120 | + // global value | ||
| 121 | + labelValues.addAll(Arrays.asList(hostId)); | ||
| 122 | + if (collector instanceof DBmetric) | ||
| 123 | + labelValues.addAll(Arrays.asList(nodeId)); | ||
| 124 | + if (labelNames.size() != labelValues.size()) { | ||
| 125 | + log.error("collector {} metric {} error:{}{}", collectorName, key, labelNames, | ||
| 126 | + labelValues); | ||
| 127 | + return; | ||
| 128 | + } | ||
| 129 | + samples.add(new Sample(key, labelNames, labelValues, value.getValue())); | ||
| 130 | + }); | ||
| 131 | + String help = v.getHelp(); | ||
| 132 | + if (StrUtil.isBlank(help)) { | ||
| 133 | + help = StrUtil.upperFirst(collectorName) + " information field " + k; | ||
| 134 | + } | ||
| 135 | + list.add(new MetricFamilySamples(key, v.getType(), help, samples)); | ||
| 136 | + }); | ||
| 137 | + } catch (IOException e) { | ||
| 138 | + log.error("collect fail:{}", collectorName); | ||
| 139 | + } | ||
| 140 | + CACHE.put(collectorName, list); | ||
| 141 | + }); | ||
| 142 | + } catch (Exception e) { | ||
| 143 | + log.error("metric cache err", e); | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/CmdUtil.java+70-0
| @@ -0,0 +1,70 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.util; | ||
| 5 | + | ||
| 6 | +import java.io.BufferedReader; | ||
| 7 | +import java.io.FileNotFoundException; | ||
| 8 | +import java.io.IOException; | ||
| 9 | +import java.io.InputStreamReader; | ||
| 10 | +import java.util.Arrays; | ||
| 11 | +import java.util.function.BiConsumer; | ||
| 12 | +import java.util.function.Consumer; | ||
| 13 | + | ||
| 14 | +import lombok.extern.log4j.Log4j2; | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +public class CmdUtil { | ||
| 18 | + public static final String[] cmd(String... cmd) { | ||
| 19 | + return cmd; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public static final void readFromCmd(String cmd, Consumer<String> consumer) | ||
| 23 | + throws FileNotFoundException, IOException { | ||
| 24 | + readFromCmd(Arrays.asList("sh", "-c", cmd).toArray(new String[3]), consumer); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public static final void readFromCmd(String cmd, BiConsumer<Integer, String> consumer) | ||
| 28 | + throws FileNotFoundException, IOException { | ||
| 29 | + readFromCmd(Arrays.asList("sh", "-c", cmd).toArray(new String[3]), consumer); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public static final void readFromCmd(String[] cmd, Consumer<String> consumer) | ||
| 33 | + throws FileNotFoundException, IOException { | ||
| 34 | + if (consumer != null) | ||
| 35 | + readFromCmd(cmd, (i, line) -> consumer.accept(line)); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public static final void readFromCmd(String[] cmd, BiConsumer<Integer, String> consumer) | ||
| 39 | + throws FileNotFoundException, IOException { | ||
| 40 | + var process = new ProcessBuilder().command(cmd).start(); | ||
| 41 | + try { | ||
| 42 | + process.waitFor(); | ||
| 43 | + } catch (InterruptedException e) { | ||
| 44 | + log.error("", e); | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()));) { | ||
| 48 | + int i = -1; | ||
| 49 | + while (reader.ready()) { | ||
| 50 | + i++; | ||
| 51 | + String line = reader.readLine(); | ||
| 52 | + if (line.isBlank()) | ||
| 53 | + continue; | ||
| 54 | + if (consumer != null) | ||
| 55 | + consumer.accept(i, line); | ||
| 56 | + } | ||
| 57 | + } catch (Exception e) { | ||
| 58 | + log.error("cmd '{}' format error", cmd, e); | ||
| 59 | + throw e; | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public static final String readFromCmd(String cmd) throws FileNotFoundException, IOException { | ||
| 64 | + StringBuilder str = new StringBuilder(); | ||
| 65 | + readFromCmd(cmd, line -> { | ||
| 66 | + str.append(line); | ||
| 67 | + }); | ||
| 68 | + return str.toString(); | ||
| 69 | + } | ||
| 70 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/DbUtil.java+61-0
| @@ -0,0 +1,61 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package org.opengauss.plugin.agent.util; | ||
| 6 | + | ||
| 7 | +import java.sql.Connection; | ||
| 8 | +import java.sql.DriverManager; | ||
| 9 | +import java.sql.SQLException; | ||
| 10 | +import java.util.ArrayList; | ||
| 11 | +import java.util.Collections; | ||
| 12 | +import java.util.HashMap; | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Map; | ||
| 15 | + | ||
| 16 | +import org.opengauss.plugin.agent.server.HostMetric; | ||
| 17 | +import org.springframework.stereotype.Component; | ||
| 18 | + | ||
| 19 | +import lombok.AllArgsConstructor; | ||
| 20 | +import lombok.extern.log4j.Log4j2; | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +public class DbUtil { | ||
| 26 | + private static Connection conn; | ||
| 27 | + | ||
| 28 | + private final HostMetric hostMetric; | ||
| 29 | + | ||
| 30 | + public final List<Map<String, Object>> query(String sql) { | ||
| 31 | + synchronized (conn) { | ||
| 32 | + try { | ||
| 33 | + conn = DriverManager.getConnection("jdbc:opengauss://" + "localhost" + ":" + hostMetric.getDbport() | ||
| 34 | + + "/" + "postgres" + "?TimeZone=UTC", hostMetric.getDbUsername(), hostMetric.getDbPassword()); | ||
| 35 | + } catch (SQLException e) { | ||
| 36 | + conn = null; | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + try { | ||
| 40 | + var stmt = conn.createStatement(); | ||
| 41 | + var rs = stmt.executeQuery(sql); | ||
| 42 | + var rsmeta = rs.getMetaData(); | ||
| 43 | + List<Map<String, Object>> list = new ArrayList<>(); | ||
| 44 | + while (rs.next()) { | ||
| 45 | + Map<String, Object> map = new HashMap<>(); | ||
| 46 | + for (int i = 0; i < rsmeta.getColumnCount(); i++) { | ||
| 47 | + var obj = rs.getObject(i + 1); | ||
| 48 | + if (obj == null) { | ||
| 49 | + obj = ""; | ||
| 50 | + } | ||
| 51 | + map.put(rsmeta.getColumnName(i + 1), obj); | ||
| 52 | + } | ||
| 53 | + list.add(map); | ||
| 54 | + } | ||
| 55 | + return list; | ||
| 56 | + } catch (SQLException e) { | ||
| 57 | + log.error("sql error, cause :{} sql:{}", e.getMessage(), sql); | ||
| 58 | + return Collections.emptyList(); | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/FileUtil.java+28-0
| @@ -0,0 +1,28 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.util; | ||
| 5 | + | ||
| 6 | +import java.io.FileNotFoundException; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.function.BiConsumer; | ||
| 9 | +import java.util.function.Consumer; | ||
| 10 | + | ||
| 11 | +public class FileUtil { | ||
| 12 | + /** | ||
| 13 | + * read file to line skip blank line | ||
| 14 | + */ | ||
| 15 | + public static final void readFileLine(String name, Consumer<String> consumer) | ||
| 16 | + throws FileNotFoundException, IOException { | ||
| 17 | + if (consumer != null) | ||
| 18 | + readFileLine(name, (i, line) -> consumer.accept(line)); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * read file to line skip blank line | ||
| 23 | + */ | ||
| 24 | + public static final void readFileLine(String name, BiConsumer<Integer, String> consumer) | ||
| 25 | + throws FileNotFoundException, IOException { | ||
| 26 | + CmdUtil.readFromCmd(CmdUtil.cmd("cat", name), consumer); | ||
| 27 | + } | ||
| 28 | +} | ||
Aplugins/observability-instance/InstanceExporter/src/main/java/org/opengauss/plugin/agent/util/StringUtil.java+22-0
| @@ -0,0 +1,22 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) GBA-NCTI-ISDC. 2022-2023. All rights reserved. | ||
| 3 | + */ | ||
| 4 | +package org.opengauss.plugin.agent.util; | ||
| 5 | + | ||
| 6 | +public class StringUtil { | ||
| 7 | + public static final String[] splitByBlank(String str) { | ||
| 8 | + return str.trim().split("\\s+"); | ||
| 9 | + } | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * replace "()" and " " to "_" and remove last ":", example: "Active(anon):" -> | ||
| 13 | + * "Active_anon" | ||
| 14 | + */ | ||
| 15 | + public static final String replaceParenthesis(String str) { | ||
| 16 | + return str.split(":")[0].replaceAll(" ", "_").replaceAll("\\((.*)\\)", "_$1").replaceAll("__", "_"); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + public static final String removeLast(String str) { | ||
| 20 | + return str.substring(0, str.length() - 1); | ||
| 21 | + } | ||
| 22 | +} | ||
Rplugins/observability-instance/files/og_exporter.yml→plugins/observability-instance/InstanceExporter/src/main/resources/og_exporter.yml+66-4
Dplugins/observability-instance/files/prometheus.yml+0-44
Dplugins/observability-instance/src/main/java/com/nctigba/common/mybatis/BasePageDTO.java+0-200
Dplugins/observability-instance/src/main/java/com/nctigba/common/mybatis/MyPage.java+0-100
Dplugins/observability-instance/src/main/java/com/nctigba/common/web/config/ControllerConfig.java+0-14
Dplugins/observability-instance/src/main/java/com/nctigba/common/web/config/package-info.java+0-21
Aplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/BaseI18nException.java+59-0
Mplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/CustomException.java+33-30
Mplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/CustomExceptionEnum.java+17-15
Mplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/InstanceException.java+32-12
Aplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/InstanceExceptionMsgEnum.java+20-0
Dplugins/observability-instance/src/main/java/com/nctigba/common/web/exception/ResponseCode.java+0-98
Dplugins/observability-instance/src/main/java/com/nctigba/common/web/model/RestResult.java+0-32
Dplugins/observability-instance/src/main/java/com/nctigba/common/web/model/query/InstanceQuery.java+0-15
Dplugins/observability-instance/src/main/java/com/nctigba/common/web/model/query/PageBaseQuery.java+0-18
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/ObservabilityPluginApplication.java+4-2
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/config/AutoFillMetaObjectHandler.java+0-50
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/config/DataSourceConfig.java+19-16
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/config/MybatisPlusConfig.java+9-6
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/config/ParamInfoInitConfig.java+176-173
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/config/PluginExtensionInfoConfig.java+15-12
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/BaseConstance.java+0-19
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/CommonConstants.java+37-32
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/DatabaseType.java+9-6
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/DriverConstants.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/JdbcConnectConstants.java+3-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MetricsLine.java+138-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MetricsValue.java+86-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MonitoringConstants.java+4-1
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MonitoringResultType.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/MonitoringType.java+4-1
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/constants/OSType.java+3-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ControllerConfig.java+29-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/EnvironmentController.java+151-169
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/IndexController.java+48-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/Installer.java+64-61
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/MonitoringController.java+26-18
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/PageController.java+181-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ParamInfoController.java+3-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ResourceCPUController.java+97-0
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/ServerInfoController.java+0-34
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/SessionController.java+115-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/TopSQLController.java+31-27
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/controller/WdrController.java+3-0
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/param/DatabaseParamDTO.java+0-89
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/param/OsParamDTO.java+0-89
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/param/ParamInfoDTO.java+22-19
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/server/ServerInfoReq.java+3-1
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/server/ServerInfoResp.java+0-22
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/session/BlockTreeDto.java+22-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/session/DetailStatisticDto.java+24-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/topsql/TopSQLInfoReq.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/topsql/TopSQLListReq.java+3-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/dto/topsql/TopSQLNowReq.java+17-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/NctigbaEnv.java+42-18
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/OpsWdrEntity.java+65-62
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/ParamInfo.java+35-32
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/ParamValueInfo.java+29-26
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/Searc.java+0-48
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/entity/ServerInfoEntity.java+4-2
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/MonitoringHandlerFactory.java+11-4
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/OSHandlerFactory.java+0-50
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/InstanceHandlerFactory.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/SessionHandlerFactory.java+23-27
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/factory/TopSQLHandlerFactory.java+8-2
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/instance/InstanceHandler.java+0-33
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/instance/NormalInstanceHandler.java+0-90
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/monitoring/MonitoringHandler.java+4-1
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/monitoring/NormalMonitoringHandler.java+327-324
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/os/NormalOSHandler.java+0-22
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/os/OSHandler.java+0-22
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/session/OpenGaussSessionHandler.java+394-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/session/SessionHandler.java+36-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/topsql/OpenGaussTopSQLHandler.java+102-59
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/handler/topsql/TopSQLHandler.java+27-6
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/listener/PluginListener.java+14-5
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/DbConfigMapper.java+22-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/NctigbaEnvMapper.java+4-1
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/OpsWdrMapper.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/ParamInfoMapper.java+46-43
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/ParamValueInfoMapper.java+73-70
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/ServerInfoMapper.java+4-1
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/mapper/TopSqlMapper.java+13-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/DictionaryConfig.java+21-18
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/ExecutionPlan.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/IndexAdvice.java+3-1
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/InstanceInfo.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/InstanceNodeInfo.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/PartitionDataResp.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/ResInfo.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/WdrGeneratorBody.java+14-11
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/WdrSnapshotVO.java+9-6
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/monitoring/MonitoringMetric.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/monitoring/MonitoringParam.java+3-0
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/param/DatabaseParamData.java+0-58
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/param/OsParamData.java+0-94
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/model/param/ParamQuery.java+6-3
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/pool/PoolManager.java+0-86
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/pool/SSHPoolManager.java+0-78
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/AbstractInstaller.java+86-83
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ClusterManager.java+156-150
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ClusterOpsProviderManager.java+0-66
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ExporterInstallService.java+337-0
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ExporterService.java+0-303
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/IServerInfoService.java+3-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/MetricsService.java+201-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/MonitoringService.java+3-1
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/OpsWdrService.java+333-328
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ParamInfoService.java+3-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/PrometheusService.java+208-188
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/SessionService.java+28-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/TopSQLService.java+189-44
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/MonitoringServiceImpl.java+8-3
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/ServerInfoServiceImpl.java+0-41
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/SessionServiceImpl.java+229-0
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/impl/TopSQLServiceImpl.java+0-124
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/AbstractOpsProvider.java+231-230
Rplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/ClusterOpsProvider.java→plugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/ClusterOpsProvider.java+8-5
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/ClusterOpsProviderManager.java+69-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/EnterpriseOpsProvider.java+37-34
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/LiteOpsProvider.java+44-41
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/MinimaListOpsProvider.java+47-44
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/OpenEulerArch64EnterpriseOpsProvider.java+38-35
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/OpenEulerArch64LiteOpsProvider.java+38-35
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/OpenEulerArch64MinimaListOpsProvider.java+47-44
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/OpenEulerX86EnterpriseOpsProvider.java+38-35
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/OpenEulerX86LiteOpsProvider.java+38-35
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/service/provider/OpenEulerX86MinimaListOpsProvider.java+47-44
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/Download.java+20-17
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/HttpUtils.java+8-4
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/JschUtil.java+442-445
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/Language.java+28-0
Aplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/ListUtil.java+34-0
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/MessageSourceUtil.java+64-49
Dplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/SSHOperator.java+0-245
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/SshSession.java+105-94
Mplugins/observability-instance/src/main/java/com/nctigba/observability/instance/util/YamlUtil.java+19-16
Mplugins/observability-instance/src/test/java/com/nctigba/observability/instance/MonitoringServiceTest.java+7-4
Mplugins/observability-instance/src/test/java/com/nctigba/observability/instance/ObservabilityPluginApplicationTests.java+6-3
Mplugins/observability-instance/src/test/java/com/nctigba/observability/instance/TopSQLServiceTest.java+8-5
Aplugins/observability-instance/web-ui/src/pages/dashboardV2/instanceMonitor/instanceMetrics/Index.vue+249-0
Aplugins/observability-instance/web-ui/src/pages/dashboardV2/instanceMonitor/sessionMonitor/Detail.vue+548-0
Aplugins/observability-instance/web-ui/src/pages/dashboardV2/instanceMonitor/sessionMonitor/Index.vue+387-0
Aplugins/observability-instance/web-ui/src/pages/dashboardV2/resourceMonitor/network/Index.vue+315-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/common/web/exception/CustomException.java+60-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/common/web/exception/CustomExceptionEnum.java+34-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/common/web/exception/HisDiagnosisException.java+29-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/config/ElasticsearchProvider.java+70-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/config/history/HisDiagnosisInit.java+170-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/AgentParamCommon.java+15-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/DiagnosisTypeCommon.java+16-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/ElasticSearchCommon.java+25-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/MetricCommon.java+23-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/OptionCommon.java+33-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/PrometheusConstants.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/SqlCommon.java+33-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/constants/history/ThresholdCommon.java+25-0
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/controller/EnvironmentController.java+56-57
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/controller/HisDiagnosisController.java+47-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/controller/HisDiagnosisTaskController.java+56-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/controller/HisThresholdController.java+51-0
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/listener/PluginListener.java+30-27
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/mapper/history/HisDiagnosisResultMapper.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/mapper/history/HisDiagnosisTaskMapper.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/mapper/history/HisThresholdMapper.java+22-0
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/NctigbaEnv.java+40-21
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/DataStoreConfig.java+25-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/HisDiagnosisResult.java+91-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/HisDiagnosisTask.java+132-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/HisDiagnosisThreshold.java+57-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/data/AgentData.java+23-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/data/DatabaseData.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/data/ElasticSearchData.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/data/PrometheusData.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/AgentDTO.java+29-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/AnalysisDTO.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/HisDiagnosisTaskDTO.java+26-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/HisThresholdDTO.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/LockAnalysisDTO.java+23-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/LogDetailInfoDTO.java+26-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/LogInfoDTO.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/MetricToTableDTO.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/OptionDTO.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/dto/WaitEventInfo.java+23-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/AspAnalysisDTO.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/BusinessConnCountDTO.java+25-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/CurrentCpuDTO.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/CurrentCpuUsageDTO.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/LockDTO.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/MetricDataDTO.java+23-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/PrometheusDataDTO.java+26-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/point/WaitEventDTO.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/query/EsSearchQuery.java+73-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/query/HisThresholdQuery.java+23-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/query/MonitoringParam.java+40-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/query/OptionQuery.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/result/HisTreeNode.java+83-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/result/Node.java+32-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/model/history/result/TaskState.java+23-0
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/AbstractInstaller.java+3-3
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/AgentService.java+197-198
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/ClusterManager.java+2-2
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/diagnosis/TaskCreator.java+63-67
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/diagnosis/analysis/OffCpuAnaly.java+1-1
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/diagnosis/analysis/OnCpuAnaly.java+1-1
Mplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/diagnosis/caller/BccCaller.java+109-112
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/DataStoreService.java+25-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/HisDiagnosisPointService.java+32-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/HisDiagnosisService.java+21-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/HisThresholdService.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/Impl/DataStoreServiceImpl.java+56-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/Impl/HisDiagnosisServiceImpl.java+225-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/Impl/HisThresholdServiceImpl.java+71-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/Impl/TaskServiceImpl.java+292-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/TaskService.java+24-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/CollectionItem.java+18-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/agent/AgentCollectionItem.java+31-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/agent/CurrentCpuUsageItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/agent/DbProcessCurrentCpuItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/agent/OtherProcessCurrentCpuItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/agent/TopDbProcessItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/elastic/DeadlockItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/elastic/ElasticSearchCollectionItem.java+168-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/elastic/LockTimeoutItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/ActivityNumItem.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/ActivityNumItem2.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/AvgCpuItem.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/DbAvgCpuItem.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/PrometheusCollectionItem.java+110-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/ThreadPoolUsageItem.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/ThreadPoolUsageItem2.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/metric/WaitEventItem.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/BusinessConnCountItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/CpuTimeTopSqlItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/DatabaseCollectionItem.java+95-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/PoorSqlItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/SlowSqlItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/ThreadWaitEventItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/collection/table/TopCpuTimeSqlItem.java+22-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/AspAnalysis.java+241-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/AvgCpuUsageRate.java+104-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/BusinessConnCount.java+311-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/CpuTimeTopSql.java+97-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/CurrentCpuUsage.java+104-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/CurrentSlowSql.java+94-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/CurrentWaitEvent.java+127-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/DatabaseHostLowPressure.java+125-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/DatabaseHostPressure.java+125-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/DbProcessAvgCpuUsage.java+105-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/DbProcessCurrentCpuUsage.java+109-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/DeadlockAnalysis.java+102-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/HistoryWaitEvent.java+163-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/LockAnalysis.java+51-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/LockTimeout.java+102-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/OtherProcessAvgCpuUsage.java+145-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/OtherProcessCurrentCpuUsage.java+106-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/PoorSql.java+47-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/TaskInfo.java+74-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/TopCpuTimeSql.java+97-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/TopDbProcess.java+84-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/WaitEventAnalysis.java+47-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/service/history/point/WdrAnalysis.java+160-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/AgentUtil.java+99-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/ComparatorUtil.java+43-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/DbUtil.java+74-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/EsLogSearchUtils.java+316-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/HostUtil.java+38-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/HttpUtils.java+75-0
Aplugins/observability-sql-diagnosis/src/main/java/com/nctigba/observability/sql/util/PrometheusUtil.java+248-0
Binary files do not support preview
Dplugins/observability-sql-diagnosis/web-ui/package-lock.json+0-13134
此文件变更行数或变更字符数较多,你可以直接
Mplugins/observability-sql-diagnosis/web-ui/src/pages/datasource/task_detail/detail_large.vue+199-90
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/AspAnalysis/Index.vue+159-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/AvgCpuUsageRate/Index.vue+121-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/BusinessConnCount/Index.vue+159-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/CpuTimeTopSql/Index.vue+137-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/CurrentCpuUsage/Index.vue+84-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/DbProcessAvgCpuUsage/Index.vue+121-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/DbProcessCurrentCpuUsage/Index.vue+119-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/OtherProcessAvgCpuUsage/Index.vue+129-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/OtherProcessCurrentCpuUsage/Index.vue+119-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/TopCpuTimeSql/Index.vue+135-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/TopDbProcess/Index.vue+119-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/CPU/WdrAnalysis/Index.vue+121-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/DBHostPress/Index.vue+163-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/Lock/DeadlockAnalysis/Index.vue+130-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/Lock/LockAnalysis/Index.vue+79-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/Lock/LockTimeout/Index.vue+130-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/SQL/CurrentSlowSql/Index.vue+130-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/SQL/HistorySlowSql/Index.vue+121-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/SQL/PoorSql/Index.vue+79-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/TaskInfo/Index.vue+216-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/WaitEvent/CurrentWaitEvent/Index.vue+125-0
Aplugins/observability-sql-diagnosis/web-ui/src/pages/diagnosisTask/detail/pointInfos/WaitEvent/HistoryWaitEvent/Index.vue+125-0