Public.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <template>
  2. <div>
  3. <a-form
  4. class="mt-3"
  5. :form="form.fc"
  6. v-bind="formItemLayout"
  7. @submit="submit"
  8. hideRequiredMark>
  9. <a-form-item :label="$t('compute.text_297', [$t('dictionary.project')])" v-show="false">
  10. <domain-project
  11. :fc="form.fc"
  12. :fd="form.fd"
  13. :decorators="{ project: decorators.project, domain: decorators.domain }"
  14. @fetchDomainCallback="fetchDomainCallback"
  15. @fetchProjectCallback="fetchProjectCallback" />
  16. </a-form-item>
  17. <a-form-item class="mb-0" :label="$t('compute.text_498')">
  18. <bill :decorators="decorators.bill" :form="form" :provider-list="form.fi.providerList" :disabledBillType="disabledBillType" />
  19. </a-form-item>
  20. <a-form-item :label="$t('compute.text_294')">
  21. <a-input-number v-decorator="decorators.count" @blur="countBlur" :min="1" :max="100" />
  22. </a-form-item>
  23. <area-selects
  24. class="mb-0"
  25. v-if="showAreaSelect"
  26. :wrapperCol="formItemLayout.wrapperCol"
  27. :labelCol="formItemLayout.labelCol"
  28. ref="areaSelectRef"
  29. :providerParams="providerParams"
  30. :cloudregionParams="cloudregionParams"
  31. :zoneParams="zoneParams"
  32. :defaultActiveFirstOption="['provider']"
  33. filterBrandResource="compute_engine"
  34. @providerFetchSuccess="providerFetchSuccess" />
  35. <a-form-item :label="$t('compute.text_1058')" class="mb-0">
  36. <cpu-radio :decorator="decorators.vcpu" :options="form.fi.cpuMem.cpus || []" @change="cpuChange" />
  37. </a-form-item>
  38. <a-form-item :label="$t('compute.text_369')" class="mb-0">
  39. <mem-radio :decorator="decorators.vmem" :options="form.fi.cpuMem.mems_mb || []" />
  40. </a-form-item>
  41. <a-form-item :label="$t('compute.text_109')">
  42. <sku
  43. v-decorator="decorators.sku"
  44. :priceUnit="skuPriceUnit"
  45. :type="type"
  46. :sku-params="skuParam"
  47. :hypervisor="hypervisor"
  48. :hasMeterService="hasMeterService" />
  49. </a-form-item>
  50. <a-form-item :label="$t('compute.text_49')" class="mb-0">
  51. <system-disk
  52. v-if="form.fd.sku"
  53. :decorator="decorators.systemDisk"
  54. :type="type"
  55. :form="form"
  56. :hypervisor="hypervisor"
  57. :sku="form.fd.sku"
  58. :capability-data="form.fi.capability"
  59. :image="form.fi.imageMsg" />
  60. </a-form-item>
  61. <a-form-item :label="$t('compute.text_50')">
  62. <data-disk
  63. v-if="form.fd.sku"
  64. :decorator="decorators.dataDisk"
  65. :type="type"
  66. :form="form"
  67. :hypervisor="hypervisor"
  68. :sku="form.fd.sku"
  69. :defaultType="form.fd.systemDiskType"
  70. :capability-data="form.fi.capability"
  71. :simplify="true"
  72. ref="dataDiskRef" />
  73. </a-form-item>
  74. <bottom-bar
  75. ref="bottomBarRef"
  76. :loading="submiting"
  77. :form="form"
  78. :errors.sync="errors"
  79. :type="type"
  80. :resourceType="form.fd.resourceType"
  81. :dataDiskSizes="dataDiskSizes"
  82. :isOpenWorkflow="isOpenWorkflow"
  83. :isServertemplate="isServertemplate"
  84. :hasMeterService="hasMeterService" />
  85. </a-form>
  86. </div>
  87. </template>
  88. <script>
  89. import * as R from 'ramda'
  90. import Bill from '../components/Bill'
  91. import mixin from './mixin'
  92. import { LOGIN_TYPES_MAP, BILL_TYPES_MAP } from '@Compute/constants'
  93. import { resolveValueChangeField } from '@/utils/common/ant'
  94. import { PROVIDER_MAP, HYPERVISORS_MAP } from '@/constants'
  95. import AreaSelects from '@/sections/AreaSelects'
  96. export default {
  97. name: 'VMPublicCreate',
  98. components: {
  99. Bill,
  100. AreaSelects,
  101. },
  102. mixins: [mixin],
  103. computed: {
  104. // 是否为包年包月
  105. isPackage () {
  106. return this.form.fd.billType === BILL_TYPES_MAP.package.key
  107. },
  108. showAreaSelect () {
  109. if (this.$store.getters.isAdminMode && this.$store.getters.l3PermissionEnable) {
  110. if (this.form.fd.domain && this.form.fd.domain.key) {
  111. return true
  112. } else {
  113. return false
  114. }
  115. }
  116. return true
  117. },
  118. networkParam () {
  119. if (!this.cloudregionZoneParams.cloudregion) return {}
  120. const params = {
  121. filter: 'server_type.notin(ipmi, pxe)',
  122. usable: true,
  123. ...this.cloudregionZoneParams,
  124. ...this.scopeParams,
  125. }
  126. return params
  127. },
  128. providerParams () {
  129. return {
  130. usable: true,
  131. public_cloud: true,
  132. scope: this.$store.getters.scope,
  133. }
  134. },
  135. cloudregionParams () {
  136. return {
  137. cloud_env: 'public',
  138. usable: true,
  139. show_emulated: true,
  140. scope: this.$store.getters.scope,
  141. }
  142. },
  143. zoneParams () {
  144. return {
  145. cloud_env: 'public',
  146. usable: true,
  147. show_emulated: true,
  148. order_by: 'created_at',
  149. order: 'asc',
  150. scope: this.$store.getters.scope,
  151. }
  152. },
  153. cacheImageParams () {
  154. const params = {}
  155. if (R.is(Object, this.form.fd.sku)) {
  156. if (this.cloudregionZoneParams.cloudregion) {
  157. params.cloudregion_id = this.cloudregionZoneParams.cloudregion
  158. }
  159. }
  160. if (!params.cloudregion_id) return {}
  161. return params
  162. },
  163. eipParams () {
  164. if (!this.cloudregionZoneParams.cloudregion) return {}
  165. return {
  166. project: this.project,
  167. region: this.cloudregionZoneParams.cloudregion,
  168. }
  169. },
  170. skuPriceUnit () {
  171. if (this.isPackage) {
  172. return {
  173. key: 'month_price',
  174. unit: this.$t('compute.text_173'),
  175. }
  176. }
  177. return {
  178. key: 'hour_price',
  179. unit: this.$t('compute.text_172'),
  180. }
  181. },
  182. skuParam () {
  183. const params = {
  184. public_cloud: true,
  185. limit: 0,
  186. cpu_core_count: this.form.fd.vcpu || this.decorators.vcpu[1].initialValue,
  187. memory_size_mb: this.form.fd.vmem,
  188. usable: true,
  189. enabled: true,
  190. ...this.scopeParams,
  191. }
  192. if (this.$store.getters.isAdminMode) {
  193. delete params.project_domain
  194. }
  195. if (this.form.fd.cloudregion) params.cloudregion = this.form.fd.cloudregion
  196. if (this.form.fd.zone) params.zone_id = this.form.fd.zone
  197. const { provider } = this.form.fd
  198. if (provider) {
  199. params.provider = PROVIDER_MAP[provider] ? PROVIDER_MAP[provider].hypervisor : provider
  200. } else {
  201. const providerList = this.form.fi.providerList
  202. if (providerList && providerList.length) {
  203. const providers = providerList.map(item => item.name)
  204. params.filter = `provider.in(${providers.join(',')})`
  205. } else { // 公有云条件下没有 provider 不用请求接口
  206. return {} // sku 组件没有参数不会请求数据
  207. }
  208. }
  209. if (this.form.fd.billType === 'quantity') {
  210. params.postpaid_status = 'available'
  211. } else if (this.form.fd.billType === 'package') {
  212. params.prepaid_status = 'available'
  213. }
  214. return params
  215. },
  216. policyHostParams () {
  217. const params = {
  218. show_emulated: true,
  219. resource_type: 'shared',
  220. enabled: 1,
  221. usable: true,
  222. limit: 0,
  223. }
  224. if (this.cloudregionZoneParams) {
  225. params.zone = this.cloudregionZoneParams.zone
  226. if (!params.zone) {
  227. params.cloudregion = this.cloudregionZoneParams.cloudregion
  228. }
  229. }
  230. if (!params.zone && !params.cloudregion) {
  231. return // 此时将不请求接口
  232. }
  233. return params
  234. },
  235. hypervisor () {
  236. if (R.is(Object, this.form.fd.sku)) {
  237. const { provider } = this.form.fd.sku
  238. if (provider) {
  239. return PROVIDER_MAP[provider].hypervisor
  240. }
  241. }
  242. return ''
  243. },
  244. loginTypes () {
  245. const loginTypes = { ...LOGIN_TYPES_MAP }
  246. const hypervisor = this.hypervisor
  247. if (HYPERVISORS_MAP.ucloud.key === hypervisor) {
  248. delete loginTypes[LOGIN_TYPES_MAP.image.key]
  249. delete loginTypes[LOGIN_TYPES_MAP.keypair.key]
  250. }
  251. if (HYPERVISORS_MAP.aws.key === hypervisor) {
  252. delete loginTypes[LOGIN_TYPES_MAP.random.key]
  253. delete loginTypes[LOGIN_TYPES_MAP.password.key]
  254. }
  255. if (HYPERVISORS_MAP.azure.key === hypervisor) {
  256. delete loginTypes[LOGIN_TYPES_MAP.image.key]
  257. }
  258. if (HYPERVISORS_MAP.ctyun.key === hypervisor) {
  259. delete loginTypes[LOGIN_TYPES_MAP.keypair.key]
  260. delete loginTypes[LOGIN_TYPES_MAP.image.key]
  261. }
  262. if (HYPERVISORS_MAP.google.key === hypervisor) {
  263. delete loginTypes[LOGIN_TYPES_MAP.image.key]
  264. }
  265. if (HYPERVISORS_MAP.qcloud.key === hypervisor) {
  266. delete loginTypes[LOGIN_TYPES_MAP.image.key]
  267. }
  268. if (this.form.fd.os === 'Windows') {
  269. // 以下平台在选择 windows 镜像时禁用关联密钥
  270. const disableKeypairHyper = [
  271. HYPERVISORS_MAP.azure.key,
  272. HYPERVISORS_MAP.aliyun.key,
  273. HYPERVISORS_MAP.qcloud.key,
  274. HYPERVISORS_MAP.ucloud.key,
  275. HYPERVISORS_MAP.esxi.key,
  276. HYPERVISORS_MAP.ksyun.key,
  277. ]
  278. if (disableKeypairHyper.includes(hypervisor)) {
  279. delete loginTypes[LOGIN_TYPES_MAP.keypair.key]
  280. }
  281. if (HYPERVISORS_MAP.google.key === hypervisor) {
  282. delete loginTypes[LOGIN_TYPES_MAP.keypair.key]
  283. }
  284. }
  285. if (this.isServertemplate) {
  286. delete loginTypes[LOGIN_TYPES_MAP.keypair.key]
  287. delete loginTypes[LOGIN_TYPES_MAP.password.key]
  288. }
  289. return Object.keys(loginTypes)
  290. },
  291. osSelectTypes () {
  292. if (HYPERVISORS_MAP.ctyun.key === this.hypervisor) {
  293. return ['public', 'public_customize']
  294. }
  295. return []
  296. },
  297. instanceSpecParams () {
  298. const params = {
  299. public_cloud: true,
  300. usable: true,
  301. enabled: true,
  302. }
  303. const { provider, cloudregion, zone } = this.form.fd
  304. if (provider) params.provider = provider
  305. if (cloudregion) params.cloudregion = cloudregion
  306. if (zone) params.zone = zone
  307. return params
  308. },
  309. cloudproviderParamsExtra () {
  310. const params = {
  311. ...this.scopeParams,
  312. }
  313. const { cloudregion } = this.form.fd
  314. if (this.form.fd.sku && this.form.fd.sku.provider) {
  315. params.provider = this.form.fd.sku.provider
  316. }
  317. if (cloudregion) params.cloudregion = cloudregion
  318. return params
  319. },
  320. hideCloudaccountSched () {
  321. return !!this.form.fd.prefer_manager
  322. },
  323. disabledBillType () {
  324. if (this.form.fd.sku && this.form.fd.sku.provider) {
  325. if (this.form.fd.sku.provider === PROVIDER_MAP.Google.key) { // 谷歌云不支持包年包月
  326. return 'package'
  327. }
  328. }
  329. return ''
  330. },
  331. policycloudproviderParams () {
  332. const params = {
  333. limit: 0,
  334. cloudregion: this.cloudregionZoneParams.cloudregion,
  335. ...this.scopeParams,
  336. }
  337. if (this.form.fd.zone) {
  338. params.zone = this.form.fd.zone
  339. }
  340. if (this.form.fi.networkVpcObj && this.form.fi.networkVpcObj.manager_id) {
  341. params.search = this.form.fi.networkVpcObj.manager_id
  342. }
  343. return params
  344. },
  345. },
  346. watch: {
  347. 'form.fd.billType' (val) {
  348. // 计费方式为包年包月平台不含 azure、aws,这里统一做清空处理
  349. if (val === BILL_TYPES_MAP.package.key) {
  350. this.form.fc.setFieldsValue({
  351. provider: undefined,
  352. cloudregion: undefined,
  353. zone: undefined,
  354. })
  355. }
  356. this.$refs.areaSelectRef.fetchs(['provider'])
  357. },
  358. 'form.fd.duration' (val, oldVal) {
  359. if (this.form.fd.billType === BILL_TYPES_MAP.package.key) {
  360. if (val === '1W' || oldVal === '1W') {
  361. this.form.fc.setFieldsValue({
  362. provider: undefined,
  363. cloudregion: undefined,
  364. zone: undefined,
  365. })
  366. this.$refs.areaSelectRef.fetchs(['provider', 'cloudregion', 'zone'])
  367. }
  368. }
  369. },
  370. },
  371. created () {
  372. this.baywatch(['form.fd.provider', 'form.fd.cloudregion', 'form.fd.zone'], this.fetchInstanceSpecs)
  373. this.baywatch(['form.fd.sku', 'form.fd.zone'], this.withFetchCapbilites)
  374. },
  375. methods: {
  376. providerFetchSuccess (list) {
  377. // 计费方式为包年包月平台不含 azure、aws、google
  378. if (this.form.fd.billType === BILL_TYPES_MAP.package.key) {
  379. if (this.form.fd.duration === '1W') {
  380. list = list.filter(item => HYPERVISORS_MAP.aliyun.key === item.name.toLowerCase())
  381. this.form.fc.setFieldsValue({
  382. provider: HYPERVISORS_MAP.aliyun.provider,
  383. })
  384. } else {
  385. list = list.filter(item => {
  386. return ![HYPERVISORS_MAP.azure.key, HYPERVISORS_MAP.aws.key, HYPERVISORS_MAP.google.key].includes(item.name.toLowerCase())
  387. })
  388. }
  389. }
  390. // 过滤京东云和移动云等只读的云
  391. list = list.filter(item => {
  392. return ![HYPERVISORS_MAP.jdcloud.key, HYPERVISORS_MAP.ecloud.key].includes(item.name.toLowerCase())
  393. })
  394. this.$set(this.form.fi, 'providerList', list)
  395. return list
  396. },
  397. onValuesChange (vm, changedFields) {
  398. this.$nextTick(() => {
  399. const formValue = this.form.fc.getFieldsValue()
  400. const newField = resolveValueChangeField(changedFields)
  401. this._setNewFieldToFd(newField, formValue)
  402. })
  403. },
  404. async fetchCapability () {
  405. const params = {
  406. show_emulated: true,
  407. scope: 'system',
  408. resource_type: this.form.fc.getFieldValue('resourceType'),
  409. }
  410. let id = this.cloudregionZoneParams.cloudregion
  411. let resource = 'cloudregions'
  412. if (this.cloudregionZoneParams.zone) {
  413. id = this.cloudregionZoneParams.zone
  414. resource = 'zones'
  415. }
  416. const capabilityParams = { id, spec: 'disk-capability', params }
  417. if (!id) return
  418. if (R.equals(this.capabilityParams, capabilityParams)) return // 和已有的参数一样则不发请求
  419. this.capabilityParams = capabilityParams
  420. try {
  421. const { data } = await new this.$Manager(resource).getSpecific(this.capabilityParams)
  422. this.form.fi.capability = data
  423. } catch (error) {
  424. throw error
  425. }
  426. },
  427. async fetchInstanceSpecs () {
  428. try {
  429. const { data } = await this.serverskusM.get({ id: 'instance-specs', params: this.instanceSpecParams })
  430. this.form.fi.cpuMem = data
  431. const vcpuDecorator = this.decorators.vcpu
  432. const vcpuInit = vcpuDecorator[1].initialValue
  433. const cpu = this.form.fd.vcpu || vcpuInit
  434. this.cpuChange(cpu)
  435. } catch (error) {
  436. throw error
  437. }
  438. },
  439. withFetchCapbilites (val, oldVal) {
  440. if (val && !R.equals(val, oldVal)) {
  441. this.fetchCapability()
  442. }
  443. },
  444. },
  445. }
  446. </script>