columns.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. import _ from 'lodash'
  2. import PasswordFetcher from '@Compute/sections/PasswordFetcher'
  3. import {
  4. getRegionTableColumn,
  5. getStatusTableColumn,
  6. getBrandTableColumn,
  7. getEnabledTableColumn,
  8. getNameDescriptionTableColumn,
  9. getPublicScopeTableColumn,
  10. getProjectDomainTableColumn,
  11. getTagTableColumn,
  12. getAccountTableColumn,
  13. getOsArch,
  14. getTimeTableColumn,
  15. getCopyWithContentTableColumn,
  16. } from '@/utils/common/tableColumn'
  17. import { sizestr, bytesPerSecondStr } from '@/utils/utils'
  18. import i18n from '@/locales'
  19. import { getHostSpecInfo } from '../utils/index'
  20. export default {
  21. created () {
  22. const getStatusToolTip = (row) => {
  23. if (row.metadata) {
  24. const sysWarn = row.metadata.sys_warn
  25. const sysError = row.metadata.sys_error
  26. const titleCon = sysWarn || sysError
  27. if (titleCon) {
  28. // const aLink = <side-page-trigger vm={this} name='HostSidePage' id={row.id} list={this.list} tab='event-drawer'>查看日志</side-page-trigger>
  29. const aIcon = <a-icon type="exclamation-circle" class={ { 'ml-1 oc-pointer': true, 'warning-color': sysWarn, 'error-color': sysError } } />
  30. return <a-tooltip placement="right">
  31. <template slot="title">
  32. { titleCon }
  33. </template>
  34. { aIcon }
  35. </a-tooltip>
  36. }
  37. }
  38. return null
  39. }
  40. this.columns = [
  41. getNameDescriptionTableColumn({
  42. onManager: this.onManager,
  43. hideField: true,
  44. addBackup: true,
  45. formRules: [
  46. { required: true, message: i18n.t('compute.text_210') },
  47. // { validator: this.$validate('serverCreateName') },
  48. ],
  49. slotCallback: row => {
  50. return (
  51. <side-page-trigger onTrigger={ () => this.handleOpenSidepage(row) }>{ row.name }</side-page-trigger>
  52. )
  53. },
  54. cellWrapSlots: row => {
  55. return {
  56. append: () => {
  57. var ret = []
  58. if (row.is_baremetal) {
  59. ret.push(<a-tooltip title={i18n.t('compute.text_562')}><icon class='ml-2' type='res-host' style={{ color: '#1890ff' }} /></a-tooltip>)
  60. }
  61. if (row.isolated_device_count) {
  62. ret.push(<a-tooltip title={i18n.t('compute.text_113')}><icon class='ml-2' type='passthrough' /></a-tooltip>)
  63. }
  64. if (row.page_size_kb > 4) {
  65. ret.push(<a-tooltip title={i18n.t('compute.large_page_memory_tips')}><icon class='ml-2' type='large-page-memory' /></a-tooltip>)
  66. }
  67. return ret
  68. },
  69. }
  70. },
  71. }),
  72. getStatusTableColumn({
  73. statusModule: 'host',
  74. minWidth: 100,
  75. vm: this,
  76. }),
  77. getEnabledTableColumn(),
  78. getStatusTableColumn({
  79. field: 'host_status',
  80. title: i18n.t('compute.text_502'),
  81. statusModule: 'host_status',
  82. slotCallback: row => {
  83. return [
  84. <div class='d-flex align-items-center text-truncate'>
  85. <status status={ row.host_status } statusModule='host_status' />
  86. { getStatusToolTip(row) }
  87. </div>,
  88. ]
  89. },
  90. }),
  91. getTagTableColumn({
  92. onManager: this.onManager,
  93. resource: 'hosts',
  94. columns: () => this.columns,
  95. editCheck: (row) => (row.provider || '').toLowerCase() !== 'bingocloud',
  96. }),
  97. {
  98. field: 'custom_ip',
  99. title: 'IP',
  100. width: 200,
  101. showOverflow: 'ellipsis',
  102. slots: {
  103. default: ({ row }) => {
  104. const cellWrap = []
  105. if (row.access_ip) {
  106. cellWrap.push(
  107. <div class="d-flex">
  108. <list-body-cell-wrap row={row} field="access_ip" copy><span class="text-color-help">{this.$t('compute.text_1319')}</span></list-body-cell-wrap>
  109. </div>,
  110. )
  111. }
  112. if (row.ipmi_ip) {
  113. cellWrap.push(
  114. <div class="d-flex">
  115. <list-body-cell-wrap row={row} field="ipmi_ip" copy><span class="text-color-help">{this.$t('compute.text_1320')}</span></list-body-cell-wrap>
  116. </div>,
  117. )
  118. }
  119. if (row.public_ip) {
  120. cellWrap.push(
  121. <div class="d-flex">
  122. <list-body-cell-wrap row={row} field="public_ip" copy><span class="text-color-help"> (EIP) </span></list-body-cell-wrap>
  123. </div>,
  124. )
  125. }
  126. return cellWrap
  127. },
  128. },
  129. formatter: ({ row }) => {
  130. const list = []
  131. if (row.access_ip) {
  132. list.push(`${row.access_ip}${this.$t('compute.text_1319')}`)
  133. }
  134. if (row.ipmi_ip) {
  135. list.push(`${row.ipmi_ip}${this.$t('compute.text_1320')}`)
  136. }
  137. return list.length ? list.join(',') : '-'
  138. },
  139. },
  140. {
  141. field: 'id',
  142. title: 'IPMI',
  143. width: 60,
  144. slots: {
  145. default: ({ cellValue, row }) => {
  146. if (!row.is_baremetal) {
  147. return '-'
  148. } else {
  149. return [<PasswordFetcher serverId={ row.id } resourceType='baremetals' />]
  150. }
  151. },
  152. },
  153. },
  154. {
  155. field: 'server_id',
  156. title: i18n.t('compute.text_566'),
  157. width: 70,
  158. slots: {
  159. default: ({ cellValue, row }) => {
  160. if (!row.is_baremetal) {
  161. return '-'
  162. } else {
  163. return [<PasswordFetcher serverId={ row.server_id } resourceType='servers' />]
  164. }
  165. },
  166. },
  167. },
  168. {
  169. field: 'nonsystem_guests',
  170. sortBy: 'order_by_server_count',
  171. title: '#VM',
  172. width: 60,
  173. sortable: true,
  174. slots: {
  175. default: ({ row }, h) => {
  176. if (this.isPreLoad && row.nonsystem_guests === undefined) return [<data-loading />]
  177. return `${row.nonsystem_guests}`
  178. },
  179. },
  180. formatter: ({ row }) => {
  181. return row.nonsystem_guests || '-'
  182. },
  183. },
  184. getOsArch({ field: 'cpu_architecture' }),
  185. {
  186. field: 'cpu_usage',
  187. title: this.$t('compute.text_563'),
  188. minWidth: 100,
  189. sortable: true,
  190. // sortBy: 'order_by_cpu_commit',
  191. slots: {
  192. default: ({ row }) => {
  193. const { cpu_count = 0, cpu_used = 0 } = getHostSpecInfo(row)
  194. const title = `${this.$t('common_407')}: ${Math.round(cpu_used)}\n${this.$t('common_234')}: ${Math.round(cpu_count)}`
  195. return [<UsedPercent used={cpu_used} total={cpu_count} title={title} usedFormatter={(val) => val > 0 ? (Math.max(Math.round(val), 1)) : Math.round(val)} totalFormatter={(val) => val > 0 ? (Math.max(Math.round(val), 1)) : Math.round(val)} />]
  196. },
  197. header: ({ column }) => {
  198. return [
  199. <span>
  200. <span>{column.title}</span>
  201. <a-tooltip class="ml-1" title={this.$t('compute.order_by_used_percent')}><a-icon type="question-circle" style="color: #aaa;" /></a-tooltip>
  202. </span>,
  203. ]
  204. },
  205. },
  206. formatter: ({ row }) => {
  207. const { cpu_count = 0, cpu_used = 0 } = getHostSpecInfo(row)
  208. const title = `${this.$t('common_407')}: ${Math.round(cpu_used)}, ${this.$t('common_234')}: ${Math.round(cpu_count)}`
  209. return title
  210. },
  211. },
  212. {
  213. field: 'virtual_cpu_usage',
  214. title: this.$t('compute.text_563_1'),
  215. minWidth: 100,
  216. sortable: true,
  217. // sortBy: 'order_by_cpu_commit',
  218. slots: {
  219. default: ({ row }) => {
  220. const { cpu_commit = 0, cpu_count = 0, cpu_count_virtual = 0, cpu_commit_bound } = getHostSpecInfo(row)
  221. const title = `${this.$t('common_233')}: ${Math.round(cpu_commit)}\n` +
  222. `${this.$t('common_234')}: ${Math.round(cpu_count_virtual)}\n` +
  223. `${this.$t('compute.text_594')}: ${(cpu_commit / cpu_count).toFixed(2)}\n` +
  224. `${this.$t('compute.cpu_commit_bound')}: ${cpu_commit_bound}`
  225. return [<UsedPercent used={cpu_commit} total={cpu_count_virtual} usedLabel={this.$t('common_233')} title={title} text={`${Math.round(cpu_commit)}/${Math.round(cpu_count_virtual)}`} />]
  226. },
  227. header: ({ column }) => {
  228. return [
  229. <span>
  230. <span>{column.title}</span>
  231. <a-tooltip class="ml-1" title={this.$t('compute.order_by_commit_percent')}><a-icon type="question-circle" style="color: #aaa;" /></a-tooltip>
  232. </span>,
  233. ]
  234. },
  235. },
  236. formatter: ({ row }) => {
  237. const { cpu_commit = 0, cpu_count_virtual = 0 } = getHostSpecInfo(row)
  238. const title = `${this.$t('common_233')}: ${Math.round(cpu_commit)}, ${this.$t('common_234')}: ${Math.round(cpu_count_virtual)}`
  239. return title
  240. },
  241. },
  242. {
  243. field: 'mem_usage',
  244. title: this.$t('compute.text_564'),
  245. minWidth: 100,
  246. sortable: true,
  247. // sortBy: 'order_by_mem_commit',
  248. slots: {
  249. default: ({ row }) => {
  250. const { mem_size, mem_used } = getHostSpecInfo(row)
  251. const title = `${this.$t('common_407')}: ${sizestr(mem_used, 'M', 1024)}\n${this.$t('common_234')}: ${sizestr(mem_size, 'M', 1024)}`
  252. return [<UsedPercent title={title} used={mem_used} total={mem_size} usedFormatter={(val) => sizestr(val, 'M', 1024)} totalFormatter={(val) => sizestr(val, 'M', 1024)} />]
  253. },
  254. header: ({ column }) => {
  255. return [
  256. <span>
  257. <span>{column.title}</span>
  258. <a-tooltip class="ml-1" title={this.$t('compute.order_by_used_percent')}><a-icon type="question-circle" style="color: #aaa;" /></a-tooltip>
  259. </span>,
  260. ]
  261. },
  262. },
  263. formatter: ({ row }) => {
  264. const { mem_size, mem_used } = getHostSpecInfo(row)
  265. const title = `${this.$t('common_407')}: ${sizestr(mem_used, 'M', 1024)}, ${this.$t('common_234')}: ${sizestr(mem_size, 'M', 1024)}`
  266. return title
  267. },
  268. },
  269. {
  270. field: 'virtual_mem_usage',
  271. title: this.$t('compute.text_564_1'),
  272. minWidth: 100,
  273. sortable: true,
  274. // sortBy: 'order_by_mem_commit',
  275. slots: {
  276. default: ({ row }) => {
  277. const { mem_size_virtual, mem_commit, mem_size, mem_commit_bound } = getHostSpecInfo(row)
  278. const title = `${this.$t('common_233')}: ${sizestr(mem_commit, 'M', 1024)}\n` +
  279. `${this.$t('common_234')}: ${sizestr(mem_size_virtual, 'M', 1024)}\n` +
  280. `${this.$t('compute.text_594')}: ${(mem_commit / mem_size).toFixed(2)}\n` +
  281. `${this.$t('compute.memory_commit_bound')}: ${mem_commit_bound}`
  282. return [<UsedPercent title={title} used={mem_commit} total={mem_size_virtual} usedLabel={this.$t('common_233')} usedFormatter={(val) => sizestr(val, 'M', 1024)} totalFormatter={(val) => sizestr(val, 'M', 1024)} />]
  283. },
  284. header: ({ column }) => {
  285. return [
  286. <span>
  287. <span>{column.title}</span>
  288. <a-tooltip class="ml-1" title={this.$t('compute.order_by_commit_percent')}><a-icon type="question-circle" style="color: #aaa;" /></a-tooltip>
  289. </span>,
  290. ]
  291. },
  292. },
  293. formatter: ({ row }) => {
  294. const { mem_size_virtual, mem_commit } = getHostSpecInfo(row)
  295. const title = `${this.$t('common_233')}: ${sizestr(mem_commit, 'M', 1024)}, ${this.$t('common_234')}: ${sizestr(mem_size_virtual, 'M', 1024)}`
  296. return title
  297. },
  298. },
  299. {
  300. field: 'storage_usage',
  301. title: this.$t('compute.text_565'),
  302. minWidth: 100,
  303. sortable: true,
  304. // sortBy: 'order_by_mem_commit',
  305. slots: {
  306. default: ({ row }) => {
  307. const { storage_size, actual_storage_used } = getHostSpecInfo(row)
  308. const title = `${this.$t('common_407')}: ${sizestr(actual_storage_used, 'M', 1024)}\n${this.$t('common_234')}: ${sizestr(storage_size, 'M', 1024)}`
  309. return [<UsedPercent title={title} used={actual_storage_used} total={storage_size} usedFormatter={(val) => sizestr(val, 'M', 1024)} totalFormatter={(val) => sizestr(val, 'M', 1024)} />]
  310. },
  311. header: ({ column }) => {
  312. return [
  313. <span>
  314. <span>{column.title}</span>
  315. <a-tooltip class="ml-1" title={this.$t('compute.order_by_used_percent')}><a-icon type="question-circle" style="color: #aaa;" /></a-tooltip>
  316. </span>,
  317. ]
  318. },
  319. },
  320. formatter: ({ row }) => {
  321. const { storage_size, actual_storage_used } = getHostSpecInfo(row)
  322. const title = `${this.$t('common_407')}: ${sizestr(actual_storage_used, 'M', 1024)}, ${this.$t('common_234')}: ${sizestr(storage_size, 'M', 1024)}`
  323. return title
  324. },
  325. },
  326. {
  327. field: 'virtual_storage_usage',
  328. title: this.$t('compute.text_565_1'),
  329. minWidth: 100,
  330. sortable: true,
  331. // sortBy: 'order_by_storage_virtual',
  332. slots: {
  333. default: ({ row }) => {
  334. const { storage_size_virtual, storage_commit, storage_size } = getHostSpecInfo(row)
  335. const title = `${this.$t('common_233')}: ${sizestr(storage_commit, 'M', 1024)}\n` +
  336. `${this.$t('common_234')}: ${sizestr(storage_size_virtual, 'M', 1024)}\n` +
  337. `${this.$t('compute.text_594')}: ${(storage_commit / storage_size).toFixed(2)}\n` +
  338. `${this.$t('compute.storage_commit_bound')}: ${(storage_size_virtual / storage_size).toFixed(2)}`
  339. return [<UsedPercent title={title} used={storage_commit} total={storage_size_virtual} usedLabel={this.$t('common_233')} usedFormatter={(val) => sizestr(val, 'M', 1024)} totalFormatter={(val) => sizestr(val, 'M', 1024)} />]
  340. },
  341. header: ({ column }) => {
  342. return [
  343. <span>
  344. <span>{column.title}</span>
  345. <a-tooltip class="ml-1" title={this.$t('compute.order_by_commit_percent')}><a-icon type="question-circle" style="color: #aaa;" /></a-tooltip>
  346. </span>,
  347. ]
  348. },
  349. },
  350. formatter: ({ row }) => {
  351. const { storage_size_virtual, storage_commit } = getHostSpecInfo(row)
  352. const title = `${this.$t('common_233')}: ${sizestr(storage_commit, 'M', 1024)}, ${this.$t('common_234')}: ${sizestr(storage_size_virtual, 'M', 1024)}`
  353. return title
  354. },
  355. },
  356. {
  357. field: 'disk_rate',
  358. title: i18n.t('common.disk_rate'),
  359. minWidth: 100,
  360. slots: {
  361. default: ({ row }) => {
  362. if (row.alert_data && row.alert_data.hasOwnProperty('disk_read_rate') && row.alert_data.hasOwnProperty('disk_write_rate')) {
  363. return [
  364. <div>{i18n.t('common.disk_read_rate_value', [bytesPerSecondStr(row.alert_data.disk_read_rate)])}</div>,
  365. <div>{i18n.t('common.disk_write_rate_value', [bytesPerSecondStr(row.alert_data.disk_write_rate)])}</div>,
  366. ]
  367. }
  368. return '-'
  369. },
  370. },
  371. formatter: ({ row }) => {
  372. if (row.alert_data && row.alert_data.hasOwnProperty('disk_read_rate') && row.alert_data.hasOwnProperty('disk_write_rate')) {
  373. return `${i18n.t('common.disk_read_rate_value', [bytesPerSecondStr(row.alert_data.disk_read_rate)])} / ${i18n.t('common.disk_write_rate_value', [bytesPerSecondStr(row.alert_data.disk_write_rate)])}`
  374. }
  375. return '-'
  376. },
  377. },
  378. {
  379. field: 'net_iops',
  380. title: i18n.t('common.net_iops'),
  381. minWidth: 100,
  382. slots: {
  383. default: ({ row }) => {
  384. if (row.alert_data && row.alert_data.hasOwnProperty('net_in_rate') && row.alert_data.hasOwnProperty('net_out_rate')) {
  385. return [
  386. <div>{i18n.t('common.net_in_rate_value', [bytesPerSecondStr(row.alert_data.net_in_rate)])}</div>,
  387. <div>{i18n.t('common.net_out_rate_value', [bytesPerSecondStr(row.alert_data.net_out_rate)])}</div>,
  388. ]
  389. }
  390. return '-'
  391. },
  392. },
  393. formatter: ({ row }) => {
  394. if (row.alert_data && row.alert_data.hasOwnProperty('net_in_rate') && row.alert_data.hasOwnProperty('net_out_rate')) {
  395. return `${i18n.t('common.net_in_rate_value', [bytesPerSecondStr(row.alert_data.net_in_rate)])} / ${i18n.t('common.net_out_rate_value', [bytesPerSecondStr(row.alert_data.net_out_rate)])}`
  396. }
  397. return '-'
  398. },
  399. },
  400. {
  401. field: 'manufacture',
  402. title: i18n.t('compute.text_847'),
  403. width: 70,
  404. slots: {
  405. default: ({ row }) => {
  406. if (row.sys_info && row.sys_info.oem_name) {
  407. const oem_name = row.sys_info.oem_name.replaceAll(' ', '_')
  408. const icons = {
  409. dell: { height: '25px' },
  410. hp: { height: '25px' },
  411. hpe: { height: '30px' },
  412. inspur: { height: '50px' },
  413. lenovo: { height: '10px' },
  414. supermicro: { height: '30px' },
  415. huawei: { height: '30px' },
  416. red_hat: { height: '30px' },
  417. ieit_systems: { height: '30px' },
  418. }
  419. const arr = Object.keys(icons)
  420. if (!arr.includes(oem_name)) {
  421. return row.sys_info.oem_name
  422. }
  423. const imgSrc = require(`../../physicalmachine/assets/${oem_name}.svg`)
  424. return [
  425. <a-tooltip title={ row.sys_info.oem_name }>
  426. <img src={ imgSrc } style={ icons[oem_name] } />
  427. </a-tooltip>,
  428. ]
  429. }
  430. },
  431. },
  432. formatter: ({ row }) => {
  433. if (row.sys_info && row.sys_info.oem_name) {
  434. return row.sys_info.oem_name
  435. }
  436. return '-'
  437. },
  438. },
  439. {
  440. field: 'model',
  441. title: this.$t('compute.text_580'),
  442. formatter: ({ cellValue, row }) => {
  443. return ((row.sys_info || {}).model) || '-'
  444. },
  445. },
  446. getCopyWithContentTableColumn({
  447. field: 'sn',
  448. title: this.$t('compute.text_591'),
  449. }),
  450. {
  451. field: 'host_type',
  452. title: this.$t('compute.host.host_type.title'),
  453. width: 80,
  454. formatter: ({ cellValue, row }) => {
  455. let ret = '-'
  456. if (row.host_type === 'container') {
  457. ret = this.$t('compute.host.host_type.container.title')
  458. } else if (row.host_type === 'kvm' || row.host_type === 'hypervisor') {
  459. ret = this.$t('compute.host.host_type.kvm.title')
  460. } else if (row.host_type === 'baremetal') {
  461. ret = this.$t('compute.host.host_type.baremetal.title')
  462. } else if (row.host_type) {
  463. ret = row.host_type
  464. }
  465. return ret
  466. },
  467. },
  468. {
  469. field: 'schedtags',
  470. title: i18n.t('compute.text_541'),
  471. width: 120,
  472. // type: 'expand',
  473. slots: {
  474. default: ({ row }) => {
  475. const tags = _.sortBy(row.schedtags, ['default', 'name'])
  476. if (!tags.length) {
  477. return [
  478. <div class='text-color-help'>{this.$t('compute.text_1322')}</div>,
  479. ]
  480. }
  481. const list = tags.map(tag => <a-tag class='mb-2 mr-1' color='blue'>{tag.name}</a-tag>)
  482. return [
  483. <list-body-cell-popover text={this.$t('compute.text_619', [tags.length])} max-width="400px" >
  484. <div style="display: inline-flex; flex-wrap: wrap">
  485. {...list}
  486. </div>
  487. </list-body-cell-popover>,
  488. ]
  489. },
  490. },
  491. formatter: ({ row }) => {
  492. const tags = _.sortBy(row.schedtags, ['default', 'name'])
  493. if (tags.length > 0) {
  494. return tags.map(tag => tag.name)
  495. }
  496. return this.$t('compute.text_1322')
  497. },
  498. },
  499. getBrandTableColumn(),
  500. getAccountTableColumn({ vm: this }),
  501. getPublicScopeTableColumn({ vm: this, resource: 'hosts' }),
  502. getProjectDomainTableColumn({ vm: this }),
  503. getRegionTableColumn({ vm: this }),
  504. {
  505. field: 'alert_data',
  506. title: this.$t('compute.alert_status'),
  507. hidden: () => {
  508. return this.$isScopedPolicyMenuHidden('host_hidden_columns.alert_data')
  509. },
  510. slots: {
  511. header: () => {
  512. return [<span style="margin-right:5px">{this.$t('compute.alert_status')}</span>, <help-tooltip name="alertDataTimeRange" />]
  513. },
  514. default: ({ row }) => {
  515. if (row.alert_data?.alert_state) {
  516. return [<status status={row.alert_data?.alert_state} statusModule='monitorresources' />]
  517. }
  518. return '-'
  519. },
  520. },
  521. },
  522. getTimeTableColumn(),
  523. ]
  524. },
  525. }