Merge pull request #3335 from h3poteto/iss-3301/login

refs #3301 Rewrite Login with composition API
This commit is contained in:
AkiraFukushima 2022-05-04 00:49:06 +09:00 committed by GitHub
commit 875d7dbde2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 96 deletions

View File

@ -16,25 +16,34 @@
</el-container> </el-container>
</template> </template>
<script> <script lang="ts">
import LoginForm from './Login/LoginForm' import { defineComponent } from 'vue'
import { mapState } from 'vuex' import { useRouter } from 'vue-router'
import { useStore } from '@/store'
import LoginForm from './Login/LoginForm.vue'
import { ACTION_TYPES } from '@/store/Login'
export default { export default defineComponent({
name: 'login', name: 'login',
components: { LoginForm }, components: { LoginForm },
computed: { setup() {
...mapState({ const space = 'Login'
page: state => state.Login.page const store = useStore()
}) const router = useRouter()
},
methods: { const close = () => {
close() { store.dispatch(`${space}/${ACTION_TYPES.PAGE_BACK}`)
this.$store.dispatch('Login/pageBack') return router.push({
return this.$router.push({ path: '/', query: { redirect: 'home' } }) path: '/',
query: { redirect: 'home' }
})
}
return {
close
} }
} }
} })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,9 +1,9 @@
<template> <template>
<el-form <el-form
ref="loginForm" ref="loginFormRef"
label-width="120px" label-width="120px"
label-position="top" label-position="top"
v-on:submit.prevent="confirm('loginForm')" v-on:submit.prevent="confirm(loginFormRef)"
class="login-form" class="login-form"
:rules="rules" :rules="rules"
:model="form" :model="form"
@ -26,7 +26,7 @@
type="primary" type="primary"
class="search" class="search"
v-else v-else
@click="confirm('loginForm')" @click="confirm(loginFormRef)"
v-loading="searching" v-loading="searching"
element-loading-background="rgba(0, 0, 0, 0.8)" element-loading-background="rgba(0, 0, 0, 0.8)"
> >
@ -36,112 +36,118 @@
</el-form> </el-form>
</template> </template>
<script> <script lang="ts">
import { mapState } from 'vuex' import { defineComponent, computed, reactive, ref } from 'vue'
import { domainFormat } from '../../utils/validator' import { useI18next } from 'vue3-i18next'
import { ElLoading, ElMessage, FormInstance, FormRules } from 'element-plus'
import { useRouter } from 'vue-router'
import { useStore } from '@/store'
import { domainFormat } from '@/utils/validator'
import { ACTION_TYPES } from '@/store/Login'
export default { export default defineComponent({
name: 'login-form', name: 'login-form',
data() { setup() {
return { const space = 'Login'
form: { const store = useStore()
domainName: '' const i18n = useI18next()
} const router = useRouter()
}
}, const form = reactive({
computed: { domainName: ''
...mapState({ })
selectedInstance: state => state.Login.selectedInstance, const loginFormRef = ref<FormInstance>()
searching: state => state.Login.searching,
sns: state => state.Login.sns const selectedInstance = computed(() => store.state.Login.selectedInstance)
}), const searching = computed(() => store.state.Login.searching)
allowLogin: function () { const sns = computed(() => store.state.Login.sns)
return this.selectedInstance && this.form.domainName === this.selectedInstance const allowLogin = computed(() => selectedInstance.value && form.domainName === selectedInstance.value)
}, const rules = reactive<FormRules>({
rules: { domainName: [
get() { {
return { type: 'string',
domainName: [ required: true,
{ message: i18n.t('validation.login.require_domain_name')
type: 'string', },
required: true, {
message: this.$t('validation.login.require_domain_name') pattern: domainFormat,
}, trigger: 'change',
{ message: i18n.t('validation.login.domain_format')
pattern: domainFormat,
trigger: 'change',
message: this.$t('validation.login.domain_format')
}
]
} }
} ]
} })
},
methods: { const login = () => {
login() { const loading = ElLoading.service({
const loading = this.$loading({
lock: true, lock: true,
text: this.$t('message.loading'), text: i18n.t('message.loading'),
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}) })
this.$store store
.dispatch('Login/fetchLogin') .dispatch(`${space}/${ACTION_TYPES.FETCH_LOGIN}`)
.then(url => { .then(url => {
loading.close() store.dispatch(`${space}/${ACTION_TYPES.PAGE_BACK}`)
this.$store.dispatch('Login/pageBack') router.push({
this.$router.push({
path: '/authorize', path: '/authorize',
query: { url: url, sns: this.sns } query: { url: url, sns: sns.value }
}) })
}) })
.catch(() => { .catch(err => {
loading.close() ElMessage({
this.$message({ message: i18n.t('message.authorize_url_error'),
message: this.$t('message.authorize_url_error'),
type: 'error' type: 'error'
}) })
console.error(err)
}) })
}, .finally(() => {
confirm(formName) { loading.close()
this.$refs[formName].validate(valid => { })
}
const confirm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(valid => {
if (valid) { if (valid) {
this.$store return store
.dispatch('Login/confirmInstance', this.form.domainName) .dispatch(`${space}/${ACTION_TYPES.CONFIRM_INSTANCE}`, form.domainName)
.then(() => { .then(() => {
this.$message({ ElMessage({
message: this.$t('message.domain_confirmed', { message: i18n.t('message.domain_confirmed', {
domain: this.form.domainName domain: form.domainName
}), }),
type: 'success' type: 'success'
}) })
}) })
.catch(() => { .catch(err => {
this.$message({ ElMessage({
message: this.$t('message.domain_doesnt_exist', { message: i18n.t('message.domain_doesnt_exist', {
domain: this.form.domainName domain: form.domainName
}), }),
type: 'error' type: 'error'
}) })
console.error(err)
}) })
} else { } else {
this.$message({ ElMessage({
message: this.$t('validation.login.domain_format'), message: i18n.t('validation.login.domain_format'),
type: 'error' type: 'error'
}) })
return false return false
} }
}) })
}, }
handleKey(_event) {
if (!this.selectedInstance) { return {
this.confirm('loginForm') form,
} else { loginFormRef,
this.login() searching,
} allowLogin,
rules,
login,
confirm
} }
} }
} })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -3,7 +3,7 @@ import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store' import { RootState } from '@/store'
import { MyWindow } from '~/src/types/global' import { MyWindow } from '~/src/types/global'
const win = (window as any) as MyWindow const win = window as any as MyWindow
export type LoginState = { export type LoginState = {
selectedInstance: string | null selectedInstance: string | null
@ -35,18 +35,24 @@ const mutations: MutationTree<LoginState> = {
} }
} }
export const ACTION_TYPES = {
FETCH_LOGIN: 'fetchLogin',
PAGE_BACK: 'pageBack',
CONFIRM_INSTANCE: 'confirmInstance'
}
const actions: ActionTree<LoginState, RootState> = { const actions: ActionTree<LoginState, RootState> = {
fetchLogin: async ({ state }): Promise<string> => { [ACTION_TYPES.FETCH_LOGIN]: async ({ state }): Promise<string> => {
const url = await win.ipcRenderer.invoke('get-auth-url', { const url = await win.ipcRenderer.invoke('get-auth-url', {
instance: state.selectedInstance, instance: state.selectedInstance,
sns: state.sns sns: state.sns
}) })
return url return url
}, },
pageBack: ({ commit }) => { [ACTION_TYPES.PAGE_BACK]: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_INSTANCE, null) commit(MUTATION_TYPES.CHANGE_INSTANCE, null)
}, },
confirmInstance: async ({ commit }, domain: string): Promise<boolean> => { [ACTION_TYPES.CONFIRM_INSTANCE]: async ({ commit }, domain: string): Promise<boolean> => {
commit(MUTATION_TYPES.CHANGE_SEARCHING, true) commit(MUTATION_TYPES.CHANGE_SEARCHING, true)
const cleanDomain = domain.trim() const cleanDomain = domain.trim()
try { try {