index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. <template>
  2. <div class="data-disk">
  3. <template v-if="dataDisks.length === 0 && (disabled || imageType === 'backup' || imageType === 'snapshot')"><span class="warning-color">{{$t('compute.text_128')}}</span></template>
  4. <template v-else>
  5. <div class="d-flex" v-for="(item, i) in dataDisks" :key="item.key">
  6. <disk
  7. :ref="'disks'"
  8. :diskKey="item.key"
  9. :max="max(i)"
  10. :min="item.min || min(i)"
  11. :form="form"
  12. :schedtagParams="getSchedtagParams()"
  13. :snapshots-params="getSnapshotsParams"
  14. :diskTypeLabel="getDiskTypeLabel(i, diskTypeLabel)"
  15. :decorator="genDecorator(item.key)"
  16. :hypervisor="hypervisor"
  17. :types-map="typesMap"
  18. :elements="elements"
  19. :disabled="getDisabled(item)"
  20. :size-disabled="item.sizeDisabled"
  21. :simplify="simplify"
  22. :storageParams="storageParams"
  23. :storageHostParams="storageHostParams"
  24. :isStorageShow="isStorageShow"
  25. :isIopsShow="isIopsShow"
  26. :isThroughputShow="isThroughputShow"
  27. :defaultIops="item.iops"
  28. :defaultThroughput="item.throughput"
  29. :iopsLimit="iopsLimit[item.key]"
  30. :isAutoResetShow="isAutoResetShow"
  31. :imageType="imageType"
  32. @snapshotChange="val => snapshotChange(item, val, i)"
  33. @diskTypeChange="val => diskTypeChange(item, val, i)"
  34. @storageHostChange="(val) => $emit('storageHostChange', val)" />
  35. <a-button v-if="!getDisabled(item, 'minus') && (dataDisks.length > 1 ? (i !== 0) : true) && isAddDiskShow" shape="circle" icon="minus" size="small" @click="decrease(item.key)" class="mt-2" />
  36. </div>
  37. <div class="d-flex align-items-center" v-if="diskRemain > 0 && !disabled && isAddDiskShow && imageType !== 'backup' && imageType !== 'snapshot'">
  38. <a-button type="primary" shape="circle" icon="plus" size="small" @click="add" />
  39. <a-button type="link" @click="add">{{$t('compute.text_129')}}</a-button>
  40. <span class="count-tips">{{$t('compute.text_130')}}<span class="remain-num">{{ diskRemain }}</span>{{$t('compute.text_131')}}</span>
  41. </div>
  42. </template>
  43. </div>
  44. </template>
  45. <script>
  46. import _ from 'lodash'
  47. import * as R from 'ramda'
  48. import Disk from '@Compute/sections/Disk'
  49. import { MEDIUM_MAP } from '@Compute/constants'
  50. import { STORAGE_TYPES } from '@/constants/compute'
  51. import { HYPERVISORS_MAP } from '@/constants'
  52. import { uuid, findAndUnshift, findAndPush } from '@/utils/utils'
  53. import { diskSupportTypeMedium, getOriginDiskKey } from '@/utils/common/hypervisor'
  54. // 磁盘最小值
  55. const DISK_MIN_SIZE = 10
  56. export default {
  57. name: 'dataDisk',
  58. components: {
  59. Disk,
  60. },
  61. props: {
  62. form: {
  63. type: Object,
  64. required: true,
  65. validator: val => val.fc,
  66. },
  67. type: {
  68. type: String,
  69. required: true,
  70. validator: val => ['idc', 'private', 'public'].includes(val),
  71. },
  72. hypervisor: {
  73. type: String,
  74. required: true,
  75. },
  76. sku: {
  77. type: Object,
  78. },
  79. simplify: {
  80. type: Boolean,
  81. default: false,
  82. },
  83. capabilityData: {
  84. type: Object,
  85. required: true,
  86. },
  87. decorator: {
  88. type: Object,
  89. required: true,
  90. validator: val => {
  91. const fields = ['type', 'size', 'schedtag', 'policy', 'snapshot', 'filetype', 'mountPath']
  92. return fields.every(f => R.is(Function, val[f]))
  93. },
  94. },
  95. disabled: {
  96. type: Boolean,
  97. default: false,
  98. },
  99. isHostImageType: {
  100. type: Boolean,
  101. default: false,
  102. },
  103. isSnapshotImageType: {
  104. type: Boolean,
  105. default: false,
  106. },
  107. domain: {
  108. type: String,
  109. default: 'default',
  110. },
  111. isWindows: {
  112. type: Boolean,
  113. default: false,
  114. },
  115. enableMointpoint: { // 允许支持挂载点(目前仅新建oncloud支持)
  116. type: Boolean,
  117. default: false, // 默认不支持挂载点
  118. },
  119. defaultType: {
  120. type: Object,
  121. },
  122. isStorageShow: {
  123. type: Boolean,
  124. default: false,
  125. },
  126. storageParams: {
  127. type: Object,
  128. },
  129. storageHostParams: Object,
  130. isIopsShow: {
  131. type: Boolean,
  132. default: false,
  133. },
  134. isThroughputShow: {
  135. type: Boolean,
  136. default: false,
  137. },
  138. isServertemplate: {
  139. type: Boolean,
  140. default: false,
  141. },
  142. isVminstanceContainer: {
  143. type: Boolean,
  144. default: false,
  145. },
  146. isAutoResetShow: {
  147. type: Boolean,
  148. default: false,
  149. },
  150. forceElements: {
  151. type: Array,
  152. },
  153. isAddDiskShow: {
  154. type: Boolean,
  155. default: true,
  156. },
  157. forceSizeDisabled: {
  158. type: Boolean,
  159. default: false,
  160. },
  161. imageType: {
  162. type: String,
  163. },
  164. isInitForm: {
  165. type: Boolean,
  166. default: false,
  167. },
  168. },
  169. data () {
  170. return {
  171. dataDisks: [],
  172. }
  173. },
  174. computed: {
  175. isPublic () {
  176. return this.type === 'public'
  177. },
  178. isPrivate () {
  179. return this.type === 'private'
  180. },
  181. isIDC () {
  182. return this.type === 'idc'
  183. },
  184. isAws () {
  185. return this.hypervisor === HYPERVISORS_MAP.aws.key
  186. },
  187. elements () {
  188. const ret = []
  189. if (this.forceElements) return this.forceElements
  190. if (this.isSnapshotImageType) return ret
  191. if (this.isHostImageType) return ['snapshot', 'schedtag']
  192. if (this.isVminstanceContainer) return ['storage', 'schedtag']
  193. if (this.enableMointpoint) {
  194. if (!this.isWindows) {
  195. if (this.hypervisor === HYPERVISORS_MAP.kvm.key) {
  196. ret.push('mount-point')
  197. }
  198. }
  199. }
  200. if (this.hypervisor === HYPERVISORS_MAP.kvm.key) {
  201. ret.push('snapshot')
  202. }
  203. if (this.form.fd.hypervisor === HYPERVISORS_MAP.esxi.key ||
  204. this.hypervisor === HYPERVISORS_MAP.esxi.key ||
  205. this.form.fd.hypervisor === HYPERVISORS_MAP.kvm.key ||
  206. this.hypervisor === HYPERVISORS_MAP.kvm.key) {
  207. ret.push('storage') // vmware,kvm支持指定存储
  208. }
  209. if (this.isIDC || this.isPrivate) {
  210. // if (this.isStorageShow) {
  211. // return ret // 指定块存储后,系统盘和数据盘均确定且不在支持设置调度标签
  212. // } else {
  213. ret.push('schedtag')
  214. // }
  215. }
  216. if (this.isAws && !this.isServertemplate) {
  217. if (this.currentTypeObj()?.key === 'gp3') {
  218. ret.push('iops', 'throughput')
  219. }
  220. if (this.currentTypeObj()?.key === 'io1') {
  221. ret.push('iops')
  222. }
  223. }
  224. return ret
  225. },
  226. iopsLimit () {
  227. const value = {}
  228. if (!this.isAws || this.isServertemplate) return value
  229. this.dataDisks.map(item => {
  230. const type = item.diskType?.key
  231. let ret = { min: 0 }
  232. // gp3 iops 不能超过磁盘500倍
  233. if (type === 'gp3') {
  234. ret = { min: 3000, max: 16000 }
  235. if (this.form.fd.dataDiskSizes?.[item.key]) {
  236. ret.max = this.form.fd.dataDiskSizes?.[item.key] * 500 < ret.max ? this.form.fd.dataDiskSizes?.[item.key] * 500 : ret.max
  237. }
  238. }
  239. // io1 iops 不能超过磁盘50倍
  240. if (type === 'io1') {
  241. ret = { min: 100, max: 64000 }
  242. if (this.form.fd.dataDiskSizes?.[item.key]) {
  243. ret.max = this.form.fd.dataDiskSizes?.[item.key] * 50 < ret.max ? this.form.fd.dataDiskSizes?.[item.key] * 50 : ret.max
  244. }
  245. }
  246. value[item.key] = ret
  247. })
  248. return value
  249. },
  250. typesMap () {
  251. const ret = {}
  252. const hyper = this.getHypervisor()
  253. const hypervisorDisks = { ...STORAGE_TYPES[hyper] } || {}
  254. if (!this.capabilityData || !this.capabilityData.data_storage_types2) return ret
  255. let currentTypes = this.capabilityData.data_storage_types2[hyper] || []
  256. if (!R.isNil(this.sku) && !R.isEmpty(this.sku)) {
  257. if (this.sku.data_disk_types) {
  258. const skuDiskTypes = this.sku.data_disk_types.split(',')
  259. if (skuDiskTypes && skuDiskTypes.length) {
  260. currentTypes = currentTypes.filter(val => {
  261. const type = val.split('/')[0]
  262. return skuDiskTypes.includes(type)
  263. })
  264. }
  265. } else {
  266. for (const obj in hypervisorDisks) {
  267. if (hypervisorDisks[obj].skuFamily && !hypervisorDisks[obj].skuFamily.includes(this.sku.instance_type_family)) {
  268. delete hypervisorDisks[obj]
  269. }
  270. }
  271. }
  272. } else {
  273. if (this.isPublic) {
  274. currentTypes = []
  275. }
  276. }
  277. if (hyper === HYPERVISORS_MAP.openstack.key) { // 前端特殊处理:openstack数据盘不支持 nova
  278. currentTypes = currentTypes.filter(val => {
  279. const types = val.split('/')
  280. if (types.length > 0) {
  281. return types[0] !== 'nova'
  282. }
  283. return true
  284. })
  285. }
  286. if (currentTypes.find(val => val.includes('local'))) {
  287. if (this.hypervisor === HYPERVISORS_MAP.google.key) {
  288. currentTypes = findAndPush(currentTypes, item => item.includes('local'))
  289. } else {
  290. currentTypes = findAndUnshift(currentTypes, item => item.includes('local'))
  291. }
  292. }
  293. for (let i = 0, len = currentTypes.length; i < len; i++) {
  294. const typeItemArr = currentTypes[i].split('/')
  295. const type = typeItemArr[0]
  296. const medium = typeItemArr[1]
  297. let opt = hypervisorDisks[type] || this.getExtraDiskOpt(type)
  298. // 磁盘区分介质
  299. if (diskSupportTypeMedium(hyper)) {
  300. opt = {
  301. ...opt,
  302. key: `${type}/${medium}`,
  303. label: `${opt.label}(${MEDIUM_MAP[medium]})`,
  304. }
  305. }
  306. if (opt) {
  307. const min = Math.max(DISK_MIN_SIZE, opt.min)
  308. let max = opt.max
  309. // 谷歌云共享核心磁盘最多为3072GB
  310. if (hyper === HYPERVISORS_MAP.google.key && this.sku && ['e2-micro', 'e2-small', 'e2-medium', 'f1-micro', 'g1-small'].includes(this.sku.name)) {
  311. max = 3072
  312. }
  313. if (opt) {
  314. ret[opt.key] = {
  315. ...opt,
  316. min,
  317. medium,
  318. max: max,
  319. }
  320. }
  321. }
  322. }
  323. // if (this.isIDC && this.hypervisor !== HYPERVISORS_MAP.kvm.key) {
  324. // ret[STORAGE_AUTO.key] = STORAGE_AUTO
  325. // }
  326. if (this.hypervisor === HYPERVISORS_MAP.qcloud.key) {
  327. delete ret.local_nvme
  328. delete ret.local_pro
  329. }
  330. return ret
  331. },
  332. diskRemain () {
  333. const remain = this.capabilityData.max_data_disk_count - this.dataDisks.length
  334. return Math.max(remain, 0)
  335. },
  336. diskTypeLabel () {
  337. return _.get(this.dataDisks, '[0].diskType.label')
  338. },
  339. getSnapshotsParams () {
  340. const staticParams = {
  341. with_meta: true,
  342. cloud_env: 'onpremise',
  343. limit: 0,
  344. disk_type: 'data',
  345. is_instance_snapshot: false,
  346. $t: uuid(),
  347. status: 'ready',
  348. os_arch: this.form.fd.os_arch,
  349. }
  350. const scopeParams = {}
  351. if (this.$store.getters.isAdminMode) {
  352. scopeParams.project_domain = this.domain
  353. } else {
  354. scopeParams.scope = this.$store.getters.scope
  355. }
  356. let diskTypeKey = _.get(this.dataDisks, '[0].diskType.key')
  357. const hypervisor = _.get(this.form.fd, 'hypervisor')
  358. if (diskTypeKey) {
  359. // 磁盘区分介质
  360. if (diskSupportTypeMedium(hypervisor)) {
  361. diskTypeKey = getOriginDiskKey(diskTypeKey)
  362. }
  363. staticParams['joint_filter.0'] = `storages.id(storage_id).storage_type.equals(${diskTypeKey})`
  364. }
  365. return {
  366. ...staticParams,
  367. ...scopeParams,
  368. }
  369. },
  370. },
  371. watch: {
  372. typesMap (v, oldV) {
  373. if (!R.equals(v, oldV)) {
  374. if (this.dataDisks && this.dataDisks.length) {
  375. this.dataDisks.forEach((disk, index) => {
  376. this.form.fc.setFieldsValue({
  377. [`dataDiskSizes[${disk.key}]`]: Math.max((disk.value || 0), this.min(index)),
  378. })
  379. if (this.isInitForm) return
  380. if (!disk.disabled) this.decrease(disk.key)
  381. })
  382. }
  383. }
  384. },
  385. defaultType (v, oldV) {
  386. // vmware系统盘改变清空数据盘,忽略调整配置初始化的情况
  387. if (this.getHypervisor() === HYPERVISORS_MAP.esxi.key && oldV && oldV.label) {
  388. this.dataDisks = []
  389. }
  390. },
  391. },
  392. methods: {
  393. currentTypeObj (index = 0) {
  394. // 非阿里云 数据盘仅第一块盘的磁盘类型可以修改
  395. const diskTypeKey = _.get(this.dataDisks, `[${index}].diskType.key`)
  396. if (diskTypeKey) {
  397. return this.typesMap[diskTypeKey]
  398. }
  399. if (!R.isNil(this.typesMap) && !R.isEmpty(this.typesMap)) {
  400. const firstKey = Object.keys(this.typesMap)[0]
  401. return this.typesMap[firstKey]
  402. }
  403. return {}
  404. },
  405. currentDiskCapability (index = 0) {
  406. if (this.hypervisor !== HYPERVISORS_MAP.kvm.key) return {}
  407. const instance_capabilities = this.capabilityData.instance_capabilities || []
  408. const storages = instance_capabilities.find(item => item.hypervisor === this.hypervisor)?.storages || {}
  409. const data_disk = storages.data_disk || []
  410. const currentDisk = data_disk.find(item => this.currentTypeObj(index).key?.startsWith(item.storage_type))
  411. return currentDisk
  412. },
  413. max (index = 0) {
  414. return this.currentDiskCapability(index)?.max_size_gb || this.currentTypeObj(index)?.max || DISK_MIN_SIZE
  415. },
  416. min (index = 0) {
  417. return this.currentDiskCapability(index)?.min_size_gb || this.currentTypeObj(index)?.min || DISK_MIN_SIZE
  418. },
  419. getDisabled (item, itemName) {
  420. if (item.disabled) return true
  421. if (itemName && item[`${itemName}Disabled`]) {
  422. return true // 这里目前仅针对 minus 按钮
  423. }
  424. return this.disabled
  425. },
  426. genDecorator (uid) {
  427. const ret = {}
  428. R.forEachObjIndexed((item, key) => {
  429. ret[key] = item(uid)
  430. }, this.decorator)
  431. return ret
  432. },
  433. decrease (key) {
  434. const index = this.dataDisks.findIndex(val => val.key === key)
  435. this.dataDisks.splice(index, 1)
  436. this.$nextTick(() => {
  437. if (index === 0 && this.dataDisks.length > 0) {
  438. const key = `dataDiskTypes[${this.dataDisks[0].key}]`
  439. const defaultKey = Object.keys(this.typesMap)[0]
  440. if (defaultKey) {
  441. const dataDiskTypes = {
  442. key: this.typesMap[defaultKey].key,
  443. label: this.typesMap[defaultKey].label,
  444. }
  445. this.form.fc.setFieldsValue({
  446. [key]: dataDiskTypes,
  447. })
  448. }
  449. }
  450. const formValue = this.form.fc.getFieldsValue()
  451. if (this.form.fd) { // 如果上层表单有fd时,需要在此同步数据(外层监听不到减少表单的情况)
  452. this.form.fd.dataDiskSizes = formValue.dataDiskSizes || {}
  453. }
  454. })
  455. },
  456. add ({ size, diskType, policy, schedtag, snapshot, filetype, mountPath, min, disabled = false, sizeDisabled = false, medium, preallocation, autoReset, ...ret } = {}) {
  457. const key = uuid()
  458. let newDiskType = diskType
  459. // 磁盘区分介质
  460. if (this.hypervisor && diskSupportTypeMedium(this.hypervisor) && medium) {
  461. newDiskType = `${diskType}/${medium}`
  462. }
  463. const typeObj = this.typesMap[newDiskType]
  464. const idx = this.dataDisks?.length || 0
  465. let dataDiskTypes = {
  466. key: _.get(this.dataDisks, '[0].diskType.key'),
  467. label: _.get(this.dataDisks, '[0].diskType.label'),
  468. index: idx,
  469. }
  470. if (R.is(Object, typeObj)) { // 传入diskType,回填
  471. dataDiskTypes = {
  472. key: typeObj.key || diskType,
  473. label: typeObj.label || diskType,
  474. index: idx,
  475. }
  476. } else if (!diskType && !_.get(this.dataDisks, '[0].diskType')) { // 表单中数据盘无第一项,需要 set 磁盘类型默认值
  477. const defaultKey = Object.keys(this.typesMap)[0]
  478. if (R.is(Object, this.defaultType) && this.defaultType.key && this.defaultType.label && this.typesMap[this.defaultType.key]) {
  479. dataDiskTypes = {
  480. ...this.defaultType,
  481. index: idx,
  482. }
  483. } else if (defaultKey) {
  484. dataDiskTypes = {
  485. key: this.typesMap[defaultKey].key,
  486. label: this.typesMap[defaultKey].label,
  487. index: idx,
  488. }
  489. }
  490. }
  491. const dataDiskItem = {
  492. key,
  493. disabled,
  494. sizeDisabled,
  495. diskType: dataDiskTypes,
  496. ...ret, // 目前仅用于 minus 按钮
  497. }
  498. if (min) {
  499. dataDiskItem.min = Math.max(min, this.min(idx), DISK_MIN_SIZE)
  500. }
  501. this.dataDisks.push(dataDiskItem)
  502. this.$nextTick(() => {
  503. const configs = {}
  504. const value = {
  505. [`dataDiskSizes[${key}]`]: R.is(Number, size) ? size : (min || this.min(idx)),
  506. }
  507. value[`dataDiskTypes[${key}]`] = dataDiskTypes
  508. if (schedtag) { // 磁盘调度标签
  509. configs.showAdvanced = true
  510. configs.showSchedtag = true
  511. value[`dataDiskSchedtags[${key}]`] = schedtag
  512. }
  513. if (policy) { // 磁盘调度策略
  514. value[`dataDiskPolicys[${key}]`] = policy
  515. configs.showAdvanced = true
  516. configs.showSchedtag = true
  517. }
  518. if (snapshot && (filetype || mountPath)) {
  519. console.error(this.$t('compute.text_132'))
  520. }
  521. if (snapshot) { // 磁盘快照
  522. value[`dataDiskSnapshots[${key}]`] = snapshot
  523. configs.showAdvanced = true
  524. configs.showSnapshot = true
  525. }
  526. if (filetype) { // 磁盘文件系统
  527. value[`dataDiskFiletypes[${key}]`] = filetype
  528. configs.showAdvanced = true
  529. configs.showMountpoint = true
  530. }
  531. if (mountPath) { // 磁盘挂载路径
  532. value[`dataDiskMountPaths[${key}]`] = mountPath
  533. configs.showAdvanced = true
  534. configs.showMountpoint = true
  535. }
  536. if (autoReset) {
  537. value[`dataDiskAutoReset[${key}]`] = autoReset
  538. configs.showAdvanced = true
  539. configs.isAutoResetShow = true
  540. }
  541. if (this.getHypervisor() === HYPERVISORS_MAP.esxi.key) {
  542. value[`dataDiskPreallocation[${key}]`] = preallocation
  543. configs.showAdvanced = true
  544. configs.showPreallocation = true
  545. }
  546. if (configs.showAdvanced) {
  547. setTimeout(() => {
  548. this.$refs.disks[this.dataDisks.findIndex(val => val.key === key)].setValues(configs)
  549. setTimeout(() => {
  550. this.form.fc.setFieldsValue(value)
  551. }, 1000)
  552. this.setDiskMedium(dataDiskTypes)
  553. }, 1000)
  554. } else {
  555. this.form.fc.setFieldsValue(value)
  556. this.setDiskMedium(dataDiskTypes)
  557. }
  558. })
  559. },
  560. getExtraDiskOpt (type) {
  561. // 腾讯云过滤掉local_basic和local_ssd类型的盘
  562. if (this.getHypervisor() === HYPERVISORS_MAP.qcloud.key) {
  563. if (['local_basic', 'local_ssd'].includes(type)) {
  564. return
  565. }
  566. }
  567. // VMware过滤掉rbd类型的盘
  568. if (this.getHypervisor() === HYPERVISORS_MAP.esxi.key) {
  569. if (['rbd'].includes(type)) {
  570. return
  571. }
  572. }
  573. return {
  574. label: `${type}`,
  575. key: `${type}`,
  576. min: 1,
  577. max: 3 * 1024,
  578. sysMin: 10,
  579. sysMax: 500,
  580. }
  581. },
  582. getHypervisor () {
  583. let ret = this.hypervisor
  584. if (this.isPublic) {
  585. if (this.sku && this.sku.provider) {
  586. ret = this.sku.provider.toLowerCase()
  587. }
  588. }
  589. return ret
  590. },
  591. getSchedtagParams () {
  592. const params = {
  593. with_meta: true,
  594. resource_type: 'storages',
  595. limit: 0,
  596. }
  597. const scopeParams = {}
  598. if (this.$store.getters.isAdminMode) {
  599. scopeParams.project_domain = this.domain
  600. } else {
  601. scopeParams.scope = this.$store.getters.scope
  602. }
  603. return {
  604. ...params,
  605. ...scopeParams,
  606. }
  607. },
  608. diskTypeChange (item, val) {
  609. if (!this.forceSizeDisabled) {
  610. item.sizeDisabled = false
  611. }
  612. // 非阿里云 仅第一块盘可以更改磁盘类型
  613. if (this.getHypervisor() !== HYPERVISORS_MAP.aliyun.key) {
  614. this.$nextTick(() => {
  615. if (!this.forceSizeDisabled) {
  616. const dataDiskItem = {
  617. ...item,
  618. diskType: val,
  619. }
  620. if (item.min) {
  621. dataDiskItem.min = Math.max(item.min, this.min(0))
  622. }
  623. this.$set(this.dataDisks, 0, dataDiskItem)
  624. this.form.fc.setFieldsValue({
  625. [`dataDiskSizes[${item.key}]`]: Math.max((dataDiskItem.min || 0), this.min(0)),
  626. })
  627. }
  628. // 数据盘更改类型
  629. if (val.key !== item.diskType?.key) {
  630. const { dataDiskSizes = {} } = this.form.fd
  631. for (const diskId in dataDiskSizes) {
  632. const curDiskType = this.form.fd[`dataDiskTypes[${diskId}]`]
  633. if (curDiskType) {
  634. this.form.fc.setFieldsValue({
  635. [`dataDiskTypes[${diskId}]`]: { ...val, index: curDiskType?.index },
  636. })
  637. }
  638. }
  639. }
  640. this.setDiskMedium(val)
  641. })
  642. } else {
  643. this.$nextTick(() => {
  644. if (!this.forceSizeDisabled) {
  645. const dataDiskItem = {
  646. ...item,
  647. diskType: val,
  648. }
  649. const index = this.dataDisks.findIndex(val => val.key === item.key)
  650. if (item.min) {
  651. dataDiskItem.min = Math.max(item.min, this.min(index))
  652. }
  653. this.$set(this.dataDisks, index || 0, dataDiskItem)
  654. this.form.fc.setFieldsValue({
  655. [`dataDiskSizes[${item.key}]`]: Math.max((dataDiskItem.min || 0), this.min(index)),
  656. })
  657. }
  658. // 数据盘更改类型
  659. if (val.key !== item.diskType?.key) {
  660. const { dataDiskSizes = {} } = this.form.fd
  661. for (const diskId in dataDiskSizes) {
  662. const curDiskType = this.form.fd[`dataDiskTypes[${diskId}]`]
  663. if (curDiskType && diskId === val.key) {
  664. this.form.fc.setFieldsValue({
  665. [`dataDiskTypes[${diskId}]`]: { ...val, index: curDiskType?.index },
  666. })
  667. }
  668. }
  669. }
  670. this.setDiskMedium(val)
  671. })
  672. }
  673. },
  674. snapshotChange (item, val, i) {
  675. this.form.fc.setFieldsValue({
  676. [`dataDiskSizes[${item.key}]`]: val,
  677. })
  678. item.sizeDisabled = true
  679. },
  680. setDiskMedium (v) {
  681. if (this.form.fi) {
  682. this.$set(this.form.fi, 'dataDiskMedium', _.get(this.typesMap, `[${v.key}].medium`))
  683. }
  684. },
  685. getDiskTypeLabel (i, diskTypeLabel) {
  686. if (this.getHypervisor() === HYPERVISORS_MAP.esxi.key) {
  687. return this.$te(`common.storage.${diskTypeLabel}`) ? this.$t(`common.storage.${diskTypeLabel}`) : diskTypeLabel
  688. }
  689. if (i === 0 || this.getHypervisor() === HYPERVISORS_MAP.aliyun.key) {
  690. return ''
  691. }
  692. if (this.$te(`common.storage.${diskTypeLabel}`)) {
  693. return this.$t(`common.storage.${diskTypeLabel}`)
  694. }
  695. if (_.get(this.typesMap, `[${diskTypeLabel}].label`)) {
  696. return _.get(this.typesMap, `[${diskTypeLabel}].label`)
  697. }
  698. return diskTypeLabel
  699. },
  700. isSomeLocal (types) {
  701. const localTypes = types.filter(item => item.indexOf('local') !== -1)
  702. return localTypes.length > 1
  703. },
  704. },
  705. }
  706. </script>
  707. <style lang="less" scoped>
  708. @import '~@/styles/less/theme';
  709. .data-disk {
  710. .count-tips {
  711. .remain-num {
  712. color: @primary-color;
  713. }
  714. }
  715. }
  716. </style>