可以设置管理界面和用户界面的浏览器图标和Logo

This commit is contained in:
GoEdgeLab
2021-02-25 20:54:30 +08:00
parent 0d2b5d33fa
commit 6b132482ca
11 changed files with 344 additions and 1 deletions

View File

@@ -65,6 +65,7 @@ func (this *IndexAction) RunGet(params struct {
} else {
this.Data["version"] = teaconst.Version
}
this.Data["faviconFileId"] = config.FaviconFileId
this.Show()
}

View File

@@ -91,6 +91,7 @@ func (this *UploadPopupAction) RunPost(params struct {
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
if err != nil {
this.ErrorPage(err)
return
}
// 保存

View File

@@ -3,7 +3,9 @@ package ui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"io"
)
type IndexAction struct {
@@ -32,10 +34,14 @@ func (this *IndexAction) RunPost(params struct {
ShowFinance bool
ShowVersion bool
Version string
FaviconFile *actions.File
LogoFile *actions.File
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改管理界面设置")
params.Must.
Field("productName", params.ProductName).
Require("请输入产品名称").
@@ -53,6 +59,101 @@ func (this *IndexAction) RunPost(params struct {
config.ShowFinance = params.ShowFinance
config.ShowVersion = params.ShowVersion
config.Version = params.Version
// 上传Favicon文件
if params.FaviconFile != nil {
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
Filename: params.FaviconFile.Filename,
Size: params.FaviconFile.Size,
IsPublic: true,
})
if err != nil {
this.ErrorPage(err)
return
}
fileId := createResp.FileId
// 上传内容
buf := make([]byte, 512*1024)
reader, err := params.FaviconFile.OriginFile.Open()
if err != nil {
this.ErrorPage(err)
return
}
for {
n, err := reader.Read(buf)
if n > 0 {
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
FileId: fileId,
Data: buf[:n],
})
if err != nil {
this.Fail("上传失败:" + err.Error())
}
}
if err != nil {
if err == io.EOF {
break
}
this.Fail("上传失败:" + err.Error())
}
}
// 置为已完成
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
if err != nil {
this.ErrorPage(err)
}
config.FaviconFileId = fileId
}
// 上传Logo文件
if params.LogoFile != nil {
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
Filename: params.LogoFile.Filename,
Size: params.LogoFile.Size,
IsPublic: true,
})
if err != nil {
this.ErrorPage(err)
return
}
fileId := createResp.FileId
// 上传内容
buf := make([]byte, 512*1024)
reader, err := params.LogoFile.OriginFile.Open()
if err != nil {
this.ErrorPage(err)
return
}
for {
n, err := reader.Read(buf)
if n > 0 {
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
FileId: fileId,
Data: buf[:n],
})
if err != nil {
this.Fail("上传失败:" + err.Error())
}
}
if err != nil {
if err == io.EOF {
break
}
this.Fail("上传失败:" + err.Error())
}
}
// 置为已完成
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
if err != nil {
this.ErrorPage(err)
}
config.LogoFileId = fileId
}
err = configloaders.UpdateAdminUIConfig(config)
if err != nil {
this.ErrorPage(err)

View File

@@ -3,7 +3,9 @@ package userui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"io"
)
type IndexAction struct {
@@ -32,6 +34,8 @@ func (this *IndexAction) RunPost(params struct {
ShowVersion bool
Version string
ShowFinance bool
FaviconFile *actions.File
LogoFile *actions.File
Must *actions.Must
CSRF *actionutils.CSRF
@@ -53,6 +57,101 @@ func (this *IndexAction) RunPost(params struct {
config.ShowVersion = params.ShowVersion
config.Version = params.Version
config.ShowFinance = params.ShowFinance
// 上传Favicon文件
if params.FaviconFile != nil {
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
Filename: params.FaviconFile.Filename,
Size: params.FaviconFile.Size,
IsPublic: true,
})
if err != nil {
this.ErrorPage(err)
return
}
fileId := createResp.FileId
// 上传内容
buf := make([]byte, 512*1024)
reader, err := params.FaviconFile.OriginFile.Open()
if err != nil {
this.ErrorPage(err)
return
}
for {
n, err := reader.Read(buf)
if n > 0 {
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
FileId: fileId,
Data: buf[:n],
})
if err != nil {
this.Fail("上传失败:" + err.Error())
}
}
if err != nil {
if err == io.EOF {
break
}
this.Fail("上传失败:" + err.Error())
}
}
// 置为已完成
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
if err != nil {
this.ErrorPage(err)
}
config.FaviconFileId = fileId
}
// 上传Logo文件
if params.LogoFile != nil {
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
Filename: params.LogoFile.Filename,
Size: params.LogoFile.Size,
IsPublic: true,
})
if err != nil {
this.ErrorPage(err)
return
}
fileId := createResp.FileId
// 上传内容
buf := make([]byte, 512*1024)
reader, err := params.LogoFile.OriginFile.Open()
if err != nil {
this.ErrorPage(err)
return
}
for {
n, err := reader.Read(buf)
if n > 0 {
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
FileId: fileId,
Data: buf[:n],
})
if err != nil {
this.Fail("上传失败:" + err.Error())
}
}
if err != nil {
if err == io.EOF {
break
}
this.Fail("上传失败:" + err.Error())
}
}
// 置为已完成
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
if err != nil {
this.ErrorPage(err)
}
config.LogoFileId = fileId
}
err = configloaders.UpdateUserUIConfig(config)
if err != nil {
this.ErrorPage(err)

View File

@@ -0,0 +1,68 @@
package ui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"mime"
"path/filepath"
"strconv"
)
// 公开的图片,不需要检查用户权限
type ImageAction struct {
actionutils.ParentAction
}
func (this *ImageAction) Init() {
this.Nav("", "", "")
}
func (this *ImageAction) RunGet(params struct {
FileId int64
}) {
fileResp, err := this.RPC().FileRPC().FindEnabledFile(this.AdminContext(), &pb.FindEnabledFileRequest{FileId: params.FileId})
if err != nil {
this.ErrorPage(err)
return
}
file := fileResp.File
if file == nil {
this.NotFound("file", params.FileId)
return
}
if !file.IsPublic {
this.NotFound("file", params.FileId)
return
}
chunkIdsResp, err := this.RPC().FileChunkRPC().FindAllFileChunkIds(this.AdminContext(), &pb.FindAllFileChunkIdsRequest{FileId: file.Id})
if err != nil {
this.ErrorPage(err)
return
}
mimeType := ""
if len(file.Filename) > 0 {
ext := filepath.Ext(file.Filename)
mimeType = mime.TypeByExtension(ext)
}
if len(mimeType) == 0 {
mimeType = "image/png"
}
this.AddHeader("Last-Modified", "Fri, 06 Sep 2019 08:29:50 GMT")
this.AddHeader("Content-Type", mimeType)
this.AddHeader("Content-Length", strconv.FormatInt(file.Size, 10))
for _, chunkId := range chunkIdsResp.FileChunkIds {
chunkResp, err := this.RPC().FileChunkRPC().DownloadFileChunk(this.AdminContext(), &pb.DownloadFileChunkRequest{FileChunkId: chunkId})
if err != nil {
this.ErrorPage(err)
return
}
if chunkResp.FileChunk == nil {
continue
}
this.Write(chunkResp.FileChunk.Data)
}
}

