feat(1.0):调试模版消息

This commit is contained in:
summer 2025-10-27 11:05:03 +08:00
parent d469c4a8ab
commit de9acfa863
12 changed files with 658 additions and 58 deletions

View File

@ -34,6 +34,6 @@ eg :
```shell ```shell
# 根目录下执行 # 根目录下执行
go run cmd/gormgen/main.go -dsn "root:api2api..@tcp(sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555)/mini_chat?charset=utf8mb4&parseTime=True&loc=Local" -tables "log_operation,log_request,admin,app_keyword,app_keyword_reply,app_user,app_message_log,mini_program" go run cmd/gormgen/main.go -dsn "root:api2api..@tcp(sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555)/mini_chat?charset=utf8mb4&parseTime=True&loc=Local" -tables "log_operation,log_request,admin,app_keyword,app_keyword_reply,app_user,app_message_log,mini_program,mini_program_access_token"
``` ```

View File

@ -0,0 +1,39 @@
package miniprogram
import (
"fmt"
"github.com/go-resty/resty/v2"
)
type AccessTokenResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
}
// GetAccessToken 获取微信 access_token
// DOC: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
func GetAccessToken(appID, appSecret string, resultStruct interface{}) error {
requestData := map[string]string{}
requestData["grant_type"] = "client_credential"
requestData["appid"] = appID
requestData["secret"] = appSecret
response, err := resty.New().R().
ForceContentType("application/json").
SetHeader("Content-Type", "application/json").
SetQueryParams(requestData).
SetResult(resultStruct).
Get("https://api.weixin.qq.com/cgi-bin/token")
if err != nil {
return err
}
// 检查响应状态码
if response.IsError() {
return fmt.Errorf("服务异常(%d)", response.StatusCode())
}
return nil
}

View File

@ -0,0 +1,16 @@
package miniprogram
import (
"testing"
)
func TestGetAccessToken(t *testing.T) {
res := new(AccessTokenResponse)
err := GetAccessToken("wx26ad074017e1e63f", "026c19ce4f3bb090c56573024c59a8be", res)
if err != nil {
t.Error(err)
}
t.Logf("access_token: %s", res.AccessToken)
t.Logf("expires_in: %d", res.ExpiresIn)
}

View File

