index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <template>
  2. <a-row v-loading="loading">
  3. <a-col :md="{ span: 24 }" :lg="{ span: 22 }" :xl="{ span: 16 }" :xxl="{ span: 11 }" class="mb-5">
  4. <alert-form
  5. v-if="!isUpdate || (loaded && !loading)"
  6. ref="alertFormRef"
  7. :alertData="alertData"
  8. :threshold.sync="threshold"
  9. :timeRangeParams="timeRangeParams"
  10. :isUpdate="isUpdate"
  11. @refresh="refresh"
  12. @resetChart="resetChart"
  13. @mertricItemChange="mertricItemChange"
  14. @scopeChange="scopeChange" />
  15. </a-col>
  16. <a-col class="line mb-5" :md="{ span: 24 }" :lg="{ span: 22 }" :xl="{ span: 16 }" :xxl="{ span: 12, offset: 1 }">
  17. <monitor-header
  18. class="mb-4"
  19. :timeOpts="timeOpts"
  20. :time.sync="time"
  21. :showTimegroup="false"
  22. :showGroupFunc="false"
  23. @refresh="fetchData">
  24. <template v-slot:radio-button-append>
  25. <custom-date :time.sync="time" :customTime.sync="customTime" :showCustomTimeText="time==='custom'" />
  26. </template>
  27. </monitor-header>
  28. <div>
  29. <template v-if="chartLoading"><loader loading /></template>
  30. <monitor-line v-else class="mb-3"
  31. :series="series"
  32. :timeFormatStr="timeFormatStr"
  33. :lineChartOptions="lineChartOptions"
  34. :description="lineDescription"
  35. :threshold="threshold"
  36. :pager="pager"
  37. :key="pager.total"
  38. @pageChange="pageChange" />
  39. </div>
  40. </a-col>
  41. </a-row>
  42. </template>
  43. <script>
  44. import * as R from 'ramda'
  45. import _ from 'lodash'
  46. import MonitorLine from '@Monitor/sections/MonitorLine'
  47. import CustomDate from '@/sections/CustomDate'
  48. import MonitorHeader from '@/sections/Monitor/Header'
  49. import { getSignature } from '@/utils/crypto'
  50. import { timeOpts } from '@/constants/monitor'
  51. import { MONITOR_MAX_POINTERS } from '@Monitor/constants'
  52. import AlertForm from './form'
  53. export default {
  54. name: 'Commonalert',
  55. components: {
  56. MonitorHeader,
  57. MonitorLine,
  58. AlertForm,
  59. CustomDate,
  60. },
  61. props: {
  62. isUpdate: {
  63. type: Boolean,
  64. default: false,
  65. },
  66. commonalertId: {
  67. type: String,
  68. },
  69. },
  70. data () {
  71. return {
  72. series: [],
  73. timeOpts,
  74. time: '1h',
  75. customTime: null,
  76. formmMetric: null,
  77. threshold: undefined,
  78. alertData: null,
  79. loading: false,
  80. loaded: false,
  81. chartLoading: false,
  82. pager: { seriesIndex: 0, total: 0, page: 1, limit: 10 },
  83. lineDescription: {},
  84. scopeParams: {},
  85. }
  86. },
  87. computed: {
  88. timeFormatStr () {
  89. const defaultTimeFormat = 'YYYY-MM-DD HH:mm'
  90. return _.get(this.timeOpts, '[this.time].timeFormat') || defaultTimeFormat
  91. },
  92. lineChartOptions () {
  93. if (!this.threshold) {
  94. return {
  95. legend: {
  96. show: false,
  97. },
  98. }
  99. }
  100. return {
  101. sampling: 'average',
  102. animation: false,
  103. legend: {
  104. show: false,
  105. },
  106. series: [{
  107. markLine: {
  108. lineStyle: {
  109. color: '#f5222d',
  110. },
  111. data: [{
  112. name: this.$t('monitor.text00014'),
  113. yAxis: this.threshold,
  114. label: {
  115. position: 'insideEndBottom',
  116. },
  117. }],
  118. },
  119. }],
  120. }
  121. },
  122. timeRangeParams () {
  123. const params = {}
  124. if (this.time === 'custom') { // 自定义时间
  125. if (this.customTime && this.customTime.from && this.customTime.to) {
  126. params.from = this.customTime.from
  127. params.to = this.customTime.to
  128. }
  129. } else {
  130. params.from = this.time
  131. }
  132. return params
  133. },
  134. timeGroup () {
  135. let tg = '1m'
  136. let diffHour = 1
  137. const noNumberReg = /\D+/g
  138. if (this.time === 'custom') {
  139. diffHour = this.customTime.from.replace(noNumberReg, '') - this.customTime.to.replace(noNumberReg, '')
  140. } else {
  141. diffHour = this.time.replace(noNumberReg, '')
  142. }
  143. const diff = diffHour * 60 // 变分钟
  144. tg = `${diff / MONITOR_MAX_POINTERS}m`
  145. return tg
  146. },
  147. },
  148. watch: {
  149. time () {
  150. this.fetchData()
  151. },
  152. customTime () {
  153. this.fetchData()
  154. },
  155. scopeParams () {
  156. this.fetchData()
  157. },
  158. },
  159. created () {
  160. if (this.isUpdate) {
  161. this.fetchCommonalert().then((res) => {
  162. if (this.alertData && this.alertData.common_alert_metric_details && this.alertData.common_alert_metric_details.length > 0) {
  163. const desc = this.alertData.common_alert_metric_details[0].field_description
  164. this.lineDescription.isUpdate = true
  165. this.lineDescription.metric_res_type = this.alertData.common_alert_metric_details[0].res_type
  166. if (this.alertData.common_alert_metric_details[0].measurement === 'cloudaccount_balance') {
  167. desc.unit = 'currency'
  168. }
  169. this.$set(this.lineDescription, 'description', desc || {})
  170. }
  171. })
  172. }
  173. },
  174. methods: {
  175. async fetchCommonalert () {
  176. try {
  177. this.loading = true
  178. const { data } = await new this.$Manager('commonalerts', 'v1')
  179. .get({
  180. id: this.commonalertId,
  181. params: { scope: this.$store.getters.scope },
  182. })
  183. this.alertData = data
  184. const time = _.get(this.alertData, 'settings.conditions[0].query.from')
  185. if (~time.indexOf('now-')) {
  186. this.time = 'custom'
  187. this.customTime = {
  188. from: time,
  189. to: _.get(this.alertData, 'settings.conditions[0].query.to') || 'now',
  190. }
  191. } else {
  192. this.time = this.timeOpts[time] ? time : '1h'
  193. }
  194. this.loading = false
  195. } catch (error) {
  196. this.loading = false
  197. throw error
  198. } finally {
  199. this.loaded = true
  200. }
  201. },
  202. cancel () {
  203. this.$router.push('/commonalerts')
  204. },
  205. reset () {
  206. this.$refs.alertFormRef.form.fc.resetFields()
  207. },
  208. resetChart () {
  209. this.series = []
  210. },
  211. scopeChange (scopeParams) {
  212. this.scopeParams = scopeParams
  213. },
  214. async submit () {
  215. try {
  216. const { fd, monitorParams } = await this.$refs.alertFormRef.validate()
  217. const data = {
  218. scope: fd.scope,
  219. // interval: this.timeGroup,
  220. alert_duration: fd.alert_duration,
  221. generate_name: fd.name,
  222. description: fd.description,
  223. period: fd.period,
  224. channel: fd.channel,
  225. recipients: fd.recipients,
  226. alert_type: 'normal', // normal(自定义) system(系统内置)
  227. level: fd.level,
  228. metric_query: [{
  229. model: monitorParams,
  230. reduce: fd.reduce,
  231. comparator: fd.comparator,
  232. threshold: fd.threshold,
  233. }],
  234. }
  235. if (fd.silent_period) {
  236. data.silent_period = fd.silent_period
  237. }
  238. if (fd.comparator === 'nodata') {
  239. data.metric_query[0].condition_type = 'nodata_query'
  240. }
  241. if (fd.channel) {
  242. data.channel = fd.channel
  243. } else {
  244. data.channel = []
  245. }
  246. if (fd.robot_ids) {
  247. data.robot_ids = fd.robot_ids
  248. } else {
  249. data.robot_ids = []
  250. }
  251. if (fd.enabled_contact_types) {
  252. data.channel.push(...fd.enabled_contact_types)
  253. }
  254. if (fd.roles) {
  255. data.roles = fd.roles
  256. }
  257. if (fd.domain || fd.domain_id) data.domain_id = (fd.domain || fd.domain_id)
  258. if (fd.project) data.project_id = fd.project
  259. const periodNum = parseInt(fd.period)
  260. const unit = fd.period.split('').pop()
  261. if (unit === 'm' && periodNum * fd.alert_duration < 10) {
  262. data.from = '10m'
  263. } else {
  264. data.from = (periodNum * fd.alert_duration) + unit
  265. }
  266. this.$emit('update:loading', true)
  267. if (this.isUpdate) {
  268. await new this.$Manager('commonalerts', 'v1').update({ id: this.commonalertId, data })
  269. } else {
  270. await new this.$Manager('commonalerts', 'v1').create({ data })
  271. }
  272. this.$emit('update:loading', false)
  273. this.$message.success(this.$t('common.success'))
  274. this.cancel()
  275. } catch (error) {
  276. this.$emit('update:loading', false)
  277. throw error
  278. }
  279. },
  280. async pageChange (pager) {
  281. await this._refresh(pager.limit, (pager.page - 1) * pager.limit)
  282. },
  283. async _refresh (limit, offset) {
  284. try {
  285. await this.fetchData(limit, offset)
  286. } catch (error) {
  287. this.formmMetric = { model: {} }
  288. throw error
  289. }
  290. },
  291. async refresh (params) {
  292. this.formmMetric = R.is(Object, params) ? [{ model: params }] : null
  293. await this._refresh(10, 0)
  294. },
  295. async fetchData (limit = this.pager.limit, offset = 0) {
  296. try {
  297. const data = {
  298. metric_query: this.formmMetric,
  299. interval: this.timeGroup,
  300. slimit: limit,
  301. soffset: offset,
  302. ...this.scopeParams,
  303. }
  304. if (this.time === 'custom') { // 自定义时间
  305. if (this.customTime && this.customTime.from && this.customTime.to) {
  306. data.from = this.customTime.from
  307. data.to = this.customTime.to
  308. }
  309. } else {
  310. data.from = this.time
  311. }
  312. if (!data.metric_query || !data.from || !_.get(data.metric_query, '[0].model.measurement') || !_.get(data.metric_query, '[0].model.select')) return
  313. this.chartLoading = true
  314. data.signature = getSignature(data)
  315. const { data: { series = [], series_total = 0 } } = await new this.$Manager('unifiedmonitors', 'v1').performAction({ id: 'query', action: '', data })
  316. this.series = []
  317. this.$nextTick(_ => {
  318. if (this.lineDescription.id === 'balance' && this.lineDescription.metric_res_type === 'cloudaccount') {
  319. const currencyList = []
  320. series.map(item => {
  321. const { tags = {} } = item
  322. const { currency = 'CNY' } = tags
  323. if (!currencyList.includes(currency)) {
  324. currencyList.push(currency)
  325. }
  326. })
  327. if (currencyList.length !== 1 && this.lineDescription.description) {
  328. this.lineDescription.description.unit = ''
  329. }
  330. if (currencyList.length === 1 && this.lineDescription.description) {
  331. this.lineDescription.description.unit = 'currency'
  332. }
  333. }
  334. this.series = series
  335. this.pager = { seriesIndex: 0, total: series_total, page: 1 + offset / limit, limit: limit }
  336. this.chartLoading = false
  337. })
  338. } catch (error) {
  339. this.chartLoading = false
  340. throw error
  341. }
  342. },
  343. mertricItemChange (val) {
  344. const t = +this.time.replace(/\D+/, '')
  345. const existBalance = this.lineDescription.id === 'balance'
  346. if (!existBalance && val.id === 'balance' && ~this.time.indexOf('h') && t < 3) { // 时间都是转换成h了,这里仅需要对比h即可
  347. this.time = '72h'
  348. this.$message.warning(this.$t('common_562', [val.label]))
  349. }
  350. if (this.lineDescription && this.lineDescription.isUpdate) {
  351. delete this.lineDescription.isUpdate
  352. Object.assign(this.lineDescription, val)
  353. } else {
  354. this.lineDescription = val
  355. }
  356. },
  357. },
  358. }
  359. </script>