250 lines
5.9 KiB
Vue
250 lines
5.9 KiB
Vue
<template>
|
|
<nav class="navmain">
|
|
<router-link :to="{ name: 'home' }" c-c f style="color: inherit; height: 100%; text-decoration: none">
|
|
<img height="50" src="@/assets/index.svg" width="50" />
|
|
<div>
|
|
<label style="font-size: 20px; margin-left: 10px; cursor: pointer">{{ useSettingStore.appName }}</label>
|
|
<label style="margin-left: 5px; font-size: 12px; cursor: pointer">V{{ useSettingStore.appVersion }}</label>
|
|
</div>
|
|
</router-link>
|
|
<div style="flex-grow: 1"></div>
|
|
<div c-c f style="height: 100%">
|
|
<div
|
|
v-bind:class="{
|
|
'router-item-atc': router.currentRoute.value.name === 'home',
|
|
'router-item': true,
|
|
}"
|
|
@click="router.push({ name: 'home' })">
|
|
<Icon icon="material-symbols:home" />
|
|
{{ $t('nav.title.home') }}
|
|
<div class="after"></div>
|
|
</div>
|
|
<div
|
|
v-bind:class="{
|
|
'router-item-atc': router.currentRoute.value.path.startsWith('/file'),
|
|
'router-item': true,
|
|
}"
|
|
@click="openFile()">
|
|
<Icon icon="material-symbols:folder-rounded" />
|
|
文件
|
|
<div class="after"></div>
|
|
</div>
|
|
<div
|
|
v-bind:class="{
|
|
'router-item-atc': router.currentRoute.value.name === 'user',
|
|
'router-item': true,
|
|
}"
|
|
@click="router.push({ name: 'user' })">
|
|
<Icon icon="material-symbols:person-rounded" />
|
|
用户
|
|
<div class="after"></div>
|
|
</div>
|
|
<div
|
|
v-bind:class="{
|
|
'router-item-atc': router.currentRoute.value.name === 'api',
|
|
'router-item': true,
|
|
}"
|
|
@click="router.push({ name: 'api' })">
|
|
<icon icon="mdi:api" />
|
|
API
|
|
<div class="after"></div>
|
|
</div>
|
|
<div
|
|
v-bind:class="{
|
|
'router-item': true,
|
|
}"
|
|
@click="activeSetting.on()">
|
|
<Icon icon="material-symbols:settings" />
|
|
设置
|
|
<div class="after"></div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<nav class="nav">
|
|
<n-drawer v-model:show="activeSetting.value" placement="right">
|
|
<n-drawer-content title="设置">
|
|
<n-divider>主题配置</n-divider>
|
|
<div c-c f>
|
|
<n-radio-group v-model:value="useSettingStore.themeMode" name="team">
|
|
<n-radio-button value="light">亮色</n-radio-button>
|
|
<n-radio-button value="dark">暗色</n-radio-button>
|
|
<n-radio-button value="auto">自动</n-radio-button>
|
|
</n-radio-group>
|
|
</div>
|
|
<n-divider>语言配置</n-divider>
|
|
<n-select
|
|
:options="messageData"
|
|
:render-label="renderLabel"
|
|
:render-tag="renderMultipleSelectTag"
|
|
:value="useSettingStore.language"
|
|
filterable
|
|
@update-value="useSettingStore.setLanguage"></n-select>
|
|
</n-drawer-content>
|
|
</n-drawer>
|
|
</nav>
|
|
</template>
|
|
<script lang="ts" setup>
|
|
import Icon from '@/components/Icon.vue';
|
|
import { UseBoolRef } from '@/util';
|
|
import { type languageIndexItemValueType, message, messageData, router, UseAuthStore, UseSettingStore } from '@/plugin';
|
|
import { getSysInfo } from '@/api/system.ts';
|
|
import type { SelectOption } from 'naive-ui/es/select/src/interface';
|
|
import type { VNodeChild } from 'vue';
|
|
|
|
export type RenderTag = (
|
|
props: {
|
|
option: SelectOption;
|
|
handleClose: () => void;
|
|
} & languageIndexItemValueType,
|
|
) => VNodeChild;
|
|
|
|
export type RenderTagSelect = (props: {
|
|
option: SelectOption & languageIndexItemValueType;
|
|
handleClose: () => void;
|
|
}) => VNodeChild;
|
|
const renderLabel: RenderTag = (data) => {
|
|
return h(
|
|
'div',
|
|
{
|
|
f: '',
|
|
'n-c': '',
|
|
style: {
|
|
gap: '10px',
|
|
},
|
|
},
|
|
[h(Icon, { icon: data.icon }), data.title],
|
|
);
|
|
};
|
|
const renderMultipleSelectTag: RenderTagSelect = ({ option: data }) => {
|
|
return h(
|
|
'div',
|
|
{
|
|
f: '',
|
|
'n-c': '',
|
|
style: {
|
|
gap: '10px',
|
|
},
|
|
},
|
|
[h(Icon, { icon: data.icon }), data.title],
|
|
);
|
|
};
|
|
|
|
const useSettingStore = UseSettingStore();
|
|
const activeSetting = UseBoolRef();
|
|
const useAuthStore = UseAuthStore();
|
|
getSysInfo().then((r) => {
|
|
const data = r.json().data;
|
|
useSettingStore.appName = data.appName;
|
|
useSettingStore.appVersion = data.appVersion;
|
|
document.title = data.appName;
|
|
});
|
|
useAuthStore.woIsMe();
|
|
|
|
useSettingStore.setLanguage(null);
|
|
|
|
function openFile() {
|
|
if (useAuthStore.isLogin) {
|
|
router.push({
|
|
path: `/file/${useAuthStore.username}`,
|
|
});
|
|
} else {
|
|
message.error('请先登录');
|
|
router.push({
|
|
path: `/login`,
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
html.dark {
|
|
.router-item-atc {
|
|
--atc-color: #66ffad;
|
|
|
|
&:hover {
|
|
--atc-color: #66b3ff !important;
|
|
}
|
|
}
|
|
|
|
.router-item {
|
|
&:hover {
|
|
--atc-color: #965522;
|
|
background-color: rgba(255, 255, 255, 0.15);
|
|
}
|
|
}
|
|
}
|
|
|
|
.router-item-atc {
|
|
--atc-color: #64a8fc;
|
|
|
|
&:hover {
|
|
--atc-color: #42e3e8;
|
|
}
|
|
}
|
|
|
|
:where(.router-item) {
|
|
cursor: pointer;
|
|
min-width: 50px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100%;
|
|
position: relative;
|
|
--atc-color: rgba(255, 255, 255, 0);
|
|
|
|
&:hover {
|
|
--atc-color: #ffd56f;
|
|
background-color: rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.after {
|
|
width: 100%;
|
|
height: 2px;
|
|
position: absolute;
|
|
bottom: 0;
|
|
background-color: var(--atc-color);
|
|
}
|
|
}
|
|
|
|
.nvr-button {
|
|
border-radius: 10px;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.nvr-button:hover {
|
|
background-color: #d8d8d8;
|
|
}
|
|
|
|
html.dark {
|
|
.nvr-button:hover {
|
|
background-color: #404040;
|
|
}
|
|
}
|
|
|
|
.nav {
|
|
height: 66px;
|
|
width: 100%;
|
|
}
|
|
|
|
.navmain {
|
|
position: fixed;
|
|
backdrop-filter: blur(5px);
|
|
height: 65px;
|
|
width: calc(100% - 40px);
|
|
z-index: 5;
|
|
padding: 0 20px;
|
|
display: flex;
|
|
|
|
background-color: rgba(221, 221, 221, 0.6);
|
|
border-bottom: #d3d3d3 1px solid;
|
|
}
|
|
|
|
html.dark {
|
|
.navmain {
|
|
background-color: rgba(0, 0, 0, 0.6);
|
|
border-bottom: #424242 1px solid;
|
|
}
|
|
}
|
|
</style>
|