index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. <template>
  2. <div>
  3. <page-header :title="$t('common_661')" :tabs="cloudEnvOptions" :current-tab.sync="cloudEnv" />
  4. <page-body>
  5. <a-form
  6. class="mt-3"
  7. :form="form.fc"
  8. @submit.prevent="handleSubmit"
  9. v-bind="formItemLayout"
  10. hideRequiredMark>
  11. <a-form-item :label="$t('network.text_205', [$t('dictionary.project')])" v-if="isAdminMode">
  12. <domain-project :decorators="decorators.projectDomain" :fc="form.fc" :labelInValue="false" @update:domain="domainChange" />
  13. </a-form-item>
  14. <a-form-item v-if="cloudEnv === 'public'" :label="$t('dictionary.cloudaccount')" class="mb-0">
  15. <a-row :gutter="8" class="w-100">
  16. <a-col :span="12">
  17. <a-form-item :wrapperCol="{ span: 24 }">
  18. <a-select
  19. :allowClear="allowClear"
  20. class="w-100"
  21. style="width:100%"
  22. v-decorator="decorators.brand"
  23. :placeholder="$t('rules.provider')"
  24. @change="brandChange"
  25. showSearch>
  26. <a-select-option v-for="item of brandOpts" :value="item.key" :key="item.key">{{ item.label }}</a-select-option>
  27. </a-select>
  28. </a-form-item>
  29. </a-col>
  30. <a-col :span="12">
  31. <a-form-item :wrapperCol="{ span: 24 }">
  32. <base-select
  33. :remote="true"
  34. class="w-100"
  35. :needParams="true"
  36. v-decorator="decorators.account"
  37. resource="cloudaccounts"
  38. isDefaultSelect
  39. :params="accountParams"
  40. :remote-fn="q => ({ filter: `name.contains(${q})` })"
  41. :select-props="{ placeholder: $t('rules.cloudaccount') }"
  42. @update:item="handleAccountChange" />
  43. </a-form-item></a-col>
  44. </a-row>
  45. </a-form-item>
  46. <a-form-item v-if="cloudEnv=== 'public'" :label="$t('compute.text_15')">
  47. <base-select
  48. resource="cloudproviders"
  49. v-decorator="decorators.cloudprovider"
  50. :params="cloudproviderParams"
  51. :isDefaultSelect="true"
  52. :showSync="true"
  53. :select-props="{ placeholder: $t('common_588') }" />
  54. </a-form-item>
  55. <a-form-item :label="$t('network.text_717')">
  56. <a-select
  57. v-decorator="decorators.zoneType" @change="zoneTypeChangeHandle">
  58. <a-select-option v-for="v in zoneTypes" :value="v.value" :key="v.value">
  59. <div>{{ v.label }}<span class="ml-2">{{ v.desc }}</span></div>
  60. </a-select-option>
  61. </a-select>
  62. </a-form-item>
  63. <a-form-item :label="$t('network.text_156')">
  64. <a-input v-decorator="decorators.name" :placeholder="$t('network.text_157')" />
  65. </a-form-item>
  66. <a-form-item label="VPC" v-if="cloudEnv === 'public' && currentZoneType === 'PrivateZone'">
  67. <base-select
  68. v-decorator="decorators.vpc_ids"
  69. resource="vpcs"
  70. remote
  71. :params="vpcParams"
  72. :needParams="true"
  73. :labelFormat="vpcLabelFormat"
  74. :select-props="{ placeholder: $t('common_226'), mode: 'multiple' }"
  75. :remote-fn="q => ({ filter: `name.contains(${q})` })" />
  76. </a-form-item>
  77. <a-form-item :label="$t('common.description')">
  78. <a-textarea :auto-size="{ minRows: 1, maxRows: 3 }" v-decorator="decorators.description" :placeholder="$t('common_367')" />
  79. </a-form-item>
  80. <a-form-item :label="$t('common.text00012')" class="mb-0">
  81. <tag
  82. v-decorator="decorators.__meta__" />
  83. </a-form-item>
  84. </a-form>
  85. </page-body>
  86. <page-footer>
  87. <div slot="right">
  88. <a-button class="mr-3" type="primary" :loading="loading" @click="handleConfirm">{{ $t('dialog.ok') }}</a-button>
  89. <a-button @click="cancel">{{ this.$t('dialog.cancel') }}</a-button>
  90. </div>
  91. </page-footer>
  92. </div>
  93. </template>
  94. <script>
  95. import _ from 'lodash'
  96. import { mapGetters } from 'vuex'
  97. import { HYPERVISORS_MAP } from '@/constants'
  98. import DomainProject from '@/sections/DomainProject'
  99. import validateForm, { validate } from '@/utils/validate'
  100. import { getCloudEnvOptions } from '@/utils/common/hypervisor'
  101. import Tag from '@/sections/Tag'
  102. import { zoneTypes } from '../constants'
  103. export default {
  104. name: 'DnsZoneCreate',
  105. components: {
  106. DomainProject,
  107. Tag,
  108. },
  109. data () {
  110. const cloudEnvOptions = getCloudEnvOptions('compute_engine_brands').filter(val => ['onpremise', 'public'].includes(val.key))
  111. const cloudEnv = this.$route.params?.cloudEnv || _.get(cloudEnvOptions, '[0].key')
  112. const zoneType = zoneTypes[0].value
  113. return {
  114. loading: false,
  115. cloudEnvOptions,
  116. cloudEnv,
  117. form: {
  118. fc: this.$form.createForm(this, {
  119. onValuesChange: (props, values) => {
  120. Object.keys(values).forEach((key) => {
  121. this.form.fd[key] = values[key]
  122. })
  123. },
  124. }),
  125. fd: {
  126. brand: '',
  127. account: '',
  128. cloudprovider: '',
  129. zoneType,
  130. },
  131. },
  132. decorators: {
  133. projectDomain: {
  134. project: [
  135. 'project',
  136. {
  137. initialValue: undefined,
  138. },
  139. ],
  140. domain: [
  141. 'domain',
  142. {
  143. initialValue: undefined,
  144. },
  145. ],
  146. },
  147. brand: [
  148. 'brand',
  149. {
  150. rules: [
  151. { required: true, message: this.$t('rules.brand') },
  152. ],
  153. },
  154. ],
  155. account: [
  156. 'account',
  157. {
  158. rules: [
  159. { required: true, message: this.$t('rules.cloudaccount') },
  160. ],
  161. },
  162. ],
  163. cloudprovider: [
  164. 'cloudprovider',
  165. {
  166. rules: [
  167. { required: true, message: this.$t('common_588') },
  168. ],
  169. },
  170. ],
  171. vpc_ids: [
  172. 'vpc_ids',
  173. {
  174. rules: [
  175. { required: true, message: this.$t('network.text_274') },
  176. ],
  177. },
  178. ],
  179. name: [
  180. 'name',
  181. {
  182. validateFirst: true,
  183. rules: [
  184. { required: true, message: this.$t('network.text_157') },
  185. { validator: this.checkDomainHandle },
  186. ],
  187. },
  188. ],
  189. description: ['description'],
  190. zoneType: [
  191. 'zoneType',
  192. {
  193. initialValue: zoneType,
  194. validateFirst: true,
  195. rules: [
  196. { required: true, message: this.$t('network.text_717') },
  197. ],
  198. },
  199. ],
  200. __meta__: [
  201. '__meta__',
  202. {
  203. rules: [
  204. { validator: validateForm('tagName') },
  205. ],
  206. },
  207. ],
  208. },
  209. formItemLayout: {
  210. wrapperCol: {
  211. span: 21,
  212. },
  213. labelCol: {
  214. span: 3,
  215. },
  216. },
  217. brandOpts: [],
  218. domainId: '',
  219. currentZoneType: zoneTypes[0].value,
  220. }
  221. },
  222. computed: {
  223. ...mapGetters(['isAdminMode', 'scope', 'capability']),
  224. vpcParams () {
  225. const params = {
  226. limit: 20,
  227. usable_vpc: true,
  228. scope: this.scope,
  229. }
  230. if (this.isAdminMode && this.domainId) {
  231. params.project_domain = this.domainId
  232. delete params.scope
  233. }
  234. if (this.form.fd.brand) {
  235. params.brand = this.form.fd.brand
  236. }
  237. return params
  238. },
  239. zoneTypes () {
  240. if (this.cloudEnv === 'onpremise') {
  241. return zoneTypes.filter(item => item.value === 'PrivateZone')
  242. }
  243. if (this.isCloudflare || !this.cloudEnv) {
  244. return zoneTypes.filter(item => item.value === 'PublicZone')
  245. }
  246. return zoneTypes
  247. },
  248. accountParams () {
  249. return {
  250. scope: this.$store.getters.scope,
  251. provider: this.form?.fd?.brand,
  252. limit: 20,
  253. }
  254. },
  255. cloudproviderParams () {
  256. return {
  257. scope: this.$store.getters.scope,
  258. read_only: false,
  259. cloudaccount_id: this.form?.fd?.account,
  260. }
  261. },
  262. isCloudflare () {
  263. return this.form.fd.brand === 'Cloudflare'
  264. },
  265. },
  266. watch: {
  267. cloudEnv: function (val) {
  268. if (val === 'onpremise') {
  269. this.form.fc.setFieldsValue({
  270. zoneType: 'PrivateZone',
  271. })
  272. this.form.fd.zoneType = 'PrivateZone'
  273. this.currentZoneType = 'PrivateZone'
  274. } else {
  275. this.initBrands()
  276. }
  277. },
  278. zoneTypes (val, oldval) {
  279. this.form.fc.setFieldsValue({
  280. zoneType: val[0].value,
  281. })
  282. this.form.fd.zoneType = val[0].value
  283. this.currentZoneType = val[0].value
  284. },
  285. },
  286. mounted () {
  287. if (this.cloudEnv === 'public') {
  288. this.initBrands()
  289. }
  290. },
  291. methods: {
  292. initBrands () {
  293. const ret = []
  294. const brands = this.capability.dns_brands.filter(key => ['Aliyun', 'Aws', 'Qcloud', 'Cloudflare'].includes(key))
  295. brands.map(key => {
  296. const target = HYPERVISORS_MAP[key.toLowerCase()]
  297. ret.push({ key: target.provider, label: target.label })
  298. })
  299. const brand = ret[0] ? ret[0].key : ''
  300. this.form.fd.brand = brand
  301. this.brandOpts = ret
  302. this.$nextTick(() => {
  303. this.form.fc.setFieldsValue({
  304. brand,
  305. })
  306. })
  307. },
  308. domainChange (domainId) {
  309. this.domainId = domainId
  310. },
  311. doCreate (data) {
  312. return new this.$Manager('dns_zones').create({ data })
  313. },
  314. async handleConfirm () {
  315. this.loading = true
  316. try {
  317. const values = await this.form.fc.validateFields()
  318. const { domain, project, name, zoneType, description, cloudprovider } = values
  319. const data = {
  320. domain: domain || this.$store.getters.userInfo.project_domain,
  321. project: project,
  322. name,
  323. description,
  324. zone_type: zoneType,
  325. __meta__: values.__meta__,
  326. }
  327. if (this.cloudEnv === 'public') {
  328. data.cloudprovider_id = cloudprovider
  329. if (zoneType === 'PrivateZone') {
  330. data.vpc_ids = values.vpc_ids
  331. }
  332. }
  333. await this.doCreate(data)
  334. this.$router.push({
  335. name: 'DnsZone',
  336. params: {
  337. cloudEnv: this.cloudEnv,
  338. },
  339. })
  340. } catch (err) {
  341. throw err
  342. } finally {
  343. this.loading = false
  344. }
  345. },
  346. checkDomainHandle (rule, value, callback) {
  347. if (this.form.fd.zoneType === 'PublicZone') {
  348. if (validate(value, 'domain') === false || validate(value, 'domain').result === false) {
  349. callback(new Error(this.$t('network.text_178')))
  350. }
  351. }
  352. callback()
  353. },
  354. zoneTypeChangeHandle (value) {
  355. this.currentZoneType = value
  356. this.$nextTick(() => {
  357. this.form.fc.validateFields(['name'], { force: true })
  358. })
  359. },
  360. vpcLabelFormat (item) {
  361. if (item.manager) {
  362. if (item.cidr_block) {
  363. return <div><span class="text-color-secondary">VPC:</span> { item.name }<span>({ item.cidr_block })</span><span class="ml-2 text-color-secondary">{this.$t('common_711')}: { item.manager }</span></div>
  364. }
  365. return <div><span class="text-color-secondary">VPC:</span> { item.name }<span class="ml-2 text-color-secondary">{this.$t('common_711')}: { item.manager }</span></div>
  366. }
  367. return <div>{ item.name }</div>
  368. },
  369. cancel () {
  370. this.$router.push({
  371. name: 'DnsZone',
  372. params: {
  373. cloudEnv: this.cloudEnv,
  374. },
  375. })
  376. },
  377. },
  378. }
  379. </script>
  380. <style lang="less" scoped>
  381. .steps {
  382. max-width: 750px;
  383. margin: 32px 0;
  384. }
  385. </style>