From edb673ee34c1a5b10cd24c50979ba85f80812e73 Mon Sep 17 00:00:00 2001 From: osi Date: Fri, 19 Sep 2025 19:40:00 +0800 Subject: [PATCH 1/3] =?UTF-8?q?:art:=20=E5=8E=BB=E9=99=A4mysql=E7=A1=AC?= =?UTF-8?q?=E7=BC=96=E7=A0=81=20=E6=96=B9=E4=BE=BF=E5=88=87=E6=8D=A2pgsql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/internal/logic/admin/notice.go | 56 ++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/server/internal/logic/admin/notice.go b/server/internal/logic/admin/notice.go index 3470869..8db1dfd 100644 --- a/server/internal/logic/admin/notice.go +++ b/server/internal/logic/admin/notice.go @@ -159,6 +159,45 @@ func (s *sAdminNotice) View(ctx context.Context, in *adminin.NoticeViewInp) (res return res, nil } +// api列表 不需要登陆 +func (s *sAdminNotice) ApiList(ctx context.Context, in *adminin.NoticeListInp) (list []*adminin.NoticeViewModel, totalCount int, err error) { + + + mod := s.Model(ctx) + + if in.Title != "" { + mod = mod.WhereLike("title", "%"+in.Title+"%") + } + + if in.Content != "" { + mod = mod.WhereLike("content", "%"+in.Content+"%") + } + + if in.Type > 0 { + mod = mod.Where("type", in.Type) + } + + if in.Status > 0 { + mod = mod.Where("status", in.Status) + } + + totalCount, err = mod.Count() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return list, totalCount, err + } + + if totalCount == 0 { + return list, totalCount, nil + } + + if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return list, totalCount, err + } + + return list, totalCount, err +} // List 获取列表 func (s *sAdminNotice) List(ctx context.Context, in *adminin.NoticeListInp) (list []*adminin.NoticeListModel, totalCount int, err error) { var memberId = contexts.GetUserId(ctx) @@ -291,7 +330,8 @@ func (s *sAdminNotice) UnreadCount(ctx context.Context, in *adminin.NoticeUnread stat := func(t int) (count int) { all, err := dao.AdminNotice.Ctx(ctx).As("nr"). - Where("type =? and id IN(?)", t, in.MessageIds). + Where("type", t). + WhereIn("id", in.MessageIds). Count() if err != nil { g.Log().Infof(ctx, "UnreadCount stat err:%+v", err) @@ -304,7 +344,8 @@ func (s *sAdminNotice) UnreadCount(ctx context.Context, in *adminin.NoticeUnread read, err := dao.AdminNoticeRead.Ctx(ctx).As("nr"). LeftJoin("admin_notice n", "nr.notice_id=n.id"). - Where("n.type = ? and n.id IN(?)", t, in.MessageIds). + Where("n.type", t). + WhereIn("n.id", in.MessageIds). Where("nr.member_id", in.MemberId). Count() if err != nil { @@ -327,8 +368,9 @@ func (s *sAdminNotice) messageIds(ctx context.Context, memberId int64) (ids []in columns, err := s.Model(ctx, &handler.Option{FilterAuth: false}). Fields(dao.AdminNotice.Columns().Id). Where(dao.AdminNotice.Columns().Status, consts.StatusEnabled). - Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))", - []int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter, + Where( + s.Model(ctx, &handler.Option{FilterAuth: false}).Builder().WhereIn("type",[]int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}). + WhereOr(s.Model(ctx, &handler.Option{FilterAuth: false}).Builder().Where("type", consts.NoticeTypeLetter).Wheref("receiver->>'$.key'= ?", gconv.String(memberId))), ).Array() if err != nil { err = gerror.Wrap(err, "获取我的消息失败!") @@ -381,7 +423,8 @@ func (s *sAdminNotice) ReadAll(ctx context.Context, in *adminin.NoticeReadAllInp array, err := dao.AdminNotice.Ctx(ctx). Fields("id"). - Where("type = ? and id IN(?)", in.Type, allMessageIds). + Where("type", in.Type). + WhereIn("id", allMessageIds). Array() if err != nil { return @@ -395,7 +438,8 @@ func (s *sAdminNotice) ReadAll(ctx context.Context, in *adminin.NoticeReadAllInp array, err = dao.AdminNoticeRead.Ctx(ctx).As("nr"). Fields("nr.notice_id"). LeftJoin("admin_notice n", "nr.notice_id=n.id"). - Where("n.type = ? and n.id IN(?)", in.Type, messageIds). + Where("n.type", in.Type). + WhereIn("n.id", messageIds). Where("nr.member_id", memberId). Array() if err != nil { From f254132e187606985b0a71832a7406735bfdd581 Mon Sep 17 00:00:00 2001 From: osi Date: Fri, 19 Sep 2025 20:44:33 +0800 Subject: [PATCH 2/3] =?UTF-8?q?:art:=20:fire:=20:sparkles:=20:ambulance:?= =?UTF-8?q?=20=E9=9B=86=E6=88=90=E5=89=8D=E7=AB=AF=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=9A=84&=E5=85=BC=E5=AE=B9=E5=AE=B9=E5=99=A8=E5=8C=96?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=8F=92=E4=BB=B6=E7=9A=84=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=94=B9=E9=80=A0&=E6=8F=90=E4=BE=9B=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=96=B0=E7=9A=84=E8=BD=AE=E6=92=AD=E5=9B=BE=E6=8F=92?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/addons/flashbanner/README.MD | 45 +++++ .../flashbanner/api/admin/banner/banner.go | 65 +++++++ .../flashbanner/api/admin/config/config.go | 30 +++ .../api/admin/index/banner/banner.go | 33 ++++ .../flashbanner/api/admin/index/index.go | 23 +++ .../addons/flashbanner/api/api/index/index.go | 21 +++ .../flashbanner/api/home/index/index.go | 21 +++ .../flashbanner/api/websocket/index/index.go | 21 +++ server/addons/flashbanner/consts/consts.go | 9 + .../controller/admin/banner/banner.go | 81 ++++++++ .../controller/admin/sys/banner.go | 14 ++ .../controller/admin/sys/config.go | 33 ++++ .../flashbanner/controller/admin/sys/index.go | 30 +++ .../controller/api/banner/banner.go | 41 ++++ .../flashbanner/controller/api/index.go | 31 +++ .../flashbanner/controller/home/index.go | 34 ++++ .../flashbanner/controller/websocket/index.go | 30 +++ server/addons/flashbanner/crons/crons.go | 9 + server/addons/flashbanner/dao/banner.go | 12 ++ .../addons/flashbanner/dao/internal/banner.go | 89 +++++++++ server/addons/flashbanner/global/global.go | 12 ++ server/addons/flashbanner/global/init.go | 22 +++ server/addons/flashbanner/logic/.gitkeep | 0 server/addons/flashbanner/logic/logic.go | 9 + server/addons/flashbanner/logic/sys/banner.go | 173 +++++++++++++++++ server/addons/flashbanner/logic/sys/config.go | 59 ++++++ server/addons/flashbanner/logic/sys/index.go | 35 ++++ server/addons/flashbanner/main.go | 176 ++++++++++++++++++ server/addons/flashbanner/model/config.go | 11 ++ .../addons/flashbanner/model/entity/banner.go | 22 +++ .../flashbanner/model/input/sysin/banner.go | 98 ++++++++++ .../flashbanner/model/input/sysin/config.go | 24 +++ .../flashbanner/model/input/sysin/index.go | 27 +++ server/addons/flashbanner/queues/queues.go | 9 + .../flashbanner/resource/public/.gitkeep | 0 .../flashbanner/resource/public/default | 1 + .../resource/template/home/index.html | 30 +++ server/addons/flashbanner/router/admin.go | 36 ++++ server/addons/flashbanner/router/api.go | 32 ++++ .../flashbanner/router/genrouter/init.go | 34 ++++ server/addons/flashbanner/router/home.go | 25 +++ server/addons/flashbanner/router/websocket.go | 39 ++++ server/addons/flashbanner/service/.gitkeep | 0 server/addons/flashbanner/service/sys.go | 71 +++++++ .../api/addons/flashbanner/config/index.ts | 17 ++ .../web/src/api/addons/flashbanner/index.ts | 33 ++++ .../addons/flashbanner/components/Edit.vue | 106 +++++++++++ .../addons/flashbanner/components/model.ts | 83 +++++++++ .../flashbanner/config/BasicSetting.vue | 74 ++++++++ .../addons/flashbanner/config/system.vue | 82 ++++++++ .../src/views/addons/flashbanner/index.vue | 151 +++++++++++++++ .../migrations/flashbanner/install.pg.sql | 167 +++++++++++++++++ .../addons/migrations/flashbanner/install.sql | 33 ++++ .../migrations/flashbanner/uninstall.pg.sql | 9 + .../migrations/flashbanner/uninstall.sql | 9 + server/addons/migrations/readme.md | 2 + server/addons/migrations/sqlDo.go | 66 +++++++ server/addons/modules/flashbanner.go | 8 + server/internal/library/addons/build.go | 49 +++-- .../generate/default/addon/README.MD.template | 11 ++ .../generate/default/addon/main.go.template | 68 ++++++- 61 files changed, 2569 insertions(+), 16 deletions(-) create mode 100644 server/addons/flashbanner/README.MD create mode 100644 server/addons/flashbanner/api/admin/banner/banner.go create mode 100644 server/addons/flashbanner/api/admin/config/config.go create mode 100644 server/addons/flashbanner/api/admin/index/banner/banner.go create mode 100644 server/addons/flashbanner/api/admin/index/index.go create mode 100644 server/addons/flashbanner/api/api/index/index.go create mode 100644 server/addons/flashbanner/api/home/index/index.go create mode 100644 server/addons/flashbanner/api/websocket/index/index.go create mode 100644 server/addons/flashbanner/consts/consts.go create mode 100644 server/addons/flashbanner/controller/admin/banner/banner.go create mode 100644 server/addons/flashbanner/controller/admin/sys/banner.go create mode 100644 server/addons/flashbanner/controller/admin/sys/config.go create mode 100644 server/addons/flashbanner/controller/admin/sys/index.go create mode 100644 server/addons/flashbanner/controller/api/banner/banner.go create mode 100644 server/addons/flashbanner/controller/api/index.go create mode 100644 server/addons/flashbanner/controller/home/index.go create mode 100644 server/addons/flashbanner/controller/websocket/index.go create mode 100644 server/addons/flashbanner/crons/crons.go create mode 100644 server/addons/flashbanner/dao/banner.go create mode 100644 server/addons/flashbanner/dao/internal/banner.go create mode 100644 server/addons/flashbanner/global/global.go create mode 100644 server/addons/flashbanner/global/init.go create mode 100644 server/addons/flashbanner/logic/.gitkeep create mode 100644 server/addons/flashbanner/logic/logic.go create mode 100644 server/addons/flashbanner/logic/sys/banner.go create mode 100644 server/addons/flashbanner/logic/sys/config.go create mode 100644 server/addons/flashbanner/logic/sys/index.go create mode 100644 server/addons/flashbanner/main.go create mode 100644 server/addons/flashbanner/model/config.go create mode 100644 server/addons/flashbanner/model/entity/banner.go create mode 100644 server/addons/flashbanner/model/input/sysin/banner.go create mode 100644 server/addons/flashbanner/model/input/sysin/config.go create mode 100644 server/addons/flashbanner/model/input/sysin/index.go create mode 100644 server/addons/flashbanner/queues/queues.go create mode 100644 server/addons/flashbanner/resource/public/.gitkeep create mode 100644 server/addons/flashbanner/resource/public/default create mode 100644 server/addons/flashbanner/resource/template/home/index.html create mode 100644 server/addons/flashbanner/router/admin.go create mode 100644 server/addons/flashbanner/router/api.go create mode 100644 server/addons/flashbanner/router/genrouter/init.go create mode 100644 server/addons/flashbanner/router/home.go create mode 100644 server/addons/flashbanner/router/websocket.go create mode 100644 server/addons/flashbanner/service/.gitkeep create mode 100644 server/addons/flashbanner/service/sys.go create mode 100644 server/addons/flashbanner/web/src/api/addons/flashbanner/config/index.ts create mode 100644 server/addons/flashbanner/web/src/api/addons/flashbanner/index.ts create mode 100644 server/addons/flashbanner/web/src/views/addons/flashbanner/components/Edit.vue create mode 100644 server/addons/flashbanner/web/src/views/addons/flashbanner/components/model.ts create mode 100644 server/addons/flashbanner/web/src/views/addons/flashbanner/config/BasicSetting.vue create mode 100644 server/addons/flashbanner/web/src/views/addons/flashbanner/config/system.vue create mode 100644 server/addons/flashbanner/web/src/views/addons/flashbanner/index.vue create mode 100644 server/addons/migrations/flashbanner/install.pg.sql create mode 100644 server/addons/migrations/flashbanner/install.sql create mode 100644 server/addons/migrations/flashbanner/uninstall.pg.sql create mode 100644 server/addons/migrations/flashbanner/uninstall.sql create mode 100644 server/addons/migrations/readme.md create mode 100644 server/addons/migrations/sqlDo.go create mode 100644 server/addons/modules/flashbanner.go diff --git a/server/addons/flashbanner/README.MD b/server/addons/flashbanner/README.MD new file mode 100644 index 0000000..76a4f7b --- /dev/null +++ b/server/addons/flashbanner/README.MD @@ -0,0 +1,45 @@ +## 轮播图管理 + +### 简介 + + + + +### 使用说明 + + + + +### 迁移或安装 + +1、安装 HotGo (2.17.8及以上) + +项目介绍:https://github.com/bufanyun/hotgo + +2、将当前插件项目拷贝进 HotGo 根目录的 server/addons 目录下 + +3、在 HotGo 根目录的 server/addons/modules 目录下创建go文件:flashbanner.go,内容如下: +```go +package modules + +import _ "hotgo/addons/flashbanner" +``` + +4、HotGo 后台进入 开发工具->插件管理->找到 轮播图管理 (flashbanner) 进行安装 + +5、重启服务即可生效 + + +### 常用命令行 + +```shell +# 接口维护-gen service +gf gen service -s=addons/flashbanner/logic -d=addons/flashbanner/service + +``` + +### `gf gen dao` 之后迁移model文件 +``` +cp .\internal\dao\internal\banner* .\addons\flashbanner\dao\internal\ +cp .\internal\model\entity\banner* .\addons\flashbanner\model\entity\ +``` diff --git a/server/addons/flashbanner/api/admin/banner/banner.go b/server/addons/flashbanner/api/admin/banner/banner.go new file mode 100644 index 0000000..9d75f55 --- /dev/null +++ b/server/addons/flashbanner/api/admin/banner/banner.go @@ -0,0 +1,65 @@ +// Package banner +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package banner + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" + "hotgo/internal/model/input/form" +) + +// CreateReq 创建轮播图 +type CreateReq struct { + g.Meta `path:"/banner/create" method:"post" tags:"轮播图" summary:"创建轮播图"` + sysin.BannerCreateInp +} + +type CreateRes struct{} + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/banner/list" method:"get" tags:"轮播图" summary:"获取轮播图列表"` + sysin.BannerListInp +} + +type ListRes struct { + List []*sysin.BannerListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/banner/view" method:"get" tags:"轮播图" summary:"获取指定轮播图信息"` + sysin.BannerViewInp +} + +type ViewRes struct { + *sysin.BannerViewModel +} + +// EditReq 修改/新增轮播图 +type EditReq struct { + g.Meta `path:"/banner/edit" method:"post" tags:"轮播图" summary:"修改/新增轮播图"` + sysin.BannerEditInp +} + +type EditRes struct{} + +// DeleteReq 删除轮播图 +type DeleteReq struct { + g.Meta `path:"/banner/delete" method:"post" tags:"轮播图" summary:"删除轮播图"` + sysin.BannerDeleteInp +} + +type DeleteRes struct{} + +// StatusReq 更新轮播图状态 +type StatusReq struct { + g.Meta `path:"/banner/status" method:"post" tags:"轮播图" summary:"更新轮播图状态"` + sysin.BannerStatusInp +} + +type StatusRes struct{} \ No newline at end of file diff --git a/server/addons/flashbanner/api/admin/config/config.go b/server/addons/flashbanner/api/admin/config/config.go new file mode 100644 index 0000000..e54dc78 --- /dev/null +++ b/server/addons/flashbanner/api/admin/config/config.go @@ -0,0 +1,30 @@ +// Package config +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package config + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" +) + +// GetReq 获取指定分组的配置 +type GetReq struct { + g.Meta `path:"/config/get" method:"get" tags:"轮播图管理" summary:"获取指定分组的配置"` + sysin.GetConfigInp +} + +type GetRes struct { + *sysin.GetConfigModel +} + +// UpdateReq 获取指定分组的配置 +type UpdateReq struct { + g.Meta `path:"/config/update" method:"post" tags:"轮播图管理" summary:"获取指定分组的配置"` + sysin.UpdateConfigInp +} + +type UpdateRes struct { +} diff --git a/server/addons/flashbanner/api/admin/index/banner/banner.go b/server/addons/flashbanner/api/admin/index/banner/banner.go new file mode 100644 index 0000000..8ef1cb2 --- /dev/null +++ b/server/addons/flashbanner/api/admin/index/banner/banner.go @@ -0,0 +1,33 @@ +// Package banner +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package banner + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/banner/list" method:"get" tags:"轮播图" summary:"获取轮播图列表"` + sysin.BannerListInp +} + +type ListRes struct { + List []*sysin.BannerListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/banner/view" method:"get" tags:"轮播图" summary:"获取指定轮播图信息"` + sysin.BannerViewInp +} + +type ViewRes struct { + *sysin.BannerViewModel +} diff --git a/server/addons/flashbanner/api/admin/index/index.go b/server/addons/flashbanner/api/admin/index/index.go new file mode 100644 index 0000000..9688324 --- /dev/null +++ b/server/addons/flashbanner/api/admin/index/index.go @@ -0,0 +1,23 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"轮播图管理" summary:"测试后台API"` + sysin.IndexTestInp +} + +type TestRes struct { + *sysin.IndexTestModel +} + + diff --git a/server/addons/flashbanner/api/api/index/index.go b/server/addons/flashbanner/api/api/index/index.go new file mode 100644 index 0000000..763ef79 --- /dev/null +++ b/server/addons/flashbanner/api/api/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"轮播图管理" summary:"测试前台API"` + sysin.IndexTestInp +} + +type TestRes struct { + *sysin.IndexTestModel +} diff --git a/server/addons/flashbanner/api/home/index/index.go b/server/addons/flashbanner/api/home/index/index.go new file mode 100644 index 0000000..31fce84 --- /dev/null +++ b/server/addons/flashbanner/api/home/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" summary:"轮播图管理" tags:"测试首页"` + sysin.IndexTestInp +} + +type TestRes struct { + g.Meta `mime:"text/html" type:"string" example:""` +} diff --git a/server/addons/flashbanner/api/websocket/index/index.go b/server/addons/flashbanner/api/websocket/index/index.go new file mode 100644 index 0000000..c437577 --- /dev/null +++ b/server/addons/flashbanner/api/websocket/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"轮播图管理" summary:"测试websocket"` + sysin.IndexTestInp +} + +type TestRes struct { + *sysin.IndexTestModel +} diff --git a/server/addons/flashbanner/consts/consts.go b/server/addons/flashbanner/consts/consts.go new file mode 100644 index 0000000..4306296 --- /dev/null +++ b/server/addons/flashbanner/consts/consts.go @@ -0,0 +1,9 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 常量枚举. +// 插件中的常量枚举可以统一在这目录下 diff --git a/server/addons/flashbanner/controller/admin/banner/banner.go b/server/addons/flashbanner/controller/admin/banner/banner.go new file mode 100644 index 0000000..45f2c2c --- /dev/null +++ b/server/addons/flashbanner/controller/admin/banner/banner.go @@ -0,0 +1,81 @@ +// Package banner +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package banner + +import ( + "context" + "hotgo/addons/flashbanner/api/admin/banner" + "hotgo/addons/flashbanner/service" +) + +var ( + Banner = cBanner{} +) + +type cBanner struct{} + +// Create 创建轮播图 +func (c *cBanner) Create(ctx context.Context, req *banner.CreateReq) (res *banner.CreateRes, err error) { + err = service.SysBanner().Create(ctx, &req.BannerCreateInp) + if err != nil { + return nil, err + } + res = &banner.CreateRes{} + return res, nil +} + +// List 获取轮播图列表 +func (c *cBanner) List(ctx context.Context, req *banner.ListReq) (res *banner.ListRes, err error) { + list, totalCount, err := service.SysBanner().List(ctx, &req.BannerListInp) + if err != nil { + return nil, err + } + res = &banner.ListRes{ + List: list, + } + res.PageRes.Pack(&req.BannerListInp, totalCount) + return res, nil +} + +// View 获取指定轮播图信息 +func (c *cBanner) View(ctx context.Context, req *banner.ViewReq) (res *banner.ViewRes, err error) { + model, err := service.SysBanner().View(ctx, &req.BannerViewInp) + if err != nil { + return nil, err + } + res = &banner.ViewRes{model} + return res, nil +} + +// Edit 修改/新增轮播图 +func (c *cBanner) Edit(ctx context.Context, req *banner.EditReq) (res *banner.EditRes, err error) { + err = service.SysBanner().Edit(ctx, &req.BannerEditInp) + if err != nil { + return nil, err + } + res = &banner.EditRes{} + return res, nil +} + +// Delete 删除轮播图 +func (c *cBanner) Delete(ctx context.Context, req *banner.DeleteReq) (res *banner.DeleteRes, err error) { + err = service.SysBanner().Delete(ctx, &req.BannerDeleteInp) + if err != nil { + return nil, err + } + res = &banner.DeleteRes{} + return res, nil +} + +// Status 更新轮播图状态 +func (c *cBanner) Status(ctx context.Context, req *banner.StatusReq) (res *banner.StatusRes, err error) { + err = service.SysBanner().Status(ctx, &req.BannerStatusInp) + if err != nil { + return nil, err + } + res = &banner.StatusRes{} + return res, nil +} \ No newline at end of file diff --git a/server/addons/flashbanner/controller/admin/sys/banner.go b/server/addons/flashbanner/controller/admin/sys/banner.go new file mode 100644 index 0000000..47dbe1e --- /dev/null +++ b/server/addons/flashbanner/controller/admin/sys/banner.go @@ -0,0 +1,14 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "hotgo/addons/flashbanner/controller/admin/banner" +) + +var ( + Banner = banner.Banner +) \ No newline at end of file diff --git a/server/addons/flashbanner/controller/admin/sys/config.go b/server/addons/flashbanner/controller/admin/sys/config.go new file mode 100644 index 0000000..8d72a27 --- /dev/null +++ b/server/addons/flashbanner/controller/admin/sys/config.go @@ -0,0 +1,33 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/flashbanner/api/admin/config" + "hotgo/addons/flashbanner/service" +) + +var ( + Config = cConfig{} +) + +type cConfig struct{} + +// GetConfig 获取指定分组的配置 +func (c *cConfig) GetConfig(ctx context.Context, req *config.GetReq) (res *config.GetRes, err error) { + data, err := service.SysConfig().GetConfigByGroup(ctx, &req.GetConfigInp) + + res = new(config.GetRes) + res.GetConfigModel = data + return +} + +// UpdateConfig 更新指定分组的配置 +func (c *cConfig) UpdateConfig(ctx context.Context, req *config.UpdateReq) (res *config.UpdateRes, err error) { + err = service.SysConfig().UpdateConfigByGroup(ctx, &req.UpdateConfigInp) + return +} diff --git a/server/addons/flashbanner/controller/admin/sys/index.go b/server/addons/flashbanner/controller/admin/sys/index.go new file mode 100644 index 0000000..74fa221 --- /dev/null +++ b/server/addons/flashbanner/controller/admin/sys/index.go @@ -0,0 +1,30 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/flashbanner/api/admin/index" + "hotgo/addons/flashbanner/service" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// Test 测试 +func (c *cIndex) Test(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + res = new(index.TestRes) + res.IndexTestModel = data + return +} diff --git a/server/addons/flashbanner/controller/api/banner/banner.go b/server/addons/flashbanner/controller/api/banner/banner.go new file mode 100644 index 0000000..bdbea11 --- /dev/null +++ b/server/addons/flashbanner/controller/api/banner/banner.go @@ -0,0 +1,41 @@ +// Package banner +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package banner + +import ( + "context" + "hotgo/addons/flashbanner/api/admin/banner" + "hotgo/addons/flashbanner/service" +) + +var ( + BannerIndex = cBanner{} +) + +type cBanner struct{} + +// List 获取轮播图列表 +func (c *cBanner) List(ctx context.Context, req *banner.ListReq) (res *banner.ListRes, err error) { + list, totalCount, err := service.SysBanner().List(ctx, &req.BannerListInp) + if err != nil { + return nil, err + } + res = &banner.ListRes{ + List: list, + } + res.PageRes.Pack(&req.BannerListInp, totalCount) + return res, nil +} + +// View 获取指定轮播图信息 +func (c *cBanner) View(ctx context.Context, req *banner.ViewReq) (res *banner.ViewRes, err error) { + model, err := service.SysBanner().View(ctx, &req.BannerViewInp) + if err != nil { + return nil, err + } + res = &banner.ViewRes{model} + return res, nil +} diff --git a/server/addons/flashbanner/controller/api/index.go b/server/addons/flashbanner/controller/api/index.go new file mode 100644 index 0000000..3e03d76 --- /dev/null +++ b/server/addons/flashbanner/controller/api/index.go @@ -0,0 +1,31 @@ +// Package api +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package api + +import ( + "context" + "hotgo/addons/flashbanner/api/api/index" + "hotgo/addons/flashbanner/service" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// Test 测试 +func (c *cIndex) Test(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + res = new(index.TestRes) + res.IndexTestModel = data + return +} + diff --git a/server/addons/flashbanner/controller/home/index.go b/server/addons/flashbanner/controller/home/index.go new file mode 100644 index 0000000..a615998 --- /dev/null +++ b/server/addons/flashbanner/controller/home/index.go @@ -0,0 +1,34 @@ +// Package home +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package home + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/flashbanner/api/home/index" + "hotgo/addons/flashbanner/service" + "hotgo/internal/model" + isc "hotgo/internal/service" +) + +// Index 基础 +var Index = cIndex{} + +type cIndex struct{} + +func (a *cIndex) Index(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + isc.View().RenderTpl(ctx, "home/index.html", model.View{Data: g.Map{ + "name": data.Name, + "module": data.Module, + "time": data.Time, + }}) + return +} diff --git a/server/addons/flashbanner/controller/websocket/index.go b/server/addons/flashbanner/controller/websocket/index.go new file mode 100644 index 0000000..117b8b0 --- /dev/null +++ b/server/addons/flashbanner/controller/websocket/index.go @@ -0,0 +1,30 @@ +// Package websocket +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package websocket + +import ( + "context" + "hotgo/addons/flashbanner/api/websocket/index" + "hotgo/addons/flashbanner/service" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// Test 测试 +func (c *cIndex) Test(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + res = new(index.TestRes) + res.IndexTestModel = data + return +} diff --git a/server/addons/flashbanner/crons/crons.go b/server/addons/flashbanner/crons/crons.go new file mode 100644 index 0000000..fd6a45f --- /dev/null +++ b/server/addons/flashbanner/crons/crons.go @@ -0,0 +1,9 @@ +// Package crons +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package crons + +// 定时任务. +// 插件中的定时任务可以统一在这里注册和处理 diff --git a/server/addons/flashbanner/dao/banner.go b/server/addons/flashbanner/dao/banner.go new file mode 100644 index 0000000..82e8627 --- /dev/null +++ b/server/addons/flashbanner/dao/banner.go @@ -0,0 +1,12 @@ +// Package dao +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package dao + +import "hotgo/addons/flashbanner/dao/internal" + +var ( + Banner = internal.NewBannerDao() +) \ No newline at end of file diff --git a/server/addons/flashbanner/dao/internal/banner.go b/server/addons/flashbanner/dao/internal/banner.go new file mode 100644 index 0000000..41250f1 --- /dev/null +++ b/server/addons/flashbanner/dao/internal/banner.go @@ -0,0 +1,89 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// BannerDao is the data access object for table hg_banner. +type BannerDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns BannerColumns // columns contains all the column names of Table for convenient usage. +} + +// BannerColumns defines and stores column names for table hg_banner. +type BannerColumns struct { + Id string // + Name string // 轮播图名称 + Cover string // 图片URL + Link string // 跳转链接,小程序内用相对地址 + Type string // 类型默认不传 + Status string // 1可用 + Sort string // 排序,数字越大越靠前 + CreatedAt string // + UpdatedAt string // +} + +// bannerColumns holds the columns for table hg_banner. +var bannerColumns = BannerColumns{ + Id: "id", + Name: "name", + Cover: "cover", + Link: "link", + Type: "type", + Status: "status", + Sort: "sort", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewBannerDao creates and returns a new DAO object for table data access. +func NewBannerDao() *BannerDao { + return &BannerDao{ + group: "default", + table: "hg_banner", + columns: bannerColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *BannerDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *BannerDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *BannerDao) Columns() BannerColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *BannerDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *BannerDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *BannerDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/server/addons/flashbanner/global/global.go b/server/addons/flashbanner/global/global.go new file mode 100644 index 0000000..4dbc10a --- /dev/null +++ b/server/addons/flashbanner/global/global.go @@ -0,0 +1,12 @@ +// Package global +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package global + +import "hotgo/internal/library/addons" + +var ( + skeleton *addons.Skeleton // 插件架子 +) diff --git a/server/addons/flashbanner/global/init.go b/server/addons/flashbanner/global/init.go new file mode 100644 index 0000000..1cebca1 --- /dev/null +++ b/server/addons/flashbanner/global/init.go @@ -0,0 +1,22 @@ +// Package global +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package global + +import ( + "context" + "hotgo/internal/library/addons" +) + +func Init(ctx context.Context, sk *addons.Skeleton) { + skeleton = sk +} + +func GetSkeleton() *addons.Skeleton { + if skeleton == nil { + panic("addon skeleton not initialized.") + } + return skeleton +} diff --git a/server/addons/flashbanner/logic/.gitkeep b/server/addons/flashbanner/logic/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/addons/flashbanner/logic/logic.go b/server/addons/flashbanner/logic/logic.go new file mode 100644 index 0000000..bd63903 --- /dev/null +++ b/server/addons/flashbanner/logic/logic.go @@ -0,0 +1,9 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package logic + +import ( + _ "hotgo/addons/flashbanner/logic/sys" +) diff --git a/server/addons/flashbanner/logic/sys/banner.go b/server/addons/flashbanner/logic/sys/banner.go new file mode 100644 index 0000000..d2d1f66 --- /dev/null +++ b/server/addons/flashbanner/logic/sys/banner.go @@ -0,0 +1,173 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/flashbanner/dao" + "hotgo/addons/flashbanner/model/entity" + "hotgo/addons/flashbanner/model/input/sysin" + "hotgo/addons/flashbanner/service" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +type sSysBanner struct{} + +func NewSysBanner() *sSysBanner { + return &sSysBanner{} +} + +func init() { + service.RegisterSysBanner(NewSysBanner()) +} + +// GetMaxSort 获取最大排序值 +func (s *sSysBanner) GetMaxSort(ctx context.Context) (maxSort int, err error) { + var result struct { + MaxSort int `json:"maxSort"` + } + err = dao.Banner.Ctx(ctx).Fields("MAX(sort) as maxSort").Scan(&result) + if err != nil { + return 0, gerror.Wrap(err, "获取最大排序值失败") + } + return result.MaxSort, nil +} + +// Create 创建轮播图 +func (s *sSysBanner) Create(ctx context.Context, in *sysin.BannerCreateInp) (err error) { + // 如果没有设置排序值,自动设置为最大值+1 + if in.Sort == 0 { + maxSort, err := s.GetMaxSort(ctx) + if err != nil { + return err + } + in.Sort = maxSort + 1 + } + + _, err = dao.Banner.Ctx(ctx).Data(g.Map{ + dao.Banner.Columns().Name: in.Name, + dao.Banner.Columns().Cover: in.Cover, + dao.Banner.Columns().Link: in.Link, + dao.Banner.Columns().Type: in.Type, + dao.Banner.Columns().Status: 1, // 默认启用 + dao.Banner.Columns().Sort: in.Sort, + dao.Banner.Columns().CreatedAt: gtime.Now(), + dao.Banner.Columns().UpdatedAt: gtime.Now(), + }).Insert() + if err != nil { + err = gerror.Wrap(err, "创建轮播图失败") + return + } + return +} + +// Edit 修改/新增轮播图 +func (s *sSysBanner) Edit(ctx context.Context, in *sysin.BannerEditInp) (err error) { + if in.Id > 0 { + // 修改 + _, err = dao.Banner.Ctx(ctx).Where(dao.Banner.Columns().Id, in.Id).Data(g.Map{ + dao.Banner.Columns().Name: in.Name, + dao.Banner.Columns().Cover: in.Cover, + dao.Banner.Columns().Link: in.Link, + dao.Banner.Columns().Type: in.Type, + dao.Banner.Columns().Status: in.Status, + dao.Banner.Columns().Sort: in.Sort, + dao.Banner.Columns().UpdatedAt: gtime.Now(), + }).Update() + if err != nil { + err = gerror.Wrap(err, "修改轮播图失败") + return + } + } else { + // 新增 + _, err = dao.Banner.Ctx(ctx).Data(g.Map{ + dao.Banner.Columns().Name: in.Name, + dao.Banner.Columns().Cover: in.Cover, + dao.Banner.Columns().Link: in.Link, + dao.Banner.Columns().Type: in.Type, + dao.Banner.Columns().Status: in.Status, + dao.Banner.Columns().Sort: in.Sort, + dao.Banner.Columns().CreatedAt: gtime.Now(), + dao.Banner.Columns().UpdatedAt: gtime.Now(), + }).Insert() + if err != nil { + err = gerror.Wrap(err, "新增轮播图失败") + return + } + } + return +} + +// Delete 删除轮播图 +func (s *sSysBanner) Delete(ctx context.Context, in *sysin.BannerDeleteInp) (err error) { + _, err = dao.Banner.Ctx(ctx).Where(dao.Banner.Columns().Id, in.Id).Delete() + if err != nil { + err = gerror.Wrap(err, "删除轮播图失败") + return + } + return +} + +// View 获取指定轮播图信息 +func (s *sSysBanner) View(ctx context.Context, in *sysin.BannerViewInp) (res *sysin.BannerViewModel, err error) { + var banner entity.Banner + err = dao.Banner.Ctx(ctx).Where(dao.Banner.Columns().Id, in.Id).Scan(&banner) + if err != nil { + err = gerror.Wrap(err, "获取轮播图信息失败") + return + } + if banner.Id == 0 { + err = gerror.New("轮播图不存在") + return + } + res = &sysin.BannerViewModel{Banner: banner} + return +} + +// List 获取轮播图列表 +func (s *sSysBanner) List(ctx context.Context, in *sysin.BannerListInp) (list []*sysin.BannerListModel, totalCount int, err error) { + m := dao.Banner.Ctx(ctx) + + // 条件查询 + if in.Name != "" { + m = m.WhereLike(dao.Banner.Columns().Name, "%"+in.Name+"%") + } + if in.Type > 0 { + m = m.Where(dao.Banner.Columns().Type, in.Type) + } + + var banners []*entity.Banner + if in.Page > 0 && in.PerPage > 0 { + err = m.Page(in.Page, in.PerPage).OrderDesc(dao.Banner.Columns().Sort).OrderDesc(dao.Banner.Columns().Id).ScanAndCount(&banners, &totalCount, false) + } else { + err = m.OrderDesc(dao.Banner.Columns().Sort).OrderDesc(dao.Banner.Columns().Id).ScanAndCount(&banners, &totalCount, false) + } + if err != nil { + err = gerror.Wrap(err, "获取轮播图列表失败") + return + } + + list = make([]*sysin.BannerListModel, len(banners)) + for i, banner := range banners { + list[i] = &sysin.BannerListModel{Banner: *banner} + } + return +} + +// Status 更新轮播图状态 +func (s *sSysBanner) Status(ctx context.Context, in *sysin.BannerStatusInp) (err error) { + _, err = dao.Banner.Ctx(ctx).Where(dao.Banner.Columns().Id, in.Id).Data(g.Map{ + dao.Banner.Columns().Status: in.Status, + dao.Banner.Columns().UpdatedAt: gtime.Now(), + }).Update() + if err != nil { + err = gerror.Wrap(err, "更新轮播图状态失败") + return + } + return +} \ No newline at end of file diff --git a/server/addons/flashbanner/logic/sys/config.go b/server/addons/flashbanner/logic/sys/config.go new file mode 100644 index 0000000..958b35c --- /dev/null +++ b/server/addons/flashbanner/logic/sys/config.go @@ -0,0 +1,59 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "hotgo/addons/flashbanner/global" + "hotgo/addons/flashbanner/model" + "hotgo/addons/flashbanner/model/input/sysin" + "hotgo/addons/flashbanner/service" + isc "hotgo/internal/service" +) + +type sSysConfig struct{} + +func NewSysConfig() *sSysConfig { + return &sSysConfig{} +} + +func init() { + service.RegisterSysConfig(NewSysConfig()) +} + +// GetBasic 获取基础配置 +func (s *sSysConfig) GetBasic(ctx context.Context) (conf *model.BasicConfig, err error) { + var in sysin.GetConfigInp + in.GetAddonsConfigInp.AddonName = global.GetSkeleton().Name + in.GetAddonsConfigInp.Group = "basic" + models, err := isc.SysAddonsConfig().GetConfigByGroup(ctx, &in.GetAddonsConfigInp) + if err != nil { + return + } + + err = gconv.Struct(models.List, &conf) + return +} + +// GetConfigByGroup 获取指定分组配置 +func (s *sSysConfig) GetConfigByGroup(ctx context.Context, in *sysin.GetConfigInp) (res *sysin.GetConfigModel, err error) { + in.GetAddonsConfigInp.AddonName = global.GetSkeleton().Name + models, err := isc.SysAddonsConfig().GetConfigByGroup(ctx, &in.GetAddonsConfigInp) + if err != nil { + return + } + + res = new(sysin.GetConfigModel) + res.List = models.List + return +} + +// UpdateConfigByGroup 更新指定分组的配置 +func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in *sysin.UpdateConfigInp) error { + in.UpdateAddonsConfigInp.AddonName = global.GetSkeleton().Name + return isc.SysAddonsConfig().UpdateConfigByGroup(ctx, &in.UpdateAddonsConfigInp) +} diff --git a/server/addons/flashbanner/logic/sys/index.go b/server/addons/flashbanner/logic/sys/index.go new file mode 100644 index 0000000..7b7878d --- /dev/null +++ b/server/addons/flashbanner/logic/sys/index.go @@ -0,0 +1,35 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/addons/flashbanner/global" + "hotgo/addons/flashbanner/model/input/sysin" + "hotgo/addons/flashbanner/service" + "hotgo/internal/library/contexts" +) + +type sSysIndex struct{} + +func NewSysIndex() *sSysIndex { + return &sSysIndex{} +} + +func init() { + service.RegisterSysIndex(NewSysIndex()) +} + +// Test 测试 +func (s *sSysIndex) Test(ctx context.Context, in *sysin.IndexTestInp) (res *sysin.IndexTestModel, err error) { + res = new(sysin.IndexTestModel) + res.Name = in.Name + res.Module = fmt.Sprintf("当前插件模块是:%s,当前应用模块是:%s", global.GetSkeleton().Name, contexts.Get(ctx).Module) + res.Time = gtime.Now() + return +} diff --git a/server/addons/flashbanner/main.go b/server/addons/flashbanner/main.go new file mode 100644 index 0000000..b33799a --- /dev/null +++ b/server/addons/flashbanner/main.go @@ -0,0 +1,176 @@ +// Package flashbanner +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package flashbanner + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gctx" + _ "hotgo/addons/flashbanner/crons" + "hotgo/addons/flashbanner/global" + _ "hotgo/addons/flashbanner/logic" + _ "hotgo/addons/flashbanner/queues" + "hotgo/addons/flashbanner/router" + "hotgo/addons/migrations" + "hotgo/internal/library/addons" + "hotgo/internal/service" + "sync" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + + +) + +type module struct { + skeleton *addons.Skeleton + ctx context.Context + sync.Mutex +} + +func init() { + newModule() +} + +func newModule() { + m := &module{ + skeleton: &addons.Skeleton{ + Label: `轮播图管理`, + Name: `flashbanner`, + Group: 6, + Logo: "", + Brief: ``, + Description: ``, + Author: ``, + Version: `v1.0.0`, // 当该版本号高于已安装的版本号时,会提示可以更新 + }, + ctx: gctx.New(), + } + addons.RegisterModule(m) +} + +// Start 启动模块 +func (m *module) Start(option *addons.Option) (err error) { + // 初始化模块 + global.Init(m.ctx, m.skeleton) + + // 注册插件路由 + option.Server.Group("/", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Addon) + router.Admin(m.ctx, group) + router.Api(m.ctx, group) + router.Home(m.ctx, group) + router.WebSocket(m.ctx, group) + }) + return +} + +// Stop 停止模块 +func (m *module) Stop() (err error) { + return +} + +// Ctx 上下文 +func (m *module) Ctx() context.Context { + return m.ctx +} + +// GetSkeleton 获取模块 +func (m *module) GetSkeleton() *addons.Skeleton { + return m.skeleton +} + +// Install 安装模块 +func (m *module) Install(ctx context.Context) (err error) { + // 执行数据库安装文件 + // 获取当前目录 + sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/flashbanner/install.sql" + g.Log().Debug(ctx, "安装模块", m.skeleton.Label, "路径", sqlPath) + result, err := migrations.DoSqlContent(ctx, sqlPath) + if err != nil { + g.Log().Error(ctx, "安装模块", m.skeleton.Label, "失败", err) + return + } + g.Log().Debug(ctx, "安装模块", m.skeleton.Label, "成功", result) + // 复制web目录下的文件到管理后台对应位置 + // 插件的前端配置文件位于插件目录下的web子目录 + sourceWebPath := gfile.Pwd() + gfile.Separator + "addons/" + m.skeleton.Name + "/web/src/views/addons/" + m.skeleton.Name + targetWebPath := "../web/src/views/addons/" + m.skeleton.Name + g.Log().Debug(ctx, "复制前端配置文件", "源路径:", sourceWebPath, "目标路径:", targetWebPath) + + // 检查源路径是否存在 + if gfile.Exists(sourceWebPath) { + err = gfile.CopyDir(sourceWebPath, targetWebPath) + if err != nil { + g.Log().Error(ctx, "复制前端配置文件失败:", err) + } else { + g.Log().Debug(ctx, "复制前端配置文件成功") + } + } else { + g.Log().Warning(ctx, "前端配置文件源路径不存在:", sourceWebPath) + } + + // 复制API文件 + sourceApiPath := gfile.Pwd() + gfile.Separator + "addons/" + m.skeleton.Name + "/web/src/api/addons/" + m.skeleton.Name + targetApiPath := "../web/src/api/addons/" + m.skeleton.Name + g.Log().Debug(ctx, "复制API文件", "源路径:", sourceApiPath, "目标路径:", targetApiPath) + if gfile.Exists(sourceApiPath) { + err = gfile.CopyDir(sourceApiPath, targetApiPath) + if err != nil { + g.Log().Error(ctx, "复制API文件失败:", err) + } else { + g.Log().Debug(ctx, "复制API文件成功") + } + } else { + g.Log().Warning(ctx, "API文件源路径不存在:", sourceApiPath) + } + return +} + +// Upgrade 更新模块 +func (m *module) Upgrade(ctx context.Context) (err error) { + // ... + return +} + +// UnInstall 卸载模块 +func (m *module) UnInstall(ctx context.Context) (err error) { + // ... + // 移除数据库安装文件 + sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/flashbanner/uninstall.sql" + g.Log().Debug(ctx, "卸载模块", m.skeleton.Label, "路径", sqlPath) + result, err := migrations.DoSqlContent(ctx, sqlPath) + if err != nil { + g.Log().Error(ctx, "卸载模块", m.skeleton.Label, "失败", err) + return + } + g.Log().Debug(ctx, "卸载模块", m.skeleton.Label, "成功", result) + // 删除前端文件 + targetWebPath := "../web/src/views/addons/" + m.skeleton.Name + targetApiPath := "../web/src/api/addons/" + m.skeleton.Name + + // 删除配置页面文件 + if gfile.Exists(targetWebPath) { + err = gfile.Remove(targetWebPath) + if err != nil { + g.Log().Warning(ctx, "删除前端配置文件失败:", err) + } else { + g.Log().Debug(ctx, "删除前端配置文件成功") + } + } + + // 删除API文件 + if gfile.Exists(targetApiPath) { + err = gfile.Remove(targetApiPath) + if err != nil { + g.Log().Warning(ctx, "删除API文件失败:", err) + } else { + g.Log().Debug(ctx, "删除API文件成功") + } + } + + return +} diff --git a/server/addons/flashbanner/model/config.go b/server/addons/flashbanner/model/config.go new file mode 100644 index 0000000..7ad8505 --- /dev/null +++ b/server/addons/flashbanner/model/config.go @@ -0,0 +1,11 @@ +// Package model +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package model + +// BasicConfig 基础配置 +type BasicConfig struct { + Test string `json:"basicTest"` +} diff --git a/server/addons/flashbanner/model/entity/banner.go b/server/addons/flashbanner/model/entity/banner.go new file mode 100644 index 0000000..bc5689d --- /dev/null +++ b/server/addons/flashbanner/model/entity/banner.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Banner is the golang structure for table banner. +type Banner struct { + Id int `json:"id" orm:"id" description:""` + Name string `json:"name" orm:"name" description:"轮播图名称"` + Cover string `json:"cover" orm:"cover" description:"图片URL"` + Link string `json:"link" orm:"link" description:"跳转链接,小程序内用相对地址"` + Type int `json:"type" orm:"type" description:"类型默认不传"` + Status uint `json:"status" orm:"status" description:"1可用"` + Sort int `json:"sort" orm:"sort" description:"排序,数字越大越靠前"` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/addons/flashbanner/model/input/sysin/banner.go b/server/addons/flashbanner/model/input/sysin/banner.go new file mode 100644 index 0000000..127f60e --- /dev/null +++ b/server/addons/flashbanner/model/input/sysin/banner.go @@ -0,0 +1,98 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sysin + +import ( + "context" + "hotgo/addons/flashbanner/model/entity" + "hotgo/internal/model/input/form" + "github.com/gogf/gf/v2/errors/gerror" +) + +// BannerCreateInp 创建轮播图 +type BannerCreateInp struct { + Name string `json:"name" v:"required#轮播图名称不能为空" dc:"轮播图名称"` + Cover string `json:"cover" v:"required#轮播图封面不能为空" dc:"轮播图封面"` + Link string `json:"link" dc:"轮播图链接"` + Type int `json:"type" dc:"轮播图类型"` + Sort int `json:"sort" dc:"排序,数字越大越靠前"` +} + +func (in *BannerCreateInp) Filter(ctx context.Context) (err error) { + return +} + +type BannerCreateModel struct{} + +// BannerEditInp 修改/新增轮播图 +type BannerEditInp struct { + entity.Banner +} + +func (in *BannerEditInp) Filter(ctx context.Context) (err error) { + if in.Name == "" { + err = gerror.New("轮播图名称不能为空") + return + } + if in.Cover == "" { + err = gerror.New("轮播图封面不能为空") + return + } + return +} + +type BannerEditModel struct{} + +// BannerDeleteInp 删除轮播图 +type BannerDeleteInp struct { + Id interface{} `json:"id" v:"required#轮播图ID不能为空" dc:"轮播图ID"` +} + +func (in *BannerDeleteInp) Filter(ctx context.Context) (err error) { + return +} + +type BannerDeleteModel struct{} + +// BannerViewInp 获取指定轮播图信息 +type BannerViewInp struct { + Id int64 `json:"id" v:"required#轮播图ID不能为空" dc:"轮播图ID"` +} + +func (in *BannerViewInp) Filter(ctx context.Context) (err error) { + return +} + +type BannerViewModel struct { + entity.Banner +} + +// BannerListInp 获取轮播图列表 +type BannerListInp struct { + form.PageReq + Name string `json:"name" dc:"轮播图名称"` + Type int `json:"type" dc:"轮播图类型"` +} + +func (in *BannerListInp) Filter(ctx context.Context) (err error) { + return +} + +type BannerListModel struct { + entity.Banner +} + +// BannerStatusInp 更新轮播图状态 +type BannerStatusInp struct { + Id int64 `json:"id" v:"required#轮播图ID不能为空" dc:"轮播图ID"` + Status int `json:"status" v:"required#状态不能为空" dc:"状态"` +} + +func (in *BannerStatusInp) Filter(ctx context.Context) (err error) { + return +} + +type BannerStatusModel struct{} \ No newline at end of file diff --git a/server/addons/flashbanner/model/input/sysin/config.go b/server/addons/flashbanner/model/input/sysin/config.go new file mode 100644 index 0000000..de3b02c --- /dev/null +++ b/server/addons/flashbanner/model/input/sysin/config.go @@ -0,0 +1,24 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sysin + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/sysin" +) + +// UpdateConfigInp 更新指定配置 +type UpdateConfigInp struct { + sysin.UpdateAddonsConfigInp +} + +type GetConfigInp struct { + sysin.GetAddonsConfigInp +} + +type GetConfigModel struct { + List g.Map `json:"list"` +} diff --git a/server/addons/flashbanner/model/input/sysin/index.go b/server/addons/flashbanner/model/input/sysin/index.go new file mode 100644 index 0000000..01d3bdc --- /dev/null +++ b/server/addons/flashbanner/model/input/sysin/index.go @@ -0,0 +1,27 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// +package sysin + +import ( + "context" + "github.com/gogf/gf/v2/os/gtime" +) + +// IndexTestInp 测试 +type IndexTestInp struct { + Name string `json:"name" d:"HotGo" dc:"名称"` +} + +func (in *IndexTestInp) Filter(ctx context.Context) (err error) { + return +} + +type IndexTestModel struct { + Name string `json:"name" dc:"名称"` + Module string `json:"module" dc:"当前插件模块"` + Time *gtime.Time `json:"time" dc:"当前时间"` +} diff --git a/server/addons/flashbanner/queues/queues.go b/server/addons/flashbanner/queues/queues.go new file mode 100644 index 0000000..4d0559c --- /dev/null +++ b/server/addons/flashbanner/queues/queues.go @@ -0,0 +1,9 @@ +// Package queues +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package queues + +// 消息队列. +// 插件中的消息队列消费者可以统一在这里注册和处理 diff --git a/server/addons/flashbanner/resource/public/.gitkeep b/server/addons/flashbanner/resource/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/addons/flashbanner/resource/public/default b/server/addons/flashbanner/resource/public/default new file mode 100644 index 0000000..e3ad56a --- /dev/null +++ b/server/addons/flashbanner/resource/public/default @@ -0,0 +1 @@ +Hello!这是创建插件 [轮播图管理] 时默认生成的一个静态目录文件,用于测试,当你看到这个提示时,说明已经联调成功啦! diff --git a/server/addons/flashbanner/resource/template/home/index.html b/server/addons/flashbanner/resource/template/home/index.html new file mode 100644 index 0000000..3502f4a --- /dev/null +++ b/server/addons/flashbanner/resource/template/home/index.html @@ -0,0 +1,30 @@ + + + + + + + + + @{.Title} + + + + +
+

