index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. <template>
  2. <div class="cloudaccount-create">
  3. <page-header :title="$t('cloudenv.text_271')" />
  4. <steps class="my-3" v-model="step" />
  5. <component
  6. ref="stepRef"
  7. :is="currentComponent"
  8. :prepareNetData="prepareNetData"
  9. :current-item.sync="currentItem"
  10. :account="newAccountInfo"
  11. :provider="currentItem.provider"
  12. :create-form-data="createCloudaccountFormData"
  13. :cloneData="cloneData" /><!-- provider 是为了 VmNetwork 的 prop 不报错 -->
  14. <page-footer isForm>
  15. <div slot="left">
  16. <div class="d-flex align-items-center">
  17. <div class="mr-2">{{$t('cloudenv.text_272')}}</div>
  18. <div class="item d-flex p-1 mb-0 align-items-center active">
  19. <img :src="currentItem.logo" :style="currentItem.logoStyle" />
  20. <h5 class="ml-2" v-if="showName(currentItem)">{{ currentItem.name }}</h5>
  21. </div>
  22. </div>
  23. </div>
  24. <div slot="right">
  25. <a-button class="mr-3" @click="perv" v-if="!isFirstStep && !isScheduledSetting">{{$t('cloudenv.text_273')}}</a-button>
  26. <a-button :disabled="nextDisabled" class="mr-3" type="primary" @click="next" :loading="loading">{{ nextStepTitle }}</a-button>
  27. <test-button v-if="['create-cloudaccount', 'bill-form', 'bill-file-index'].includes(currentComponent)" class="mr-3" :post="testPost" :isSuccessAlert="!['bill-form', 'bill-file-index'].includes(currentComponent)" />
  28. <a-button @click="cancel">{{['select-region', 'bill-form', 'bill-file-index', 'scheduled-settings'].includes(currentComponent) ? $t('cloudenv.text_274'): $t('cloudenv.text_170')}}</a-button>
  29. </div>
  30. </page-footer>
  31. </div>
  32. </template>
  33. <script>
  34. import { CLOUDACCOUNT_TYPES, notSupportSelectRegion } from '@Cloudenv/views/cloudaccount/constants'
  35. import step from '@/mixins/step'
  36. import { Manager } from '@/utils/manager'
  37. import { getRequestT } from '@/utils/utils'
  38. import TestButton from '@/sections/TestButton'
  39. import SelectCloudaccount from './form/SelectCloudaccount'
  40. import CreateCloudaccount from './form/CreateCloudaccount'
  41. import SelectRegion from './form/SelectRegion'
  42. import ScheduledSettings from './form/ScheduledSettings'
  43. import BillForm from './form/BillForm'
  44. import BillFileIndex from './BillFileIndex'
  45. import GuestNetwork from './form/GuestNetwork'
  46. import HostNetwork from './form/HostNetwork'
  47. export default {
  48. name: 'Cloudaccount',
  49. components: {
  50. SelectCloudaccount,
  51. CreateCloudaccount,
  52. SelectRegion,
  53. BillForm,
  54. BillFileIndex,
  55. GuestNetwork,
  56. HostNetwork,
  57. TestButton,
  58. ScheduledSettings,
  59. },
  60. mixins: [step],
  61. data () {
  62. const { params: cloneData = {} } = this.$route
  63. return {
  64. testLoding: false,
  65. newAccountInfo: {},
  66. isAdminMode: this.$store.getters.isAdminMode,
  67. isDomainMode: this.$store.getters.isDomainMode,
  68. l3PermissionEnable: this.$store.getters.l3PermissionEnable,
  69. userInfo: this.$store.getters.userInfo,
  70. currentItem: Object.values(Object.values(CLOUDACCOUNT_TYPES)[0])[0],
  71. currentComponent: 'SelectCloudaccount',
  72. vmwareFormData: null,
  73. loading: false,
  74. prepareNetData: {},
  75. networkData: {},
  76. createCloudaccountFormData: null,
  77. step: {
  78. steps: [],
  79. currentStep: 0,
  80. },
  81. offsetFormLayout: {
  82. wrapperCol: {
  83. md: { span: 18, offset: 6 },
  84. xl: { span: 20, offset: 3 },
  85. xxl: { span: 22, offset: 2 },
  86. },
  87. },
  88. cloneData,
  89. }
  90. },
  91. computed: {
  92. nextText () {
  93. if (this.step.currentStep >= this.step.steps.length - 1) {
  94. return this.$t('cloudenv.text_275')
  95. }
  96. return this.$t('cloudenv.text_276')
  97. },
  98. stepKey () {
  99. return this.step.steps[this.step.currentStep].key
  100. },
  101. isBill () {
  102. return ['Aws', 'Aliyun', 'Google', 'Huawei', 'Azure', 'Qcloud', 'JDcloud', 'VolcEngine', 'Ksyun'].indexOf(this.currentItem.provider) > -1 && this.$appConfig.isPrivate && !this.$store.getters.isSysCE
  103. },
  104. isGoogle () {
  105. return this.currentItem.provider === 'Google'
  106. },
  107. brand () {
  108. return this.currentItem.provider.toLowerCase()
  109. },
  110. nextDisabled () {
  111. // if (this.currentComponent === 'host-network' && (!this.prepareNetData.hosts || (this.prepareNetData.hosts && !this.prepareNetData.hosts.length))) {
  112. // return true
  113. // }
  114. return false
  115. },
  116. isScheduledSetting () {
  117. return this.step.currentStep === this.step.steps.length - 1
  118. },
  119. },
  120. watch: {
  121. 'step.currentStep' (step) {
  122. this.currentComponent = this.step.steps[step].key
  123. },
  124. currentItem (val) {
  125. this.changeSteps(val)
  126. },
  127. },
  128. created () {
  129. this.cloudaccountsM = new Manager('cloudaccounts', 'v2')
  130. this.networksM = new Manager('networks', 'v2')
  131. this.changeSteps()
  132. this.$nextTick(() => {
  133. if (this.cloneData.provider) {
  134. this.setStep(1)
  135. const { params: cloneData = {} } = this.$route
  136. let currentItem = {}
  137. if (cloneData.provider) {
  138. const types = Object.values(CLOUDACCOUNT_TYPES)
  139. for (let i = 0; i < types.length; i++) {
  140. const items = Object.values(types[i])
  141. for (let j = 0; j < items.length; j++) {
  142. if (items[j].provider === cloneData.provider) {
  143. currentItem = items[j]
  144. }
  145. }
  146. }
  147. }
  148. if (currentItem.provider) {
  149. this.currentItem = currentItem
  150. }
  151. }
  152. })
  153. },
  154. methods: {
  155. // async getFetchPrepareNets () {
  156. // if (!this.vmwareFormData) return false
  157. // try {
  158. // const { name, host, password, port, project, username, proxy_setting } = this.vmwareFormData
  159. // const performData = {
  160. // name,
  161. // host,
  162. // password,
  163. // port,
  164. // project: project.key,
  165. // provider: 'VMware',
  166. // username,
  167. // proxy_setting,
  168. // }
  169. // if (this.$store.getters.isAdminMode && this.vmwareFormData.domain && this.vmwareFormData.domain.key) {
  170. // performData.project_domain = this.vmwareFormData.domain.key
  171. // }
  172. // const { data } = await this.cloudaccountsM.performClassAction({
  173. // action: 'prepare-nets',
  174. // data: performData,
  175. // })
  176. // this.prepareNetData = data.wire_networks[0] || {}
  177. // } catch (err) {
  178. // throw err
  179. // }
  180. // },
  181. changeSteps (val) {
  182. const steps = [
  183. { title: this.$t('cloudenv.text_277'), key: 'select-cloudaccount' },
  184. { title: this.$t('cloudenv.text_278'), key: 'create-cloudaccount' },
  185. ]
  186. if (notSupportSelectRegion.indexOf(this.currentItem.provider) === -1) {
  187. steps.push({ title: this.$t('cloudenv.select_region'), key: 'select-region' })
  188. }
  189. if (this.isBill) {
  190. if (this.isGoogle) {
  191. steps.push({ title: this.$t('cloudenv.text_279'), key: 'bill-file-index' })
  192. } else {
  193. steps.push({ title: this.$t('cloudenv.text_279'), key: 'bill-form' })
  194. }
  195. }
  196. steps.push({ title: this.$t('cloudenv.scheduled_settings_title'), key: 'scheduled-settings' })
  197. this.step.steps = steps
  198. },
  199. async cancel () {
  200. const isSupportSelectRegion = notSupportSelectRegion.indexOf(this.currentItem.provider) === -1
  201. if (this.step.currentStep === 2 && notSupportSelectRegion.indexOf(this.currentItem.provider) === -1) {
  202. await this.$refs.stepRef.validateForm()
  203. await this.doCreateCloudaccountByRegion()
  204. }
  205. if (this.isBill) {
  206. if (isSupportSelectRegion && this.step.currentStep === this.step.steps.length - 2) {
  207. this.step.currentStep++
  208. this.currentComponent = 'scheduled-settings'
  209. } else {
  210. this.$router.push('/cloudaccount')
  211. }
  212. } else {
  213. if (isSupportSelectRegion && this.step.currentStep === this.step.steps.length - 2) {
  214. this.step.currentStep++
  215. this.currentComponent = 'scheduled-settings'
  216. } else {
  217. this.$router.push('/cloudaccount')
  218. }
  219. }
  220. },
  221. showName (item) {
  222. if ((item.data && item.data.hiddenName) || item.hiddenName) {
  223. return false
  224. } else {
  225. return true
  226. }
  227. },
  228. _addDomainProject (data) {
  229. data.domain_id = this.userInfo.projectDomainId
  230. data.tenant = this.userInfo.projectId
  231. if (data.domain && data.domain.key) data.domain_id = data.domain.key
  232. if (data.project && data.project.key) data.tenant = data.project.key
  233. delete data.domain
  234. delete data.project
  235. if (!this.isAdminMode || !this.l3PermissionEnable) delete data.domain_id
  236. const { resource_map_type = [] } = data
  237. if (resource_map_type.includes('project_mapping') && data.project_mapping_id) {
  238. if (data.effective_scope === 'resource') {
  239. data.enable_resource_sync = true
  240. } else if (data.effective_scope === 'project') {
  241. data.enable_project_sync = true
  242. }
  243. }
  244. if (resource_map_type.includes('cloudprovider')) {
  245. data.auto_create_project_for_provider = true
  246. }
  247. if (resource_map_type.includes('external_project')) {
  248. data.auto_create_project = true
  249. }
  250. delete data.effective_scope
  251. delete data.resource_map_type
  252. },
  253. _providerDiff (data) {
  254. const brand = this.currentItem.provider.toLowerCase()
  255. // if (brand === 'ucloud' || brand === 'huawei' || brand === 'azure') {
  256. // data['auto_create_project'] = true
  257. // }
  258. if (brand === 'dstack') {
  259. data.brand = 'DStack'
  260. data.provider = 'ZStack'
  261. }
  262. },
  263. async doCreateCloudaccount (formData) {
  264. formData.options = {}
  265. for (const key in formData) {
  266. if (key.startsWith('options__')) {
  267. if (formData[key].length > 0) {
  268. formData.options[key.substring('options__'.length)] = formData[key]
  269. }
  270. delete formData[key]
  271. }
  272. }
  273. const data = {
  274. ...formData,
  275. enabled: true,
  276. provider: this.currentItem.provider,
  277. }
  278. if (formData.sync_interval_seconds) {
  279. data.sync_interval_seconds = formData.sync_interval_seconds * 60 // 转换为秒
  280. }
  281. if (formData.verify_method) {
  282. data.username = `${formData.username}@${formData.verify_method}`
  283. delete data.verify_method
  284. }
  285. this._addDomainProject(data)
  286. this._providerDiff(data)
  287. const ret = await this.cloudaccountsM.create({ data })
  288. if (this.$store.getters.auth.stats.cloudaccounts === 0) {
  289. await this.$store.dispatch('auth/getStats')
  290. if (this.$store.getters.auth.stats.cloudaccounts > 0) {
  291. await this.$store.dispatch('common/deleteObject', {
  292. name: 'topAlert',
  293. key: 'createCloudAccounts',
  294. })
  295. }
  296. }
  297. return ret.data
  298. },
  299. formatNetParams (values) {
  300. const { keys = [] } = values
  301. return keys.map(k => {
  302. return {
  303. zone: 'default',
  304. wire: 'default',
  305. ...values[k],
  306. }
  307. })
  308. },
  309. async doCreateNetwork (wire) {
  310. const hostNetData = this.networkData['host-network']
  311. const hostParams = this.formatNetParams(hostNetData)
  312. const promises = []
  313. hostParams.forEach(dta => {
  314. promises.push(new Promise((resolve, reject) => {
  315. dta.server_type = 'baremetal'
  316. dta.wire = wire.id
  317. dta.generate_name = dta.name
  318. dta.tenant = this.newAccountInfo.tenant
  319. if (this.isAdminMode && this.l3PermissionEnable) {
  320. dta.domain_id = this.newAccountInfo.domain_id
  321. }
  322. delete dta.name
  323. this.networksM.create({
  324. data: dta,
  325. params: { $t: getRequestT() },
  326. }).then(({ data }) => {
  327. resolve(data)
  328. }).catch(err => {
  329. reject(err)
  330. })
  331. }))
  332. })
  333. const guestNetData = this.networkData['guest-network']
  334. if (guestNetData.isCreate) {
  335. const guestParams = this.formatNetParams(guestNetData)
  336. guestParams.forEach(dta => {
  337. promises.push(new Promise((resolve, reject) => {
  338. dta.server_type = 'guest'
  339. dta.wire = wire.id
  340. dta.generate_name = dta.name
  341. dta.tenant = this.newAccountInfo.tenant
  342. dta.public_scope = 'domain'
  343. dta.is_public = true
  344. if (this.isAdminMode && this.l3PermissionEnable) {
  345. dta.domain_id = this.newAccountInfo.domain_id
  346. }
  347. delete dta.name
  348. this.networksM.create({
  349. data: dta,
  350. params: { $t: getRequestT() },
  351. }).then(({ data }) => {
  352. resolve(data)
  353. }).catch(err => {
  354. reject(err)
  355. })
  356. }))
  357. })
  358. }
  359. await Promise.all(promises)
  360. },
  361. // async createWire () {
  362. // const manager = new this.$Manager('wires')
  363. // try {
  364. // if (!this.prepareNetData.suitable_wire && this.prepareNetData.suggested_wire) {
  365. // const { name, description, zone_id, zone_ids } = this.prepareNetData.suggested_wire
  366. // const params = {
  367. // generate_name: name,
  368. // description,
  369. // zone_id: zone_id || ((zone_ids && zone_ids.length > 0) ? zone_ids[0] : undefined),
  370. // vpc_id: 'default',
  371. // bandwidth: '1000',
  372. // }
  373. // params.tenant = this.newAccountInfo.tenant
  374. // if (this.isAdminMode && this.l3PermissionEnable) {
  375. // params.domain_id = this.newAccountInfo.domain_id
  376. // }
  377. // const { data } = await manager.create({
  378. // data: params,
  379. // })
  380. // return data
  381. // }
  382. // return {
  383. // id: this.prepareNetData.suitable_wire,
  384. // }
  385. // } catch (err) {
  386. // throw err
  387. // }
  388. // },
  389. // async vmwareForm (values) {
  390. // if (this.step.currentStep === 1) {
  391. // this.vmwareFormData = values
  392. // await this.getFetchPrepareNets()
  393. // }
  394. // if (this.step.currentStep > 1) {
  395. // this.networkData[this.currentComponent] = values
  396. // }
  397. // if (this.step.currentStep === 3) {
  398. // try {
  399. // this.newAccountInfo = await this.doCreateCloudaccount(this.vmwareFormData)
  400. // const wireDta = await this.createWire()
  401. // try {
  402. // await this.doCreateNetwork(wireDta)
  403. // } catch (error) {
  404. // this.$router.push('/cloudaccount')
  405. // throw error
  406. // }
  407. // this.$router.push('/cloudaccount')
  408. // } catch (err) {
  409. // throw err
  410. // }
  411. // }
  412. // },
  413. async validateForm () {
  414. try {
  415. let createForm = this.$refs.stepRef.$refs.createForm
  416. if (this.brand === 'vmware' && this.step.currentStep > 1) {
  417. createForm = this.$refs.stepRef
  418. }
  419. if (this.step.currentStep === 2 && notSupportSelectRegion.indexOf(this.currentItem.provider) === -1) {
  420. await this.$refs.stepRef.validateForm()
  421. return this.doCreateCloudaccountByRegion()
  422. }
  423. if (this.step.currentStep === this.step.steps.length - 2 && this.isBill) {
  424. return this.fetchBillSubmit()
  425. }
  426. if (this.step.currentStep === this.step.steps.length - 1) {
  427. return this.$refs.stepRef.handleConfirm(this.newAccountInfo.id)
  428. }
  429. if (!createForm) return false
  430. const values = await createForm.validateForm()
  431. this.loading = true
  432. // if (this.brand === 'vmware') {
  433. // return await this.vmwareForm(values)
  434. // }
  435. if (values.ucloud_project_id && values.access_key_id) {
  436. values.access_key_id = values.access_key_id + '::' + values.ucloud_project_id
  437. delete values.ucloud_project_id
  438. }
  439. if (values.share_mode && values.share_mode === 'global') {
  440. values.public_scope = 'system'
  441. values.is_public = true
  442. delete values.share_mode
  443. }
  444. if (notSupportSelectRegion.indexOf(this.currentItem.provider) === -1) {
  445. this.createCloudaccountFormData = values // 存储配置账号信息用来在配置同步资源区域步骤创建云账号
  446. values.show_sub_accounts = true
  447. values.dry_run = true
  448. }
  449. this.newAccountInfo = await this.doCreateCloudaccount(values)
  450. this.$store.dispatch('auth/getCapabilities')
  451. if (notSupportSelectRegion.indexOf(this.currentItem.provider) === -1) {
  452. this.currentComponent = 'select-region'
  453. } else {
  454. if (this.isBill) {
  455. this.currentComponent = 'billConfig'
  456. } else {
  457. // this.$router.push('/cloudaccount')
  458. }
  459. }
  460. } catch (err) {
  461. throw err
  462. } finally {
  463. this.loading = false
  464. }
  465. },
  466. async fetchBillSubmit () {
  467. const BILL_FORM = this.$refs.stepRef
  468. this.loading = true
  469. try {
  470. await BILL_FORM.doSubmit(this.newAccountInfo)
  471. this.currentComponent = 'scheduled-settings'
  472. } catch (err) {
  473. throw err
  474. } finally {
  475. this.loading = false
  476. }
  477. },
  478. next () {
  479. const { currentStep } = this.step
  480. const next = currentStep + 1
  481. this.setStep(next)
  482. },
  483. perv () {
  484. const { currentStep } = this.step
  485. const prev = currentStep - 1
  486. this.setStep(prev)
  487. },
  488. testPost () {
  489. if (this.currentComponent === 'create-cloudaccount') {
  490. return this.handleTest()
  491. }
  492. if (this.$refs.stepRef && this.$refs.stepRef.testPost) {
  493. return this.$refs.stepRef.testPost()
  494. }
  495. },
  496. async handleTest () {
  497. const createForm = this.$refs.stepRef.$refs.createForm
  498. const formData = await createForm.validateForm()
  499. if (formData.ucloud_project_id && formData.access_key_id) {
  500. formData.access_key_id = formData.access_key_id + '::' + formData.ucloud_project_id
  501. delete formData.ucloud_project_id
  502. }
  503. const data = {
  504. ...formData,
  505. enabled: true,
  506. provider: this.currentItem.provider,
  507. }
  508. if (formData.sync_interval_seconds) {
  509. data.sync_interval_seconds = formData.sync_interval_seconds * 60 // 转换为秒
  510. }
  511. if (formData.verify_method) {
  512. data.username = `${formData.username}@${formData.verify_method}`
  513. delete data.verify_method
  514. }
  515. this._addDomainProject(data)
  516. this._providerDiff(data)
  517. await this.cloudaccountsM.create({
  518. data: {
  519. ...data,
  520. dry_run: true,
  521. },
  522. })
  523. },
  524. async doCreateCloudaccountByRegion () {
  525. const chooseRegions = this.$refs.stepRef.chooseRegions
  526. let data = this.createCloudaccountFormData
  527. if (chooseRegions?.length > 0) {
  528. const cloudregionIds = chooseRegions.map(v => {
  529. if (v.id?.endsWith('/')) {
  530. return { name: v.name }
  531. }
  532. return { id: v.id }
  533. })
  534. data = {
  535. ...this.createCloudaccountFormData,
  536. sub_accounts: {
  537. accounts: this.newAccountInfo.sub_accounts.accounts,
  538. cloudregions: cloudregionIds,
  539. },
  540. }
  541. } else {
  542. data = {
  543. ...this.createCloudaccountFormData,
  544. }
  545. }
  546. delete data.show_sub_accounts
  547. delete data.dry_run
  548. this.newAccountInfo = await this.doCreateCloudaccount(data)
  549. // if (this.step.currentStep === this.step.steps.length - 1) {
  550. // this.$router.push('/cloudaccount')
  551. // }
  552. },
  553. },
  554. }
  555. </script>
  556. <style lang="less">
  557. .cloudaccount-create {
  558. .item {
  559. width: 120px;
  560. cursor: pointer;
  561. display: block;
  562. font-size: 14px;
  563. margin-bottom: 10px;
  564. border: 1px solid #eee;
  565. text-align: center;
  566. border-radius: 3px;
  567. box-sizing: border-box;
  568. &.active {
  569. border-color:#4DA1FF;
  570. h5{
  571. color:#4DA1FF;
  572. }
  573. }
  574. &:hover {
  575. border-color:#4DA1FF;
  576. h5{
  577. color:#4DA1FF;
  578. }
  579. }
  580. h5 {
  581. margin: 0;
  582. font-size: 13px;
  583. font-weight: 400;
  584. }
  585. img {
  586. height: 24px;
  587. }
  588. }
  589. }
  590. </style>