From f6766d3dbd7329af1426c1846b2f5797d93a5200 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Sat, 19 Sep 2026 14:36:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=85=BB=E6=88=90?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cultivatecontent/cultivate_content.go | 42 +++ .../admin/cultivateflower/cultivate_flower.go | 33 ++ server/hack/config.yaml | 10 + server/internal/consts/cultivate.go | 54 +++ .../controller/admin/sys/cultivate_content.go | 57 +++ .../controller/admin/sys/cultivate_flower.go | 40 +++ server/internal/dao/admin_operation_log.go | 22 ++ server/internal/dao/content_audit_log.go | 22 ++ server/internal/dao/feed_comment.go | 22 ++ server/internal/dao/feed_media.go | 22 ++ server/internal/dao/feed_post.go | 22 ++ server/internal/dao/feed_report.go | 22 ++ server/internal/dao/flower_catalog.go | 22 ++ server/internal/dao/flower_stage_rule.go | 22 ++ .../dao/internal/admin_operation_log.go | 103 ++++++ .../dao/internal/content_audit_log.go | 103 ++++++ server/internal/dao/internal/feed_comment.go | 105 ++++++ server/internal/dao/internal/feed_media.go | 105 ++++++ server/internal/dao/internal/feed_post.go | 117 +++++++ server/internal/dao/internal/feed_report.go | 109 ++++++ .../internal/dao/internal/flower_catalog.go | 109 ++++++ .../dao/internal/flower_stage_rule.go | 109 ++++++ .../internal/logic/sys/cultivate_content.go | 324 ++++++++++++++++++ server/internal/logic/sys/cultivate_flower.go | 191 +++++++++++ .../internal/model/do/admin_operation_log.go | 29 ++ server/internal/model/do/content_audit_log.go | 29 ++ server/internal/model/do/feed_comment.go | 29 ++ server/internal/model/do/feed_media.go | 29 ++ server/internal/model/do/feed_post.go | 35 ++ server/internal/model/do/feed_report.go | 32 ++ server/internal/model/do/flower_catalog.go | 32 ++ server/internal/model/do/flower_stage_rule.go | 32 ++ .../model/entity/admin_operation_log.go | 27 ++ .../model/entity/content_audit_log.go | 27 ++ server/internal/model/entity/feed_comment.go | 27 ++ server/internal/model/entity/feed_media.go | 27 ++ server/internal/model/entity/feed_post.go | 33 ++ server/internal/model/entity/feed_report.go | 30 ++ .../internal/model/entity/flower_catalog.go | 30 ++ .../model/entity/flower_stage_rule.go | 30 ++ .../model/input/sysin/cultivate_content.go | 149 ++++++++ .../model/input/sysin/cultivate_flower.go | 155 +++++++++ .../router/genrouter/cultivate_content.go | 5 + .../router/genrouter/cultivate_flower.go | 5 + server/internal/service/sys.go | 35 ++ server/manifest/config/config.example.yaml | 3 + server/manifest/config/config.template | 6 + .../storage/data/generate/cultivate_menu.sql | 47 +++ web/src/api/cultivate/content.ts | 7 + web/src/api/cultivate/flowers.ts | 6 + web/src/views/cultivate/content/index.vue | 37 ++ web/src/views/cultivate/content/model.ts | 43 +++ web/src/views/cultivate/flowers/edit.vue | 49 +++ web/src/views/cultivate/flowers/index.vue | 36 ++ web/src/views/cultivate/flowers/model.ts | 83 +++++ web/src/views/cultivate/logs/index.vue | 13 + web/src/views/cultivate/logs/model.ts | 12 + web/src/views/cultivate/reports/index.vue | 25 ++ web/src/views/cultivate/reports/model.ts | 20 ++ 59 files changed, 3001 insertions(+) create mode 100644 server/api/admin/cultivatecontent/cultivate_content.go create mode 100644 server/api/admin/cultivateflower/cultivate_flower.go create mode 100644 server/internal/consts/cultivate.go create mode 100644 server/internal/controller/admin/sys/cultivate_content.go create mode 100644 server/internal/controller/admin/sys/cultivate_flower.go create mode 100644 server/internal/dao/admin_operation_log.go create mode 100644 server/internal/dao/content_audit_log.go create mode 100644 server/internal/dao/feed_comment.go create mode 100644 server/internal/dao/feed_media.go create mode 100644 server/internal/dao/feed_post.go create mode 100644 server/internal/dao/feed_report.go create mode 100644 server/internal/dao/flower_catalog.go create mode 100644 server/internal/dao/flower_stage_rule.go create mode 100644 server/internal/dao/internal/admin_operation_log.go create mode 100644 server/internal/dao/internal/content_audit_log.go create mode 100644 server/internal/dao/internal/feed_comment.go create mode 100644 server/internal/dao/internal/feed_media.go create mode 100644 server/internal/dao/internal/feed_post.go create mode 100644 server/internal/dao/internal/feed_report.go create mode 100644 server/internal/dao/internal/flower_catalog.go create mode 100644 server/internal/dao/internal/flower_stage_rule.go create mode 100644 server/internal/logic/sys/cultivate_content.go create mode 100644 server/internal/logic/sys/cultivate_flower.go create mode 100644 server/internal/model/do/admin_operation_log.go create mode 100644 server/internal/model/do/content_audit_log.go create mode 100644 server/internal/model/do/feed_comment.go create mode 100644 server/internal/model/do/feed_media.go create mode 100644 server/internal/model/do/feed_post.go create mode 100644 server/internal/model/do/feed_report.go create mode 100644 server/internal/model/do/flower_catalog.go create mode 100644 server/internal/model/do/flower_stage_rule.go create mode 100644 server/internal/model/entity/admin_operation_log.go create mode 100644 server/internal/model/entity/content_audit_log.go create mode 100644 server/internal/model/entity/feed_comment.go create mode 100644 server/internal/model/entity/feed_media.go create mode 100644 server/internal/model/entity/feed_post.go create mode 100644 server/internal/model/entity/feed_report.go create mode 100644 server/internal/model/entity/flower_catalog.go create mode 100644 server/internal/model/entity/flower_stage_rule.go create mode 100644 server/internal/model/input/sysin/cultivate_content.go create mode 100644 server/internal/model/input/sysin/cultivate_flower.go create mode 100644 server/internal/router/genrouter/cultivate_content.go create mode 100644 server/internal/router/genrouter/cultivate_flower.go create mode 100644 server/storage/data/generate/cultivate_menu.sql create mode 100644 web/src/api/cultivate/content.ts create mode 100644 web/src/api/cultivate/flowers.ts create mode 100644 web/src/views/cultivate/content/index.vue create mode 100644 web/src/views/cultivate/content/model.ts create mode 100644 web/src/views/cultivate/flowers/edit.vue create mode 100644 web/src/views/cultivate/flowers/index.vue create mode 100644 web/src/views/cultivate/flowers/model.ts create mode 100644 web/src/views/cultivate/logs/index.vue create mode 100644 web/src/views/cultivate/logs/model.ts create mode 100644 web/src/views/cultivate/reports/index.vue create mode 100644 web/src/views/cultivate/reports/model.ts diff --git a/server/api/admin/cultivatecontent/cultivate_content.go b/server/api/admin/cultivatecontent/cultivate_content.go new file mode 100644 index 0000000..d0cfae7 --- /dev/null +++ b/server/api/admin/cultivatecontent/cultivate_content.go @@ -0,0 +1,42 @@ +package cultivatecontent + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +type ListReq struct { + g.Meta `path:"/cultivate/content/list" method:"get" tags:"养成管理" summary:"获取动态或评论审核列表"` + sysin.CultivateContentListInp +} +type ListRes struct { + form.PageRes + List []*sysin.CultivateContentListModel `json:"list"` +} +type ReviewReq struct { + g.Meta `path:"/cultivate/content/review" method:"post" tags:"养成管理" summary:"审核或下架动态评论"` + sysin.CultivateContentReviewInp +} +type ReviewRes struct{} +type ReportListReq struct { + g.Meta `path:"/cultivate/reports/list" method:"get" tags:"养成管理" summary:"获取举报列表"` + sysin.CultivateReportListInp +} +type ReportListRes struct { + form.PageRes + List []*sysin.CultivateReportListModel `json:"list"` +} +type ReportHandleReq struct { + g.Meta `path:"/cultivate/reports/handle" method:"post" tags:"养成管理" summary:"处理举报"` + sysin.CultivateReportHandleInp +} +type ReportHandleRes struct{} +type LogListReq struct { + g.Meta `path:"/cultivate/logs/list" method:"get" tags:"养成管理" summary:"获取养成管理操作日志"` + sysin.CultivateOperationLogListInp +} +type LogListRes struct { + form.PageRes + List []*sysin.CultivateOperationLogListModel `json:"list"` +} diff --git a/server/api/admin/cultivateflower/cultivate_flower.go b/server/api/admin/cultivateflower/cultivate_flower.go new file mode 100644 index 0000000..9a9d21c --- /dev/null +++ b/server/api/admin/cultivateflower/cultivate_flower.go @@ -0,0 +1,33 @@ +package cultivateflower + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +type ListReq struct { + g.Meta `path:"/cultivate/flowers/list" method:"get" tags:"养成管理" summary:"获取花种列表"` + sysin.CultivateFlowerListInp +} +type ListRes struct { + form.PageRes + List []*sysin.CultivateFlowerListModel `json:"list"` +} +type ViewReq struct { + g.Meta `path:"/cultivate/flowers/view" method:"get" tags:"养成管理" summary:"获取花种详情"` + sysin.CultivateFlowerViewInp +} +type ViewRes struct { + *sysin.CultivateFlowerViewModel +} +type EditReq struct { + g.Meta `path:"/cultivate/flowers/edit" method:"post" tags:"养成管理" summary:"新建或编辑花种及阶段规则"` + sysin.CultivateFlowerEditInp +} +type EditRes struct{} +type StatusReq struct { + g.Meta `path:"/cultivate/flowers/status" method:"post" tags:"养成管理" summary:"更新花种上下架状态"` + sysin.CultivateFlowerStatusInp +} +type StatusRes struct{} diff --git a/server/hack/config.yaml b/server/hack/config.yaml index d0e5c50..5b08599 100644 --- a/server/hack/config.yaml +++ b/server/hack/config.yaml @@ -34,6 +34,16 @@ gfcli: gJsonSupport: true clear: false + - link: "mysql:root:root@tcp(127.0.0.1:3306)/cultivate?loc=Local&parseTime=true&charset=utf8mb4" + group: "cultivate" + tables: "cv_flower_catalog,cv_flower_stage_rule,cv_feed_post,cv_feed_media,cv_feed_comment,cv_feed_report,cv_content_audit_log,cv_admin_operation_log" + removePrefix: "cv_" + descriptionTag: true + noModelComment: true + jsonCase: "CamelLower" + gJsonSupport: true + clear: false + # service: # 生成业务配置 # srcFolder: "internal/logic" diff --git a/server/internal/consts/cultivate.go b/server/internal/consts/cultivate.go new file mode 100644 index 0000000..1635457 --- /dev/null +++ b/server/internal/consts/cultivate.go @@ -0,0 +1,54 @@ +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +const ( + CultivateFlowerOnline = "online" + CultivateFlowerOffline = "offline" + CultivateFlowerActivityOnly = "activity_only" + CultivateFlowerMaintenance = "maintenance" +) + +var CultivateFlowerStatusOptions = []*model.Option{ + dict.GenSuccessOption(CultivateFlowerOnline, "已上架"), + dict.GenDefaultOption(CultivateFlowerOffline, "已下架"), + dict.GenPrimaryOption(CultivateFlowerActivityOnly, "仅活动"), + dict.GenWarningOption(CultivateFlowerMaintenance, "维护中"), +} + +var CultivateContentStatusOptions = []*model.Option{ + dict.GenWarningOption("reviewing", "待审核"), + dict.GenSuccessOption("published", "已发布"), + dict.GenErrorOption("rejected", "已拒绝"), + dict.GenDefaultOption("taken_down", "已下架"), + dict.GenDefaultOption("deleted", "已删除"), +} + +var CultivateReportStatusOptions = []*model.Option{ + dict.GenWarningOption("submitted", "待处理"), + dict.GenPrimaryOption("processing", "处理中"), + dict.GenSuccessOption("resolved", "已处理"), + dict.GenDefaultOption("rejected", "已驳回"), +} + +var CultivateContentTypeOptions = []*model.Option{ + dict.GenPrimaryOption("feed_post", "动态"), + dict.GenInfoOption("feed_comment", "评论"), +} + +var CultivateReportObjectTypeOptions = []*model.Option{ + dict.GenPrimaryOption("feed_post", "动态"), + dict.GenInfoOption("feed_comment", "评论"), + dict.GenDefaultOption("user", "用户"), +} + +func init() { + dict.RegisterEnums("CultivateFlowerStatusOptions", "养成花种状态", CultivateFlowerStatusOptions) + dict.RegisterEnums("CultivateContentStatusOptions", "养成内容状态", CultivateContentStatusOptions) + dict.RegisterEnums("CultivateReportStatusOptions", "养成举报状态", CultivateReportStatusOptions) + dict.RegisterEnums("CultivateContentTypeOptions", "养成内容类型", CultivateContentTypeOptions) + dict.RegisterEnums("CultivateReportObjectTypeOptions", "养成举报对象类型", CultivateReportObjectTypeOptions) +} diff --git a/server/internal/controller/admin/sys/cultivate_content.go b/server/internal/controller/admin/sys/cultivate_content.go new file mode 100644 index 0000000..6841c32 --- /dev/null +++ b/server/internal/controller/admin/sys/cultivate_content.go @@ -0,0 +1,57 @@ +package sys + +import ( + "context" + "hotgo/api/admin/cultivatecontent" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var CultivateContent = cCultivateContent{} + +type cCultivateContent struct{} + +func (*cCultivateContent) List(ctx context.Context, req *cultivatecontent.ListReq) (res *cultivatecontent.ListRes, err error) { + list, total, err := service.SysCultivateContent().List(ctx, &req.CultivateContentListInp) + if err != nil { + return nil, err + } + if list == nil { + list = []*sysin.CultivateContentListModel{} + } + res = &cultivatecontent.ListRes{List: list} + res.PageRes.Pack(req, total) + return +} +func (*cCultivateContent) Review(ctx context.Context, req *cultivatecontent.ReviewReq) (res *cultivatecontent.ReviewRes, err error) { + err = service.SysCultivateContent().Review(ctx, &req.CultivateContentReviewInp) + return +} +func (*cCultivateContent) ReportList(ctx context.Context, req *cultivatecontent.ReportListReq) (res *cultivatecontent.ReportListRes, err error) { + list, total, err := service.SysCultivateContent().ReportList(ctx, &req.CultivateReportListInp) + if err != nil { + return nil, err + } + if list == nil { + list = []*sysin.CultivateReportListModel{} + } + res = &cultivatecontent.ReportListRes{List: list} + res.PageRes.Pack(req, total) + return +} +func (*cCultivateContent) ReportHandle(ctx context.Context, req *cultivatecontent.ReportHandleReq) (res *cultivatecontent.ReportHandleRes, err error) { + err = service.SysCultivateContent().ReportHandle(ctx, &req.CultivateReportHandleInp) + return +} +func (*cCultivateContent) LogList(ctx context.Context, req *cultivatecontent.LogListReq) (res *cultivatecontent.LogListRes, err error) { + list, total, err := service.SysCultivateContent().LogList(ctx, &req.CultivateOperationLogListInp) + if err != nil { + return nil, err + } + if list == nil { + list = []*sysin.CultivateOperationLogListModel{} + } + res = &cultivatecontent.LogListRes{List: list} + res.PageRes.Pack(req, total) + return +} diff --git a/server/internal/controller/admin/sys/cultivate_flower.go b/server/internal/controller/admin/sys/cultivate_flower.go new file mode 100644 index 0000000..ca7c259 --- /dev/null +++ b/server/internal/controller/admin/sys/cultivate_flower.go @@ -0,0 +1,40 @@ +package sys + +import ( + "context" + "hotgo/api/admin/cultivateflower" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var CultivateFlower = cCultivateFlower{} + +type cCultivateFlower struct{} + +func (*cCultivateFlower) List(ctx context.Context, req *cultivateflower.ListReq) (res *cultivateflower.ListRes, err error) { + list, total, err := service.SysCultivateFlower().List(ctx, &req.CultivateFlowerListInp) + if err != nil { + return nil, err + } + if list == nil { + list = []*sysin.CultivateFlowerListModel{} + } + res = &cultivateflower.ListRes{List: list} + res.PageRes.Pack(req, total) + return +} +func (*cCultivateFlower) View(ctx context.Context, req *cultivateflower.ViewReq) (res *cultivateflower.ViewRes, err error) { + data, err := service.SysCultivateFlower().View(ctx, &req.CultivateFlowerViewInp) + if err != nil { + return nil, err + } + return &cultivateflower.ViewRes{CultivateFlowerViewModel: data}, nil +} +func (*cCultivateFlower) Edit(ctx context.Context, req *cultivateflower.EditReq) (res *cultivateflower.EditRes, err error) { + err = service.SysCultivateFlower().Edit(ctx, &req.CultivateFlowerEditInp) + return +} +func (*cCultivateFlower) Status(ctx context.Context, req *cultivateflower.StatusReq) (res *cultivateflower.StatusRes, err error) { + err = service.SysCultivateFlower().Status(ctx, &req.CultivateFlowerStatusInp) + return +} diff --git a/server/internal/dao/admin_operation_log.go b/server/internal/dao/admin_operation_log.go new file mode 100644 index 0000000..634f918 --- /dev/null +++ b/server/internal/dao/admin_operation_log.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// adminOperationLogDao is the data access object for the table cv_admin_operation_log. +// You can define custom methods on it to extend its functionality as needed. +type adminOperationLogDao struct { + *internal.AdminOperationLogDao +} + +var ( + // AdminOperationLog is a globally accessible object for table cv_admin_operation_log operations. + AdminOperationLog = adminOperationLogDao{internal.NewAdminOperationLogDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/content_audit_log.go b/server/internal/dao/content_audit_log.go new file mode 100644 index 0000000..437e3c6 --- /dev/null +++ b/server/internal/dao/content_audit_log.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// contentAuditLogDao is the data access object for the table cv_content_audit_log. +// You can define custom methods on it to extend its functionality as needed. +type contentAuditLogDao struct { + *internal.ContentAuditLogDao +} + +var ( + // ContentAuditLog is a globally accessible object for table cv_content_audit_log operations. + ContentAuditLog = contentAuditLogDao{internal.NewContentAuditLogDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/feed_comment.go b/server/internal/dao/feed_comment.go new file mode 100644 index 0000000..22dda10 --- /dev/null +++ b/server/internal/dao/feed_comment.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// feedCommentDao is the data access object for the table cv_feed_comment. +// You can define custom methods on it to extend its functionality as needed. +type feedCommentDao struct { + *internal.FeedCommentDao +} + +var ( + // FeedComment is a globally accessible object for table cv_feed_comment operations. + FeedComment = feedCommentDao{internal.NewFeedCommentDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/feed_media.go b/server/internal/dao/feed_media.go new file mode 100644 index 0000000..80af1b8 --- /dev/null +++ b/server/internal/dao/feed_media.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// feedMediaDao is the data access object for the table cv_feed_media. +// You can define custom methods on it to extend its functionality as needed. +type feedMediaDao struct { + *internal.FeedMediaDao +} + +var ( + // FeedMedia is a globally accessible object for table cv_feed_media operations. + FeedMedia = feedMediaDao{internal.NewFeedMediaDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/feed_post.go b/server/internal/dao/feed_post.go new file mode 100644 index 0000000..87a4432 --- /dev/null +++ b/server/internal/dao/feed_post.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// feedPostDao is the data access object for the table cv_feed_post. +// You can define custom methods on it to extend its functionality as needed. +type feedPostDao struct { + *internal.FeedPostDao +} + +var ( + // FeedPost is a globally accessible object for table cv_feed_post operations. + FeedPost = feedPostDao{internal.NewFeedPostDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/feed_report.go b/server/internal/dao/feed_report.go new file mode 100644 index 0000000..a8124e5 --- /dev/null +++ b/server/internal/dao/feed_report.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// feedReportDao is the data access object for the table cv_feed_report. +// You can define custom methods on it to extend its functionality as needed. +type feedReportDao struct { + *internal.FeedReportDao +} + +var ( + // FeedReport is a globally accessible object for table cv_feed_report operations. + FeedReport = feedReportDao{internal.NewFeedReportDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/flower_catalog.go b/server/internal/dao/flower_catalog.go new file mode 100644 index 0000000..48858d6 --- /dev/null +++ b/server/internal/dao/flower_catalog.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// flowerCatalogDao is the data access object for the table cv_flower_catalog. +// You can define custom methods on it to extend its functionality as needed. +type flowerCatalogDao struct { + *internal.FlowerCatalogDao +} + +var ( + // FlowerCatalog is a globally accessible object for table cv_flower_catalog operations. + FlowerCatalog = flowerCatalogDao{internal.NewFlowerCatalogDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/flower_stage_rule.go b/server/internal/dao/flower_stage_rule.go new file mode 100644 index 0000000..6e6957d --- /dev/null +++ b/server/internal/dao/flower_stage_rule.go @@ -0,0 +1,22 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "hotgo/internal/dao/internal" +) + +// flowerStageRuleDao is the data access object for the table cv_flower_stage_rule. +// You can define custom methods on it to extend its functionality as needed. +type flowerStageRuleDao struct { + *internal.FlowerStageRuleDao +} + +var ( + // FlowerStageRule is a globally accessible object for table cv_flower_stage_rule operations. + FlowerStageRule = flowerStageRuleDao{internal.NewFlowerStageRuleDao()} +) + +// Add your custom methods and functionality below. diff --git a/server/internal/dao/internal/admin_operation_log.go b/server/internal/dao/internal/admin_operation_log.go new file mode 100644 index 0000000..640b6d1 --- /dev/null +++ b/server/internal/dao/internal/admin_operation_log.go @@ -0,0 +1,103 @@ +// ========================================================================== +// 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" +) + +// AdminOperationLogDao is the data access object for the table cv_admin_operation_log. +type AdminOperationLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns AdminOperationLogColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// AdminOperationLogColumns defines and stores column names for the table cv_admin_operation_log. +type AdminOperationLogColumns struct { + Id string // + TenantId string // + OperatorId string // + OperationType string // + TargetType string // + TargetId string // + RequestId string // + BeforeSnapshot string // + AfterSnapshot string // + Reason string // + IpAddress string // + UserAgent string // + CreatedAt string // +} + +// adminOperationLogColumns holds the columns for the table cv_admin_operation_log. +var adminOperationLogColumns = AdminOperationLogColumns{ + Id: "id", + TenantId: "tenant_id", + OperatorId: "operator_id", + OperationType: "operation_type", + TargetType: "target_type", + TargetId: "target_id", + RequestId: "request_id", + BeforeSnapshot: "before_snapshot", + AfterSnapshot: "after_snapshot", + Reason: "reason", + IpAddress: "ip_address", + UserAgent: "user_agent", + CreatedAt: "created_at", +} + +// NewAdminOperationLogDao creates and returns a new DAO object for table data access. +func NewAdminOperationLogDao(handlers ...gdb.ModelHandler) *AdminOperationLogDao { + return &AdminOperationLogDao{ + group: "cultivate", + table: "cv_admin_operation_log", + columns: adminOperationLogColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *AdminOperationLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *AdminOperationLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *AdminOperationLogDao) Columns() AdminOperationLogColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *AdminOperationLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *AdminOperationLogDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *AdminOperationLogDao) 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/internal/dao/internal/content_audit_log.go b/server/internal/dao/internal/content_audit_log.go new file mode 100644 index 0000000..0a44a75 --- /dev/null +++ b/server/internal/dao/internal/content_audit_log.go @@ -0,0 +1,103 @@ +// ========================================================================== +// 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" +) + +// ContentAuditLogDao is the data access object for the table cv_content_audit_log. +type ContentAuditLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns ContentAuditLogColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// ContentAuditLogColumns defines and stores column names for the table cv_content_audit_log. +type ContentAuditLogColumns struct { + Id string // + TenantId string // + ObjectType string // + ObjectId string // + AuditRequestId string // + AuditSource string // + StatusBefore string // + StatusAfter string // + ResultCode string // + RiskLabels string // + OperatorId string // + OccurredAt string // + CreatedAt string // +} + +// contentAuditLogColumns holds the columns for the table cv_content_audit_log. +var contentAuditLogColumns = ContentAuditLogColumns{ + Id: "id", + TenantId: "tenant_id", + ObjectType: "object_type", + ObjectId: "object_id", + AuditRequestId: "audit_request_id", + AuditSource: "audit_source", + StatusBefore: "status_before", + StatusAfter: "status_after", + ResultCode: "result_code", + RiskLabels: "risk_labels", + OperatorId: "operator_id", + OccurredAt: "occurred_at", + CreatedAt: "created_at", +} + +// NewContentAuditLogDao creates and returns a new DAO object for table data access. +func NewContentAuditLogDao(handlers ...gdb.ModelHandler) *ContentAuditLogDao { + return &ContentAuditLogDao{ + group: "cultivate", + table: "cv_content_audit_log", + columns: contentAuditLogColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *ContentAuditLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *ContentAuditLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *ContentAuditLogDao) Columns() ContentAuditLogColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *ContentAuditLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *ContentAuditLogDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *ContentAuditLogDao) 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/internal/dao/internal/feed_comment.go b/server/internal/dao/internal/feed_comment.go new file mode 100644 index 0000000..ca3fc1f --- /dev/null +++ b/server/internal/dao/internal/feed_comment.go @@ -0,0 +1,105 @@ +// ========================================================================== +// 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" +) + +// FeedCommentDao is the data access object for the table cv_feed_comment. +type FeedCommentDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FeedCommentColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// FeedCommentColumns defines and stores column names for the table cv_feed_comment. +type FeedCommentColumns struct { + Id string // + TenantId string // + PostId string // + AuthorId string // + ContentText string // + Status string // + AuditStatus string // + AuditRequestId string // + DeletedBy string // + DeleteReason string // + PublishedAt string // + DeletedAt string // + CreatedAt string // + UpdatedAt string // +} + +// feedCommentColumns holds the columns for the table cv_feed_comment. +var feedCommentColumns = FeedCommentColumns{ + Id: "id", + TenantId: "tenant_id", + PostId: "post_id", + AuthorId: "author_id", + ContentText: "content_text", + Status: "status", + AuditStatus: "audit_status", + AuditRequestId: "audit_request_id", + DeletedBy: "deleted_by", + DeleteReason: "delete_reason", + PublishedAt: "published_at", + DeletedAt: "deleted_at", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFeedCommentDao creates and returns a new DAO object for table data access. +func NewFeedCommentDao(handlers ...gdb.ModelHandler) *FeedCommentDao { + return &FeedCommentDao{ + group: "cultivate", + table: "cv_feed_comment", + columns: feedCommentColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FeedCommentDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FeedCommentDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FeedCommentDao) Columns() FeedCommentColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FeedCommentDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FeedCommentDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FeedCommentDao) 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/internal/dao/internal/feed_media.go b/server/internal/dao/internal/feed_media.go new file mode 100644 index 0000000..ea5e7c2 --- /dev/null +++ b/server/internal/dao/internal/feed_media.go @@ -0,0 +1,105 @@ +// ========================================================================== +// 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" +) + +// FeedMediaDao is the data access object for the table cv_feed_media. +type FeedMediaDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FeedMediaColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// FeedMediaColumns defines and stores column names for the table cv_feed_media. +type FeedMediaColumns struct { + Id string // + TenantId string // + PostId string // + UserId string // + MediaType string // + FileId string // + ThumbnailFileId string // + Width string // + Height string // + SortNo string // + AuditStatus string // + AuditRequestId string // + CreatedAt string // + UpdatedAt string // +} + +// feedMediaColumns holds the columns for the table cv_feed_media. +var feedMediaColumns = FeedMediaColumns{ + Id: "id", + TenantId: "tenant_id", + PostId: "post_id", + UserId: "user_id", + MediaType: "media_type", + FileId: "file_id", + ThumbnailFileId: "thumbnail_file_id", + Width: "width", + Height: "height", + SortNo: "sort_no", + AuditStatus: "audit_status", + AuditRequestId: "audit_request_id", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFeedMediaDao creates and returns a new DAO object for table data access. +func NewFeedMediaDao(handlers ...gdb.ModelHandler) *FeedMediaDao { + return &FeedMediaDao{ + group: "cultivate", + table: "cv_feed_media", + columns: feedMediaColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FeedMediaDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FeedMediaDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FeedMediaDao) Columns() FeedMediaColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FeedMediaDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FeedMediaDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FeedMediaDao) 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/internal/dao/internal/feed_post.go b/server/internal/dao/internal/feed_post.go new file mode 100644 index 0000000..f70fbaf --- /dev/null +++ b/server/internal/dao/internal/feed_post.go @@ -0,0 +1,117 @@ +// ========================================================================== +// 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" +) + +// FeedPostDao is the data access object for the table cv_feed_post. +type FeedPostDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FeedPostColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// FeedPostColumns defines and stores column names for the table cv_feed_post. +type FeedPostColumns struct { + Id string // + TenantId string // + AuthorId string // + ContentText string // + FlowerCode string // + SourceType string // + SourceId string // + Visibility string // + Status string // + AuditStatus string // + AuditRequestId string // + RejectReasonCode string // + LikeCount string // + CommentCount string // + Version string // + PublishedAt string // + DeletedAt string // + TakenDownAt string // + CreatedAt string // + UpdatedAt string // +} + +// feedPostColumns holds the columns for the table cv_feed_post. +var feedPostColumns = FeedPostColumns{ + Id: "id", + TenantId: "tenant_id", + AuthorId: "author_id", + ContentText: "content_text", + FlowerCode: "flower_code", + SourceType: "source_type", + SourceId: "source_id", + Visibility: "visibility", + Status: "status", + AuditStatus: "audit_status", + AuditRequestId: "audit_request_id", + RejectReasonCode: "reject_reason_code", + LikeCount: "like_count", + CommentCount: "comment_count", + Version: "version", + PublishedAt: "published_at", + DeletedAt: "deleted_at", + TakenDownAt: "taken_down_at", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFeedPostDao creates and returns a new DAO object for table data access. +func NewFeedPostDao(handlers ...gdb.ModelHandler) *FeedPostDao { + return &FeedPostDao{ + group: "cultivate", + table: "cv_feed_post", + columns: feedPostColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FeedPostDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FeedPostDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FeedPostDao) Columns() FeedPostColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FeedPostDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FeedPostDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FeedPostDao) 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/internal/dao/internal/feed_report.go b/server/internal/dao/internal/feed_report.go new file mode 100644 index 0000000..9da350d --- /dev/null +++ b/server/internal/dao/internal/feed_report.go @@ -0,0 +1,109 @@ +// ========================================================================== +// 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" +) + +// FeedReportDao is the data access object for the table cv_feed_report. +type FeedReportDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FeedReportColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// FeedReportColumns defines and stores column names for the table cv_feed_report. +type FeedReportColumns struct { + Id string // + TenantId string // + ReporterId string // + ReportedUserId string // + ObjectType string // + ObjectId string // + ReasonCode string // + Description string // + EvidenceFileIds string // + SourcePage string // + Status string // + HandlerId string // + HandleResult string // + HandledAt string // + CreatedAt string // + UpdatedAt string // +} + +// feedReportColumns holds the columns for the table cv_feed_report. +var feedReportColumns = FeedReportColumns{ + Id: "id", + TenantId: "tenant_id", + ReporterId: "reporter_id", + ReportedUserId: "reported_user_id", + ObjectType: "object_type", + ObjectId: "object_id", + ReasonCode: "reason_code", + Description: "description", + EvidenceFileIds: "evidence_file_ids", + SourcePage: "source_page", + Status: "status", + HandlerId: "handler_id", + HandleResult: "handle_result", + HandledAt: "handled_at", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFeedReportDao creates and returns a new DAO object for table data access. +func NewFeedReportDao(handlers ...gdb.ModelHandler) *FeedReportDao { + return &FeedReportDao{ + group: "cultivate", + table: "cv_feed_report", + columns: feedReportColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FeedReportDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FeedReportDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FeedReportDao) Columns() FeedReportColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FeedReportDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FeedReportDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FeedReportDao) 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/internal/dao/internal/flower_catalog.go b/server/internal/dao/internal/flower_catalog.go new file mode 100644 index 0000000..fc0012e --- /dev/null +++ b/server/internal/dao/internal/flower_catalog.go @@ -0,0 +1,109 @@ +// ========================================================================== +// 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" +) + +// FlowerCatalogDao is the data access object for the table cv_flower_catalog. +type FlowerCatalogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FlowerCatalogColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// FlowerCatalogColumns defines and stores column names for the table cv_flower_catalog. +type FlowerCatalogColumns struct { + Id string // + TenantId string // + FlowerCode string // + FlowerName string // + FlowerDesc string // + IconFileId string // + Status string // + ConfigVersion string // + DailyWaterLimit string // + DailyFertilizeLimit string // + ShareConfig string // + SortNo string // + OnlineAt string // + OfflineAt string // + CreatedAt string // + UpdatedAt string // +} + +// flowerCatalogColumns holds the columns for the table cv_flower_catalog. +var flowerCatalogColumns = FlowerCatalogColumns{ + Id: "id", + TenantId: "tenant_id", + FlowerCode: "flower_code", + FlowerName: "flower_name", + FlowerDesc: "flower_desc", + IconFileId: "icon_file_id", + Status: "status", + ConfigVersion: "config_version", + DailyWaterLimit: "daily_water_limit", + DailyFertilizeLimit: "daily_fertilize_limit", + ShareConfig: "share_config", + SortNo: "sort_no", + OnlineAt: "online_at", + OfflineAt: "offline_at", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFlowerCatalogDao creates and returns a new DAO object for table data access. +func NewFlowerCatalogDao(handlers ...gdb.ModelHandler) *FlowerCatalogDao { + return &FlowerCatalogDao{ + group: "cultivate", + table: "cv_flower_catalog", + columns: flowerCatalogColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FlowerCatalogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FlowerCatalogDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FlowerCatalogDao) Columns() FlowerCatalogColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FlowerCatalogDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FlowerCatalogDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FlowerCatalogDao) 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/internal/dao/internal/flower_stage_rule.go b/server/internal/dao/internal/flower_stage_rule.go new file mode 100644 index 0000000..94d6177 --- /dev/null +++ b/server/internal/dao/internal/flower_stage_rule.go @@ -0,0 +1,109 @@ +// ========================================================================== +// 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" +) + +// FlowerStageRuleDao is the data access object for the table cv_flower_stage_rule. +type FlowerStageRuleDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FlowerStageRuleColumns // columns contains all the column names of Table for convenient usage. + handlers []gdb.ModelHandler // handlers for customized model modification. +} + +// FlowerStageRuleColumns defines and stores column names for the table cv_flower_stage_rule. +type FlowerStageRuleColumns struct { + Id string // + TenantId string // + FlowerCatalogId string // + Stage string // + NextStage string // + RequiredPoints string // + WaterPoints string // + FertilizePoints string // + AllowedActions string // + ImageFileId string // + AnimationFileId string // + ProgressTextTemplate string // + CompletionText string // + SortNo string // + CreatedAt string // + UpdatedAt string // +} + +// flowerStageRuleColumns holds the columns for the table cv_flower_stage_rule. +var flowerStageRuleColumns = FlowerStageRuleColumns{ + Id: "id", + TenantId: "tenant_id", + FlowerCatalogId: "flower_catalog_id", + Stage: "stage", + NextStage: "next_stage", + RequiredPoints: "required_points", + WaterPoints: "water_points", + FertilizePoints: "fertilize_points", + AllowedActions: "allowed_actions", + ImageFileId: "image_file_id", + AnimationFileId: "animation_file_id", + ProgressTextTemplate: "progress_text_template", + CompletionText: "completion_text", + SortNo: "sort_no", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFlowerStageRuleDao creates and returns a new DAO object for table data access. +func NewFlowerStageRuleDao(handlers ...gdb.ModelHandler) *FlowerStageRuleDao { + return &FlowerStageRuleDao{ + group: "cultivate", + table: "cv_flower_stage_rule", + columns: flowerStageRuleColumns, + handlers: handlers, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FlowerStageRuleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FlowerStageRuleDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FlowerStageRuleDao) Columns() FlowerStageRuleColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FlowerStageRuleDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FlowerStageRuleDao) Ctx(ctx context.Context) *gdb.Model { + model := dao.DB().Model(dao.table) + for _, handler := range dao.handlers { + model = handler(model) + } + return model.Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FlowerStageRuleDao) 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/internal/logic/sys/cultivate_content.go b/server/internal/logic/sys/cultivate_content.go new file mode 100644 index 0000000..7ed2994 --- /dev/null +++ b/server/internal/logic/sys/cultivate_content.go @@ -0,0 +1,324 @@ +package sys + +import ( + "context" + "database/sql" + "errors" + "strconv" + "strings" + "time" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + + "hotgo/internal/dao" + "hotgo/internal/library/contexts" + "hotgo/internal/library/imtenant" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +type sSysCultivateContent struct{} + +func NewSysCultivateContent() *sSysCultivateContent { return &sSysCultivateContent{} } +func init() { service.RegisterSysCultivateContent(NewSysCultivateContent()) } + +func (s *sSysCultivateContent) List(ctx context.Context, in *sysin.CultivateContentListInp) (list []*sysin.CultivateContentListModel, totalCount int, err error) { + tenantID := cultivateTenantID(ctx) + if in.ObjectType == "feed_comment" { + columns := dao.FeedComment.Columns() + mod := dao.FeedComment.Ctx(ctx).Where(columns.TenantId, tenantID) + if in.AuthorId != "" { + mod = mod.Where(columns.AuthorId, in.AuthorId) + } + if in.Status != "" { + mod = mod.Where(columns.Status, in.Status) + } + if in.Keyword != "" { + mod = mod.WhereLike(columns.ContentText, "%"+strings.TrimSpace(in.Keyword)+"%") + } + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(columns.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + var rows []*entity.FeedComment + err = mod.Page(in.Page, in.PerPage).OrderDesc(columns.Id).ScanAndCount(&rows, &totalCount, false) + if err != nil { + return nil, 0, gerror.Wrap(err, "获取评论审核列表失败") + } + list = make([]*sysin.CultivateContentListModel, 0, len(rows)) + for _, row := range rows { + list = append(list, &sysin.CultivateContentListModel{Id: strconv.FormatUint(row.Id, 10), ObjectType: "feed_comment", PostId: strconv.FormatUint(row.PostId, 10), AuthorId: strconv.FormatUint(row.AuthorId, 10), ContentText: row.ContentText, Status: row.Status, AuditStatus: row.AuditStatus, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}) + } + return + } + columns := dao.FeedPost.Columns() + mod := dao.FeedPost.Ctx(ctx).Where(columns.TenantId, tenantID) + if in.AuthorId != "" { + mod = mod.Where(columns.AuthorId, in.AuthorId) + } + if in.Status != "" { + mod = mod.Where(columns.Status, in.Status) + } + if in.Keyword != "" { + mod = mod.WhereLike(columns.ContentText, "%"+strings.TrimSpace(in.Keyword)+"%") + } + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(columns.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + var rows []*entity.FeedPost + err = mod.Page(in.Page, in.PerPage).OrderDesc(columns.Id).ScanAndCount(&rows, &totalCount, false) + if err != nil { + return nil, 0, gerror.Wrap(err, "获取动态审核列表失败") + } + list = make([]*sysin.CultivateContentListModel, 0, len(rows)) + for _, row := range rows { + list = append(list, &sysin.CultivateContentListModel{Id: strconv.FormatUint(row.Id, 10), ObjectType: "feed_post", AuthorId: strconv.FormatUint(row.AuthorId, 10), ContentText: row.ContentText, FlowerCode: row.FlowerCode, Visibility: row.Visibility, Status: row.Status, AuditStatus: row.AuditStatus, RejectReason: row.RejectReasonCode, LikeCount: row.LikeCount, CommentCount: row.CommentCount, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}) + } + return +} + +func (s *sSysCultivateContent) Review(ctx context.Context, in *sysin.CultivateContentReviewInp) error { + tenantID, operatorID := cultivateTenantID(ctx), contexts.GetUserId(ctx) + return dao.FeedPost.Transaction(ctx, func(txCtx context.Context, tx gdb.TX) error { + if in.ObjectType == "feed_comment" { + return s.reviewComment(txCtx, tx, tenantID, operatorID, in) + } + return s.reviewPost(txCtx, tx, tenantID, operatorID, in) + }) +} + +func (s *sSysCultivateContent) reviewPost(ctx context.Context, tx gdb.TX, tenantID, operatorID int64, in *sysin.CultivateContentReviewInp) error { + columns := dao.FeedPost.Columns() + var before entity.FeedPost + err := tx.Model(dao.FeedPost.Table()).Where(g.Map{columns.Id: in.ObjectId, columns.TenantId: tenantID}).LockUpdate().Scan(&before) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return err + } + if before.Id == 0 { + return gerror.New("动态不存在") + } + now := time.Now().UTC() + data := g.Map{columns.UpdatedAt: now, columns.Version: gdb.Raw(columns.Version + "+1")} + afterStatus := before.Status + switch in.Action { + case "approve": + if before.Status != "reviewing" && before.Status != "rejected" { + return gerror.New("仅待审核或已拒绝动态可审核通过") + } + afterStatus = "published" + data[columns.Status] = afterStatus + data[columns.AuditStatus] = "approved" + data[columns.RejectReasonCode] = "" + if before.PublishedAt == nil { + data[columns.PublishedAt] = now + } + case "reject": + if before.Status != "reviewing" { + return gerror.New("仅待审核动态可拒绝") + } + afterStatus = "rejected" + data[columns.Status] = afterStatus + data[columns.AuditStatus] = "rejected" + data[columns.RejectReasonCode] = in.Reason + case "take_down": + if before.Status != "published" { + return gerror.New("仅已发布动态可下架") + } + afterStatus = "taken_down" + data[columns.Status] = afterStatus + data[columns.TakenDownAt] = now + data[columns.RejectReasonCode] = in.Reason + case "restore": + if before.Status != "taken_down" { + return gerror.New("仅已下架动态可恢复") + } + afterStatus = "published" + data[columns.Status] = afterStatus + data[columns.TakenDownAt] = nil + data[columns.RejectReasonCode] = "" + } + if _, err = tx.Model(dao.FeedPost.Table()).Where(columns.Id, before.Id).Data(data).Update(); err != nil { + return gerror.Wrap(err, "更新动态审核状态失败") + } + if err = writeContentAudit(ctx, tx, tenantID, operatorID, "feed_post", before.Id, before.Status, afterStatus, in.Action, now); err != nil { + return err + } + return writeCultivateOperation(ctx, tx, tenantID, operatorID, "content."+in.Action, "feed_post", in.Id, before, data, in.Reason, now) +} + +func (s *sSysCultivateContent) reviewComment(ctx context.Context, tx gdb.TX, tenantID, operatorID int64, in *sysin.CultivateContentReviewInp) error { + columns := dao.FeedComment.Columns() + var before entity.FeedComment + err := tx.Model(dao.FeedComment.Table()).Where(g.Map{columns.Id: in.ObjectId, columns.TenantId: tenantID}).LockUpdate().Scan(&before) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return err + } + if before.Id == 0 { + return gerror.New("评论不存在") + } + now := time.Now().UTC() + data := g.Map{columns.UpdatedAt: now} + afterStatus := before.Status + counterDelta := 0 + switch in.Action { + case "approve": + if before.Status != "reviewing" && before.Status != "rejected" { + return gerror.New("仅待审核或已拒绝评论可审核通过") + } + afterStatus = "published" + data[columns.Status] = afterStatus + data[columns.AuditStatus] = "approved" + data[columns.PublishedAt] = now + counterDelta = 1 + case "reject": + if before.Status != "reviewing" { + return gerror.New("仅待审核评论可拒绝") + } + afterStatus = "rejected" + data[columns.Status] = afterStatus + data[columns.AuditStatus] = "rejected" + data[columns.DeleteReason] = in.Reason + case "take_down": + if before.Status != "published" { + return gerror.New("仅已发布评论可下架") + } + afterStatus = "taken_down" + data[columns.Status] = afterStatus + data[columns.DeleteReason] = in.Reason + counterDelta = -1 + case "restore": + if before.Status != "taken_down" { + return gerror.New("仅已下架评论可恢复") + } + afterStatus = "published" + data[columns.Status] = afterStatus + data[columns.DeleteReason] = "" + counterDelta = 1 + } + if _, err = tx.Model(dao.FeedComment.Table()).Where(columns.Id, before.Id).Data(data).Update(); err != nil { + return gerror.Wrap(err, "更新评论审核状态失败") + } + if counterDelta != 0 { + postColumns := dao.FeedPost.Columns() + expression := "`comment_count` + 1" + if counterDelta < 0 { + expression = "GREATEST(`comment_count` - 1, 0)" + } + if _, err = tx.Model(dao.FeedPost.Table()).Where(g.Map{postColumns.Id: before.PostId, postColumns.TenantId: tenantID}).Data(g.Map{postColumns.CommentCount: gdb.Raw(expression), postColumns.UpdatedAt: now}).Update(); err != nil { + return gerror.Wrap(err, "更新动态评论数失败") + } + } + if err = writeContentAudit(ctx, tx, tenantID, operatorID, "feed_comment", before.Id, before.Status, afterStatus, in.Action, now); err != nil { + return err + } + return writeCultivateOperation(ctx, tx, tenantID, operatorID, "content."+in.Action, "feed_comment", in.Id, before, data, in.Reason, now) +} + +func writeContentAudit(ctx context.Context, tx gdb.TX, tenantID, operatorID int64, objectType string, objectID uint64, before, after, result string, now time.Time) error { + id, err := imtenant.NextSnowflakeID(ctx) + if err != nil { + return err + } + columns := dao.ContentAuditLog.Columns() + _, err = tx.Model(dao.ContentAuditLog.Table()).Data(g.Map{columns.Id: id, columns.TenantId: tenantID, columns.ObjectType: objectType, columns.ObjectId: objectID, columns.AuditSource: "manual", columns.StatusBefore: before, columns.StatusAfter: after, columns.ResultCode: result, columns.RiskLabels: "[]", columns.OperatorId: operatorID, columns.OccurredAt: now, columns.CreatedAt: now}).Insert() + return err +} + +func (s *sSysCultivateContent) ReportList(ctx context.Context, in *sysin.CultivateReportListInp) (list []*sysin.CultivateReportListModel, totalCount int, err error) { + columns := dao.FeedReport.Columns() + mod := dao.FeedReport.Ctx(ctx).Where(columns.TenantId, cultivateTenantID(ctx)) + if in.ObjectType != "" { + mod = mod.Where(columns.ObjectType, in.ObjectType) + } + if in.Status != "" { + mod = mod.Where(columns.Status, in.Status) + } + if in.ReporterId != "" { + mod = mod.Where(columns.ReporterId, in.ReporterId) + } + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(columns.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + var rows []*entity.FeedReport + if err = mod.Page(in.Page, in.PerPage).OrderDesc(columns.Id).ScanAndCount(&rows, &totalCount, false); err != nil { + return nil, 0, gerror.Wrap(err, "获取举报列表失败") + } + list = make([]*sysin.CultivateReportListModel, 0, len(rows)) + for _, row := range rows { + list = append(list, &sysin.CultivateReportListModel{Id: strconv.FormatUint(row.Id, 10), ReporterId: strconv.FormatUint(row.ReporterId, 10), ReportedUserId: strconv.FormatUint(row.ReportedUserId, 10), ObjectType: row.ObjectType, ObjectId: row.ObjectId, ReasonCode: row.ReasonCode, Description: row.Description, EvidenceFileIds: row.EvidenceFileIds, SourcePage: row.SourcePage, Status: row.Status, HandlerId: optionalUint(row.HandlerId), HandleResult: row.HandleResult, HandledAt: row.HandledAt, CreatedAt: row.CreatedAt}) + } + return +} + +func (s *sSysCultivateContent) ReportHandle(ctx context.Context, in *sysin.CultivateReportHandleInp) error { + tenantID, operatorID := cultivateTenantID(ctx), contexts.GetUserId(ctx) + return dao.FeedReport.Transaction(ctx, func(txCtx context.Context, tx gdb.TX) error { + columns := dao.FeedReport.Columns() + var before entity.FeedReport + err := tx.Model(dao.FeedReport.Table()).Where(g.Map{columns.Id: in.ReportId, columns.TenantId: tenantID}).LockUpdate().Scan(&before) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return err + } + if before.Id == 0 { + return gerror.New("举报记录不存在") + } + if before.Status == "resolved" || before.Status == "rejected" { + return gerror.New("举报已办结,不能重复处理") + } + now := time.Now().UTC() + status := in.Action + if status == "resolve" { + status = "resolved" + } + data := g.Map{columns.Status: status, columns.HandlerId: operatorID, columns.HandleResult: in.HandleResult, columns.UpdatedAt: now} + if status == "resolved" || status == "rejected" { + data[columns.HandledAt] = now + } + if _, err = tx.Model(dao.FeedReport.Table()).Where(columns.Id, before.Id).Data(data).Update(); err != nil { + return gerror.Wrap(err, "更新举报处理状态失败") + } + return writeCultivateOperation(txCtx, tx, tenantID, operatorID, "report."+in.Action, "feed_report", in.Id, before, data, in.HandleResult, now) + }) +} + +func (s *sSysCultivateContent) LogList(ctx context.Context, in *sysin.CultivateOperationLogListInp) (list []*sysin.CultivateOperationLogListModel, totalCount int, err error) { + columns := dao.AdminOperationLog.Columns() + mod := dao.AdminOperationLog.Ctx(ctx).Where(columns.TenantId, cultivateTenantID(ctx)) + if in.OperatorId != "" { + mod = mod.Where(columns.OperatorId, in.OperatorId) + } + if in.OperationType != "" { + mod = mod.WhereLike(columns.OperationType, "%"+strings.TrimSpace(in.OperationType)+"%") + } + if in.TargetType != "" { + mod = mod.Where(columns.TargetType, in.TargetType) + } + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(columns.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + var rows []*entity.AdminOperationLog + if err = mod.Page(in.Page, in.PerPage).OrderDesc(columns.Id).ScanAndCount(&rows, &totalCount, false); err != nil { + return nil, 0, gerror.Wrap(err, "获取操作日志失败") + } + list = make([]*sysin.CultivateOperationLogListModel, 0, len(rows)) + for _, row := range rows { + list = append(list, &sysin.CultivateOperationLogListModel{Id: strconv.FormatUint(row.Id, 10), OperatorId: strconv.FormatUint(row.OperatorId, 10), OperationType: row.OperationType, TargetType: row.TargetType, TargetId: row.TargetId, RequestId: row.RequestId, BeforeSnapshot: jsonValue(row.BeforeSnapshot), AfterSnapshot: jsonValue(row.AfterSnapshot), Reason: row.Reason, CreatedAt: row.CreatedAt}) + } + return +} + +func optionalUint(value uint64) string { + if value == 0 { + return "" + } + return strconv.FormatUint(value, 10) +} +func jsonValue(value *gjson.Json) any { + if value == nil { + return nil + } + return value +} diff --git a/server/internal/logic/sys/cultivate_flower.go b/server/internal/logic/sys/cultivate_flower.go new file mode 100644 index 0000000..46175b9 --- /dev/null +++ b/server/internal/logic/sys/cultivate_flower.go @@ -0,0 +1,191 @@ +package sys + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + + "hotgo/internal/dao" + "hotgo/internal/library/contexts" + "hotgo/internal/library/imtenant" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +type sSysCultivateFlower struct{} + +func NewSysCultivateFlower() *sSysCultivateFlower { return &sSysCultivateFlower{} } +func init() { service.RegisterSysCultivateFlower(NewSysCultivateFlower()) } + +func cultivateTenantID(ctx context.Context) int64 { + id := contexts.GetTenantId(ctx) + if id <= 0 { + id = g.Cfg().MustGet(ctx, "cultivate.defaultTenantId", 1).Int64() + } + return id +} + +func (s *sSysCultivateFlower) List(ctx context.Context, in *sysin.CultivateFlowerListInp) (list []*sysin.CultivateFlowerListModel, totalCount int, err error) { + c := dao.FlowerCatalog.Columns() + mod := dao.FlowerCatalog.Ctx(ctx).Fields("cv_flower_catalog.*, COUNT(cv_flower_stage_rule.id) AS stage_count").LeftJoin(dao.FlowerStageRule.Table(), "cv_flower_stage_rule.flower_catalog_id=cv_flower_catalog.id AND cv_flower_stage_rule.tenant_id=cv_flower_catalog.tenant_id").Where("cv_flower_catalog."+c.TenantId, cultivateTenantID(ctx)).Group("cv_flower_catalog." + c.Id) + if in.FlowerCode != "" { + mod = mod.WhereLike("cv_flower_catalog."+c.FlowerCode, "%"+strings.TrimSpace(in.FlowerCode)+"%") + } + if in.FlowerName != "" { + mod = mod.WhereLike("cv_flower_catalog."+c.FlowerName, "%"+strings.TrimSpace(in.FlowerName)+"%") + } + if in.Status != "" { + mod = mod.Where("cv_flower_catalog."+c.Status, in.Status) + } + if in.ConfigVersion != "" { + mod = mod.Where("cv_flower_catalog."+c.ConfigVersion, in.ConfigVersion) + } + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween("cv_flower_catalog."+c.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + mod = mod.Page(in.Page, in.PerPage).OrderAsc("cv_flower_catalog." + c.SortNo).OrderDesc("cv_flower_catalog." + c.Id) + if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { + err = gerror.Wrap(err, "获取花种列表失败") + } + return +} + +func (s *sSysCultivateFlower) View(ctx context.Context, in *sysin.CultivateFlowerViewInp) (res *sysin.CultivateFlowerViewModel, err error) { + c := dao.FlowerCatalog.Columns() + var catalog entity.FlowerCatalog + if err = dao.FlowerCatalog.Ctx(ctx).Where(g.Map{c.Id: in.Id, c.TenantId: cultivateTenantID(ctx)}).Scan(&catalog); err != nil { + return + } + if catalog.Id == 0 { + return nil, gerror.New("花种不存在") + } + res = &sysin.CultivateFlowerViewModel{CultivateFlowerEditInp: sysin.CultivateFlowerEditInp{Id: catalog.Id, FlowerCode: catalog.FlowerCode, FlowerName: catalog.FlowerName, FlowerDesc: catalog.FlowerDesc, IconFileId: catalog.IconFileId, Status: catalog.Status, DailyWaterLimit: catalog.DailyWaterLimit, DailyFertilizeLimit: catalog.DailyFertilizeLimit, ShareConfig: catalog.ShareConfig, SortNo: catalog.SortNo}, ConfigVersion: catalog.ConfigVersion, CreatedAt: catalog.CreatedAt, UpdatedAt: catalog.UpdatedAt} + rc := dao.FlowerStageRule.Columns() + var rules []*entity.FlowerStageRule + if err = dao.FlowerStageRule.Ctx(ctx).Where(g.Map{rc.TenantId: cultivateTenantID(ctx), rc.FlowerCatalogId: catalog.Id}).OrderAsc(rc.SortNo).OrderAsc(rc.Id).Scan(&rules); err != nil { + return + } + for _, rule := range rules { + actions := []string{} + if rule.AllowedActions != nil { + _ = json.Unmarshal(rule.AllowedActions.MustToJson(), &actions) + } + res.StageRules = append(res.StageRules, &sysin.CultivateStageRuleEditInp{Id: rule.Id, Stage: rule.Stage, NextStage: rule.NextStage, RequiredPoints: rule.RequiredPoints, WaterPoints: rule.WaterPoints, FertilizePoints: rule.FertilizePoints, AllowedActions: actions, ImageFileId: rule.ImageFileId, AnimationFileId: rule.AnimationFileId, ProgressTextTemplate: rule.ProgressTextTemplate, CompletionText: rule.CompletionText, SortNo: rule.SortNo}) + } + return +} + +func (s *sSysCultivateFlower) Edit(ctx context.Context, in *sysin.CultivateFlowerEditInp) (err error) { + tenantID := cultivateTenantID(ctx) + operatorID := contexts.GetUserId(ctx) + now := time.Now().UTC() + version := "cat_" + now.Format("20060102_150405") + return dao.FlowerCatalog.Transaction(ctx, func(txCtx context.Context, tx gdb.TX) error { + c := dao.FlowerCatalog.Columns() + var before entity.FlowerCatalog + if in.Id > 0 { + if e := tx.Model(dao.FlowerCatalog.Table()).Where(g.Map{c.Id: in.Id, c.TenantId: tenantID}).LockUpdate().Scan(&before); e != nil { + return e + } + if before.Id == 0 { + return gerror.New("花种不存在") + } + if before.FlowerCode != in.FlowerCode { + return gerror.New("花种编码创建后不可修改") + } + } + shareJSON := "{}" + if in.ShareConfig != nil { + shareJSON = in.ShareConfig.MustToJsonString() + } + data := g.Map{c.FlowerName: in.FlowerName, c.FlowerDesc: in.FlowerDesc, c.IconFileId: in.IconFileId, c.Status: in.Status, c.ConfigVersion: version, c.DailyWaterLimit: in.DailyWaterLimit, c.DailyFertilizeLimit: in.DailyFertilizeLimit, c.ShareConfig: shareJSON, c.SortNo: in.SortNo, c.UpdatedAt: now} + if in.Status == "online" { + data[c.OnlineAt] = now + data[c.OfflineAt] = nil + } else if in.Status == "offline" { + data[c.OfflineAt] = now + } + if in.Id == 0 { + id, e := imtenant.NextSnowflakeID(txCtx) + if e != nil { + return e + } + in.Id = uint64(id) + data[c.Id] = id + data[c.TenantId] = tenantID + data[c.FlowerCode] = in.FlowerCode + data[c.CreatedAt] = now + if _, e = tx.Model(dao.FlowerCatalog.Table()).Data(data).Insert(); e != nil { + return gerror.Wrap(e, "新增花种失败") + } + } else { + if _, e := tx.Model(dao.FlowerCatalog.Table()).Where(g.Map{c.Id: in.Id, c.TenantId: tenantID}).Data(data).Update(); e != nil { + return gerror.Wrap(e, "修改花种失败") + } + } + rc := dao.FlowerStageRule.Columns() + if _, e := tx.Model(dao.FlowerStageRule.Table()).Where(g.Map{rc.TenantId: tenantID, rc.FlowerCatalogId: in.Id}).Delete(); e != nil { + return e + } + for _, rule := range in.StageRules { + id, e := imtenant.NextSnowflakeID(txCtx) + if e != nil { + return e + } + actions, _ := json.Marshal(rule.AllowedActions) + _, e = tx.Model(dao.FlowerStageRule.Table()).Data(g.Map{rc.Id: id, rc.TenantId: tenantID, rc.FlowerCatalogId: in.Id, rc.Stage: rule.Stage, rc.NextStage: rule.NextStage, rc.RequiredPoints: rule.RequiredPoints, rc.WaterPoints: rule.WaterPoints, rc.FertilizePoints: rule.FertilizePoints, rc.AllowedActions: string(actions), rc.ImageFileId: rule.ImageFileId, rc.AnimationFileId: rule.AnimationFileId, rc.ProgressTextTemplate: rule.ProgressTextTemplate, rc.CompletionText: rule.CompletionText, rc.SortNo: rule.SortNo, rc.CreatedAt: now, rc.UpdatedAt: now}).Insert() + if e != nil { + return gerror.Wrap(e, "保存成长阶段失败") + } + } + return writeCultivateOperation(txCtx, tx, tenantID, operatorID, map[bool]string{true: "flower.edit", false: "flower.create"}[before.Id > 0], "flower", fmt.Sprint(in.Id), before, in, "", now) + }) +} + +func (s *sSysCultivateFlower) Status(ctx context.Context, in *sysin.CultivateFlowerStatusInp) error { + tenantID := cultivateTenantID(ctx) + operatorID := contexts.GetUserId(ctx) + now := time.Now().UTC() + return dao.FlowerCatalog.Transaction(ctx, func(txCtx context.Context, tx gdb.TX) error { + c := dao.FlowerCatalog.Columns() + var before entity.FlowerCatalog + if e := tx.Model(dao.FlowerCatalog.Table()).Where(g.Map{c.Id: in.Id, c.TenantId: tenantID}).LockUpdate().Scan(&before); e != nil { + return e + } + if before.Id == 0 { + return gerror.New("花种不存在") + } + data := g.Map{c.Status: in.Status, c.ConfigVersion: "cat_" + now.Format("20060102_150405"), c.UpdatedAt: now} + if in.Status == "online" { + data[c.OnlineAt] = now + data[c.OfflineAt] = nil + } else if in.Status == "offline" { + data[c.OfflineAt] = now + } + if _, e := tx.Model(dao.FlowerCatalog.Table()).Where(c.Id, in.Id).Data(data).Update(); e != nil { + return e + } + return writeCultivateOperation(txCtx, tx, tenantID, operatorID, "flower.status", "flower", fmt.Sprint(in.Id), before, data, in.Reason, now) + }) +} + +func writeCultivateOperation(ctx context.Context, tx gdb.TX, tenantID, operatorID int64, operation, targetType, targetID string, before, after any, reason string, now time.Time) error { + id, e := imtenant.NextSnowflakeID(ctx) + if e != nil { + return e + } + beforeJSON, _ := json.Marshal(before) + afterJSON, _ := json.Marshal(after) + c := dao.AdminOperationLog.Columns() + _, e = tx.Model(dao.AdminOperationLog.Table()).Data(g.Map{c.Id: id, c.TenantId: tenantID, c.OperatorId: operatorID, c.OperationType: operation, c.TargetType: targetType, c.TargetId: targetID, c.RequestId: gctx.CtxId(ctx), c.BeforeSnapshot: gjson.New(beforeJSON).MustToJsonString(), c.AfterSnapshot: gjson.New(afterJSON).MustToJsonString(), c.Reason: reason, c.IpAddress: "", c.UserAgent: "", c.CreatedAt: now}).Insert() + return e +} diff --git a/server/internal/model/do/admin_operation_log.go b/server/internal/model/do/admin_operation_log.go new file mode 100644 index 0000000..c399a41 --- /dev/null +++ b/server/internal/model/do/admin_operation_log.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminOperationLog is the golang structure of table cv_admin_operation_log for DAO operations like Where/Data. +type AdminOperationLog struct { + g.Meta `orm:"table:cv_admin_operation_log, do:true"` + Id any // + TenantId any // + OperatorId any // + OperationType any // + TargetType any // + TargetId any // + RequestId any // + BeforeSnapshot *gjson.Json // + AfterSnapshot *gjson.Json // + Reason any // + IpAddress any // + UserAgent any // + CreatedAt *gtime.Time // +} diff --git a/server/internal/model/do/content_audit_log.go b/server/internal/model/do/content_audit_log.go new file mode 100644 index 0000000..fefee99 --- /dev/null +++ b/server/internal/model/do/content_audit_log.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// ContentAuditLog is the golang structure of table cv_content_audit_log for DAO operations like Where/Data. +type ContentAuditLog struct { + g.Meta `orm:"table:cv_content_audit_log, do:true"` + Id any // + TenantId any // + ObjectType any // + ObjectId any // + AuditRequestId any // + AuditSource any // + StatusBefore any // + StatusAfter any // + ResultCode any // + RiskLabels *gjson.Json // + OperatorId any // + OccurredAt *gtime.Time // + CreatedAt *gtime.Time // +} diff --git a/server/internal/model/do/feed_comment.go b/server/internal/model/do/feed_comment.go new file mode 100644 index 0000000..d3813b0 --- /dev/null +++ b/server/internal/model/do/feed_comment.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedComment is the golang structure of table cv_feed_comment for DAO operations like Where/Data. +type FeedComment struct { + g.Meta `orm:"table:cv_feed_comment, do:true"` + Id any // + TenantId any // + PostId any // + AuthorId any // + ContentText any // + Status any // + AuditStatus any // + AuditRequestId any // + DeletedBy any // + DeleteReason any // + PublishedAt *gtime.Time // + DeletedAt *gtime.Time // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // +} diff --git a/server/internal/model/do/feed_media.go b/server/internal/model/do/feed_media.go new file mode 100644 index 0000000..89740e3 --- /dev/null +++ b/server/internal/model/do/feed_media.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedMedia is the golang structure of table cv_feed_media for DAO operations like Where/Data. +type FeedMedia struct { + g.Meta `orm:"table:cv_feed_media, do:true"` + Id any // + TenantId any // + PostId any // + UserId any // + MediaType any // + FileId any // + ThumbnailFileId any // + Width any // + Height any // + SortNo any // + AuditStatus any // + AuditRequestId any // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // +} diff --git a/server/internal/model/do/feed_post.go b/server/internal/model/do/feed_post.go new file mode 100644 index 0000000..2d29103 --- /dev/null +++ b/server/internal/model/do/feed_post.go @@ -0,0 +1,35 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedPost is the golang structure of table cv_feed_post for DAO operations like Where/Data. +type FeedPost struct { + g.Meta `orm:"table:cv_feed_post, do:true"` + Id any // + TenantId any // + AuthorId any // + ContentText any // + FlowerCode any // + SourceType any // + SourceId any // + Visibility any // + Status any // + AuditStatus any // + AuditRequestId any // + RejectReasonCode any // + LikeCount any // + CommentCount any // + Version any // + PublishedAt *gtime.Time // + DeletedAt *gtime.Time // + TakenDownAt *gtime.Time // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // +} diff --git a/server/internal/model/do/feed_report.go b/server/internal/model/do/feed_report.go new file mode 100644 index 0000000..f728602 --- /dev/null +++ b/server/internal/model/do/feed_report.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedReport is the golang structure of table cv_feed_report for DAO operations like Where/Data. +type FeedReport struct { + g.Meta `orm:"table:cv_feed_report, do:true"` + Id any // + TenantId any // + ReporterId any // + ReportedUserId any // + ObjectType any // + ObjectId any // + ReasonCode any // + Description any // + EvidenceFileIds *gjson.Json // + SourcePage any // + Status any // + HandlerId any // + HandleResult any // + HandledAt *gtime.Time // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // +} diff --git a/server/internal/model/do/flower_catalog.go b/server/internal/model/do/flower_catalog.go new file mode 100644 index 0000000..09f6bf0 --- /dev/null +++ b/server/internal/model/do/flower_catalog.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// FlowerCatalog is the golang structure of table cv_flower_catalog for DAO operations like Where/Data. +type FlowerCatalog struct { + g.Meta `orm:"table:cv_flower_catalog, do:true"` + Id any // + TenantId any // + FlowerCode any // + FlowerName any // + FlowerDesc any // + IconFileId any // + Status any // + ConfigVersion any // + DailyWaterLimit any // + DailyFertilizeLimit any // + ShareConfig *gjson.Json // + SortNo any // + OnlineAt *gtime.Time // + OfflineAt *gtime.Time // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // +} diff --git a/server/internal/model/do/flower_stage_rule.go b/server/internal/model/do/flower_stage_rule.go new file mode 100644 index 0000000..8c1bbd6 --- /dev/null +++ b/server/internal/model/do/flower_stage_rule.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// FlowerStageRule is the golang structure of table cv_flower_stage_rule for DAO operations like Where/Data. +type FlowerStageRule struct { + g.Meta `orm:"table:cv_flower_stage_rule, do:true"` + Id any // + TenantId any // + FlowerCatalogId any // + Stage any // + NextStage any // + RequiredPoints any // + WaterPoints any // + FertilizePoints any // + AllowedActions *gjson.Json // + ImageFileId any // + AnimationFileId any // + ProgressTextTemplate any // + CompletionText any // + SortNo any // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // +} diff --git a/server/internal/model/entity/admin_operation_log.go b/server/internal/model/entity/admin_operation_log.go new file mode 100644 index 0000000..8d00338 --- /dev/null +++ b/server/internal/model/entity/admin_operation_log.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminOperationLog is the golang structure for table admin_operation_log. +type AdminOperationLog struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + OperatorId uint64 `json:"operatorId" orm:"operator_id" description:""` + OperationType string `json:"operationType" orm:"operation_type" description:""` + TargetType string `json:"targetType" orm:"target_type" description:""` + TargetId string `json:"targetId" orm:"target_id" description:""` + RequestId string `json:"requestId" orm:"request_id" description:""` + BeforeSnapshot *gjson.Json `json:"beforeSnapshot" orm:"before_snapshot" description:""` + AfterSnapshot *gjson.Json `json:"afterSnapshot" orm:"after_snapshot" description:""` + Reason string `json:"reason" orm:"reason" description:""` + IpAddress string `json:"ipAddress" orm:"ip_address" description:""` + UserAgent string `json:"userAgent" orm:"user_agent" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` +} diff --git a/server/internal/model/entity/content_audit_log.go b/server/internal/model/entity/content_audit_log.go new file mode 100644 index 0000000..a2dacc5 --- /dev/null +++ b/server/internal/model/entity/content_audit_log.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// ContentAuditLog is the golang structure for table content_audit_log. +type ContentAuditLog struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + ObjectType string `json:"objectType" orm:"object_type" description:""` + ObjectId uint64 `json:"objectId" orm:"object_id" description:""` + AuditRequestId string `json:"auditRequestId" orm:"audit_request_id" description:""` + AuditSource string `json:"auditSource" orm:"audit_source" description:""` + StatusBefore string `json:"statusBefore" orm:"status_before" description:""` + StatusAfter string `json:"statusAfter" orm:"status_after" description:""` + ResultCode string `json:"resultCode" orm:"result_code" description:""` + RiskLabels *gjson.Json `json:"riskLabels" orm:"risk_labels" description:""` + OperatorId uint64 `json:"operatorId" orm:"operator_id" description:""` + OccurredAt *gtime.Time `json:"occurredAt" orm:"occurred_at" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` +} diff --git a/server/internal/model/entity/feed_comment.go b/server/internal/model/entity/feed_comment.go new file mode 100644 index 0000000..1d1b250 --- /dev/null +++ b/server/internal/model/entity/feed_comment.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedComment is the golang structure for table feed_comment. +type FeedComment struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + PostId uint64 `json:"postId" orm:"post_id" description:""` + AuthorId uint64 `json:"authorId" orm:"author_id" description:""` + ContentText string `json:"contentText" orm:"content_text" description:""` + Status string `json:"status" orm:"status" description:""` + AuditStatus string `json:"auditStatus" orm:"audit_status" description:""` + AuditRequestId string `json:"auditRequestId" orm:"audit_request_id" description:""` + DeletedBy uint64 `json:"deletedBy" orm:"deleted_by" description:""` + DeleteReason string `json:"deleteReason" orm:"delete_reason" description:""` + PublishedAt *gtime.Time `json:"publishedAt" orm:"published_at" description:""` + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/internal/model/entity/feed_media.go b/server/internal/model/entity/feed_media.go new file mode 100644 index 0000000..3fb3343 --- /dev/null +++ b/server/internal/model/entity/feed_media.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedMedia is the golang structure for table feed_media. +type FeedMedia struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + PostId uint64 `json:"postId" orm:"post_id" description:""` + UserId uint64 `json:"userId" orm:"user_id" description:""` + MediaType string `json:"mediaType" orm:"media_type" description:""` + FileId string `json:"fileId" orm:"file_id" description:""` + ThumbnailFileId string `json:"thumbnailFileId" orm:"thumbnail_file_id" description:""` + Width uint `json:"width" orm:"width" description:""` + Height uint `json:"height" orm:"height" description:""` + SortNo uint `json:"sortNo" orm:"sort_no" description:""` + AuditStatus string `json:"auditStatus" orm:"audit_status" description:""` + AuditRequestId string `json:"auditRequestId" orm:"audit_request_id" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/internal/model/entity/feed_post.go b/server/internal/model/entity/feed_post.go new file mode 100644 index 0000000..87be5d2 --- /dev/null +++ b/server/internal/model/entity/feed_post.go @@ -0,0 +1,33 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedPost is the golang structure for table feed_post. +type FeedPost struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + AuthorId uint64 `json:"authorId" orm:"author_id" description:""` + ContentText string `json:"contentText" orm:"content_text" description:""` + FlowerCode string `json:"flowerCode" orm:"flower_code" description:""` + SourceType string `json:"sourceType" orm:"source_type" description:""` + SourceId uint64 `json:"sourceId" orm:"source_id" description:""` + Visibility string `json:"visibility" orm:"visibility" description:""` + Status string `json:"status" orm:"status" description:""` + AuditStatus string `json:"auditStatus" orm:"audit_status" description:""` + AuditRequestId string `json:"auditRequestId" orm:"audit_request_id" description:""` + RejectReasonCode string `json:"rejectReasonCode" orm:"reject_reason_code" description:""` + LikeCount uint `json:"likeCount" orm:"like_count" description:""` + CommentCount uint `json:"commentCount" orm:"comment_count" description:""` + Version uint `json:"version" orm:"version" description:""` + PublishedAt *gtime.Time `json:"publishedAt" orm:"published_at" description:""` + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""` + TakenDownAt *gtime.Time `json:"takenDownAt" orm:"taken_down_at" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/internal/model/entity/feed_report.go b/server/internal/model/entity/feed_report.go new file mode 100644 index 0000000..68bd200 --- /dev/null +++ b/server/internal/model/entity/feed_report.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// FeedReport is the golang structure for table feed_report. +type FeedReport struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + ReporterId uint64 `json:"reporterId" orm:"reporter_id" description:""` + ReportedUserId uint64 `json:"reportedUserId" orm:"reported_user_id" description:""` + ObjectType string `json:"objectType" orm:"object_type" description:""` + ObjectId string `json:"objectId" orm:"object_id" description:""` + ReasonCode string `json:"reasonCode" orm:"reason_code" description:""` + Description string `json:"description" orm:"description" description:""` + EvidenceFileIds *gjson.Json `json:"evidenceFileIds" orm:"evidence_file_ids" description:""` + SourcePage string `json:"sourcePage" orm:"source_page" description:""` + Status string `json:"status" orm:"status" description:""` + HandlerId uint64 `json:"handlerId" orm:"handler_id" description:""` + HandleResult string `json:"handleResult" orm:"handle_result" description:""` + HandledAt *gtime.Time `json:"handledAt" orm:"handled_at" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/internal/model/entity/flower_catalog.go b/server/internal/model/entity/flower_catalog.go new file mode 100644 index 0000000..3703e7c --- /dev/null +++ b/server/internal/model/entity/flower_catalog.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// FlowerCatalog is the golang structure for table flower_catalog. +type FlowerCatalog struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + FlowerCode string `json:"flowerCode" orm:"flower_code" description:""` + FlowerName string `json:"flowerName" orm:"flower_name" description:""` + FlowerDesc string `json:"flowerDesc" orm:"flower_desc" description:""` + IconFileId string `json:"iconFileId" orm:"icon_file_id" description:""` + Status string `json:"status" orm:"status" description:""` + ConfigVersion string `json:"configVersion" orm:"config_version" description:""` + DailyWaterLimit uint `json:"dailyWaterLimit" orm:"daily_water_limit" description:""` + DailyFertilizeLimit uint `json:"dailyFertilizeLimit" orm:"daily_fertilize_limit" description:""` + ShareConfig *gjson.Json `json:"shareConfig" orm:"share_config" description:""` + SortNo int `json:"sortNo" orm:"sort_no" description:""` + OnlineAt *gtime.Time `json:"onlineAt" orm:"online_at" description:""` + OfflineAt *gtime.Time `json:"offlineAt" orm:"offline_at" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/internal/model/entity/flower_stage_rule.go b/server/internal/model/entity/flower_stage_rule.go new file mode 100644 index 0000000..bd9bfbd --- /dev/null +++ b/server/internal/model/entity/flower_stage_rule.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// FlowerStageRule is the golang structure for table flower_stage_rule. +type FlowerStageRule struct { + Id uint64 `json:"id" orm:"id" description:""` + TenantId uint64 `json:"tenantId" orm:"tenant_id" description:""` + FlowerCatalogId uint64 `json:"flowerCatalogId" orm:"flower_catalog_id" description:""` + Stage string `json:"stage" orm:"stage" description:""` + NextStage string `json:"nextStage" orm:"next_stage" description:""` + RequiredPoints uint `json:"requiredPoints" orm:"required_points" description:""` + WaterPoints uint `json:"waterPoints" orm:"water_points" description:""` + FertilizePoints uint `json:"fertilizePoints" orm:"fertilize_points" description:""` + AllowedActions *gjson.Json `json:"allowedActions" orm:"allowed_actions" description:""` + ImageFileId string `json:"imageFileId" orm:"image_file_id" description:""` + AnimationFileId string `json:"animationFileId" orm:"animation_file_id" description:""` + ProgressTextTemplate string `json:"progressTextTemplate" orm:"progress_text_template" description:""` + CompletionText string `json:"completionText" orm:"completion_text" description:""` + SortNo int `json:"sortNo" orm:"sort_no" description:""` + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""` +} diff --git a/server/internal/model/input/sysin/cultivate_content.go b/server/internal/model/input/sysin/cultivate_content.go new file mode 100644 index 0000000..10946a1 --- /dev/null +++ b/server/internal/model/input/sysin/cultivate_content.go @@ -0,0 +1,149 @@ +package sysin + +import ( + "context" + "strconv" + "strings" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + + "hotgo/internal/model/input/form" +) + +type CultivateContentListInp struct { + form.PageReq + ObjectType string `json:"objectType" d:"feed_post"` + AuthorId string `json:"authorId"` + Status string `json:"status"` + Keyword string `json:"keyword"` + CreatedAt []*gtime.Time `json:"createdAt"` +} + +func (in *CultivateContentListInp) Filter(context.Context) error { + in.ObjectType = strings.TrimSpace(in.ObjectType) + if in.ObjectType != "feed_post" && in.ObjectType != "feed_comment" { + return gerror.New("内容类型不正确") + } + if in.AuthorId != "" { + if _, err := strconv.ParseUint(in.AuthorId, 10, 64); err != nil { + return gerror.New("作者ID不正确") + } + } + return nil +} + +type CultivateContentListModel struct { + Id string `json:"id"` + ObjectType string `json:"objectType"` + PostId string `json:"postId"` + AuthorId string `json:"authorId"` + ContentText string `json:"contentText"` + FlowerCode string `json:"flowerCode"` + Visibility string `json:"visibility"` + Status string `json:"status"` + AuditStatus string `json:"auditStatus"` + RejectReason string `json:"rejectReason"` + LikeCount uint `json:"likeCount"` + CommentCount uint `json:"commentCount"` + CreatedAt *gtime.Time `json:"createdAt"` + UpdatedAt *gtime.Time `json:"updatedAt"` +} + +type CultivateContentReviewInp struct { + ObjectType string `json:"objectType" v:"required|in:feed_post,feed_comment#内容类型不能为空|内容类型不正确"` + Id string `json:"id" v:"required#内容ID不能为空"` + Action string `json:"action" v:"required|in:approve,reject,take_down,restore#审核动作不能为空|审核动作不正确"` + Reason string `json:"reason"` + ObjectId uint64 `json:"-"` +} + +func (in *CultivateContentReviewInp) Filter(context.Context) error { + id, err := strconv.ParseUint(strings.TrimSpace(in.Id), 10, 64) + if err != nil || id == 0 { + return gerror.New("内容ID不正确") + } + in.ObjectId = id + in.Reason = strings.TrimSpace(in.Reason) + if (in.Action == "reject" || in.Action == "take_down") && in.Reason == "" { + return gerror.New("拒绝或下架时必须填写原因") + } + return nil +} + +type CultivateReportListInp struct { + form.PageReq + ObjectType string `json:"objectType"` + Status string `json:"status"` + ReporterId string `json:"reporterId"` + CreatedAt []*gtime.Time `json:"createdAt"` +} + +func (in *CultivateReportListInp) Filter(context.Context) error { + if in.ReporterId != "" { + if _, err := strconv.ParseUint(in.ReporterId, 10, 64); err != nil { + return gerror.New("举报人ID不正确") + } + } + return nil +} + +type CultivateReportListModel struct { + Id string `json:"id"` + ReporterId string `json:"reporterId"` + ReportedUserId string `json:"reportedUserId"` + ObjectType string `json:"objectType"` + ObjectId string `json:"objectId"` + ReasonCode string `json:"reasonCode"` + Description string `json:"description"` + EvidenceFileIds any `json:"evidenceFileIds"` + SourcePage string `json:"sourcePage"` + Status string `json:"status"` + HandlerId string `json:"handlerId"` + HandleResult string `json:"handleResult"` + HandledAt *gtime.Time `json:"handledAt"` + CreatedAt *gtime.Time `json:"createdAt"` +} + +type CultivateReportHandleInp struct { + Id string `json:"id" v:"required#举报ID不能为空"` + Action string `json:"action" v:"required|in:processing,resolve,reject#处理动作不能为空|处理动作不正确"` + HandleResult string `json:"handleResult"` + ReportId uint64 `json:"-"` +} + +func (in *CultivateReportHandleInp) Filter(context.Context) error { + id, err := strconv.ParseUint(strings.TrimSpace(in.Id), 10, 64) + if err != nil || id == 0 { + return gerror.New("举报ID不正确") + } + in.ReportId = id + in.HandleResult = strings.TrimSpace(in.HandleResult) + if in.Action != "processing" && in.HandleResult == "" { + return gerror.New("办结举报时必须填写处理结果") + } + return nil +} + +type CultivateOperationLogListInp struct { + form.PageReq + OperatorId string `json:"operatorId"` + OperationType string `json:"operationType"` + TargetType string `json:"targetType"` + CreatedAt []*gtime.Time `json:"createdAt"` +} + +func (*CultivateOperationLogListInp) Filter(context.Context) error { return nil } + +type CultivateOperationLogListModel struct { + Id string `json:"id"` + OperatorId string `json:"operatorId"` + OperationType string `json:"operationType"` + TargetType string `json:"targetType"` + TargetId string `json:"targetId"` + RequestId string `json:"requestId"` + BeforeSnapshot any `json:"beforeSnapshot"` + AfterSnapshot any `json:"afterSnapshot"` + Reason string `json:"reason"` + CreatedAt *gtime.Time `json:"createdAt"` +} diff --git a/server/internal/model/input/sysin/cultivate_flower.go b/server/internal/model/input/sysin/cultivate_flower.go new file mode 100644 index 0000000..c0764b7 --- /dev/null +++ b/server/internal/model/input/sysin/cultivate_flower.go @@ -0,0 +1,155 @@ +package sysin + +import ( + "context" + "strings" + + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + + "hotgo/internal/model/input/form" +) + +type CultivateStageRuleEditInp struct { + Id uint64 `json:"id"` + Stage string `json:"stage"` + NextStage string `json:"nextStage"` + RequiredPoints uint `json:"requiredPoints"` + WaterPoints uint `json:"waterPoints"` + FertilizePoints uint `json:"fertilizePoints"` + AllowedActions []string `json:"allowedActions"` + ImageFileId string `json:"imageFileId"` + AnimationFileId string `json:"animationFileId"` + ProgressTextTemplate string `json:"progressTextTemplate"` + CompletionText string `json:"completionText"` + SortNo int `json:"sortNo"` +} + +type CultivateFlowerEditInp struct { + Id uint64 `json:"id"` + FlowerCode string `json:"flowerCode"` + FlowerName string `json:"flowerName"` + FlowerDesc string `json:"flowerDesc"` + IconFileId string `json:"iconFileId"` + Status string `json:"status"` + DailyWaterLimit uint `json:"dailyWaterLimit"` + DailyFertilizeLimit uint `json:"dailyFertilizeLimit"` + ShareConfig *gjson.Json `json:"shareConfig"` + SortNo int `json:"sortNo"` + StageRules []*CultivateStageRuleEditInp `json:"stageRules"` +} + +func (in *CultivateFlowerEditInp) Filter(ctx context.Context) error { + in.FlowerCode = strings.TrimSpace(in.FlowerCode) + in.FlowerName = strings.TrimSpace(in.FlowerName) + if in.FlowerCode == "" || in.FlowerName == "" { + return gerror.New("花种编码和名称不能为空") + } + validStatus := map[string]bool{"online": true, "offline": true, "activity_only": true, "maintenance": true} + if !validStatus[in.Status] { + return gerror.New("花种状态不正确") + } + if len(in.StageRules) == 0 { + return gerror.New("至少配置一个成长阶段") + } + validStage := map[string]bool{"seed": true, "sprout": true, "bud": true, "bloom": true} + validAction := map[string]bool{"water": true, "fertilize": true} + seen := map[string]bool{} + for _, rule := range in.StageRules { + if rule == nil || !validStage[rule.Stage] { + return gerror.New("成长阶段不正确") + } + if seen[rule.Stage] { + return gerror.New("成长阶段不能重复") + } + seen[rule.Stage] = true + if rule.Stage != "bloom" && rule.RequiredPoints == 0 { + return gerror.New("非开花阶段升级阈值必须大于0") + } + if rule.NextStage != "" && !validStage[rule.NextStage] { + return gerror.New("下一阶段不正确") + } + if rule.Stage != "bloom" && len(rule.AllowedActions) == 0 { + return gerror.New("非开花阶段至少允许一种成长动作") + } + for _, action := range rule.AllowedActions { + if !validAction[action] { + return gerror.New("成长动作不正确") + } + } + } + stage := "seed" + visited := map[string]bool{} + for stage != "" { + if visited[stage] { + return gerror.New("成长阶段链不能形成循环") + } + visited[stage] = true + var next string + found := false + for _, r := range in.StageRules { + if r.Stage == stage { + next = r.NextStage + found = true + break + } + } + if !found { + return gerror.New("成长阶段链必须从 seed 连续配置") + } + stage = next + } + if !visited["bloom"] { + return gerror.New("成长阶段链必须以 bloom 结束") + } + return nil +} + +type CultivateFlowerListInp struct { + form.PageReq + FlowerCode string `json:"flowerCode"` + FlowerName string `json:"flowerName"` + Status string `json:"status"` + ConfigVersion string `json:"configVersion"` + CreatedAt []*gtime.Time `json:"createdAt"` +} + +func (*CultivateFlowerListInp) Filter(context.Context) error { return nil } + +type CultivateFlowerListModel struct { + Id uint64 `json:"id"` + FlowerCode string `json:"flowerCode"` + FlowerName string `json:"flowerName"` + FlowerDesc string `json:"flowerDesc"` + IconFileId string `json:"iconFileId"` + Status string `json:"status"` + ConfigVersion string `json:"configVersion"` + DailyWaterLimit uint `json:"dailyWaterLimit"` + DailyFertilizeLimit uint `json:"dailyFertilizeLimit"` + SortNo int `json:"sortNo"` + StageCount int `json:"stageCount"` + CreatedAt *gtime.Time `json:"createdAt"` + UpdatedAt *gtime.Time `json:"updatedAt"` +} + +type CultivateFlowerViewInp struct { + Id uint64 `json:"id" v:"required#ID不能为空"` +} + +func (*CultivateFlowerViewInp) Filter(context.Context) error { return nil } + +type CultivateFlowerViewModel struct { + CultivateFlowerEditInp + ConfigVersion string `json:"configVersion"` + CreatedAt *gtime.Time `json:"createdAt"` + UpdatedAt *gtime.Time `json:"updatedAt"` +} + +type CultivateFlowerStatusInp struct { + Id uint64 `json:"id" v:"required#ID不能为空"` + Status string `json:"status" v:"required|in:online,offline,activity_only,maintenance#状态不能为空|状态不正确"` + Reason string `json:"reason"` +} + +func (*CultivateFlowerStatusInp) Filter(context.Context) error { return nil } diff --git a/server/internal/router/genrouter/cultivate_content.go b/server/internal/router/genrouter/cultivate_content.go new file mode 100644 index 0000000..c92986a --- /dev/null +++ b/server/internal/router/genrouter/cultivate_content.go @@ -0,0 +1,5 @@ +package genrouter + +import "hotgo/internal/controller/admin/sys" + +func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.CultivateContent) } diff --git a/server/internal/router/genrouter/cultivate_flower.go b/server/internal/router/genrouter/cultivate_flower.go new file mode 100644 index 0000000..d63341c --- /dev/null +++ b/server/internal/router/genrouter/cultivate_flower.go @@ -0,0 +1,5 @@ +package genrouter + +import "hotgo/internal/controller/admin/sys" + +func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.CultivateFlower) } diff --git a/server/internal/service/sys.go b/server/internal/service/sys.go index 303f564..0ff1412 100644 --- a/server/internal/service/sys.go +++ b/server/internal/service/sys.go @@ -172,6 +172,19 @@ type ( // Switch 更新CURD列表开关 Switch(ctx context.Context, in *sysin.CurdDemoSwitchInp) (err error) } + ISysCultivateFlower interface { + List(ctx context.Context, in *sysin.CultivateFlowerListInp) (list []*sysin.CultivateFlowerListModel, totalCount int, err error) + View(ctx context.Context, in *sysin.CultivateFlowerViewInp) (res *sysin.CultivateFlowerViewModel, err error) + Edit(ctx context.Context, in *sysin.CultivateFlowerEditInp) (err error) + Status(ctx context.Context, in *sysin.CultivateFlowerStatusInp) (err error) + } + ISysCultivateContent interface { + List(ctx context.Context, in *sysin.CultivateContentListInp) (list []*sysin.CultivateContentListModel, totalCount int, err error) + Review(ctx context.Context, in *sysin.CultivateContentReviewInp) error + ReportList(ctx context.Context, in *sysin.CultivateReportListInp) (list []*sysin.CultivateReportListModel, totalCount int, err error) + ReportHandle(ctx context.Context, in *sysin.CultivateReportHandleInp) error + LogList(ctx context.Context, in *sysin.CultivateOperationLogListInp) (list []*sysin.CultivateOperationLogListModel, totalCount int, err error) + } ISysImTenant interface { // Model IM租户ORM模型 Model(ctx context.Context, option ...*handler.Option) *gdb.Model @@ -767,6 +780,8 @@ var ( localSysCron ISysCron localSysCronGroup ISysCronGroup localSysCurdDemo ISysCurdDemo + localSysCultivateFlower ISysCultivateFlower + localSysCultivateContent ISysCultivateContent localSysImTenant ISysImTenant localSysImRegistration ISysImRegistration localSysImInvite ISysImInvite @@ -901,6 +916,26 @@ func RegisterSysCurdDemo(i ISysCurdDemo) { localSysCurdDemo = i } +func SysCultivateFlower() ISysCultivateFlower { + if localSysCultivateFlower == nil { + panic("implement not found for interface ISysCultivateFlower, forgot register?") + } + return localSysCultivateFlower +} + +func RegisterSysCultivateFlower(i ISysCultivateFlower) { + localSysCultivateFlower = i +} + +func SysCultivateContent() ISysCultivateContent { + if localSysCultivateContent == nil { + panic("implement not found for interface ISysCultivateContent, forgot register?") + } + return localSysCultivateContent +} + +func RegisterSysCultivateContent(i ISysCultivateContent) { localSysCultivateContent = i } + func SysImTenant() ISysImTenant { if localSysImTenant == nil { panic("implement not found for interface ISysImTenant, forgot register?") diff --git a/server/manifest/config/config.example.yaml b/server/manifest/config/config.example.yaml index 2e19c79..b0e0584 100644 --- a/server/manifest/config/config.example.yaml +++ b/server/manifest/config/config.example.yaml @@ -240,6 +240,9 @@ database: link: "mysql:root:${MYSQL_PASSWORD}@tcp(mysql.118im.com:30306)/hotgo?loc=Local&parseTime=true&charset=utf8mb4" debug: true Prefix: "hg_" + cultivate: + link: "mysql:root:${MYSQL_PASSWORD}@tcp(127.0.0.1:3306)/cultivate?loc=Local&parseTime=true&charset=utf8mb4" + debug: true imRegistry: link: "mysql:root:${MYSQL_PASSWORD}@tcp(mysql.118im.com:30306)/hotgo?loc=Local&parseTime=true&charset=utf8mb4" debug: true diff --git a/server/manifest/config/config.template b/server/manifest/config/config.template index db4b688..18a38b5 100644 --- a/server/manifest/config/config.template +++ b/server/manifest/config/config.template @@ -240,8 +240,14 @@ database: link: "$MYSQL_DSN" debug: true Prefix: "hg_" + cultivate: + link: "$CULTIVATE_MYSQL_DSN" + debug: true +cultivate: + defaultTenantId: 1 + # 链路追踪 jaeger: switch: false # 链路追踪开关,可选:true|false,默认为false diff --git a/server/storage/data/generate/cultivate_menu.sql b/server/storage/data/generate/cultivate_menu.sql new file mode 100644 index 0000000..5a9c457 --- /dev/null +++ b/server/storage/data/generate/cultivate_menu.sql @@ -0,0 +1,47 @@ +-- 养成管理菜单与首期花种配置权限(可重复执行) +SET NAMES utf8mb4; +SET @now := NOW(); + +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,created_at,updated_at) +SELECT 0,1,'','养成管理','cultivateManager','/cultivate','ExperimentOutlined',1,'/cultivate/flowers','','','LAYOUT',1,'',0,0,'',0,0,0,124,'后院养成与物友动态管理',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateManager'); +SET @cultivateId := (SELECT id FROM hg_admin_menu WHERE name='cultivateManager' 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,created_at,updated_at) +SELECT @cultivateId,2,CONCAT('tr_',@cultivateId,' '),'花种配置','cultivateFlowers','flowers','',2,'','/cultivate/flowers/list','','/cultivate/flowers/index',1,'cultivateFlowers',0,0,'',1,0,0,40,'花种、成长阶段、每日限额与素材配置',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateFlowers'); +SET @flowersId := (SELECT id FROM hg_admin_menu WHERE name='cultivateFlowers' 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,created_at,updated_at) +SELECT @flowersId,3,CONCAT('tr_',@cultivateId,' tr_',@flowersId,' '),'查看花种','cultivateFlowersView','','',3,'','/cultivate/flowers/view','','',1,'',0,0,'',0,1,0,30,'',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateFlowersView'); + +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,created_at,updated_at) +SELECT @flowersId,3,CONCAT('tr_',@cultivateId,' tr_',@flowersId,' '),'编辑花种','cultivateFlowersEdit','','',3,'','/cultivate/flowers/edit','','',1,'',0,0,'',0,1,0,20,'',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateFlowersEdit'); + +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,created_at,updated_at) +SELECT @flowersId,3,CONCAT('tr_',@cultivateId,' tr_',@flowersId,' '),'上下架花种','cultivateFlowersStatus','','',3,'','/cultivate/flowers/status','','',1,'',0,0,'',0,1,0,10,'',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateFlowersStatus'); + +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,created_at,updated_at) +SELECT @cultivateId,2,CONCAT('tr_',@cultivateId,' '),'内容审核','cultivateContent','content','',2,'','/cultivate/content/list','','/cultivate/content/index',1,'cultivateContent',0,0,'',1,0,0,30,'物友动态与评论审核管理',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateContent'); +SET @contentId := (SELECT id FROM hg_admin_menu WHERE name='cultivateContent' 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,created_at,updated_at) +SELECT @contentId,3,CONCAT('tr_',@cultivateId,' tr_',@contentId,' '),'审核内容','cultivateContentReview','','',3,'','/cultivate/content/review','','',1,'',0,0,'',0,1,0,20,'',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateContentReview'); + +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,created_at,updated_at) +SELECT @cultivateId,2,CONCAT('tr_',@cultivateId,' '),'举报处理','cultivateReports','reports','',2,'','/cultivate/reports/list','','/cultivate/reports/index',1,'cultivateReports',0,0,'',1,0,0,20,'物友内容与用户举报处理',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateReports'); +SET @reportsId := (SELECT id FROM hg_admin_menu WHERE name='cultivateReports' 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,created_at,updated_at) +SELECT @reportsId,3,CONCAT('tr_',@cultivateId,' tr_',@reportsId,' '),'处理举报','cultivateReportsHandle','','',3,'','/cultivate/reports/handle','','',1,'',0,0,'',0,1,0,20,'',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateReportsHandle'); + +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,created_at,updated_at) +SELECT @cultivateId,2,CONCAT('tr_',@cultivateId,' '),'操作日志','cultivateLogs','logs','',2,'','/cultivate/logs/list','','/cultivate/logs/index',1,'cultivateLogs',0,0,'',1,0,0,10,'养成管理操作审计日志',1,@now,@now +WHERE NOT EXISTS (SELECT 1 FROM hg_admin_menu WHERE name='cultivateLogs'); diff --git a/web/src/api/cultivate/content.ts b/web/src/api/cultivate/content.ts new file mode 100644 index 0000000..ef1a63f --- /dev/null +++ b/web/src/api/cultivate/content.ts @@ -0,0 +1,7 @@ +import { http } from '@/utils/http/axios'; + +export function ContentList(params) { return http.request({ url: '/cultivate/content/list', method: 'get', params }); } +export function ContentReview(params) { return http.request({ url: '/cultivate/content/review', method: 'POST', params }); } +export function ReportList(params) { return http.request({ url: '/cultivate/reports/list', method: 'get', params }); } +export function ReportHandle(params) { return http.request({ url: '/cultivate/reports/handle', method: 'POST', params }); } +export function OperationLogList(params) { return http.request({ url: '/cultivate/logs/list', method: 'get', params }); } diff --git a/web/src/api/cultivate/flowers.ts b/web/src/api/cultivate/flowers.ts new file mode 100644 index 0000000..2fe02d5 --- /dev/null +++ b/web/src/api/cultivate/flowers.ts @@ -0,0 +1,6 @@ +import { http } from '@/utils/http/axios'; + +export function List(params) { return http.request({ url: '/cultivate/flowers/list', method: 'get', params }); } +export function View(params) { return http.request({ url: '/cultivate/flowers/view', method: 'get', params }); } +export function Edit(params) { return http.request({ url: '/cultivate/flowers/edit', method: 'POST', params }); } +export function Status(params) { return http.request({ url: '/cultivate/flowers/status', method: 'POST', params }); } diff --git a/web/src/views/cultivate/content/index.vue b/web/src/views/cultivate/content/index.vue new file mode 100644 index 0000000..1918026 --- /dev/null +++ b/web/src/views/cultivate/content/index.vue @@ -0,0 +1,37 @@ + + + diff --git a/web/src/views/cultivate/content/model.ts b/web/src/views/cultivate/content/model.ts new file mode 100644 index 0000000..6d8f470 --- /dev/null +++ b/web/src/views/cultivate/content/model.ts @@ -0,0 +1,43 @@ +import { computed, h, ref } from 'vue'; +import { NTag } from 'naive-ui'; +import { FormSchema } from '@/components/Form'; +import { useDictStore } from '@/store/modules/dict'; + +const dict = useDictStore(); + +export interface ContentState { + id: string; + objectType: string; + postId: string; + authorId: string; + contentText: string; + flowerCode: string; + visibility: string; + status: string; + auditStatus: string; + rejectReason: string; + likeCount: number; + commentCount: number; + createdAt: string; +} + +export const schemas = ref([ + { field: 'objectType', component: 'NSelect', label: '内容类型', defaultValue: 'feed_post', componentProps: { options: computed(() => dict.getOptions('CultivateContentTypeOptions')) } }, + { field: 'status', component: 'NSelect', label: '状态', componentProps: { options: computed(() => dict.getOptions('CultivateContentStatusOptions')), clearable: true } }, + { field: 'authorId', component: 'NInput', label: '作者ID', componentProps: { placeholder: '请输入作者ID' } }, + { field: 'keyword', component: 'NInput', label: '内容关键词', componentProps: { placeholder: '请输入正文关键词' } }, +]); + +export const columns = [ + { title: '内容ID', key: 'id', width: 190 }, + { title: '类型', key: 'objectType', width: 90, render: (row: ContentState) => dict.getLabel('CultivateContentTypeOptions', row.objectType) }, + { title: '作者ID', key: 'authorId', width: 150 }, + { title: '正文', key: 'contentText', width: 300, ellipsis: { tooltip: true } }, + { title: '可见范围', key: 'visibility', width: 100 }, + { title: '状态', key: 'status', width: 110, render(row: ContentState) { return h(NTag, { type: row.status === 'published' ? 'success' : row.status === 'reviewing' ? 'warning' : row.status === 'rejected' ? 'error' : 'default' }, { default: () => dict.getLabel('CultivateContentStatusOptions', row.status) }); } }, + { title: '点赞', key: 'likeCount', width: 80 }, + { title: '评论', key: 'commentCount', width: 80 }, + { title: '创建时间', key: 'createdAt', width: 180 }, +]; + +export function loadOptions() { dict.loadOptions(['CultivateContentTypeOptions', 'CultivateContentStatusOptions']); } diff --git a/web/src/views/cultivate/flowers/edit.vue b/web/src/views/cultivate/flowers/edit.vue new file mode 100644 index 0000000..a24da02 --- /dev/null +++ b/web/src/views/cultivate/flowers/edit.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/web/src/views/cultivate/flowers/index.vue b/web/src/views/cultivate/flowers/index.vue new file mode 100644 index 0000000..0a4cbe5 --- /dev/null +++ b/web/src/views/cultivate/flowers/index.vue @@ -0,0 +1,36 @@ + + + diff --git a/web/src/views/cultivate/flowers/model.ts b/web/src/views/cultivate/flowers/model.ts new file mode 100644 index 0000000..715accc --- /dev/null +++ b/web/src/views/cultivate/flowers/model.ts @@ -0,0 +1,83 @@ +import { computed, h, ref } from 'vue'; +import { NTag } from 'naive-ui'; +import { cloneDeep } from 'lodash-es'; +import { FormSchema } from '@/components/Form'; +import { useDictStore } from '@/store/modules/dict'; + +const dict = useDictStore(); + +export interface StageRule { + id?: number; + stage: string; + nextStage: string; + requiredPoints: number; + waterPoints: number; + fertilizePoints: number; + allowedActions: string[]; + imageFileId: string; + animationFileId: string; + progressTextTemplate: string; + completionText: string; + sortNo: number; +} + +export class State { + id = 0; + flowerCode = ''; + flowerName = ''; + flowerDesc = ''; + iconFileId = ''; + status = 'offline'; + configVersion = ''; + dailyWaterLimit = 3; + dailyFertilizeLimit = 1; + shareConfig: Record = { can_share_snapshot: true, default_tag: '' }; + sortNo = 0; + stageRules: StageRule[] = defaultStageRules(); + createdAt = ''; + updatedAt = ''; + constructor(state?: Partial) { if (state) Object.assign(this, state); } +} + +export function defaultStageRules(): StageRule[] { + return [ + stageRule('seed', 'sprout', 12, 1, 0, ['water'], 10), + stageRule('sprout', 'bud', 60, 1, 0, ['water'], 20), + stageRule('bud', 'bloom', 90, 1, 5, ['water', 'fertilize'], 30), + stageRule('bloom', '', 0, 0, 0, [], 40), + ]; +} +function stageRule(stage: string, nextStage: string, requiredPoints: number, waterPoints: number, fertilizePoints: number, allowedActions: string[], sortNo: number): StageRule { + return { stage, nextStage, requiredPoints, waterPoints, fertilizePoints, allowedActions, imageFileId: '', animationFileId: '', progressTextTemplate: '', completionText: '', sortNo }; +} +export function newState(state: State | Record | null): State { return state ? new State(cloneDeep(state)) : new State(); } + +export const rules = { + flowerCode: { required: true, trigger: ['blur', 'input'], message: '请输入花种编码' }, + flowerName: { required: true, trigger: ['blur', 'input'], message: '请输入花种名称' }, + status: { required: true, trigger: ['change'], message: '请选择状态' }, +}; + +export const schemas = ref([ + { field: 'flowerCode', component: 'NInput', label: '花种编码', componentProps: { placeholder: '请输入花种编码' } }, + { field: 'flowerName', component: 'NInput', label: '花种名称', componentProps: { placeholder: '请输入花种名称' } }, + { field: 'status', component: 'NSelect', label: '状态', componentProps: { options: computed(() => dict.getOptions('CultivateFlowerStatusOptions')), clearable: true } }, + { field: 'configVersion', component: 'NInput', label: '配置版本', componentProps: { placeholder: '请输入配置版本' } }, +]); + +export const columns = [ + { title: '花种编码', key: 'flowerCode', width: 140 }, + { title: '花种名称', key: 'flowerName', width: 140 }, + { title: '花语/简介', key: 'flowerDesc', width: 240, ellipsis: { tooltip: true } }, + { title: '成长阶段', key: 'stageCount', width: 100 }, + { title: '浇水上限', key: 'dailyWaterLimit', width: 100 }, + { title: '施肥上限', key: 'dailyFertilizeLimit', width: 100 }, + { title: '配置版本', key: 'configVersion', width: 180 }, + { title: '状态', key: 'status', width: 100, render(row: State) { return h(NTag, { type: row.status === 'online' ? 'success' : 'default' }, { default: () => dict.getLabel('CultivateFlowerStatusOptions', row.status) }); } }, + { title: '排序', key: 'sortNo', width: 80 }, + { title: '更新时间', key: 'updatedAt', width: 180 }, +]; + +export function loadOptions() { dict.loadOptions(['CultivateFlowerStatusOptions']); } +export const statusOptions = computed(() => dict.getOptions('CultivateFlowerStatusOptions')); +export const actionOptions = [{ label: '浇水', value: 'water' }, { label: '施肥', value: 'fertilize' }]; diff --git a/web/src/views/cultivate/logs/index.vue b/web/src/views/cultivate/logs/index.vue new file mode 100644 index 0000000..0f34527 --- /dev/null +++ b/web/src/views/cultivate/logs/index.vue @@ -0,0 +1,13 @@ + + diff --git a/web/src/views/cultivate/logs/model.ts b/web/src/views/cultivate/logs/model.ts new file mode 100644 index 0000000..c261243 --- /dev/null +++ b/web/src/views/cultivate/logs/model.ts @@ -0,0 +1,12 @@ +import { ref } from 'vue'; +import { FormSchema } from '@/components/Form'; +export const schemas = ref([ + { field: 'operatorId', component: 'NInput', label: '操作人ID', componentProps: { placeholder: '请输入操作人ID' } }, + { field: 'operationType', component: 'NInput', label: '操作类型', componentProps: { placeholder: '如 content、report、flower' } }, + { field: 'targetType', component: 'NInput', label: '对象类型', componentProps: { placeholder: '请输入对象类型' } }, +]); +export const columns = [ + { title: '日志ID', key: 'id', width: 190 }, { title: '操作人', key: 'operatorId', width: 150 }, { title: '操作类型', key: 'operationType', width: 160 }, + { title: '对象类型', key: 'targetType', width: 130 }, { title: '对象ID', key: 'targetId', width: 190 }, { title: '原因/结果', key: 'reason', width: 260, ellipsis: { tooltip: true } }, + { title: '请求ID', key: 'requestId', width: 220 }, { title: '操作时间', key: 'createdAt', width: 180 }, +]; diff --git a/web/src/views/cultivate/reports/index.vue b/web/src/views/cultivate/reports/index.vue new file mode 100644 index 0000000..e6d1fd6 --- /dev/null +++ b/web/src/views/cultivate/reports/index.vue @@ -0,0 +1,25 @@ + + diff --git a/web/src/views/cultivate/reports/model.ts b/web/src/views/cultivate/reports/model.ts new file mode 100644 index 0000000..5606d89 --- /dev/null +++ b/web/src/views/cultivate/reports/model.ts @@ -0,0 +1,20 @@ +import { computed, h, ref } from 'vue'; +import { NTag } from 'naive-ui'; +import { FormSchema } from '@/components/Form'; +import { useDictStore } from '@/store/modules/dict'; + +const dict = useDictStore(); +export interface ReportState { id: string; reporterId: string; reportedUserId: string; objectType: string; objectId: string; reasonCode: string; description: string; status: string; handlerId: string; handleResult: string; handledAt: string; createdAt: string; } +export const schemas = ref([ + { field: 'objectType', component: 'NSelect', label: '对象类型', componentProps: { options: computed(() => dict.getOptions('CultivateReportObjectTypeOptions')), clearable: true } }, + { field: 'status', component: 'NSelect', label: '处理状态', componentProps: { options: computed(() => dict.getOptions('CultivateReportStatusOptions')), clearable: true } }, + { field: 'reporterId', component: 'NInput', label: '举报人ID', componentProps: { placeholder: '请输入举报人ID' } }, +]); +export const columns = [ + { title: '举报ID', key: 'id', width: 190 }, { title: '举报人', key: 'reporterId', width: 150 }, { title: '被举报人', key: 'reportedUserId', width: 150 }, + { title: '对象', key: 'objectType', width: 90, render: (row: ReportState) => dict.getLabel('CultivateReportObjectTypeOptions', row.objectType) || row.objectType }, + { title: '对象ID', key: 'objectId', width: 190 }, { title: '原因', key: 'reasonCode', width: 120 }, { title: '补充说明', key: 'description', width: 220, ellipsis: { tooltip: true } }, + { title: '状态', key: 'status', width: 100, render(row: ReportState) { return h(NTag, { type: row.status === 'resolved' ? 'success' : row.status === 'submitted' ? 'warning' : 'default' }, { default: () => dict.getLabel('CultivateReportStatusOptions', row.status) }); } }, + { title: '处理结果', key: 'handleResult', width: 220, ellipsis: { tooltip: true } }, { title: '提交时间', key: 'createdAt', width: 180 }, +]; +export function loadOptions() { dict.loadOptions(['CultivateReportObjectTypeOptions', 'CultivateReportStatusOptions']); }