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": { "dependencies": {
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@openai/realtime-api-beta": "github:openai/openai-realtime-api-beta", "@openai/realtime-api-beta": "github:openai/openai-realtime-api-beta",
"animate.css": "^4.1.1",
"axios": "^0.27.2", "axios": "^0.27.2",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"compressorjs": "^1.2.1", "compressorjs": "^1.2.1",

View File

@ -1,18 +1,19 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-cn"> <html lang="zh-cn" data-theme="light">
<head>
<head> <meta charset="utf-8" />
<meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"> name="viewport"
content="width=device-width,initial-scale=1.0,user-scalable=no"
/>
<title>Geek-AI 创作助手</title> <title>Geek-AI 创作助手</title>
</head> </head>
<body>
<noscript>
<strong>请开启JavaScript支持</strong>
</noscript>
<div id="app"></div>
</body>
<body>
<noscript>
<strong>请开启JavaScript支持</strong>
</noscript>
<div id="app"></div>
</body>
</html> </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 { .index-page {
margin: 0 margin: 0
overflow hidden overflow hidden
color #ffffff color var(--text-color)
display flex display flex
justify-content center justify-content center
align-items baseline align-items baseline
@ -47,11 +48,20 @@
display flex display flex
padding 20px 0 padding 20px 0
color #ffffff color var(--text-color);
.iconfont{
color var(--text-color);
font-size: 28px;
}
.icon-book{
margin-right: 6px;
}
.title { .title {
font-size 24px color var(--text-color);
font-size: 24px;
padding 10px 10px 0 10px padding 10px 10px 0 10px
font-weight: 700;
} }
.logo { .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);}
}
} }
} }
@ -122,3 +160,37 @@
} }
} }
.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-face {
font-family: "iconfont"; /* Project id 4125778 */ font-family: 'iconfont'; /* Project id 4125778 */
src: url('iconfont.woff2?t=1731289567907') format('woff2'), src: url('//at.alicdn.com/t/c/font_4125778_gs96jfl3hlc.woff2?t=1732009095144') format('woff2'),
url('iconfont.woff?t=1731289567907') format('woff'), url('//at.alicdn.com/t/c/font_4125778_gs96jfl3hlc.woff?t=1732009095144') format('woff'),
url('iconfont.ttf?t=1731289567907') format('truetype'); url('//at.alicdn.com/t/c/font_4125778_gs96jfl3hlc.ttf?t=1732009095144') format('truetype');
} }
.iconfont { .iconfont {

View File

@ -1,9 +1,11 @@
<template> <template>
<div class="foot-container"> <div class="foot-container">
<div class="footer"> <div class="footer">
<div><span :style="{color:textColor}">{{copyRight}}</span></div> <div>
<span>{{ copyRight }}</span>
</div>
<div v-if="!license.de_copy"> <div v-if="!license.de_copy">
<a :href="gitURL" target="_blank" :style="{color:textColor}"> <a :href="gitURL" target="_blank">
{{ title }} - {{ title }} -
{{ version }} {{ version }}
</a> </a>
@ -12,37 +14,45 @@
</div> </div>
</template> </template>
<script setup> <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"; const title = ref("");
import {httpGet} from "@/utils/http"; const version = ref(process.env.VUE_APP_VERSION);
import {showMessageError} from "@/utils/dialog"; const gitURL = ref(process.env.VUE_APP_GIT_URL);
import {getLicenseInfo, getSystemInfo} from "@/store/cache"; 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({ const props = defineProps({
textColor: { textColor: {
type: String, type: String,
default: '#ffffff' default: "#ffffff"
}, }
}); });
// //
getSystemInfo().then(res => { getSystemInfo()
title.value = res.data.title??process.env.VUE_APP_TITLE .then((res) => {
copyRight.value = res.data.copyright.length>1?res.data.copyright:'极客学长 © 2023 - '+new Date().getFullYear()+' All rights reserved.' title.value = res.data.title ?? process.env.VUE_APP_TITLE;
}).catch(e => { copyRight.value =
showMessageError("获取系统配置失败:" + e.message) res.data.copyright.length > 1
}) ? res.data.copyright
: "极客学长 © 2023 - " +
new Date().getFullYear() +
" All rights reserved.";
})
.catch((e) => {
showMessageError("获取系统配置失败:" + e.message);
});
getLicenseInfo().then(res => { getLicenseInfo()
license.value = res.data .then((res) => {
}).catch(e => { license.value = res.data;
showMessageError("获取 License 失败:" + e.message) })
}) .catch((e) => {
showMessageError("获取 License 失败:" + e.message);
});
</script> </script>
<style scoped lang="stylus"> <style scoped lang="stylus">
@ -62,11 +72,15 @@ getLicenseInfo().then(res => {
width 100% width 100%
a { a {
color:var(--text-color)
&:hover { &:hover {
text-decoration underline 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 // * @Author yangjian102621@163.com
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import {createApp} from 'vue' import { createApp } from "vue";
import ElementPlus from "element-plus" import ElementPlus from "element-plus";
import "element-plus/dist/index.css" import "element-plus/dist/index.css";
import '@/assets/iconfont/iconfont.css'; import "@/assets/iconfont/iconfont.css";
import 'vant/lib/index.css'; import "vant/lib/index.css";
import App from './App.vue' import App from "./App.vue";
import {createPinia} from "pinia"; import { useThemeStore } from "@/store/theme";
import { createPinia } from "pinia";
import "animate.css/animate.min.css";
import { import {
ActionSheet, ActionSheet,
Badge, Badge,
Button, Button,
Cell, Cell,
CellGroup, CellGroup,
Circle, Circle,
Col, Col,
Collapse, Collapse,
CollapseItem, CollapseItem,
ConfigProvider, ConfigProvider,
Dialog, Dialog,
Divider, Divider,
DropdownItem, DropdownItem,
DropdownMenu, DropdownMenu,
Empty, Empty,
Field, Field,
Form, Form,
Grid, Grid,
GridItem, GridItem,
Icon, Icon,
Image, Image,
ImagePreview, ImagePreview,
Lazyload, Lazyload,
List, List,
Loading, Loading,
NavBar, NavBar,
NoticeBar, NoticeBar,
Notify, Notify,
Overlay, Overlay,
Picker, Picker,
Popup, Popup,
Row, Row,
Search, Search,
ShareSheet, ShareSheet,
Slider, Slider,
Sticky, Sticky,
SwipeCell, SwipeCell,
Switch, Switch,
Tab, Tab,
Tabbar, Tabbar,
TabbarItem, TabbarItem,
Tabs, Tabs,
Tag, Tag,
TextEllipsis, TextEllipsis,
Uploader Uploader
} from "vant"; } from "vant";
import {router} from "@/router"; import { router } from "@/router";
import 'v3-waterfall/dist/style.css' import "v3-waterfall/dist/style.css";
import V3waterfall from "v3-waterfall"; 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); const app = createApp(App);
app.use(createPinia()); app.use(createPinia());
@ -70,12 +81,12 @@ app.use(Tabbar);
app.use(TabbarItem); app.use(TabbarItem);
app.use(NavBar); app.use(NavBar);
app.use(Search); app.use(Search);
app.use(Cell) app.use(Cell);
app.use(Image) app.use(Image);
app.use(TextEllipsis) app.use(TextEllipsis);
app.use(Notify) app.use(Notify);
app.use(Picker) app.use(Picker);
app.use(Popup) app.use(Popup);
app.use(List); app.use(List);
app.use(Form); app.use(Form);
app.use(Field); app.use(Field);
@ -91,12 +102,12 @@ app.use(ShareSheet);
app.use(Switch); app.use(Switch);
app.use(Uploader); app.use(Uploader);
app.use(Tag); app.use(Tag);
app.use(V3waterfall) app.use(V3waterfall);
app.use(Overlay) app.use(Overlay);
app.use(Col) app.use(Col);
app.use(Row) app.use(Row);
app.use(Slider) app.use(Slider);
app.use(Badge) app.use(Badge);
app.use(Collapse); app.use(Collapse);
app.use(CollapseItem); app.use(CollapseItem);
app.use(Grid); app.use(Grid);
@ -111,6 +122,4 @@ app.use(Tabs);
app.use(Divider); app.use(Divider);
app.use(NoticeBar); app.use(NoticeBar);
app.use(ActionSheet); 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> <template>
<div class="index-page" :style="{height: winHeight+'px'}"> <div class="index-page">
<div :class="theme.imageBg?'color-bg image-bg':'color-bg'" :style="{backgroundImage:'url('+bgStyle.backgroundImage+')', backgroundColor:bgStyle.backgroundColor}"></div> <ThemeChange />
<div class="menu-box"> <div class="menu-box">
<el-menu <el-menu mode="horizontal" :ellipsis="false">
mode="horizontal"
:ellipsis="false"
>
<div class="menu-item"> <div class="menu-item">
<el-image :src="logo" class="logo" alt="Geek-AI"/> <el-image :src="logo" class="logo" alt="Geek-AI" />
<div class="title" :style="{color:theme.textColor}">{{ title }}</div>
</div> </div>
<div class="menu-item"> <div class="menu-item">
<span v-if="!license.de_copy"> <span v-if="!license.de_copy">
<a :href="docsURL" target="_blank"> <el-tooltip
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" round> v-if="!license.de_copy"
<i class="iconfont icon-book"></i> class="box-item"
<span>文档</span> effect="light"
</el-button> content="部署文档"
</a> placement="bottom"
>
<a :href="gitURL" target="_blank"> <a :href="docsURL" class="link-button" target="_blank">
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" round> <i class="iconfont icon-book"></i>
<i class="iconfont icon-github"></i> </a>
<span>源码</span> </el-tooltip>
</el-button> <el-tooltip
</a> 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>
<span v-if="!isLogin"> <span v-if="!isLogin">
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" @click="router.push('/login')" class="shadow" round>登录</el-button> <!-- <el-button @click="router.push('/login')" class="shadow" round
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" @click="router.push('/register')" class="shadow" round>注册</el-button> >登录</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> </span>
</div> </div>
</el-menu> </el-menu>
</div> </div>
<div class="content"> <div class="content">
<h1 :style="{color:theme.textColor}">欢迎使用 {{ title }}</h1> <h1 class="animate__animated animate__backInDown">
<p :style="{color:theme.textColor}">{{ slogan }}</p> {{ 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"> <div class="navs animate__animated animate__backInDown">
<el-space wrap> <el-space wrap :size="14">
<div v-for="item in navs" :key="item.url" class="nav-item"> <div
<el-button @click="router.push(item.url)" :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" :dark="false"> v-for="item in navs"
<i :class="'iconfont '+iconMap[item.url]"></i> :key="item.url"
<span>{{item.name}}</span> class="nav-item-box"
</el-button> @click="router.push(item.url)"
>
<i :class="'iconfont ' + iconMap[item.url]"></i>
<div>{{ item.name }}</div>
</div> </div>
</el-space> </el-space>
</div> </div>
</div> </div>
<footer-bar :text-color="theme.textColor" /> <footer-bar />
</div> </div>
</template> </template>
<script setup> <script setup>
import { onMounted, ref } from "vue";
import {onMounted, ref} from "vue"; import { useRouter } from "vue-router";
import {useRouter} from "vue-router";
import FooterBar from "@/components/FooterBar.vue"; import FooterBar from "@/components/FooterBar.vue";
import {httpGet} from "@/utils/http"; import ThemeChange from "@/components/ThemeChange.vue";
import {ElMessage} from "element-plus"; import { httpGet } from "@/utils/http";
import {checkSession, getLicenseInfo, getSystemInfo} from "@/store/cache"; import { ElMessage } from "element-plus";
import {isMobile} from "@/utils/libs"; import { checkSession, getLicenseInfo, getSystemInfo } from "@/store/cache";
import { isMobile } from "@/utils/libs";
const router = useRouter() const router = useRouter();
if (isMobile()) { if (isMobile()) {
router.push("/mobile/index") router.push("/mobile/index");
} }
const title = ref("") const title = ref("");
const logo = ref("") const logo = ref("");
const slogan = ref("") const slogan = ref("");
const license = ref({de_copy: true}) const license = ref({ de_copy: true });
const winHeight = window.innerHeight - 150
const isLogin = ref(false) const isLogin = ref(false);
const docsURL = ref(process.env.VUE_APP_DOCS_URL) const docsURL = ref(process.env.VUE_APP_DOCS_URL);
const gitURL = ref(process.env.VUE_APP_GIT_URL) const gitURL = ref(process.env.VUE_APP_GIT_URL);
const navs = ref([]) const navs = ref([]);
const btnColors = ref([
{bgColor: "#fff143", textColor: "#50616D"}, const iconMap = ref({
{bgColor: "#eaff56", textColor: "#50616D"}, "/chat": "icon-chat",
{bgColor: "#bddd22", textColor: "#50616D"}, "/mj": "icon-mj",
{bgColor: "#1bd1a5", textColor: "#50616D"}, "/sd": "icon-sd",
{bgColor: "#e0eee8", textColor: "#50616D"}, "/dalle": "icon-dalle",
{bgColor: "#7bcfa6", textColor: "#50616D"}, "/images-wall": "icon-image",
{bgColor: "#bce672", textColor: "#50616D"}, "/suno": "icon-suno",
{bgColor: "#44cef6", textColor: "#ffffff"}, "/xmind": "icon-xmind",
{bgColor: "#70f3ff", textColor: "#50616D"}, "/apps": "icon-app",
{bgColor: "#fffbf0", textColor: "#50616D"}, "/member": "icon-vip-user",
{bgColor: "#d6ecf0", textColor: "#50616D"}, "/invite": "icon-share",
{bgColor: "#88ada6", textColor: "#50616D"}, "/luma": "icon-luma"
{bgColor: "#30dff3", textColor: "#50616D"}, });
{bgColor: "#d3e0f3", textColor: "#50616D"},
{bgColor: "#e9e7ef", textColor: "#50616D"}, const displayedChars = ref([]);
{bgColor: "#eacd76", textColor: "#50616D"}, const initAnimation = ref("");
{bgColor: "#f2be45", textColor: "#50616D"}, let timer = null; //
{bgColor: "#549688", textColor: "#ffffff"},
{bgColor: "#758a99", textColor: "#ffffff"}, //
{bgColor: "#41555d", textColor: "#ffffff"}, const interTime = ref(50);
{bgColor: "#21aa93", textColor: "#ffffff"}, const interArr = [90, 100, 70, 88, 80, 110, 85, 400, 90, 99];
{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})
onMounted(() => { onMounted(() => {
getSystemInfo().then(res => { getSystemInfo()
title.value = res.data.title .then((res) => {
logo.value = res.data.logo title.value = res.data.title;
if (res.data.index_bg_url === 'color') { logo.value = res.data.logo;
// slogan.value = res.data.slogan;
theme.value.bgColor = color.bgColor if (timer) clearInterval(timer); //
theme.value.btnBgColor = color.bgColor timer = setInterval(setContent, interTime.value);
theme.value.textColor = color.textColor })
theme.value.btnTextColor = color.textColor .catch((e) => {
// ElMessage.error("获取系统配置失败:" + e.message);
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"
}
slogan.value = res.data.slogan getLicenseInfo()
}).catch(e => { .then((res) => {
ElMessage.error("获取系统配置失败:" + e.message) license.value = res.data;
}) })
.catch((e) => {
license.value = { de_copy: false };
ElMessage.error("获取 License 配置失败:" + e.message);
});
getLicenseInfo().then(res => { httpGet("/api/menu/list?index=1")
license.value = res.data .then((res) => {
}).catch(e => { navs.value = res.data;
license.value = {de_copy: false} })
ElMessage.error("获取 License 配置失败:" + e.message) .catch((e) => {
}) ElMessage.error("获取导航菜单失败:" + e.message);
});
httpGet("/api/menu/list?index=1").then(res => { checkSession()
navs.value = res.data .then(() => {
}).catch(e => { isLogin.value = true;
ElMessage.error("获取导航菜单失败:" + e.message) })
}) .catch(() => {});
});
checkSession().then(() => { //
isLogin.value = true const setContent = () => {
}).catch(()=>{}) 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> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>

View File

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

View File

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