对接登录

This commit is contained in:
05412 2024-07-31 18:11:59 +08:00
parent 408994e4f0
commit f81afb3782
6 changed files with 136 additions and 9 deletions

View File

@ -1,11 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref} from "vue"; import {ref} from "vue";
import {login} from "../../script/functions";
const showLoginDialog = ref(false) const showLoginDialog = ref(false)
const username = ref('') const username = ref('')
const password = ref('') const password = ref('')
const passwordVisibleState = ref(false) const passwordVisibleState = ref(false)
const loading = ref(false)
const loginDisabled = ref(false)
const loginIcon = ref<any>(null)
async function tryLogin() {
loading.value = true
const isSuccess = await login(username.value, password.value)
if (isSuccess) {
loginIcon.value = "mdi-check"
loading.value = false
loginDisabled.value = true
setTimeout(() => {
showLoginDialog.value = false
}, 1000)
} else {
alert("login failed")
loading.value = false
}
}
</script> </script>
<template> <template>
@ -36,19 +56,30 @@ const passwordVisibleState = ref(false)
</v-main> </v-main>
</v-app> </v-app>
</v-responsive> </v-responsive>
<v-dialog v-model="showLoginDialog" persistent width="500"> <v-dialog v-model="showLoginDialog" persistent width="400">
<v-card prepend-icon="mdi-login" title="LOGIN" class="px-10"> <v-card prepend-icon="mdi-login" title="LOGIN" class="px-10">
<v-text-field class="login-dialong-input" flat prepend-icon="mdi-account" label="USERNAME" density="compact" <v-text-field class="login-dialong-input" flat prepend-inner-icon="mdi-account-outline" label="USERNAME"
density="compact"
hide-details single-line rounded="lg" variant="solo-filled" v-model="username"></v-text-field> hide-details single-line rounded="lg" variant="solo-filled" v-model="username"></v-text-field>
<v-text-field class="login-dialong-input" flat prepend-icon="mdi-lock" label="PASSWORD" density="compact" <v-text-field class="login-dialong-input" flat prepend-inner-icon="mdi-lock-outline" label="PASSWORD"
hide-details single-line v-model="password" rounded="lg" variant="solo-filled" density="compact" hide-details single-line v-model="password" rounded="lg" variant="solo-filled"
:type="passwordVisibleState ? 'text' :'password'" title="password" :type="passwordVisibleState ? 'text' :'password'" title="password"
:append-inner-icon="passwordVisibleState ? 'mdi-eye-off' : 'mdi-eye'" :append-inner-icon="passwordVisibleState ? 'mdi-eye-off' : 'mdi-eye'"
@click:append-inner="passwordVisibleState = !passwordVisibleState"></v-text-field> @click:append-inner="passwordVisibleState = !passwordVisibleState"></v-text-field>
<v-card color="surface-variant" variant="tonal">
<v-card-text class="text-medium-emphasis text-caption">
PLEASE CONFIRM YOU HAVE READ AND AGREE TO THE
<v-label class="text-caption"><a href="javascript:void(0);">TERMS OF SERVICE</a></v-label>
</v-card-text>
</v-card>
<v-checkbox class="login-dialong-input" label="Remember me" hide-details color="primary"></v-checkbox>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text="CANCEL" @click="showLoginDialog = false"></v-btn> <v-btn text="CANCEL" @click="showLoginDialog = false"></v-btn>
<v-btn color="primary" text="OK" @click="console.log(username, password)"></v-btn> <v-btn :loading="loading" color="primary" text="LOGIN" @click="tryLogin()" :icon="loginIcon"
:disabled="loginDisabled">
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
@ -58,7 +89,8 @@ const passwordVisibleState = ref(false)
max-width: 500px; max-width: 500px;
min-width: 200px; min-width: 200px;
} }
.login-dialong-input { .login-dialong-input {
margin-bottom: 10px; margin: 10px 0;
} }
</style> </style>

View File

@ -8,6 +8,7 @@ const slogans = [
const show = ref(""); const show = ref("");
let c = 0, i = 0, showIndicator = ref(true); let c = 0, i = 0, showIndicator = ref(true);
const showTimeout = 10000; const showTimeout = 10000;
const printTime = 1000;
showSlogan(0) showSlogan(0)
setInterval(() => { setInterval(() => {
i++ i++
@ -18,7 +19,7 @@ setInterval(() => {
function showSlogan(i: number) { function showSlogan(i: number) {
const slogan = slogans[i] const slogan = slogans[i]
const timeout = 2000 / slogan.length const timeout = printTime / slogan.length
const handle = setInterval(() => { const handle = setInterval(() => {
show.value = slogan.substring(0, c % slogan.length + 1); show.value = slogan.substring(0, c % slogan.length + 1);
c++; c++;
@ -30,7 +31,7 @@ function showSlogan(i: number) {
setTimeout(() => { setTimeout(() => {
clearInterval(indicatorHandle) clearInterval(indicatorHandle)
showIndicator.value = true; showIndicator.value = true;
}, showTimeout - 2000) }, showTimeout - printTime)
} }
}, timeout) }, timeout)
} }

View File

@ -1,9 +1,44 @@
<script setup lang="ts"> <script setup lang="ts">
import {request} from "../../script/functions.ts";
import {ref} from "vue";
interface Urls {
key: string,
value: string
}
interface Surls {
code: number,
msg?: string,
value?: Urls[]
}
const urls = ref<Urls[]>([])
async function getSurl() {
const requestPromise = request('api/surl/get', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token') || ''
}
})
try {
const request = await requestPromise
const body: Surls = await request.json()
urls.value = body.value ?? []
} catch (e) {
console.log(e)
}
}
</script> </script>
<template> <template>
<v-window></v-window> <v-btn @click="getSurl">get</v-btn>
<ul>
<li v-for="url in urls">
<a :href="url.value">{{url.key}}: {{ url.value }}</a>
</li>
</ul>
</template> </template>
<style scoped> <style scoped>

45
src/script/functions.ts Normal file
View File

@ -0,0 +1,45 @@
import {useSiteConfigStore} from "../stores/siteconfig-store.ts";
import {useUserinfoStore} from "../stores/userinfo-store.ts";
interface LoginInfo {
code: number,
msg?: string,
value?: {
expireAt: string,
token: string
}
}
async function request(path: string, init: RequestInit): Promise<Response> {
const useSiteConfig = useSiteConfigStore()
const siteConfig = useSiteConfig.siteConfig
const protocol = siteConfig.protocol
const host = siteConfig.host
return fetch(`${protocol}://${host}/${path}`, init)
}
async function login(username: string, password: string): Promise<boolean> {
const userinfoStore = useUserinfoStore()
const responsePromise = request('login', {
method: 'POST',
body: JSON.stringify({username, password}),
headers: {
'Content-Type': 'application/json'
},
mode: 'cors'
})
try {
const response = await responsePromise
const body: LoginInfo = await response.json()
if(body.code == 0) {
userinfoStore.setToken(body.value?.token ?? '')
return true
} else {
return false
}
} catch (_) {
return false
}
}
export { request, login }

View File

@ -0,0 +1,14 @@
import {defineStore} from "pinia";
import {ref} from "vue";
interface SiteConfig {
protocol: string,
host: string
}
export const useSiteConfigStore = defineStore('siteConfigStore', ()=> {
const siteConfig = ref<SiteConfig>({
protocol: 'http',
host: 'localhost:18888'
})
return { siteConfig }
})