@ -0,0 +1,58 @@
package miniprogram
import (
"fmt"
"github.com/go-resty/resty/v2"
)
type SendSubscribeMessageResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
type SendSubscribeMessageRequest struct {
Touser string `json:"touser"`
TemplateID string `json:"template_id"`
Page string `json:"page"`
MiniprogramState string `json:"miniprogram_state"`
Lang string `json:"lang"`
Data struct {
Thing1 struct {
Value string `json:"value"`
} `json:"thing1"`
Time2 struct {
Value string `json:"value"`
} `json:"time2"`
Thing4 struct {
Value string `json:"value"`
} `json:"thing4"`
} `json:"data"`
}
// SendSubscribeMessage 发送订阅消息
// DOC: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html
func SendSubscribeMessage(accessToken string, requestData *SendSubscribeMessageRequest, resultStruct interface{}) error {
response, err := resty.New().R().
ForceContentType("application/json").
SetHeader("Content-Type", "application/json").
SetBody(requestData).
SetResult(resultStruct).
Post(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s", accessToken))
if err != nil {
return err
}
// 检查响应状态码
if response.IsError() {
return fmt.Errorf("服务异常(%d)", response.StatusCode())
}
// 检查响应结果
if response.Result().(*SendSubscribeMessageResponse).Errcode != 0 {
return fmt.Errorf("服务异常(%d): %s", response.Result().(*SendSubscribeMessageResponse).Errcode, response.Result().(*SendSubscribeMessageResponse).Errmsg)
}
return nil
}

View File

@ -0,0 +1,32 @@
package miniprogram
import (
"testing"
)
func TestSendSubscribeMessage(t *testing.T) {
res := new(AccessTokenResponse)
err := GetAccessToken("wx26ad074017e1e63f", "026c19ce4f3bb090c56573024c59a8be", res)
if err != nil {
t.Errorf("获取 access_token 错误: %s", err.Error())
}
sendSubscribeMessageRequest := new(SendSubscribeMessageRequest)
sendSubscribeMessageRequest.Touser = "onjlN4wrsGe09SdRrpl4D_FWBh0I"
sendSubscribeMessageRequest.TemplateID = "9dCV3z7vRPBGm8iMtSXsD7ZVyUjld46w7HTH9zLnzWw"
sendSubscribeMessageRequest.Page = "pages/contact/index"
sendSubscribeMessageRequest.MiniprogramState = "trial"
sendSubscribeMessageRequest.Lang = "zh_CN"
sendSubscribeMessageRequest.Data.Thing1.Value = "测试(CC)"
sendSubscribeMessageRequest.Data.Time2.Value = "2025-10-27"
sendSubscribeMessageRequest.Data.Thing4.Value = "测试(CC)"
sendSubscribeMessageResponse := new(SendSubscribeMessageResponse)
err = SendSubscribeMessage(res.AccessToken, sendSubscribeMessageRequest, sendSubscribeMessageResponse)
if err != nil {
t.Error(err)
}
t.Logf("Errcode: %d", sendSubscribeMessageResponse.Errcode)
t.Logf("Errmsg: %s", sendSubscribeMessageResponse.Errmsg)
}

View File

@ -35,8 +35,8 @@ func newAppMessageLog(db *gorm.DB, opts ...gen.DOOption) appMessageLog {
_appMessageLog.ReceiverID = field.NewString(tableName, "receiver_id") _appMessageLog.ReceiverID = field.NewString(tableName, "receiver_id")
_appMessageLog.MsgType = field.NewInt32(tableName, "msg_type") _appMessageLog.MsgType = field.NewInt32(tableName, "msg_type")
_appMessageLog.Content = field.NewString(tableName, "content") _appMessageLog.Content = field.NewString(tableName, "content")
_appMessageLog.IsRead = field.NewInt32(tableName, "is_read")
_appMessageLog.CreatedAt = field.NewTime(tableName, "created_at") _appMessageLog.CreatedAt = field.NewTime(tableName, "created_at")
_appMessageLog.IsRead = field.NewInt32(tableName, "is_read")
_appMessageLog.fillFieldMap() _appMessageLog.fillFieldMap()
@ -56,8 +56,8 @@ type appMessageLog struct {
ReceiverID field.String // 接收人ID ReceiverID field.String // 接收人ID
MsgType field.Int32 // 消息类型(1:文本 2:图片) MsgType field.Int32 // 消息类型(1:文本 2:图片)
Content field.String // 消息内容 Content field.String // 消息内容
IsRead field.Int32 // 是否已读(0:未读 1:已读)
CreatedAt field.Time // 创建时间 CreatedAt field.Time // 创建时间
IsRead field.Int32 // 是否已读(0:未读 1:已读)
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@ -83,6 +83,7 @@ func (a *appMessageLog) updateTableName(table string) *appMessageLog {
a.MsgType = field.NewInt32(table, "msg_type") a.MsgType = field.NewInt32(table, "msg_type")
a.Content = field.NewString(table, "content") a.Content = field.NewString(table, "content")
a.CreatedAt = field.NewTime(table, "created_at") a.CreatedAt = field.NewTime(table, "created_at")
a.IsRead = field.NewInt32(table, "is_read")
a.fillFieldMap() a.fillFieldMap()
@ -108,8 +109,8 @@ func (a *appMessageLog) fillFieldMap() {
a.fieldMap["receiver_id"] = a.ReceiverID a.fieldMap["receiver_id"] = a.ReceiverID
a.fieldMap["msg_type"] = a.MsgType a.fieldMap["msg_type"] = a.MsgType
a.fieldMap["content"] = a.Content a.fieldMap["content"] = a.Content
a.fieldMap["is_read"] = a.IsRead
a.fieldMap["created_at"] = a.CreatedAt a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["is_read"] = a.IsRead
} }
func (a appMessageLog) clone(db *gorm.DB) appMessageLog { func (a appMessageLog) clone(db *gorm.DB) appMessageLog {

View File

@ -25,6 +25,7 @@ var (
LogOperation *logOperation LogOperation *logOperation
LogRequest *logRequest LogRequest *logRequest
MiniProgram *miniProgram MiniProgram *miniProgram
MiniProgramAccessToken *miniProgramAccessToken
) )
func SetDefault(db *gorm.DB, opts ...gen.DOOption) { func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
@ -37,48 +38,52 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
LogOperation = &Q.LogOperation LogOperation = &Q.LogOperation
LogRequest = &Q.LogRequest LogRequest = &Q.LogRequest
MiniProgram = &Q.MiniProgram MiniProgram = &Q.MiniProgram
MiniProgramAccessToken = &Q.MiniProgramAccessToken
} }
func Use(db *gorm.DB, opts ...gen.DOOption) *Query { func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{ return &Query{
db: db, db: db,
Admin: newAdmin(db, opts...), Admin: newAdmin(db, opts...),
AppKeyword: newAppKeyword(db, opts...), AppKeyword: newAppKeyword(db, opts...),
AppKeywordReply: newAppKeywordReply(db, opts...), AppKeywordReply: newAppKeywordReply(db, opts...),
AppMessageLog: newAppMessageLog(db, opts...), AppMessageLog: newAppMessageLog(db, opts...),
AppUser: newAppUser(db, opts...), AppUser: newAppUser(db, opts...),
LogOperation: newLogOperation(db, opts...), LogOperation: newLogOperation(db, opts...),
LogRequest: newLogRequest(db, opts...), LogRequest: newLogRequest(db, opts...),
MiniProgram: newMiniProgram(db, opts...), MiniProgram: newMiniProgram(db, opts...),
MiniProgramAccessToken: newMiniProgramAccessToken(db, opts...),
} }
} }
type Query struct { type Query struct {
db *gorm.DB db *gorm.DB
Admin admin Admin admin
AppKeyword appKeyword AppKeyword appKeyword
AppKeywordReply appKeywordReply AppKeywordReply appKeywordReply
AppMessageLog appMessageLog AppMessageLog appMessageLog
AppUser appUser AppUser appUser
LogOperation logOperation LogOperation logOperation
LogRequest logRequest LogRequest logRequest
MiniProgram miniProgram MiniProgram miniProgram
MiniProgramAccessToken miniProgramAccessToken
} }
func (q *Query) Available() bool { return q.db != nil } func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query { func (q *Query) clone(db *gorm.DB) *Query {
return &Query{ return &Query{
db: db, db: db,
Admin: q.Admin.clone(db), Admin: q.Admin.clone(db),
AppKeyword: q.AppKeyword.clone(db), AppKeyword: q.AppKeyword.clone(db),
AppKeywordReply: q.AppKeywordReply.clone(db), AppKeywordReply: q.AppKeywordReply.clone(db),
AppMessageLog: q.AppMessageLog.clone(db), AppMessageLog: q.AppMessageLog.clone(db),
AppUser: q.AppUser.clone(db), AppUser: q.AppUser.clone(db),
LogOperation: q.LogOperation.clone(db), LogOperation: q.LogOperation.clone(db),
LogRequest: q.LogRequest.clone(db), LogRequest: q.LogRequest.clone(db),
MiniProgram: q.MiniProgram.clone(db), MiniProgram: q.MiniProgram.clone(db),
MiniProgramAccessToken: q.MiniProgramAccessToken.clone(db),
} }
} }
@ -92,49 +97,52 @@ func (q *Query) WriteDB() *Query {
func (q *Query) ReplaceDB(db *gorm.DB) *Query { func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{ return &Query{
db: db, db: db,
Admin: q.Admin.replaceDB(db), Admin: q.Admin.replaceDB(db),
AppKeyword: q.AppKeyword.replaceDB(db), AppKeyword: q.AppKeyword.replaceDB(db),
AppKeywordReply: q.AppKeywordReply.replaceDB(db), AppKeywordReply: q.AppKeywordReply.replaceDB(db),
AppMessageLog: q.AppMessageLog.replaceDB(db), AppMessageLog: q.AppMessageLog.replaceDB(db),
AppUser: q.AppUser.replaceDB(db), AppUser: q.AppUser.replaceDB(db),
LogOperation: q.LogOperation.replaceDB(db), LogOperation: q.LogOperation.replaceDB(db),
LogRequest: q.LogRequest.replaceDB(db), LogRequest: q.LogRequest.replaceDB(db),
MiniProgram: q.MiniProgram.replaceDB(db), MiniProgram: q.MiniProgram.replaceDB(db),
MiniProgramAccessToken: q.MiniProgramAccessToken.replaceDB(db),
} }
} }
type queryCtx struct { type queryCtx struct {
Admin *adminDo Admin *adminDo
AppKeyword *appKeywordDo AppKeyword *appKeywordDo
AppKeywordReply *appKeywordReplyDo AppKeywordReply *appKeywordReplyDo
AppMessageLog *appMessageLogDo AppMessageLog *appMessageLogDo
AppUser *appUserDo AppUser *appUserDo
LogOperation *logOperationDo LogOperation *logOperationDo
LogRequest *logRequestDo LogRequest *logRequestDo
MiniProgram *miniProgramDo MiniProgram *miniProgramDo
MiniProgramAccessToken *miniProgramAccessTokenDo
} }
func (q *Query) WithContext(ctx context.Context) *queryCtx { func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{ return &queryCtx{
Admin: q.Admin.WithContext(ctx), Admin: q.Admin.WithContext(ctx),
AppKeyword: q.AppKeyword.WithContext(ctx), AppKeyword: q.AppKeyword.WithContext(ctx),
AppKeywordReply: q.AppKeywordReply.WithContext(ctx), AppKeywordReply: q.AppKeywordReply.WithContext(ctx),
AppMessageLog: q.AppMessageLog.WithContext(ctx), AppMessageLog: q.AppMessageLog.WithContext(ctx),
AppUser: q.AppUser.WithContext(ctx), AppUser: q.AppUser.WithContext(ctx),
LogOperation: q.LogOperation.WithContext(ctx), LogOperation: q.LogOperation.WithContext(ctx),
LogRequest: q.LogRequest.WithContext(ctx), LogRequest: q.LogRequest.WithContext(ctx),
MiniProgram: q.MiniProgram.WithContext(ctx), MiniProgram: q.MiniProgram.WithContext(ctx),
MiniProgramAccessToken: q.MiniProgramAccessToken.WithContext(ctx),
} }
} }
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error { func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.ReplaceDB(tx)) }, opts...) return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
} }
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx { func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
tx := q.db.Begin(opts...) tx := q.db.Begin(opts...)
return &QueryTx{Query: q.ReplaceDB(tx), Error: tx.Error} return &QueryTx{Query: q.clone(tx), Error: tx.Error}
} }
type QueryTx struct { type QueryTx struct {

View File

@ -0,0 +1,336 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dao
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"mini-chat/internal/repository/mysql/model"
)
func newMiniProgramAccessToken(db *gorm.DB, opts ...gen.DOOption) miniProgramAccessToken {
_miniProgramAccessToken := miniProgramAccessToken{}
_miniProgramAccessToken.miniProgramAccessTokenDo.UseDB(db, opts...)
_miniProgramAccessToken.miniProgramAccessTokenDo.UseModel(&model.MiniProgramAccessToken{})
tableName := _miniProgramAccessToken.miniProgramAccessTokenDo.TableName()
_miniProgramAccessToken.ALL = field.NewAsterisk(tableName)
_miniProgramAccessToken.ID = field.NewInt32(tableName, "id")
_miniProgramAccessToken.AppID = field.NewString(tableName, "app_id")
_miniProgramAccessToken.AccessToken = field.NewString(tableName, "access_token")
_miniProgramAccessToken.CreatedAt = field.NewTime(tableName, "created_at")
_miniProgramAccessToken.ExpiredAt = field.NewTime(tableName, "expired_at")
_miniProgramAccessToken.fillFieldMap()
return _miniProgramAccessToken
}
// miniProgramAccessToken 小程序 access_token 表
type miniProgramAccessToken struct {
miniProgramAccessTokenDo
ALL field.Asterisk
ID field.Int32 // 主键
AppID field.String // app_id
AccessToken field.String // access_token
CreatedAt field.Time // 创建时间
ExpiredAt field.Time // 过期时间
fieldMap map[string]field.Expr
}
func (m miniProgramAccessToken) Table(newTableName string) *miniProgramAccessToken {
m.miniProgramAccessTokenDo.UseTable(newTableName)
return m.updateTableName(newTableName)
}
func (m miniProgramAccessToken) As(alias string) *miniProgramAccessToken {
m.miniProgramAccessTokenDo.DO = *(m.miniProgramAccessTokenDo.As(alias).(*gen.DO))
return m.updateTableName(alias)
}
func (m *miniProgramAccessToken) updateTableName(table string) *miniProgramAccessToken {
m.ALL = field.NewAsterisk(table)
m.ID = field.NewInt32(table, "id")
m.AppID = field.NewString(table, "app_id")
m.AccessToken = field.NewString(table, "access_token")
m.CreatedAt = field.NewTime(table, "created_at")
m.ExpiredAt = field.NewTime(table, "expired_at")
m.fillFieldMap()
return m
}
func (m *miniProgramAccessToken) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := m.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (m *miniProgramAccessToken) fillFieldMap() {
m.fieldMap = make(map[string]field.Expr, 5)
m.fieldMap["id"] = m.ID
m.fieldMap["app_id"] = m.AppID
m.fieldMap["access_token"] = m.AccessToken
m.fieldMap["created_at"] = m.CreatedAt
m.fieldMap["expired_at"] = m.ExpiredAt
}
func (m miniProgramAccessToken) clone(db *gorm.DB) miniProgramAccessToken {
m.miniProgramAccessTokenDo.ReplaceConnPool(db.Statement.ConnPool)
return m
}
func (m miniProgramAccessToken) replaceDB(db *gorm.DB) miniProgramAccessToken {
m.miniProgramAccessTokenDo.ReplaceDB(db)
return m
}
type miniProgramAccessTokenDo struct{ gen.DO }
func (m miniProgramAccessTokenDo) Debug() *miniProgramAccessTokenDo {
return m.withDO(m.DO.Debug())
}
func (m miniProgramAccessTokenDo) WithContext(ctx context.Context) *miniProgramAccessTokenDo {
return m.withDO(m.DO.WithContext(ctx))
}
func (m miniProgramAccessTokenDo) ReadDB() *miniProgramAccessTokenDo {
return m.Clauses(dbresolver.Read)
}
func (m miniProgramAccessTokenDo) WriteDB() *miniProgramAccessTokenDo {
return m.Clauses(dbresolver.Write)
}
func (m miniProgramAccessTokenDo) Session(config *gorm.Session) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Session(config))
}
func (m miniProgramAccessTokenDo) Clauses(conds ...clause.Expression) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Clauses(conds...))
}
func (m miniProgramAccessTokenDo) Returning(value interface{}, columns ...string) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Returning(value, columns...))
}
func (m miniProgramAccessTokenDo) Not(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Not(conds...))
}
func (m miniProgramAccessTokenDo) Or(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Or(conds...))
}
func (m miniProgramAccessTokenDo) Select(conds ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Select(conds...))
}
func (m miniProgramAccessTokenDo) Where(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Where(conds...))
}
func (m miniProgramAccessTokenDo) Order(conds ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Order(conds...))
}
func (m miniProgramAccessTokenDo) Distinct(cols ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Distinct(cols...))
}
func (m miniProgramAccessTokenDo) Omit(cols ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Omit(cols...))
}
func (m miniProgramAccessTokenDo) Join(table schema.Tabler, on ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Join(table, on...))
}
func (m miniProgramAccessTokenDo) LeftJoin(table schema.Tabler, on ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.LeftJoin(table, on...))
}
func (m miniProgramAccessTokenDo) RightJoin(table schema.Tabler, on ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.RightJoin(table, on...))
}
func (m miniProgramAccessTokenDo) Group(cols ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Group(cols...))
}
func (m miniProgramAccessTokenDo) Having(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Having(conds...))
}
func (m miniProgramAccessTokenDo) Limit(limit int) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Limit(limit))
}
func (m miniProgramAccessTokenDo) Offset(offset int) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Offset(offset))
}
func (m miniProgramAccessTokenDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Scopes(funcs...))
}
func (m miniProgramAccessTokenDo) Unscoped() *miniProgramAccessTokenDo {
return m.withDO(m.DO.Unscoped())
}
func (m miniProgramAccessTokenDo) Create(values ...*model.MiniProgramAccessToken) error {
if len(values) == 0 {
return nil
}
return m.DO.Create(values)
}
func (m miniProgramAccessTokenDo) CreateInBatches(values []*model.MiniProgramAccessToken, batchSize int) error {
return m.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (m miniProgramAccessTokenDo) Save(values ...*model.MiniProgramAccessToken) error {
if len(values) == 0 {
return nil
}
return m.DO.Save(values)
}
func (m miniProgramAccessTokenDo) First() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) Take() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) Last() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) Find() ([]*model.MiniProgramAccessToken, error) {
result, err := m.DO.Find()
return result.([]*model.MiniProgramAccessToken), err
}
func (m miniProgramAccessTokenDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.MiniProgramAccessToken, err error) {
buf := make([]*model.MiniProgramAccessToken, 0, batchSize)
err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (m miniProgramAccessTokenDo) FindInBatches(result *[]*model.MiniProgramAccessToken, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return m.DO.FindInBatches(result, batchSize, fc)
}
func (m miniProgramAccessTokenDo) Attrs(attrs ...field.AssignExpr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Attrs(attrs...))
}
func (m miniProgramAccessTokenDo) Assign(attrs ...field.AssignExpr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Assign(attrs...))
}
func (m miniProgramAccessTokenDo) Joins(fields ...field.RelationField) *miniProgramAccessTokenDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Joins(_f))
}
return &m
}
func (m miniProgramAccessTokenDo) Preload(fields ...field.RelationField) *miniProgramAccessTokenDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Preload(_f))
}
return &m
}
func (m miniProgramAccessTokenDo) FirstOrInit() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) FirstOrCreate() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) FindByPage(offset int, limit int) (result []*model.MiniProgramAccessToken, count int64, err error) {
result, err = m.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = m.Offset(-1).Limit(-1).Count()
return
}
func (m miniProgramAccessTokenDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = m.Count()
if err != nil {
return
}
err = m.Offset(offset).Limit(limit).Scan(result)
return
}
func (m miniProgramAccessTokenDo) Scan(result interface{}) (err error) {
return m.DO.Scan(result)
}
func (m miniProgramAccessTokenDo) Delete(models ...*model.MiniProgramAccessToken) (result gen.ResultInfo, err error) {
return m.DO.Delete(models)
}
func (m *miniProgramAccessTokenDo) withDO(do gen.Dao) *miniProgramAccessTokenDo {
m.DO = *do.(*gen.DO)
return m
}

