Browse Source

新增微信二维码获取、短信验证码发送

Ohio-HYF 2 years ago
parent
commit
3a34f4476d

+ 1 - 0
config/init.go

@@ -35,6 +35,7 @@ func loadExternelConfig(config *system_model.Config) {
 	redis.Init(config.Redis)
 	service.LoginAuthInit(config.Server.Session)
 	service.SendCodeInit(config.Server.Session)
+	service.QrCodeInit(config.Server.Session)
 }
 
 func getEnv() string {

+ 42 - 0
core/escape.go

@@ -0,0 +1,42 @@
+// based on https://github.com/golang/go/blob/master/src/net/url/url.go
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package core
+
+func shouldEscape(c byte) bool {
+	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c == '-' || c == '~' || c == '.' {
+		return false
+	}
+	return true
+}
+func escape(s string) string {
+	hexCount := 0
+	for i := 0; i < len(s); i++ {
+		c := s[i]
+		if shouldEscape(c) {
+			hexCount++
+		}
+	}
+
+	if hexCount == 0 {
+		return s
+	}
+
+	t := make([]byte, len(s)+2*hexCount)
+	j := 0
+	for i := 0; i < len(s); i++ {
+		switch c := s[i]; {
+		case shouldEscape(c):
+			t[j] = '%'
+			t[j+1] = "0123456789ABCDEF"[c>>4]
+			t[j+2] = "0123456789ABCDEF"[c&15]
+			j += 3
+		default:
+			t[j] = s[i]
+			j++
+		}
+	}
+	return string(t)
+}

+ 208 - 0
core/signer.go

@@ -0,0 +1,208 @@
+// HWS API Gateway Signature
+// based on https://github.com/datastream/aws/blob/master/signv4.go
+// Copyright (c) 2014, Xianjie
+
+package core
+
+import (
+	"bytes"
+	"crypto/hmac"
+	"crypto/sha256"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"sort"
+	"strings"
+	"time"
+)
+
+const (
+	BasicDateFormat     = "20060102T150405Z"
+	Algorithm           = "SDK-HMAC-SHA256"
+	HeaderXDate         = "X-Sdk-Date"
+	HeaderHost          = "host"
+	HeaderAuthorization = "Authorization"
+	HeaderContentSha256 = "X-Sdk-Content-Sha256"
+)
+
+func hmacsha256(key []byte, data string) ([]byte, error) {
+	h := hmac.New(sha256.New, []byte(key))
+	if _, err := h.Write([]byte(data)); err != nil {
+		return nil, err
+	}
+	return h.Sum(nil), nil
+}
+
+// Build a CanonicalRequest from a regular request string
+//
+// CanonicalRequest =
+//  HTTPRequestMethod + '\n' +
+//  CanonicalURI + '\n' +
+//  CanonicalQueryString + '\n' +
+//  CanonicalHeaders + '\n' +
+//  SignedHeaders + '\n' +
+//  HexEncode(Hash(RequestPayload))
+func CanonicalRequest(r *http.Request, signedHeaders []string) (string, error) {
+	var hexencode string
+	var err error
+	if hex := r.Header.Get(HeaderContentSha256); hex != "" {
+		hexencode = hex
+	} else {
+		data, err := RequestPayload(r)
+		if err != nil {
+			return "", err
+		}
+		hexencode, err = HexEncodeSHA256Hash(data)
+		if err != nil {
+			return "", err
+		}
+	}
+	return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", r.Method, CanonicalURI(r), CanonicalQueryString(r), CanonicalHeaders(r, signedHeaders), strings.Join(signedHeaders, ";"), hexencode), err
+}
+
+// CanonicalURI returns request uri
+func CanonicalURI(r *http.Request) string {
+	pattens := strings.Split(r.URL.Path, "/")
+	var uri []string
+	for _, v := range pattens {
+		uri = append(uri, escape(v))
+	}
+	urlpath := strings.Join(uri, "/")
+	if len(urlpath) == 0 || urlpath[len(urlpath)-1] != '/' {
+		urlpath = urlpath + "/"
+	}
+	return urlpath
+}
+
+// CanonicalQueryString
+func CanonicalQueryString(r *http.Request) string {
+	var keys []string
+	query := r.URL.Query()
+	for key := range query {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	var a []string
+	for _, key := range keys {
+		k := escape(key)
+		sort.Strings(query[key])
+		for _, v := range query[key] {
+			kv := fmt.Sprintf("%s=%s", k, escape(v))
+			a = append(a, kv)
+		}
+	}
+	queryStr := strings.Join(a, "&")
+	r.URL.RawQuery = queryStr
+	return queryStr
+}
+
+// CanonicalHeaders
+func CanonicalHeaders(r *http.Request, signerHeaders []string) string {
+	var a []string
+	header := make(map[string][]string)
+	for k, v := range r.Header {
+		header[strings.ToLower(k)] = v
+	}
+	for _, key := range signerHeaders {
+		value := header[key]
+		if strings.EqualFold(key, HeaderHost) {
+			value = []string{r.Host}
+		}
+		sort.Strings(value)
+		for _, v := range value {
+			a = append(a, key+":"+strings.TrimSpace(v))
+		}
+	}
+	return fmt.Sprintf("%s\n", strings.Join(a, "\n"))
+}
+
+// SignedHeaders
+func SignedHeaders(r *http.Request) []string {
+	var a []string
+	for key := range r.Header {
+		a = append(a, strings.ToLower(key))
+	}
+	sort.Strings(a)
+	return a
+}
+
+// RequestPayload
+func RequestPayload(r *http.Request) ([]byte, error) {
+	if r.Body == nil {
+		return []byte(""), nil
+	}
+	b, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return []byte(""), err
+	}
+	r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+	return b, err
+}
+
+// Create a "String to Sign".
+func StringToSign(canonicalRequest string, t time.Time) (string, error) {
+	hash := sha256.New()
+	_, err := hash.Write([]byte(canonicalRequest))
+	if err != nil {
+		return "", err
+	}
+	return fmt.Sprintf("%s\n%s\n%x",
+		Algorithm, t.UTC().Format(BasicDateFormat), hash.Sum(nil)), nil
+}
+
+// Create the HWS Signature.
+func SignStringToSign(stringToSign string, signingKey []byte) (string, error) {
+	hm, err := hmacsha256(signingKey, stringToSign)
+	return fmt.Sprintf("%x", hm), err
+}
+
+// HexEncodeSHA256Hash returns hexcode of sha256
+func HexEncodeSHA256Hash(body []byte) (string, error) {
+	hash := sha256.New()
+	if body == nil {
+		body = []byte("")
+	}
+	_, err := hash.Write(body)
+	return fmt.Sprintf("%x", hash.Sum(nil)), err
+}
+
+// Get the finalized value for the "Authorization" header. The signature parameter is the output from SignStringToSign
+func AuthHeaderValue(signature, accessKey string, signedHeaders []string) string {
+	return fmt.Sprintf("%s Access=%s, SignedHeaders=%s, Signature=%s", Algorithm, accessKey, strings.Join(signedHeaders, ";"), signature)
+}
+
+// Signature HWS meta
+type Signer struct {
+	Key    string
+	Secret string
+}
+
+// SignRequest set Authorization header
+func (s *Signer) Sign(r *http.Request) error {
+	var t time.Time
+	var err error
+	var dt string
+	if dt = r.Header.Get(HeaderXDate); dt != "" {
+		t, err = time.Parse(BasicDateFormat, dt)
+	}
+	if err != nil || dt == "" {
+		t = time.Now()
+		r.Header.Set(HeaderXDate, t.UTC().Format(BasicDateFormat))
+	}
+	signedHeaders := SignedHeaders(r)
+	canonicalRequest, err := CanonicalRequest(r, signedHeaders)
+	if err != nil {
+		return err
+	}
+	stringToSign, err := StringToSign(canonicalRequest, t)
+	if err != nil {
+		return err
+	}
+	signature, err := SignStringToSign(stringToSign, []byte(s.Secret))
+	if err != nil {
+		return err
+	}
+	authValue := AuthHeaderValue(signature, s.Key, signedHeaders)
+	r.Header.Set(HeaderAuthorization, authValue)
+	return nil
+}

+ 17 - 16
db/invoice.go

@@ -4,13 +4,14 @@ import (
 	context "context"
 	"encoding/json"
 	"fmt"
-	"github.com/issue9/conv"
-	"github.com/sirupsen/logrus"
 	"time"
 	"youngee_b_api/consts"
 	"youngee_b_api/model/gorm_model"
 	"youngee_b_api/model/http_model"
 	"youngee_b_api/util"
+
+	"github.com/issue9/conv"
+	"github.com/sirupsen/logrus"
 )
 
 func AddReceiveAddress(ctx context.Context, enterpriseId string, req *http_model.AddReceiveAddressRequest) error {
@@ -198,10 +199,10 @@ func GetBillingId(ctx context.Context, enterpriseId string) string {
 	}
 	return billingIdPrefix + last
 }
-func GetInvoiceRecords(ctx context.Context, req *http_model.GetInvoiceRecordRequest) (*http_model.InvoiceRecordsData, error) {
+func GetInvoiceRecords(ctx context.Context, req *http_model.GetInvoiceRecordRequest, enterpriseID string) (*http_model.InvoiceRecordsData, error) {
 	db := GetReadDB(ctx)
 	var invoiceRecords []*gorm_model.YounggeeInvoiceRecord
-	db = db.Debug().Model(gorm_model.YounggeeInvoiceRecord{}).Where("status = 2")
+	db = db.Debug().Model(gorm_model.YounggeeInvoiceRecord{}).Where("status = 2 and enterprise_id = ?", enterpriseID)
 	if req.BillingAt != "" {
 		db = db.Where("billing_at like ?", req.BillingAt+"%")
 	}
@@ -210,18 +211,18 @@ func GetInvoiceRecords(ctx context.Context, req *http_model.GetInvoiceRecordRequ
 		logrus.WithContext(ctx).Errorf("[GetInvoiceRecords] error query mysql limit, err:%+v", err)
 		return nil, err
 	}
-	var enterpriseIds []string
-	for _, invoiceRecord := range invoiceRecords {
-		enterpriseIds = append(enterpriseIds, invoiceRecord.EnterpriseID)
-	}
-	util.RemoveStrRepByMap(enterpriseIds)
-	enterpriseIdToUserInfoMap := make(map[string]gorm_model.Enterprise)
-	db1 := GetReadDB(ctx)
-	for _, v := range enterpriseIds {
-		enterpriseInfo := gorm_model.Enterprise{}
-		db1.Model(gorm_model.Enterprise{}).Where("enterprise_id = ?", v).Find(&enterpriseInfo)
-		enterpriseIdToUserInfoMap[v] = enterpriseInfo
-	}
+	// var enterpriseIds []string
+	// for _, invoiceRecord := range invoiceRecords {
+	// 	enterpriseIds = append(enterpriseIds, invoiceRecord.EnterpriseID)
+	// }
+	// util.RemoveStrRepByMap(enterpriseIds)
+	// enterpriseIdToUserInfoMap := make(map[string]gorm_model.Enterprise)
+	// db1 := GetReadDB(ctx)
+	// for _, v := range enterpriseIds {
+	// 	enterpriseInfo := gorm_model.Enterprise{}
+	// 	db1.Model(gorm_model.Enterprise{}).Where("enterprise_id = ?", v).Find(&enterpriseInfo)
+	// 	enterpriseIdToUserInfoMap[v] = enterpriseInfo
+	// }
 	var InvoiceRecords []*http_model.InvoiceRecordsPreviews
 	for _, invoiceRecord := range invoiceRecords {
 		InvoiceRecord := new(http_model.InvoiceRecordsPreviews)

+ 6 - 3
handler/getInvoiceRecord.go

@@ -1,12 +1,14 @@
 package handler
 
 import (
-	"github.com/gin-gonic/gin"
-	"github.com/sirupsen/logrus"
 	"youngee_b_api/consts"
 	"youngee_b_api/db"
+	"youngee_b_api/middleware"
 	"youngee_b_api/model/http_model"
 	"youngee_b_api/util"
+
+	"github.com/gin-gonic/gin"
+	"github.com/sirupsen/logrus"
 )
 
 func WrapGetInvoiceRecordHandler(ctx *gin.Context) {
@@ -33,7 +35,8 @@ func (g GetInvoiceRecordHandler) getRequest() interface{} {
 }
 
 func (g GetInvoiceRecordHandler) run() {
-	data, err := db.GetInvoiceRecords(g.ctx, g.req)
+	enterpriseID := middleware.GetSessionAuth(g.ctx).EnterpriseID
+	data, err := db.GetInvoiceRecords(g.ctx, g.req, enterpriseID)
 	if err != nil {
 		// 数据库查询失败,返回5001
 		logrus.Errorf("[GetInvoiceRecordHandler] call GetInvoiceRecords err:%+v\n", err)

+ 58 - 0
handler/qrcode.go

@@ -0,0 +1,58 @@
+package handler
+
+import (
+	"youngee_b_api/consts"
+	"youngee_b_api/model/http_model"
+	"youngee_b_api/service"
+	"youngee_b_api/util"
+
+	"github.com/gin-gonic/gin"
+	"github.com/sirupsen/logrus"
+)
+
+func WrapGetWxQRCodeHandler(ctx *gin.Context) {
+	handler := newGetWxQRCodeHandler(ctx)
+	baseRun(handler)
+}
+
+type GetWxQRCodeHandler struct {
+	ctx  *gin.Context
+	req  *http_model.GetWxQRCodeRequest
+	resp *http_model.CommonResponse
+}
+
+func (q GetWxQRCodeHandler) getContext() *gin.Context {
+	return q.ctx
+}
+
+func (q GetWxQRCodeHandler) getResponse() interface{} {
+	return q.resp
+}
+
+func (q GetWxQRCodeHandler) getRequest() interface{} {
+	return q.req
+}
+
+func (q GetWxQRCodeHandler) run() {
+	req := http_model.GetWxQRCodeRequest{}
+	req = *q.req
+	data, err := service.QrCode.GetWxQrCode(q.ctx, req.Scene, req.Page)
+	if err != nil {
+		logrus.WithContext(q.ctx).Errorf("[GetWxQRCodeHandler] error GetWxQrCode, err:%+v", err)
+		util.HandlerPackErrorResp(q.resp, consts.ErrorInternal, consts.DefaultToast)
+		return
+	}
+	q.resp.Data = data
+}
+
+func (q GetWxQRCodeHandler) checkParam() error {
+	return nil
+}
+
+func newGetWxQRCodeHandler(ctx *gin.Context) *GetWxQRCodeHandler {
+	return &GetWxQRCodeHandler{
+		ctx:  ctx,
+		req:  http_model.NewGetWxQRCodeRequest(),
+		resp: http_model.NewGetWxQRCodeResponse(),
+	}
+}

+ 26 - 19
handler/send_code.go

@@ -58,28 +58,35 @@ func (h *SendCodeHandler) run() {
 	vcode := service.SendCode.GetCode(h.ctx)
 	// 2. 发送验证码
 	fmt.Println(vcode)
-	if data.Email == "login" {
-		// 根据手机号查询邮箱
-		email, err := service.SendCode.GetEmailByPhone(h.ctx, data.Phone)
-		if err != nil {
-			logrus.Errorf("[SendeCodeHandler] call SetSession err:%+v\n", err)
-			if email != "" {
-				util.HandlerPackErrorResp(h.resp, consts.ErrorInternal, "账号不存在")
-			} else {
-				util.HandlerPackErrorResp(h.resp, consts.ErrorInternal, "")
-			}
-			log.Info("SendeCode fail,req:%+v", h.req)
-			return
-		}
-		subject := "Youngee验证码"
-		service.SMTPMailServiceIstance.SendHtmlMail(email, subject, vcode)
-	} else {
-		subject := "Youngee验证码"
-		service.SMTPMailServiceIstance.SendHtmlMail(data.Email, subject, vcode)
+	err := service.SendCode.SendCode(h.ctx, data.Phone, vcode)
+	if err != nil {
+		logrus.Errorf("[SendeCodeHandler] call SetSession err:%+v\n", err)
+		util.HandlerPackErrorResp(h.resp, consts.ErrorInternal, "")
+		log.Info("SendeCode fail,req:%+v", h.req)
+		return
 	}
+	// if data.Email == "login" {
+	// 	// 根据手机号查询邮箱
+	// 	email, err := service.SendCode.GetEmailByPhone(h.ctx, data.Phone)
+	// 	if err != nil {
+	// 		logrus.Errorf("[SendeCodeHandler] call SetSession err:%+v\n", err)
+	// 		if email != "" {
+	// 			util.HandlerPackErrorResp(h.resp, consts.ErrorInternal, "账号不存在")
+	// 		} else {
+	// 			util.HandlerPackErrorResp(h.resp, consts.ErrorInternal, "")
+	// 		}
+	// 		log.Info("SendeCode fail,req:%+v", h.req)
+	// 		return
+	// 	}
+	// 	subject := "Youngee验证码"
+	// 	service.SMTPMailServiceIstance.SendHtmlMail(email, subject, vcode)
+	// } else {
+	// 	subject := "Youngee验证码"
+	// 	service.SMTPMailServiceIstance.SendHtmlMail(data.Email, subject, vcode)
+	// }
 
 	// 3. {phone:code}存到redis
-	err := service.SendCode.SetSession(h.ctx, data.Phone, vcode)
+	err = service.SendCode.SetSession(h.ctx, data.Phone, vcode)
 	if err != nil {
 		logrus.Errorf("[SendeCodeHandler] call SetSession err:%+v\n", err)
 		util.HandlerPackErrorResp(h.resp, consts.ErrorInternal, "")

+ 23 - 0
licenses/license-datastream-aws

@@ -0,0 +1,23 @@
+Copyright (c) 2014, Xianjie
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 27 - 0
licenses/license-go

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 41 - 0
model/http_model/qecode.go

@@ -0,0 +1,41 @@
+package http_model
+
+type GetWxQRCodeRequest struct {
+	Scene string `json:"scene"` // 需要携带的参数,目前为任务id
+	Page  string `json:"page"`  // 页面path
+}
+
+type WxAccessTokenResponse struct {
+	AccessToken string `json:"access_token"` // 获取到的凭证
+	ExpiresIn   int    `json:"expires_in"`   // 凭证有效时间,单位:秒。目前是7200秒之内的值。
+	Errcode     int    `json:"errcode"`      // 错误码
+	Errmsg      string `json:"errmsg"`       // 错误信息
+}
+
+type WxQrCodeRequest struct {
+	Scene      string `json:"scene"`
+	Page       string `json:"page"`
+	Width      int    `json:"width,omitempty"`
+	CheckPath  bool   `json:"check_path,omitempty"`
+	EnvVersion string `json:"env_version,omitempty"`
+}
+
+type WxQrCodeResponse struct {
+	Errcode     int    `json:"errcode"`
+	Errmsg      string `json:"errmsg"`
+	ContentType string `json:"contentType"`
+	Buffer      []byte `json:"buffer"`
+}
+type GetWxQRCodeData struct {
+	QrCodeBytes []byte `json:"qr_code_bytes"`
+}
+
+func NewGetWxQRCodeRequest() *GetWxQRCodeRequest {
+	return new(GetWxQRCodeRequest)
+}
+
+func NewGetWxQRCodeResponse() *CommonResponse {
+	resp := new(CommonResponse)
+	resp.Data = new(GetWxQRCodeData)
+	return resp
+}

+ 2 - 0
route/init.go

@@ -124,5 +124,7 @@ func InitRoute(r *gin.Engine) {
 
 		m.POST("/project/recruit/getservicecharge", handler.WrapGetServiceChargeHandler) // 获取产品置换服务费
 		m.POST("/product/deletePhotoUrl", handler.WrapDeletePhotoUrlHandler)             // 在数据库中删除图片url
+
+		m.POST("/qrcode/getwxqrcode", handler.WrapGetWxQRCodeHandler) // 获取微信二维码
 	}
 }

+ 50 - 1
service/enterprise.go

@@ -2,13 +2,14 @@ package service
 
 import (
 	"context"
-	"github.com/issue9/conv"
 	"math/rand"
 	"time"
 	"youngee_b_api/db"
 	"youngee_b_api/model/gorm_model"
 	"youngee_b_api/model/http_model"
 
+	"github.com/issue9/conv"
+
 	log "github.com/sirupsen/logrus"
 )
 
@@ -64,3 +65,51 @@ func (*enterprise) CreateEnterpriseUser(ctx context.Context, newEnterprise http_
 		return res, nil
 	}
 }
+
+func (*enterprise) CreateEnterprise(ctx context.Context, phone string) (*http_model.RegisterData, error) {
+	user := gorm_model.YounggeeUser{
+		Phone:         phone,
+		User:          "1001",
+		Username:      phone,
+		Password:      "1001",
+		RealName:      "",
+		Role:          "3",
+		Email:         "",
+		LastLoginTime: time.Now().UTC().Local(),
+	}
+	userId, err := db.CreateUser(ctx, user)
+	if err != nil {
+		log.Infof("[CreateEnterpriseUser] fail,err:%+v", err)
+		return nil, err
+	} else {
+		rand.Seed(time.Now().UnixNano())
+		th := conv.MustString(time.Now().Hour())
+		tm := conv.MustString(time.Now().Minute())
+		if len(tm) < 2 {
+			tm = "0" + tm
+		}
+		if len(tm) < 2 {
+			th = "0" + th
+		}
+		ShowEnterpriseID := "1" + th + tm + conv.MustString(rand.Intn(10000-1000)+1000)
+		enterprise := &gorm_model.Enterprise{
+			EnterpriseID:     ShowEnterpriseID,
+			Industry:         1,
+			BusinessName:     phone,
+			UserID:           *userId,
+			Balance:          0,
+			FrozenBalance:    0,
+			AvailableBalance: 0,
+		}
+		enterpriseId, err := db.CreateEnterprise(ctx, *enterprise)
+		if err != nil {
+			log.Infof("[CreateEnterpriseUser] fail,err:%+v", err)
+			return nil, err
+		}
+		res := &http_model.RegisterData{
+			EnterpriseId: *enterpriseId,
+			UserID:       *userId,
+		}
+		return res, nil
+	}
+}

+ 10 - 3
service/login_auth.go

@@ -54,9 +54,16 @@ func (l *loginAuth) AuthCode(ctx context.Context, phone string, code string) (st
 	if err != nil {
 		return "", err
 	} else if user == nil {
-		// 账号不存在
-		logrus.Debugf("[AuthCode] auth fail,phone:%+v", phone)
-		return "账号不存在", errors.New("auth fail")
+		// 账号不存在,则注册账号
+		_, err = Enterprise.CreateEnterprise(ctx, phone)
+		if err != nil {
+			return "账号创建失败", err
+		}
+		user, err = db.GetUserByPhone(ctx, phone)
+		fmt.Println("login_auth", user, err)
+		if err != nil {
+			return "", err
+		}
 	} else if string(user.Role) != consts.BRole {
 		// 账号权限有误
 		logrus.Debugf("[AuthCode] auth fail,phone:%+v", phone)

+ 123 - 0
service/qrcode.go

@@ -0,0 +1,123 @@
+package service
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+	"youngee_b_api/consts"
+	"youngee_b_api/model/http_model"
+	"youngee_b_api/model/system_model"
+	"youngee_b_api/redis"
+)
+
+const (
+	accessTokenUrlFormat = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
+	qrCodeUrlFormat      = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"
+	wxAccesssTokenKey    = "wx_access_token"
+)
+
+var QrCode *qrcode
+
+type qrcode struct {
+	sessionTTL time.Duration
+}
+
+func QrCodeInit(config *system_model.Session) {
+	qrCode := new(qrcode)
+	qrCode.sessionTTL = time.Duration(config.TTL) * time.Minute
+	QrCode = qrCode
+}
+
+// getAndCacheWxAccessToken 获取并缓存微信的access token
+func getAndCacheWxAccessToken(ctx context.Context) (string, error) {
+	appId := "wxac396a3be7a16844"
+	secret := "c82ae9e75b4ed7d8022db5bda5371892"
+	url := fmt.Sprintf(accessTokenUrlFormat, appId, secret)
+
+	resp, err := http.Get(url)
+	if err != nil {
+		return "", errors.New("request access token failed")
+	}
+	defer resp.Body.Close()
+
+	// 解析微信服务端返回的信息
+	var accessTokenRes http_model.WxAccessTokenResponse
+	decoder := json.NewDecoder(resp.Body)
+	if err = decoder.Decode(&accessTokenRes); err != nil {
+		return "", errors.New("decode wx response failed")
+	}
+
+	if accessTokenRes.Errcode != 0 {
+		return "", errors.New("request access token failed")
+	}
+
+	// 缓存获取的access token,比微信返回的有效时间短5分钟失效
+	err = redis.Set(ctx, wxAccesssTokenKey, accessTokenRes.AccessToken, QrCode.sessionTTL)
+	if err != nil {
+		return "", err
+	}
+	return accessTokenRes.AccessToken, nil
+}
+
+func (q *qrcode) GetWxQrCode(ctx context.Context, Scene string, Page string) (*http_model.GetWxQRCodeData, error) {
+	// 获取access_token
+	accessToken, err := redis.Get(ctx, wxAccesssTokenKey)
+	if err != nil && err != consts.RedisNil {
+		// fmt.Printf("err: %+v\n", err)
+		return nil, err
+	}
+	if accessToken == "" {
+		// 如果没有缓存的access token 则获取并缓存
+		accessToken, err = getAndCacheWxAccessToken(ctx)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	qrRequest := http_model.WxQrCodeRequest{
+		Scene:      Scene,
+		Page:       Page,
+		Width:      430,
+		CheckPath:  false,
+		EnvVersion: "release",
+	}
+	jsonBody, err := json.Marshal(qrRequest)
+	if err != nil {
+		return nil, err
+	}
+
+	qrCodeUrl := fmt.Sprintf(qrCodeUrlFormat, accessToken)
+	resp, err := http.Post(qrCodeUrl, "application/json; charset=utf8", bytes.NewReader(jsonBody))
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	var qrcodeBytes []byte
+
+	switch header := resp.Header.Get("content-Type"); {
+	case strings.HasPrefix(header, "application/json"):
+		// 如果返回的是json结构,说明发生错误
+		var qrResponse *http_model.WxQrCodeResponse
+		decoder := json.NewDecoder(resp.Body)
+		if err = decoder.Decode(&qrResponse); err != nil {
+			return nil, err
+		}
+		return nil, nil
+	case strings.HasPrefix(header, "image"):
+		qrcodeBytes, err = ioutil.ReadAll(resp.Body)
+		if err != nil {
+			return nil, err
+		}
+	}
+	data := http_model.GetWxQRCodeData{
+		QrCodeBytes: qrcodeBytes,
+	}
+	return &data, nil
+}

+ 42 - 0
service/send_code.go

@@ -1,12 +1,17 @@
 package service
 
 import (
+	// "apig-sdk/go/core"
+	"bytes"
 	"context"
 	"errors"
 	"fmt"
+	"io/ioutil"
 	"math/rand"
+	"net/http"
 	"time"
 	"youngee_b_api/consts"
+	"youngee_b_api/core"
 	"youngee_b_api/db"
 	"youngee_b_api/model/system_model"
 	"youngee_b_api/redis"
@@ -56,3 +61,40 @@ func (s *sendCode) GetEmailByPhone(ctx context.Context, phone string) (string, e
 	}
 	return user.Email, nil
 }
+
+func (s *sendCode) SendCode(ctx context.Context, phone string, vcode string) error {
+	signer := core.Signer{
+		Key:    "9a9a78319abd43348b43ec59d23b44bb",
+		Secret: "ed588c47c681417fabe13c612dcfb046",
+	}
+	// sdRequest := http_model.SendCodeData{
+	// 	PhoneNumber: "17604018234",
+	// 	TemplateId:  "TPL_0000",
+	// 	Content:     "code:1234,expire_at:5",
+	// }
+	// jsonBody, err := json.Marshal(sdRequest)
+	// if err != nil {
+	// 	return err
+	// }
+	// content := fmt.Sprintf("【创信】你的验证码是" + vcode + ",3分钟内有效!")
+	templateId := "M4089F58FF"
+	url := fmt.Sprintf("https://smssend.apistore.huaweicloud.com/sms/send?receive=" + phone + "&templateId=" + templateId + "&values=" + vcode)
+	fmt.Printf("url: %+v\n", url)
+
+	r, _ := http.NewRequest("POST", url,
+		ioutil.NopCloser(bytes.NewBuffer([]byte("foo=bar"))))
+
+	r.Header.Add("x-stage", "RELEASE")
+	signer.Sign(r)
+
+	fmt.Printf("request: %+v\n", r)
+	resp, err := http.DefaultClient.Do(r)
+	fmt.Printf("resp: %+v\n", resp)
+	if err != nil {
+		return err
+	} else {
+		body, _ := ioutil.ReadAll(resp.Body)
+		fmt.Printf("resp: %+v\n", body)
+	}
+	return nil
+}