index.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  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">
  6. {{ form.fd.name }}<a-icon class="ml-2" type="loading" v-if="loading" />
  7. <span v-if="isResDeny" class="ml-2"><a-icon class="warning-color mr-1" type="warning" />{{ $t('common.permission.403') }}</span>
  8. </div>
  9. <div class="dashboard-card-header-right">
  10. <slot name="actions" :handle-edit="handleEdit" />
  11. <a class="ml-2" v-if="!edit" @click="goPage">
  12. <icon type="arrow-right" style="font-size:18px" />
  13. </a>
  14. </div>
  15. </div>
  16. <div class="dashboard-card-body flex-column justify-content-center">
  17. <template v-if="seriesData && seriesData.length">
  18. <div class="flex-fill position-relative">
  19. <div class="dashboard-fco-wrap">
  20. <template v-for="item in seriesData">
  21. <div class="mt-2 mb-2" :key="item.name">
  22. <div class="d-flex mini-text">
  23. <div class="flex-fill text-truncate" :title="item.name">{{ item.name }}</div>
  24. <div class="flex-grow-0 flex-shrink-0 text-color-help ml-2">{{ getLabel(item.value) }}</div>
  25. </div>
  26. <a-progress :percent="getPercent(item.value)" :showInfo="false" status="normal" :strokeWidth="4" stroke-color="#ADE4B6" />
  27. </div>
  28. </template>
  29. </div>
  30. </div>
  31. </template>
  32. <template v-else>
  33. <data-empty />
  34. </template>
  35. </div>
  36. </div>
  37. <base-drawer :visible.sync="visible" :title="$t('dashboard.text_5')" @ok="handleSubmit">
  38. <a-form
  39. hideRequiredMark
  40. :form="form.fc"
  41. v-bind="formItemLayout">
  42. <a-form-item :label="$t('dashboard.text_6')">
  43. <a-input v-decorator="decorators.name" />
  44. </a-form-item>
  45. <a-form-item :label="$t('dashboard.text_56')">
  46. <a-radio-group v-decorator="decorators.resType" @change="handleResTypeChange">
  47. <a-radio-button value="server">{{$t('dashboard.text_57')}}</a-radio-button>
  48. <a-radio-button value="host">{{$t('dashboard.text_58')}}</a-radio-button>
  49. </a-radio-group>
  50. </a-form-item>
  51. <a-form-item :label="$t('dashboard.text_55')">
  52. <a-select v-decorator="decorators.brand" allowClear :placeholder="$t('dashboard.text_99')" mode="multiple">
  53. <template v-for="item of brands">
  54. <a-select-option :key="item.key" :value="item.key">{{ item.label }}</a-select-option>
  55. </template>
  56. </a-select>
  57. </a-form-item>
  58. <a-form-item :label="$t('dashboard.text_20')">
  59. <a-select v-decorator="decorators.usage">
  60. <template v-for="item of usageOptions[form.fd.resType]">
  61. <a-select-option :key="item.key" :value="item.key">{{ item.label }}</a-select-option>
  62. </template>
  63. </a-select>
  64. <div slot="extra" v-if="showDocsLink()">
  65. <i18n path="metricConfig.create_form.metric_extra">
  66. <template #link>
  67. <help-link :href="metricDoc">{{$t('metricConfig.create_form.usage_link')}}</help-link>
  68. </template>
  69. </i18n>
  70. </div>
  71. </a-form-item>
  72. <a-form-item :label="$t('monitor.overview.aggregate')">
  73. <a-select v-decorator="decorators.dimensionId">
  74. <a-select-option v-for="item in dimentions" :value="item.id" :key="item.id">{{ item.label }}</a-select-option>
  75. </a-select>
  76. </a-form-item>
  77. <a-form-item label="TOP/Bottom">
  78. <a-select v-decorator="decorators.order">
  79. <a-select-option value="TOP">TOP</a-select-option>
  80. <a-select-option value="BOTTOM">BOTTOM</a-select-option>
  81. </a-select>
  82. </a-form-item>
  83. <a-form-item :label="$t('dashboard.text_59')">
  84. <a-input-number :min="1" :max="100" v-decorator="decorators.limit" />
  85. </a-form-item>
  86. <a-form-item :label="$t('dashboard.text_60')">
  87. <a-select v-decorator="decorators.time">
  88. <template v-for="item of timeOptions">
  89. <a-select-option :key="item.key" :value="item.key">{{ item.label }}</a-select-option>
  90. </template>
  91. </a-select>
  92. </a-form-item>
  93. </a-form>
  94. </base-drawer>
  95. </div>
  96. </template>
  97. <script>
  98. import * as R from 'ramda'
  99. import { mapGetters } from 'vuex'
  100. import BaseDrawer from '@Dashboard/components/BaseDrawer'
  101. import { load } from '@Dashboard/utils/cache'
  102. import { resolveValueChangeField } from '@/utils/common/ant'
  103. import { findPlatform, typeClouds } from '@/utils/common/hypervisor'
  104. import { getRequestT } from '@/utils/utils'
  105. import { hasPermission } from '@/utils/auth'
  106. import { getSignature } from '@/utils/crypto'
  107. import { getMetricDocs } from '@Dashboard/constants'
  108. import setting from '@/config/setting'
  109. import { showDocsLink } from '@/constants/docs'
  110. import { usageConfig, serverUsageOptions, hostUsageOptions } from './constants'
  111. export default {
  112. name: 'Top5',
  113. components: {
  114. BaseDrawer,
  115. },
  116. props: {
  117. options: {
  118. type: Object,
  119. required: true,
  120. },
  121. params: Object,
  122. edit: Boolean,
  123. dataRangeParams: {
  124. type: Object,
  125. },
  126. },
  127. data () {
  128. const initialBrandValue = (this.params && this.params.brand && R.split(',', this.params.brand)) || []
  129. const initialResTypeValue = (this.params && this.params.resType) || 'server'
  130. const initialDimensionId = (this.params && this.params.dimensionId) || (initialResTypeValue === 'server' ? 'vm_id' : 'host_id')
  131. let initialUsage = this.params && this.params.usage
  132. if (!initialUsage) {
  133. if (initialResTypeValue === 'server') {
  134. initialUsage = serverUsageOptions[0].key
  135. }
  136. if (initialResTypeValue === 'host') {
  137. initialUsage = hostUsageOptions[0].key
  138. }
  139. }
  140. const initialNameValue = (this.params && this.params.name) || `${serverUsageOptions[0].label}TOP5`
  141. const initialOrderValue = (this.params && this.params.order) || 'TOP'
  142. const initialLimit = (this.params && this.params.limit) || 5
  143. const initialTime = (this.params && this.params.time) || 24 * 60
  144. return {
  145. showDocsLink,
  146. data: [],
  147. visible: false,
  148. loading: false,
  149. seriesData: [],
  150. form: {
  151. fc: this.$form.createForm(this, {
  152. onValuesChange: (props, values) => {
  153. const newField = resolveValueChangeField(values)
  154. R.forEachObjIndexed((item, key) => {
  155. this.$set(this.form.fd, key, item)
  156. }, newField)
  157. },
  158. }),
  159. fd: {
  160. name: initialNameValue,
  161. brand: initialBrandValue,
  162. resType: initialResTypeValue,
  163. usage: initialUsage,
  164. order: initialOrderValue,
  165. limit: initialLimit,
  166. time: initialTime,
  167. dimensionId: initialDimensionId,
  168. },
  169. },
  170. usageOptions: {
  171. server: serverUsageOptions,
  172. host: hostUsageOptions,
  173. },
  174. timeOptions: [
  175. { label: this.$t('timeselect.hour', [1]), key: 60 * 60 },
  176. { label: this.$t('timeselect.hours', [6]), key: 360 * 60 },
  177. { label: this.$t('timeselect.hours', [12]), key: 12 * 60 * 60 },
  178. { label: this.$t('timeselect.days', [1]), key: 24 * 60 * 60 },
  179. { label: this.$t('timeselect.days', [7]), key: 7 * 24 * 60 * 60 },
  180. { label: this.$t('timeselect.days', [14]), key: 14 * 24 * 60 * 60 },
  181. { label: this.$t('timeselect.months', [1]), key: 30 * 24 * 60 * 60 },
  182. ],
  183. decorators: {
  184. name: [
  185. 'name',
  186. {
  187. initialValue: initialNameValue,
  188. rules: [
  189. { required: true, message: this.$t('dashboard.text_8') },
  190. ],
  191. },
  192. ],
  193. brand: [
  194. 'brand',
  195. {
  196. initialValue: initialBrandValue,
  197. // rules: [
  198. // { required: true, message: this.$t('dashboard.text_72') },
  199. // ],
  200. },
  201. ],
  202. resType: [
  203. 'resType',
  204. {
  205. initialValue: initialResTypeValue,
  206. rules: [
  207. { required: true, message: this.$t('dashboard.text_73') },
  208. ],
  209. },
  210. ],
  211. usage: [
  212. 'usage',
  213. {
  214. initialValue: initialUsage,
  215. rules: [
  216. { required: true, message: this.$t('dashboard.text_22') },
  217. ],
  218. },
  219. ],
  220. order: [
  221. 'order',
  222. {
  223. initialValue: initialOrderValue,
  224. rules: [
  225. { required: true, message: this.$t('dashboard.text_74') },
  226. ],
  227. },
  228. ],
  229. limit: [
  230. 'limit',
  231. {
  232. initialValue: initialLimit,
  233. rules: [
  234. { required: true, message: this.$t('dashboard.text_75') },
  235. ],
  236. },
  237. ],
  238. time: [
  239. 'time',
  240. {
  241. initialValue: initialTime,
  242. rules: [
  243. { required: true, message: this.$t('dashboard.text_76') },
  244. ],
  245. },
  246. ],
  247. dimensionId: [
  248. 'dimensionId',
  249. {
  250. initialValue: initialDimensionId,
  251. rules: [{ required: true, message: '' }],
  252. },
  253. ],
  254. },
  255. formItemLayout: {
  256. wrapperCol: {
  257. span: 18,
  258. },
  259. labelCol: {
  260. span: 6,
  261. },
  262. },
  263. metricDoc: getMetricDocs(this.$store.getters.scope),
  264. }
  265. },
  266. computed: {
  267. ...mapGetters(['scope', 'capability', 'isAdminMode', 'isDomainMode', 'isProjectMode', 'userInfo', 'permission']),
  268. brandEnvs () {
  269. const brand = this.form.fd.brand
  270. return brand.map(key => findPlatform(key))
  271. },
  272. maxSeriesData () {
  273. const dataList = this.seriesData.map(item => Number(item.value))
  274. const maxData = Math.max.apply(null, dataList)
  275. return maxData > 100 ? maxData : 100
  276. },
  277. brands () {
  278. const isServer = this.form.fd.resType === 'server'
  279. const brands = (this.capability.brands || []).map(item => {
  280. const opt = typeClouds.brandMap[item]
  281. if (opt) {
  282. return {
  283. label: opt.label,
  284. key: opt.key,
  285. }
  286. }
  287. return {
  288. label: item,
  289. key: item,
  290. }
  291. })
  292. if (isServer) {
  293. return brands.filter(item => {
  294. const env = findPlatform(item.key)
  295. return env !== 'private' || env !== 'idc'
  296. })
  297. }
  298. return brands.filter(item => {
  299. const env = findPlatform(item.key)
  300. return env === 'private' || env === 'idc'
  301. })
  302. },
  303. dimentions () {
  304. const curScope = this.scope
  305. const scopeLevel = Math.max(['project', 'domain', 'system'].indexOf(curScope) + 1, 0)
  306. const ret = []
  307. if (this.form.fd.resType === 'server') {
  308. ret.push({ scope: curScope, id: 'vm_id', name: 'vm_name', label: this.$t('cloudenv.text_99') })
  309. } else {
  310. ret.push({ scope: curScope, id: 'host_id', name: 'host', label: this.$t('cloudenv.text_101') })
  311. }
  312. scopeLevel > 2 && ret.push({
  313. scope: curScope,
  314. id: 'domain_id',
  315. name: 'project_domain',
  316. label: this.$t('dictionary.domain'),
  317. })
  318. scopeLevel > 1 && this.form.fd.resType === 'server' && ret.push({
  319. scope: curScope,
  320. id: 'tenant_id',
  321. name: 'tenant',
  322. label: this.$t('dictionary.project'),
  323. })
  324. ret.push({ scope: curScope, id: 'brand', name: 'brand', label: this.$t('common.brands') })
  325. ret.push({ scope: curScope, id: 'cloudregion_id', name: 'cloudregion', label: this.$t('cloudenv.text_10') })
  326. ret.push({ scope: curScope, id: 'zone_id', name: 'zone', label: this.$t('cloudenv.text_11') })
  327. return ret
  328. },
  329. dimension () {
  330. return this.dimentions.filter((d) => { return d.id === this.form.fd.dimensionId })[0]
  331. },
  332. isResDeny () {
  333. const usage = this.params?.usage || ''
  334. if (usage.endsWith('vm_cpu') || usage.endsWith('vm_mem') || usage.endsWith('vm_disk')) {
  335. return !hasPermission({ key: 'servers_list', permissionData: this.permission })
  336. }
  337. return !hasPermission({ key: 'compute_usages_get' })
  338. },
  339. },
  340. watch: {
  341. 'form.fd' (val) {
  342. const newVal = { ...val }
  343. for (const key in newVal) {
  344. this.decorators[key][1].initialValue = newVal[key]
  345. }
  346. this.form.fc.setFieldsValue(newVal)
  347. this.$nextTick(() => {
  348. this.fetchData()
  349. })
  350. // this.changeName(val)
  351. },
  352. 'form.fd.resType' (val) {
  353. if (this.dimentions.filter(item => item.id === this.form.fd.dimensionId).length === 0) {
  354. this.form.fc.setFieldsValue({
  355. dimensionId: this.dimentions[0].id,
  356. })
  357. }
  358. this.changeName(val, this.form.fd.usage)
  359. },
  360. 'form.fd.usage': {
  361. handler (val) {
  362. this.changeName(this.form.fd.resType, val)
  363. },
  364. },
  365. 'dataRangeParams.scope': {
  366. handler (val) {
  367. this.fetchData()
  368. },
  369. immediate: true,
  370. },
  371. 'dataRangeParams.domain': {
  372. handler (val) {
  373. this.fetchData()
  374. },
  375. immediate: true,
  376. },
  377. 'dataRangeParams.project': {
  378. handler (val) {
  379. this.fetchData()
  380. },
  381. immediate: true,
  382. },
  383. },
  384. created () {
  385. const values = { ...this.form.fd }
  386. values.brand = R.join(',', values.brand || [])
  387. this.$emit('update', this.options.i, values)
  388. this.fetchData()
  389. },
  390. methods: {
  391. refresh () {
  392. return this.fetchData()
  393. },
  394. async fetchData () {
  395. // if (!this.form.fd.brand) return
  396. if (this.isResDeny) return
  397. this.loading = true
  398. try {
  399. const requestData = this.genQueryData()
  400. requestData.signature = getSignature(requestData)
  401. const data = await load({
  402. res: 'unifiedmonitors',
  403. actionArgs: {
  404. url: '/v1/unifiedmonitors/query',
  405. method: 'POST',
  406. params: {
  407. $t: getRequestT(),
  408. ignoreErrorStatusCode: [403],
  409. },
  410. data: requestData,
  411. },
  412. useManager: false,
  413. resPath: 'data.series',
  414. })
  415. this.seriesData = this.toHistogramChartData(data || [])
  416. } finally {
  417. this.loading = false
  418. }
  419. },
  420. toHistogramChartData (series) {
  421. const { order, limit } = this.form.fd
  422. let rows = series.map((item) => {
  423. const lastPoint = item.points ? item.points[item.points.length - 1] : undefined
  424. if (lastPoint) {
  425. return {
  426. name: this.filterByOem(item.tags[this.dimension.name]),
  427. id: item.tags[this.dimension.id],
  428. value: lastPoint[0],
  429. timestamp: lastPoint[1],
  430. tags: item.tags,
  431. }
  432. }
  433. })
  434. rows = rows.sort((a, b) => {
  435. if (order.toLowerCase() === 'bottom') {
  436. return a.value - b.value
  437. } else {
  438. return b.value - a.value
  439. }
  440. })
  441. if (rows.length > limit) {
  442. rows = rows.slice(0, limit)
  443. }
  444. return rows
  445. },
  446. filterByOem (name) {
  447. if (this.form.fd.dimensionId === 'brand') {
  448. if (name === 'OneCloud') {
  449. return setting.brand[setting.language] || name
  450. } else if (name === 'Cloudpods') {
  451. const { companyInfo = {} } = this.$store.state.app
  452. return setting.language === 'en' ? (companyInfo.inner_copyright_en || name) : (companyInfo.inner_copyright || name)
  453. }
  454. }
  455. return name
  456. },
  457. handleEdit () {
  458. this.visible = true
  459. },
  460. async handleSubmit () {
  461. try {
  462. const values = await this.form.fc.validateFields()
  463. this.form.fd = values
  464. const updateValues = { ...values }
  465. updateValues.brand = updateValues.brand.join(',')
  466. this.$emit('update', this.options.i, updateValues)
  467. this.visible = false
  468. } catch (error) {
  469. throw error
  470. }
  471. },
  472. handleResTypeChange (e) {
  473. this.form.fc.setFieldsValue({
  474. usage: this.usageOptions[e.target.value][0].key,
  475. brand: [],
  476. })
  477. },
  478. genQueryData () {
  479. const fd = this.form.fd
  480. let ret = ''
  481. const brandKey = 'brand'
  482. const brand = this.form.fd.brand
  483. const usageKeys = fd.usage.split(',')
  484. const min = fd.time / 60
  485. const condition = this.getDomainOrProjectQuery()
  486. const brandTags = brand.map(key => {
  487. return {
  488. key: brandKey,
  489. value: key,
  490. operator: '=',
  491. condition: 'and',
  492. }
  493. })
  494. const rangeTags = []
  495. if (this.isAdminMode && this.dataRangeParams?.scope === 'domain' && this.dataRangeParams?.domain) {
  496. rangeTags.push({
  497. key: 'domain_id',
  498. value: this.dataRangeParams?.domain,
  499. operator: '=',
  500. })
  501. }
  502. if (this.isAdminMode && this.dataRangeParams?.scope === 'project' && this.dataRangeParams?.project) {
  503. rangeTags.push({
  504. key: 'tenant_id',
  505. value: this.dataRangeParams?.project,
  506. operator: '=',
  507. })
  508. }
  509. if (this.isDomainMode && this.dataRangeParams?.scope === 'project' && this.dataRangeParams?.project) {
  510. rangeTags.push({
  511. key: 'tenant_id',
  512. value: this.dataRangeParams?.project,
  513. operator: '=',
  514. })
  515. }
  516. if (this.brandEnvs.length && this.brandEnvs.every(env => env === 'public')) {
  517. if (fd.resType === 'server') {
  518. // ret = `SELECT ${fd.order}("${usageKeys[0]}", "vm_name", "vm_ip", "hypervisor", ${fd.limit}) FROM "${usageKeys[1]}" WHERE time > now() - ${min}m AND "${brandKey}"='${brand}'`
  519. ret = {
  520. metric_query: [
  521. {
  522. model: {
  523. database: 'telegraf',
  524. measurement: usageKeys[1],
  525. select: [
  526. [
  527. {
  528. type: 'field',
  529. params: [usageKeys[0], 'vm_name', 'vm_ip'],
  530. },
  531. { type: 'mean' },
  532. { type: 'abs' },
  533. ],
  534. ],
  535. tags: [
  536. {
  537. key: this.groupInput(),
  538. operator: '!=',
  539. value: '',
  540. },
  541. ...brandTags,
  542. ...rangeTags,
  543. ],
  544. group_by: this.groupBy(usageKeys[0]),
  545. },
  546. },
  547. ],
  548. scope: this.scope,
  549. from: `${min}m`,
  550. interval: `${min}m`,
  551. unit: true,
  552. }
  553. }
  554. if (condition && condition.length > 0) {
  555. // ret += ` AND ${condition}`
  556. ret.metric_query[0].model.tags.push(condition)
  557. }
  558. return ret
  559. } else if (this.brandEnvs.includes('idc') || this.brandEnvs.includes('private')) {
  560. if (fd.resType === 'server') {
  561. // ret = `SELECT ${fd.order}("${usageKeys[0]}", "vm_name", "vm_ip", ${fd.limit}) FROM "telegraf"."30day_only"."${usageKeys[1]}" WHERE time > now() - ${min}m AND "${brandKey}"='${brand}'`
  562. ret = {
  563. metric_query: [
  564. {
  565. model: {
  566. database: 'telegraf',
  567. measurement: usageKeys[1],
  568. select: [
  569. [
  570. {
  571. type: 'field',
  572. params: [usageKeys[0], 'vm_name', 'vm_ip'],
  573. },
  574. { type: 'mean' },
  575. { type: 'abs' },
  576. ],
  577. ],
  578. tags: [
  579. {
  580. key: this.groupInput(),
  581. operator: '!=',
  582. value: '',
  583. },
  584. ...brandTags,
  585. ...rangeTags,
  586. ],
  587. group_by: this.groupBy(usageKeys[0]),
  588. },
  589. },
  590. ],
  591. scope: this.scope,
  592. from: `${min}m`,
  593. interval: `${min}m`,
  594. unit: true,
  595. }
  596. }
  597. if (fd.resType === 'host') {
  598. // ret = `SELECT ${fd.order}("${usageKeys[0]}", ${fd.limit}) FROM "${usageKeys[1]}" WHERE "res_type" = 'host' AND time > now() - ${min}m AND "${brandKey}" = '${brand}' GROUP BY "host"`
  599. ret = {
  600. metric_query: [
  601. {
  602. model: {
  603. database: 'telegraf',
  604. measurement: usageKeys[1],
  605. select: [
  606. [
  607. {
  608. type: 'field',
  609. params: [usageKeys[0], 'host', 'host_ip'],
  610. },
  611. { type: 'mean' },
  612. { type: 'abs' },
  613. ],
  614. ],
  615. tags: [
  616. {
  617. key: this.groupInput(),
  618. operator: '!=',
  619. value: '',
  620. },
  621. ...brandTags,
  622. ...rangeTags,
  623. ],
  624. group_by: this.groupBy(usageKeys[0]),
  625. },
  626. },
  627. ],
  628. scope: this.scope,
  629. from: `${min}m`,
  630. interval: `${min}m`,
  631. unit: true,
  632. }
  633. }
  634. if (condition) {
  635. ret.metric_query[0].model.tags.push(condition)
  636. // ret += ` AND ${condition}`
  637. }
  638. return ret
  639. } else {
  640. if (fd.resType === 'server') {
  641. ret = {
  642. metric_query: [
  643. {
  644. model: {
  645. database: 'telegraf',
  646. measurement: usageKeys[1],
  647. select: [
  648. [
  649. {
  650. type: 'field',
  651. params: [usageKeys[0], 'vm_name', 'vm_ip'],
  652. },
  653. { type: 'mean' },
  654. { type: 'abs' },
  655. ],
  656. ],
  657. tags: [
  658. {
  659. key: this.groupInput(),
  660. operator: '!=',
  661. value: '',
  662. },
  663. ...rangeTags,
  664. ],
  665. group_by: this.groupBy(usageKeys[0]),
  666. },
  667. },
  668. ],
  669. scope: this.scope,
  670. from: `${min}m`,
  671. unit: true,
  672. interval: `${min}m`,
  673. }
  674. }
  675. if (fd.resType === 'host') {
  676. ret = {
  677. metric_query: [
  678. {
  679. model: {
  680. database: 'telegraf',
  681. measurement: usageKeys[1],
  682. select: [
  683. [
  684. {
  685. type: 'field',
  686. params: [usageKeys[0], 'host', 'host_ip'],
  687. },
  688. { type: 'mean' },
  689. { type: 'abs' },
  690. ],
  691. ],
  692. tags: [
  693. {
  694. key: this.groupInput(),
  695. operator: '!=',
  696. value: '',
  697. },
  698. ...rangeTags,
  699. ],
  700. group_by: this.groupBy(usageKeys[0]),
  701. },
  702. },
  703. ],
  704. scope: this.scope,
  705. from: `${min}m`,
  706. unit: true,
  707. interval: `${min}m`,
  708. }
  709. }
  710. if (condition && condition.length > 0) {
  711. // ret += ` AND ${condition}`
  712. ret.metric_query[0].model.tags.push(condition)
  713. }
  714. return ret
  715. }
  716. },
  717. getLabel (val) {
  718. const fixedVal = isNaN(Number(val)) ? 0 : Number(val).toFixed(2)
  719. const formatter = usageConfig[this.form.fd.usage] && usageConfig[this.form.fd.usage].formatter
  720. if (formatter) return formatter(fixedVal)
  721. return fixedVal
  722. },
  723. getPercent (val) {
  724. const num = (val / this.maxSeriesData).toFixed(2) * 100
  725. return Number.isFinite(num) ? num : 0
  726. },
  727. getDomainOrProjectQuery () {
  728. if (this.isProjectMode) {
  729. // return `"tenant_id" = '${this.userInfo.projectId}'`
  730. return {
  731. key: 'tenant_id',
  732. value: this.userInfo.projectId,
  733. operator: '=',
  734. }
  735. } else if (this.isDomainMode) {
  736. // return `"domain_id" = '${this.userInfo.projectDomainId}'`
  737. return {
  738. key: 'domain_id',
  739. value: this.userInfo.projectDomainId,
  740. operator: '=',
  741. }
  742. }
  743. return null
  744. },
  745. groupInput () {
  746. if (this.form.fd.resType === 'host') {
  747. return 'project_domain'
  748. }
  749. switch (this.dimension.scope) {
  750. case 'system':
  751. return 'project_domain'
  752. default:
  753. return 'tenant'
  754. }
  755. },
  756. groupBy (field) {
  757. const ret = []
  758. if (this.dimension.name === 'tenant') {
  759. ret.push({ type: 'field', params: ['tenant'] })
  760. } else {
  761. ret.push({ type: 'field', params: [this.dimension.name] })
  762. ret.push({ type: 'field', params: [this.dimension.id] })
  763. }
  764. return ret
  765. },
  766. goPage () {
  767. this.$router.push('./monitoroverview')
  768. },
  769. changeName (resType, usage) {
  770. let usage_label = ''
  771. if (resType === 'server') {
  772. usage_label = serverUsageOptions.find(item => item.key === usage)?.label
  773. }
  774. if (resType === 'host') {
  775. usage_label = hostUsageOptions.find(item => item.key === usage)?.label
  776. }
  777. this.form.fc.setFieldsValue({
  778. name: `${usage_label}TOP5`,
  779. })
  780. },
  781. },
  782. }
  783. </script>