View File

@ -20,8 +20,8 @@ type AppMessageLog struct {
ReceiverID string `gorm:"column:receiver_id;not null;comment:接收人ID" json:"receiver_id"` // 接收人ID ReceiverID string `gorm:"column:receiver_id;not null;comment:接收人ID" json:"receiver_id"` // 接收人ID
MsgType int32 `gorm:"column:msg_type;not null;comment:消息类型(1:文本 2:图片)" json:"msg_type"` // 消息类型(1:文本 2:图片) 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"` // 消息内容 Content string `gorm:"column:content;not null;comment:消息内容" json:"content"` // 消息内容
IsRead int32 `gorm:"column:is_read;not null;default:0;comment:是否已读(0:未读 1:已读)" json:"is_read"` // 是否已读(0:未读 1:已读)
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
IsRead int32 `gorm:"column:is_read;comment:是否已读(0:未读 1:已读)" json:"is_read"` // 是否已读(0:未读 1:已读)
} }
// TableName AppMessageLog's table name // TableName AppMessageLog's table name

View File

@ -0,0 +1,25 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
)
const TableNameMiniProgramAccessToken = "mini_program_access_token"
// MiniProgramAccessToken 小程序 access_token 表
type MiniProgramAccessToken struct {
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键
AppID string `gorm:"column:app_id;not null;comment:app_id" json:"app_id"` // app_id
AccessToken string `gorm:"column:access_token;not null;comment:access_token" json:"access_token"` // access_token
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
ExpiredAt time.Time `gorm:"column:expired_at;not null;default:CURRENT_TIMESTAMP;comment:过期时间" json:"expired_at"` // 过期时间
}
// TableName MiniProgramAccessToken's table name
func (*MiniProgramAccessToken) TableName() string {
return TableNameMiniProgramAccessToken
}

