BottomBar.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <template>
  2. <page-footer>
  3. <template v-slot:right>
  4. <div class="d-flex align-items-center" v-if="hasMeterService()">
  5. <div class="mr-4 d-flex align-items-center">
  6. <div class="text-truncate">{{$t('compute.text_286')}}</div>
  7. <div class="ml-2 prices">
  8. <div class="hour d-flex">
  9. <template v-if="price">
  10. <m-animated-number :value="price" :formatValue="priceFormat" />
  11. <discount-price class="ml-2 mini-text" :discount="discount" :origin="originPrice" />
  12. </template>
  13. </div>
  14. <div class="tips text-truncate">
  15. <span v-html="priceTips" />
  16. </div>
  17. </div>
  18. </div>
  19. </div>
  20. <div class="btns-wrapper d-flex align-items-center">
  21. <a-button
  22. class="ml-3"
  23. type="primary"
  24. native-type="submit"
  25. html-type="submit"
  26. @click="handleConfirm"
  27. :loading="loading">{{ $t('common_258') }}</a-button>
  28. <a-button class="ml-3" @click="() => $router.back()">{{$t('common.cancel')}}</a-button>
  29. </div>
  30. </template>
  31. </page-footer>
  32. </template>
  33. <script>
  34. import _ from 'lodash'
  35. import { mapGetters } from 'vuex'
  36. import { PROVIDER_MAP } from '@/constants'
  37. import DiscountPrice from '@/sections/DiscountPrice'
  38. import { hasMeterService } from '@/utils/auth'
  39. import { PriceFetcherByPriceKey } from '@/utils/common/price'
  40. import { currencyUnitMap } from '@/constants/currency'
  41. export default {
  42. name: 'BottomBar',
  43. components: {
  44. DiscountPrice,
  45. },
  46. inject: ['form'],
  47. props: {
  48. currentCloudregion: {
  49. type: Object,
  50. },
  51. currentStorage: {
  52. type: Object,
  53. },
  54. storageTypes: {
  55. type: Array,
  56. },
  57. size: {
  58. type: Number,
  59. },
  60. currentCloudzone: {
  61. type: Object,
  62. },
  63. provider: {
  64. type: [Array, String],
  65. },
  66. },
  67. data () {
  68. this._getPrice = _.debounce(this._getPrice, 500)
  69. return {
  70. loading: false,
  71. priceObj: null,
  72. currency: currencyUnitMap.CNY.sign,
  73. discount: 0,
  74. price: null,
  75. priceFormat: null,
  76. originPrice: null,
  77. priceTips: '--',
  78. key: '',
  79. hasMeterService,
  80. }
  81. },
  82. computed: {
  83. ...mapGetters(['userInfo']),
  84. },
  85. watch: {
  86. currentStorage: {
  87. deep: true,
  88. handler (options) {
  89. this._getPrice()
  90. },
  91. },
  92. currentCloudregion (value) {
  93. if (value && value.provider) {
  94. this._getPrice()
  95. return
  96. }
  97. if (value && value.external_id) {
  98. this._getPrice()
  99. }
  100. },
  101. 'currentCloudzone.external_id' () {
  102. this._getPrice()
  103. },
  104. key () {
  105. this._getPrice()
  106. },
  107. size () {
  108. this._getPrice()
  109. },
  110. },
  111. created () {
  112. this._getPrice()
  113. },
  114. methods: {
  115. async _getPrice () {
  116. if (!hasMeterService()) return
  117. try {
  118. if (!this.currentStorage.value || !this.currentCloudregion) {
  119. this.key = ''
  120. return
  121. }
  122. // let _storageTypes = this.storageTypes.map(item => {
  123. // return item.split('/')
  124. // })
  125. // _storageTypes = Object.fromEntries(_storageTypes)
  126. let key = ''
  127. let region = ''
  128. let zone = ''
  129. const { type, backend } = this.getType(this.currentStorage.value)
  130. let external_id = this.currentCloudregion.external_id
  131. if (!external_id) {
  132. external_id = '/'
  133. }
  134. let pv = this.currentCloudregion.provider
  135. if (this.currentCloudregion.external_id && this.currentCloudregion.external_id.includes('/')) {
  136. const cloudregionExternalArr = external_id.split('/')
  137. if (this.currentCloudregion.cloud_env === 'public') {
  138. if (!this.currentCloudzone) return
  139. key = type
  140. region = cloudregionExternalArr[1]
  141. zone = this.currentCloudzone.external_id.split('/')[2]
  142. } else {
  143. key = `${backend}.${type}`
  144. }
  145. pv = cloudregionExternalArr[0]
  146. } else {
  147. key = `${backend}.${type}`
  148. }
  149. this.key = key
  150. const price_key = `${pv}::${region}::${zone}::disk::${key}`
  151. const pf = new PriceFetcherByPriceKey({
  152. scope: this.$store.getters.scope,
  153. priceKey: price_key,
  154. amount: this.size,
  155. })
  156. const p = await pf.getPriceObj()
  157. p.setOptions({ priceFmt: '0,0.000' })
  158. this.currency = p.currency
  159. this.discount = p.discount
  160. this.price = p.price
  161. this.priceFormat = p.priceFormat
  162. this.originPrice = p.originPrice
  163. this.priceTips = p.priceTips
  164. } catch (err) {
  165. throw err
  166. }
  167. },
  168. doCreate (data) {
  169. return new this.$Manager('disks').create({ data })
  170. },
  171. async handleConfirm () {
  172. this.loading = true
  173. try {
  174. let values = await this.form.fc.validateFields()
  175. const { project, domain, cloudregion, zone, manager_id, backend, encryptEnable, encrypt_key_id, encrypt_key_alg, storage, iops, throughput, ...rest } = values
  176. const oProvider = PROVIDER_MAP[this.currentCloudregion.provider]
  177. const provider = Array.isArray(this.provider) ? this.provider[0] : this.provider
  178. values = {
  179. ...rest,
  180. backend: backend.split('__')[0],
  181. medium: backend.split('__')[1],
  182. hypervisor: oProvider ? oProvider.hypervisor : provider,
  183. size: values.size * 1024,
  184. project_domain: (domain && domain.key) || this.userInfo.projectDomainId,
  185. project_id: (project && project.key) || this.userInfo.projectId,
  186. prefer_region_id: cloudregion,
  187. prefer_zone: zone,
  188. prefer_manager_id: manager_id,
  189. }
  190. if (encryptEnable === 'existing' && encrypt_key_id) {
  191. values.encrypt_key_id = encrypt_key_id
  192. } else if (encryptEnable === 'new') {
  193. values.encrypt_key_new = true
  194. values.encrypt_key_alg = encrypt_key_alg
  195. values.encrypt_key_user_id = this.userInfo.id
  196. }
  197. if (storage) {
  198. values.storage_id = storage
  199. }
  200. if (iops) {
  201. values.iops = iops
  202. }
  203. if (throughput) {
  204. values.throughput = throughput
  205. }
  206. Reflect.deleteProperty(values, 'cloudregion')
  207. Reflect.deleteProperty(values, 'zone')
  208. await this.doCreate(values)
  209. const successBack = () => {
  210. this.$message.success(this.$t('k8s.text_184'))
  211. this.$router.push('/disk')
  212. }
  213. successBack()
  214. } catch (error) {
  215. this.loading = false
  216. throw error
  217. }
  218. },
  219. getType (curVal) {
  220. const curIndex = curVal.lastIndexOf('__')
  221. const type = curVal.substring(0, curIndex)
  222. const backend = curVal.substr(curIndex + 2)
  223. return { type, backend }
  224. },
  225. },
  226. }
  227. </script>
  228. <style lang="less" scoped>
  229. @import '../../../../../../src/styles/less/theme';
  230. .prices {
  231. .hour {
  232. color: @error-color;
  233. font-size: 24px;
  234. }
  235. .tips {
  236. color: #999;
  237. font-size: 12px;
  238. }
  239. }
  240. </style>