View File

@@ -13,6 +13,9 @@ func init() {
server.
Prefix("/ui").
// 公共可以访问的链接
Get("/image/:fileId", new(ImageAction)).
// 以下的需要压缩
Helper(&actions.Gzip{Level: gzip.BestCompression}).
Get("/components.js", new(ComponentsAction)).

View File

@@ -88,6 +88,8 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
action.Data["teaShowVersion"] = config.ShowVersion
action.Data["teaTitle"] = config.AdminSystemName
action.Data["teaName"] = config.ProductName
action.Data["teaFaviconFileId"] = config.FaviconFileId
action.Data["teaLogoFileId"] = config.LogoFileId
action.Data["teaUsername"] = configloaders.FindAdminFullname(adminId)
action.Data["teaUserAvatar"] = ""

View File

@@ -4,7 +4,11 @@
<title>{$.teaTitle}</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
{$if eq .teaFaviconFileId 0}
<link rel="shortcut icon" href="/images/favicon.png"/>
{$else}
<link rel="shortcut icon" href="/ui/image/{$.teaFaviconFileId}"/>
{$end}
<link rel="stylesheet" type="text/css" href="/_/@default/@layout.css" media="all"/>
{$TEA.SEMANTIC}
<link rel="stylesheet" type="text/css" href="/_/@default/@layout_override.css" media="all"/>
@@ -23,7 +27,7 @@
<!-- 顶部导航 -->
<div class="ui menu top-nav blue inverted small borderless" v-cloak="">
<a href="/" class="item">
<i class="ui icon leaf"></i> &nbsp; {{teaTitle}}&nbsp;<sup v-if="teaShowVersion">v{{teaVersion}}</sup> &nbsp;
<i class="ui icon leaf" v-if="teaLogoFileId == 0"></i><img v-if="teaLogoFileId > 0" :src="'/ui/image/' + teaLogoFileId"/> &nbsp; {{teaTitle}}&nbsp;<sup v-if="teaShowVersion">v{{teaVersion}}</sup> &nbsp;
</a>
<div class="right menu">

View File

@@ -2,7 +2,11 @@
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
{$if eq .faviconFileId 0}
<link rel="shortcut icon" href="/images/favicon.png"/>
{$else}
<link rel="shortcut icon" href="/ui/image/{$ .faviconFileId}"/>
{$end}
<title>登录{$.systemName}</title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
{$TEA.VUE}

View File

@@ -41,6 +41,36 @@
<checkbox name="showFinance" v-model="config.showFinance"></checkbox>
</td>
</tr>
<tr>
<td>浏览器图标</td>
<td>
<div v-if="config.faviconFileId > 0">
<a :href="'/ui/image/' + config.faviconFileId" target="_blank"><img :src="'/ui/image/' + config.faviconFileId" style="width:32px;border:1px #ccc solid;"/></a>
</div>
<div v-else>
<span class="disabled">还没有上传。</span>
</div>
<div style="margin-top: 0.8em">
<input type="file" name="faviconFile" accept=".png"/>
</div>
<p class="comment">在浏览器标签栏显示的图标请使用PNG格式。</p>
</td>
</tr>
<tr>
<td>Logo</td>
<td>
<div v-if="config.logoFileId > 0">
<a :href="'/ui/image/' + config.logoFileId" target="_blank"><img :src="'/ui/image/' + config.logoFileId" style="width:32px;border:1px #ccc solid;"/></a>
</div>
<div v-else>
<span class="disabled">还没有上传。</span>
</div>
<div style="margin-top: 0.8em">
<input type="file" name="logoFile" accept=".png"/>
</div>
<p class="comment">显示在系统界面上的图标请使用PNG格式。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>

View File

@@ -41,6 +41,36 @@
<checkbox name="showFinance" v-model="config.showFinance"></checkbox>
</td>
</tr>
<tr>
<td>浏览器图标</td>
<td>
<div v-if="config.faviconFileId > 0">
<a :href="'/ui/image/' + config.faviconFileId" target="_blank"><img :src="'/ui/image/' + config.faviconFileId" style="width:32px;border:1px #ccc solid;"/></a>
</div>
<div v-else>
<span class="disabled">还没有上传。</span>
</div>
<div style="margin-top: 0.8em">
<input type="file" name="faviconFile" accept=".png"/>
</div>
<p class="comment">在浏览器标签栏显示的图标请使用PNG格式。</p>
</td>
</tr>
<tr>
<td>Logo</td>
<td>
<div v-if="config.logoFileId > 0">
<a :href="'/ui/image/' + config.logoFileId" target="_blank"><img :src="'/ui/image/' + config.logoFileId" style="width:32px;border:1px #ccc solid;"/></a>
</div>
<div v-else>
<span class="disabled">还没有上传。</span>
</div>
<div style="margin-top: 0.8em">
<input type="file" name="logoFile" accept=".png"/>
</div>
<p class="comment">显示在系统界面上的图标请使用PNG格式。</p>
</td>
</tr>
</table>
<p class="comment">修改后,可能需要等待数分钟才会生效。</p>