List.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <template>
  2. <page-list
  3. show-tag-columns
  4. show-tag-columns2
  5. show-tag-filter
  6. :list="list"
  7. :columns="templateListColumns || columns"
  8. :group-actions="groupActions"
  9. :single-actions="singleActions"
  10. :export-data-options="exportDataOptions"
  11. :showSearchbox="showSearchbox"
  12. :showSingleActions="isTemplate ? false : showActions"
  13. :showGroupActions="showActions && showGroupActions"
  14. :before-show-menu="beforeShowMenu"
  15. :show-page="!isTemplate" />
  16. </template>
  17. <script>
  18. import * as R from 'ramda'
  19. import { mapGetters } from 'vuex'
  20. import {
  21. getTenantFilter,
  22. getStatusFilter,
  23. getBrandFilter,
  24. getNameFilter,
  25. getDomainFilter,
  26. getAccountFilter,
  27. getRegionFilter,
  28. getDescriptionFilter,
  29. getGuestStatusFilter,
  30. getDistinctFieldsFilter,
  31. } from '@/utils/common/tableFilter'
  32. import { getDisabledProvidersActionMeta } from '@/utils/common/hypervisor'
  33. import { diskResizeConfig } from '@Compute/views/disk/utils'
  34. import expectStatus from '@/constants/expectStatus'
  35. import WindowsMixin from '@/mixins/windows'
  36. import GlobalSearchMixin from '@/mixins/globalSearch'
  37. import ListMixin from '@/mixins/list'
  38. import ResTemplateListMixin from '@/mixins/resTemplateList'
  39. import { PROVIDER_MAP } from '@/constants'
  40. import SingleActionsMixin from '../mixins/singleActions'
  41. import ColumnsMixin from '../mixins/columns'
  42. import { MEDIUM_MAP } from '../../../constants'
  43. export default {
  44. name: 'DiskList',
  45. mixins: [WindowsMixin, ListMixin, GlobalSearchMixin, ColumnsMixin, SingleActionsMixin, ResTemplateListMixin],
  46. props: {
  47. id: String,
  48. getParams: {
  49. type: [Function, Object],
  50. },
  51. cloudEnv: String,
  52. cloudEnvOptions: {
  53. type: Array,
  54. },
  55. showCreateAction: {
  56. type: Boolean,
  57. default: true,
  58. },
  59. hiddenColumns: {
  60. type: Array,
  61. default: () => ([]),
  62. },
  63. hiddenFilterOptions: {
  64. type: Array,
  65. default: () => ([]),
  66. },
  67. },
  68. data () {
  69. const filter = {}
  70. if (this.$route.query.hasOwnProperty('unused')) {
  71. filter.unused = [this.$route.query.unused]
  72. }
  73. const { medium_type } = this.$route.query
  74. if (medium_type) {
  75. filter.medium_type = R.is(Array, medium_type) ? medium_type : [medium_type]
  76. }
  77. const createAction = {
  78. label: this.$t('compute.perform_create'),
  79. permission: 'disks_create',
  80. action: () => {
  81. this.$router.push({
  82. path: '/disk/create',
  83. query: {
  84. type: this.cloudEnv,
  85. },
  86. })
  87. // return [
  88. // {
  89. // label: 'IDC',
  90. // permission: 'disks_create',
  91. // action: () => {
  92. // this.createDialog('DiskCreateDialog', {
  93. // title: this.$t('compute.perform_create'),
  94. // onManager: this.onManager,
  95. // diskType: 'idc',
  96. // })
  97. // },
  98. // },
  99. // {
  100. // label: this.$t('compute.text_400'),
  101. // permission: 'disks_create',
  102. // action: () => {
  103. // this.createDialog('DiskCreateDialog', {
  104. // title: this.$t('compute.perform_create'),
  105. // onManager: this.onManager,
  106. // diskType: 'private',
  107. // })
  108. // },
  109. // },
  110. // {
  111. // label: this.$t('compute.text_401'),
  112. // permission: 'disks_create',
  113. // action: () => {
  114. // this.createDialog('DiskCreateDialog', {
  115. // title: this.$t('compute.perform_create'),
  116. // onManager: this.onManager,
  117. // diskType: 'public',
  118. // })
  119. // },
  120. // },
  121. // ]
  122. },
  123. meta: () => ({
  124. buttonType: 'primary',
  125. validate: !this.cloudEnvEmpty,
  126. tooltip: this.cloudEnvEmpty ? this.$t('common.no_platform_available') : '',
  127. }),
  128. hidden: () => this.$isScopedPolicyMenuHidden('disk_hidden_menus.disk_create'),
  129. }
  130. const groupActions = [
  131. {
  132. label: this.$t('compute.text_275'),
  133. actions: () => {
  134. return [
  135. {
  136. label: this.$t('compute.perform_sync_status'),
  137. permission: 'disks_perform_syncstatus',
  138. action: () => {
  139. this.onManager('batchPerformAction', {
  140. steadyStatus: ['running', 'ready'],
  141. managerArgs: {
  142. action: 'syncstatus',
  143. },
  144. })
  145. },
  146. meta: () => {
  147. var ret = {
  148. validate: true,
  149. tooltip: '',
  150. }
  151. const isSomeVMware = this.list.selectedItems.some(v => v.provider === PROVIDER_MAP.VMware.key)
  152. if (isSomeVMware) {
  153. ret.validate = false
  154. ret.tooltip = this.$t('compute.text_450')
  155. return ret
  156. }
  157. return ret
  158. },
  159. extraMeta: obj => {
  160. return getDisabledProvidersActionMeta({
  161. rows: this.list.selectedItems,
  162. disabledProviders: ['SangFor'],
  163. })
  164. },
  165. hidden: () => this.$isScopedPolicyMenuHidden('disk_hidden_menus.disk_perform_syncstatus'),
  166. },
  167. {
  168. label: this.$t('table.action.set_tag'),
  169. permission: 'disks_perform_set_user_metadata',
  170. action: () => {
  171. this.createDialog('SetTagDialog', {
  172. data: this.list.selectedItems,
  173. columns: this.columns,
  174. onManager: this.onManager,
  175. mode: 'add',
  176. params: {
  177. resources: 'disk',
  178. },
  179. tipName: this.$t('compute.text_100'),
  180. })
  181. },
  182. extraMeta: obj => {
  183. return getDisabledProvidersActionMeta({
  184. rows: this.list.selectedItems,
  185. disabledProviders: ['BingoCloud'],
  186. })
  187. },
  188. // hidden: () => this.$isScopedPolicyMenuHidden('disk_hidden_menus.disk_perform_set_tags'),
  189. },
  190. {
  191. label: this.$t('compute.disk_perform_resize'),
  192. permission: 'disks_perform_resize',
  193. action: obj => {
  194. this.createDialog('DiskCapacityUpdateDialog', {
  195. data: this.list.selectedItems,
  196. columns: this.columns,
  197. refresh: this.refresh,
  198. })
  199. },
  200. meta: () => {
  201. const ret = { validate: true, tooltip: '' }
  202. this.list.selectedItems.forEach(obj => {
  203. const provider = obj.provider?.toLowerCase()
  204. if (diskResizeConfig[provider]) {
  205. if (!diskResizeConfig[provider](obj).validate) {
  206. ret.validate = false
  207. ret.tooltip = diskResizeConfig[provider](obj).tooltip
  208. return ret
  209. }
  210. }
  211. if (obj.status === 'migrating') {
  212. ret.validate = false
  213. ret.tooltip = this.$t('compute.disk_migrating_tip')
  214. return ret
  215. }
  216. })
  217. return ret
  218. },
  219. extraMeta: obj => {
  220. const ret = { validate: true, tooltip: '' }
  221. this.list.selectedItems.forEach(obj => {
  222. const v = getDisabledProvidersActionMeta({
  223. row: obj,
  224. disabledProviders: ['BingoCloud', 'SangFor'],
  225. })
  226. if (!v.validate) {
  227. ret.validate = false
  228. ret.tooltip = v.tooltip
  229. }
  230. })
  231. return ret
  232. },
  233. hidden: () => this.$isScopedPolicyMenuHidden('disk_hidden_menus.disk_perform_resize'),
  234. },
  235. {
  236. label: this.$t('compute.perform_delete'),
  237. permission: 'disks_delete',
  238. action: () => {
  239. this.createDialog('DiskDeleteDialog', {
  240. data: this.list.selectedItems,
  241. columns: this.columns,
  242. title: this.$t('compute.perform_delete'),
  243. onManager: this.onManager,
  244. })
  245. },
  246. meta: () => this.$getDeleteResult(this.list.selectedItems),
  247. extraMeta: obj => {
  248. return getDisabledProvidersActionMeta({
  249. rows: this.list.selectedItems,
  250. disabledProviders: ['BingoCloud'],
  251. })
  252. },
  253. hidden: () => this.$isScopedPolicyMenuHidden('disk_hidden_menus.disk_delete'),
  254. },
  255. ]
  256. },
  257. meta: () => {
  258. return {
  259. validate: this.list.selected.length,
  260. }
  261. },
  262. },
  263. ]
  264. if (this.showCreateAction) {
  265. groupActions.unshift(createAction)
  266. }
  267. const filterOptions = {
  268. id: {
  269. label: this.$t('table.title.id'),
  270. },
  271. name: getNameFilter(),
  272. description: getDescriptionFilter(),
  273. status: getStatusFilter('disk'),
  274. storage: {
  275. label: this.$t('table.title.disk_storage'),
  276. jointFilter: true,
  277. },
  278. server_id: getDistinctFieldsFilter({
  279. field: ['id', 'name'],
  280. type: 'extra_field',
  281. label: this.$t('res.server'),
  282. dropdown: true,
  283. mapper: (list, data) => {
  284. const { extra_fields = [] } = data
  285. const ret = extra_fields.map(item => ({ label: item.name, key: item.id })).filter(item => item.label && item.key)
  286. const ret2 = ret.map(item => {
  287. const len = ret.filter(l => l.label === item.label).length
  288. if (len > 1) {
  289. item.label = `${item.label} (${(item.key || '').substring(0, 6)})`
  290. }
  291. return item
  292. })
  293. return ret2
  294. },
  295. getParams: { extra_resource: 'server' },
  296. }),
  297. disk_type: {
  298. label: this.$t('table.title.disk_type'),
  299. dropdown: true,
  300. // multiple: true,
  301. items: [
  302. { label: this.$t('compute.text_50'), key: 'data' },
  303. { label: this.$t('compute.text_49'), key: 'sys' },
  304. ],
  305. },
  306. unused: {
  307. label: this.$t('table.title.disk_mounted'),
  308. hiddenField: 'guest_count',
  309. dropdown: true,
  310. items: [
  311. { label: this.$t('compute.text_394'), key: 'false' },
  312. { label: this.$t('compute.text_395'), key: 'true' },
  313. ],
  314. },
  315. brand: getBrandFilter(),
  316. projects: getTenantFilter(),
  317. project_domains: getDomainFilter(),
  318. account: getAccountFilter(),
  319. region: getRegionFilter(),
  320. medium_type: {
  321. label: this.$t('table.title.disk_medium_type'),
  322. dropdown: true,
  323. multiple: true,
  324. jointFilter: true,
  325. filter: true,
  326. formatter: val => {
  327. return `storages.id(storage_id).medium_type.equals(${val})`
  328. },
  329. items: Object.keys(MEDIUM_MAP).map((k) => {
  330. return { label: MEDIUM_MAP[k], key: k }
  331. }),
  332. },
  333. guest_status: getGuestStatusFilter({ hiddenField: 'guest' }),
  334. }
  335. for (let i = 0, len = this.hiddenFilterOptions.length; i < len; i++) {
  336. delete filterOptions[this.hiddenFilterOptions[i]]
  337. }
  338. return {
  339. list: this.$list.createList(this, {
  340. ctx: this,
  341. id: this.id,
  342. resource: 'disks',
  343. getParams: this.getParam,
  344. isTemplate: this.isTemplate,
  345. templateLimit: this.templateLimit,
  346. filterOptions,
  347. filter,
  348. steadyStatus: {
  349. status: Object.values(expectStatus.disk).flat(),
  350. guest_status: [...Object.values(expectStatus.server).flat(), '', undefined],
  351. },
  352. responseData: this.responseData,
  353. hiddenColumns: this.hiddenColumns, // ['metadata', 'disk_format', 'storage', 'medium_type', 'created_at'],
  354. autoHiddenFilterKey: 'disk_hidden_columns',
  355. }),
  356. groupActions,
  357. }
  358. },
  359. computed: {
  360. ...mapGetters(['isProjectMode']),
  361. showActions () {
  362. return !this.$isScopedPolicyMenuHidden('disk_hidden_columns.perform_action')
  363. },
  364. exportDataOptions () {
  365. return {
  366. downloadType: 'local',
  367. title: this.$t('compute.text_100'),
  368. items: [
  369. { label: 'ID', key: 'id' },
  370. { field: 'external_id', label: this.$t('table.title.external_id') },
  371. ...this.columns,
  372. ],
  373. fixedItems: [
  374. { key: 'disk_size', label: this.$t('table.title.disk_size') + '(M)' },
  375. ],
  376. }
  377. },
  378. },
  379. watch: {
  380. cloudEnv (val) {
  381. this.$nextTick(() => {
  382. this.list.fetchData(0)
  383. })
  384. },
  385. },
  386. created () {
  387. this.initSidePageTab('disk-detail')
  388. this.list.fetchData()
  389. },
  390. methods: {
  391. getParam () {
  392. const ret = { ...(R.is(Function, this.getParams) ? this.getParams() : this.getParams) }
  393. if (this.cloudEnv) ret.cloud_env = this.cloudEnv
  394. return ret
  395. },
  396. handleOpenSidepage (row, tab) {
  397. this.initSidePageTab('disk-detail')
  398. this.sidePageTriggerHandle(this, 'DiskSidePage', {
  399. id: row.id,
  400. resource: 'disks',
  401. getParams: this.getParam,
  402. steadyStatus: {
  403. status: Object.values(expectStatus.disk).flat(),
  404. guest_status: [...Object.values(expectStatus.server).flat(), '', undefined],
  405. },
  406. }, {
  407. list: this.list,
  408. hiddenColumns: this.hiddenColumns,
  409. tab,
  410. })
  411. },
  412. beforeShowMenu () {
  413. return this.$store.dispatch('scopedPolicy/get', {
  414. category: ['disk_hidden_menus'],
  415. })
  416. },
  417. },
  418. }
  419. </script>