mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-08-28 10:09:54 +08:00
增加前台模块,添加实例html模板页面
This commit is contained in:
@@ -10,4 +10,5 @@ import (
|
||||
_ "hotgo/internal/logic/hook"
|
||||
_ "hotgo/internal/logic/middleware"
|
||||
_ "hotgo/internal/logic/sys"
|
||||
_ "hotgo/internal/logic/view"
|
||||
)
|
||||
|
@@ -29,6 +29,12 @@ func (s *sMiddleware) ResponseHandler(r *ghttp.Request) {
|
||||
err error
|
||||
)
|
||||
|
||||
// 模板页面响应
|
||||
if "text/html" == r.Response.Header().Get("Content-Type") {
|
||||
r.Middleware.Next()
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.GetError(); err != nil {
|
||||
g.Log().Print(ctx, err)
|
||||
// 记录到自定义错误日志文件
|
||||
|
192
server/internal/logic/view/view.go
Normal file
192
server/internal/logic/view/view.go
Normal file
@@ -0,0 +1,192 @@
|
||||
// Package view
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package view
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
type sView struct{}
|
||||
|
||||
func init() {
|
||||
service.RegisterView(New())
|
||||
}
|
||||
|
||||
func New() *sView {
|
||||
return &sView{}
|
||||
}
|
||||
|
||||
// GetBreadCrumb 前台系统-获取面包屑列表
|
||||
func (s *sView) GetBreadCrumb(ctx context.Context, in *model.ViewGetBreadCrumbInput) []model.ViewBreadCrumb {
|
||||
breadcrumb := []model.ViewBreadCrumb{
|
||||
{Name: "首页", Url: "/"},
|
||||
}
|
||||
return breadcrumb
|
||||
}
|
||||
|
||||
// GetTitle 前台系统-获取标题
|
||||
func (s *sView) GetTitle(ctx context.Context, in *model.ViewGetTitleInput) string {
|
||||
return "title"
|
||||
}
|
||||
|
||||
// RenderTpl 渲染指定模板页面
|
||||
func (s *sView) RenderTpl(ctx context.Context, tpl string, data ...model.View) {
|
||||
var (
|
||||
viewObj = model.View{}
|
||||
viewData = make(g.Map)
|
||||
request = g.RequestFromCtx(ctx)
|
||||
)
|
||||
if len(data) > 0 {
|
||||
viewObj = data[0]
|
||||
}
|
||||
if viewObj.Title == "" {
|
||||
viewObj.Title = g.Cfg().MustGet(ctx, `setting.title`).String()
|
||||
} else {
|
||||
viewObj.Title = viewObj.Title + ` - ` + g.Cfg().MustGet(ctx, `setting.title`).String()
|
||||
}
|
||||
if viewObj.Keywords == "" {
|
||||
viewObj.Keywords = g.Cfg().MustGet(ctx, `setting.keywords`).String()
|
||||
}
|
||||
if viewObj.Description == "" {
|
||||
viewObj.Description = g.Cfg().MustGet(ctx, `setting.description`).String()
|
||||
}
|
||||
if viewObj.IpcCode == "" {
|
||||
viewObj.IpcCode = g.Cfg().MustGet(ctx, `setting.icpCode`).String()
|
||||
}
|
||||
|
||||
if viewObj.GET == nil {
|
||||
viewObj.GET = request.GetQueryMap()
|
||||
}
|
||||
|
||||
// 去掉空数据
|
||||
viewData = gconv.Map(viewObj)
|
||||
for k, v := range viewData {
|
||||
if g.IsEmpty(v) {
|
||||
delete(viewData, k)
|
||||
}
|
||||
}
|
||||
// 内置对象
|
||||
viewData["BuildIn"] = &viewBuildIn{httpRequest: request}
|
||||
|
||||
// 渲染模板
|
||||
_ = request.Response.WriteTpl(tpl, viewData)
|
||||
}
|
||||
|
||||
// Render 渲染默认模板页面
|
||||
func (s *sView) Render(ctx context.Context, data ...model.View) {
|
||||
s.RenderTpl(ctx, g.Cfg().MustGet(ctx, "viewer.homeLayout").String(), data...)
|
||||
}
|
||||
|
||||
// Render302 跳转中间页面
|
||||
func (s *sView) Render302(ctx context.Context, data ...model.View) {
|
||||
view := model.View{}
|
||||
if len(data) > 0 {
|
||||
view = data[0]
|
||||
}
|
||||
if view.Title == "" {
|
||||
view.Title = "页面跳转中"
|
||||
}
|
||||
//view.MainTpl = s.getViewFolderName(ctx) + "/pages/302.html"
|
||||
//s.Render(ctx, view)
|
||||
s.RenderTpl(ctx, "default/pages/302.html", view)
|
||||
}
|
||||
|
||||
// Render401 401页面
|
||||
func (s *sView) Render401(ctx context.Context, data ...model.View) {
|
||||
view := model.View{}
|
||||
if len(data) > 0 {
|
||||
view = data[0]
|
||||
}
|
||||
if view.Title == "" {
|
||||
view.Title = "无访问权限"
|
||||
}
|
||||
s.RenderTpl(ctx, "default/pages/401.html", view)
|
||||
}
|
||||
|
||||
// Render403 403页面
|
||||
func (s *sView) Render403(ctx context.Context, data ...model.View) {
|
||||
view := model.View{}
|
||||
if len(data) > 0 {
|
||||
view = data[0]
|
||||
}
|
||||
if view.Title == "" {
|
||||
view.Title = "无访问权限"
|
||||
}
|
||||
s.RenderTpl(ctx, "default/pages/403.html", view)
|
||||
}
|
||||
|
||||
// Render404 404页面
|
||||
func (s *sView) Render404(ctx context.Context, data ...model.View) {
|
||||
view := model.View{}
|
||||
if len(data) > 0 {
|
||||
view = data[0]
|
||||
}
|
||||
if view.Title == "" {
|
||||
view.Title = "资源不存在"
|
||||
}
|
||||
s.RenderTpl(ctx, "default/pages/404.html", view)
|
||||
}
|
||||
|
||||
// Render500 500页面
|
||||
func (s *sView) Render500(ctx context.Context, data ...model.View) {
|
||||
view := model.View{}
|
||||
if len(data) > 0 {
|
||||
view = data[0]
|
||||
}
|
||||
if view.Title == "" {
|
||||
view.Title = "请求执行错误"
|
||||
}
|
||||
s.RenderTpl(ctx, "default/pages/500.html", view)
|
||||
}
|
||||
|
||||
func (s *sView) Error(ctx context.Context, err error) {
|
||||
view := model.View{
|
||||
Title: "错误提示",
|
||||
Error: err.Error(),
|
||||
}
|
||||
s.RenderTpl(ctx, "default/pages/500.html", view)
|
||||
}
|
||||
|
||||
// 获取视图存储目录
|
||||
func (s *sView) getViewFolderName(ctx context.Context) string {
|
||||
return gstr.Split(g.Cfg().MustGet(ctx, "viewer.indexLayout").String(), "/")[0]
|
||||
}
|
||||
|
||||
// 获取自动设置的MainTpl
|
||||
func (s *sView) getDefaultMainTpl(ctx context.Context) string {
|
||||
var (
|
||||
viewFolderPrefix = s.getViewFolderName(ctx)
|
||||
urlPathArray = gstr.SplitAndTrim(g.RequestFromCtx(ctx).URL.Path, "/")
|
||||
mainTpl string
|
||||
)
|
||||
if len(urlPathArray) > 0 && urlPathArray[0] == viewFolderPrefix {
|
||||
urlPathArray = urlPathArray[1:]
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(urlPathArray) == 2:
|
||||
// 如果2级路由为数字,那么为模块的详情页面,那么路由固定为/xxx/detail。
|
||||
// 如果需要定制化内容模板,请在具体路由方法中设置MainTpl。
|
||||
if gstr.IsNumeric(urlPathArray[1]) {
|
||||
urlPathArray[1] = "detail"
|
||||
}
|
||||
mainTpl = viewFolderPrefix + "/" + gfile.Join(urlPathArray[0], urlPathArray[1]) + ".html"
|
||||
case len(urlPathArray) == 1:
|
||||
mainTpl = viewFolderPrefix + "/" + urlPathArray[0] + "/index.html"
|
||||
default:
|
||||
// 默认首页内容
|
||||
mainTpl = viewFolderPrefix + "/index/index.html"
|
||||
}
|
||||
|
||||
return gstr.TrimLeft(mainTpl, "/")
|
||||
}
|
91
server/internal/logic/view/view_buildin.go
Normal file
91
server/internal/logic/view/view_buildin.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package view
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hotgo/internal/consts"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gmode"
|
||||
)
|
||||
|
||||
// 视图自定义方法管理对象
|
||||
type viewBuildIn struct {
|
||||
httpRequest *ghttp.Request
|
||||
}
|
||||
|
||||
// Page 创建分页HTML内容
|
||||
func (s *viewBuildIn) Page(total, size int) string {
|
||||
page := s.httpRequest.GetPage(total, size)
|
||||
page.LinkStyle = "page-link"
|
||||
page.SpanStyle = "page-link"
|
||||
page.PrevPageTag = "«"
|
||||
page.NextPageTag = "»"
|
||||
content := page.PrevPage() + page.PageBar() + page.NextPage()
|
||||
content = gstr.ReplaceByMap(content, map[string]string{
|
||||
"<span": "<li class=\"page-item disabled\"><span",
|
||||
"/span>": "/span></li>",
|
||||
"<a": "<li class=\"page-item\"><a",
|
||||
"/a>": "/a></li>",
|
||||
})
|
||||
return content
|
||||
}
|
||||
|
||||
// UrlPath 获取当前页面的Url Path.
|
||||
func (s *viewBuildIn) UrlPath() string {
|
||||
return s.httpRequest.URL.Path
|
||||
}
|
||||
|
||||
// FormatTime 格式化时间
|
||||
func (s *viewBuildIn) FormatTime(gt *gtime.Time) string {
|
||||
if gt == nil {
|
||||
return ""
|
||||
}
|
||||
n := gtime.Now().Timestamp()
|
||||
t := gt.Timestamp()
|
||||
|
||||
var ys int64 = 31536000
|
||||
var ds int64 = 86400
|
||||
var hs int64 = 3600
|
||||
var ms int64 = 60
|
||||
var ss int64 = 1
|
||||
|
||||
var rs string
|
||||
|
||||
d := n - t
|
||||
switch {
|
||||
case d > ys:
|
||||
rs = fmt.Sprintf("%d年前", int(d/ys))
|
||||
case d > ds:
|
||||
rs = fmt.Sprintf("%d天前", int(d/ds))
|
||||
case d > hs:
|
||||
rs = fmt.Sprintf("%d小时前", int(d/hs))
|
||||
case d > ms:
|
||||
rs = fmt.Sprintf("%d分钟前", int(d/ms))
|
||||
case d > ss:
|
||||
rs = fmt.Sprintf("%d秒前", int(d/ss))
|
||||
default:
|
||||
rs = "刚刚"
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// Version 随机数 开发环境时间戳,线上为前端版本号
|
||||
func (s *viewBuildIn) Version() string {
|
||||
var rand string
|
||||
if gmode.IsDevelop() {
|
||||
rand = gconv.String(gtime.TimestampMilli())
|
||||
} else {
|
||||
rand = consts.VersionApp
|
||||
}
|
||||
return rand
|
||||
}
|
Reference in New Issue
Block a user