| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- <template>
- <a-spin :spinning="loading">
- <page-header :title="title" />
- <page-body>
- <steps class="my-3" v-model="step" />
- <div class="step1" v-show="isSetpOne">
- <a-form :form="endpointForm" ref="endpointFormRef" v-bind="formItemLayout">
- <a-form-item :label="$t('dictionary.domain')" key="domain" v-show="showDomainSelect">
- <base-select
- v-model="filters.project_domain"
- v-if="showDomainSelect"
- :isDefaultSelect="true"
- resource="domains"
- :params="renderOrders.project_domain.params"
- filterable
- version="v1"
- @change="handleDomainChange"
- :select-props="{ placeholder: `${$t('common.text00106')}${$t('dictionary.domain')}` }" />
- </a-form-item>
- <a-form-item :label="$t('common.name')">
- <a-input v-decorator="decorators.generate_name" :placeholder="$t('common.placeholder')" @change="handleNameChange" />
- <name-repeated v-slot:extra res="proxy_endpoints" :name="generate_name" />
- </a-form-item>
- <a-form-item :label="$t('common.description')">
- <a-textarea :auto-size="{ minRows: 1, maxRows: 3 }" v-decorator="decorators.description" :placeholder="$t('common_367')" />
- </a-form-item>
- <area-selects
- class="mb-0"
- ref="areaSelects"
- @change="handleAreaChange"
- :allowClear="false"
- :wrapperCol="formItemLayout.wrapperCol"
- :labelCol="formItemLayout.labelCol"
- :names="areaselectsName"
- :cloudregionParams="renderOrders.region.params"
- :providerParams="renderOrders.brand.params"
- :cloudregionParamsMapper="cloudregionParamsMapper"
- filterBrandResource="compute_engine" />
- <a-form-item :label="$t('cloudenv.text_7')">
- <a-row :gutter="9">
- <a-col :span="12">
- <base-select
- resource="vpcs"
- filterable
- need-params
- v-model="filters.vpc"
- ref="vpcSelects"
- @change="handleVpcChange"
- class="vpc-selector"
- :isDefaultSelect="true"
- :params="renderOrders.vpc.params"
- :labelFormat="vpcLabelFormat"
- :select-props="{ placeholder: $t('network.text_274') }" />
- </a-col>
- <a-col :span="12">
- <base-select
- resource="networks"
- need-params
- filterable
- v-model="filters.network"
- ref="networkSelects"
- :style="{'--network-title': networkTitle}"
- class="network-selector"
- @change="handleNetworkChange"
- :isDefaultSelect="false"
- :params="renderOrders.network.params"
- :labelFormat="networkLabelFormat"
- :select-props="{ placeholder: $t('common_227') }" />
- </a-col>
- </a-row>
- </a-form-item>
- <a-form-item :label="$t('network.text_226')">
- <div>
- <search-box :options="options" v-model="searchValue" @input="search" />
- <detect-ssh-table :params="params" :key="table1Key" :showRadioSelect="true" @radio-change="handleRadioChange" :maxColumns="3" :remote="false" style="padding-top: 15px;" />
- <a-input v-decorator="decorators.server_id" v-show="false" />
- <div v-if="showDocsLink()">{{$t('compute.text_196')}}<help-link href="/vminstance">{{$t('compute.perform_create')}}</help-link>,{{$t('network.ssh-proxy.endpoints.create.vminstance.tips')}}<help-link :href="vmConfigurationLink">{{$t('network.ssh-proxy.endpoints.create.vminstance.tips.link')}}</help-link></div>
- </div>
- </a-form-item>
- </a-form>
- </div>
- <div class="step2" v-if="!isSetpOne">
- <detect-ssh-table :params="t2Params" :key="table2Key" :ansibleTasks="ansibleTasks" :remote="true" :maxColumns="3" @onDetecting="handleDetectStatusChange" />
- <a-alert :message="alertMessage" :type="alertType" v-show="alertType" />
- <setup-ssh-form ref="setupForm" :servers="servers" @tasks="handleSetupSSHTasks" v-show="showSetupForm" />
- </div>
- </page-body>
- <page-footer>
- <template v-slot:right>
- <a-button size="large" :loading="loading || detecting" @click="lastStep" v-show="!isSetpOne">{{ $t('scope.text_107') }}</a-button>
- <a-button class="ml-2" type="primary" size="large" :loading="loading || detecting" @click="handleSubmit">{{ isSetpOne ? $t('scope.text_108') : $t('common.ok') }}</a-button>
- <a-button class="ml-2" size="large" @click="handleCancel">{{ $t('dialog.cancel') }}</a-button>
- </template>
- </page-footer>
- </a-spin>
- </template>
- <script>
- import _ from 'lodash'
- import { DetectSshTable } from '@Compute/views/vminstance/dialogs/DetectSSH'
- import SetupSshForm from '@Compute/views/vminstance/create/form/SetupSSHForm'
- import AreaSelects from '@/sections/AreaSelects'
- import NameRepeated from '@/sections/NameRepeated'
- import {
- getStatusTableColumn,
- getIpsTableColumn,
- getNameDescriptionTableColumn,
- } from '@/utils/common/tableColumn'
- import { getNameFilter } from '@/utils/common/tableFilter'
- import ListMixin from '@/mixins/list'
- import { DOCS_MAP, showDocsLink } from '@/constants/docs'
- export default {
- name: 'SshProxyCreateForm',
- components: {
- DetectSshTable,
- SetupSshForm,
- AreaSelects,
- NameRepeated,
- },
- mixins: [ListMixin],
- data () {
- let domain = ''
- let showDomainSelect = true
- const serverlist = this.$list.createList(this, { id: 'ssh-endpoint-create-form', resource: 'servers' })
- if (this.$store.getters.scope === 'system') {
- domain = 'default'
- } else {
- showDomainSelect = false
- domain = this.$store.getters.userInfo.projectDomain || ''
- }
- const columns = [
- getNameDescriptionTableColumn({
- onManager: new this.$Manager('servers'),
- hideField: true,
- addBackup: true,
- editDesc: false,
- edit: false,
- slotCallback: row => {
- return (
- <side-page-trigger>{ row.name }</side-page-trigger>
- )
- },
- }),
- getStatusTableColumn({
- minWidth: 130,
- statusModule: 'server',
- slotCallback: row => {
- return [
- <div class='d-flex align-items-center text-truncate'>
- <status status={ row.status } statusModule='server' />
- </div>,
- ]
- },
- }),
- getIpsTableColumn({ field: 'ip', title: 'IP', vm: this }),
- ]
- this.handleNameChange = _.debounce(this.handleNameChange, 500)
- return {
- showDocsLink,
- loading: false,
- detecting: false,
- title: this.$t('network.ssh-proxy.endpoints.create'),
- networkTitle: JSON.stringify(`${this.$t('network.text_565')}: `),
- generate_name: '',
- step: {
- steps: [
- { title: this.$t('network.ssh-proxy.endpoint.create.step1'), key: 'select-endpoint' },
- { title: this.$t('network.ssh-proxy.endpoint.create.step2'), key: 'create-ssh-endpoint' },
- ],
- currentStep: 0,
- },
- endpointForm: this.$form.createForm(this.$refs.endpointFormRef),
- decorators: {
- generate_name: [
- 'generate_name',
- {
- rules: [
- { required: true, message: this.$t('network.text_116') },
- { validator: this.$validate('resourceName') },
- ],
- },
- ],
- description: ['description'],
- server_id: [
- 'server_id',
- {
- rules: [
- { required: true, message: this.$t('network.text_60') },
- ],
- },
- ],
- },
- servers: [],
- searchValue: {},
- options: {
- name: getNameFilter(),
- ip_addr: {
- label: 'IP',
- },
- },
- ansibleTasks: {},
- areaselectsName: ['provider', 'cloudregion'],
- showSetupForm: false,
- sshableStatus: '',
- alertMessage: '',
- alertType: '',
- table1Key: 't1',
- table2Key: 't2',
- t2Params: {
- onManager: serverlist.onManager,
- data: [],
- columns: columns,
- },
- params: {
- onManager: serverlist.onManager,
- data: [],
- columns: columns,
- },
- showDomainSelect: showDomainSelect,
- filters: {
- project_domain: domain,
- vpc: '',
- network: '',
- region: '',
- brand: '',
- },
- currentIndex: 1,
- renderOrders: {
- project_domain: { order: 1, next: 'brand', params: { scope: this.$store.getters.scope } },
- brand: { order: 2, next: 'region', params: { scope: this.$store.getters.scope, project_domain: domain } },
- region: { order: 3, next: 'vpc', params: {} },
- vpc: { order: 4, next: 'network', params: {} },
- network: { order: 5, next: 'server', params: {}, optional: true },
- server: { order: 6, params: {} },
- },
- formItemLayout: {
- wrapperCol: {
- span: 22,
- },
- labelCol: {
- span: 2,
- },
- },
- }
- },
- computed: {
- isSetpOne () {
- return this.step.currentStep === 0
- },
- vmConfigurationLink () {
- const lang = this.$store.getters.setting.language
- return DOCS_MAP.sshProxyVmConfiguration(lang)
- },
- },
- created () {
- if (!this.showDomainSelect) {
- this.handleDomainChange(this.filters.project_domain)
- }
- },
- methods: {
- _params (base, key, value) {
- const ret = Object.assign({}, base)
- if (value) {
- ret[key] = value
- } else {
- if (key) delete ret[key]
- }
- return ret
- },
- async fetchServers () {
- if (this.waitRender('server')) return
- const extraParams = {
- limit: 50,
- }
- if (this.searchValue.name) extraParams.filter = `name.contains('${this.searchValue.name.join(',')}')`
- if (this.searchValue.ip_addr) extraParams.ip_addr = this.searchValue.ip_addr.join(',')
- const params = Object.assign({}, this.renderOrders.server.params, extraParams)
- try {
- const ret = await new this.$Manager('servers').list({ params })
- this.params.data = ret.data.data
- this.$nextTick(() => {
- this.table1Key += 1
- })
- } catch (e) {
- throw e
- }
- },
- setNextRender (key, params) {
- this.currentIndex = this.renderOrders[key].order
- this.renderOrders[key].params = params
- // for (const item in this.renderOrders) {
- // if (this.renderOrders[item].order > this.currentIndex) {
- // this.renderOrders[item].params = {}
- // }
- // }
- },
- waitRender (key) {
- return this.currentIndex < this.renderOrders[key].order
- },
- handleDomainChange (e) {
- if (this.filters.domain !== e) {
- this.filters.domain = e
- if (e) {
- this.setNextRender('brand', this._params(this.renderOrders.project_domain.params, 'project_domain', e))
- this.$refs.areaSelects.fetchs(this.areaselectsName)
- }
- }
- },
- handleAreaChange (e) {
- if (e.hasOwnProperty('cloudregion')) {
- this.filters.region = e.cloudregion ? e.cloudregion.id : ''
- this.setNextRender('vpc', this._params(this.renderOrders.region.params, 'region', this.filters.region))
- }
- if (e.hasOwnProperty('provider')) {
- this.filters.brand = e.provider ? e.provider.id : ''
- this.setNextRender('region', this._params(this.renderOrders.brand.params, 'brand', this.filters.brand))
- }
- },
- handleVpcChange (e) {
- this.filters.vpc = e
- if (e || Object.keys(this.$refs.vpcSelects.resOpts).length === 0) {
- this.setNextRender('network', this._params(this.renderOrders.vpc.params, 'vpc', this.filters.vpc))
- }
- },
- handleNetworkChange (e) {
- this.filters.network = e
- if (e || Object.keys(this.$refs.networkSelects.resOpts).length === 0 || this.renderOrders.network.optional) {
- this.setNextRender('server', this._params(this.renderOrders.network.params, 'network', this.filters.network))
- this.fetchServers()
- }
- },
- search (e) {
- this.fetchServers()
- },
- vpcLabelFormat (item) {
- if (item.manager) {
- if (item.cidr_block) {
- return <div> { item.name }<span>({ item.cidr_block })</span><span class="ml-2 text-color-secondary">{this.$t('common_711')}: { item.manager }</span></div>
- }
- return <div> { item.name }<span class="ml-2 text-color-secondary">{this.$t('common_711')}: { item.manager }</span></div>
- }
- return <div>{ item.name }</div>
- },
- networkLabelFormat (item) {
- /* <span className="text-color-secondary option-prefix"></span> */
- return <div> { item.name } ({ item.guest_ip_start } - { item.guest_ip_end })</div>
- },
- handleRadioChange (row) {
- if (row) {
- this.t2Params.data = [row]
- this.servers = [row.id]
- this.endpointForm.setFieldsValue({ server_id: row.id })
- } else {
- this.t2Params.data = []
- this.servers = []
- this.endpointForm.setFieldsValue({ server_id: undefined })
- }
- this.table2Key += 1
- },
- handleSetupSSHTasks (tasks) {
- this.ansibleTasks = tasks
- this.table2Key += 1
- },
- handleNameChange (e) {
- this.generate_name = e.target.value
- },
- lastStep () {
- this.sshableStatus = ''
- this.showSetupForm = false
- this.step.currentStep = 0
- },
- async handleDetectStatusChange (e) {
- this.detecting = e
- if (this.sshableStatus || !this.detecting) {
- const newStatus = this.t2Params.data[0] ? this.t2Params.data[0].sshable_status : ''
- // 如果上次已经检测过状态,并且本次新状态是available,则可以直接创建endpoints
- if (this.sshableStatus && newStatus === 'available') {
- try {
- await this.submitEndpoint()
- } catch (e) {
- throw e
- }
- } else {
- if (newStatus !== 'available') {
- this.showSetupForm = true
- this.alertType = 'warning'
- this.alertMessage = this.$t('network.ssh-proxy.endpoint.create.step2.tips_failed')
- } else {
- this.alertType = 'success'
- this.showSetupForm = false
- this.alertMessage = this.$t('network.ssh-proxy.endpoint.create.step2.tips_success')
- }
- this.sshableStatus = newStatus
- }
- }
- },
- cloudregionParamsMapper (params) {
- const ret = { ...params }
- if (ret.provider === 'OneCloud') {
- delete ret.capability
- }
- return ret
- },
- handleCancel () {
- this.$router.push('/ssh-proxy')
- },
- validateForm (form) {
- return new Promise((resolve, reject) => {
- form.validateFieldsAndScroll({ scroll: { alignWithTop: true, offsetTop: 100 } }, (err, values) => {
- if (!err) {
- resolve(values)
- } else {
- reject(err)
- }
- })
- })
- },
- async submitEndpoint () {
- const values = await this.validateForm(this.endpointForm)
- await new this.$Manager('proxy_endpoints').performClassAction({ action: 'create-from-server', data: values })
- this.handleCancel()
- },
- async submitNextStep () {
- await this.validateForm(this.endpointForm)
- this.step.currentStep = 1
- },
- async submitMakeSshable () {
- await this.$refs.setupForm.submit()
- },
- async handleSubmit (e) {
- this.loading = true
- try {
- if (this.isSetpOne) {
- await this.submitNextStep()
- } else {
- if (this.showSetupForm) {
- await this.submitMakeSshable()
- }
- if (this.sshableStatus === 'available') {
- await this.submitEndpoint()
- }
- }
- } catch (err) {
- throw err
- } finally {
- this.loading = false
- }
- },
- },
- }
- </script>
- <style scoped>
- .vpc-selector .ant-select-selection-selected-value div:before {
- content: 'VPC:';
- color: rgba(0, 0, 0, 0.45);
- }
- .network-selector .ant-select-selection-selected-value div:before {
- content: var(--network-title);
- color: rgba(0, 0, 0, 0.45);
- }
- </style>
|