feat: change theme and index style

This commit is contained in:
廖庆斯 2024-11-20 00:09:25 +08:00
parent 6aaf607ed7
commit 9a97a1ee72
19 changed files with 5190 additions and 14633 deletions

18923
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
"dependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@openai/realtime-api-beta": "github:openai/openai-realtime-api-beta",
"animate.css": "^4.1.1",
"axios": "^0.27.2",
"clipboard": "^2.0.11",
"compressorjs": "^1.2.1",

View File

@ -1,18 +1,19 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
<html lang="zh-cn" data-theme="light">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,user-scalable=no"
/>
<title>Geek-AI 创作助手</title>
</head>
</head>
<body>
<noscript>
<strong>请开启JavaScript支持</strong>
</noscript>
<div id="app"></div>
</body>
</html>
<body>
<noscript>
<strong>请开启JavaScript支持</strong>
</noscript>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1,9 @@
.btn-go{
background: var(--btnColor);
color: #fff;
border-radius: 5px;
padding: 5px 10px;
&:hover{
color: #fff;
}
}

View File

@ -0,0 +1,24 @@
@font-face {
font-family: "OPlusSans3-Regular";
src: url("../fonts/OPlusSans3-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "OPlusSans3-Medium";
src: url("../fonts/OPlusSans3-Medium.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
$font-regular = "OPlusSans3-Regular", "PingFangSC-Regular", "Roboto", "sans-serif";
$font-medium = "OPlusSans3-Medium", "PingFangSC-Medium", "Roboto", "sans-serif";
.font-regular {
font-family: $font-regular;
font-weight: normal;
}
.font-medium {
font-family: $font-medium;
font-weight: 500;
}

View File

@ -1,7 +1,8 @@
.index-page {
margin: 0
overflow hidden
color #ffffff
color var(--text-color)
display flex
justify-content center
align-items baseline
@ -47,11 +48,20 @@
display flex
padding 20px 0
color #ffffff
color var(--text-color);
.iconfont{
color var(--text-color);
font-size: 28px;
}
.icon-book{
margin-right: 6px;
}
.title {
font-size 24px
color var(--text-color);
font-size: 24px;
padding 10px 10px 0 10px
font-weight: 700;
}
.logo {
@ -112,6 +122,34 @@
}
}
}
.nav-item-box{
width: 100%;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.645,0.045,0.355,1);
aspect-ratio: 1.1028 / 1;
background: var( --card-bg)
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 160px
// min-height: 190px;
i{
display: inline-block
min-width: 48px;
width: 48px;
height: 48px;
font-size: 38px
border-radius: 24px;
color: var(--normal-color)
}
&:hover{
box-shadow: 0 4px 14px 0 rgba(17, 13, 83, .18);
transform: translateY(-8px);}
}
}
}
@ -121,4 +159,38 @@
}
}
}
}
.cursor-ani {
position: relative;
}
.cursor-ani::after {
content: '';
position: absolute;
width: 1px;
height: 28px;
background: #333;
transform: translateX(3px) translateY(3px);
animation: cursor-blinks 0.8s infinite forwards;
}
@keyframes cursor-blinks {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.cursor-ani {
display: inline-block;
min-height: 34px;
font-size: 1.5em;
}
.msg-text span {
transition: color 0.3s ease; /* */
font-weight: bold;
}

View File

@ -0,0 +1,21 @@
@import 'font.styl'
:root[data-theme="dark"]{
--text-color: rgba(255, 255, 255, 1) !important; //
--normal-color: rgba(163, 174, 208, 1); //
p, h1, h2, h3, h4, h5, h6, article {
color: var(--text-color) !important;
font-family: $font-regular;
}
html,
body,
#app,
.wrapper {
background-color: rgb(13, 20, 53) !important;
font-family: $font-regular;
}
--btnColor: linear-gradient(88deg, #af61f0 1.44%, #5b62ce);
--card-bg: rgba(17, 28, 68, 1);
}

View File

@ -0,0 +1,26 @@
@import 'font.styl'
:root[data-theme="light"] {
// rgba(43, 54, 116, 1)
--text-color: #5b62ce; //
--normal-color: rgba(43, 54, 116, 1); //
p, h1, h2, h3, h4, h5, h6, article {
color: var(--text-color) !important;
font-family: $font-regular;
}
html,
body,
#app,
.wrapper {
background: linear-gradient(88deg, #fff3f3 1.44%, #e7e8ff);
// background: linear-gradient(180deg, #fff, #fff4fa 40%, #fbd9fd 55%, #e2d5ff 70%);
font-family: $font-regular;
}
--btnColor: linear-gradient(88deg, #af61f0 1.44%, #5b62ce);
--card-bg:#fff;
}

View File

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,9 @@
@font-face {
font-family: "iconfont"; /* Project id 4125778 */
src: url('iconfont.woff2?t=1731289567907') format('woff2'),
url('iconfont.woff?t=1731289567907') format('woff'),
url('iconfont.ttf?t=1731289567907') format('truetype');
font-family: 'iconfont'; /* Project id 4125778 */
src: url('//at.alicdn.com/t/c/font_4125778_gs96jfl3hlc.woff2?t=1732009095144') format('woff2'),
url('//at.alicdn.com/t/c/font_4125778_gs96jfl3hlc.woff?t=1732009095144') format('woff'),
url('//at.alicdn.com/t/c/font_4125778_gs96jfl3hlc.ttf?t=1732009095144') format('truetype');
}
.iconfont {

View File

@ -1,9 +1,11 @@
<template>
<div class="foot-container">
<div class="footer">
<div><span :style="{color:textColor}">{{copyRight}}</span></div>
<div>
<span>{{ copyRight }}</span>
</div>
<div v-if="!license.de_copy">
<a :href="gitURL" target="_blank" :style="{color:textColor}">
<a :href="gitURL" target="_blank">
{{ title }} -
{{ version }}
</a>
@ -12,37 +14,45 @@
</div>
</template>
<script setup>
import { ref } from "vue";
import { httpGet } from "@/utils/http";
import { showMessageError } from "@/utils/dialog";
import { getLicenseInfo, getSystemInfo } from "@/store/cache";
import {ref} from "vue";
import {httpGet} from "@/utils/http";
import {showMessageError} from "@/utils/dialog";
import {getLicenseInfo, getSystemInfo} from "@/store/cache";
const title = ref("")
const version = ref(process.env.VUE_APP_VERSION)
const gitURL = ref(process.env.VUE_APP_GIT_URL)
const copyRight = ref('')
const license = ref({})
const title = ref("");
const version = ref(process.env.VUE_APP_VERSION);
const gitURL = ref(process.env.VUE_APP_GIT_URL);
const copyRight = ref("");
const license = ref({});
const props = defineProps({
textColor: {
type: String,
default: '#ffffff'
},
default: "#ffffff"
}
});
//
getSystemInfo().then(res => {
title.value = res.data.title??process.env.VUE_APP_TITLE
copyRight.value = res.data.copyright.length>1?res.data.copyright:'极客学长 © 2023 - '+new Date().getFullYear()+' All rights reserved.'
}).catch(e => {
showMessageError("获取系统配置失败:" + e.message)
})
getSystemInfo()
.then((res) => {
title.value = res.data.title ?? process.env.VUE_APP_TITLE;
copyRight.value =
res.data.copyright.length > 1
? res.data.copyright
: "极客学长 © 2023 - " +
new Date().getFullYear() +
" All rights reserved.";
})
.catch((e) => {
showMessageError("获取系统配置失败:" + e.message);
});
getLicenseInfo().then(res => {
license.value = res.data
}).catch(e => {
showMessageError("获取 License 失败:" + e.message)
})
getLicenseInfo()
.then((res) => {
license.value = res.data;
})
.catch((e) => {
showMessageError("获取 License 失败:" + e.message);
});
</script>
<style scoped lang="stylus">
@ -62,11 +72,15 @@ getLicenseInfo().then(res => {
width 100%
a {
color:var(--text-color)
&:hover {
text-decoration underline
}
}
span{
color:var(--text-color)
}
}
}
</style>
</style>

View File

@ -0,0 +1,56 @@
<template>
<div class="theme-box" @click="toggleTheme">
<span class="iconfont icon-yueliang">{{
themePage === "light" ? "&#xe679;" : "&#xe60b;"
}}</span>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
// localStorage
const themePage = ref(localStorage.getItem("theme") || "light");
//
const toggleTheme = () => {
themePage.value = themePage.value === "light" ? "dark" : "light";
document.documentElement.setAttribute("data-theme", themePage.value); // HTML data-theme
localStorage.setItem("theme", themePage.value); // localStorage
};
onMounted(() => {
document.documentElement.setAttribute("data-theme", themePage.value);
});
</script>
<style lang="stylus" scoped>
@import '@/assets/iconfont/iconfont.css'
.theme-box{
position: fixed;
right: 40px;
bottom: 262px;
cursor: pointer;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 50%;
width 35px;
height: 35px;
line-height: 35px;
text-align: center;
background-color: rgb(146, 147, 148);
transition: all 0.3s ease;
&:hover{
transform: scale(1.1);
}
&:active{
transform: scale(0.9);
}
.iconfont{
font-size: 20px;
color: yellow;
transition: transform 0.3s ease;
}
}
</style>

View File

@ -5,63 +5,74 @@
// * @Author yangjian102621@163.com
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import {createApp} from 'vue'
import ElementPlus from "element-plus"
import "element-plus/dist/index.css"
import '@/assets/iconfont/iconfont.css';
import 'vant/lib/index.css';
import App from './App.vue'
import {createPinia} from "pinia";
import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import "@/assets/iconfont/iconfont.css";
import "vant/lib/index.css";
import App from "./App.vue";
import { useThemeStore } from "@/store/theme";
import { createPinia } from "pinia";
import "animate.css/animate.min.css";
import {
ActionSheet,
Badge,
Button,
Cell,
CellGroup,
Circle,
Col,
Collapse,
CollapseItem,
ConfigProvider,
Dialog,
Divider,
DropdownItem,
DropdownMenu,
Empty,
Field,
Form,
Grid,
GridItem,
Icon,
Image,
ImagePreview,
Lazyload,
List,
Loading,
NavBar,
NoticeBar,
Notify,
Overlay,
Picker,
Popup,
Row,
Search,
ShareSheet,
Slider,
Sticky,
SwipeCell,
Switch,
Tab,
Tabbar,
TabbarItem,
Tabs,
Tag,
TextEllipsis,
Uploader
ActionSheet,
Badge,
Button,
Cell,
CellGroup,
Circle,
Col,
Collapse,
CollapseItem,
ConfigProvider,
Dialog,
Divider,
DropdownItem,
DropdownMenu,
Empty,
Field,
Form,
Grid,
GridItem,
Icon,
Image,
ImagePreview,
Lazyload,
List,
Loading,
NavBar,
NoticeBar,
Notify,
Overlay,
Picker,
Popup,
Row,
Search,
ShareSheet,
Slider,
Sticky,
SwipeCell,
Switch,
Tab,
Tabbar,
TabbarItem,
Tabs,
Tag,
TextEllipsis,
Uploader
} from "vant";
import {router} from "@/router";
import 'v3-waterfall/dist/style.css'
import { router } from "@/router";
import "v3-waterfall/dist/style.css";
import V3waterfall from "v3-waterfall";
import "@/assets/css/theme-dark.styl";
import "@/assets/css/theme-light.styl";
import "@/assets/css/common.styl";
const pinia = createPinia();
const themeStore = useThemeStore(pinia); // 使用 theme store
// 设置初始主题
document.documentElement.setAttribute("data-theme", themeStore.theme);
const app = createApp(App);
app.use(createPinia());
@ -70,12 +81,12 @@ app.use(Tabbar);
app.use(TabbarItem);
app.use(NavBar);
app.use(Search);
app.use(Cell)
app.use(Image)
app.use(TextEllipsis)
app.use(Notify)
app.use(Picker)
app.use(Popup)
app.use(Cell);
app.use(Image);
app.use(TextEllipsis);
app.use(Notify);
app.use(Picker);
app.use(Popup);
app.use(List);
app.use(Form);
app.use(Field);
@ -91,12 +102,12 @@ app.use(ShareSheet);
app.use(Switch);
app.use(Uploader);
app.use(Tag);
app.use(V3waterfall)
app.use(Overlay)
app.use(Col)
app.use(Row)
app.use(Slider)
app.use(Badge)
app.use(V3waterfall);
app.use(Overlay);
app.use(Col);
app.use(Row);
app.use(Slider);
app.use(Badge);
app.use(Collapse);
app.use(CollapseItem);
app.use(Grid);
@ -111,6 +122,4 @@ app.use(Tabs);
app.use(Divider);
app.use(NoticeBar);
app.use(ActionSheet);
app.use(router).use(ElementPlus).mount('#app')
app.use(router).use(ElementPlus).mount("#app");

15
web/src/store/theme.js Normal file
View File

@ -0,0 +1,15 @@
// src/store/index.js
import { defineStore } from "pinia";
export const useThemeStore = defineStore("theme", {
state: () => ({
theme: localStorage.getItem("theme") || "light" // 默认从 localStorage 获取主题
}),
actions: {
setTheme(theme) {
this.theme = theme;
document.documentElement.setAttribute("data-theme", theme);
localStorage.setItem("theme", theme); // 保存到 localStorage
}
}
});

View File

@ -1,178 +1,194 @@
<template>
<div class="index-page" :style="{height: winHeight+'px'}">
<div :class="theme.imageBg?'color-bg image-bg':'color-bg'" :style="{backgroundImage:'url('+bgStyle.backgroundImage+')', backgroundColor:bgStyle.backgroundColor}"></div>
<div class="index-page">
<ThemeChange />
<div class="menu-box">
<el-menu
mode="horizontal"
:ellipsis="false"
>
<el-menu mode="horizontal" :ellipsis="false">
<div class="menu-item">
<el-image :src="logo" class="logo" alt="Geek-AI"/>
<div class="title" :style="{color:theme.textColor}">{{ title }}</div>
<el-image :src="logo" class="logo" alt="Geek-AI" />
</div>
<div class="menu-item">
<span v-if="!license.de_copy">
<a :href="docsURL" target="_blank">
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" round>
<i class="iconfont icon-book"></i>
<span>文档</span>
</el-button>
</a>
<a :href="gitURL" target="_blank">
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" round>
<i class="iconfont icon-github"></i>
<span>源码</span>
</el-button>
</a>
<el-tooltip
v-if="!license.de_copy"
class="box-item"
effect="light"
content="部署文档"
placement="bottom"
>
<a :href="docsURL" class="link-button" target="_blank">
<i class="iconfont icon-book"></i>
</a>
</el-tooltip>
<el-tooltip
v-if="!license.de_copy"
class="box-item"
effect="light"
content="项目源码"
placement="bottom"
>
<a :href="gitURL" class="link-button" target="_blank">
<i class="iconfont icon-github"></i>
</a>
</el-tooltip>
</span>
<span v-if="!isLogin">
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" @click="router.push('/login')" class="shadow" round>登录</el-button>
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" @click="router.push('/register')" class="shadow" round>注册</el-button>
<!-- <el-button @click="router.push('/login')" class="shadow" round
>登录</el-button
>
<el-button @click="router.push('/register')" class="shadow" round
>注册</el-button
> -->
<el-button
@click="router.push('/login')"
class="btn-go animate__animated animate__pulse animate__infinite"
round
>登录/注册</el-button
>
</span>
</div>
</el-menu>
</div>
<div class="content">
<h1 :style="{color:theme.textColor}">欢迎使用 {{ title }}</h1>
<p :style="{color:theme.textColor}">{{ slogan }}</p>
<h1 class="animate__animated animate__backInDown">
{{ title }}
</h1>
<div class="msg-text cursor-ani">
<span
v-for="(char, index) in displayedChars"
:key="index"
:style="{ color: rainbowColor(index) }"
>
{{ char }}
</span>
</div>
<div class="navs">
<el-space wrap>
<div v-for="item in navs" :key="item.url" class="nav-item">
<el-button @click="router.push(item.url)" :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" :dark="false">
<i :class="'iconfont '+iconMap[item.url]"></i>
<span>{{item.name}}</span>
</el-button>
<div class="navs animate__animated animate__backInDown">
<el-space wrap :size="14">
<div
v-for="item in navs"
:key="item.url"
class="nav-item-box"
@click="router.push(item.url)"
>
<i :class="'iconfont ' + iconMap[item.url]"></i>
<div>{{ item.name }}</div>
</div>
</el-space>
</div>
</div>
<footer-bar :text-color="theme.textColor" />
<footer-bar />
</div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import {useRouter} from "vue-router";
import { onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import FooterBar from "@/components/FooterBar.vue";
import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus";
import {checkSession, getLicenseInfo, getSystemInfo} from "@/store/cache";
import {isMobile} from "@/utils/libs";
import ThemeChange from "@/components/ThemeChange.vue";
import { httpGet } from "@/utils/http";
import { ElMessage } from "element-plus";
import { checkSession, getLicenseInfo, getSystemInfo } from "@/store/cache";
import { isMobile } from "@/utils/libs";
const router = useRouter()
const router = useRouter();
if (isMobile()) {
router.push("/mobile/index")
router.push("/mobile/index");
}
const title = ref("")
const logo = ref("")
const slogan = ref("")
const license = ref({de_copy: true})
const winHeight = window.innerHeight - 150
const isLogin = ref(false)
const docsURL = ref(process.env.VUE_APP_DOCS_URL)
const gitURL = ref(process.env.VUE_APP_GIT_URL)
const navs = ref([])
const btnColors = ref([
{bgColor: "#fff143", textColor: "#50616D"},
{bgColor: "#eaff56", textColor: "#50616D"},
{bgColor: "#bddd22", textColor: "#50616D"},
{bgColor: "#1bd1a5", textColor: "#50616D"},
{bgColor: "#e0eee8", textColor: "#50616D"},
{bgColor: "#7bcfa6", textColor: "#50616D"},
{bgColor: "#bce672", textColor: "#50616D"},
{bgColor: "#44cef6", textColor: "#ffffff"},
{bgColor: "#70f3ff", textColor: "#50616D"},
{bgColor: "#fffbf0", textColor: "#50616D"},
{bgColor: "#d6ecf0", textColor: "#50616D"},
{bgColor: "#88ada6", textColor: "#50616D"},
{bgColor: "#30dff3", textColor: "#50616D"},
{bgColor: "#d3e0f3", textColor: "#50616D"},
{bgColor: "#e9e7ef", textColor: "#50616D"},
{bgColor: "#eacd76", textColor: "#50616D"},
{bgColor: "#f2be45", textColor: "#50616D"},
{bgColor: "#549688", textColor: "#ffffff"},
{bgColor: "#758a99", textColor: "#ffffff"},
{bgColor: "#41555d", textColor: "#ffffff"},
{bgColor: "#21aa93", textColor: "#ffffff"},
{bgColor: "#0aa344", textColor: "#ffffff"},
{bgColor: "#f05654", textColor: "#ffffff"},
{bgColor: "#db5a6b", textColor: "#ffffff"},
{bgColor: "#db5a6b", textColor: "#ffffff"},
{bgColor: "#8d4bbb", textColor: "#ffffff"},
{bgColor: "#426666", textColor: "#ffffff"},
{bgColor: "#177cb0", textColor: "#ffffff"},
{bgColor: "#395260", textColor: "#ffffff"},
{bgColor: "#519a73", textColor: "#ffffff"},
{bgColor: "#75878a", textColor: "#ffffff"},
])
const iconMap =ref(
{
"/chat": "icon-chat",
"/mj": "icon-mj",
"/sd": "icon-sd",
"/dalle": "icon-dalle",
"/images-wall": "icon-image",
"/suno": "icon-suno",
"/xmind": "icon-xmind",
"/apps": "icon-app",
"/member": "icon-vip-user",
"/invite": "icon-share",
"/luma": "icon-luma",
}
)
const bgStyle = {}
const color = btnColors.value[Math.floor(Math.random() * btnColors.value.length)]
const theme = ref({bgColor: "#ffffff", btnBgColor: color.bgColor, btnTextColor: color.textColor, textColor: "#ffffff", imageBg:true})
const title = ref("");
const logo = ref("");
const slogan = ref("");
const license = ref({ de_copy: true });
const isLogin = ref(false);
const docsURL = ref(process.env.VUE_APP_DOCS_URL);
const gitURL = ref(process.env.VUE_APP_GIT_URL);
const navs = ref([]);
const iconMap = ref({
"/chat": "icon-chat",
"/mj": "icon-mj",
"/sd": "icon-sd",
"/dalle": "icon-dalle",
"/images-wall": "icon-image",
"/suno": "icon-suno",
"/xmind": "icon-xmind",
"/apps": "icon-app",
"/member": "icon-vip-user",
"/invite": "icon-share",
"/luma": "icon-luma"
});
const displayedChars = ref([]);
const initAnimation = ref("");
let timer = null; //
//
const interTime = ref(50);
const interArr = [90, 100, 70, 88, 80, 110, 85, 400, 90, 99];
onMounted(() => {
getSystemInfo().then(res => {
title.value = res.data.title
logo.value = res.data.logo
if (res.data.index_bg_url === 'color') {
//
theme.value.bgColor = color.bgColor
theme.value.btnBgColor = color.bgColor
theme.value.textColor = color.textColor
theme.value.btnTextColor = color.textColor
//
bgStyle.backgroundColor = theme.value.bgColor
bgStyle.backgroundImage = "/images/transparent-bg.png"
theme.value.imageBg = false
} else if (res.data.index_bg_url) {
bgStyle.backgroundImage = res.data.index_bg_url
} else {
bgStyle.backgroundImage = "/images/index-bg.jpg"
}
getSystemInfo()
.then((res) => {
title.value = res.data.title;
logo.value = res.data.logo;
slogan.value = res.data.slogan;
if (timer) clearInterval(timer); //
timer = setInterval(setContent, interTime.value);
})
.catch((e) => {
ElMessage.error("获取系统配置失败:" + e.message);
});
slogan.value = res.data.slogan
}).catch(e => {
ElMessage.error("获取系统配置失败:" + e.message)
})
getLicenseInfo()
.then((res) => {
license.value = res.data;
})
.catch((e) => {
license.value = { de_copy: false };
ElMessage.error("获取 License 配置失败:" + e.message);
});
getLicenseInfo().then(res => {
license.value = res.data
}).catch(e => {
license.value = {de_copy: false}
ElMessage.error("获取 License 配置失败:" + e.message)
})
httpGet("/api/menu/list?index=1")
.then((res) => {
navs.value = res.data;
})
.catch((e) => {
ElMessage.error("获取导航菜单失败:" + e.message);
});
httpGet("/api/menu/list?index=1").then(res => {
navs.value = res.data
}).catch(e => {
ElMessage.error("获取导航菜单失败:" + e.message)
})
checkSession().then(() => {
isLogin.value = true
}).catch(()=>{})
})
checkSession()
.then(() => {
isLogin.value = true;
})
.catch(() => {});
});
//
const setContent = () => {
if (initAnimation.value.length >= slogan.value.length) {
//
initAnimation.value = "";
displayedChars.value = [];
if (timer) clearInterval(timer);
timer = setInterval(setContent, interTime.value);
return;
} else {
const nextChar = slogan.value.charAt(initAnimation.value.length);
initAnimation.value += slogan.value.charAt(initAnimation.value.length); //
displayedChars.value.push(nextChar);
interTime.value = interArr[Math.floor(Math.random() * interArr.length)]; //
if (timer) clearInterval(timer);
timer = setInterval(setContent, interTime.value);
}
};
//
const rainbowColor = (index) => {
const hue = (index * 40) % 360; // 40
return `hsl(${hue}, 90%, 50%)`; // (hue)(70%)(50%)
};
</script>
<style lang="stylus" scoped>

View File

@ -1,10 +1,13 @@
<template>
<div class="admin-home" v-if="isLogin">
<admin-sidebar/>
<admin-sidebar />
<div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
<admin-header/>
<admin-tags/>
<div :class="'content '+theme" :style="{height:contentHeight+'px'}">
<admin-header />
<admin-tags />
<div
:class="'content ' + theme"
:style="{ height: contentHeight + 'px' }"
>
<router-view v-slot="{ Component }">
<transition name="move" mode="out-in">
<keep-alive :include="tags.nameList">
@ -17,40 +20,43 @@
</div>
</template>
<script setup>
import {useSidebarStore} from '@/store/sidebar';
import {useTagsStore} from '@/store/tags';
import { useSidebarStore } from "@/store/sidebar";
import { useTagsStore } from "@/store/tags";
import AdminHeader from "@/components/admin/AdminHeader.vue";
import AdminSidebar from "@/components/admin/AdminSidebar.vue";
import AdminTags from "@/components/admin/AdminTags.vue";
import {useRouter} from "vue-router";
import {checkAdminSession} from "@/store/cache";
import {ref, watch} from "vue";
import {useSharedStore} from "@/store/sharedata";
import { useRouter } from "vue-router";
import { checkAdminSession } from "@/store/cache";
import { ref, watch } from "vue";
import { useSharedStore } from "@/store/sharedata";
const sidebar = useSidebarStore();
const tags = useTagsStore();
const isLogin = ref(false)
const contentHeight = window.innerHeight - 80
const store = useSharedStore()
const theme = ref(store.adminTheme)
const isLogin = ref(false);
const contentHeight = window.innerHeight - 80;
const store = useSharedStore();
const theme = ref(store.adminTheme);
//
const router = useRouter();
checkAdminSession().then(() => {
isLogin.value = true
}).catch(() => {
router.replace('/admin/login')
})
watch(() => store.adminTheme, (val) => {
theme.value = val
})
checkAdminSession()
.then(() => {
isLogin.value = true;
})
.catch(() => {
router.replace("/admin/login");
});
watch(
() => store.adminTheme,
(val) => {
theme.value = val;
}
);
</script>
<style scoped lang="stylus">
@import '@/assets/css/color-dark.styl';
// @import '@/assets/css/color-dark.styl';
@import '@/assets/css/main.styl';
@import '@/assets/iconfont/iconfont.css';
</style>

View File

@ -1,31 +1,36 @@
const {defineConfig} = require('@vue/cli-service')
let webpack = require('webpack')
const { defineConfig } = require("@vue/cli-service");
const path = require("path");
let webpack = require("webpack");
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false, //关闭eslint校验
productionSourceMap: false, //在生产模式中禁用 Source Map既可以减少包大小也可以加密源码
configureWebpack: {
// disable performance hints
performance: {
hints: false
},
plugins: [
new webpack.optimize.MinChunkSizePlugin({minChunkSize: 10000})
]
transpileDependencies: true,
lintOnSave: false, //关闭eslint校验
productionSourceMap: false, //在生产模式中禁用 Source Map既可以减少包大小也可以加密源码
configureWebpack: {
// disable performance hints
performance: {
hints: false
},
publicPath: '/',
outputDir: 'dist',
crossorigin: "anonymous",
devServer: {
allowedHosts: "all",
port: 8888,
proxy: {
'/static/upload/': {
target: process.env.VUE_APP_API_HOST,
changeOrigin: true,
}
}
plugins: [new webpack.optimize.MinChunkSizePlugin({ minChunkSize: 10000 })],
resolve: {
alias: {
"@": path.resolve(__dirname, "src")
}
}
})
},
publicPath: "/",
outputDir: "dist",
crossorigin: "anonymous",
devServer: {
allowedHosts: "all",
port: 8888,
proxy: {
"/static/upload/": {
target: process.env.VUE_APP_API_HOST,
changeOrigin: true
}
}
}
});