mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
enable use random pure color background for index page
This commit is contained in:
parent
7463cfc66c
commit
cb0dacd5e0
@ -6,6 +6,7 @@
|
||||
* 功能优化:增加 session 和系统配置缓存,确保每个页面只进行一次 session 和 get system config 请求
|
||||
* 功能优化:在应用列表页面,无需先添加模型到用户工作区,可以直接使用
|
||||
* 功能新增:MJ 绘图失败的任务不会自动删除,而是会在列表页显示失败详细错误信息
|
||||
* 功能新增:允许在管理后台设置首页显示的导航菜单
|
||||
* 功能新增:增加 Suno 文生音乐页面功能
|
||||
|
||||
## v4.1.0
|
||||
|
@ -228,5 +228,6 @@ type SystemConfig struct {
|
||||
SdNegPrompt string `json:"sd_neg_prompt"` // SD 默认反向提示词
|
||||
|
||||
IndexBgURL string `json:"index_bg_url"` // 前端首页背景图片
|
||||
IndexNavs []int `json:"index_navs"` // 首页显示的导航菜单
|
||||
Copyright string `json:"copyright"` // 版权信息
|
||||
}
|
||||
|
@ -27,9 +27,15 @@ func NewMenuHandler(app *core.AppServer, db *gorm.DB) *MenuHandler {
|
||||
|
||||
// List 数据列表
|
||||
func (h *MenuHandler) List(c *gin.Context) {
|
||||
index := h.GetBool(c, "index")
|
||||
var items []model.Menu
|
||||
var list = make([]vo.Menu, 0)
|
||||
res := h.DB.Where("enabled", true).Order("sort_num ASC").Find(&items)
|
||||
session := h.DB.Session(&gorm.Session{})
|
||||
session = session.Where("enabled", true)
|
||||
if index {
|
||||
session = session.Where("id IN ?", h.App.SysConfig.IndexNavs)
|
||||
}
|
||||
res := session.Order("sort_num ASC").Find(&items)
|
||||
if res.Error == nil {
|
||||
for _, item := range items {
|
||||
var product vo.Menu
|
||||
|
BIN
web/public/images/transparent-bg.png
Normal file
BIN
web/public/images/transparent-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
116
web/src/assets/css/index.styl
Normal file
116
web/src/assets/css/index.styl
Normal file
@ -0,0 +1,116 @@
|
||||
.index-page {
|
||||
margin: 0
|
||||
overflow hidden
|
||||
color #ffffff
|
||||
display flex
|
||||
justify-content center
|
||||
align-items baseline
|
||||
padding-top 150px
|
||||
|
||||
.color-bg {
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
width 100vw
|
||||
height 100vh
|
||||
}
|
||||
|
||||
.image-bg {
|
||||
filter: blur(8px);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow rgba(0, 0, 0, 0.3) 0px 0px 3px
|
||||
|
||||
&:hover {
|
||||
box-shadow rgba(0, 0, 0, 0.3) 0px 0px 8px
|
||||
}
|
||||
}
|
||||
|
||||
.menu-box {
|
||||
position absolute
|
||||
top 0
|
||||
width 100%
|
||||
display flex
|
||||
|
||||
.el-menu {
|
||||
padding 0 30px
|
||||
width 100%
|
||||
display flex
|
||||
justify-content space-between
|
||||
background none
|
||||
border none
|
||||
|
||||
.menu-item {
|
||||
display flex
|
||||
padding 20px 0
|
||||
|
||||
color #ffffff
|
||||
|
||||
.title {
|
||||
font-size 24px
|
||||
padding 10px 10px 0 10px
|
||||
}
|
||||
|
||||
.el-image {
|
||||
height 50px
|
||||
}
|
||||
|
||||
.el-button {
|
||||
margin-left 10px
|
||||
|
||||
span {
|
||||
margin-left 5px
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
position relative
|
||||
|
||||
h1 {
|
||||
font-size: 5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.navs {
|
||||
display flex
|
||||
max-width 900px
|
||||
padding 20px
|
||||
|
||||
.nav-item {
|
||||
width 200px
|
||||
.el-button {
|
||||
width 100%
|
||||
padding: 25px 20px;
|
||||
font-size: 1.3rem;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.iconfont {
|
||||
font-size 24px
|
||||
margin-right 10px
|
||||
position relative
|
||||
top -2px
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
.el-link__inner {
|
||||
color #ffffff
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4125778 */
|
||||
src: url('iconfont.woff2?t=1721292490257') format('woff2'),
|
||||
url('iconfont.woff?t=1721292490257') format('woff'),
|
||||
url('iconfont.ttf?t=1721292490257') format('truetype');
|
||||
src: url('iconfont.woff2?t=1721356513025') format('woff2'),
|
||||
url('iconfont.woff?t=1721356513025') format('woff'),
|
||||
url('iconfont.ttf?t=1721356513025') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,10 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-app:before {
|
||||
content: "\e64f";
|
||||
}
|
||||
|
||||
.icon-pause:before {
|
||||
content: "\e693";
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -5,6 +5,13 @@
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "1503777",
|
||||
"name": "应用",
|
||||
"font_class": "app",
|
||||
"unicode": "e64f",
|
||||
"unicode_decimal": 58959
|
||||
},
|
||||
{
|
||||
"icon_id": "7156146",
|
||||
"name": "暂停",
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<div class="foot-container">
|
||||
<div class="footer">
|
||||
<div v-if="license.de_copy">{{copyRight}}</div>
|
||||
<div v-if="license.de_copy" :style="{color:textColor}">{{copyRight}}</div>
|
||||
<div v-else>
|
||||
<span>{{copyRight}}</span>
|
||||
<el-link type="primary" :href="gitURL" target="_blank" style="--el-link-text-color:#ffffff">
|
||||
{{ title }} -
|
||||
{{ version }}
|
||||
</el-link>
|
||||
<span :style="{color:textColor}">{{copyRight}}</span>
|
||||
<div>
|
||||
<a :href="gitURL" target="_blank" :style="{color:textColor}">
|
||||
{{ title }} -
|
||||
{{ version }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -23,7 +25,12 @@ 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'
|
||||
},
|
||||
});
|
||||
|
||||
// 获取系统配置
|
||||
httpGet("/api/config/get?key=system").then(res => {
|
||||
@ -56,8 +63,10 @@ httpGet("/api/config/license").then(res => {
|
||||
padding 20px;
|
||||
width 100%
|
||||
|
||||
.el-link {
|
||||
color #409eff
|
||||
a {
|
||||
&:hover {
|
||||
text-decoration underline
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="index-page" :style="{height: winHeight+'px'}">
|
||||
<div class="index-bg" :style="{backgroundImage: 'url('+bgImgUrl+')'}"></div>
|
||||
<div :class="theme.imageBg?'color-bg image-bg':'color-bg'" :style="{backgroundImage:'url('+bgStyle.backgroundImage+')', backgroundColor:bgStyle.backgroundColor}"></div>
|
||||
<div class="menu-box">
|
||||
<el-menu
|
||||
mode="horizontal"
|
||||
@ -8,19 +8,19 @@
|
||||
>
|
||||
<div class="menu-item">
|
||||
<el-image :src="logo" alt="Geek-AI"/>
|
||||
<div class="title">{{ title }}</div>
|
||||
<div class="title" :style="{color:theme.textColor}">{{ title }}</div>
|
||||
</div>
|
||||
<div class="menu-item">
|
||||
<span v-if="!license.de_copy">
|
||||
<a :href="docsURL" target="_blank">
|
||||
<el-button type="primary" round>
|
||||
<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 type="success" round>
|
||||
<el-button :color="theme.btnBgColor" :style="{color: theme.btnTextColor}" class="shadow" round>
|
||||
<i class="iconfont icon-github"></i>
|
||||
<span>源码</span>
|
||||
</el-button>
|
||||
@ -28,36 +28,29 @@
|
||||
</span>
|
||||
|
||||
<span v-if="!isLogin">
|
||||
<el-button @click="router.push('/login')" round>登录</el-button>
|
||||
<el-button @click="router.push('/register')" round>注册</el-button>
|
||||
<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>
|
||||
</span>
|
||||
</div>
|
||||
</el-menu>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h1>欢迎使用 {{ title }}</h1>
|
||||
<p>{{ slogan }}</p>
|
||||
<el-button @click="router.push('/chat')" color="#ffffff" style="color:#007bff" :dark="false">
|
||||
<i class="iconfont icon-chat"></i>
|
||||
<span>AI 对话</span>
|
||||
</el-button>
|
||||
<el-button @click="router.push('/mj')" color="#C4CCFD" style="color:#424282" :dark="false">
|
||||
<i class="iconfont icon-mj"></i>
|
||||
<span>MJ 绘画</span>
|
||||
</el-button>
|
||||
<h1 :style="{color:theme.textColor}">欢迎使用 {{ title }}</h1>
|
||||
<p :style="{color:theme.textColor}">{{ slogan }}</p>
|
||||
|
||||
<el-button @click="router.push('/sd')" color="#4AE6DF" style="color:#424282" :dark="false">
|
||||
<i class="iconfont icon-sd"></i>
|
||||
<span>SD 绘画</span>
|
||||
</el-button>
|
||||
<el-button @click="router.push('/xmind')" color="#FFFD55" style="color:#424282" :dark="false">
|
||||
<i class="iconfont icon-xmind"></i>
|
||||
<span>思维导图</span>
|
||||
</el-button>
|
||||
<!-- <div id="animation-container"></div>-->
|
||||
<div class="navs">
|
||||
<el-space wrap>
|
||||
<div v-for="item in navs" 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>
|
||||
</el-space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer-bar />
|
||||
<footer-bar :text-color="theme.textColor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -82,23 +75,82 @@ const logo = ref("")
|
||||
const slogan = ref("")
|
||||
const license = ref({})
|
||||
const winHeight = window.innerHeight - 150
|
||||
const bgImgUrl = ref('')
|
||||
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",
|
||||
}
|
||||
)
|
||||
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(() => {
|
||||
httpGet("/api/config/get?key=system").then(res => {
|
||||
title.value = res.data.title
|
||||
logo.value = res.data.logo
|
||||
if (res.data.index_bg_url) {
|
||||
bgImgUrl.value = res.data.index_bg_url
|
||||
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 {
|
||||
bgImgUrl.value = "/images/index-bg.jpg"
|
||||
}
|
||||
if (res.data.slogan) {
|
||||
slogan.value = res.data.slogan
|
||||
bgStyle.backgroundImage = "/images/index-bg.jpg"
|
||||
}
|
||||
|
||||
slogan.value = res.data.slogan
|
||||
}).catch(e => {
|
||||
ElMessage.error("获取系统配置失败:" + e.message)
|
||||
})
|
||||
@ -106,7 +158,13 @@ onMounted(() => {
|
||||
httpGet("/api/config/license").then(res => {
|
||||
license.value = res.data
|
||||
}).catch(e => {
|
||||
ElMessage.error("获取 License 配置:" + e.message)
|
||||
ElMessage.error("获取 License 配置失败:" + e.message)
|
||||
})
|
||||
|
||||
httpGet("/api/menu/list?index=1").then(res => {
|
||||
navs.value = res.data
|
||||
}).catch(e => {
|
||||
ElMessage.error("获取导航菜单失败:" + e.message)
|
||||
})
|
||||
|
||||
checkSession().then(() => {
|
||||
@ -117,107 +175,5 @@ onMounted(() => {
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@import '@/assets/iconfont/iconfont.css'
|
||||
.index-page {
|
||||
margin: 0
|
||||
overflow hidden
|
||||
color #ffffff
|
||||
display flex
|
||||
justify-content center
|
||||
align-items baseline
|
||||
padding-top 150px
|
||||
|
||||
.index-bg {
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
width 100vw
|
||||
height 100vh
|
||||
filter: blur(8px);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.menu-box {
|
||||
position absolute
|
||||
top 0
|
||||
width 100%
|
||||
display flex
|
||||
|
||||
.el-menu {
|
||||
padding 0 30px
|
||||
width 100%
|
||||
display flex
|
||||
justify-content space-between
|
||||
background none
|
||||
border none
|
||||
|
||||
.menu-item {
|
||||
display flex
|
||||
padding 20px 0
|
||||
|
||||
color #ffffff
|
||||
|
||||
.title {
|
||||
font-size 24px
|
||||
padding 10px 10px 0 10px
|
||||
}
|
||||
|
||||
.el-image {
|
||||
height 50px
|
||||
}
|
||||
|
||||
.el-button {
|
||||
margin-left 10px
|
||||
|
||||
span {
|
||||
margin-left 5px
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
position relative
|
||||
|
||||
h1 {
|
||||
font-size: 5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
padding: 25px 20px;
|
||||
font-size: 1.3rem;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.iconfont {
|
||||
font-size 1.6rem
|
||||
margin-right 10px
|
||||
}
|
||||
}
|
||||
|
||||
#animation-container {
|
||||
display flex
|
||||
justify-content center
|
||||
width 100%
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
top: 350px
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
.el-link__inner {
|
||||
color #ffffff
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@import "@/assets/css/index.styl"
|
||||
</style>
|
||||
|
@ -50,6 +50,38 @@
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button type="primary" @click="system.index_bg_url = 'https://api.dujin.org/bing/1920.php'">使用动态背景</el-button>
|
||||
<el-button @click="system.index_bg_url = 'color'">使用纯色背景</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="首页导航菜单" prop="index_navs">
|
||||
<div class="tip-input">
|
||||
<el-select
|
||||
v-model="system['index_navs']"
|
||||
multiple
|
||||
:filterable="true"
|
||||
placeholder="请选择菜单,多选"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in menus"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<div class="info">
|
||||
<el-tooltip
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
content="被选中的菜单将会在首页导航栏显示"
|
||||
placement="right"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
@ -407,6 +439,7 @@ const models = ref([])
|
||||
const openAIModels = ref([])
|
||||
const notice = ref("")
|
||||
const license = ref({is_active: false})
|
||||
const menus = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
// 加载系统配置
|
||||
@ -431,6 +464,12 @@ onMounted(() => {
|
||||
ElMessage.error("获取模型失败:" + e.message)
|
||||
})
|
||||
|
||||
httpGet('/api/admin/menu/list').then(res => {
|
||||
menus.value = res.data
|
||||
}).catch(e => {
|
||||
ElMessage.error("获取模型失败:" + e.message)
|
||||
})
|
||||
|
||||
fetchLicense()
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user