index.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. {{ fd.name }}
  7. <a-icon class="ml-2" type="loading" v-if="loading" />
  8. </div>
  9. <div class="dashboard-card-header-right">
  10. <slot name="actions" :handle-edit="() => visible = true" />
  11. <router-link v-if="!edit" to="/vminstance" class="ml-2">
  12. <icon type="arrow-right" style="font-size:18px" />
  13. </router-link>
  14. </div>
  15. </div>
  16. <div class="dashboard-card-body align-items-center justify-content-center">
  17. <e-chart :options="chartOptions" style="height: 100%; width: 100%;" autoresize />
  18. </div>
  19. </div>
  20. <base-drawer :visible.sync="visible" :title="$t('dashboard.text_5')" @ok="handleSubmit">
  21. <a-form-model
  22. ref="form"
  23. hideRequiredMark
  24. :model="fd"
  25. :rules="rules">
  26. <a-form-model-item :label="$t('dashboard.text_6')" prop="name">
  27. <a-input v-model="fd.name" />
  28. </a-form-model-item>
  29. <a-form-model-item :label="$t('dashboard.group_by')" prop="type">
  30. <a-radio-group v-model="fd.type" @change="handleType">
  31. <a-radio-button value="domain" v-if="isAdminMode">
  32. {{ $t('dictionary.domain') }}
  33. </a-radio-button>
  34. <a-radio-button value="project">
  35. {{ $t('dictionary.project') }}
  36. </a-radio-button>
  37. </a-radio-group>
  38. </a-form-model-item>
  39. </a-form-model>
  40. </base-drawer>
  41. </div>
  42. </template>
  43. <script>
  44. import * as R from 'ramda'
  45. import { mapGetters } from 'vuex'
  46. import BaseDrawer from '@Dashboard/components/BaseDrawer'
  47. import { load } from '@Dashboard/utils/cache'
  48. import { getRequestT } from '@/utils/utils'
  49. import { chartColors } from '@/constants'
  50. import { numerify } from '@/filters'
  51. export default {
  52. name: 'ServerNumberDetail',
  53. components: {
  54. BaseDrawer,
  55. },
  56. props: {
  57. options: {
  58. type: Object,
  59. required: true,
  60. },
  61. params: Object,
  62. edit: Boolean,
  63. dataRangeParams: {
  64. type: Object,
  65. },
  66. },
  67. data () {
  68. const initNameValue = (this.params && this.params.name) || this.$t('dashborad.server_domain_numbers')
  69. const initType = (this.params && this.params.type) || 'domain'
  70. return {
  71. data: [],
  72. visible: false,
  73. loading: false,
  74. fd: {
  75. name: initNameValue,
  76. type: initType,
  77. },
  78. rules: {
  79. name: [
  80. { required: true, message: this.$t('dashboard.text_8') },
  81. ],
  82. },
  83. }
  84. },
  85. computed: {
  86. ...mapGetters(['scope', 'isAdminMode', 'isDomainMode']),
  87. allServers () {
  88. const arr = this.data.map(item => item.count)
  89. return R.sum(arr)
  90. },
  91. outherData () {
  92. return this.data.map(item => {
  93. const ret = {
  94. ...item,
  95. formatted_amount: item.count,
  96. percent: this.getPercent(item.count, this.allServers),
  97. value: item.count,
  98. }
  99. return ret
  100. })
  101. },
  102. chartOptions () {
  103. return {
  104. title: [
  105. {
  106. text: this.$t('dashboard.text_181'),
  107. subtext: `${this.allServers}`,
  108. textStyle: {
  109. fontSize: 12,
  110. color: '#ccc',
  111. },
  112. subtextStyle: {
  113. fontSize: 18,
  114. color: 'rgb(100, 100, 100)',
  115. },
  116. top: '42%',
  117. left: '24.5%',
  118. textAlign: 'center',
  119. },
  120. ],
  121. tooltip: {
  122. show: true,
  123. trigger: 'item',
  124. formatter: (params) => {
  125. const { name, count, percent } = params.data
  126. return `${name}: ${count}(${percent}%)`
  127. },
  128. },
  129. color: chartColors,
  130. legend: {
  131. type: 'scroll',
  132. pageIconSize: 8,
  133. icon: 'circle',
  134. orient: 'vertical',
  135. left: '50%',
  136. align: 'left',
  137. top: 'middle',
  138. itemHeight: 8,
  139. itemWidth: 8,
  140. textStyle: {
  141. rich: {
  142. name: {
  143. verticalAlign: 'right',
  144. align: 'left',
  145. fontSize: 12,
  146. color: 'rgb(100, 100, 100)',
  147. height: 20,
  148. },
  149. percent: {
  150. align: 'left',
  151. color: '#1890ff',
  152. borderWidth: 1,
  153. borderColor: '#1890ff',
  154. padding: [3, 5, 3, 5],
  155. },
  156. formatted_amount: {
  157. align: 'left',
  158. fontSize: 12,
  159. color: 'rgb(150, 150, 150)',
  160. padidng: 0,
  161. },
  162. },
  163. },
  164. height: '90%',
  165. formatter: name => {
  166. const item = R.find(R.propEq('name', name))(this.outherData)
  167. if (item) {
  168. return `{name|${name}}\n{formatted_amount|${item.formatted_amount}} {percent|${item.percent}%}`
  169. }
  170. return name
  171. },
  172. },
  173. series: [
  174. {
  175. name: this.$t('dashboard.text_49'),
  176. type: 'pie',
  177. center: ['25%', '50%'],
  178. radius: ['50%', '65%'],
  179. hoverAnimation: false,
  180. label: {
  181. normal: {
  182. show: false,
  183. },
  184. },
  185. labelLine: {
  186. normal: {
  187. show: false,
  188. },
  189. },
  190. data: this.outherData,
  191. },
  192. ],
  193. }
  194. },
  195. },
  196. watch: {
  197. 'fd.type' (val) {
  198. this.fetchData()
  199. },
  200. isDomainMode: {
  201. handler (val) {
  202. if (val) {
  203. this.fd.name = this.$t('dashborad.server_project_numbers')
  204. this.fd.type = 'project'
  205. }
  206. },
  207. immediate: true,
  208. },
  209. 'dataRangeParams.scope': {
  210. handler (val) {
  211. this.fetchData()
  212. },
  213. immediate: true,
  214. },
  215. 'dataRangeParams.domain': {
  216. handler (val) {
  217. this.fetchData()
  218. },
  219. immediate: true,
  220. },
  221. 'dataRangeParams.project': {
  222. handler (val) {
  223. this.fetchData()
  224. },
  225. immediate: true,
  226. },
  227. },
  228. created () {
  229. this.fetchData()
  230. this.$emit('update', this.options.i, {
  231. ...this.fd,
  232. })
  233. },
  234. methods: {
  235. refresh () {
  236. return this.fetchData()
  237. },
  238. async fetchData () {
  239. this.loading = true
  240. try {
  241. const params = {
  242. $t: getRequestT(),
  243. scope: this.scope,
  244. }
  245. if (this.isAdminMode) {
  246. if (this.dataRangeParams?.scope === 'domain' && this.dataRangeParams?.domain) {
  247. params.domain_id = this.dataRangeParams?.domain
  248. }
  249. if (this.dataRangeParams?.scope === 'project' && this.dataRangeParams?.project) {
  250. params.project_id = this.dataRangeParams?.project
  251. }
  252. }
  253. if (this.isDomainMode) {
  254. if (this.dataRangeParams?.scope === 'project' && this.dataRangeParams?.project) {
  255. params.project_id = this.dataRangeParams?.project
  256. }
  257. }
  258. const data = await load({
  259. res: 'servers',
  260. actionArgs: {
  261. url: `/v2/servers/${this.fd.type}-statistics`,
  262. method: 'GET',
  263. params,
  264. },
  265. useManager: false,
  266. resPath: 'data',
  267. })
  268. this.data = data || []
  269. this.data.sort(this.compareData)
  270. } finally {
  271. this.loading = false
  272. }
  273. },
  274. async handleSubmit () {
  275. try {
  276. await this.$refs.form.validate()
  277. this.$emit('update', this.options.i, this.fd)
  278. this.visible = false
  279. } catch (error) {
  280. throw error
  281. }
  282. },
  283. getPercent (num, den) {
  284. const percent = (num / den) * 100
  285. if (percent && percent < 10) {
  286. return percent.toFixed(1)
  287. }
  288. return `${numerify(percent, 'percent')}`
  289. },
  290. compareData (a, b) {
  291. if (a.count > b.count) {
  292. return -1
  293. } else if (a.count < b.count) {
  294. return 1
  295. } else {
  296. return 0
  297. }
  298. },
  299. handleType (v) {
  300. if (v.target.value === 'domain') {
  301. this.fd.name = this.$t('dashborad.server_domain_numbers')
  302. } else {
  303. this.fd.name = this.$t('dashborad.server_project_numbers')
  304. }
  305. },
  306. },
  307. }
  308. </script>