mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-02-02 18:28:41 +08:00
增加前台模块,添加实例html模板页面
This commit is contained in:
parent
6b3333340f
commit
a7658b9b8b
1
server/.gitignore
vendored
1
server/.gitignore
vendored
@ -24,6 +24,7 @@ resource/ssl/server.key
|
||||
temp/
|
||||
main.exe
|
||||
main.exe~
|
||||
*.exe
|
||||
*.log
|
||||
*.zip
|
||||
.idea
|
||||
|
16
server/api/home/base/site.go
Normal file
16
server/api/home/base/site.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Package base
|
||||
// @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 base
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type SiteIndexReq struct {
|
||||
g.Meta `path:"/index" method:"get" summary:"首页" tags:"首页"`
|
||||
}
|
||||
type SiteIndexRes struct {
|
||||
g.Meta `mime:"text/html" type:"string" example:"<html/>"`
|
||||
}
|
@ -17,7 +17,7 @@ var (
|
||||
serverCloseSignal chan struct{}
|
||||
Main = &gcmd.Command{
|
||||
Description: `
|
||||
欢迎使用HotGo!
|
||||
命令提示符
|
||||
---------------------------------------------------------------------------------
|
||||
启动服务
|
||||
>> HTTP服务 [go run main.go http]
|
||||
@ -34,8 +34,8 @@ var (
|
||||
Name: "help",
|
||||
Brief: "查看帮助",
|
||||
Description: `
|
||||
欢迎使用 HotGo
|
||||
当前版本:v2.0.0
|
||||
github地址:https://github.com/bufanyun/hotgo
|
||||
文档地址:文档正在书写中,请耐心等一等。
|
||||
`,
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,8 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
baseApi "hotgo/api/home/base"
|
||||
"hotgo/internal/controller/home/base"
|
||||
"hotgo/internal/library/casbin"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/router"
|
||||
@ -55,7 +57,7 @@ var (
|
||||
|
||||
// 注册默认首页路由
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello hotGo!!")
|
||||
_, _ = base.Site.Index(r.Context(), &baseApi.SiteIndexReq{})
|
||||
return
|
||||
})
|
||||
|
||||
@ -72,6 +74,8 @@ var (
|
||||
// 注册websocket路由
|
||||
router.WebSocket(ctx, group)
|
||||
|
||||
// 注册前台页面路由
|
||||
router.Home(ctx, group)
|
||||
})
|
||||
|
||||
// 启动定时任务
|
||||
|
29
server/internal/controller/home/base/site.go
Normal file
29
server/internal/controller/home/base/site.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Package base
|
||||
// @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 base
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/api/home/base"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
// Site 基础
|
||||
var Site = cSite{}
|
||||
|
||||
type cSite struct{}
|
||||
|
||||
func (a *cSite) Index(ctx context.Context, req *base.SiteIndexReq) (res *base.SiteIndexRes, err error) {
|
||||
service.View().Render(ctx, model.View{Data: g.Map{
|
||||
"name": "HotGo",
|
||||
"version": consts.VersionApp,
|
||||
}})
|
||||
return
|
||||
}
|
@ -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
|
||||
}
|
42
server/internal/model/view.go
Normal file
42
server/internal/model/view.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Package model
|
||||
// @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 model
|
||||
|
||||
// View 视图渲染内容对象
|
||||
type View struct {
|
||||
Title string // 页面标题
|
||||
Keywords string // 页面Keywords
|
||||
Description string // 页面Description
|
||||
IpcCode string // ICP备案号
|
||||
Error string // 错误信息
|
||||
MainTpl string // 自定义MainTpl展示模板文件
|
||||
Redirect string // 引导页面跳转
|
||||
ContentType string // 内容模型
|
||||
BreadCrumb []ViewBreadCrumb // 面包屑
|
||||
GET map[string]interface{} // GET参数
|
||||
Data interface{} // 页面参数
|
||||
}
|
||||
|
||||
// ViewBreadCrumb 视图面包屑结构
|
||||
type ViewBreadCrumb struct {
|
||||
Name string // 显示名称
|
||||
Url string // 链接地址,当为空时表示被选中
|
||||
}
|
||||
|
||||
// ViewGetBreadCrumbInput 获取面包屑请求
|
||||
type ViewGetBreadCrumbInput struct {
|
||||
ContentId uint // (可选)内容ID
|
||||
ContentType string // (可选)内容类型
|
||||
CategoryId uint // (可选)栏目ID
|
||||
}
|
||||
|
||||
// ViewGetTitleInput 获取title请求
|
||||
type ViewGetTitleInput struct {
|
||||
ContentType string // (可选)内容类型
|
||||
CategoryId uint // (可选)栏目ID
|
||||
CurrentName string // (可选)当前名称
|
||||
}
|
26
server/internal/router/home.go
Normal file
26
server/internal/router/home.go
Normal file
@ -0,0 +1,26 @@
|
||||
// Package router
|
||||
// @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 router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"hotgo/internal/controller/home/base"
|
||||
)
|
||||
|
||||
// Home 前台页面路由
|
||||
func Home(ctx context.Context, group *ghttp.RouterGroup) {
|
||||
routerPrefix, _ := g.Cfg().Get(ctx, "router.home.prefix", "/home")
|
||||
|
||||
group.Group(routerPrefix.String(), func(group *ghttp.RouterGroup) {
|
||||
group.Bind(
|
||||
base.Site, // 基础
|
||||
)
|
||||
|
||||
})
|
||||
}
|
@ -92,13 +92,13 @@ type (
|
||||
)
|
||||
|
||||
var (
|
||||
localAdminMemberPost IAdminMemberPost
|
||||
localAdminMenu IAdminMenu
|
||||
localAdminNotice IAdminNotice
|
||||
localAdminPost IAdminPost
|
||||
localAdminRole IAdminRole
|
||||
localAdminDept IAdminDept
|
||||
localAdminMember IAdminMember
|
||||
localAdminMemberPost IAdminMemberPost
|
||||
localAdminMenu IAdminMenu
|
||||
)
|
||||
|
||||
func AdminMemberPost() IAdminMemberPost {
|
||||
|
@ -16,12 +16,6 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
ISysDictType interface {
|
||||
Tree(ctx context.Context) (list []g.Map, err error)
|
||||
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
|
||||
Select(ctx context.Context, in sysin.DictTypeSelectInp) (list sysin.DictTypeSelectModel, err error)
|
||||
}
|
||||
ISysLog interface {
|
||||
Export(ctx context.Context, in sysin.LogListInp) (err error)
|
||||
RealWrite(ctx context.Context, commonLog entity.SysLog) error
|
||||
@ -32,6 +26,15 @@ type (
|
||||
Delete(ctx context.Context, in sysin.LogDeleteInp) error
|
||||
List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int64, err error)
|
||||
}
|
||||
ISysAttachment interface {
|
||||
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (*sysin.AttachmentMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
|
||||
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int64, err error)
|
||||
Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (data *entity.SysAttachment, err error)
|
||||
}
|
||||
ISysBlacklist interface {
|
||||
Delete(ctx context.Context, in sysin.BlacklistDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.BlacklistEditInp) (err error)
|
||||
@ -40,12 +43,6 @@ type (
|
||||
View(ctx context.Context, in sysin.BlacklistViewInp) (res *sysin.BlacklistViewModel, err error)
|
||||
List(ctx context.Context, in sysin.BlacklistListInp) (list []*sysin.BlacklistListModel, totalCount int64, err error)
|
||||
}
|
||||
ISysConfig interface {
|
||||
GetSmtp(ctx context.Context) (conf *model.EmailConfig, err error)
|
||||
GetConfigByGroup(ctx context.Context, in sysin.GetConfigInp) (*sysin.GetConfigModel, error)
|
||||
ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error)
|
||||
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error
|
||||
}
|
||||
ISysCron interface {
|
||||
StartCron(ctx context.Context)
|
||||
Delete(ctx context.Context, in sysin.CronDeleteInp) error
|
||||
@ -55,6 +52,23 @@ type (
|
||||
View(ctx context.Context, in sysin.CronViewInp) (res *sysin.CronViewModel, err error)
|
||||
List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int64, err error)
|
||||
}
|
||||
ISysDictData interface {
|
||||
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
|
||||
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int64, err error)
|
||||
}
|
||||
ISysDictType interface {
|
||||
Tree(ctx context.Context) (list []g.Map, err error)
|
||||
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
|
||||
Select(ctx context.Context, in sysin.DictTypeSelectInp) (list sysin.DictTypeSelectModel, err error)
|
||||
}
|
||||
ISysConfig interface {
|
||||
GetSmtp(ctx context.Context) (conf *model.EmailConfig, err error)
|
||||
GetConfigByGroup(ctx context.Context, in sysin.GetConfigInp) (*sysin.GetConfigModel, error)
|
||||
ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error)
|
||||
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error
|
||||
}
|
||||
ISysCronGroup interface {
|
||||
Delete(ctx context.Context, in sysin.CronGroupDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.CronGroupEditInp) (err error)
|
||||
@ -64,20 +78,6 @@ type (
|
||||
List(ctx context.Context, in sysin.CronGroupListInp) (list []*sysin.CronGroupListModel, totalCount int64, err error)
|
||||
Select(ctx context.Context, in sysin.CronGroupSelectInp) (list sysin.CronGroupSelectModel, err error)
|
||||
}
|
||||
ISysDictData interface {
|
||||
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
|
||||
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int64, err error)
|
||||
}
|
||||
ISysAttachment interface {
|
||||
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (*sysin.AttachmentMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
|
||||
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int64, err error)
|
||||
Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (data *entity.SysAttachment, err error)
|
||||
}
|
||||
ISysProvinces interface {
|
||||
Delete(ctx context.Context, in sysin.ProvincesDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error)
|
||||
@ -89,50 +89,17 @@ type (
|
||||
)
|
||||
|
||||
var (
|
||||
localSysConfig ISysConfig
|
||||
localSysBlacklist ISysBlacklist
|
||||
localSysCron ISysCron
|
||||
localSysCronGroup ISysCronGroup
|
||||
localSysDictData ISysDictData
|
||||
localSysDictType ISysDictType
|
||||
localSysLog ISysLog
|
||||
localSysBlacklist ISysBlacklist
|
||||
localSysProvinces ISysProvinces
|
||||
localSysAttachment ISysAttachment
|
||||
localSysCronGroup ISysCronGroup
|
||||
localSysProvinces ISysProvinces
|
||||
localSysConfig ISysConfig
|
||||
)
|
||||
|
||||
func SysAttachment() ISysAttachment {
|
||||
if localSysAttachment == nil {
|
||||
panic("implement not found for interface ISysAttachment, forgot register?")
|
||||
}
|
||||
return localSysAttachment
|
||||
}
|
||||
|
||||
func RegisterSysAttachment(i ISysAttachment) {
|
||||
localSysAttachment = i
|
||||
}
|
||||
|
||||
func SysProvinces() ISysProvinces {
|
||||
if localSysProvinces == nil {
|
||||
panic("implement not found for interface ISysProvinces, forgot register?")
|
||||
}
|
||||
return localSysProvinces
|
||||
}
|
||||
|
||||
func RegisterSysProvinces(i ISysProvinces) {
|
||||
localSysProvinces = i
|
||||
}
|
||||
|
||||
func SysBlacklist() ISysBlacklist {
|
||||
if localSysBlacklist == nil {
|
||||
panic("implement not found for interface ISysBlacklist, forgot register?")
|
||||
}
|
||||
return localSysBlacklist
|
||||
}
|
||||
|
||||
func RegisterSysBlacklist(i ISysBlacklist) {
|
||||
localSysBlacklist = i
|
||||
}
|
||||
|
||||
func SysConfig() ISysConfig {
|
||||
if localSysConfig == nil {
|
||||
panic("implement not found for interface ISysConfig, forgot register?")
|
||||
@ -144,17 +111,6 @@ func RegisterSysConfig(i ISysConfig) {
|
||||
localSysConfig = i
|
||||
}
|
||||
|
||||
func SysCron() ISysCron {
|
||||
if localSysCron == nil {
|
||||
panic("implement not found for interface ISysCron, forgot register?")
|
||||
}
|
||||
return localSysCron
|
||||
}
|
||||
|
||||
func RegisterSysCron(i ISysCron) {
|
||||
localSysCron = i
|
||||
}
|
||||
|
||||
func SysCronGroup() ISysCronGroup {
|
||||
if localSysCronGroup == nil {
|
||||
panic("implement not found for interface ISysCronGroup, forgot register?")
|
||||
@ -166,6 +122,17 @@ func RegisterSysCronGroup(i ISysCronGroup) {
|
||||
localSysCronGroup = i
|
||||
}
|
||||
|
||||
func SysProvinces() ISysProvinces {
|
||||
if localSysProvinces == nil {
|
||||
panic("implement not found for interface ISysProvinces, forgot register?")
|
||||
}
|
||||
return localSysProvinces
|
||||
}
|
||||
|
||||
func RegisterSysProvinces(i ISysProvinces) {
|
||||
localSysProvinces = i
|
||||
}
|
||||
|
||||
func SysDictData() ISysDictData {
|
||||
if localSysDictData == nil {
|
||||
panic("implement not found for interface ISysDictData, forgot register?")
|
||||
@ -198,3 +165,36 @@ func SysLog() ISysLog {
|
||||
func RegisterSysLog(i ISysLog) {
|
||||
localSysLog = i
|
||||
}
|
||||
|
||||
func SysAttachment() ISysAttachment {
|
||||
if localSysAttachment == nil {
|
||||
panic("implement not found for interface ISysAttachment, forgot register?")
|
||||
}
|
||||
return localSysAttachment
|
||||
}
|
||||
|
||||
func RegisterSysAttachment(i ISysAttachment) {
|
||||
localSysAttachment = i
|
||||
}
|
||||
|
||||
func SysBlacklist() ISysBlacklist {
|
||||
if localSysBlacklist == nil {
|
||||
panic("implement not found for interface ISysBlacklist, forgot register?")
|
||||
}
|
||||
return localSysBlacklist
|
||||
}
|
||||
|
||||
func RegisterSysBlacklist(i ISysBlacklist) {
|
||||
localSysBlacklist = i
|
||||
}
|
||||
|
||||
func SysCron() ISysCron {
|
||||
if localSysCron == nil {
|
||||
panic("implement not found for interface ISysCron, forgot register?")
|
||||
}
|
||||
return localSysCron
|
||||
}
|
||||
|
||||
func RegisterSysCron(i ISysCron) {
|
||||
localSysCron = i
|
||||
}
|
||||
|
41
server/internal/service/view.go
Normal file
41
server/internal/service/view.go
Normal file
@ -0,0 +1,41 @@
|
||||
// ================================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/internal/model"
|
||||
)
|
||||
|
||||
type (
|
||||
IView interface {
|
||||
GetBreadCrumb(ctx context.Context, in *model.ViewGetBreadCrumbInput) []model.ViewBreadCrumb
|
||||
GetTitle(ctx context.Context, in *model.ViewGetTitleInput) string
|
||||
RenderTpl(ctx context.Context, tpl string, data ...model.View)
|
||||
Render(ctx context.Context, data ...model.View)
|
||||
Render302(ctx context.Context, data ...model.View)
|
||||
Render401(ctx context.Context, data ...model.View)
|
||||
Render403(ctx context.Context, data ...model.View)
|
||||
Render404(ctx context.Context, data ...model.View)
|
||||
Render500(ctx context.Context, data ...model.View)
|
||||
Error(ctx context.Context, err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localView IView
|
||||
)
|
||||
|
||||
func View() IView {
|
||||
if localView == nil {
|
||||
panic("implement not found for interface IView, forgot register?")
|
||||
}
|
||||
return localView
|
||||
}
|
||||
|
||||
func RegisterView(i IView) {
|
||||
localView = i
|
||||
}
|
@ -46,6 +46,7 @@ type Client struct {
|
||||
Socket *websocket.Conn // 用户连接
|
||||
Send chan *WResponse // 待发送的数据
|
||||
SendClose bool // 发送是否关闭
|
||||
closeSignal chan struct{} // 关闭信号
|
||||
FirstTime uint64 // 首次连接时间
|
||||
HeartbeatTime uint64 // 用户上次心跳时间
|
||||
Tags garray.StrArray // 标签
|
||||
@ -63,6 +64,7 @@ func NewClient(r *ghttp.Request, socket *websocket.Conn, firstTime uint64) (clie
|
||||
Socket: socket,
|
||||
Send: make(chan *WResponse, 100),
|
||||
SendClose: false,
|
||||
closeSignal: make(chan struct{}, 1),
|
||||
FirstTime: firstTime,
|
||||
HeartbeatTime: firstTime,
|
||||
User: contexts.Get(r.Context()).User,
|
||||
@ -107,6 +109,9 @@ func (c *Client) write() {
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-c.closeSignal:
|
||||
g.Log().Infof(ctxManager, "websocket client quit, user:%+v", c.User)
|
||||
return
|
||||
case message, ok := <-c.Send:
|
||||
if !ok {
|
||||
// 发送数据错误 关闭连接
|
||||
@ -159,12 +164,13 @@ func (c *Client) close() {
|
||||
return
|
||||
}
|
||||
c.SendClose = true
|
||||
if _, ok := <-c.Send; !ok {
|
||||
g.Log().Warningf(ctxManager, "close of closed channel, client.id:%v", c.ID)
|
||||
} else {
|
||||
// 关闭 chan
|
||||
close(c.Send)
|
||||
}
|
||||
//if _, ok := <-c.Send; !ok {
|
||||
// g.Log().Warningf(ctxManager, "close of closed channel, client.id:%v", c.ID)
|
||||
//} else {
|
||||
// // 关闭 chan
|
||||
// close(c.Send)
|
||||
//}
|
||||
c.closeSignal <- struct{}{}
|
||||
}
|
||||
|
||||
// Close 关闭指定客户端连接
|
||||
|
@ -50,6 +50,18 @@ server:
|
||||
pprofEnabled: true # 是否开启PProf性能调试特性。默认为false
|
||||
pprofPattern: "/pprof" # 开启PProf时有效,表示PProf特性的页面访问路径,对当前Server绑定的所有域名有效。
|
||||
|
||||
viewer:
|
||||
paths: "resource/template"
|
||||
defaultFile: "index.html"
|
||||
delimiters: ["@{", "}"]
|
||||
homeLayout: "home/index.html"
|
||||
|
||||
# 内容设置
|
||||
setting:
|
||||
title: "HotGo"
|
||||
keywords: "中后台解决方案,gf框架,vue3"
|
||||
description: "hotgo 是一个基于 goframe2,vue3,vite2,TypeScript,uinapp 的中后台解决方案,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你,持续更新中。"
|
||||
|
||||
|
||||
# 路由配置
|
||||
router:
|
||||
@ -82,6 +94,12 @@ router:
|
||||
# 不需要验证登录的路由地址
|
||||
exceptLogin: [
|
||||
]
|
||||
# 前台页面
|
||||
home:
|
||||
# 前缀
|
||||
prefix: "/home"
|
||||
# 不需要验证登录的路由地址
|
||||
exceptPath: [ ]
|
||||
|
||||
#JWT
|
||||
jwt:
|
||||
|
2
server/resource/public/resource/home/js/jquery-3.6.0.min.js
vendored
Normal file
2
server/resource/public/resource/home/js/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
33
server/resource/template/home/index.html
Normal file
33
server/resource/template/home/index.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
|
||||
<meta name="keywords" content="@{.Keywords}"/>
|
||||
<meta name="description" content="@{.Description}"/>
|
||||
<title>@{.Title}</title>
|
||||
<script type="text/javascript" src="/resource/home/js/jquery-3.6.0.min.js"></script>
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="padding-top: 100px;text-align:center;">
|
||||
<h1><p>Hello,@{.Data.name}!!</p></h1>
|
||||
<h2><p>当前版本:@{.Data.version}</p></h2>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user