kobe6258 hace 7 meses
padre
commit
b373f961d3
Se han modificado 47 ficheros con 1334 adiciones y 442 borrados
  1. 28 28
      common/component/cache/redis.go
  2. 21 3
      common/component/component.go
  3. 9 4
      common/component/config/config.go
  4. 11 7
      common/component/config/db_config.go
  5. 20 5
      common/component/config/redis_config.go
  6. 89 0
      common/component/config/sms_config.go
  7. 9 3
      common/component/config/wechat_config.go
  8. 32 6
      common/component/database/db_connector.go
  9. 1 1
      common/component/log/log_plugin.go
  10. 27 0
      common/component/log/log_plugin_test.go
  11. 82 0
      common/component/sms/emas_sms_sender.go
  12. 95 0
      common/component/sms/juhe_sms_sender.go
  13. 0 127
      common/component/wechat/http/request.go
  14. 16 10
      common/component/wechat/we_http/response.go
  15. 60 137
      common/component/wechat/wechat_client.go
  16. 0 5
      common/contants/constants.go
  17. 9 0
      common/contants/contants.go
  18. 39 36
      common/exception/exc_enums.go
  19. 19 0
      common/http/err.go
  20. 29 0
      common/http/status.go
  21. 37 0
      common/utils/auth/auth_utils.go
  22. 9 2
      common/utils/client/http_client.go
  23. 11 0
      common/utils/redis/key_generator.go
  24. 52 0
      common/utils/sms/sms_client.go
  25. 5 1
      common/utils/string/string_utils.go
  26. 69 0
      common/web_socket/ws_client.go
  27. 75 18
      controllers/base_controller.go
  28. 92 0
      controllers/user/auth_controller.go
  29. 16 2
      controllers/user/user_controller.go
  30. 47 0
      controllers/ws_controller.go
  31. 25 0
      domian/sms/emas_sms_service.go
  32. BIN
      eta_mini_ht_api.exe~
  33. 5 0
      facade/user/user_facade.go
  34. 3 2
      go.mod
  35. 2 4
      go.sum
  36. 14 13
      main.go
  37. 1 1
      middleware/auth_middleware.go
  38. 43 0
      models/sms/api_mt_zsyyt.go
  39. 5 0
      models/sms/sms_code.go
  40. 18 0
      routers/commentsRouter.go
  41. 6 1
      routers/router.go
  42. 0 0
      swagger/swagger-ui-bundle.js
  43. 0 0
      swagger/swagger-ui-es-bundle-core.js
  44. 0 0
      swagger/swagger-ui-es-bundle.js
  45. 0 0
      swagger/swagger-ui.js
  46. 117 16
      swagger/swagger.json
  47. 86 10
      swagger/swagger.yml

+ 28 - 28
common/component/cache/redis.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"eta_mini_ht_api/common/component/config"
 	logger "eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/common/contants"
 	"github.com/go-redis/redis/v8"
 	"log"
 	"strings"