View File

@ -0,0 +1,32 @@
package services_miniprogram
import (
"mini-chat/internal/pkg/core"
"mini-chat/internal/pkg/logger"
"mini-chat/internal/repository/mysql"
"mini-chat/internal/repository/mysql/dao"
)
var _ Service = (*service)(nil)
type Service interface {
i()
GetAccessToken(appID, appSecret string, ctx core.Context) (string, error)
}
type service struct {
logger logger.CustomLogger
writeDB *dao.Query
readDB *dao.Query
}
func New(logger logger.CustomLogger, db mysql.Repo) Service {
return &service{
logger: logger,
writeDB: dao.Use(db.GetDbW()),
readDB: dao.Use(db.GetDbR()),
}
}
func (s *service) i() {}

View File

@ -0,0 +1,53 @@
package services_miniprogram
import (
"fmt"
"time"
"mini-chat/internal/pkg/core"
"mini-chat/internal/pkg/miniprogram"
"mini-chat/internal/repository/mysql/model"
"go.uber.org/zap"
"gorm.io/gorm"
)
func (s *service) GetAccessToken(appID, appSecret string, ctx core.Context) (string, error) {
info, err := s.readDB.MiniProgramAccessToken.WithContext(ctx.RequestContext()).
Where(s.readDB.MiniProgramAccessToken.AppID.Eq(appID)).
Where(s.readDB.MiniProgramAccessToken.ExpiredAt.Gte(time.Now())).First()
if err != nil && err != gorm.ErrRecordNotFound {
return "", err
}
accessToken := ""
if err == gorm.ErrRecordNotFound {
// 生成 access_token
accessTokenResponse := new(miniprogram.AccessTokenResponse)
if err := miniprogram.GetAccessToken(appID, appSecret, accessTokenResponse); err != nil {
s.logger.Error("GetAccessToken failed", zap.Error(err))
return "", err
}
if accessTokenResponse.AccessToken == "" {
return "", fmt.Errorf("access_token is empty")
}
// 保存 access_token
accessTokenData := new(model.MiniProgramAccessToken)
accessTokenData.AppID = appID
accessTokenData.AccessToken = accessTokenResponse.AccessToken
accessTokenData.CreatedAt = time.Now()
accessTokenData.ExpiredAt = time.Now().Add(time.Duration(accessTokenResponse.ExpiresIn) * time.Second)
if err := s.writeDB.MiniProgramAccessToken.WithContext(ctx.RequestContext()).Create(accessTokenData); err != nil {
return "", err
}
accessToken = accessTokenResponse.AccessToken
} else {
accessToken = info.AccessToken
}
return accessToken, nil
}