index.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <template>
  2. <a-popover v-model="visible" trigger="click" placement="left">
  3. <template slot="content">
  4. <div v-if="mfaShow" class="wrap-inner">
  5. <h5 class="auth-base-title text-center">{{ $t('auth.secret.verify.title') }}</h5>
  6. <div class="verify-tip">{{ $t('auth.secret.reset.prefix1') }}</div>
  7. <div class="code-wrap d-flex justify-content-center">
  8. <security-code ref="security-code" is-small v-model="securityCode" :error="error" @completed="onValid" @clear="onClear" blurOnComplete />
  9. </div>
  10. <div class="status-tip">
  11. <div v-if="error" class="error">{{ $t('auth.secret.validate') }}</div>
  12. <div v-if="mfaLoading" class="loading"><a-icon type="sync" spin />{{ $t('auth.secret.loading') }}</div>
  13. </div>
  14. </div>
  15. <a-icon type="sync" spin v-else-if="infoShow && loading" />
  16. <div v-else-if="infoShow && !loading" class="info-wrapper">
  17. <div>
  18. <span class="label inline-block">{{$t('compute.text_1017')}}:</span>
  19. <span class="inline-block"><list-body-cell-wrap copy alwaysShowCopyBtn field="vnc_type" :row="form" /></span>
  20. </div>
  21. <div class="mt-2">
  22. <span class="label inline-block">{{$t('compute.text_386')}}:</span>
  23. <span class="inline-block"><list-body-cell-wrap copy alwaysShowCopyBtn field="ip" :row="form" /></span>
  24. </div>
  25. <div class="mt-2">
  26. <span class="label inline-block">{{$t('compute.text_349')}}:</span>
  27. <span class="inline-block"><list-body-cell-wrap copy alwaysShowCopyBtn field="port" :row="form" /></span>
  28. </div>
  29. <div class="mt-2">
  30. <span class="label inline-block">{{$t('compute.text_340')}}:</span>
  31. <span class="inline-block"><list-body-cell-wrap copy alwaysShowCopyBtn field="password" :row="form" /></span>
  32. </div>
  33. </div>
  34. </template>
  35. <div>
  36. <div class="info-btn d-flex justify-content-center pl-2 pr-2" @click.stop="handleWrapClick">
  37. <span @click.stop="handleButtonClick" style="font-size: 12px">{{buttonText}}</span>
  38. <span class="ml-2" @click.stop="handleKeyClick">
  39. <icon size="12" class="keypair-icon" type="keypairs" fill="#555" />
  40. </span>
  41. </div>
  42. </div>
  43. </a-popover>
  44. </template>
  45. <script>
  46. import { mapGetters } from 'vuex'
  47. import WindowsMixin from '@/mixins/windows'
  48. export default {
  49. name: 'VncInfoFetcher',
  50. mixins: [WindowsMixin],
  51. props: {
  52. onManager: Function,
  53. row: Object,
  54. buttonText: String,
  55. buttonProps: Object,
  56. },
  57. data () {
  58. return {
  59. securityCode: '',
  60. error: false,
  61. visible: false,
  62. mfaShow: false,
  63. infoShow: false,
  64. loading: false,
  65. form: {
  66. vnc_type: '',
  67. ip: '',
  68. port: '',
  69. password: '',
  70. },
  71. }
  72. },
  73. computed: {
  74. ...mapGetters(['userInfo', 'auth']),
  75. enableMFA () {
  76. return this.userInfo.enable_mfa && this.auth.auth.system_totp_on
  77. },
  78. },
  79. watch: {
  80. securityCode (val) {
  81. if (val.length < 6) {
  82. this.error = false
  83. }
  84. },
  85. },
  86. methods: {
  87. handleWrapClick (e) {
  88. this.$nextTick(() => {
  89. if (this.visible) return
  90. this.buttonProps.onClick(e)
  91. })
  92. },
  93. handleButtonClick (e) {
  94. this.$nextTick(() => {
  95. if (this.visible) return
  96. this.buttonProps.onClick(e)
  97. })
  98. },
  99. handleKeyClick () {
  100. if (this.visible) return
  101. if (this.enableMFA) {
  102. this.mfaShow = true
  103. this.visible = true
  104. } else {
  105. this.visible = true
  106. this.fetchInfo()
  107. }
  108. },
  109. async fetchInfo () {
  110. this.loading = true
  111. this.infoShow = true
  112. this.mfaShow = false
  113. this.securityCode = ''
  114. try {
  115. const { data = {} } = await new this.$Manager('servers', 'v2').getSpecific({
  116. id: this.row.id,
  117. spec: 'vnc',
  118. })
  119. this.form.vnc_type = data.protocol || '-'
  120. this.form.ip = data.host || '-'
  121. this.form.port = data.port || '-'
  122. this.form.password = data.password || '-'
  123. this.loading = false
  124. } catch (err) {
  125. this.loading = false
  126. throw err
  127. }
  128. },
  129. async onValid () {
  130. this.mfaLoading = true
  131. try {
  132. await this.$store.dispatch('auth/validPasscode', {
  133. passcode: this.securityCode,
  134. })
  135. this.mfaLoading = false
  136. await this.$store.commit('auth/UPDATE_AUTH')
  137. this.fetchInfo()
  138. } catch (error) {
  139. this.error = true
  140. this.mfaLoading = false
  141. }
  142. },
  143. onClear () {
  144. this.error = false
  145. this.$refs['security-code'].focusInput(1)
  146. },
  147. },
  148. }
  149. </script>
  150. <style lang="less" scoped>
  151. @import '~@/styles/less/theme';
  152. .info-btn:hover{
  153. color: @primary-color;
  154. }
  155. .info-wrapper {
  156. font-size: 14px;
  157. }
  158. .label {
  159. width: 100px;
  160. }
  161. .inline-block {
  162. display: inline-block;
  163. }
  164. .wrap {
  165. width: 810px;
  166. position: relative;
  167. }
  168. .wrap-inner {
  169. padding: 10px 20px 0 20px;
  170. }
  171. .code-wrap {
  172. margin-top: 15px;
  173. }
  174. .status-tip {
  175. font-size: 12px;
  176. margin-top: 15px;
  177. text-align: center;
  178. .error {
  179. color: #DD2727;
  180. }
  181. .loading {
  182. i {
  183. margin-right: 5px;
  184. }
  185. }
  186. }
  187. .verify-tip {
  188. color: #A6AEBC;
  189. font-size: 12px;
  190. text-align: center;
  191. margin-bottom: 20px;
  192. .reset-secret-btn {
  193. margin-left: 10px;
  194. }
  195. }
  196. </style>