index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. import _ from 'lodash'
  2. import * as R from 'ramda'
  3. import { metric_zh, alertStrategyMaps, preiodMaps, levelMaps } from '@Monitor/constants'
  4. import { channelMaps } from '@/constants'
  5. import i18n from '@/locales'
  6. import { transformUnit, arrayToObj } from '@/utils/utils'
  7. import { currencyUnitMap } from '@/constants/currency'
  8. export const levelColumn = () => ({
  9. field: 'level',
  10. title: i18n.t('monitor.level'),
  11. minWidth: 40,
  12. sortable: true,
  13. slots: {
  14. default: ({ row }, h) => {
  15. const levelItem = levelMaps[row.level]
  16. const text = levelItem ? levelItem.label : row.level
  17. return [h('a-tag', {
  18. props: {
  19. color: levelItem ? levelItem.color : levelMaps.normal.color,
  20. },
  21. }, text)]
  22. },
  23. },
  24. })
  25. export const conditionColumn = {
  26. field: 'channel',
  27. title: i18n.t('monitor.text_11'),
  28. minWidth: 80,
  29. formatter: ({ row }) => {
  30. if (!row.channel || !row.channel.length) return '-'
  31. return row.channel.filter(val => ~val.indexOf('robot')).map(val => (channelMaps[val] || {}).label).join('、')
  32. },
  33. }
  34. export const robotsColumn = (robotList) => ({
  35. field: 'robot_ids',
  36. title: i18n.t('monitor.text_11'),
  37. slots: {
  38. default: ({ row }, h) => {
  39. if (!row.robot_ids || !row.robot_ids.length) return '-'
  40. const robotsMap = arrayToObj(robotList, 'id')
  41. const robotNames = row.robot_ids.map(val => robotsMap[val].name)
  42. return robotNames.map(val => {
  43. return h('a-tag', val)
  44. })
  45. },
  46. },
  47. })
  48. export const strategyColumn = (field = 'common_alert_metric_details', title = i18n.t('monitor.strategy_detail'), data) => ({
  49. field,
  50. title,
  51. minWidth: 120,
  52. slots: {
  53. default: ({ row }, h) => {
  54. const { filters, strategyConfig, strategyArr = [] } = getMetircAlertUtil(data || row, field)
  55. const periodTxt = i18n.t('monitor.text_102', [strategyConfig.period])
  56. if (!(data || row)[field]) return '-'
  57. let filterNode = null
  58. if (filters.length > 0) {
  59. filterNode = (
  60. <a-tag class="w-100">
  61. <div>{i18n.t('monitor.text_101')}: </div>
  62. {filters.map(v => <div class="w-100 text-truncate" title={v}>{v}</div>)}
  63. </a-tag>
  64. )
  65. }
  66. const strategys = strategyArr.map(item => <div>{item}</div>)
  67. return [
  68. <div>
  69. <div>{i18n.t('monitor.commonalert.alert_condition.content')}{periodTxt}:</div>
  70. <div>{strategys}</div>
  71. {filterNode}
  72. </div>,
  73. ]
  74. },
  75. },
  76. formatter: ({ row }) => {
  77. const { filters, strategyConfig, strategyArr = [] } = getMetircAlertUtil(data || row, field)
  78. const periodTxt = i18n.t('monitor.text_102', [strategyConfig.period])
  79. if (!(data || row)[field]) return ''
  80. let filterNode = null
  81. if (filters.length > 0) {
  82. filterNode = i18n.t('monitor.text_101') + ':'
  83. filters.map(v => {
  84. filterNode += v
  85. })
  86. }
  87. const strategys = strategyArr.filter(item => item).join(',')
  88. return i18n.t('monitor.commonalert.alert_condition.content') + periodTxt + ':' + strategys + (filterNode || '')
  89. },
  90. })
  91. export const reasonColumn = () => ({
  92. field: 'reason',
  93. title: i18n.t('monitor.alert_reason'),
  94. minWidth: 100,
  95. formatter: ({ row }) => {
  96. return row.reason || '-'
  97. },
  98. })
  99. export const projectTableColumn = () => ({
  100. field: 'project',
  101. title: i18n.t('monitor.text00015'),
  102. slots: {
  103. default: ({ row }, h) => {
  104. if (!row.tenant && !row.project_domain) {
  105. return i18n.t('monitor.text00024')
  106. }
  107. const domain = row.project_domain || row.domain
  108. if (!row.tenant && domain) {
  109. return `${domain}${i18n.t('monitor.text00025')}`
  110. }
  111. if (row.tenant && domain) {
  112. return [
  113. <list-body-cell-wrap copy field='tenant' row={row} />,
  114. <list-body-cell-wrap hide-field copy field="domain" row={{ domain }}>
  115. <span class='text-weak'>{domain}</span>
  116. </list-body-cell-wrap>,
  117. ]
  118. }
  119. },
  120. },
  121. })
  122. export const recipientsColumn = recipientList => ({
  123. field: 'recipients',
  124. title: i18n.t('compute.text_740'),
  125. slots: {
  126. default: ({ row }, h) => {
  127. if (!row.recipients || !row.recipients.length) return '-'
  128. const recipientsMap = arrayToObj(recipientList, 'id')
  129. const recipientNames = []
  130. row.recipients.map(val => {
  131. if (recipientsMap[val]) {
  132. recipientNames.push(recipientsMap[val].name)
  133. }
  134. })
  135. return recipientNames.map(val => {
  136. return h('a-tag', val)
  137. })
  138. },
  139. },
  140. })
  141. export const rolesColumn = roleList => ({
  142. field: 'role_ids',
  143. title: i18n.t('monitor.role'),
  144. slots: {
  145. default: ({ row }, h) => {
  146. if (!row.role_ids || !row.role_ids.length) return '-'
  147. const rolesMap = arrayToObj(roleList, 'id')
  148. const roleNames = []
  149. row.role_ids.map(val => {
  150. if (rolesMap[val]) {
  151. roleNames.push(rolesMap[val].name)
  152. }
  153. })
  154. return roleNames.map(val => {
  155. return h('a-tag', val)
  156. })
  157. },
  158. },
  159. })
  160. export function getMetircAlertUtil (row, field, condition) {
  161. let strategy = '-'
  162. let strategyConfig = {
  163. measurement: '',
  164. period: '', // 时间间隔 2h 14d
  165. metric: '', // 监控指标
  166. comparator: '', // > < within
  167. threshold: null, // 阈值
  168. unit: '', // 单位
  169. time_from: row.time_from,
  170. }
  171. let hasDeltaCondition = false
  172. if (row[field] && ((R.type(row[field]) === 'Array') || R.type(row[field]) === 'Object') && !R.isEmpty(row[field])) {
  173. if (R.type(row[field]) === 'Array') {
  174. row[field].forEach(item => {
  175. if (item.reduce === 'delta') {
  176. hasDeltaCondition = true
  177. }
  178. })
  179. }
  180. }
  181. const strategyArr = []
  182. const strategyConfigArr = []
  183. const filters = []
  184. const getStrategyInfo = (detail) => {
  185. let measurement = detail.measurement_display_name || detail.measurement_desc || detail.measurement
  186. if (metric_zh[measurement]) measurement = metric_zh[measurement]
  187. strategyConfig.measurement = measurement
  188. let metric = _.get(detail, 'field_description.display_name') || detail.field_desc || detail.field
  189. if (metric) {
  190. metric = metric_zh[metric] || metric
  191. }
  192. strategyConfig.metric = metric
  193. const reduce = (alertStrategyMaps[detail.reduce || detail.reducer || 'avg']) || ''
  194. let alert_duration = row.alert_duration ? i18n.t('monitor.list.duration.label', [row.alert_duration]) : row[field].alert_duration ? i18n.t('monitor.list.duration.label', [row[field].alert_duration]) : ''
  195. // delta 条件不计算持续时间
  196. if (hasDeltaCondition) {
  197. alert_duration = ''
  198. }
  199. let preiod = ((preiodMaps[row.period] || {}).label) || ((preiodMaps[detail.period] || {}).label) || row.period || detail.period
  200. let unit = detail.field_description ? _.get(detail, 'field_description.unit') : (R.type(row.eval_data) === 'Array' ? (_.get(row, 'eval_data[0].unit') || '') : '')
  201. let threshold = R.is(String, detail.threshold) ? { text: detail.threshold } : transformUnit(detail.threshold, unit)
  202. if (detail.measurement === 'cloudaccount_balance' && unit === 'RMB') {
  203. unit = ''
  204. if (detail.filters && detail.filters.length) {
  205. const targets = detail.filters.filter(item => item.key === 'currency')
  206. const cs = []
  207. targets.map(item => {
  208. if (item.value && !cs.includes(item.value)) {
  209. cs.push(item.value)
  210. }
  211. })
  212. if (cs.length === 1) {
  213. unit = currencyUnitMap[cs[0]]?.sign || ''
  214. }
  215. }
  216. threshold = R.is(String, detail.threshold) ? { text: detail.threshold } : unit ? { text: `${unit}${detail.threshold}` } : { text: detail.threshold }
  217. }
  218. let comparator = detail.comparator
  219. let txt = threshold.text
  220. if (detail.comparator === 'within_range' && detail.within_range) {
  221. comparator = ''
  222. txt = `[${detail.within_range[0]}${threshold.unit}, ${detail.within_range[1]}${threshold.unit}]`
  223. strategyConfig.within_range = detail.within_range
  224. }
  225. if (detail.comparator === 'within_range' && detail.threshold_range) {
  226. comparator = ''
  227. txt = i18n.t('monitor.threshold_range_in', [`${detail.threshold_range[0]}${unit || detail.unit || ''}`, `${detail.threshold_range[1]}${unit || detail.unit || ''}`])
  228. strategyConfig.within_range = detail.threshold_range
  229. }
  230. if (detail.comparator === 'outside_range' && detail.threshold_range) {
  231. comparator = ''
  232. txt = i18n.t('monitor.threshold_range_out', [`${detail.threshold_range[0]}${unit || detail.unit || ''}`, `${detail.threshold_range[1]}${unit || detail.unit || ''}`])
  233. strategyConfig.outside_range = detail.threshold_range
  234. }
  235. strategyConfig.comparator = detail.comparator
  236. strategyConfig.threshold = detail.threshold
  237. strategyConfig.unit = unit
  238. strategy = i18n.t('monitor.text_6', [measurement, metric, reduce, alert_duration, comparator, txt])
  239. if (detail.condition_type === 'nodata_query') { // 系统上报数据为空
  240. strategy = i18n.t('monitor.text_108', [alert_duration])
  241. }
  242. if (condition) return strategy // 只要触发条件信息
  243. if (preiod) {
  244. preiod = preiod.replace(i18n.t('monitor.text_103'), '')
  245. // strategy += `${i18n.t('monitor.text_102', [preiod])}`
  246. strategyConfig.period = preiod
  247. }
  248. const silent_period = row.silent_period || row[field].silent_period
  249. if (silent_period) {
  250. let p = silent_period
  251. if (p.endsWith('m')) {
  252. const pi = parseInt(p.replace('m', ''))
  253. if (pi && pi >= 60 && pi % 60 === 0) {
  254. p = i18n.t('monitor.duration.silent.hour', [pi / 60])
  255. } else {
  256. p = i18n.t('monitor.duration.silent.minute', [p.replace('m', '')])
  257. }
  258. } else if (p.endsWith('h')) {
  259. p = i18n.t('monitor.duration.silent.hour', [p.replace('h', '')])
  260. }
  261. strategy += `${i18n.t('monitor.commonalerts.list.silent', [p])}`
  262. strategyConfig.silent_period = silent_period
  263. }
  264. return {
  265. strategy,
  266. strategyConfig,
  267. }
  268. }
  269. if (row[field] && ((R.type(row[field]) === 'Array') || R.type(row[field]) === 'Object') && !R.isEmpty(row[field])) {
  270. let detail = ''
  271. if (R.type(row[field]) === 'Array') {
  272. detail = row[field][0]
  273. row[field].forEach(item => {
  274. const strategyInfo = getStrategyInfo(item)
  275. strategyArr.push(strategyInfo.strategy)
  276. strategyConfigArr.push(strategyInfo.strategyConfig)
  277. })
  278. } else if (R.type(row[field]) === 'Object') {
  279. detail = row[field]
  280. const strategyInfo = getStrategyInfo(detail)
  281. strategy = strategyInfo.strategy
  282. strategyConfig = strategyInfo.strategyConfig
  283. }
  284. if (detail.filters && detail.filters.length) {
  285. detail.filters.forEach((val, i) => {
  286. if (val.key) {
  287. if (val.key !== 'brand' || val.value.toLowerCase() !== 'onecloud') {
  288. filters.push(`${(val.condition && i !== 0) ? val.condition : ''} ${val.key} ${val.operator} ${val.value}`)
  289. } else {
  290. filters.push(`${(val.condition && i !== 0) ? val.condition : ''} ${val.key} ${val.operator} ${i18n.t('brand')}`)
  291. }
  292. }
  293. })
  294. }
  295. }
  296. return {
  297. strategy,
  298. strategyConfig,
  299. filters,
  300. strategyArr,
  301. strategyConfigArr,
  302. }
  303. }
  304. export const getResTypeColumn = ({ field = 'common_alert_metric_details' } = {}) => ({
  305. field: 'res_type',
  306. title: i18n.t('monitor.text_97'),
  307. formatter: ({ row }) => {
  308. const str = _.get(row[field], '[0].res_type')
  309. if (!str) return '-'
  310. if (i18n.te(`dictionary.${str}`)) return i18n.t(`dictionary.${str}`)
  311. return str
  312. },
  313. })
  314. export const getVerifiedContactTypesTableColumn = ({ field = 'channel', title = i18n.t('common_599'), vm } = {}) => {
  315. return {
  316. title: i18n.t('common_599'),
  317. field: 'channel',
  318. minWidth: 120,
  319. slots: {
  320. default: ({ row }, h) => {
  321. const color = '#52c41a'
  322. const channel = row.channel || []
  323. const renderComponents = []
  324. channel.forEach((ctype) => {
  325. switch (ctype) {
  326. case 'webconsole':
  327. renderComponents.push(<icon class="mr-2" type='webconsole' style={{ color: color }} title={i18n.t('dictionary.webconsole')} />)
  328. break
  329. case 'email':
  330. renderComponents.push(<icon class='mr-2' type='email' style={{ color: color }} title={i18n.t('common.email')} />)
  331. break
  332. case 'mobile':
  333. renderComponents.push(<icon class='mr-2' type='mobile' style={{ color: color }} title={i18n.t('common.mobile')} />)
  334. break
  335. case 'dingtalk':
  336. renderComponents.push(<icon class='mr-2' type='dingtalk' style={{ color: color }} title={i18n.t('common.dingtalk')} />)
  337. break
  338. case 'feishu':
  339. renderComponents.push(<icon class='mr-2' type='feishu' style={{ color: color }} title={i18n.t('common.feishu')} />)
  340. break
  341. case 'workwx':
  342. renderComponents.push(<icon class='mr-2' type='workwx' style={{ color: color }} title={i18n.t('common.workwx')} />)
  343. break
  344. case 'alert_event':
  345. renderComponents.push(<icon class="mr-2" type="alert-event" style={{ color: color }} title={i18n.t('common.workflow.alert_event')} />)
  346. break
  347. case 'alert_ticket':
  348. renderComponents.push(<icon class="mr-2" type="navbar-process" style={{ color: color }} title={i18n.t('common.workflow.alert_ticket')} />)
  349. break
  350. default:
  351. break
  352. }
  353. })
  354. return renderComponents
  355. },
  356. },
  357. }
  358. }
  359. export const getValueWithUnit = (value = 0, unit = '') => {
  360. const currencyUnitList = Object.keys(currencyUnitMap)
  361. // 金额类型的单位
  362. for (let i = 0; i < currencyUnitList.length; i++) {
  363. if (unit.indexOf(currencyUnitList[i]) !== -1) {
  364. return `${currencyUnitMap[currencyUnitList[i]].sign} ${value}`
  365. }
  366. }
  367. return value
  368. }
  369. export const getStrategyInfo = (detail) => {
  370. let strategy = '-'
  371. const strategyConfig = {
  372. measurement: '',
  373. period: '', // 时间间隔 2h 14d
  374. metric: '', // 监控指标
  375. comparator: '', // > < within
  376. threshold: null, // 阈值
  377. unit: '', // 单位
  378. time_from: detail.time_from,
  379. }
  380. let measurement = detail.measurement_display_name || detail.measurement_desc || detail.measurement
  381. if (metric_zh[measurement]) measurement = metric_zh[measurement]
  382. strategyConfig.measurement = measurement
  383. let metric = _.get(detail, 'field_description.display_name') || detail.field_desc || detail.field
  384. if (metric) {
  385. metric = metric_zh[metric] || metric
  386. }
  387. strategyConfig.metric = metric
  388. const reduce = (alertStrategyMaps[detail.reduce || detail.reducer || 'avg']) || ''
  389. const alert_duration = detail.alert_duration ? i18n.t('monitor.list.duration.label', [detail.alert_duration]) : detail.alert_duration ? i18n.t('monitor.list.duration.label', [detail.alert_duration]) : ''
  390. let preiod = ((preiodMaps[detail.period] || {}).label) || detail.period
  391. let unit = detail.field_description ? _.get(detail, 'field_description.unit') : (R.type(detail.eval_data) === 'Array' ? (_.get(detail, 'eval_data[0].unit') || '') : '')
  392. let threshold = R.is(String, detail.threshold) ? { text: detail.threshold } : transformUnit(detail.threshold, unit)
  393. if (detail.measurement === 'cloudaccount_balance' && unit === 'RMB') {
  394. unit = ''
  395. if (detail.filters && detail.filters.length) {
  396. const targets = detail.filters.filter(item => item.key === 'currency')
  397. const cs = []
  398. targets.map(item => {
  399. if (item.value && !cs.includes(item.value)) {
  400. cs.push(item.value)
  401. }
  402. })
  403. if (cs.length === 1) {
  404. unit = currencyUnitMap[cs[0]]?.sign || ''
  405. }
  406. }
  407. threshold = R.is(String, detail.threshold) ? { text: detail.threshold } : unit ? { text: `${unit}${detail.threshold}` } : { text: detail.threshold }
  408. }
  409. let comparator = detail.comparator
  410. let txt = threshold.text
  411. if (detail.comparator === 'within_range' && detail.within_range) {
  412. comparator = ''
  413. txt = `[${detail.within_range[0]}${threshold.unit}, ${detail.within_range[1]}${threshold.unit}]`
  414. strategyConfig.within_range = detail.within_range
  415. }
  416. if (detail.comparator === 'within_range' && detail.threshold_range) {
  417. comparator = ''
  418. txt = i18n.t('monitor.threshold_range_in', [`${detail.threshold_range[0]}${unit || detail.unit || ''}`, `${detail.threshold_range[1]}${unit || detail.unit || ''}`])
  419. strategyConfig.within_range = detail.threshold_range
  420. }
  421. if (detail.comparator === 'outside_range' && detail.threshold_range) {
  422. comparator = ''
  423. txt = i18n.t('monitor.threshold_range_out', [`${detail.threshold_range[0]}${unit || detail.unit || ''}`, `${detail.threshold_range[1]}${unit || detail.unit || ''}`])
  424. strategyConfig.outside_range = detail.threshold_range
  425. }
  426. strategyConfig.comparator = detail.comparator
  427. strategyConfig.threshold = detail.threshold
  428. strategyConfig.unit = unit
  429. strategy = i18n.t('monitor.text_6', [measurement, metric, reduce, alert_duration, comparator, txt])
  430. if (detail.condition_type === 'nodata_query') { // 系统上报数据为空
  431. strategy = i18n.t('monitor.text_108', [alert_duration])
  432. }
  433. if (preiod) {
  434. preiod = preiod.replace(i18n.t('monitor.text_103'), '')
  435. // strategy += `${i18n.t('monitor.text_102', [preiod])}`
  436. strategyConfig.period = preiod
  437. }
  438. const silent_period = detail.silent_period
  439. if (silent_period) {
  440. let p = silent_period
  441. if (p.endsWith('m')) {
  442. const pi = parseInt(p.replace('m', ''))
  443. if (pi && pi >= 60 && pi % 60 === 0) {
  444. p = i18n.t('monitor.duration.silent.hour', [pi / 60])
  445. } else {
  446. p = i18n.t('monitor.duration.silent.minute', [p.replace('m', '')])
  447. }
  448. } else if (p.endsWith('h')) {
  449. p = i18n.t('monitor.duration.silent.hour', [p.replace('h', '')])
  450. }
  451. strategy += `${i18n.t('monitor.commonalerts.list.silent', [p])}`
  452. strategyConfig.silent_period = silent_period
  453. }
  454. return {
  455. strategy,
  456. strategyConfig,
  457. }
  458. }