diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b9cc83..0af817fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * 功能优化:增加 session 和系统配置缓存,确保每个页面只进行一次 session 和 get system config 请求 * 功能优化:在应用列表页面,无需先添加模型到用户工作区,可以直接使用 * 功能新增:MJ 绘图失败的任务不会自动删除,而是会在列表页显示失败详细错误信息 +* 功能新增:允许在管理后台设置首页显示的导航菜单 * 功能新增:增加 Suno 文生音乐页面功能 ## v4.1.0 diff --git a/api/core/types/config.go b/api/core/types/config.go index 1158b684..027ea14a 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -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"` // 版权信息 } diff --git a/api/handler/menu_handler.go b/api/handler/menu_handler.go index 647ed1e0..39de1c78 100644 --- a/api/handler/menu_handler.go +++ b/api/handler/menu_handler.go @@ -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 diff --git a/web/public/images/transparent-bg.png b/web/public/images/transparent-bg.png new file mode 100644 index 00000000..8b1a375c Binary files /dev/null and b/web/public/images/transparent-bg.png differ diff --git a/web/src/assets/css/index.styl b/web/src/assets/css/index.styl new file mode 100644 index 00000000..8a47c12a --- /dev/null +++ b/web/src/assets/css/index.styl @@ -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 + } + } + +} \ No newline at end of file diff --git a/web/src/assets/iconfont/iconfont.css b/web/src/assets/iconfont/iconfont.css index ef2d1a57..10b4f5de 100644 --- a/web/src/assets/iconfont/iconfont.css +++ b/web/src/assets/iconfont/iconfont.css @@ -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"; } diff --git a/web/src/assets/iconfont/iconfont.js b/web/src/assets/iconfont/iconfont.js index 25288e87..1e83327f 100644 --- a/web/src/assets/iconfont/iconfont.js +++ b/web/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4125778='',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],c=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,h,i,o,z,m=function(l,c){c.parentNode.insertBefore(l,c)};if(c&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}t=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),t()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(i=t,o=a.document,z=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,s())})}function s(){z||(z=!0,i())}function p(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(p,50)}s()}}(window); \ No newline at end of file +window._iconfont_svg_string_4125778='',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],c=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,h,i,o,z,m=function(l,c){c.parentNode.insertBefore(l,c)};if(c&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}t=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),t()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(i=t,o=a.document,z=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,s())})}function s(){z||(z=!0,i())}function p(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(p,50)}s()}}(window); \ No newline at end of file diff --git a/web/src/assets/iconfont/iconfont.json b/web/src/assets/iconfont/iconfont.json index c48278e4..d1b11fab 100644 --- a/web/src/assets/iconfont/iconfont.json +++ b/web/src/assets/iconfont/iconfont.json @@ -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": "暂停", diff --git a/web/src/assets/iconfont/iconfont.ttf b/web/src/assets/iconfont/iconfont.ttf index 5e3d71bc..18b71dce 100644 Binary files a/web/src/assets/iconfont/iconfont.ttf and b/web/src/assets/iconfont/iconfont.ttf differ diff --git a/web/src/assets/iconfont/iconfont.woff b/web/src/assets/iconfont/iconfont.woff index 5156107d..5663d176 100644 Binary files a/web/src/assets/iconfont/iconfont.woff and b/web/src/assets/iconfont/iconfont.woff differ diff --git a/web/src/assets/iconfont/iconfont.woff2 b/web/src/assets/iconfont/iconfont.woff2 index d2db2973..7418be6e 100644 Binary files a/web/src/assets/iconfont/iconfont.woff2 and b/web/src/assets/iconfont/iconfont.woff2 differ diff --git a/web/src/components/FooterBar.vue b/web/src/components/FooterBar.vue index 671adf31..c30955ca 100644 --- a/web/src/components/FooterBar.vue +++ b/web/src/components/FooterBar.vue @@ -1,13 +1,15 @@ 使用动态背景 + 使用纯色背景 + + + + +
+ + + +
+ + + + + +
@@ -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() })