From a2e9d28ae73c30c84c5d2c2ba8a01a216a8e6d02 Mon Sep 17 00:00:00 2001 From: summer <> Date: Thu, 16 Oct 2025 17:16:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(1.0):=20=E6=96=B0=E5=A2=9E=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs.go | 81 +++++++++++++++++++ docs/swagger.json | 81 +++++++++++++++++++ docs/swagger.yaml | 54 +++++++++++++ internal/api/message/message.go | 21 +++++ internal/api/message/message_send_admin.go | 69 ++++++++++++++++ internal/code/code.go | 2 + internal/code/zh-cn.go | 2 + .../mysql/dao/app_message_log.gen.go | 4 +- .../mysql/model/app_message_log.gen.go | 4 +- internal/router/router.go | 4 + 10 files changed, 318 insertions(+), 4 deletions(-) create mode 100644 internal/api/message/message.go create mode 100644 internal/api/message/message_send_admin.go diff --git a/docs/docs.go b/docs/docs.go index e44bc8c..53c1c1c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -625,6 +625,51 @@ const docTemplate = `{ } } }, + "/admin/send_message": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "管理员发送消息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "消息" + ], + "summary": "管理员发送消息", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/message.adminSendMessageRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/message.adminSendMessageResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, "/admin/upload/image": { "post": { "description": "上传图片", @@ -1102,6 +1147,42 @@ const docTemplate = `{ } } }, + "message.adminSendMessageRequest": { + "type": "object", + "required": [ + "app_id", + "content", + "msg_type", + "to_user_id" + ], + "properties": { + "app_id": { + "description": "小程序ID", + "type": "string" + }, + "content": { + "description": "内容", + "type": "string" + }, + "msg_type": { + "description": "消息类型(1:文本 2:图片)", + "type": "integer" + }, + "to_user_id": { + "description": "接收用户ID", + "type": "string" + } + } + }, + "message.adminSendMessageResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, "upload.uploadImageResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 0715dff..a971ca6 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -617,6 +617,51 @@ } } }, + "/admin/send_message": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "管理员发送消息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "消息" + ], + "summary": "管理员发送消息", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/message.adminSendMessageRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/message.adminSendMessageResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, "/admin/upload/image": { "post": { "description": "上传图片", @@ -1094,6 +1139,42 @@ } } }, + "message.adminSendMessageRequest": { + "type": "object", + "required": [ + "app_id", + "content", + "msg_type", + "to_user_id" + ], + "properties": { + "app_id": { + "description": "小程序ID", + "type": "string" + }, + "content": { + "description": "内容", + "type": "string" + }, + "msg_type": { + "description": "消息类型(1:文本 2:图片)", + "type": "integer" + }, + "to_user_id": { + "description": "接收用户ID", + "type": "string" + } + } + }, + "message.adminSendMessageResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, "upload.uploadImageResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1dddb41..87a59da 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -307,6 +307,32 @@ definitions: description: 提示信息 type: string type: object + message.adminSendMessageRequest: + properties: + app_id: + description: 小程序ID + type: string + content: + description: 内容 + type: string + msg_type: + description: 消息类型(1:文本 2:图片) + type: integer + to_user_id: + description: 接收用户ID + type: string + required: + - app_id + - content + - msg_type + - to_user_id + type: object + message.adminSendMessageResponse: + properties: + message: + description: 提示信息 + type: string + type: object upload.uploadImageResponse: properties: preview_image_url: @@ -712,6 +738,34 @@ paths: summary: 管理员登录 tags: - 管理端.登录 + /admin/send_message: + post: + consumes: + - application/json + description: 管理员发送消息 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/message.adminSendMessageRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/message.adminSendMessageResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 管理员发送消息 + tags: + - 消息 /admin/upload/image: post: consumes: diff --git a/internal/api/message/message.go b/internal/api/message/message.go new file mode 100644 index 0000000..8c8dc4f --- /dev/null +++ b/internal/api/message/message.go @@ -0,0 +1,21 @@ +package message + +import ( + "mini-chat/internal/pkg/logger" + "mini-chat/internal/repository/mysql" + "mini-chat/internal/repository/mysql/dao" +) + +type handler struct { + logger logger.CustomLogger + writeDB *dao.Query + readDB *dao.Query +} + +func New(logger logger.CustomLogger, db mysql.Repo) *handler { + return &handler{ + logger: logger, + writeDB: dao.Use(db.GetDbW()), + readDB: dao.Use(db.GetDbR()), + } +} diff --git a/internal/api/message/message_send_admin.go b/internal/api/message/message_send_admin.go new file mode 100644 index 0000000..4d5d65e --- /dev/null +++ b/internal/api/message/message_send_admin.go @@ -0,0 +1,69 @@ +package message + +import ( + "fmt" + "net/http" + "time" + + "mini-chat/internal/code" + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/validation" + "mini-chat/internal/repository/mysql/model" +) + +type adminSendMessageRequest struct { + AppID string `json:"app_id" binding:"required"` // 小程序ID + ToUserID string `json:"to_user_id" binding:"required"` // 接收用户ID + MsgType int32 `json:"msg_type" binding:"required"` // 消息类型(1:文本 2:图片) + Content string `json:"content" binding:"required"` // 内容 +} + +type adminSendMessageResponse struct { + Message string `json:"message"` // 提示信息 +} + +// AdminSendMessage 管理员发送消息 +// @Summary 管理员发送消息 +// @Description 管理员发送消息 +// @Tags 消息 +// @Accept json +// @Produce json +// @Param RequestBody body adminSendMessageRequest true "请求参数" +// @Success 200 {object} adminSendMessageResponse +// @Failure 400 {object} code.Failure +// @Router /admin/send_message [post] +// @Security LoginVerifyToken +func (h *handler) AdminSendMessage() core.HandlerFunc { + return func(ctx core.Context) { + req := new(adminSendMessageRequest) + res := new(adminSendMessageResponse) + if err := ctx.ShouldBindJSON(req); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ParamBindError, + validation.Error(err)), + ) + return + } + + createData := new(model.AppMessageLog) + createData.AppID = req.AppID + createData.SenderID = "888888" + createData.SenderName = "平台" + createData.Content = req.Content + createData.ReceiverID = req.ToUserID + createData.MsgType = req.MsgType + createData.SendTime = time.Now() + createData.CreatedAt = time.Now() + if err := h.writeDB.AppMessageLog.WithContext(ctx.RequestContext()).Create(createData); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.SendMessageError, + fmt.Sprintf("%s: %s", code.Text(code.SendMessageError), err.Error()), + )) + } + + res.Message = "操作成功" + ctx.Payload(res) + } +} diff --git a/internal/code/code.go b/internal/code/code.go index 1c281e8..d4f94ff 100644 --- a/internal/code/code.go +++ b/internal/code/code.go @@ -35,6 +35,8 @@ const ( ListKeywordMaterialError = 20306 ModifyKeywordMaterialError = 20307 DeleteKeywordMaterialError = 20308 + + SendMessageError = 20401 ) func Text(code int) string { diff --git a/internal/code/zh-cn.go b/internal/code/zh-cn.go index 425a461..bf89653 100644 --- a/internal/code/zh-cn.go +++ b/internal/code/zh-cn.go @@ -21,4 +21,6 @@ var zhCNText = map[int]string{ DeleteKeywordMaterialError: "删除关键字素材失败", ListKeywordMaterialError: "获取关键字素材列表失败", ModifyKeywordMaterialError: "修改关键字素材失败", + + SendMessageError: "发送消息失败", } diff --git a/internal/repository/mysql/dao/app_message_log.gen.go b/internal/repository/mysql/dao/app_message_log.gen.go index e90a2b6..4543d91 100644 --- a/internal/repository/mysql/dao/app_message_log.gen.go +++ b/internal/repository/mysql/dao/app_message_log.gen.go @@ -53,8 +53,8 @@ type appMessageLog struct { SenderName field.String // 发送人昵称 SendTime field.Time // 发送时间 ReceiverID field.String // 接收人ID - MsgType field.Int32 // 信息类型 - Content field.String // 内容 + MsgType field.Int32 // 消息类型(1:文本 2:图片) + Content field.String // 消息内容 CreatedAt field.Time // 创建时间 fieldMap map[string]field.Expr diff --git a/internal/repository/mysql/model/app_message_log.gen.go b/internal/repository/mysql/model/app_message_log.gen.go index 9e3a5cc..1775a84 100644 --- a/internal/repository/mysql/model/app_message_log.gen.go +++ b/internal/repository/mysql/model/app_message_log.gen.go @@ -18,8 +18,8 @@ type AppMessageLog struct { SenderName string `gorm:"column:sender_name;not null;comment:发送人昵称" json:"sender_name"` // 发送人昵称 SendTime time.Time `gorm:"column:send_time;comment:发送时间" json:"send_time"` // 发送时间 ReceiverID string `gorm:"column:receiver_id;not null;comment:接收人ID" json:"receiver_id"` // 接收人ID - MsgType int32 `gorm:"column:msg_type;not null;comment:信息类型" json:"msg_type"` // 信息类型 - Content string `gorm:"column:content;not null;comment:内容" json:"content"` // 内容 + MsgType int32 `gorm:"column:msg_type;not null;comment:消息类型(1:文本 2:图片)" json:"msg_type"` // 消息类型(1:文本 2:图片) + Content string `gorm:"column:content;not null;comment:消息内容" json:"content"` // 消息内容 CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 } diff --git a/internal/router/router.go b/internal/router/router.go index 911f872..1135418 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -5,6 +5,7 @@ import ( "mini-chat/internal/api/admin" "mini-chat/internal/api/app" "mini-chat/internal/api/keyword" + "mini-chat/internal/api/message" "mini-chat/internal/api/upload" "mini-chat/internal/cron" "mini-chat/internal/dblogger" @@ -45,6 +46,7 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (co appHandler := app.New(logger, db) uploadHandler := upload.New(logger, db) keywordHandler := keyword.New(logger, db) + messageHandler := message.New(logger, db) // 管理端非认证接口路由组 adminNonAuthApiRouter := mux.Group("/admin") @@ -72,6 +74,8 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (co adminAuthApiRouter.POST("/app/keyword/material/:id", keywordHandler.CreateKeywordMaterial()) // 配置意图关键字素材 adminAuthApiRouter.PUT("/app/keyword/material/:id", keywordHandler.ModifyKeywordMaterial()) // 修改意图关键字素材 adminAuthApiRouter.GET("/app/keyword/materials", keywordHandler.KeywordMaterialPageList()) // 获取意图关键字素材列表 + + adminAuthApiRouter.POST("/send_message", messageHandler.AdminSendMessage()) // 发送消息 } return mux, nil