index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <template>
  2. <div class="h-100 position-relative">
  3. <div class="dashboard-card-wrap">
  4. <div class="dashboard-card-header">
  5. <div class="dashboard-card-header-left">{{ form.fd.name }}<a-icon class="ml-2" type="loading" v-if="loading" /></div>
  6. <div class="dashboard-card-header-right">
  7. <slot name="actions" :handle-edit="handleEdit" />
  8. <router-link v-if="!edit" to="/monitoroverview" class="ml-2">
  9. <icon type="arrow-right" style="font-size:18px" />
  10. </router-link>
  11. </div>
  12. </div>
  13. <div class="dashboard-card-body flex-column justify-content-center">
  14. <template v-if="chartOptions.xAxis.data.length">
  15. <div class="flex-fill position-relative">
  16. <div class="dashboard-fco-wrap">
  17. <e-chart :options="chartOptions" style="height: 100%; width: 100%;" autoresize />
  18. </div>
  19. </div>
  20. </template>
  21. <template v-else>
  22. <a-empty />
  23. </template>
  24. </div>
  25. </div>
  26. <base-drawer :visible.sync="visible" :title="$t('dashboard.text_5')" @ok="handleSubmit">
  27. <a-form
  28. hideRequiredMark
  29. :form="form.fc"
  30. v-bind="formItemLayout">
  31. <a-form-item :label="$t('dashboard.text_6')">
  32. <a-input v-decorator="decorators.name" />
  33. </a-form-item>
  34. </a-form>
  35. </base-drawer>
  36. </div>
  37. </template>
  38. <script>
  39. // import i18n from 'vue-i18n'
  40. import * as R from 'ramda'
  41. import { mapGetters } from 'vuex'
  42. import { chartColors } from '@/constants'
  43. import BaseDrawer from '@Dashboard/components/BaseDrawer'
  44. import { resolveValueChangeField } from '@/utils/common/ant'
  45. import { getCurrency } from '@/utils/common/cookie'
  46. import { currencyUnitMap } from '@/constants/currency'
  47. import { getSignature } from '@/utils/crypto'
  48. // import OverviewLine from '@Monitor/components/MonitorCard/sections/chart/line'
  49. export default {
  50. name: 'AlertsTrend',
  51. components: {
  52. BaseDrawer,
  53. },
  54. props: {
  55. options: {
  56. type: Object,
  57. required: true,
  58. },
  59. params: Object,
  60. edit: Boolean,
  61. dataRangeParams: {
  62. type: Object,
  63. },
  64. },
  65. data () {
  66. const initialNameValue = (this.params && this.params.name) || this.$t('dashboard.alerts_trend')
  67. return {
  68. data: [],
  69. visible: false,
  70. loading: false,
  71. seriesData: [],
  72. form: {
  73. fc: this.$form.createForm(this, {
  74. onValuesChange: (props, values) => {
  75. const newField = resolveValueChangeField(values)
  76. R.forEachObjIndexed((item, key) => {
  77. this.$set(this.form.fd, key, item)
  78. }, newField)
  79. },
  80. }),
  81. fd: {
  82. name: initialNameValue,
  83. },
  84. },
  85. decorators: {
  86. name: [
  87. 'name',
  88. {
  89. initialValue: initialNameValue,
  90. rules: [
  91. { required: true, message: this.$t('dashboard.text_8') },
  92. ],
  93. },
  94. ],
  95. },
  96. formItemLayout: {
  97. wrapperCol: {
  98. span: 18,
  99. },
  100. labelCol: {
  101. span: 6,
  102. },
  103. },
  104. chartOptions: {
  105. tooltip: {
  106. show: true,
  107. trigger: 'axis',
  108. axisPointer: {
  109. type: 'none',
  110. },
  111. },
  112. grid: {
  113. left: 50,
  114. bottom: 30,
  115. top: 30,
  116. right: 20,
  117. width: 'auto',
  118. },
  119. xAxis: {
  120. type: 'category',
  121. data: [],
  122. },
  123. yAxis: {
  124. type: 'value',
  125. },
  126. series: [],
  127. color: chartColors,
  128. },
  129. }
  130. },
  131. computed: {
  132. ...mapGetters(['scope', 'capability', 'isAdminMode', 'isDomainMode', 'isProjectMode', 'userInfo']),
  133. newCurrencys () {
  134. return this.CURRENCYS.filter(v => {
  135. return this.currencyOpts.find(obj => obj.item_id === v.key)
  136. })
  137. },
  138. currencySign () {
  139. return currencyUnitMap[this.form.fd.currency]?.sign || currencyUnitMap.CNY.sign
  140. },
  141. extraParams () {
  142. const ret = {}
  143. if (this.scope === 'domain') ret.domain_id = this.userInfo?.projectDomainId
  144. if (this.scope === 'project') ret.project_id = this.userInfo?.projectId
  145. return ret
  146. },
  147. },
  148. watch: {
  149. 'form.fd' (val) {
  150. this.fetchData()
  151. for (const key in this.decorators) {
  152. let config = this.decorators[key][1] || {}
  153. config = {
  154. ...config,
  155. initialValue: val[key],
  156. }
  157. if (key === 'currency' && !config.initialValue) {
  158. config.initialValue = (this.params && this.params.currency) || getCurrency()
  159. }
  160. this.decorators[key][1] = config
  161. }
  162. },
  163. 'dataRangeParams.scope': {
  164. handler (val) {
  165. this.fetchData()
  166. },
  167. immediate: true,
  168. },
  169. 'dataRangeParams.domain': {
  170. handler (val) {
  171. this.fetchData()
  172. },
  173. immediate: true,
  174. },
  175. 'dataRangeParams.project': {
  176. handler (val) {
  177. this.fetchData()
  178. },
  179. immediate: true,
  180. },
  181. },
  182. created () {
  183. const values = { ...this.form.fd }
  184. this.$emit('update', this.options.i, values)
  185. this.fetchData()
  186. },
  187. methods: {
  188. refresh () {
  189. return this.fetchData()
  190. },
  191. getDate () {
  192. const end = this.$moment()
  193. const start = this.$moment().subtract(30, 'days')
  194. return {
  195. start_date: start.format('YYYY-MM-DD') + 'TZ',
  196. end_date: end.format('YYYY-MM-DD') + 'TZ',
  197. // start_date: '2021-05-01TZ',
  198. // end_date: '2021-05-31TZ',
  199. data_type: 'day',
  200. }
  201. },
  202. commonParams () {
  203. const extendParams = {
  204. scope: this.scope,
  205. }
  206. Object.assign(extendParams, this.extraParams)
  207. return extendParams
  208. },
  209. chartQueryData () {
  210. const extendParams = this.commonParams()
  211. const ret = {
  212. from: '720h',
  213. interval: '24h',
  214. metric_query: [
  215. {
  216. model: {
  217. database: 'monitor',
  218. measurement: 'alert_record_history',
  219. select: [
  220. [{ params: ['res_num'], type: 'field' }, { type: 'sum' }],
  221. ],
  222. group_by: [{
  223. type: 'tag',
  224. params: ['res_type'],
  225. }],
  226. },
  227. },
  228. ],
  229. unit: true,
  230. ...extendParams,
  231. }
  232. const tags = []
  233. if (this.isAdminMode) {
  234. if (this.dataRangeParams?.scope === 'domain' && this.dataRangeParams?.domain) {
  235. tags.push({
  236. key: 'domain_id',
  237. operator: '=',
  238. value: this.dataRangeParams?.domain,
  239. })
  240. }
  241. if (this.dataRangeParams?.scope === 'project' && this.dataRangeParams?.project) {
  242. tags.push({
  243. key: 'project_id',
  244. operator: '=',
  245. value: this.dataRangeParams?.project,
  246. })
  247. }
  248. }
  249. if (this.isDomainMode) {
  250. if (this.dataRangeParams?.scope === 'project' && this.dataRangeParams?.project) {
  251. tags.push({
  252. key: 'project_id',
  253. operator: '=',
  254. value: this.dataRangeParams?.project,
  255. })
  256. }
  257. }
  258. if (tags.length) {
  259. ret.metric_query[0].model.tags = tags
  260. }
  261. return ret
  262. },
  263. tabChartData (rawDatas) {
  264. const chartData = {
  265. columns: [],
  266. rows: [],
  267. }
  268. const list = []
  269. const dateList = []
  270. if (rawDatas && rawDatas.length > 0) {
  271. chartData.columns = []
  272. const _temp = {}
  273. rawDatas.map((item) => {
  274. const points = item.points
  275. if (!item.points) {
  276. return
  277. }
  278. const columnName = item.raw_name ? this.$t(`dictionary.${item.raw_name}`) : this.$t('monitor.overview_alert.undefined')
  279. chartData.columns.push(columnName)
  280. let series = points.map((item) => {
  281. return { name: item[1], value: item[0] }
  282. })
  283. series = series.sort((a, b) => {
  284. return a.name - b.name
  285. })
  286. for (const i in series) {
  287. const d = new Date(series[i].name)
  288. const rn = `${d.getMonth() + 1}-${d.getDate()}`
  289. if (_temp.hasOwnProperty(rn)) {
  290. _temp[rn][columnName] = series[i].value
  291. } else {
  292. _temp[rn] = { name: rn }
  293. _temp[rn][columnName] = series[i].value
  294. }
  295. }
  296. })
  297. // base data
  298. const initData = {}
  299. chartData.columns.map((item) => { initData[item] = 0 })
  300. // fill data
  301. const rows = []
  302. const now = new Date()
  303. for (let i = 30; i > 0; i--) {
  304. const cur = new Date(now - i * 24 * 60 * 60 * 1000)
  305. const rn = `${cur.getMonth() + 1}-${cur.getDate()}`
  306. dateList.push(rn)
  307. if (_temp.hasOwnProperty(rn)) {
  308. rows.push(Object.assign({}, initData, _temp[rn]))
  309. } else {
  310. rows.push(Object.assign({}, { name: rn }, initData))
  311. }
  312. }
  313. // 拼接数据
  314. chartData.columns.map((item, index) => {
  315. list.push({
  316. type: 'bar',
  317. name: item,
  318. stack: 'total',
  319. data: [],
  320. })
  321. rows.map(item2 => {
  322. list[index].data.push(item2[item])
  323. })
  324. })
  325. }
  326. return { dateList, list }
  327. },
  328. async fetchData () {
  329. this.loading = true
  330. try {
  331. var queryData = this.chartQueryData()
  332. queryData.signature = getSignature(queryData)
  333. const { data = {} } = await new this.$Manager('unifiedmonitors', 'v1').performAction({ id: 'query', action: '', data: queryData, params: { $t: new Date().getSeconds() } })
  334. const { series = [] } = data
  335. const newData = this.tabChartData(series)
  336. this.chartOptions.xAxis.data = newData.dateList
  337. this.chartOptions.series = newData.list
  338. } finally {
  339. this.loading = false
  340. }
  341. },
  342. handleEdit () {
  343. this.visible = true
  344. },
  345. async handleSubmit () {
  346. try {
  347. const values = await this.form.fc.validateFields()
  348. this.form.fd = values
  349. const updateValues = { ...values }
  350. this.$emit('update', this.options.i, updateValues)
  351. this.visible = false
  352. } catch (error) {
  353. throw error
  354. }
  355. },
  356. },
  357. }
  358. </script>