Hello,@{.Data.name}!!

+

@{.Data.module}

+

服务器时间:@{.Data.time}

+
+ + + \ No newline at end of file diff --git a/server/addons/flashbanner/router/admin.go b/server/addons/flashbanner/router/admin.go new file mode 100644 index 0000000..030c212 --- /dev/null +++ b/server/addons/flashbanner/router/admin.go @@ -0,0 +1,36 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 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/net/ghttp" + "hotgo/addons/flashbanner/controller/admin/sys" + "hotgo/addons/flashbanner/controller/admin/banner" + "hotgo/addons/flashbanner/global" + "hotgo/addons/flashbanner/router/genrouter" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" +) + +// Admin 后台路由 +func Admin(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + sys.Index, + ) + group.Middleware(service.Middleware().AdminAuth) + group.Bind( + sys.Config, + banner.Banner, + ) + }) + + // 注册生成路由 + genrouter.Register(ctx, group) +} diff --git a/server/addons/flashbanner/router/api.go b/server/addons/flashbanner/router/api.go new file mode 100644 index 0000000..c033649 --- /dev/null +++ b/server/addons/flashbanner/router/api.go @@ -0,0 +1,32 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 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/net/ghttp" + "hotgo/addons/flashbanner/controller/api/banner" + "hotgo/addons/flashbanner/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" +) + +// Api 前台路由 +func Api(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppApi, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + // 无需验证的路由 + banner.BannerIndex, + ) + group.Middleware(service.Middleware().ApiAuth) + group.Bind( + // 需要验证的路由 + // ... + ) + }) +} diff --git a/server/addons/flashbanner/router/genrouter/init.go b/server/addons/flashbanner/router/genrouter/init.go new file mode 100644 index 0000000..2441e7e --- /dev/null +++ b/server/addons/flashbanner/router/genrouter/init.go @@ -0,0 +1,34 @@ +// Package genrouter +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package genrouter + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/flashbanner/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" +) + +var ( + NoLoginRouter []interface{} // 无需登录 + LoginRequiredRouter []interface{} // 需要登录 +) + +// Register 注册通过代码生成的后台路由 +func Register(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + if len(NoLoginRouter) > 0 { + group.Bind(NoLoginRouter...) + } + group.Middleware(service.Middleware().AdminAuth) + if len(LoginRequiredRouter) > 0 { + group.Bind(LoginRequiredRouter...) + } + }) +} diff --git a/server/addons/flashbanner/router/home.go b/server/addons/flashbanner/router/home.go new file mode 100644 index 0000000..fea7312 --- /dev/null +++ b/server/addons/flashbanner/router/home.go @@ -0,0 +1,25 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 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/net/ghttp" + "hotgo/addons/flashbanner/controller/home" + "hotgo/addons/flashbanner/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" +) + +// Home 前台页面路由 +func Home(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppHome, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + home.Index, + ) + }) +} diff --git a/server/addons/flashbanner/router/websocket.go b/server/addons/flashbanner/router/websocket.go new file mode 100644 index 0000000..7ebfbd0 --- /dev/null +++ b/server/addons/flashbanner/router/websocket.go @@ -0,0 +1,39 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 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/net/ghttp" + "hotgo/addons/flashbanner/controller/websocket" + "hotgo/addons/flashbanner/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" + ws "hotgo/internal/websocket" +) + +// WebSocket ws路由配置 +func WebSocket(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppWebSocket, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + // 无需验证的路由 + websocket.Index, + ) + // ws连接中间件 + group.Middleware(service.Middleware().WebSocketAuth) + group.Bind( + // 需要验证的路由 + // .. + ) + }) + + // 注册消息路由 + ws.RegisterMsg(ws.EventHandlers{ + // ... + }) +} diff --git a/server/addons/flashbanner/service/.gitkeep b/server/addons/flashbanner/service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/addons/flashbanner/service/sys.go b/server/addons/flashbanner/service/sys.go new file mode 100644 index 0000000..9a7f5b1 --- /dev/null +++ b/server/addons/flashbanner/service/sys.go @@ -0,0 +1,71 @@ +// ================================================================================ +// 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/addons/flashbanner/model" + "hotgo/addons/flashbanner/model/input/sysin" +) + +type ( + ISysConfig interface { + GetBasic(ctx context.Context) (conf *model.BasicConfig, err error) + GetConfigByGroup(ctx context.Context, in *sysin.GetConfigInp) (res *sysin.GetConfigModel, err error) + UpdateConfigByGroup(ctx context.Context, in *sysin.UpdateConfigInp) error + } + ISysIndex interface { + Test(ctx context.Context, in *sysin.IndexTestInp) (res *sysin.IndexTestModel, err error) + } + ISysBanner interface { + Create(ctx context.Context, in *sysin.BannerCreateInp) (err error) + Edit(ctx context.Context, in *sysin.BannerEditInp) (err error) + Delete(ctx context.Context, in *sysin.BannerDeleteInp) (err error) + View(ctx context.Context, in *sysin.BannerViewInp) (res *sysin.BannerViewModel, err error) + List(ctx context.Context, in *sysin.BannerListInp) (list []*sysin.BannerListModel, totalCount int, err error) + Status(ctx context.Context, in *sysin.BannerStatusInp) (err error) + GetMaxSort(ctx context.Context) (maxSort int, err error) + } +) + +var ( + localSysConfig ISysConfig + localSysIndex ISysIndex + localSysBanner ISysBanner +) + +func SysConfig() ISysConfig { + if localSysConfig == nil { + panic("implement not found for interface ISysConfig, forgot register?") + } + return localSysConfig +} + +func RegisterSysConfig(i ISysConfig) { + localSysConfig = i +} + +func SysIndex() ISysIndex { + if localSysIndex == nil { + panic("implement not found for interface ISysIndex, forgot register?") + } + return localSysIndex +} + +func RegisterSysIndex(i ISysIndex) { + localSysIndex = i +} + +func SysBanner() ISysBanner { + if localSysBanner == nil { + panic("implement not found for interface ISysBanner, forgot register?") + } + return localSysBanner +} + +func RegisterSysBanner(i ISysBanner) { + localSysBanner = i +} diff --git a/server/addons/flashbanner/web/src/api/addons/flashbanner/config/index.ts b/server/addons/flashbanner/web/src/api/addons/flashbanner/config/index.ts new file mode 100644 index 0000000..f04d3fd --- /dev/null +++ b/server/addons/flashbanner/web/src/api/addons/flashbanner/config/index.ts @@ -0,0 +1,17 @@ +import { http } from '@/utils/http/axios'; + +export function getConfig(params) { + return http.request({ + url: '/flashbanner/config/get', + method: 'get', + params, + }); +} + +export function updateConfig(params) { + return http.request({ + url: '/flashbanner/config/update', + method: 'post', + params, + }); +} diff --git a/server/addons/flashbanner/web/src/api/addons/flashbanner/index.ts b/server/addons/flashbanner/web/src/api/addons/flashbanner/index.ts new file mode 100644 index 0000000..9e76033 --- /dev/null +++ b/server/addons/flashbanner/web/src/api/addons/flashbanner/index.ts @@ -0,0 +1,33 @@ +import { http } from '@/utils/http/axios'; + +export function List(params) { + return http.request({ + url: '/flashbanner/banner/list', + method: 'GET', + params, + }); +} + +export function Add(params) { + return http.request({ + url: '/flashbanner/banner/create', + method: 'POST', + params, + }); +} + +export function Edit(params) { + return http.request({ + url: '/flashbanner/banner/edit', + method: 'POST', + params, + }); +} + +export function Delete(params) { + return http.request({ + url: '/flashbanner/banner/delete', + method: 'POST', + params, + }); +} \ No newline at end of file diff --git a/server/addons/flashbanner/web/src/views/addons/flashbanner/components/Edit.vue b/server/addons/flashbanner/web/src/views/addons/flashbanner/components/Edit.vue new file mode 100644 index 0000000..de0e2a9 --- /dev/null +++ b/server/addons/flashbanner/web/src/views/addons/flashbanner/components/Edit.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/server/addons/flashbanner/web/src/views/addons/flashbanner/components/model.ts b/server/addons/flashbanner/web/src/views/addons/flashbanner/components/model.ts new file mode 100644 index 0000000..441cb19 --- /dev/null +++ b/server/addons/flashbanner/web/src/views/addons/flashbanner/components/model.ts @@ -0,0 +1,83 @@ +import { h, render } from 'vue'; +import { FormSchema, useForm } from '@/components/Form'; +import { NImage } from 'naive-ui'; +import { fallbackSrc } from '@/utils/hotgo'; + +// **********查询表单******** +const detailSchemas: FormSchema[] = [ + { + field: 'name', + component: 'NInput', + label: '图片名称', + defaultValue: null, + componentProps: { + placeholder: '请输入图片名称', + }, + }, +]; +export const [register, {}] = useForm({ + gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' }, + labelWidth: 80, + schemas: detailSchemas, +}); + +// *********表格********** +export const defaultColumns = [ + { + title: 'ID', + key: 'id', + width: 100, + }, + { + title: '图片名称', + key: 'name', + }, + { + title: '图片', + key: 'cover', + render(row) { + if (row.cover !== '') { + return h(NImage, { + width: 40, + height: 40, + src: row.cover, + fallbackSrc: fallbackSrc(), + style: { + width: '40px', + height: '40px', + 'max-width': '100%', + 'max-height': '100%', + }, + }); + } else { + return '暂无图片' + } + }, + }, + { + title: '链接地址', + key: 'link', + render(row) { + return h('a', { href: row.link, target: '_blank' }, row.link); + } + }, + { + title: '创建时间', + key: 'createdAt', + width: 180, + }, +]; + +// *********编辑表单规则*********** +export const rules = { + name: { + required: true, + trigger: ['blur', 'input'], + message: '请输入图片名称', + }, + cover: { + required: true, + trigger: ['blur', 'input'], + message: '请上传图片', + }, +}; \ No newline at end of file diff --git a/server/addons/flashbanner/web/src/views/addons/flashbanner/config/BasicSetting.vue b/server/addons/flashbanner/web/src/views/addons/flashbanner/config/BasicSetting.vue new file mode 100644 index 0000000..18f5f96 --- /dev/null +++ b/server/addons/flashbanner/web/src/views/addons/flashbanner/config/BasicSetting.vue @@ -0,0 +1,74 @@ + + + diff --git a/server/addons/flashbanner/web/src/views/addons/flashbanner/config/system.vue b/server/addons/flashbanner/web/src/views/addons/flashbanner/config/system.vue new file mode 100644 index 0000000..863a69e --- /dev/null +++ b/server/addons/flashbanner/web/src/views/addons/flashbanner/config/system.vue @@ -0,0 +1,82 @@ + + + diff --git a/server/addons/flashbanner/web/src/views/addons/flashbanner/index.vue b/server/addons/flashbanner/web/src/views/addons/flashbanner/index.vue new file mode 100644 index 0000000..61e0804 --- /dev/null +++ b/server/addons/flashbanner/web/src/views/addons/flashbanner/index.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/server/addons/migrations/flashbanner/install.pg.sql b/server/addons/migrations/flashbanner/install.pg.sql new file mode 100644 index 0000000..f8871d6 --- /dev/null +++ b/server/addons/migrations/flashbanner/install.pg.sql @@ -0,0 +1,167 @@ +-- 删除表(如果存在) +DROP TABLE IF EXISTS hg_banner; + +-- 创建表 +CREATE TABLE hg_banner ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + cover VARCHAR(255) DEFAULT NULL, + link VARCHAR(255) DEFAULT NULL, + type INTEGER DEFAULT 0, + status SMALLINT DEFAULT 1, + sort INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT NULL, + updated_at TIMESTAMP DEFAULT NULL +); + +-- 添加表注释 +COMMENT ON TABLE hg_banner IS '轮播图表'; + +-- 添加列注释 +COMMENT ON COLUMN hg_banner.name IS '轮播图名称'; +COMMENT ON COLUMN hg_banner.cover IS '图片URL'; +COMMENT ON COLUMN hg_banner.link IS '跳转链接,小程序内用相对地址'; +COMMENT ON COLUMN hg_banner.type IS '类型默认不传'; +COMMENT ON COLUMN hg_banner.status IS '1可用,2不可用'; +COMMENT ON COLUMN hg_banner.sort IS '排序,数字越大越靠前'; + +-- 添加 updated_at 字段的更新触发器(模拟 MySQL 的 ON UPDATE CURRENT_TIMESTAMP) +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_update_updated_at + BEFORE UPDATE ON hg_banner + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +-- 添加菜单项 +-- 先查找或创建"内容管理"父菜单(如果不存在) +INSERT INTO hg_admin_menu (pid, level, tree, title, name, path, icon, type, redirect, permissions, permission_name, component, always_show, active_menu, is_root, is_frame, frame_src, keep_alive, hidden, affix, sort, remark, status, updated_at, created_at) +SELECT 0, 1, '', '内容管理', 'content', '/content', 'BookOutlined', 1, '/content', '', '', 'LAYOUT', 2, '', 1, 2, '', 2, 2, 2, 12, '内容管理模块', 1, NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name = 'content'); + +-- 获取内容管理菜单ID并添加轮播图管理菜单 +WITH content_parent AS ( + SELECT id FROM hg_admin_menu WHERE name = 'content' LIMIT 1 +), +inserted_menu AS ( + INSERT INTO hg_admin_menu (pid, level, tree, title, name, path, icon, type, redirect, permissions, permission_name, component, always_show, active_menu, is_root, is_frame, frame_src, keep_alive, hidden, affix, sort, remark, status, updated_at, created_at) + SELECT + cp.id, + 2, + 'tr_' || cp.id::text || ' ', + '轮播图管理', + 'flashbanner', + '/flashbanner', + '', + 2, + '', + '/flashbanner/banner/list', + '', + '/addons/flashbanner/index', + 2, + '', + 2, + 2, + '', + 1, + 2, + 2, + 10, + '轮播图管理模块', + 1, + NOW(), + NOW() + FROM content_parent cp + RETURNING id +) +-- 添加子菜单和按钮 +INSERT INTO hg_admin_menu (pid, level, tree, title, name, path, icon, type, redirect, permissions, permission_name, component, always_show, active_menu, is_root, is_frame, frame_src, keep_alive, hidden, affix, sort, remark, status, updated_at, created_at) +SELECT + im.id, + 3, + 'tr_' || (SELECT id FROM content_parent)::text || ' tr_' || im.id::text || ' ', + '新增轮播', + 'addbanner', + '', + '', + 3, + '', + '/flashbanner/banner/create', + '', + '', + 2, + '', + 2, + 2, + '', + 2, + 2, + 2, + 10, + '新增轮播图权限', + 1, + NOW(), + NOW() +FROM inserted_menu im +UNION ALL +SELECT + im.id, + 3, + 'tr_' || (SELECT id FROM content_parent)::text || ' tr_' || im.id::text || ' ', + '轮播编辑', + 'editbanner', + '', + '', + 3, + '', + '/flashbanner/banner/update', + '', + '', + 2, + '', + 2, + 2, + '', + 2, + 2, + 2, + 10, + '编辑轮播图权限', + 1, + NOW(), + NOW() +FROM inserted_menu im +UNION ALL +SELECT + im.id, + 3, + 'tr_' || (SELECT id FROM content_parent)::text || ' tr_' || im.id::text || ' ', + '删除轮播', + 'delbanner', + '', + '', + 3, + '', + '/flashbanner/banner/delete', + '', + '', + 2, + '', + 2, + 2, + '', + 2, + 2, + 2, + 10, + '删除轮播图权限', + 1, + NOW(), + NOW() +FROM inserted_menu im; \ No newline at end of file diff --git a/server/addons/migrations/flashbanner/install.sql b/server/addons/migrations/flashbanner/install.sql new file mode 100644 index 0000000..86ec221 --- /dev/null +++ b/server/addons/migrations/flashbanner/install.sql @@ -0,0 +1,33 @@ +DROP TABLE IF EXISTS `hg_banner`; +CREATE TABLE `hg_banner` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL COMMENT '轮播图名称', + `cover` varchar(255) DEFAULT NULL COMMENT '图片URL', + `link` varchar(255) DEFAULT NULL COMMENT '跳转链接,小程序内用相对地址', + `type` int(11) DEFAULT 0 COMMENT '类型默认不传', + `status` tinyint(1) DEFAULT 1 COMMENT '1可用,2不可用', + `sort` int(11) DEFAULT 0 COMMENT '排序,数字越大越靠前', + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='轮播图表'; + + +-- 添加菜单项 +-- 先查找或创建"内容管理"父菜单(如果不存在) +INSERT IGNORE INTO `hg_admin_menu`(`pid`, `level`, `tree`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `sort`, `remark`, `status`, `updated_at`, `created_at`) VALUES +(0, 1, '', '内容管理', 'content', '/content', 'BookOutlined', 1, '/content', '', '', 'LAYOUT', 2, '', 1, 2, '', 2, 2, 2, 12, '内容管理模块', 1, NOW(), NOW()); + +-- 获取内容管理菜单ID并添加轮播图管理菜单 +SET @content_parent_id = (SELECT id FROM `hg_admin_menu` WHERE `name` = 'content' LIMIT 1); + +INSERT INTO `hg_admin_menu`(`pid`, `level`, `tree`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `sort`, `remark`, `status`, `updated_at`, `created_at`) VALUES +(@content_parent_id, 2, CONCAT('tr_', @content_parent_id, ' '), '轮播图管理', 'flashbanner', '/flashbanner', '', 2, '', '/flashbanner/banner/list', '', '/addons/flashbanner/index', 2, '', 2, 2, '', 1, 2, 2, 10, '轮播图管理模块', 1, NOW(), NOW()); + +-- 添加子菜单和按钮 +SET @flashbanner_menu_id = LAST_INSERT_ID(); + +INSERT INTO `hg_admin_menu`(`pid`, `level`, `tree`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `sort`, `remark`, `status`, `updated_at`, `created_at`) VALUES +(@flashbanner_menu_id, 3, CONCAT('tr_', @content_parent_id, ' tr_', @flashbanner_menu_id, ' '), '新增轮播', 'addbanner', '', '', 3, '', '/flashbanner/banner/create', '', '', 2, '', 2, 2, '', 2, 2, 2, 10, '新增轮播图权限', 1, NOW(), NOW()), +(@flashbanner_menu_id, 3, CONCAT('tr_', @content_parent_id, ' tr_', @flashbanner_menu_id, ' '), '轮播编辑', 'editbanner', '', '', 3, '', '/flashbanner/banner/update', '', '', 2, '', 2, 2, '', 2, 2, 2, 10, '编辑轮播图权限', 1, NOW(), NOW()), +(@flashbanner_menu_id, 3, CONCAT('tr_', @content_parent_id, ' tr_', @flashbanner_menu_id, ' '), '删除轮播', 'delbanner', '', '', 3, '', '/flashbanner/banner/delete', '', '', 2, '', 2, 2, '', 2, 2, 2, 10, '删除轮播图权限', 1, NOW(), NOW()); \ No newline at end of file diff --git a/server/addons/migrations/flashbanner/uninstall.pg.sql b/server/addons/migrations/flashbanner/uninstall.pg.sql new file mode 100644 index 0000000..6101a82 --- /dev/null +++ b/server/addons/migrations/flashbanner/uninstall.pg.sql @@ -0,0 +1,9 @@ +-- 删除表 +DROP TABLE IF EXISTS hg_banner; + +-- 删除 flashbanner 相关菜单 +-- 先删除子菜单(权限按钮) +DELETE FROM hg_admin_menu WHERE name IN ('addbanner', 'editbanner', 'delbanner'); + +-- 删除主菜单 +DELETE FROM hg_admin_menu WHERE name = 'flashbanner'; \ No newline at end of file diff --git a/server/addons/migrations/flashbanner/uninstall.sql b/server/addons/migrations/flashbanner/uninstall.sql new file mode 100644 index 0000000..78d971a --- /dev/null +++ b/server/addons/migrations/flashbanner/uninstall.sql @@ -0,0 +1,9 @@ +-- 删除表 +DROP TABLE IF EXISTS `hg_banner`; + +-- 删除 flashbanner 相关菜单 +-- 先删除子菜单(权限按钮) +DELETE FROM `hg_admin_menu` WHERE `name` IN ('addbanner', 'editbanner', 'delbanner'); + +-- 删除主菜单 +DELETE FROM `hg_admin_menu` WHERE `name` = 'flashbanner'; \ No newline at end of file diff --git a/server/addons/migrations/readme.md b/server/addons/migrations/readme.md new file mode 100644 index 0000000..e56eeb7 --- /dev/null +++ b/server/addons/migrations/readme.md @@ -0,0 +1,2 @@ +# 为了在容器映射sql所以需要独立出来 +# 兼容数据库和前端文件的迁移 \ No newline at end of file diff --git a/server/addons/migrations/sqlDo.go b/server/addons/migrations/sqlDo.go new file mode 100644 index 0000000..04f80b9 --- /dev/null +++ b/server/addons/migrations/sqlDo.go @@ -0,0 +1,66 @@ +package migrations + +import ( + "context" + "io" + "os" + "strings" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/container/gvar" +) +func DoSqlContent(ctx context.Context, sqlPath string) (string, error) { + open, err := os.Open(sqlPath) + if err != nil { + return "fail", err + } + defer open.Close() + sqlContent, err := io.ReadAll(open) + if err != nil { + return "fail", err + } + + // 首先尝试整个执行 + _, err = g.DB().Exec(ctx, string(sqlContent)) + if err != nil { + g.Log().Error(ctx, "整个执行SQL失败,尝试分句执行:", err) + + // 整个执行失败,尝试按分号分割执行 + sqls := strings.Split(string(sqlContent), ";") + for _, sql := range sqls { + sql = strings.TrimSpace(sql) + if sql != "" { + _, err := g.DB().Exec(ctx, sql) + if err != nil { + g.Log().Error(ctx, "执行SQL失败:", err, sql) + return "fail", err + } + } + } + } + return "success", nil +} + +func GetDbLink(ctx context.Context) *gvar.Var { + link := g.Cfg().MustGet(ctx, "database.default") + //读写分离 + if !link.IsSlice() { + return g.Cfg().MustGet(ctx, "database.default.link") + } + for _, v := range link.Array() { + // 只获取主库 + val := v.(map[string]interface{}) + if val["role"] == "master" { + return gvar.New(val["link"]) + } + } + return gvar.New("database.default.0.link") +} + +func GetDbType(ctx context.Context) string { + var ( + link = GetDbLink(ctx) + ) + config := strings.SplitN(link.String(), ":", 2) + return config[0] +} \ No newline at end of file diff --git a/server/addons/modules/flashbanner.go b/server/addons/modules/flashbanner.go new file mode 100644 index 0000000..af8ef7d --- /dev/null +++ b/server/addons/modules/flashbanner.go @@ -0,0 +1,8 @@ +// Package modules +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package modules + +import _ "hotgo/addons/flashbanner" diff --git a/server/internal/library/addons/build.go b/server/internal/library/addons/build.go index 6fab466..fa95e0d 100644 --- a/server/internal/library/addons/build.go +++ b/server/internal/library/addons/build.go @@ -8,14 +8,15 @@ package addons import ( "context" "fmt" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/os/gfile" - "github.com/gogf/gf/v2/text/gstr" "hotgo/internal/consts" "hotgo/internal/model" "hotgo/utility/validate" "strconv" "strings" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/text/gstr" ) type BuildOption struct { @@ -27,12 +28,14 @@ type BuildOption struct { // Build 构建新插件 func Build(ctx context.Context, option *BuildOption) (err error) { var ( - resourcePath = GetResourcePath(ctx) - buildPath = "./" + consts.AddonsDir + "/" + option.Skeleton.Name - modulesPath = "./" + consts.AddonsDir + "/modules/" + option.Skeleton.Name + ".go" - webApiPath = gstr.Replace(option.Config.WebApiPath, "{$name}", option.Skeleton.Name) - webViewsPath = gstr.Replace(option.Config.WebViewsPath, "{$name}", option.Skeleton.Name) - replaces = map[string]string{ + resourcePath = GetResourcePath(ctx) + buildPath = "./" + consts.AddonsDir + "/" + option.Skeleton.Name + modulesPath = "./" + consts.AddonsDir + "/modules/" + option.Skeleton.Name + ".go" + webApiPath = "./" + consts.AddonsDir + "/" + option.Skeleton.Name + "/web/src/api/addons/" + option.Skeleton.Name + webViewsPath = "./" + consts.AddonsDir + "/" + option.Skeleton.Name + "/web/src/views/addons/" + option.Skeleton.Name + webApiPathBase = gstr.Replace(option.Config.WebApiPath, "{$name}", option.Skeleton.Name) + webViewsPathBase = gstr.Replace(option.Config.WebViewsPath, "{$name}", option.Skeleton.Name) + replaces = map[string]string{ "@{.label}": option.Skeleton.Label, "@{.name}": option.Skeleton.Name, "@{.group}": strconv.Itoa(option.Skeleton.Group), @@ -94,16 +97,36 @@ func Build(ctx context.Context, option *BuildOption) (err error) { if err = gfile.PutContents(webApiPath+"/config/index.ts", gstr.ReplaceByMap(webApiLayout, replaces)); err != nil { return } - - // web插件配置主页面 - if err = gfile.PutContents(webViewsPath+"/config/BasicSetting.vue", gstr.ReplaceByMap(webConfigBasicSetting, replaces)); err != nil { + if err = gfile.PutContents(webApiPathBase+"/config/index.ts", gstr.ReplaceByMap(webApiLayout, replaces)); err != nil { return } - // web插件基础配置页面 + // web插件配置主页面 - 插件 + if err = gfile.PutContents(webViewsPath+"/config/BasicSetting.vue", gstr.ReplaceByMap(webConfigBasicSetting, replaces)); err != nil { + return + } + // web插件基础配置页面 - 插件 if err = gfile.PutContents(webViewsPath+"/config/system.vue", gstr.ReplaceByMap(webConfigSystem, replaces)); err != nil { return } + // web插件配置主页面 + if err = gfile.PutContents(webViewsPathBase+"/config/BasicSetting.vue", gstr.ReplaceByMap(webConfigBasicSetting, replaces)); err != nil { + return + } + // web插件基础配置页面 + if err = gfile.PutContents(webViewsPathBase+"/config/system.vue", gstr.ReplaceByMap(webConfigSystem, replaces)); err != nil { + return + } + + // 创建迁移文件 + sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/" + option.Skeleton.Name + "/install.sql" + sqlPathUn := gfile.Pwd() + gfile.Separator + "addons/migrations/" + option.Skeleton.Name + "/uninstall.sql" + if err = gfile.PutContents(sqlPath, ""); err != nil { + return + } + if err = gfile.PutContents(sqlPathUn, ""); err != nil { + return + } // 创建静态目录 if validate.InSlice(option.Extend, consts.AddonsExtendResourcePublic) { diff --git a/server/resource/generate/default/addon/README.MD.template b/server/resource/generate/default/addon/README.MD.template index 6d9080b..ef42a17 100644 --- a/server/resource/generate/default/addon/README.MD.template +++ b/server/resource/generate/default/addon/README.MD.template @@ -37,3 +37,14 @@ import _ "hotgo/addons/@{.name}" gf gen service -s=addons/@{.name}/logic -d=addons/@{.name}/service ``` + +```shell +# 插件迁移 +cp .\internal\dao\internal\@{.name}* .\addons\@{.name}\dao\internal\ +cp .\internal\model\entity\@{.name}* .\addons\@{.name}\model\entity\ +``` + +### 插件开发 + - 直接在后台新建插件 + - 创建迁移脚本 + - 开发工具->代码生成:自动生成前后端模块 \ No newline at end of file diff --git a/server/resource/generate/default/addon/main.go.template b/server/resource/generate/default/addon/main.go.template index 3bffaa9..088b508 100644 --- a/server/resource/generate/default/addon/main.go.template +++ b/server/resource/generate/default/addon/main.go.template @@ -14,9 +14,15 @@ import ( _ "hotgo/addons/@{.name}/logic" _ "hotgo/addons/@{.name}/queues" "hotgo/addons/@{.name}/router" + "hotgo/addons/migrations" "hotgo/internal/library/addons" "hotgo/internal/service" "sync" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + + ) type module struct { @@ -77,9 +83,54 @@ func (m *module) GetSkeleton() *addons.Skeleton { return m.skeleton } + // Install 安装模块 func (m *module) Install(ctx context.Context) (err error) { - // ... + sqlExt := ".sql" + if migrations.GetDbType(ctx) == "pgsql" { + sqlExt = ".pg.sql" + } + // 执行数据库安装文件 + sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/@{.name}/uninstall"+sqlExt + result, err := migrations.DoSqlContent(ctx, sqlPath) + if err != nil { + g.Log().Error(ctx, "安装模块", m.skeleton.Label, "失败", err) + return + } + g.Log().Debug(ctx, "安装模块", m.skeleton.Label, "成功", result) + + // 复制web目录下的文件到管理后台对应位置 + // 插件的前端配置文件位于插件目录下的web子目录 + sourceWebPath := gfile.Pwd() + gfile.Separator + "addons/@{.name}/web/src/views/addons/@{.name}" + targetWebPath := "../web/src/views/addons/@{.name}" + g.Log().Debug(ctx, "复制前端配置文件", "源路径:", sourceWebPath, "目标路径:", targetWebPath) + + // 检查源路径是否存在 + if gfile.Exists(sourceWebPath) { + err = gfile.CopyDir(sourceWebPath, targetWebPath) + if err != nil { + g.Log().Error(ctx, "复制前端配置文件失败:", err) + } else { + g.Log().Debug(ctx, "复制前端配置文件成功") + } + } else { + g.Log().Warning(ctx, "前端配置文件源路径不存在:", sourceWebPath) + } + + // 复制API文件 + sourceApiPath := gfile.Pwd() + gfile.Separator + "addons/@{.name}/web/src/api/addons/@{.name}" + targetApiPath := "../web/src/api/addons/@{.name}" + g.Log().Debug(ctx, "复制API文件", "源路径:", sourceApiPath, "目标路径:", targetApiPath) + if gfile.Exists(sourceApiPath) { + err = gfile.CopyDir(sourceApiPath, targetApiPath) + if err != nil { + g.Log().Error(ctx, "复制API文件失败:", err) + } else { + g.Log().Debug(ctx, "复制API文件成功") + } + } else { + g.Log().Warning(ctx, "API文件源路径不存在:", sourceApiPath) + } return } @@ -91,6 +142,17 @@ func (m *module) Upgrade(ctx context.Context) (err error) { // UnInstall 卸载模块 func (m *module) UnInstall(ctx context.Context) (err error) { - // ... + sqlExt := ".sql" + if migrations.GetDbType(ctx) == "pgsql" { + sqlExt = ".pg.sql" + } + // 移除数据库安装文件 + sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/@{.name}/uninstall" + sqlExt + result, err := migrations.DoSqlContent(ctx, sqlPath) + if err != nil { + g.Log().Error(ctx, "卸载模块", m.skeleton.Label, "失败", err) + return + } + g.Log().Debug(ctx, "卸载模块", m.skeleton.Label, "成功", result) return -} +} \ No newline at end of file From 0a49dccb72345e7141fb3de66eb6b93cfbece7fa Mon Sep 17 00:00:00 2001 From: osi Date: Sat, 20 Sep 2025 15:38:18 +0800 Subject: [PATCH 3/3] :bug: use install script --- server/resource/generate/default/addon/main.go.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/resource/generate/default/addon/main.go.template b/server/resource/generate/default/addon/main.go.template index 088b508..1d91948 100644 --- a/server/resource/generate/default/addon/main.go.template +++ b/server/resource/generate/default/addon/main.go.template @@ -91,7 +91,7 @@ func (m *module) Install(ctx context.Context) (err error) { sqlExt = ".pg.sql" } // 执行数据库安装文件 - sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/@{.name}/uninstall"+sqlExt + sqlPath := gfile.Pwd() + gfile.Separator + "addons/migrations/@{.name}/install"+sqlExt result, err := migrations.DoSqlContent(ctx, sqlPath) if err != nil { g.Log().Error(ctx, "安装模块", m.skeleton.Label, "失败", err)