@@ -13,40 +14,39 @@ import (
 
 var (
 	redisCache *RedisCache
-	once       sync.Once
+	redisOnce  sync.Once
 )
 
 func GetInstance() *RedisCache {
-	once.Do(func() {
-		redisConf, ok := config.GetConfig("redis").(*config.RedisConfig)
-		// 检查是否成功获取到RedisConfig实例
-		if !ok {
-			logger.Info("加载redis配置失败")
-			return
-		}
-		opts, ok := redisConf.GetConfig().(config.RedisOpts)
-		// 检查Host是否已设置,然后初始化或执行相应操作
-		if ok && opts.Host != "" {
-			logger.Info("初始化redis")
-			// 这里可以添加初始化Redis的逻辑
-			redisCache = newRedis(opts)
-		} else {
-			logger.Info("Redis configuration is incomplete: Host is missing")
-			return
+	redisOnce.Do(func() {
+		// 检查是否成功获取到RedisConfig实例,没有配置则不进行redis初始化
+		if redisConf, ok := config.GetConfig(contants.REDIS).(*config.RedisConfig); ok {
+			if redisConf.GetHost() != "" {
+				logger.Info("初始化redis")
+				// 这里可以添加初始化Redis的逻辑
+				redisCache = newRedis(redisConf)
+				_, err := redisCache.Do("Ping")
+				if err != nil {
+					logger.Warn("redis 链接失败:%v", err)
+				}
+			} else {
+				logger.Info("Redis configuration is incomplete: Host is missing")
+				return
+			}
 		}
 	})
 	return redisCache
 }
-func newRedis(opts config.RedisOpts) *RedisCache {
-	if &opts == nil || opts.Host == "" {
+func newRedis(config *config.RedisConfig) *RedisCache {
+	if &config == nil || config.GetHost() == "" {
 		log.Fatalf("redis 连接失败")
 	}
 	redisTemplate := redis.NewUniversalClient(&redis.UniversalOptions{
-		Addrs:        strings.Split(opts.Host, ";"),
-		DB:           opts.Database,
-		Password:     opts.Password,
-		IdleTimeout:  time.Second * time.Duration(opts.IdleTimeout),
-		MinIdleConns: opts.MaxIdle,
+		Addrs:        strings.Split(config.GetHost(), ","),
+		DB:           config.GetDatabase(),
+		Password:     config.GetPassword(),
+		IdleTimeout:  time.Second * time.Duration(config.GetIdleTimeout()),
+		MinIdleConns: config.GetMaxIdle(),
 	})
 	return &RedisCache{redisTemplate: redisTemplate}
 }
@@ -70,13 +70,13 @@ func (r *RedisCache) GetStringWithContext(ctx context.Context, key string) (valu
 }
 
 // SetString 设置一个值
-func (r *RedisCache) SetString(key string, val string, timeout time.Duration) error {
-	return r.redisTemplate.SetEX(context.Background(), key, val, timeout).Err()
+func (r *RedisCache) SetString(key string, val string, expired int) error {
+	return r.SetStringWithContext(context.Background(), key, val, expired)
 }
 
 // SetStringWithContext  设置一个值
-func (r *RedisCache) SetStringWithContext(ctx context.Context, key string, val string, timeout time.Duration) error {
-	return r.redisTemplate.SetEX(ctx, key, val, timeout).Err()
+func (r *RedisCache) SetStringWithContext(ctx context.Context, key string, val string, expired int) error {
+	return r.redisTemplate.SetEX(ctx, key, val, time.Duration(expired)*time.Second).Err()
 }
 
 // IsExist 判断key是否存在

+ 21 - 3
common/component/component.go

@@ -1,8 +1,26 @@
 package component
 
 import (
-	_ "eta_mini_ht_api/common/component/cache"
-	_ "eta_mini_ht_api/common/component/config"
+	"eta_mini_ht_api/common/component/cache"
+	"eta_mini_ht_api/common/component/config"
 	_ "eta_mini_ht_api/common/component/database"
-	_ "eta_mini_ht_api/common/component/log"
+	logger "eta_mini_ht_api/common/component/log"
+	_ "eta_mini_ht_api/common/component/sms"
+	"eta_mini_ht_api/common/contants"
+	"eta_mini_ht_api/common/utils/sms"
 )
+
+func init() {
+	//配置redis,不做强校验
+	if redisConf, ok := config.GetConfig(contants.REDIS).(*config.RedisConfig); ok && redisConf != nil {
+		logger.Info("开始加载redis")
+		cache.GetInstance()
+	}
+	//配置SMS平台,没有配置直接报错
+	if smsConf, ok := config.GetConfig(contants.SMS).(*config.SMSConfig); ok && smsConf != nil {
+		logger.Info("开始加载短信平台客户端")
+		sms.InitSmsSender(smsConf)
+	} else {
+		panic("加载短信平台客户端失败")
+	}
+}

+ 9 - 4
common/component/config/config.go

@@ -11,13 +11,11 @@ const (
 )
 
 type Config interface {
-	GetConfig() interface{}
 	InitConfig()
 }
 
 type BaseConfig struct {
 	prefix string
-	config map[string]string
 }
 
 func (b *BaseConfig) GetString(key string) string {
@@ -27,6 +25,13 @@ func (b *BaseConfig) GetString(key string) string {
 	}
 	return value
 }
+func (b *BaseConfig) GetInt(key string) int {
+	value, err := web.AppConfig.Int(fmt.Sprintf("%s%s%s", b.prefix, SPLIT, key))
+	if err != nil {
+		return 0
+	}
+	return value
+}
 
 type Instance func() Config
 
@@ -44,10 +49,10 @@ func GetConfig(name string) (config Config) {
 }
 func Register(name string, adapter Instance) {
 	if adapter == nil {
-		panic("cache: Register adapter is nil")
+		panic("缓存类型不存在")
 	}
 	if _, ok := configs[name]; ok {
-		panic("cache: Register called twice for adapter " + name)
+		panic("当前缓存类型已注册:" + name)
 	}
 	configs[name] = adapter
 }

+ 11 - 7
common/component/config/db_config.go

@@ -6,8 +6,8 @@ import (
 )
 
 var (
-	once   sync.Once
-	config *DBConfig
+	once     sync.Once
+	dbConfig *DBConfig
 )
 
 type DBOpts struct {
@@ -19,8 +19,12 @@ type DBConfig struct {
 	opts DBOpts
 }
 
-func (r *DBConfig) GetConfig() interface{} {
-	return r.opts
+func (r *DBConfig) GetUrl() string {
+	return r.opts.Url
+}
+
+func (r *DBConfig) GetDriver() string {
+	return r.opts.Driver
 }
 func (r *DBConfig) InitConfig() {
 	opts := DBOpts{
@@ -30,15 +34,15 @@ func (r *DBConfig) InitConfig() {
 	r.opts = opts
 }
 func NewDBConfig() Config {
-	if config == nil {
+	if dbConfig == nil {
 		once.Do(func() {
-			config = &DBConfig{
+			dbConfig = &DBConfig{
 				BaseConfig: BaseConfig{prefix: contants.DATABASE},
 				opts:       DBOpts{},
 			}
 		})
 	}
-	return config
+	return dbConfig
 }
 
 func init() {

+ 20 - 5
common/component/config/redis_config.go

@@ -1,5 +1,7 @@
 package config
 
+import "eta_mini_ht_api/common/contants"
+
 // RedisOpts redis 连接属性
 type RedisOpts struct {
 	Host        string
@@ -18,15 +20,28 @@ type RedisConfig struct {
 	opts RedisOpts
 }
 
-func (r *RedisConfig) GetConfig() interface{} {
-	return r.opts
+func (r *RedisConfig) GetHost() string {
+	return r.opts.Host
+}
+func (r *RedisConfig) GetDatabase() int {
+	return r.opts.Database
+}
+func (r *RedisConfig) GetPassword() string {
+	return r.opts.Password
 }
+func (r *RedisConfig) GetIdleTimeout() int {
+	return r.opts.IdleTimeout
+}
+func (r *RedisConfig) GetMaxIdle() int {
+	return r.opts.MaxIdle
+}
+
 func (r *RedisConfig) InitConfig() {
 	opts := RedisOpts{
 		Host:        r.GetString("host"),
 		Username:    "",
-		Password:    "",
-		Database:    0,
+		Password:    r.GetString("password"),
+		Database:    r.GetInt("db"),
 		MaxIdle:     10,
 		MaxActive:   100,
 		IdleTimeout: 10,
@@ -37,7 +52,7 @@ func (r *RedisConfig) InitConfig() {
 }
 func NewRedis() Config {
 	return &RedisConfig{
-		BaseConfig: BaseConfig{prefix: "redis"},
+		BaseConfig: BaseConfig{prefix: contants.REDIS},
 		opts:       RedisOpts{},
 	}
 }

+ 89 - 0
common/component/config/sms_config.go

@@ -0,0 +1,89 @@
+package config
+
+import (
+	"eta_mini_ht_api/common/contants"
+	"sync"
+)
+
+var (
+	smsOnce   sync.Once
+	smsConfig *SMSConfig
+)
+
+type SMSOpts struct {
+	SmsType    string
+	JhConfig   JUHE
+	EMASConfig EMAS
+}
+type SMSConfig struct {
+	BaseConfig
+	opts SMSOpts
+}
+
+type JUHE struct {
+	Key          string
+	ExpireMinute int
+	TlpId        string
+}
+
+type EMAS struct {
+	url          string
+	ExpireMinute int
+	Template     string
+}
+
+func (r *SMSConfig) GetSmsType() string {
+	return r.opts.SmsType
+}
+func (r *SMSConfig) GetJhTlpId() string {
+	return r.opts.JhConfig.TlpId
+}
+func (r *SMSConfig) GetJhExpireMinute() int {
+	return r.opts.JhConfig.ExpireMinute
+}
+
+func (r *SMSConfig) GetEMASExpireMinute() int {
+	return r.opts.EMASConfig.ExpireMinute
+}
+func (r *SMSConfig) GetEMASTemplate() string {
+	return r.opts.EMASConfig.Template
+}
+func (r *SMSConfig) GetEMASUrl() string {
+	return r.opts.EMASConfig.url
+}
+func (r *SMSConfig) GetKey() string {
+	return r.opts.JhConfig.Key
+}
+func (r *SMSConfig) InitConfig() {
+	opts := SMSOpts{
+		SmsType: r.GetString("sms_type"),
+	}
+	switch opts.SmsType {
+	case "juhe":
+		opts.JhConfig.ExpireMinute = r.GetInt("juhe.expire_minute")
+		opts.JhConfig.Key = r.GetString("juhe.key")
+		opts.JhConfig.TlpId = r.GetString("juhe.tlp_id")
+	case "emas":
+		opts.EMASConfig.ExpireMinute = r.GetInt("emas.expire_minute")
+		opts.EMASConfig.url = r.GetString("emas.url")
+		opts.EMASConfig.Template = r.GetString("emas.template")
+	default:
+	}
+	r.opts = opts
+}
+
+func NewSMSConfig() Config {
+	if smsConfig == nil {
+		smsOnce.Do(func() {
+			smsConfig = &SMSConfig{
+				BaseConfig: BaseConfig{prefix: contants.SMS},
+				opts:       SMSOpts{},
+			}
+		})
+	}
+	return smsConfig
+}
+
+func init() {
+	Register(contants.SMS, NewSMSConfig)
+}

+ 9 - 3
common/component/config/wechat_config.go

@@ -1,5 +1,7 @@
 package config
 
+import "eta_mini_ht_api/common/contants"
+
 // RedisOpts redis 连接属性
 type WechatOpts struct {
 	Appid  string
@@ -10,8 +12,12 @@ type WechatConfig struct {
 	opts WechatOpts
 }
 
-func (w *WechatConfig) GetConfig() interface{} {
-	return w.opts
+func (w *WechatConfig) GetAppid() string {
+	return w.opts.Appid
+}
+
+func (w *WechatConfig) GetSecret() string {
+	return w.opts.Secret
 }
 func (w *WechatConfig) InitConfig() {
 	opts := WechatOpts{
@@ -28,5 +34,5 @@ func NewWechat() Config {
 }
 
 func init() {
-	Register("wechat", NewWechat)
+	Register(contants.WECHAT, NewWechat)
 }

+ 32 - 6
common/component/database/db_connector.go

@@ -1,14 +1,20 @@
 package database
 
 import (
-	dbConfig "eta_mini_ht_api/common/component/config"
+	"eta_mini_ht_api/common/component/config"
 	"eta_mini_ht_api/common/component/database/dialector"
 	logger "eta_mini_ht_api/common/component/log"
 	"eta_mini_ht_api/common/contants"
 	"gorm.io/gorm"
+	"os"
 	"sync"
 )
 
+const (
+	MAIN = "main"
+	EMAS = "emas"
+)
+
 var (
 	db     *gorm.DB
 	dbOnce sync.Once
@@ -18,22 +24,42 @@ func GetInstance() *gorm.DB {
 	return db
 }
 
+var dbInsts = make(map[string]*gorm.DB)
+
+func Register(name string, dbInst *gorm.DB) {
+	if dbInst == nil {
+		panic("数据库不能为空")
+	}
+	if _, ok := dbInsts[name]; ok {
+		panic("当前数据库实例已注册:" + name)
+	}
+	dbInsts[name] = dbInst
+}
+func Select(name string) *gorm.DB {
+	db := dbInsts[name]
+	if db == nil {
+		panic("数据库未初始化")
+	}
+	return db
+}
 func init() {
+	//初始化主数据库
 	if db == nil {
 		dbOnce.Do(func() {
-			config, ok := dbConfig.GetConfig(contants.DATABASE).(*dbConfig.DBConfig)
+			dbConfig, ok := config.GetConfig(contants.DATABASE).(*config.DBConfig)
 			if !ok {
 				panic("初始化数据库失败,配置文件格式不正确")
 			}
-			driver := config.GetString("driver")
-			dns := config.GetString("url")
+			driver := dbConfig.GetDriver()
+			dns := dbConfig.GetUrl()
 			open, err := gorm.Open(dialector.GetGormDial(driver).GetDial(dns), &gorm.Config{})
 			if err != nil {
-				logger.Error("初始化数据库失败:%v", err.Error())
-				panic("初始化数据库失败")
+				logger.Error("初始化数据库失败:%v", err)
+				os.Exit(0)
 			}
 			db = open
 			logger.Info("初始化数据库成功")
 		})
 	}
+	Register(MAIN, db)
 }

+ 1 - 1
common/component/log/log_plugin.go

@@ -2,7 +2,7 @@ package logger
 
 import (
 	"encoding/json"
-	stringUtils "eta_mini_ht_api/common/utils"
+	stringUtils "eta_mini_ht_api/common/utils/string"
 	"fmt"
 	"github.com/beego/beego/v2/core/logs"
 	"log"

+ 27 - 0
common/component/log/log_plugin_test.go

@@ -0,0 +1,27 @@
+package logger
+
+import (
+	"errors"
+	"testing"
+)
+
+func TestError(t *testing.T) {
+	type args struct {
+		msg string
+		v   []interface{}
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "错误",
+			args: args{msg: "错误", v: []interface{}{errors.New("1212")}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			Error(tt.args.msg, tt.args.v...)
+		})
+	}
+}

+ 82 - 0
common/component/sms/emas_sms_sender.go

@@ -0,0 +1,82 @@
+package sms
+
+import (
+	"bytes"
+	"eta_mini_ht_api/common/component/config"
+	"eta_mini_ht_api/common/component/database"
+	"eta_mini_ht_api/common/component/database/dialector"
+	logger "eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/common/exception"
+	"eta_mini_ht_api/common/utils/sms"
+	stringUtils "eta_mini_ht_api/common/utils/string"
+	smsService "eta_mini_ht_api/domian/sms"
+	"gorm.io/gorm"
+	"os"
+	"text/template"
+)
+
+const (
+	emasDriver = "mysql"
+)
+
+type EMASSmsSender struct {
+	Url               string
+	Template          string
+	TemplateGenerator *template.Template
+	SmsExpireMinute   int
+}
+
+func initDBClient(url string) *gorm.DB {
+	open, err := gorm.Open(dialector.GetGormDial(emasDriver).GetDial(url), &gorm.Config{})
+	if err != nil {
+		logger.Error("初始化亿美短信数据库失败:%v", err)
+		os.Exit(0)
+	}
+	logger.Info("初始化数据库成功")
+	return open
+}
+func (emas *EMASSmsSender) InitSender(config *config.SMSConfig) {
+	emas.Template = config.GetEMASTemplate()
+	emas.Url = config.GetEMASUrl()
+	emas.SmsExpireMinute = config.GetEMASExpireMinute()
+	emas.TemplateGenerator = template.Must(template.New("smsTemplate").Parse(emas.Template))
+	if stringUtils.IsEmptyOrNil(emas.Url) {
+		panic("亿美短信平台初始化失败,数据库url不能为空")
+	}
+	database.Register(database.EMAS, initDBClient(emas.Url))
+}
+func (emas *EMASSmsSender) GetExpireMinute() int {
+	return emas.SmsExpireMinute
+}
+
+type EMASResp struct {
+	Reason    string `json:"reason"`
+	Result    Result `json:"result"`
+	ErrorCode int
+}
+type emasTemplate struct {
+	ExpireMinute int
+	Code         string
+}
+
+func (emas *EMASSmsSender) SendSms(mobile string, code string) (result string, err error) {
+	var content bytes.Buffer
+	if err = emas.TemplateGenerator.Execute(&content, &emasTemplate{emas.SmsExpireMinute, code}); err != nil {
+		// 处理错误,例如记录日志或返回错误给调用者
+		logger.Warn("[短信发送]生成短信内容失败:%v", err)
+		return SendFail, exception.New(exception.SendingSMSFailed)
+	}
+	msg := smsService.Msg{Mobile: mobile, Content: content.String()}
+	err = smsService.SendSms(msg)
+	if err != nil {
+		logger.Warn("[短信发送]发送短信失败:%v", err)
+		return SendFail, exception.New(exception.SendingSMSFailed)
+	}
+	return SendSuccess, nil
+}
+func NewEMASClient() sms.SMSClient {
+	return &EMASSmsSender{}
+}
+func init() {
+	sms.Register(sms.Emas, NewEMASClient)
+}

+ 95 - 0
common/component/sms/juhe_sms_sender.go

@@ -0,0 +1,95 @@
+package sms
+
+import (
+	"encoding/json"
+	"eta_mini_ht_api/common/component/config"
+	logger "eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/common/exception"
+	"eta_mini_ht_api/common/utils/sms"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+)
+
+const (
+	apiURL      = "http://v.juhe.cn/sms/send"
+	SendSuccess = "发送成功"
+
+	SendFail = "发送失败"
+)
+
+type JuheSmsSender struct {
+	tplId           string
+	SmsExpireMinute int
+	Key             string
+}
+
+func (jh *JuheSmsSender) InitSender(config *config.SMSConfig) {
+	jh.tplId = config.GetJhTlpId()
+	jh.SmsExpireMinute = config.GetJhExpireMinute()
+	jh.Key = config.GetKey()
+}
+func (jh *JuheSmsSender) GetExpireMinute() int {
+	return jh.SmsExpireMinute
+}
+
+type JHResp struct {
+	Reason    string `json:"reason"`
+	Result    Result `json:"result"`
+	ErrorCode int
+}
+type Result struct {
+	Sid   string `json:"sid"`
+	Fee   int    `json:"fee"`
+	Count int    `json:"count"`
+}
+
+func (jh *JuheSmsSender) SendSms(mobile string, code string) (result string, err error) {
+	var Url *url.URL
+	//初始化参数
+	param := url.Values{}
+	//配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
+	param.Set("mobile", mobile)   //接受短信的用户手机号码
+	param.Set("tpl_id", jh.tplId) //您申请的短信模板ID,根据实际情况修改
+	tplVal := fmt.Sprintf(`#code#=%s&#m#=%d`, code, jh.SmsExpireMinute)
+	param.Set("tpl_value", tplVal) //您设置的模板变量,根据实际情况
+	param.Set("key", jh.Key)       //应用APPKEY(应用详细页查询)
+	Url, err = url.Parse(apiURL)
+	if err != nil {
+		logger.Warn("[短信发送]解析url错误:%v", err)
+		return SendFail, exception.New(exception.SendingSMSFailed)
+	}
+	//如果参数中有中文参数,这个方法会进行URLEncode
+	Url.RawQuery = param.Encode()
+	resp, err := http.Get(Url.String())
+	if err != nil {
+		logger.Warn("[短信发送]发送失败:%v", err)
+		return SendFail, exception.New(exception.SendingSMSFailed)
+	}
+	body, _ := io.ReadAll(resp.Body)
+	var jsonResp JHResp
+	err = json.Unmarshal(body, &jsonResp)
+	if err != nil {
+		logger.Warn("[短信发送]解析jh应答失败:%v", err)
+		return SendFail, exception.New(exception.SendingSMSFailed)
+	}
+	if jsonResp.ErrorCode != 0 {
+		logger.Warn("[短信发送]发送失败%v", jsonResp.Reason)
+		return SendFail, exception.New(exception.SendingSMSFailed)
+	}
+	defer func(Body io.ReadCloser) {
+		closeErr := Body.Close()
+		if closeErr != nil {
+			logger.Error("关闭Response失败:%v", closeErr)
+		}
+	}(resp.Body)
+	logger.Info("[短信发送]发送成功,sid:%v", jsonResp.Result.Sid)
+	return SendSuccess, nil
+}
+func NewJHClient() sms.SMSClient {
+	return &JuheSmsSender{}
+}
+func init() {
+	sms.Register(sms.Juhe, NewJHClient)
+}

+ 0 - 127
common/component/wechat/http/request.go

@@ -1,127 +0,0 @@
-package http
-
-import (
-	"bytes"
-	"context"
-	"encoding/json"
-	"encoding/xml"
-	"errors"
-	"eta_mini_ht_api/common/utils/client"
-	"github.com/medivhzhan/weapp/v3/logger"
-	"net/http"
-)
-
-// ContentType 请求内容类型
-type ContentType uint
-
-const (
-	ContentTypePlain ContentType = iota
-	ContentTypeXML
-	ContentTypeJSON
-)
-
-func (ctp ContentType) String() string {
-	switch ctp {
-	case ContentTypeXML:
-		return "service/xml"
-	case ContentTypeJSON:
-		return "service/json"
-	default:
-		return "text/plain"
-	}
-}
-
-type Request struct {
-	http *client.HttpClient
-	// 获取日志记录器
-	logger      func() logger.Logger
-	contentType ContentType
-}
-
-func NewRequest(http *client.HttpClient, ctp ContentType, logger func() logger.Logger) *Request {
-	return &Request{
-		http:        http,
-		logger:      logger,
-		contentType: ctp,
-	}
-}
-
-func (cli *Request) Get(url string, response interface{}) error {
-	cli.logger().Info(context.Background(), "request url: %s", url)
-
-	resp, err := cli.http.Get(url)
-	if err != nil {
-		cli.logger().Error(context.Background(), "get error: %s", err)
-		return err
-	}
-	defer resp.Body.Close()
-	switch cli.contentType {
-	case ContentTypeXML:
-		return xml.NewDecoder(resp.Body).Decode(response)
-	case ContentTypeJSON:
-		return json.NewDecoder(resp.Body).Decode(response)
-	default:
-		return errors.New("invalid content type")
-	}
-}
-
-func (cli *Request) GetWithBody(url string) (*http.Response, error) {
-	cli.logger().Info(context.Background(), "request url: %s", url)
-	rsp, err := cli.http.Get(url)
-	if err != nil {
-		cli.logger().Error(context.Background(), "get with body error: %s", url)
-		return nil, err
-	}
-
-	return rsp, nil
-}
-
-func (cli *Request) Post(url string, params interface{}, response interface{}) error {
-	resp, err := cli.PostWithBody(url, params)
-	if err != nil {
-		cli.logger().Error(context.Background(), "post error: %s", err)
-		return err
-	}
-	defer resp.Body.Close()
-
-	switch cli.contentType {
-	case ContentTypeXML:
-		return xml.NewDecoder(resp.Body).Decode(response)
-	case ContentTypeJSON:
-		return json.NewDecoder(resp.Body).Decode(response)
-	default:
-		return errors.New("invalid content type")
-	}
-}
-
-func (cli *Request) PostWithBody(url string, params interface{}) (*http.Response, error) {
-	cli.logger().Info(context.Background(), "request url: %s", url)
-	cli.logger().Info(context.Background(), "request params: %+v", params)
-	buf := new(bytes.Buffer)
-	if params != nil {
-		switch cli.contentType {
-		case ContentTypeXML:
-			err := xml.NewEncoder(buf).Encode(params)
-			if err != nil {
-				return nil, err
-			}
-		case ContentTypeJSON:
-			enc := json.NewEncoder(buf)
-			enc.SetEscapeHTML(false)
-			err := enc.Encode(params)
-			if err != nil {
-				return nil, err
-			}
-		default:
-			return nil, errors.New("invalid content type")
-		}
-	}
-
-	rsp, err := cli.http.Post(url, cli.contentType.String(), buf)
-	if err != nil {
-		cli.logger().Error(context.Background(), "post with body error: %s", url)
-		return nil, err
-	}
-
-	return rsp, nil
-}

+ 16 - 10
common/component/wechat/http/response.go → common/component/wechat/we_http/response.go

@@ -1,4 +1,4 @@
-package http
+package we_http
 
 import (
 	"fmt"
@@ -10,15 +10,6 @@ type CommonError struct {
 	ErrMSG  string `json:"errmsg"`  // 	错误描述
 }
 
-// GetResponseError 获取微信服务器错返回误信息
-func (err CommonError) GetResponseError() error {
-	if err.ErrCode != 0 {
-		return fmt.Errorf("wechat server error: code[%d] msg[%s]", err.ErrCode, err.ErrMSG)
-	}
-
-	return nil
-}
-
 // CommonResult 微信返回错误信息
 type CommonResult struct {
 	ResultCode int    `json:"resultcode"` // 	错误码
@@ -34,3 +25,18 @@ func (err CommonResult) GetResponseError() error {
 
 	return nil
 }
+
+// LoginResponse 返回给用户的数据
+type LoginResponse struct {
+	OpenID     string `json:"openid"`
+	SessionKey string `json:"session_key"`
+	// 用户在开放平台的唯一标识符
+	// 只在满足一定条件的情况下返回
+	UnionID string `json:"unionid"`
+}
+
+// Response 请求微信返回基础数据
+type BaseResponse struct {
+	Errcode int    `json:"errcode"`
+	Errmsg  string `json:"errmsg"`
+}

+ 60 - 137
common/component/wechat/wechat_client.go

@@ -1,18 +1,25 @@
 package wechat
 
 import (
-	"eta_mini_ht_api/component/cache"
-	config2 "eta_mini_ht_api/component/config"
-	"eta_mini_ht_api/component/log"
-	"github.com/medivhzhan/weapp/v3/auth"
-	"github.com/medivhzhan/weapp/v3/request"
-	"github.com/mitchellh/mapstructure"
+	"encoding/json"
+	"errors"
+	"eta_mini_ht_api/common/component/config"
+	"eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/common/component/wechat/we_http"
+	"eta_mini_ht_api/common/contants"
+	"eta_mini_ht_api/common/utils/client"
 	"net/http"
+	"net/url"
 	"sync"
 )
 
 const (
 	baseURL = "https://api.weixin.qq.com"
+	codeAPI = "/sns/jscode2session"
+)
+const (
+	// WeChatServerError 微信服务器错误时返回返回消息
+	WeChatServerError = "微信服务器发生错误"
 )
 
 var (
@@ -22,39 +29,24 @@ var (
 
 type Client struct {
 	// HTTP请求客户端
-	request *request.Request
-	// 数据缓存器
-	cache *cache.RedisCache
-	// 日志记录器
-	logger logger.Logger
+	client *client.HttpClient
 	// 小程序后台配置: 小程序ID
 	appid string
 	// 小程序后台配置: 小程序密钥
 	secret string
-	// 用户自定义获取access_token的方法
-	accessTokenGetter AccessTokenGetter
 }
 
 func GetInstance() *Client {
 	once.Do(func() {
-		wechatConf, ok := config2.GetConfig("wechat").(*config2.WechatConfig)
-		if !ok {
-			// 处理错误情况,比如记录日志或返回错误信息
-			logger.Info("加载wechat配置失败")
-			return // 或者采取其他适当的错误处理措施
-		}
-		opts, ok := wechatConf.GetConfig().(config2.WechatOpts)
+		wechatConf, ok := config.GetConfig(contants.WECHAT).(*config.WechatConfig)
 		if !ok {
 			// 处理错误情况,比如记录日志或返回错误信息
 			logger.Info("加载wechat配置失败")
 			return // 或者采取其他适当的错误处理措施
 		}
 		// 默认配置
-		wechatClient = NewClient(opts.Appid, opts.Secret,
-			WithHttpClient(http.DefaultClient),
-			WithCache(cache.GetInstance()),
-			WithLogger(logger.GetInstance()),
-		)
+		wechatClient = NewClient(wechatConf.GetAppid(), wechatConf.GetSecret())//WithHttpClient(http.DefaultClient),
+
 	})
 	return wechatClient
 }
@@ -74,142 +66,73 @@ func NewClient(appid, secret string, opts ...func(*Client)) *Client {
 		fn(cli)
 	}
 
-	if cli.cache == nil {
-		//cli.cache = cache.NewMemoryCache()
-	}
-
-	if cli.request == nil {
-		//cli.request = request.NewRequest(http.DefaultClient, request.ContentTypeJSON, cli.Logger)
-	}
-
-	if cli.logger == nil {
-		//cli.logger = logger.NewLogger(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Info, true)
-	}
-
 	return cli
 }
 
 // WithHttpClient 自定义 HTTP Client
-func WithHttpClient(hc *http.Client) func(*Client) {
+func WithHttpClient(hc *client.HttpClient) func(*Client) {
 	return func(cli *Client) {
 		//cli.request = request.NewRequest(hc, request.ContentTypeJSON, cli.Logger)
 	}
 }
 
-// WithCache 自定义缓存
-func WithCache(cc *cache.RedisCache) func(*Client) {
-	return func(cli *Client) {
-		cli.cache = cc
-	}
+type loginResponse struct {
+	we_http.BaseResponse
+	we_http.LoginResponse
 }
 
-// WithAccessTokenSetter 自定义获取access_token的方法
-func WithAccessTokenSetter(getter AccessTokenGetter) func(*Client) {
-	return func(cli *Client) {
-		cli.accessTokenGetter = getter
+// 小程序登录
+func (cli *Client) Login(code string) (lres we_http.LoginResponse, err error) {
+	if code == "" {
+		err = errors.New("code不能为空")
+		return
 	}
-}
-
-// WithLogger 自定义日志
-func WithLogger(logger logger.Logger) func(*Client) {
-	return func(cli *Client) {
-		cli.logger = logger
+	api, err := code2url(cli.appid, cli.secret, code)
+	if err != nil {
+		return
 	}
-}
-
-// POST 参数
-type requestParams map[string]interface{}
-
-// URL 参数
-type requestQueries map[string]interface{}
-
-// tokenAPI 获取带 token 的 API 地址
-func tokenAPI(api, token string) (string, error) {
-	queries := requestQueries{
-		"access_token": token,
+	res, err := http.Get(api)
+	if err != nil {
+		return
 	}
+	defer res.Body.Close()
 
-	return request.EncodeURL(api, queries)
-}
+	if res.StatusCode != 200 {
+		err = errors.New(WeChatServerError)
+		return
+	}
 
-// convert bool to int
-func bool2int(ok bool) uint8 {
+	var data loginResponse
+	err = json.NewDecoder(res.Body).Decode(&data)
+	if err != nil {
+		return
+	}
 
-	if ok {
-		return 1
+	if data.Errcode != 0 {
+		err = errors.New(data.Errmsg)
+		return
 	}
 
-	return 0
+	lres = data.LoginResponse
+	return
 }
 
-// Logger 获取日志记录器
-func (cli *Client) Logger() logger.Logger { return cli.logger }
-
-// AccessToken 获取小程序全局唯一后台接口调用凭据(access_token)。
-// 调调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存,注意缓存。
-func (cli *Client) AccessToken() (string, error) {
-	return "", nil
-	////key := cli.tokenCacheKey()
-	//data, ok := cli.cache.Get(key)
-	//if ok {
-	//	return data.(string), nil
-	//}
-	//
-	//if cli.accessTokenGetter != nil {
-	////	token, expireIn := cli.accessTokenGetter(cli.appid, cli.secret)
-	//	//cli.cache.Set(key, token, time.Duration(expireIn)*time.Second)
-	////	return token, nil
-	//} else {
-	//
-	//	req := auth.GetStableAccessTokenRequest{
-	//		Appid:     cli.appid,
-	//		Secret:    cli.secret,
-	//		GrantType: "client_credential",
-	//	}
-	//	rsp, err := cli.NewAuth().GetStableAccessToken(&req)
-	//	if err != nil {
-	//		return "", err
-	//	}
-	//
-	//	if err := rsp.GetResponseError(); err != nil {
-	//		return "", err
-	//	}
-	//
-	//	err = cli.cache.SetString(key, rsp.AccessToken, time.Duration(rsp.ExpiresIn)*time.Second)
-	//	if err != nil {
-	//		return "", err
-	//	}
-	//	return rsp.AccessToken, nil
-	//}
-}
+// 拼接 获取 session_key 的 URL
+func code2url(appID, secret, code string) (string, error) {
 
-// 拼凑完整的 URI
-func (cli *Client) combineURI(url string, req interface{}, withToken bool) (string, error) {
-	output := make(map[string]interface{})
-	config := &mapstructure.DecoderConfig{
-		Metadata: nil,
-		Result:   &output,
-		TagName:  "query",
-	}
-	decoder, err := mapstructure.NewDecoder(config)
+	url, err := url.Parse(baseURL + codeAPI)
 	if err != nil {
 		return "", err
 	}
-	err = decoder.Decode(req)
-	if err != nil {
-		return "", err
-	}
-	if withToken {
-		token, err := cli.AccessToken()
-		if err != nil {
-			return "", err
-		}
-		output["access_token"] = token
-	}
-	return request.EncodeURL(baseURL+url, output)
-}
 
-// NewAuth 用户信息
-func (cli *Client) NewAuth() *auth.Auth {
-	return auth.NewAuth(cli.request, cli.combineURI)
+	query := url.Query()
+
+	query.Set("appid", appID)
+	query.Set("secret", secret)
+	query.Set("js_code", code)
+	query.Set("grant_type", "authorization_code")
+
+	url.RawQuery = query.Encode()
+
+	return url.String(), nil
 }

+ 0 - 5
common/contants/constants.go

@@ -1,5 +0,0 @@
-package contants
-
-const (
-	DATABASE = "database"
-)

+ 9 - 0
common/contants/contants.go

@@ -0,0 +1,9 @@
+package contants
+
+const (
+	DATABASE = "database"
+	SMS      = "sms"
+	REDIS    = "redis"
+
+	WECHAT = "wechat"
+)

+ 39 - 36
common/exception/exc_enums.go

@@ -1,47 +1,50 @@
 package exception
 
-import "errors"
+import stringUtils "eta_mini_ht_api/common/utils/string"
 
-type ErrorCode int
+type EtaError struct {
+	ErrorCode int
+	ErrorMsg  string
+}
 
-const (
-	SysErrCode ErrorCode = iota + 10000 // iota 自动递增,从 1 开始
-	ErrCodeNotFound
-	ErrCodeUnauthorized
-	ErrCodeBadRequest
-	ErrCodeInternalServer
-)
+func (e *EtaError) Error() string {
+	return e.ErrorMsg
+}
 
 const (
-	BIZErrCode ErrorCode = iota + 20000 // iota 自动递增,从 1 开始
-	BIZErrCodeErrCodeNotFound
-	BIZErrCodeErrCodeUnauthorized
-	BIZErrCodeErrCodeBadRequest
-	BIZErrCodeErrCodeInternalServer
+	// SysErrCode 系统错误
+	SysErrCode int = iota + 10000 // iota 自动递增,从 1 开始
+	UnknownError
+	Unauthorized
+	// BIZErrCode 业务错误
+	BIZErrCode int = iota + 20000 // iota 自动递增,从 1 开始
+	IllegalCodeLength
+	IllegalPhoneNumber
+	SMSCodeGenerateFailed
+	SendingSMSFailed
 )
 
-// 为枚举类型定义一个字符串表示
-func (e ErrorCode) String() string {
-	switch e {
-	case ErrCodeNotFound:
-		return "Not Found"
-	case ErrCodeUnauthorized:
-		return "Unauthorized"
-	case ErrCodeBadRequest:
-		return "Bad Request"
-	case ErrCodeInternalServer:
-		return "Internal Server Error"
-	default:
-		return "Unknown Error"
-	}
+// ErrorMap 用于存储错误码和错误信息的映射
+var ErrorMap = map[int]string{
+	UnknownError:          "未知错误",
+	Unauthorized:          "未授权",
+	IllegalCodeLength:     "无效的验证码位数设置",
+	IllegalPhoneNumber:    "无效的手机号码",
+	SMSCodeGenerateFailed: "生成手机验证码失败",
+	SendingSMSFailed:      "发送手机验证码失败",
 }
 
-// 为每个错误代码定义一个错误实例
-var (
-	ErrNotFound       = errors.New(ErrCodeNotFound.String())
-	ErrUnauthorized   = errors.New(ErrCodeUnauthorized.String())
-	ErrBadRequest     = errors.New(ErrCodeBadRequest.String())
-	ErrInternalServer = errors.New(ErrCodeInternalServer.String())
-)
+func newException(code int, msg string) error {
+	return &EtaError{
+		ErrorCode: code,
+		ErrorMsg:  msg,
+	}
+}
 
-//sys_error 系统错误
+func New(code int) *EtaError {
+	err := ErrorMap[code]
+	if stringUtils.IsBlank(err) {
+		return newException(UnknownError, ErrorMap[UnknownError]).(*EtaError)
+	}
+	return newException(code, err).(*EtaError)
+}

+ 19 - 0
common/http/err.go

@@ -0,0 +1,19 @@
+package http
+
+/**
+ * err code
+ */
+const (
+	/*
+	 * 成功
+	 */
+	ErrOK = 0
+)
+
+/**
+ * err message
+ */
+const (
+	Success = true
+	Fail    = false
+)

+ 29 - 0
common/http/status.go

@@ -0,0 +1,29 @@
+package http
+
+const (
+	ok                  = 200
+	created             = 201
+	unauthorized        = 401
+	forbidden           = 403
+	internalServerError = 500
+)
+
+/**
+ * 获取标准的 HTTP 状态码, -1 表示未找到
+ */
+func GetHttpStatusByAlias(s string) int {
+	switch s {
+	case "ok":
+		return ok
+	case "created":
+		return created
+	case "unauthorized":
+		return unauthorized
+	case "forbidden":
+		return forbidden
+	case "internalServerError":
+		return internalServerError
+	default:
+		return -1
+	}
+}

+ 37 - 0
common/utils/auth/auth_utils.go

@@ -0,0 +1,37 @@
+package auth
+
+import (
+	"crypto/rand"
+	"eta_mini_ht_api/common/exception"
+	stringUtils "eta_mini_ht_api/common/utils/string"
+	"math/big"
+	"regexp"
+)
+
+const (
+	letterBytes = "0123456789"
+)
+
+func GenerateCode(length int) (string, error) {
+	if length <= 0 {
+		return "", exception.New(exception.IllegalCodeLength)
+	}
+	b := make([]byte, length)
+	for i := range b {
+		n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letterBytes))))
+		if err != nil {
+			return "", err
+		}
+		b[i] = letterBytes[n.Int64()]
+	}
+	return string(b), nil
+}
+
+func IsValidMobile(mobile string) bool {
+	if stringUtils.IsBlank(mobile) {
+		return false
+	}
+	regex := `^(13[0-9]|14[5-9]|15[0-3,5-9]|16[6]|17[0-8]|18[0-9]|19[0-3,5-9])\d{8}$`
+	matched, _ := regexp.MatchString(regex, mobile)
+	return matched
+}

+ 9 - 2
common/utils/client/http_client.go

@@ -15,11 +15,18 @@ type HttpClient struct {
 	retryDelayFunc RetryDelayFunc
 }
 
-func GetInstance(timeout time.Duration, maxRetries int) *HttpClient {
+// NewClient 构造函数,其中 delayFunc 参数是可选的
+func NewClient(timeout time.Duration, maxRetries int, delayFunc ...RetryDelayFunc) *HttpClient {
+	var df RetryDelayFunc
+	if len(delayFunc) > 0 {
+		df = delayFunc[0]
+	} else {
+		df = defaultRetryDelayFunc
+	}
 	return &HttpClient{
 		Client:         &http.Client{Timeout: timeout},
 		maxRetries:     maxRetries,
-		retryDelayFunc: defaultRetryDelayFunc,
+		retryDelayFunc: df,
 	}
 }
 

+ 11 - 0
common/utils/redis/key_generator.go

@@ -0,0 +1,11 @@
+package redis
+
+import "fmt"
+
+const (
+	SmsKeyPrefix = "sms_code:"
+)
+
+func GenerateSmsKey(mobile string) string {
+	return fmt.Sprint(SmsKeyPrefix, mobile)
+}

+ 52 - 0
common/utils/sms/sms_client.go

@@ -0,0 +1,52 @@
+package sms
+
+import (
+	"eta_mini_ht_api/common/component/config"
+	"github.com/beego/beego/v2/core/logs"
+)
+
+var (
+	smsClient SMSClient
+)
+
+const (
+	Juhe = "juhe"
+	Emas = "emas"
+)
+
+type SMSClient interface {
+	InitSender(config *config.SMSConfig)
+	GetExpireMinute() int
+	SendSms(mobile string, code string) (rs string, err error)
+}
+
+var clients = make(map[string]Instance)
+
+type Instance func() SMSClient
+
+func getClient(config *config.SMSConfig) (client SMSClient) {
+	name := config.GetSmsType()
+	instanceFunc, ok := clients[name]
+	if !ok {
+		logs.Error("不支持当前的短信平台", name)
+		return nil
+	}
+	client = instanceFunc()
+	client.InitSender(config)
+	return client
+}
+func GetInstance() SMSClient {
+	return smsClient
+}
+func InitSmsSender(config *config.SMSConfig) {
+	smsClient = getClient(config)
+}
+func Register(name string, adapter Instance) {
+	if adapter == nil {
+		panic("不支持当前的短信平台")
+	}
+	if _, ok := clients[name]; ok {
+		panic("当前短信平台类型已注册:" + name)
+	}
+	clients[name] = adapter
+}

+ 5 - 1
common/utils/string_utils.go → common/utils/string/string_utils.go

@@ -1,4 +1,4 @@
-package stringUtils
+package string
 
 import "strings"
 
@@ -8,3 +8,7 @@ func IsEmptyOrNil(s string) bool {
 func IsBlank(s string) bool {
 	return strings.TrimSpace(s) == ""
 }
+
+func IsNotBlank(s string) bool {
+	return !IsBlank(s)
+}

+ 69 - 0
common/web_socket/ws_client.go

@@ -0,0 +1,69 @@
+package web_socket
+
+//
+//var clients = make(map[*websocket.Conn]bool) // 存储所有连接的客户端
+//var broadcast = make(chan Message)           // 用于广播消息
+//var mutex sync.Mutex                         // 用于同步访问clients map
+//
+//var upgrader
+//type Message struct {
+//	User  string `json:"user"`
+//	Msg   string `json:"msg"`
+//	Topic string `json:"topic"`
+//}
+//
+//func serveWs(w we_http.ResponseWriter, r *we_http.Request) {
+//	conn, err := upgrader.Upgrade(w, r, nil)
+//	if err != nil {
+//		log.Fatal(err)
+//		return
+//	}
+//	defer conn.Close()
+//
+//	mutex.Lock()
+//	clients[conn] = true
+//	mutex.Unlock()
+//
+//	for {
+//		var msg Message
+//		err := conn.ReadJSON(&msg)
+//		if err != nil {
+//			mutex.Lock()
+//			delete(clients, conn)
+//			mutex.Unlock()
+//			break
+//		}
+//		broadcast <- msg
+//	}
+//}
+//
+//func broadcastMessages() {
+//	for {
+//		msg := <-broadcast
+//		mutex.Lock()
+//		for client := range clients {
+//			err := client.WriteJSON(msg)
+//			if err != nil {
+//				log.Printf("error: %v", err)
+//				client.Close()
+//				delete(clients, client)
+//			}
+//		}
+//		mutex.Unlock()
+//	}
+//}
+//
+//func init() {
+//	upgrader = websocket.Upgrader{
+//		ReadBufferSize:  1024,
+//		WriteBufferSize: 1024,
+//		CheckOrigin: func(r *we_http.Request) bool {
+//			return true
+//		},
+//	}
+//
+//	we_http.HandleFunc("/ws", serveWs)
+//	go broadcastMessages()
+//
+//	we_http.ListenAndServe(":8080", nil)
+//}

+ 75 - 18
controllers/base_controller.go

@@ -1,40 +1,97 @@
 package controllers
 
-import "github.com/beego/beego/v2/server/web"
+import (
+	"encoding/json"
+	"errors"
+	"eta_mini_ht_api/common/component/cache"
+	logger "eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/common/exception"
+	"eta_mini_ht_api/common/http"
+	"github.com/beego/beego/v2/server/web"
+)
+
+var (
+	redis *cache.RedisCache
+)
 
 type BaseController struct {
 	web.Controller
 }
 
-type RetData struct {
-	ErrMsg  string      `json:"errMsg"`
-	ErrCode string      `json:"errCode"`
-	Data    interface{} `json:"data"`
+type BaseResponse struct {
+	Ret         int `description:"返回状态码"`
+	Msg         string
+	ErrMsg      string
+	ErrCode     int
+	Data        interface{}
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
 }
 
-func (b *BaseController) FailResponse() {
+func (b *BaseController) FailResponse(errInfo error) {
 
+	var retData BaseResponse
+	var etaError *exception.EtaError
+	if !errors.As(errInfo, &etaError) {
+		etaError = exception.New(exception.UnknownError)
+	}
+	retData = BaseResponse{
+		Ret:     200,
+		Msg:     "",
+		ErrMsg:  etaError.ErrorMsg,
+		ErrCode: etaError.ErrorCode,
+		Data:    nil}
+	b.Data["json"] = retData
+	b.ServeJSON()
 }
 
-/*
-* Ajax	返回Json数据
- */
-func (b *BaseController) JsonResult(status int, errCode int, errMsg string, data ...interface{}) {
-	retData := RetData{ErrMsg: "",
-		ErrCode: "0",
-		Data:    nil}
+// JsonResult /*
+func (b *BaseController) JsonResult(status int, errCode int, errMsg string, msg string, success bool, data interface{}) {
+	retData := BaseResponse{
+		Ret:     status,
+		Msg:     msg,
+		ErrMsg:  errMsg,
+		ErrCode: errCode,
+		Data:    data,
+		Success: success}
 
-	if len(data) > 0 && data[0] != nil {
-		retData.Data = data[0]
-	}
 	b.Ctx.Output.SetStatus(status)
 	b.Data["json"] = retData
-	err := b.ServeJSON()
+	b.ServeJSON()
+}
+
+func (b *BaseController) Forbidden() {
+
+}
+
+func (b *BaseController) GetPostParams(data interface{}) {
+	err := json.Unmarshal(b.Ctx.Input.RequestBody, data)
 	if err != nil {
+		logger.Error("解析请求参数失败:%v", err)
+		data = nil
+	}
+}
+
+// Wrap ControllerWrap 是一个用于封装控制器方法的函数
+func Wrap(a *BaseController, fn func() (*WrapData, error)) {
+	result, err := fn()
+	if err != nil {
+		logger.Error("%v", err)
+		a.FailResponse(err)
 		return
 	}
+	a.JsonResult(http.GetHttpStatusByAlias("ok"), http.ErrOK, "", result.Msg, http.Success, result.Data)
 }
 
-func (b *BaseController) Forbidden() {
+type WrapData struct {
+	Msg  string
+	Data interface{}
+}
 
+func (b *BaseController) Cache() *cache.RedisCache {
+	if redis == nil {
+		redis = cache.GetInstance()
+	}
+	return redis
 }

+ 92 - 0
controllers/user/auth_controller.go

@@ -0,0 +1,92 @@
+package user
+
+import (
+	logger "eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/common/component/wechat"
+	"eta_mini_ht_api/common/exception"
+	authUtils "eta_mini_ht_api/common/utils/auth"
+	"eta_mini_ht_api/common/utils/redis"
+	"eta_mini_ht_api/common/utils/sms"
+	"eta_mini_ht_api/controllers"
+	"fmt"
+)
+
+type AuthController struct {
+	controllers.BaseController
+}
+
+var (
+	smsSender sms.SMSClient
+
+	wechatClient *wechat.Client
+)
+
+func (a *AuthController) message() sms.SMSClient {
+	if smsSender == nil {
+		smsSender = sms.GetInstance()
+	}
+	return smsSender
+}
+func (a *AuthController) Prepare() {
+	if wechatClient == nil {
+		wechatClient = wechat.GetInstance()
+	}
+}
+
+// SmsCodeReq 获取验证码请求
+type LoginReq struct {
+	Code string `json:"code"`
+}
+
+// Login 小程序登录接口
+// @Summary 小程序用户登录
+// @Description 用户通过微信小程序登录
+// @Param   code     body    string  true        "获取微信小程序code"
+// @Success 200 {object} controllers.BaseResponse
+// @router /login [post]
+func (a *AuthController) Login() {
+	loginReq := new(LoginReq)
+	a.GetPostParams(loginReq)
+	wechatClient.Login(loginReq.Code)
+	//wechatClient.GetAccessToken(loginReq.Code)
+}
+
+// SmsCodeReq 获取验证码请求
+type SmsCodeReq struct {
+	Mobile string `json:"mobile"`
+}
+
+// SMSCode 小程序手机验证码接口
+// @Summary 获取手机验证码
+// @Param   mobile   body    SmsCodeReq  true        "小程序手机验证码接口"
+// @Success 200 {object} controllers.BaseResponse
+// @Description 用户发送手机验证码
+// @router /sendCode [post]
+func (a *AuthController) SMSCode() {
+	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
+		mobile := new(SmsCodeReq)
+		a.GetPostParams(mobile)
+		phoneNum := mobile.Mobile
+		if !authUtils.IsValidMobile(phoneNum) {
+			return result, exception.New(exception.IllegalPhoneNumber)
+		}
+		code, err := authUtils.GenerateCode(6)
+		if err != nil {
+			logger.Warn("生成验证码失败:%v", err)
+			return result, exception.New(exception.SMSCodeGenerateFailed)
+		}
+		fmt.Println("验证码:", code)
+		//发送短息
+		_, err = a.message().SendSms(phoneNum, code)
+		if err != nil {
+			logger.Warn("发送短信失败:%v", err)
+			return result, exception.New(exception.SendingSMSFailed)
+		}
+		err = a.Cache().SetString(redis.GenerateSmsKey(phoneNum), code, a.message().GetExpireMinute())
+		if err != nil {
+			return result, err
+		}
+		result = &controllers.WrapData{Msg: "验证码发送成功"}
+		return result, nil
+	})
+}

+ 16 - 2
controllers/user/user_controller.go

@@ -1,14 +1,27 @@
 package user
 
 import (
+	"errors"
+	"eta_mini_ht_api/common/component/cache"
+	logger "eta_mini_ht_api/common/component/log"
+	"eta_mini_ht_api/controllers"
 	"eta_mini_ht_api/domian/user"
 	"fmt"
-	beego "github.com/beego/beego/v2/server/web"
 )
 
 // Operations about Users
 type UserController struct {
-	beego.Controller
+	controllers.BaseController
+	redis *cache.RedisCache
+}
+
+func (u *UserController) Prepare() {
+	u.redis = cache.GetInstance()
+}
+
+type LoginCode struct {
+	Code int    `json:"code"`
+	Msg  string `json:"msg"`
 }
 
 // @Title GetAll
@@ -16,6 +29,7 @@ type UserController struct {
 // @Success 200 {object} models.User
 // @router / [get]
 func (u *UserController) GetAll() {
+	logger.Warn("查询用户列表:%s", errors.New("chakanjieuog"))
 	fmt.Print("查询用户列表")
 	users := user.GetUsers()
 	u.Data["json"] = users

+ 47 - 0
controllers/ws_controller.go

@@ -0,0 +1,47 @@
+package controllers
+
+import (
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/gorilla/websocket"
+	"net/http"
+	"time"
+)
+
+var upgrader = websocket.Upgrader{
+	CheckOrigin: func(r *http.Request) bool {
+		return true // 允许跨域连接
+	},
+}
+
+type WebSocketController struct {
+	beego.Controller
+}
+
+func (c *WebSocketController) Connect() {
+	ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
+	if err != nil {
+		//beego.Error(err)
+		return
+	}
+	defer ws.Close()
+
+	for {
+		var msg string
+		_, _, err := ws.ReadMessage()
+		if err != nil {
+			//	beego.Error(err)
+			break
+		}
+		// 处理接收到的消息
+		fmt.Printf("Received: %s\n", msg)
+
+		// 发送消息回客户端
+		err = ws.WriteMessage(websocket.TextMessage, []byte("Server: "+msg))
+		if err != nil {
+			//beego.Error(err)
+			break
+		}
+		time.Sleep(time.Second) // 模拟延迟
+	}
+}

+ 25 - 0
domian/sms/emas_sms_service.go

@@ -0,0 +1,25 @@
+package sms
+
+import "eta_mini_ht_api/models/sms"
+
+type Msg struct {
+	Mobile  string
+	Content string
+}
+
+func SendSms(msg Msg) (err error) {
+	apiEntity := convert(msg)
+	err = sms.Send(apiEntity)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func convert(msg Msg) sms.ApiMtZsyyt {
+	return sms.ApiMtZsyyt{
+		SMID:    1,
+		Mobiles: msg.Mobile,
+		Content: msg.Content,
+	}
+}

BIN
eta_mini_ht_api.exe~


+ 5 - 0
facade/user/user_facade.go

@@ -0,0 +1,5 @@
+package user
+
+func Login() {
+
+}

+ 3 - 2
go.mod

@@ -5,7 +5,10 @@ go 1.21
 require (
 	github.com/beego/beego/v2 v2.2.2
 	github.com/go-redis/redis/v8 v8.11.5
+	github.com/gorilla/websocket v1.5.3
 	github.com/medivhzhan/weapp/v3 v3.8.1
+	gorm.io/driver/mysql v1.5.7
+	gorm.io/gorm v1.25.11
 )
 
 require (
@@ -33,6 +36,4 @@ require (
 	golang.org/x/text v0.16.0 // indirect
 	google.golang.org/protobuf v1.34.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	gorm.io/driver/mysql v1.5.7 // indirect
-	gorm.io/gorm v1.25.11 // indirect
 )

+ 2 - 4
go.sum

@@ -24,6 +24,8 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv
 github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@@ -73,8 +75,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
@@ -91,7 +91,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
 gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
 gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
-gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
-gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
 gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
 gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=

+ 14 - 13
main.go

@@ -3,11 +3,8 @@ package main
 import (
 	_ "eta_mini_ht_api/common/component"
 	logger "eta_mini_ht_api/common/component/log"
-	"eta_mini_ht_api/common/exception"
 	_ "eta_mini_ht_api/routers"
 	"github.com/beego/beego/v2/server/web"
-	"github.com/beego/beego/v2/server/web/filter/cors"
-	"time"
 )
 
 func main() {
@@ -15,19 +12,23 @@ func main() {
 		web.BConfig.WebConfig.DirectoryIndex = true
 		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
 	}
-
 	logger.Info("初始化成功")
-	web.InsertFilter("*", web.BeforeRouter, cors.Allow(&cors.Options{
-		AllowAllOrigins:  true, // 允许所有来源的请求
-		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
-		AllowHeaders:     []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
-		ExposeHeaders:    []string{"Content-Length"},
-		AllowCredentials: true,
-		MaxAge:           12 * time.Hour,
-	}))
+	//web.InsertFilter("*", web.BeforeRouter, cors.Allow(&cors.Options{
+	//	AllowAllOrigins:  true, // 允许所有来源的请求
+	//	AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
+	//	AllowHeaders:     []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
+	//	ExposeHeaders:    []string{"Content-Length"},
+	//	AllowCredentials: true,
+	//	MaxAge:           12 * time.Hour,
+	//}))
 	//增加授权拦截
 	//web.InsertFilter("*", web.BeforeRouter, middleware.AuthMiddleware())
 	//web.ErrorHandler("*", exception.ControllerAdvice())
-	web.BConfig.RecoverFunc = exception.PanicAdvice
+	//web.BConfig.RecoverFunc = exception.PanicAdvice
+	go func() {
+		//内存数据预热预加载
+		logger.Info("开始预加载数据")
+	}()
 	web.Run()
+
 }

+ 1 - 1
middleware/auth_middleware.go

@@ -16,7 +16,7 @@ const (
 func AuthMiddleware() web.FilterFunc {
 	return func(ctx *context.Context) {
 		path := ctx.Input.URL()
-		logger.Info("请求路径" + path)
+		logger.Info("请求路径:%v", path)
 		if path == "/swagger" || path == "/swagger/*" || path == "/favicon.ico" {
 			return
 		}

+ 43 - 0
models/sms/api_mt_zsyyt.go

@@ -0,0 +1,43 @@
+package sms
+
+import (
+	"eta_mini_ht_api/common/component/database"
+	"gorm.io/gorm"
+	"time"
+)
+
+type ApiMtZsyyt struct {
+	SMID           uint32    `gorm:"column:SM_ID;type:decimal(8,0) unsigned;not null;default:0"`
+	SrcID          uint32    `gorm:"column:SRC_ID;type:decimal(8,0) unsigned;not null;default:0"`
+	Mobiles        string    `gorm:"column:MOBILES;type:longtext;not null"`
+	Content        string    `gorm:"column:CONTENT;type:text;not null"`
+	IsWap          bool      `gorm:"column:IS_WAP;type:tinyint(1);not null;default:0"`
+	URL            string    `gorm:"column:URL;type:varchar(110);not null;default:''"`
+	SendTime       time.Time `gorm:"column:SEND_TIME;type:datetime;default:'0000-00-00 00:00:00'"`
+	SmType         uint8     `gorm:"column:SM_TYPE;type:tinyint(1);not null;default:0"`
+	MsgFmt         int       `gorm:"column:MSG_FMT;type:int(11);not null;default:0"`
+	TpPid          uint8     `gorm:"column:TP_PID;type:tinyint(1);not null;default:0"`
+	TpUdhi         uint8     `gorm:"column:TP_UDHI;type:tinyint(1);not null;default:0"`
+	FeeTerminalId  string    `gorm:"column:FEE_TERMINAL_ID;type:varchar(10);not null;default:''"`
+	FeeType        string    `gorm:"column:FEE_TYPE;type:varchar(10);not null;default:''"`
+	FeeCode        string    `gorm:"column:FEE_CODE;type:varchar(10);not null;default:''"`
+	FeeUserType    int       `gorm:"column:FEE_USER_TYPE;type:int(11);not null;default:0"`
+	UnicodeContent string    `gorm:"column:UNICODE_CONTENT;type:text;not null"`
+}
+
+func (ApiMtZsyyt) TableName() string {
+	return "api_mt_zsyyt"
+}
+func db() *gorm.DB {
+	return database.Select(database.EMAS)
+}
+
+// 发送短信方法
+func Send(msg ApiMtZsyyt) error {
+	// 创建记录
+	err := db().Create(&msg).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 5 - 0
models/sms/sms_code.go

@@ -0,0 +1,5 @@
+package sms
+
+func saveCode() {
+
+}

+ 18 - 0
routers/commentsRouter.go

@@ -7,6 +7,24 @@ import (
 
 func init() {
 
+    beego.GlobalControllerRouter["eta_mini_ht_api/controllers/user:AuthController"] = append(beego.GlobalControllerRouter["eta_mini_ht_api/controllers/user:AuthController"],
+        beego.ControllerComments{
+            Method: "Login",
+            Router: `/login`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_mini_ht_api/controllers/user:AuthController"] = append(beego.GlobalControllerRouter["eta_mini_ht_api/controllers/user:AuthController"],
+        beego.ControllerComments{
+            Method: "SMSCode",
+            Router: `/sendCode`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta_mini_ht_api/controllers/user:UserController"] = append(beego.GlobalControllerRouter["eta_mini_ht_api/controllers/user:UserController"],
         beego.ControllerComments{
             Method: "GetAll",

+ 6 - 1
routers/router.go

@@ -6,12 +6,17 @@ import (
 )
 
 func init() {
-	ns := beego.NewNamespace("/v1",
+	ns := beego.NewNamespace("/htapi",
 		beego.NSNamespace("/user",
 			beego.NSInclude(
 				&user.UserController{},
 			),
 		),
+		beego.NSNamespace("/auth",
+			beego.NSInclude(
+				&user.AuthController{},
+			),
+		),
 	)
 	beego.AddNamespace(ns)
 }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
swagger/swagger-ui-bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
swagger/swagger-ui-es-bundle-core.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
swagger/swagger-ui-es-bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
swagger/swagger-ui.js


+ 117 - 16
swagger/swagger.json

@@ -3,12 +3,65 @@
     "info": {
         "contact": {}
     },
-    "schemes": [
-        "http",
-        "https"
-    ],
-    "basePath": "/v1",
+    "basePath": "/htapi",
     "paths": {
+        "/auth/login": {
+            "post": {
+                "tags": [
+                    "auth"
+                ],
+                "summary": "小程序用户登录",
+                "description": "用户通过微信小程序登录\n\u003cbr\u003e",
+                "parameters": [
+                    {
+                        "in": "body",
+                        "name": "code",
+                        "description": "获取微信小程序code",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        },
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/controllers.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/auth/sendCode": {
+            "post": {
+                "tags": [
+                    "auth"
+                ],
+                "summary": "获取手机验证码",
+                "description": "用户发送手机验证码\n\u003cbr\u003e",
+                "parameters": [
+                    {
+                        "in": "body",
+                        "name": "mobile",
+                        "description": "小程序手机验证码接口",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/SmsCodeReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/controllers.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
         "/user/": {
             "get": {
                 "tags": [
@@ -28,22 +81,64 @@
         }
     },
     "definitions": {
-        "models.Profile": {
-            "title": "Profile",
+        "SmsCodeReq": {
+            "title": "SmsCodeReq",
+            "type": "object"
+        },
+        "controllers.BaseResponse": {
+            "title": "BaseResponse",
             "type": "object",
             "properties": {
-                "Address": {
-                    "type": "string"
+                "Data": {
+                    "$ref": "#/definitions/controllers.interface"
                 },
-                "Age": {
+                "ErrCode": {
                     "type": "integer",
                     "format": "int64"
                 },
-                "Email": {
+                "ErrMsg": {
                     "type": "string"
                 },
-                "Gender": {
+                "Msg": {
                     "type": "string"
+                },
+                "Ret": {
+                    "description": "返回状态码",
+                    "type": "integer",
+                    "format": "int64"
+                },
+                "Success": {
+                    "description": "true 执行成功,false 执行失败",
+                    "type": "boolean"
+                }
+            }
+        },
+        "controllers.interface": {
+            "title": "interface",
+            "type": "object"
+        },
+        "gorm.DeletedAt": {
+            "title": "DeletedAt",
+            "type": "object"
+        },
+        "gorm.Model": {
+            "title": "Model",
+            "type": "object",
+            "properties": {
+                "CreatedAt": {
+                    "type": "string",
+                    "format": "datetime"
+                },
+                "DeletedAt": {
+                    "$ref": "#/definitions/gorm.DeletedAt"
+                },
+                "ID": {
+                    "type": "integer",
+                    "format": "int32"
+                },
+                "UpdatedAt": {
+                    "type": "string",
+                    "format": "datetime"
                 }
             }
         },
@@ -51,14 +146,20 @@
             "title": "User",
             "type": "object",
             "properties": {
-                "Id": {
+                "Gender": {
                     "type": "string"
                 },
-                "Password": {
+                "Mobile": {
                     "type": "string"
                 },
-                "Profile": {
-                    "$ref": "#/definitions/models.Profile"
+                "NickName": {
+                    "type": "string"
+                },
+                "OpenId": {
+                    "type": "string"
+                },
+                "Password": {
+                    "type": "string"
                 },
                 "Username": {
                     "type": "string"

+ 86 - 10
swagger/swagger.yml

@@ -1,7 +1,48 @@
 swagger: "2.0"
 info: {}
-basePath: /v1
+basePath: /htapi
 paths:
+  /auth/login:
+    post:
+      tags:
+      - auth
+      summary: 小程序用户登录
+      description: |-
+        用户通过微信小程序登录
+        <br>
+      parameters:
+      - in: body
+        name: code
+        description: 获取微信小程序code
+        required: true
+        schema:
+          type: string
+        type: string
+      responses:
+        "200":
+          description: ""
+          schema:
+            $ref: '#/definitions/controllers.BaseResponse'
+  /auth/sendCode:
+    post:
+      tags:
+      - auth
+      summary: 获取手机验证码
+      description: |-
+        用户发送手机验证码
+        <br>
+      parameters:
+      - in: body
+        name: mobile
+        description: 小程序手机验证码接口
+        required: true
+        schema:
+          $ref: '#/definitions/SmsCodeReq'
+      responses:
+        "200":
+          description: ""
+          schema:
+            $ref: '#/definitions/controllers.BaseResponse'
   /user/:
     get:
       tags:
@@ -16,29 +57,64 @@ paths:
           schema:
             $ref: '#/definitions/models.User'
 definitions:
-  models.Profile:
-    title: Profile
+  SmsCodeReq:
+    title: SmsCodeReq
+    type: object
+  controllers.BaseResponse:
+    title: BaseResponse
     type: object
     properties:
-      Address:
+      Data:
+        $ref: '#/definitions/controllers.interface'
+      ErrCode:
+        type: integer
+        format: int64
+      ErrMsg:
+        type: string
+      Msg:
         type: string
-      Age:
+      Ret:
+        description: 返回状态码
         type: integer
         format: int64
-      Email:
+      Success:
+        description: true 执行成功,false 执行失败
+        type: boolean
+  controllers.interface:
+    title: interface
+    type: object
+  gorm.DeletedAt:
+    title: DeletedAt
+    type: object
+  gorm.Model:
+    title: Model
+    type: object
+    properties:
+      CreatedAt:
         type: string
-      Gender:
+        format: datetime
+      DeletedAt:
+        $ref: '#/definitions/gorm.DeletedAt'
+      ID:
+        type: integer
+        format: int32
+      UpdatedAt:
         type: string
+        format: datetime
   models.User:
     title: User
     type: object
     properties:
-      Id:
+      Gender:
+        type: string
+      Mobile:
+        type: string
+      NickName:
+        type: string
+      OpenId:
         type: string
       Password:
         type: string
-      Profile:
-        $ref: '#/definitions/models.Profile'
       Username:
         type: string
 tags:

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio