This commit is contained in:
05412 2024-08-02 16:03:30 +08:00
parent 2707070af5
commit db3872cc3a
5 changed files with 59 additions and 27 deletions

12
package-lock.json generated
View File

@ -8,6 +8,7 @@
"name": "surl-front",
"version": "0.0.0",
"dependencies": {
"ky": "^1.5.0",
"pinia": "^2.2.0",
"vite-plugin-vuetify": "^2.0.3",
"vue": "^3.4.31",
@ -890,6 +891,17 @@
"he": "bin/he"
}
},
"node_modules/ky": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/ky/-/ky-1.5.0.tgz",
"integrity": "sha512-bkQo+UqryW6Zmo/DsixYZE4Z9t2mzvNMhceyIhuMuInb3knm5Q+GNGMKveydJAj+Z6piN1SwI6eR/V0G+Z0BtA==",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sindresorhus/ky?sponsor=1"
}
},
"node_modules/magic-string": {
"version": "0.30.10",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.10.tgz",

View File

@ -9,6 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"ky": "^1.5.0",
"pinia": "^2.2.0",
"vite-plugin-vuetify": "^2.0.3",
"vue": "^3.4.31",

View File

@ -54,12 +54,11 @@ function toogleLocale() {
localStorage.setItem('locale', current.value)
}
function toggleTheme () {
function toggleTheme() {
const currentTheme = theme.global.current.value.dark ? 'light' : 'dark'
theme.global.name.value = currentTheme
localStorage.setItem('theme', currentTheme)
}
</script>
<template>
@ -67,21 +66,29 @@ function toggleTheme () {
<v-app>
<v-app-bar>
<v-container class="mx-auto d-flex align-center justify-start">
<v-btn class="home-menu-button" :text="t('$vuetify.menu.home')" to="/" :active="false" prepend-icon="mdi-home"></v-btn>
<v-btn class="home-menu-button" :text="t('$vuetify.menu.services')" to="/services" :active="false"></v-btn>
<v-btn class="home-menu-button" :text="t('$vuetify.menu.home')" to="/" :active="false"
prepend-icon="mdi-home"></v-btn>
<v-btn class="home-menu-button" :text="t('$vuetify.menu.services')" to="/services" :active="false"
prepend-icon="mdi-database"></v-btn>
<v-spacer></v-spacer>
<v-text-field class="home-search-box" density="compact" :label="t('$vuetify.menu.search')" rounded="lg"
variant="solo-filled"
flat hide-details single-line append-inner-icon="mdi-magnify"></v-text-field>
<v-btn icon="mdi-theme-light-dark" class="ml-10" @click="toggleTheme"></v-btn>
<v-btn icon="mdi-translate" class="ml-2" @click="toogleLocale"></v-btn>
<v-btn icon="mdi-theme-light-dark" class="ml-10" @click="toggleTheme"
v-tooltip="t('$vuetify.menu.themeSwitchTitle')"></v-btn>
<v-btn icon="mdi-translate" class="ml-2" @click="toogleLocale" v-tooltip="t('$vuetify.menu.languageSwitchTitle')"></v-btn>
<v-badge dot color="red">
<v-btn icon="mdi-account" class="ml-2" id="avatar"></v-btn>
</v-badge>
<v-menu open-on-hover activator="#avatar" open-delay="0" close-delay="500" location="bottom" width="150">
<v-list>
<v-list-item value="1" @click="showLoginDialog = true; isLoginFaild = false" v-if="!userinfoStore.isLogin" append-icon="mdi-login">
<v-list-item value="1" @click="showLoginDialog = true; isLoginFaild = false" v-if="!userinfoStore.isLogin"
append-icon="mdi-login">
<v-list-item-title>{{ t('$vuetify.user.login') }}</v-list-item-title>
</v-list-item>
<v-list-item value="2" :active="false" @click="logout" v-if="userinfoStore.isLogin" append-icon="mdi-logout">
<v-list-item value="2" :active="false" @click="logout" v-if="userinfoStore.isLogin"
append-icon="mdi-logout">
<v-list-item-title>{{ t('$vuetify.user.logout') }}</v-list-item-title>
</v-list-item>
</v-list>
@ -91,32 +98,39 @@ function toggleTheme () {
<v-main class="px-10">
<router-view/>
</v-main>
<v-footer>footer</v-footer>
</v-app>
</v-responsive>
<v-dialog v-model="showLoginDialog" persistent width="400">
<v-card prepend-icon="mdi-login" :title="t('$vuetify.login.title')" class="px-10">
<v-text-field class="login-dialong-input" flat prepend-inner-icon="mdi-account-outline" :label="t('$vuetify.login.username')"
<v-text-field class="login-dialong-input" flat prepend-inner-icon="mdi-account-outline"
:label="t('$vuetify.login.username')"
density="compact" @input="resetLoginError"
hide-details single-line rounded="lg" variant="solo-filled" v-model="username"></v-text-field>
<v-text-field class="login-dialong-input" flat prepend-inner-icon="mdi-lock-outline" :label="t('$vuetify.login.password')"
<v-text-field class="login-dialong-input" flat prepend-inner-icon="mdi-lock-outline"
:label="t('$vuetify.login.password')"
density="compact" hide-details single-line v-model="password" rounded="lg" variant="solo-filled"
:type="passwordVisibleState ? 'text' :'password'" title="password" @input="resetLoginError"
:append-inner-icon="passwordVisibleState ? 'mdi-eye-off' : 'mdi-eye'"
@click:append-inner="passwordVisibleState = !passwordVisibleState"></v-text-field>
<v-alert class="text-medium-emphasis text-caption mb-2" type="warning" icon="mdi-alert" closable
v-model="isLoginFaild">{{ t('$vuetify.login.failedNote') }}</v-alert>
v-model="isLoginFaild">{{ t('$vuetify.login.failedNote') }}
</v-alert>
<v-card color="surface-variant mt-5" variant="tonal">
<v-card-text class="text-medium-emphasis text-caption">
{{ t('$vuetify.login.agreement') }}
<v-label class="text-caption"><a href="/input" target="_blank">{{ t('$vuetify.login.termsOfService') }}</a></v-label>
<v-label class="text-caption"><a href="/input" target="_blank">{{ t('$vuetify.login.termsOfService') }}</a>
</v-label>
</v-card-text>
</v-card>
<v-checkbox class="login-dialong-input" :label="t('$vuetify.login.rememberMe')" hide-details color="primary"></v-checkbox>
<v-checkbox class="login-dialong-input" :label="t('$vuetify.login.rememberMe')" hide-details
color="primary"></v-checkbox>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn :text="t('$vuetify.login.button.cancel')" @click="showLoginDialog = false"></v-btn>
<v-btn :loading="loading" color="primary" :text="t('$vuetify.login.button.login')" @click="tryLogin" :icon="loginIcon"
<v-btn :loading="loading" color="primary" :text="t('$vuetify.login.button.login')" @click="tryLogin"
:icon="loginIcon"
:disabled="loginDisabled">
</v-btn>
</v-card-actions>
@ -134,6 +148,6 @@ function toggleTheme () {
}
.home-menu-button {
width: 100px;
width: 120px;
}
</style>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import {request} from "../../script/functions.ts";
import {ref} from "vue";
import {ref, watch} from "vue";
interface Urls {
key: string,
@ -14,14 +14,12 @@ interface Surls {
}
const urls = ref<Urls[]>([])
const selected = ref([])
watch(selected, () => console.log(selected.value))
async function getSurl() {
const requestPromise = request('api/surl/get', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token') || ''
}
})
const requestPromise = request('api/surl/get')
try {
const request = await requestPromise
const body: Surls = await request.json()
@ -34,8 +32,9 @@ async function getSurl() {
<template>
<v-btn @click="getSurl">get</v-btn>
<v-data-table :items="urls"
:headers="[{title: 'KEY', value: 'key', key: 'key'}, {title: 'URL', value: 'value', key: 'value'}]">
<v-data-table :items="urls" :item-value="item => item" show-select v-model="selected"
v-slot:header.data-table-select height="400" fixed-header
:headers="[{title: 'KEY', value: 'key', key: 'key', align: 'center'}, {title: 'URL', value: 'value', key: 'value'}]">
</v-data-table>
</template>

View File

@ -16,12 +16,18 @@ interface Msg {
value?: any
}
async function request(path: string, init: RequestInit): Promise<Response> {
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)
return fetch(`${protocol}://${host}/${path}`, {
...init,
headers: {
...init.headers,
'Authorization': `Bearer ${useUserinfoStore().token}`
}
})
}
async function login(username: string, password: string): Promise<boolean> {