uniLogin.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <div class="auth-form-panel uni-login-panel">
  3. <div class="logo">
  4. <img alt="RunForge" src="/logo.svg" height="40">
  5. <span class="title">RunForge | 快捷登录</span>
  6. </div>
  7. <a-form size="large" :model="form" :rules="[]" class="form" @submit="handleSubmit">
  8. <div class="uniLoginButton">
  9. <div class="button" v-if="isTypeEnabled('qq')">
  10. <a-tooltip content="QQ登录" mini>
  11. <a-avatar :size="64" :style="{ backgroundColor: '#FE82A5' }"
  12. @click="GetLoginUrl('qq')"><icon-qq /></a-avatar>
  13. </a-tooltip>
  14. </div>
  15. <div class="button" v-if="isTypeEnabled('wx')">
  16. <a-tooltip content="微信登录" mini>
  17. <a-avatar :size="64" :style="{ backgroundColor: '#FE82A5' }"
  18. @click="GetLoginUrl('wx')"><icon-wechat /></a-avatar>
  19. </a-tooltip>
  20. </div>
  21. </div>
  22. <a-alert v-if="!optionsLoading && enabledTypes.length === 0" type="warning" class="disabled-tip">
  23. 快捷登录暂未开启,请使用账号密码登录
  24. </a-alert>
  25. <div class="tip">未注册的第三方账号登录后将自动注册</div>
  26. <a-button type="text" class="forgetpass" @click="emit('changeMode', 'login')">账号密码登录</a-button>
  27. </a-form>
  28. </div>
  29. <div class="loading" v-if="loading">
  30. <div class="loadingTip">
  31. <icon-loading :size="32" />
  32. <div class="text">努力加载中</div>
  33. </div>
  34. </div>
  35. </template>
  36. <script setup>
  37. import { getLoginUrl, getUniLoginOptions } from '@/api/login'
  38. import { timeFix } from '@/utils/util'
  39. import { useRoute, useRouter } from 'vue-router'
  40. import { ref, onMounted } from 'vue'
  41. import { Notification } from '@arco-design/web-vue'
  42. import { useUserStore } from '@/store/modules/user'
  43. import { isElectron } from '@/utils/electron'
  44. const userStore = useUserStore()
  45. const loading = ref(false)
  46. const optionsLoading = ref(false)
  47. const enabledTypes = ref(['qq', 'wx'])
  48. const route = useRoute()
  49. const router = useRouter()
  50. const emit = defineEmits(['changeMode', 'changeLoading'])
  51. const from = route.query.from
  52. const isTypeEnabled = (type) => enabledTypes.value.includes(type)
  53. const loadOptions = async () => {
  54. try {
  55. optionsLoading.value = true
  56. const res = await getUniLoginOptions()
  57. if (res?.code === 0 && Array.isArray(res.data?.enabledTypes))
  58. enabledTypes.value = res.data.enabledTypes
  59. } catch (error) {
  60. console.log(error)
  61. } finally {
  62. optionsLoading.value = false
  63. }
  64. }
  65. const GetLoginUrl = async (type) => {
  66. if (!isTypeEnabled(type))
  67. return requestFailed('该登录方式已关闭')
  68. try {
  69. changeLoading(true)
  70. const res = await getLoginUrl({ type })
  71. if (!res || res.code != 0)
  72. return requestFailed('获取登录链接失败!' + res?.msg ?? '')
  73. if (isElectron())
  74. window.electron.openNewWindow(res.data)
  75. else
  76. window.location.href = res.data
  77. } catch (error) {
  78. console.log(error)
  79. requestFailed('获取登录链接失败!')
  80. } finally {
  81. changeLoading(false)
  82. }
  83. }
  84. const UniLogin = async (type, code) => {
  85. try {
  86. changeLoading(true)
  87. const res = await userStore.uniLogin(type, code)
  88. loginSuccess(res)
  89. } catch (error) {
  90. requestFailed(error.message || '登录失败!请稍后再试')
  91. } finally {
  92. changeLoading(false)
  93. }
  94. }
  95. const BindSocial = async (type, code) => {
  96. try {
  97. changeLoading(true)
  98. const user = await userStore.getInfo()
  99. if (!user?.uuid || !user?.session)
  100. throw new Error('请先登录后再绑定第三方账号')
  101. await userStore.bindSocial(type, code)
  102. Notification.success({
  103. title: '绑定成功',
  104. content: `${type === 'qq' ? 'QQ' : '微信'}账号已绑定到当前账户`,
  105. duration: 2000
  106. })
  107. if (isElectron())
  108. window.electron.openOldWindow(from || '/user/setting')
  109. else
  110. router.push(from || '/user/setting')
  111. } catch (error) {
  112. requestFailed(error.message || '绑定失败!请稍后再试')
  113. router.push('/user/setting')
  114. } finally {
  115. changeLoading(false)
  116. }
  117. }
  118. const changeLoading = (value) => {
  119. loading.value = value
  120. }
  121. const loginSuccess = (res) => {
  122. Notification.success({
  123. title: `${timeFix()},${res.username}`,
  124. content: '欢迎回来!',
  125. duration: 2000
  126. })
  127. if (isElectron())
  128. window.electron.openOldWindow(from || '/')
  129. else
  130. router.push(from || '/')
  131. }
  132. const requestFailed = (msg) => {
  133. Notification.error({
  134. title: '错误',
  135. content: msg || '请求出现错误,请稍后再试',
  136. })
  137. }
  138. onMounted(() => {
  139. loadOptions()
  140. if (route.query.type && route.query.code) {
  141. if (route.query.action === 'bind')
  142. BindSocial(route.query.type, route.query.code)
  143. else
  144. UniLogin(route.query.type, route.query.code)
  145. }
  146. })
  147. </script>
  148. <style lang="less" scoped>
  149. @import '@/styles/auth-marketing.less';
  150. .loading {
  151. position: fixed;
  152. top: 0;
  153. left: 0;
  154. height: 100%;
  155. width: 100%;
  156. background-color: rgba(0, 0, 0, 0.2);
  157. z-index: 9999;
  158. border-radius: 10px;
  159. .loadingTip {
  160. position: absolute;
  161. top: 50%;
  162. left: 50%;
  163. transform: translate(-50%, -50%);
  164. color: #FE82A5;
  165. .text {
  166. font-family: 'Alimama ShuHeiTi';
  167. font-size: 1.2em;
  168. }
  169. }
  170. }
  171. .uni-login-panel {
  172. position: relative;
  173. }
  174. .tip {
  175. color: #777;
  176. font-size: 0.9em;
  177. text-align: left;
  178. margin-bottom: 20px;
  179. margin-left: -8px;
  180. }
  181. .disabled-tip {
  182. margin-bottom: 16px;
  183. text-align: left;
  184. }
  185. .uniLoginButton {
  186. display: flex;
  187. gap: 40px;
  188. justify-content: center;
  189. height: 100px;
  190. .button {
  191. cursor: pointer;
  192. }
  193. }
  194. .forgetpass {
  195. width: 100px;
  196. margin-top: -10px;
  197. margin-left: -15px;
  198. }
  199. </style>