添加仪表盘

This commit is contained in:
05412 2024-08-07 18:18:57 +08:00
parent 92abcad0db
commit 34b406492a
14 changed files with 155 additions and 65 deletions

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
profile
</template>
<style scoped>
</style>

View File

@ -37,7 +37,7 @@ async function tryRegister() {
} }
} }
loading.value = false loading.value = false
if (isRegisterFailed.value == false) { if (!isRegisterFailed.value) {
registerIcon.value = "mdi-check" registerIcon.value = "mdi-check"
disableRegister.value = true disableRegister.value = true
setTimeout(() => { setTimeout(() => {

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
security
</template>
<style scoped>
</style>

View File

@ -0,0 +1,13 @@
<script setup lang="ts">
import {getUrlsOfCurrentUser, Surl} from "../../script/functions.ts";
const surls = (await getUrlsOfCurrentUser()).value ?? <Surl[]>[]
</script>
<template>
<v-data-table :items="surls"></v-data-table>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import {useLocale} from "vuetify";
const {t} = useLocale()
</script>
<template>
<v-row class="py-5">
<v-col cols="auto">
<v-sheet elevation="1" class="rounded-lg">
<v-list class="rounded-lg">
<v-list-item to="/dashboard/url-management" prepend-icon="mdi-link" append-icon="mdi-chevron-right">
<v-list-item-title>{{t('$vuetify.dashboard.menu.url-management')}}</v-list-item-title>
</v-list-item>
<v-list-item to="/dashboard/profile" prepend-icon="mdi-account" append-icon="mdi-chevron-right">
<v-list-item-title>{{t('$vuetify.dashboard.menu.profile')}}</v-list-item-title>
</v-list-item>
<v-list-item to="/dashboard/security" prepend-icon="mdi-security" append-icon="mdi-chevron-right">
<v-list-item-title>{{t('$vuetify.dashboard.menu.security')}}</v-list-item-title>
</v-list-item>
</v-list>
</v-sheet>
</v-col>
<v-col>
<v-sheet class="border-thin rounded-lg pa-10 overflow-auto">
<router-view />
</v-sheet>
</v-col>
</v-row>
</template>
<style scoped>
</style>

View File

@ -35,7 +35,7 @@ function toggleTheme() {
</script> </script>
<template> <template>
<v-responsive class="rounded mx-auto" max-width="1600px"> <v-responsive class="rounded mx-auto" max-width="1600">
<v-app> <v-app>
<v-app-bar> <v-app-bar>
<v-container class="mx-auto d-flex align-center justify-start"> <v-container class="mx-auto d-flex align-center justify-start">
@ -55,18 +55,22 @@ function toggleTheme() {
<v-btn icon="mdi-account" class="ml-2" id="avatar"></v-btn> <v-btn icon="mdi-account" class="ml-2" id="avatar"></v-btn>
</v-badge> </v-badge>
<v-menu open-on-hover activator="#avatar" open-delay="0" close-delay="500" location="bottom" width="150"> <v-menu open-on-hover activator="#avatar" open-delay="0" close-delay="500" location="bottom" width="auto">
<v-list> <v-list>
<v-list-item value="1" @click="showLoginDialog = true" v-if="!userinfoStore.isLogin" <v-list-item :active="false" to="/dashboard/url-management" v-if="userinfoStore.isLogin"
append-icon="mdi-login"> prepend-icon="mdi-gauge" append-icon="mdi-chevron-right">
<v-list-item-title>Dashboard</v-list-item-title>
</v-list-item>
<v-list-item @click="showLoginDialog = true" v-if="!userinfoStore.isLogin"
prepend-icon="mdi-login" append-icon="mdi-chevron-right">
<v-list-item-title>{{ t('$vuetify.user.login') }}</v-list-item-title> <v-list-item-title>{{ t('$vuetify.user.login') }}</v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item value="2" :active="false" @click="logout" v-if="userinfoStore.isLogin" <v-list-item :active="false" @click="logout" v-if="userinfoStore.isLogin"
append-icon="mdi-logout"> prepend-icon="mdi-logout" append-icon="mdi-chevron-right">
<v-list-item-title>{{ t('$vuetify.user.logout') }}</v-list-item-title> <v-list-item-title>{{ t('$vuetify.user.logout') }}</v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item value="3" :active="false" @click="showRegisterDialog = true" v-if="!userinfoStore.isLogin" <v-list-item :active="false" @click="showRegisterDialog = true" v-if="!userinfoStore.isLogin"
append-icon="mdi-account-plus"> prepend-icon="mdi-account-plus" append-icon="mdi-chevron-right">
<v-list-item-title>{{ t('$vuetify.user.register') }}</v-list-item-title> <v-list-item-title>{{ t('$vuetify.user.register') }}</v-list-item-title>
</v-list-item> </v-list-item>
</v-list> </v-list>

View File

@ -1,45 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {request} from "../../script/functions.ts";
import {ref, watch} from "vue";
interface Urls {
key: string,
value: string
}
interface Surls {
code: number,
msg?: string,
value?: Urls[]
}
const urls = ref<Urls[]>([])
const selected = ref([])
const tableHeaderConfig = ref([
{title: 'KEY1', value: 'key', key: 'key'},
{title: 'URL', value: 'value', key: 'value'}
])
watch(selected, () => console.log(selected.value))
async function getSurl() {
const requestPromise = request('api/surl/get')
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-btn @click="getSurl">get</v-btn>
<v-data-table :items="urls" :item-value="item => item" show-select v-model="selected"
v-slot:header.data-table-select fixed-header density="compact"
:headers="tableHeaderConfig" :header-props="{color: 'purple'}">
</v-data-table>
</template> </template>
<style scoped> <style scoped>

View File

@ -1,12 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import LoginDialog from "../items/LoginDialog.vue"; import DashboardView from "./DashboardView.vue";
import {ref} from "vue";
const showDialog = ref(true)
</script> </script>
<template> <template>
<LoginDialog v-model="showDialog"></LoginDialog> <DashboardView></DashboardView>
</template> </template>
<style scoped> <style scoped>

View File

@ -1,10 +1,24 @@
import {createRouter, createWebHistory} from "vue-router"; import {createRouter, createWebHistory} from "vue-router";
// @ts-ignore
import Login from "./components/views/LoginView.vue"; import Login from "./components/views/LoginView.vue";
// @ts-ignore
import InputBox from "./components/items/InputBox.vue"; import InputBox from "./components/items/InputBox.vue";
// @ts-ignore
import IntroView from "./components/views/IntroView.vue"; import IntroView from "./components/views/IntroView.vue";
// @ts-ignore
import TestView from "./components/views/TestView.vue"; import TestView from "./components/views/TestView.vue";
// @ts-ignore
import ServiceView from "./components/views/ServiceView.vue"; import ServiceView from "./components/views/ServiceView.vue";
// @ts-ignore
import NotFound from "./components/items/NotFound.vue"; import NotFound from "./components/items/NotFound.vue";
// @ts-ignore
import DashboardView from "./components/views/DashboardView.vue";
// @ts-ignore
import Profile from "./components/items/Profile.vue";
// @ts-ignore
import Security from "./components/items/Security.vue";
// @ts-ignore
import UrlManagement from "./components/items/UrlManagement.vue";
const routes = [ const routes = [
{ {
@ -22,6 +36,19 @@ const routes = [
}, { }, {
path: '/services', path: '/services',
component: ServiceView component: ServiceView
}, {
path: '/dashboard',
component: DashboardView,
children: [{
path: 'profile',
component: Profile
}, {
path: 'security',
component: Security
}, {
path: 'url-management',
component: UrlManagement
}]
}, { }, {
path: '/404', path: '/404',
component: NotFound component: NotFound

View File

@ -1,7 +1,7 @@
import {useSiteConfigStore} from "../stores/siteconfig-store.ts"; import {useSiteConfigStore} from "../stores/siteconfig-store.ts";
import {useUserinfoStore} from "../stores/userinfo-store.ts"; import {useUserinfoStore} from "../stores/userinfo-store.ts";
interface LoginInfo { export interface LoginInfo {
code: number, code: number,
msg?: string, msg?: string,
value?: { value?: {
@ -10,13 +10,15 @@ interface LoginInfo {
} }
} }
interface Msg { export interface Msg<T> {
code: number, code: number,
msg?: string, msg?: string,
value?: any value?: T
} }
async function request(path: string, init: RequestInit = {}): Promise<Response> { export interface Surl {}
export async function request(path: string, init: RequestInit = {}): Promise<Response> {
const useSiteConfig = useSiteConfigStore() const useSiteConfig = useSiteConfigStore()
const siteConfig = useSiteConfig.siteConfig const siteConfig = useSiteConfig.siteConfig
const protocol = siteConfig.protocol const protocol = siteConfig.protocol
@ -30,7 +32,7 @@ async function request(path: string, init: RequestInit = {}): Promise<Response>
}) })
} }
async function login(username: string, password: string): Promise<boolean> { export async function login(username: string, password: string): Promise<boolean> {
const userinfoStore = useUserinfoStore() const userinfoStore = useUserinfoStore()
const responsePromise = request('login', { const responsePromise = request('login', {
method: 'POST', method: 'POST',
@ -54,7 +56,7 @@ async function login(username: string, password: string): Promise<boolean> {
} }
} }
async function register(username: string, password: string): Promise<boolean> { export async function register(username: string, password: string): Promise<boolean> {
const responsePromise = request('reg', { const responsePromise = request('reg', {
method: 'POST', method: 'POST',
body: JSON.stringify({username, password}), body: JSON.stringify({username, password}),
@ -65,20 +67,20 @@ async function register(username: string, password: string): Promise<boolean> {
}) })
try { try {
const response = await responsePromise const response = await responsePromise
const body: Msg = await response.json() const body: Msg<any> = await response.json()
return body.code == 0 return body.code == 0
} catch (_) { } catch (_) {
return false return false
} }
} }
function logout() { export function logout() {
const userinfoStore = useUserinfoStore() const userinfoStore = useUserinfoStore()
userinfoStore.setToken('') userinfoStore.setToken('')
window.location.reload() window.location.href = '/'
} }
async function checkLogin(): Promise<boolean> { export async function checkLogin(): Promise<boolean> {
const userinfoStore = useUserinfoStore() const userinfoStore = useUserinfoStore()
if (userinfoStore.isLogin) { if (userinfoStore.isLogin) {
try { try {
@ -87,7 +89,7 @@ async function checkLogin(): Promise<boolean> {
'Authorization': `Bearer ${userinfoStore.token}` 'Authorization': `Bearer ${userinfoStore.token}`
} }
}) })
const body: Msg = await response.json() const body: Msg<any> = await response.json()
return body.code == 0 return body.code == 0
} catch (_) { } catch (_) {
return false return false
@ -97,4 +99,8 @@ async function checkLogin(): Promise<boolean> {
} }
} }
export {request, login, logout, checkLogin, register} export async function getUrlsOfCurrentUser() {
const response = await request('api/surl/get')
const body: Msg<Surl[]> = await response.json()
return body
}

View File

@ -43,6 +43,13 @@ const en: LocaleInterface = {
register: "REGISTER", register: "REGISTER",
cancel: "CANCEL" cancel: "CANCEL"
} }
},
dashboard: {
menu: {
'url-management': 'URL Management',
profile: 'Profile',
security: 'Security'
}
} }
} }
export default en export default en

View File

@ -40,6 +40,13 @@ export default interface LocaleInterface {
register: string, register: string,
cancel: string cancel: string
} }
},
dashboard: {
menu: {
'url-management': string,
profile: string,
security: string
}
} }
// ================== // ==================
// vuetify // vuetify

View File

@ -43,6 +43,13 @@ const zhHans: LocaleInterface = {
register: "注册", register: "注册",
cancel: "取消" cancel: "取消"
} }
},
dashboard: {
menu: {
'url-management': '链接管理',
profile: '用户信息',
security: '安全性'
}
} }
} }
export default zhHans export default zhHans

View File

@ -5,7 +5,12 @@
"target": "ES2020", "target": "ES2020",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"module": "ESNext", "module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"], "lib": [
"ES2020",
"DOM",
"DOM.Iterable",
"dom"
],
"skipLibCheck": true, "skipLibCheck": true,
/* Bundler mode */ /* Bundler mode */