mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 01:06:39 +08:00
feat: change theme and index style
This commit is contained in:
parent
6aaf607ed7
commit
9a97a1ee72
18923
web/package-lock.json
generated
18923
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||||
|
@ -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>
|
9
web/src/assets/css/common.styl
Normal file
9
web/src/assets/css/common.styl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.btn-go{
|
||||||
|
background: var(--btnColor);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
&:hover{
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
24
web/src/assets/css/font.styl
Normal file
24
web/src/assets/css/font.styl
Normal 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;
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
21
web/src/assets/css/theme-dark.styl
Normal file
21
web/src/assets/css/theme-dark.styl
Normal 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);
|
||||||
|
|
||||||
|
}
|
26
web/src/assets/css/theme-light.styl
Normal file
26
web/src/assets/css/theme-light.styl
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
0
web/src/assets/css/variables.styl
Normal file
0
web/src/assets/css/variables.styl
Normal file
BIN
web/src/assets/fonts/OPlusSans3-Medium.ttf
Normal file
BIN
web/src/assets/fonts/OPlusSans3-Medium.ttf
Normal file
Binary file not shown.
BIN
web/src/assets/fonts/OPlusSans3-Regular.ttf
Normal file
BIN
web/src/assets/fonts/OPlusSans3-Regular.ttf
Normal file
Binary file not shown.
@ -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 {
|
||||||
|
@ -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>
|
56
web/src/components/ThemeChange.vue
Normal file
56
web/src/components/ThemeChange.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div class="theme-box" @click="toggleTheme">
|
||||||
|
<span class="iconfont icon-yueliang">{{
|
||||||
|
themePage === "light" ? "" : ""
|
||||||
|
}}</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>
|
147
web/src/main.js
147
web/src/main.js
@ -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
15
web/src/store/theme.js
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user