浏览代码

种草浏览量、浏览记录、发送短息验证码

Yankun168 9 月之前
父节点
当前提交
1c78fa79ca
共有 38 个文件被更改,包括 1168 次插入31 次删除
  1. 1 1
      .idea/JavaSceneConfigState.xml
  2. 9 0
      app/api/youngee_talent_api/talent_auth_post_api.go
  3. 21 3
      app/api/youngee_talent_api/talent_post_api.go
  4. 1 1
      app/model/model.go
  5. 11 0
      app/model/youngee_talent_model/project_info.go
  6. 2 2
      app/service/youngee_sectask_service/seletion_square.go
  7. 32 0
      app/service/youngee_talent_service/LoginFromSms.go
  8. 159 0
      app/service/youngee_talent_service/SendSmsCode.go
  9. 1 0
      app/service/youngee_talent_service/talent_ks_auth.go
  10. 5 3
      app/service/youngee_talent_service/wxlogin.go
  11. 11 5
      app/service/youngee_talent_service/wxshare.go
  12. 61 3
      app/service/youngee_task_service/project_info.go
  13. 39 0
      app/service/youngee_task_service/task_data.go
  14. 1 0
      app/system/sectask/sectask_api.go
  15. 2 1
      app/system/sectask/sectask_service.go
  16. 0 1
      app/utils/GetInfoFromSession.go
  17. 6 3
      app/utils/kuaidi100.go
  18. 二进制
      bin/main.exe
  19. 二进制
      bin/main.exe~
  20. 二进制
      bin/v3.5.1/linux_amd64/youngmini_server
  21. 二进制
      bin/v3.5.1/windows_amd64/youngmini_server.exe
  22. 二进制
      bin/v3.5.2/linux_amd64/youngmini_server
  23. 二进制
      bin/v3.5.2/windows_amd64/youngmini_server.exe
  24. 2 2
      config/config.toml
  25. 1 0
      go.mod
  26. 2 0
      go.sum
  27. 2 4
      main.go
  28. 2 0
      middleware/middleware_duplicate_verify.go
  29. 0 1
      middleware/middleware_wx_auth.go
  30. 2 1
      router/router.go
  31. 23 0
      vendor/github.com/satori/go.uuid/.travis.yml
  32. 20 0
      vendor/github.com/satori/go.uuid/LICENSE
  33. 65 0
      vendor/github.com/satori/go.uuid/README.md
  34. 206 0
      vendor/github.com/satori/go.uuid/codec.go
  35. 239 0
      vendor/github.com/satori/go.uuid/generator.go
  36. 78 0
      vendor/github.com/satori/go.uuid/sql.go
  37. 161 0
      vendor/github.com/satori/go.uuid/uuid.go
  38. 3 0
      vendor/modules.txt

+ 1 - 1
.idea/JavaSceneConfigState.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
 <project version="4">
   <component name="SmartInputSourceJavaSceneConfigState">
   <component name="SmartInputSourceJavaSceneConfigState">
-    <option name="customChineseScenes" value="{&quot;capsLockState&quot;:false,&quot;code&quot;:&quot;;Printf(format);Println(a);TalentHttpResult(Msg);panic(v);ListSecTaskTabRes(Msg)&quot;,&quot;enable&quot;:true,&quot;languageType&quot;:&quot;CHINESE&quot;,&quot;name&quot;:&quot;自定义中文切换&quot;,&quot;tip&quot;:&quot;&quot;}" />
+    <option name="customChineseScenes" value="{&quot;capsLockState&quot;:false,&quot;code&quot;:&quot;;Printf(format);TalentHttpResult(Msg);panic(v);ListSecTaskTabRes(Msg)&quot;,&quot;enable&quot;:true,&quot;languageType&quot;:&quot;CHINESE&quot;,&quot;name&quot;:&quot;自定义中文切换&quot;,&quot;tip&quot;:&quot;&quot;}" />
   </component>
   </component>
 </project>
 </project>

+ 9 - 0
app/api/youngee_talent_api/talent_auth_post_api.go

@@ -149,6 +149,15 @@ func (*talentAuthPostApi) AddTaskData(r *ghttp.Request) {
 	}
 	}
 }
 }
 
 
+// 收藏种草项目
+func (*talentAuthPostApi) ProjectCollection(r *ghttp.Request) {
+	res := youngee_task_service.ProjectCollection(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
 // UpdateLogisticsAddress 修改达人收货地址
 // UpdateLogisticsAddress 修改达人收货地址
 // youngee_task_info
 // youngee_task_info
 func (*talentAuthPostApi) UpdateLogisticsAddress(r *ghttp.Request) {
 func (*talentAuthPostApi) UpdateLogisticsAddress(r *ghttp.Request) {

+ 21 - 3
app/api/youngee_talent_api/talent_post_api.go

@@ -1,7 +1,6 @@
 package youngeetalentapi
 package youngeetalentapi
 
 
 import (
 import (
-	"fmt"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/net/ghttp"
 	"youngmini_server/app/service/youngee_talent_service"
 	"youngmini_server/app/service/youngee_talent_service"
 )
 )
@@ -11,11 +10,20 @@ var TalentPostApi = talentPostApi{}
 type talentPostApi struct {
 type talentPostApi struct {
 }
 }
 
 
-// Login 达人端登录
+// Login 达人端微信授权登录
 func (*talentPostApi) Login(r *ghttp.Request) {
 func (*talentPostApi) Login(r *ghttp.Request) {
 	// 向微信服务端校验登录凭证
 	// 向微信服务端校验登录凭证
 	res := youngee_talent_service.WxLogin(r)
 	res := youngee_talent_service.WxLogin(r)
-	fmt.Println("here")
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
+// Login 达人端手机号登录
+func (*talentPostApi) LoginFromSms(r *ghttp.Request) {
+	// 向微信服务端校验登录凭证
+	res := youngee_talent_service.LoginFromSms(r)
 	err := r.Response.WriteJson(res)
 	err := r.Response.WriteJson(res)
 	if err != nil {
 	if err != nil {
 		panic("write response error")
 		panic("write response error")
@@ -30,3 +38,13 @@ func (*talentPostApi) GetQrcode(r *ghttp.Request) {
 		panic("write response error")
 		panic("write response error")
 	}
 	}
 }
 }
+
+// 达人短信登录,发送验证码
+func (*talentPostApi) SendSmsCode(r *ghttp.Request) {
+	// 向微信服务端校验登录凭证
+	res := youngee_talent_service.SendSmsCode(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		r.Response.WriteJson("短信发送失败")
+	}
+}

+ 1 - 1
app/model/model.go

@@ -1310,7 +1310,7 @@ type YounggeeSelectionInfo struct {
 	IsRead           int         `orm:"is_read"              json:"is_read"`            // 是否已读
 	IsRead           int         `orm:"is_read"              json:"is_read"`            // 是否已读
 	AutoTaskId       int         `orm:"auto_task_id"         json:"auto_task_id"`       // 定时任务id
 	AutoTaskId       int         `orm:"auto_task_id"         json:"auto_task_id"`       // 定时任务id
 	AutoFailAt       *gtime.Time `orm:"auto_fail_at"         json:"auto_fail_at"`       // 失效自动处理时间
 	AutoFailAt       *gtime.Time `orm:"auto_fail_at"         json:"auto_fail_at"`       // 失效自动处理时间
-
+	Status           int         `orm:"status"         json:"status"`                   // 0代表未删除,1代表已删除
 }
 }
 
 
 // YounggeeSketchInfo is the golang structure for table younggee_sketch_info.
 // YounggeeSketchInfo is the golang structure for table younggee_sketch_info.

+ 11 - 0
app/model/youngee_talent_model/project_info.go

@@ -28,11 +28,22 @@ type ProjectInfo struct {
 	ApplyNum         int                `json:"apply_num"`        //
 	ApplyNum         int                `json:"apply_num"`        //
 	EnterpriseId     int                `json:"enterprise_id"`    // 所属企业id
 	EnterpriseId     int                `json:"enterprise_id"`    // 所属企业id
 	ProductId        int                `json:"product_id"`       // 关联商品id
 	ProductId        int                `json:"product_id"`       // 关联商品id
+	WatchedNum       int                `json:"watched_num"`      // 浏览量
 	RecruitStrategys []*RecruitStrategy `orm:"with:project_id=project_id"`
 	RecruitStrategys []*RecruitStrategy `orm:"with:project_id=project_id"`
 	ProductSnap      string             `orm:"product_snap"         json:"product_snap"`       // 商品信息快照
 	ProductSnap      string             `orm:"product_snap"         json:"product_snap"`       // 商品信息快照
 	ProductPhotoSnap string             `orm:"product_photo_snap"   json:"product_photo_snap"` // 商品图片快照
 	ProductPhotoSnap string             `orm:"product_photo_snap"   json:"product_photo_snap"` // 商品图片快照
 }
 }
 
 
+// 种草收藏列表
+type ProjectCollection struct {
+	gmeta.Meta   `orm:"younggee_project_collect_info"`
+	CollectionId int         `json:"collection_id"` // 主键自增长
+	TalentId     string      `json:"talent_id"`     //
+	ProjectId    string      `json:"project_id"`
+	CreateTime   *gtime.Time `json:"create_time"`
+	Delete       int         `json:"delete"` //默认为0。0:收藏。1:取消收藏
+}
+
 type ProjectInfoList struct {
 type ProjectInfoList struct {
 	MaxPage      int `json:"max_page"`
 	MaxPage      int `json:"max_page"`
 	ProjectInfos []*ProjectInfo
 	ProjectInfos []*ProjectInfo

+ 2 - 2
app/service/youngee_sectask_service/seletion_square.go

@@ -88,7 +88,7 @@ func GetSelectionList(r *ghttp.Request) *TalentHttpResult {
 
 
 	// 构造查询的条件
 	// 构造查询的条件
 	startId := pageIndex * cntPerPage
 	startId := pageIndex * cntPerPage
-	whereStr := fmt.Sprintf("(selection_status >= %d)", selectionStatusInProgress)
+	whereStr := fmt.Sprintf("(selection_status >= %d) AND (status = 0) ", selectionStatusInProgress)
 	/*	if platformList != nil {
 	/*	if platformList != nil {
 		whereStr = whereStr + " and platform in ("
 		whereStr = whereStr + " and platform in ("
 		for _, v := range platformList {
 		for _, v := range platformList {
@@ -332,7 +332,7 @@ func SignUpSecTask(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: -5, Msg: err.Error()}
 		return &TalentHttpResult{Code: -5, Msg: err.Error()}
 	}
 	}
 
 
-	// 收货地址详情
+	// 收货地址详情 生成的结果变成snap存在task表中,供快递100使用
 	address, err := g.DB().Model(dao.YoungeeTalentDeliveryAddress.Table).One("talent_id = ? and address_id = ?", tid, signSecTaskReq.AddressId)
 	address, err := g.DB().Model(dao.YoungeeTalentDeliveryAddress.Table).One("talent_id = ? and address_id = ?", tid, signSecTaskReq.AddressId)
 	if err != nil {
 	if err != nil {
 		return &TalentHttpResult{Code: -6, Msg: err.Error()}
 		return &TalentHttpResult{Code: -6, Msg: err.Error()}

+ 32 - 0
app/service/youngee_talent_service/LoginFromSms.go

@@ -0,0 +1,32 @@
+package youngee_talent_service
+
+import (
+	"fmt"
+	"github.com/gogf/gf/net/ghttp"
+)
+
+type LoginReq struct {
+	Phone string `json:"phone"`
+	Vcode string `json:"vcode"`
+}
+
+// 通过短信登录
+func LoginFromSms(r *ghttp.Request) *TalentHttpResult {
+	l := LoginReq{}
+	err := r.ParseForm(&l)
+	if err != nil {
+		fmt.Printf("前端数据解析错误")
+	}
+	vcode := GetCode()
+	fmt.Println("验证码为=====>", vcode)
+
+	err = SendCode(l.Phone, vcode)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: "短信发送失败"}
+	}
+
+	//验证码存redis
+	_ = SetRedis(l.Phone, vcode)
+
+	return &TalentHttpResult{Code: 1, Msg: "sendSmsCodeSuccess"}
+}

+ 159 - 0
app/service/youngee_talent_service/SendSmsCode.go

@@ -0,0 +1,159 @@
+package youngee_talent_service
+
+import (
+	"bytes"
+	"crypto/sha256"
+	"crypto/tls"
+	"encoding/base64"
+	"fmt"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	uuid "github.com/satori/go.uuid"
+	"io/ioutil"
+	"math/rand"
+	"net/http"
+	"net/url"
+	"strings"
+	"time"
+)
+
+// 无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
+const WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""
+
+// 无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
+const AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""
+
+type SendcodeReq struct {
+	Phone string `json:"phone"`
+}
+
+// 接口调用此函数
+func SendSmsCode(r *ghttp.Request) *TalentHttpResult {
+	l := SendcodeReq{}
+	err := r.ParseForm(&l)
+	if err != nil {
+		fmt.Printf("前端数据解析错误")
+	}
+	vcode := GetCode()
+	fmt.Println("验证码为=====>", vcode)
+
+	err = SendCode(l.Phone, vcode)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: "短信发送失败"}
+	}
+
+	//验证码存redis
+	_ = SetRedis(l.Phone, vcode)
+
+	return &TalentHttpResult{Code: 1, Msg: "sendSmsCodeSuccess"}
+}
+
+func SetRedis(phone string, vcode string) error {
+	err, _ := g.Redis().Do("SETEX", getRedisKey(phone), vcode, 120) //第三个参数以秒为单位
+	if err != nil {
+		fmt.Println("redis存储错误")
+	}
+	return nil
+}
+
+func getRedisKey(phone string) string {
+	return fmt.Sprintf("%s%s", "c_user:", phone)
+}
+
+// 发送验证码具体实现
+func SendCode(phone string, vcode string) error {
+	//必填,请参考"开发准备"获取如下数据,替换为实际值
+	apiAddress := "https://smsapi.cn-south-1.myhuaweicloud.com:443/sms/batchSendSms/v1" //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
+	appKey := "NETTvTJJie9ax03v9K5T4DFB9EV6"                                            //APP_Key
+	appSecret := "txi9kXIrxW0dVNMyAulrJf7XFNP7"                                         //APP_Secret
+	sender := "8823022707732"                                                           //国内短信签名通道号或国际/港澳台短信通道号
+	templateId := "7103cdd480d14d0aa8c68954a7dbeb6e"                                    //模板ID
+
+	//条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
+	//国际/港澳台短信不用关注该参数
+	signature := "样叽" //签名名称
+
+	//必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
+	receiver := "+86" + phone //短信接收人号码
+
+	//选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
+	statusCallBack := ""
+
+	/*
+	 * 选填,使用无变量模板时请赋空值 string templateParas = "";
+	 * 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为"[\"369751\"]"
+	 * 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
+	 * 模板中的每个变量都必须赋值,且取值不能为空
+	 * 查看更多模板和变量规范:产品介绍>模板和变量规范
+	 */
+	templateParas := "[\"" + vcode + "\"]" //模板变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。
+	// templateParas := "[\"12345678\"]" //模板变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。
+
+	body := buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature)
+	headers := make(map[string]string)
+	headers["Content-Type"] = "application/x-www-form-urlencoded"
+	headers["Authorization"] = AUTH_HEADER_VALUE
+	headers["X-WSSE"] = buildWsseHeader(appKey, appSecret)
+	resp, err := post(apiAddress, []byte(body), headers)
+	if err != nil {
+		return err
+	}
+	fmt.Println(resp)
+	return nil
+}
+
+func buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature string) string {
+	param := "from=" + url.QueryEscape(sender) + "&to=" + url.QueryEscape(receiver) + "&templateId=" + url.QueryEscape(templateId)
+	if templateParas != "" {
+		param += "&templateParas=" + url.QueryEscape(templateParas)
+	}
+	if statusCallBack != "" {
+		param += "&statusCallback=" + url.QueryEscape(statusCallBack)
+	}
+	if signature != "" {
+		param += "&signature=" + url.QueryEscape(signature)
+	}
+	return param
+}
+
+func post(url string, param []byte, headers map[string]string) (string, error) {
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+	}
+	client := &http.Client{Transport: tr}
+
+	req, err := http.NewRequest("POST", url, bytes.NewBuffer(param))
+	if err != nil {
+		return "", err
+	}
+	for key, header := range headers {
+		req.Header.Set(key, header)
+	}
+
+	resp, err := client.Do(req)
+	defer resp.Body.Close()
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+	return string(body), nil
+}
+
+func buildWsseHeader(appKey, appSecret string) string {
+	var cTime = time.Now().Format("2006-01-02T15:04:05Z")
+	var nonce = uuid.NewV4().String()
+	nonce = strings.ReplaceAll(nonce, "-", "")
+
+	h := sha256.New()
+	h.Write([]byte(nonce + cTime + appSecret))
+	passwordDigestBase64Str := base64.StdEncoding.EncodeToString(h.Sum(nil))
+
+	return fmt.Sprintf(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, cTime)
+}
+
+// 随机生成6位数验证码
+func GetCode() string {
+	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
+	vcode := fmt.Sprintf("%06v", rnd.Int31n(1000000))
+	return vcode
+}

+ 1 - 0
app/service/youngee_talent_service/talent_ks_auth.go

@@ -101,6 +101,7 @@ func CheckAccount(r *ghttp.Request) *TalentHttpResult {
 func CheckNewAccount(r *ghttp.Request) *TalentHttpResult {
 func CheckNewAccount(r *ghttp.Request) *TalentHttpResult {
 	//check到了更新时间在两秒内的插入的数据。则说明已绑定。弹窗消失。
 	//check到了更新时间在两秒内的插入的数据。则说明已绑定。弹窗消失。
 	//达人id获取
 	//达人id获取
+	fmt.Println("***********into checknewaccount")
 	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	if err != nil {
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"}
 		return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"}

+ 5 - 3
app/service/youngee_talent_service/wxlogin.go

@@ -28,6 +28,7 @@ const (
 )
 )
 
 
 func WxLogin(r *ghttp.Request) *TalentHttpResult {
 func WxLogin(r *ghttp.Request) *TalentHttpResult {
+
 	l := youngee_talent_model.WxLoginInfo{}
 	l := youngee_talent_model.WxLoginInfo{}
 	err := r.ParseForm(&l)
 	err := r.ParseForm(&l)
 	if err != nil {
 	if err != nil {
@@ -38,7 +39,6 @@ func WxLogin(r *ghttp.Request) *TalentHttpResult {
 	secret := g.Config().GetString("miniapp.appsecret")
 	secret := g.Config().GetString("miniapp.appsecret")
 
 
 	url := fmt.Sprintf(urlformat, appId, secret, l.Code)
 	url := fmt.Sprintf(urlformat, appId, secret, l.Code)
-	fmt.Println("url----->", url)
 	//通过前端uni.login获得了code用于拼接url
 	//通过前端uni.login获得了code用于拼接url
 	resp, err := http.Get(url)
 	resp, err := http.Get(url)
 	if err != nil {
 	if err != nil {
@@ -109,7 +109,7 @@ func WxLogin(r *ghttp.Request) *TalentHttpResult {
 		}
 		}
 	}
 	}
 
 
-	// 用微信的openid和SessionKey的md5做为token
+	// 用微信的openid和SessionKey的md5做为token。会一直生效
 	token, err := gmd5.EncryptString(wxResp.OpenId + wxResp.SessionKey)
 	token, err := gmd5.EncryptString(wxResp.OpenId + wxResp.SessionKey)
 	fmt.Println("token is " + token)
 	fmt.Println("token is " + token)
 	if err != nil {
 	if err != nil {
@@ -117,7 +117,9 @@ func WxLogin(r *ghttp.Request) *TalentHttpResult {
 	}
 	}
 	res.Token = token
 	res.Token = token
 
 
-	// 以token为键保存session
+	// 以token为键保存session 存储在服务器中
+	//自动生成一个 session ID 并通过 Cookie 将其发送给客户端,以便在后续请求中识别该客户端的会话
+	//自动生成一个 session ID,并通过 `Set-Cookie` 头将其发送给客户端,前端可以通过r.header['Set-Cookie']获取cookie
 	err = r.Session.Set(token, g.Map{
 	err = r.Session.Set(token, g.Map{
 		"talentId":     newTalentId,
 		"talentId":     newTalentId,
 		"wxOpenId":     wxResp.OpenId,
 		"wxOpenId":     wxResp.OpenId,

+ 11 - 5
app/service/youngee_talent_service/wxshare.go

@@ -16,15 +16,18 @@ import (
 )
 )
 
 
 const (
 const (
+	//获取调用微信小程序接口的access_token   7200s有效期
 	accessTokenUrlFormat = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
 	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"
+	//获取小程序码
+	qrCodeUrlFormat   = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"
+	wxAccesssTokenKey = "wx_access_token"
 )
 )
 
 
-// getAndCacheWxAccessToken 获取并缓存微信的access token
+// getAndCacheWxAccessToken 获取分享的微信二维码。如果没有token,则获取并且缓存获取并缓存微信的access token
 func getAndCacheWxAccessToken() (string, error) {
 func getAndCacheWxAccessToken() (string, error) {
 	appId := g.Config().GetString("miniapp.appid")
 	appId := g.Config().GetString("miniapp.appid")
 	secret := g.Config().GetString("miniapp.appsecret")
 	secret := g.Config().GetString("miniapp.appsecret")
+	//获取access_token的网址
 	url := fmt.Sprintf(accessTokenUrlFormat, appId, secret)
 	url := fmt.Sprintf(accessTokenUrlFormat, appId, secret)
 
 
 	resp, err := http.Get(url)
 	resp, err := http.Get(url)
@@ -44,14 +47,14 @@ func getAndCacheWxAccessToken() (string, error) {
 		return "", errors.New("request access token failed")
 		return "", errors.New("request access token failed")
 	}
 	}
 
 
-	// 缓存获取的access token,比微信返回的有效时间短5分钟失效
+	// 缓存获取的access token,比微信返回的有效时间短5分钟失效  SETEX key expiretime value
 	_, err = g.Redis().Do("SETEX", wxAccesssTokenKey, accessTokenRes.ExpiresIn-300, accessTokenRes.AccessToken)
 	_, err = g.Redis().Do("SETEX", wxAccesssTokenKey, accessTokenRes.ExpiresIn-300, accessTokenRes.AccessToken)
 
 
 	return accessTokenRes.AccessToken, nil
 	return accessTokenRes.AccessToken, nil
 }
 }
 
 
 func RequestShareInfo(r *ghttp.Request) *TalentHttpResult {
 func RequestShareInfo(r *ghttp.Request) *TalentHttpResult {
-
+	fmt.Println("*****into******")
 	var requestArg *youngee_talent_model.ShareRequest
 	var requestArg *youngee_talent_model.ShareRequest
 	if err := r.ParseForm(&requestArg); err != nil {
 	if err := r.ParseForm(&requestArg); err != nil {
 		return &TalentHttpResult{Code: -1, Msg: "param error"}
 		return &TalentHttpResult{Code: -1, Msg: "param error"}
@@ -59,6 +62,7 @@ func RequestShareInfo(r *ghttp.Request) *TalentHttpResult {
 
 
 	// 获取access_token
 	// 获取access_token
 	var accessToken string
 	var accessToken string
+	//DoVar:是一个 gredis 的方法,用于执行 Redis 命令并返回一个 gvar.Var 类型的值,这个类型可以方便地进行各种类型转换。
 	accessTokenVar, err := g.Redis().DoVar("GET", "wx_access_token")
 	accessTokenVar, err := g.Redis().DoVar("GET", "wx_access_token")
 	if err != nil {
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "get access token from cache err"}
 		return &TalentHttpResult{Code: -2, Msg: "get access token from cache err"}
@@ -71,6 +75,8 @@ func RequestShareInfo(r *ghttp.Request) *TalentHttpResult {
 		// 取缓存的access token
 		// 取缓存的access token
 		accessToken = accessTokenVar.String()
 		accessToken = accessTokenVar.String()
 	}
 	}
+	accessToken = accessTokenVar.String()
+	fmt.Println("*****wx_access_token******", accessToken)
 
 
 	qrRequest := youngee_talent_model.WxQrCodeRequest{
 	qrRequest := youngee_talent_model.WxQrCodeRequest{
 		Scene:      requestArg.Scene,
 		Scene:      requestArg.Scene,

+ 61 - 3
app/service/youngee_task_service/project_info.go

@@ -2,11 +2,16 @@ package youngee_task_service
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"github.com/gogf/gf/os/glog"
+	"github.com/gogf/gf/os/gtime"
+	"github.com/gogf/gf/util/gconv"
 	"reflect"
 	"reflect"
+	"strconv"
 	"strings"
 	"strings"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model/youngee_talent_model"
 	"youngmini_server/app/model/youngee_talent_model"
+	"youngmini_server/app/utils"
 
 
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/net/ghttp"
@@ -167,6 +172,18 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: -6, Msg: "查询数据库失败"}
 		return &TalentHttpResult{Code: -6, Msg: "查询数据库失败"}
 	}
 	}
 
 
+	// 查询每个商品的浏览量
+	for i, project := range projectInfoList.ProjectInfos {
+		projectViewKey := "project:view:" + gconv.String(project.ProjectId)
+		//redis中取浏览量 返回的是gvar.Var类型。 不存咋则为nil。经过viewCount.Int变成0
+		viewCount, err := g.Redis().DoVar("GET", projectViewKey)
+		if err != nil {
+			glog.Error(err)
+			return &TalentHttpResult{Code: 0, Msg: "Redis error"}
+		}
+		projectInfoList.ProjectInfos[i].WatchedNum = viewCount.Int()
+	}
+
 	projectInfoList.MaxPage = maxPage
 	projectInfoList.MaxPage = maxPage
 
 
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: projectInfoList}
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: projectInfoList}
@@ -174,15 +191,56 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 
 
 // 获取单个项目详情service
 // 获取单个项目详情service
 func GetProjectDetail(r *ghttp.Request) *TalentHttpResult {
 func GetProjectDetail(r *ghttp.Request) *TalentHttpResult {
+	tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	pid := r.GetQueryInt("projectid", 0)
 	pid := r.GetQueryInt("projectid", 0)
-
+	// Redis key
+	projectViewKey := "project:view:" + strconv.Itoa(pid)
+	userViewedKey := "user:viewed:" + tid + ":" + strconv.Itoa(pid)
 	if pid == 0 {
 	if pid == 0 {
 		return &TalentHttpResult{Code: -2, Msg: "parse param error"}
 		return &TalentHttpResult{Code: -2, Msg: "parse param error"}
 	}
 	}
+	//在redis中增加浏览量
+	// Check if the user has already viewed the product
+	//DoVar方便进行类型转化
+	viewed, err := g.Redis().DoVar("GET", userViewedKey)
+	if err != nil {
+		glog.Error(err)
+		return &TalentHttpResult{Code: 0, Msg: "Redis error"}
+	}
 
 
-	var ProjectDetail *youngee_talent_model.ProjectDetail
-	err := g.DB().Model(youngee_talent_model.ProjectDetail{}).WithAll().Where("project_id", pid).Scan(&ProjectDetail)
+	if viewed.IsNil() {
+		// User hasn't viewed this product yet, increase the view count
+		_, err = g.Redis().Do("INCR", projectViewKey)
+		if err != nil {
+			glog.Error(err)
+			return &TalentHttpResult{Code: 0, Msg: "Redis error"}
+		}
+		// Mark the product as viewed by this user
+		_, err = g.Redis().Do("SET", userViewedKey, true)
+		if err != nil {
+			glog.Error(err)
+			return &TalentHttpResult{Code: 0, Msg: "Redis error"}
+		}
+	}
+
+	//浏览历史
+	currentDate := gtime.Now().Format("Ymd")
+	// 设计 Redis Key
+	redisBrowseKey := fmt.Sprintf("browseProject:%s:%s", currentDate, tid)
+	fmt.Println("redis浏览记录的key为——————————", redisBrowseKey)
+	// 将 project_id 添加到 Redis 中的 SET
+	_, err = g.Redis().Do("SADD", redisBrowseKey, pid)
+	if err != nil {
+		return &TalentHttpResult{Code: 0, Msg: "Redis 存浏览历史数据失败"}
+	}
+	// 设置 Key 的过期时间为 7 天
+	_, err = g.Redis().Do("EXPIRE", redisBrowseKey, 7*24*60*60) // 7 天的秒数
+	if err != nil {
+		return &TalentHttpResult{Code: 0, Msg: "Redis 设置过期时间失败"}
+	}
 
 
+	var ProjectDetail *youngee_talent_model.ProjectDetail
+	err = g.DB().Model(youngee_talent_model.ProjectDetail{}).WithAll().Where("project_id", pid).Scan(&ProjectDetail)
 	if err != nil {
 	if err != nil {
 		return &TalentHttpResult{Code: -3, Msg: "data query failed"}
 		return &TalentHttpResult{Code: -3, Msg: "data query failed"}
 	}
 	}

+ 39 - 0
app/service/youngee_task_service/task_data.go

@@ -1,9 +1,12 @@
 package youngee_task_service
 package youngee_task_service
 
 
 import (
 import (
+	"fmt"
+	"github.com/gogf/gf/util/gconv"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model/youngee_talent_model"
 	"youngmini_server/app/model/youngee_talent_model"
+	"youngmini_server/app/utils"
 
 
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/net/ghttp"
@@ -161,3 +164,39 @@ func GetUnSubmitTaskData(r *ghttp.Request) *TalentHttpResult {
 
 
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: res}
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: res}
 }
 }
+
+// 收藏种草项目
+func ProjectCollection(r *ghttp.Request) *TalentHttpResult {
+	tId, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
+	pId := r.GetQueryString("project_id")
+	record, err := g.DB().Model("younggee_project_collect_info").Where("talent_id = ? and project_id = ?", tId, pId).One()
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: err.Error()}
+	}
+	if record == nil {
+		collectionInfo := youngee_talent_model.ProjectCollection{
+			TalentId:   tId,
+			ProjectId:  pId,
+			CreateTime: gtime.Now(),
+			Delete:     0,
+		}
+
+		_, err = g.DB().Model("younggee_project_collect_info").Data(collectionInfo).Insert()
+
+	} else {
+		// 如果记录存在,更新 Delete 字段的值 和 收藏时间
+		fmt.Println("*******", record)
+		currentDeleteValue := gconv.Int(record["delete"])
+		newDeleteValue := 1 - currentDeleteValue // 0 改成 1,1 改成 0
+		_, err = g.DB().Model("younggee_project_collect_info").
+			Where("talent_id = ? and project_id = ?", tId, pId).
+			Data(g.Map{
+				"delete":      newDeleteValue,
+				"create_time": gtime.Now(),
+			}).Update()
+		if err != nil {
+			return &TalentHttpResult{Code: -2, Msg: err.Error()}
+		}
+	}
+	return &TalentHttpResult{Code: 0, Msg: "collection success"}
+}

+ 1 - 0
app/system/sectask/sectask_api.go

@@ -43,6 +43,7 @@ func (*secTaskApi) ShowLogisticsDetail(r *ghttp.Request) {
 	if err != nil {
 	if err != nil {
 		response.Code(r, err)
 		response.Code(r, err)
 	}
 	}
+	//r.Context()使得数据可以在不同的函数间传递
 	if res, err := service.ShowLogisticsDetail(r.Context(), tid, taskId); err != nil {
 	if res, err := service.ShowLogisticsDetail(r.Context(), tid, taskId); err != nil {
 		response.Code(r, err)
 		response.Code(r, err)
 	} else {
 	} else {

+ 2 - 1
app/system/sectask/sectask_service.go

@@ -191,6 +191,7 @@ func (s *secTaskService) ShowLogisticsDetail(ctx context.Context, tid, taskId st
 		g.Log().Error("用户id不一致")
 		g.Log().Error("用户id不一致")
 		return nil, err
 		return nil, err
 	}
 	}
+	//报名成功时已有地址快照
 	resp.AddressSnap = secTask.TalentPostAddrSnap
 	resp.AddressSnap = secTask.TalentPostAddrSnap
 
 
 	// 根据任务id查询物流快递公司和快递单号
 	// 根据任务id查询物流快递公司和快递单号
@@ -206,7 +207,7 @@ func (s *secTaskService) ShowLogisticsDetail(ctx context.Context, tid, taskId st
 	resp.LogisticsCompany = logisticsInfo.CompanyName
 	resp.LogisticsCompany = logisticsInfo.CompanyName
 	resp.LogisticsNumber = logisticsInfo.LogisticsNumber
 	resp.LogisticsNumber = logisticsInfo.LogisticsNumber
 
 
-	// 查询物流详细信息
+	// 查询物流详细信息,返回规定的快递状态
 	var logisticsDetail = utils.GetKDDetails(logisticsInfo.CompanyName, logisticsInfo.LogisticsNumber)
 	var logisticsDetail = utils.GetKDDetails(logisticsInfo.CompanyName, logisticsInfo.LogisticsNumber)
 	if err != nil || logisticsInfo == nil {
 	if err != nil || logisticsInfo == nil {
 		g.Log().Error("调用快递100API查询失败")
 		g.Log().Error("调用快递100API查询失败")

+ 0 - 1
app/utils/GetInfoFromSession.go

@@ -19,7 +19,6 @@ type sessionTalentInfo struct {
 func (*sessionTalentInfo) GetTalentIdFromSession(r *ghttp.Request) (string, error) {
 func (*sessionTalentInfo) GetTalentIdFromSession(r *ghttp.Request) (string, error) {
 	//在前端request1111.js中手动把token加入header中的
 	//在前端request1111.js中手动把token加入header中的
 	t := r.GetHeader("Token")
 	t := r.GetHeader("Token")
-	fmt.Println("Token------->", t)
 	if t == "" {
 	if t == "" {
 		return "", errors.New("not found info by token")
 		return "", errors.New("not found info by token")
 	}
 	}

+ 6 - 3
app/utils/kuaidi100.go

@@ -83,21 +83,23 @@ func GetKDStatus(com, num string) string {
 	return resp.IsCheck
 	return resp.IsCheck
 }
 }
 
 
+// 参数 1.快递公司  2.订单编号,都是string类型
 func GetKDDetails(com, num string) *youngee_talent_model.KdState {
 func GetKDDetails(com, num string) *youngee_talent_model.KdState {
 	fmt.Printf("查询物流公司为 %s, 快递为编号为 %v 的快递\n", KD100Flags[com], num)
 	fmt.Printf("查询物流公司为 %s, 快递为编号为 %v 的快递\n", KD100Flags[com], num)
+	//根据键(汉字)取出值(拼音)
 	com = KD100Flags[com]
 	com = KD100Flags[com]
 	key := "GsCwDkmq1520"                          //客户授权key
 	key := "GsCwDkmq1520"                          //客户授权key
 	customer := "F2E05F275D02E5344011B3DCD6FEB80D" //查询公司编号
 	customer := "F2E05F275D02E5344011B3DCD6FEB80D" //查询公司编号
 
 
 	postUrl := "https://poll.kuaidi100.com/poll/query.do" //实时查询请求地址
 	postUrl := "https://poll.kuaidi100.com/poll/query.do" //实时查询请求地址
-
+	//使用 make 函数定义并初始化:映射(map)数据类型
 	paramData := make(map[string]string)
 	paramData := make(map[string]string)
 	paramData["com"] = com //快递公司编码
 	paramData["com"] = com //快递公司编码
 	paramData["num"] = num //快递单号
 	paramData["num"] = num //快递单号
-
+	// 将一个 map[string]string 类型的变量编码为 JSON 格式
 	paramDataSlice, _ := json.Marshal(paramData)
 	paramDataSlice, _ := json.Marshal(paramData)
 	paramjson := string(paramDataSlice)
 	paramjson := string(paramDataSlice)
-
+	//构造必要参数:签名
 	sign := strings.ToUpper(GetMD5Encode(paramjson + key + customer))
 	sign := strings.ToUpper(GetMD5Encode(paramjson + key + customer))
 
 
 	// POST请求需要三个参数,分别为customer(CustomerId)和sign(签名)和param(参数)
 	// POST请求需要三个参数,分别为customer(CustomerId)和sign(签名)和param(参数)
@@ -115,6 +117,7 @@ func GetKDDetails(com, num string) *youngee_talent_model.KdState {
 	}
 	}
 	fmt.Printf("postBody=%+v\n", postBody)
 	fmt.Printf("postBody=%+v\n", postBody)
 	resp := youngee_talent_model.KdState{}
 	resp := youngee_talent_model.KdState{}
+	//将json解析回到结构体
 	err = json.Unmarshal(postBody, &resp)
 	err = json.Unmarshal(postBody, &resp)
 	fmt.Printf("resp=%+v\n", resp)
 	fmt.Printf("resp=%+v\n", resp)
 	if resp.Data != nil {
 	if resp.Data != nil {

二进制
bin/main.exe


二进制
bin/main.exe~


二进制
bin/v3.5.1/linux_amd64/youngmini_server


二进制
bin/v3.5.1/windows_amd64/youngmini_server.exe


二进制
bin/v3.5.2/linux_amd64/youngmini_server


二进制
bin/v3.5.2/windows_amd64/youngmini_server.exe


+ 2 - 2
config/config.toml

@@ -19,7 +19,7 @@ name = "youngmini_server"
 output = "./bin"
 output = "./bin"
 pack = ""
 pack = ""
 system = "linux,windows"
 system = "linux,windows"
-version = "v3.4.1"
+version = "v3.5.2"
 [gfcli.gen.dao]
 [gfcli.gen.dao]
 jsonCase = "Snake"
 jsonCase = "Snake"
 link = "mysql:talent:talentDB_123@tcp(139.9.53.143:3306)/youngmini"
 link = "mysql:talent:talentDB_123@tcp(139.9.53.143:3306)/youngmini"
@@ -49,7 +49,7 @@ Stdout = true
 
 
 # redis
 # redis
 [redis]
 [redis]
-default = "139.9.53.143:6379,younggeeRedis_123?idleTimeout=600"
+default = "139.9.53.143:6379,younggeeRedis_123?idleTimeout=600&db=10"
 
 
 # mini program info
 # mini program info
 [miniapp]
 [miniapp]

+ 1 - 0
go.mod

@@ -9,6 +9,7 @@ require (
 	github.com/gogf/gcache-adapter v0.1.2
 	github.com/gogf/gcache-adapter v0.1.2
 	github.com/gogf/gf v1.16.6
 	github.com/gogf/gf v1.16.6
 	github.com/lin-jim-leon/kuaishou v0.3.0
 	github.com/lin-jim-leon/kuaishou v0.3.0
+	github.com/satori/go.uuid v1.2.0
 	github.com/wechatpay-apiv3/wechatpay-go v0.2.18
 	github.com/wechatpay-apiv3/wechatpay-go v0.2.18
 	github.com/wxnacy/wgo v1.0.4
 	github.com/wxnacy/wgo v1.0.4
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df

+ 2 - 0
go.sum

@@ -67,6 +67,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
 github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
 github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

+ 2 - 4
main.go

@@ -1,8 +1,6 @@
 package main
 package main
 
 
 import (
 import (
-	"fmt"
-	"youngmini_server/app/utils"
 	_ "youngmini_server/boot"
 	_ "youngmini_server/boot"
 	_ "youngmini_server/router"
 	_ "youngmini_server/router"
 
 
@@ -21,8 +19,8 @@ func main() {
 	adapter := adapter.NewRedis(g.Redis())
 	adapter := adapter.NewRedis(g.Redis())
 	g.DB().GetCache().SetAdapter(adapter)
 	g.DB().GetCache().SetAdapter(adapter)
 
 
-	var resp = utils.GetKDDetails("圆通速递", "2163347472375261969")
-	fmt.Printf("resp=%+v\n", resp)
+	//var resp = utils.GetKDDetails("圆通速递", "2163347472375261969")
+	//fmt.Printf("resp=%+v\n", resp)
 	//var resp = service.ShowLogisticsDetail("2508915060")
 	//var resp = service.ShowLogisticsDetail("2508915060")
 	//fmt.Printf("resp=%+v\n", resp)
 	//fmt.Printf("resp=%+v\n", resp)
 
 

+ 2 - 0
middleware/middleware_duplicate_verify.go

@@ -12,7 +12,9 @@ func generateDuplicateKey(r *ghttp.Request) string {
 
 
 func DuplicateVerify(r *ghttp.Request) {
 func DuplicateVerify(r *ghttp.Request) {
 	key := generateDuplicateKey(r)
 	key := generateDuplicateKey(r)
+	//DoVar 方法用于执行 Redis 命令,并返回结果
 	//v, _ := g.Redis().DoVar("GET", key)
 	//v, _ := g.Redis().DoVar("GET", key)
+	//结果转为整数类型
 	//if v.Int() != 0 {
 	//if v.Int() != 0 {
 	//	r.Response.WriteJson(g.Map{
 	//	r.Response.WriteJson(g.Map{
 	//		"code": 500,
 	//		"code": 500,

+ 0 - 1
middleware/middleware_wx_auth.go

@@ -14,7 +14,6 @@ func WxAuth(r *ghttp.Request) {
 			"code": 403,
 			"code": 403,
 			"msg":  "请重新登录",
 			"msg":  "请重新登录",
 		})
 		})
-
 		return
 		return
 	}
 	}
 
 

+ 2 - 1
router/router.go

@@ -1,6 +1,7 @@
 package router
 package router
 
 
 import (
 import (
+	"fmt"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/os/gtime"
 	"github.com/gogf/gf/os/gtime"
@@ -104,7 +105,7 @@ func init() {
 
 
 		//nignx转发含code的请求到此处
 		//nignx转发含code的请求到此处
 		s.BindHandler("/kuaishouauth", func(r *ghttp.Request) {
 		s.BindHandler("/kuaishouauth", func(r *ghttp.Request) {
-
+			fmt.Println("****进入rounter中的/kuaishouauth*******")
 			ClientKey := "ks651333097154138217"
 			ClientKey := "ks651333097154138217"
 			ClientSecret := "dBt0rVRhTpUqcrOYGGpv0A"
 			ClientSecret := "dBt0rVRhTpUqcrOYGGpv0A"
 			//SignSecret := "bf6393dce0a2b669ee348bebb837b0da"
 			//SignSecret := "bf6393dce0a2b669ee348bebb837b0da"

+ 23 - 0
vendor/github.com/satori/go.uuid/.travis.yml

@@ -0,0 +1,23 @@
+language: go
+sudo: false
+go:
+    - 1.2
+    - 1.3
+    - 1.4
+    - 1.5
+    - 1.6
+    - 1.7
+    - 1.8
+    - 1.9
+    - tip
+matrix:
+    allow_failures:
+        - go: tip
+    fast_finish: true
+before_install:
+    - go get github.com/mattn/goveralls
+    - go get golang.org/x/tools/cmd/cover
+script:
+    - $HOME/gopath/bin/goveralls -service=travis-ci
+notifications:
+    email: false

+ 20 - 0
vendor/github.com/satori/go.uuid/LICENSE

@@ -0,0 +1,20 @@
+Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 65 - 0
vendor/github.com/satori/go.uuid/README.md

@@ -0,0 +1,65 @@
+# UUID package for Go language
+
+[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid)
+[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid)
+[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid)
+
+This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
+
+With 100% test coverage and benchmarks out of box.
+
+Supported versions:
+* Version 1, based on timestamp and MAC address (RFC 4122)
+* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
+* Version 3, based on MD5 hashing (RFC 4122)
+* Version 4, based on random numbers (RFC 4122)
+* Version 5, based on SHA-1 hashing (RFC 4122)
+
+## Installation
+
+Use the `go` command:
+
+	$ go get github.com/satori/go.uuid
+
+## Requirements
+
+UUID package requires Go >= 1.2.
+
+## Example
+
+```go
+package main
+
+import (
+	"fmt"
+	"github.com/satori/go.uuid"
+)
+
+func main() {
+	// Creating UUID Version 4
+	u1 := uuid.NewV4()
+	fmt.Printf("UUIDv4: %s\n", u1)
+
+	// Parsing UUID from string input
+	u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
+	if err != nil {
+		fmt.Printf("Something gone wrong: %s", err)
+	}
+	fmt.Printf("Successfully parsed: %s", u2)
+}
+```
+
+## Documentation
+
+[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
+
+## Links
+* [RFC 4122](http://tools.ietf.org/html/rfc4122)
+* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
+
+## Copyright
+
+Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>.
+
+UUID package released under MIT License.
+See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.

+ 206 - 0
vendor/github.com/satori/go.uuid/codec.go

@@ -0,0 +1,206 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+)
+
+// FromBytes returns UUID converted from raw byte slice input.
+// It will return error if the slice isn't 16 bytes long.
+func FromBytes(input []byte) (u UUID, err error) {
+	err = u.UnmarshalBinary(input)
+	return
+}
+
+// FromBytesOrNil returns UUID converted from raw byte slice input.
+// Same behavior as FromBytes, but returns a Nil UUID on error.
+func FromBytesOrNil(input []byte) UUID {
+	uuid, err := FromBytes(input)
+	if err != nil {
+		return Nil
+	}
+	return uuid
+}
+
+// FromString returns UUID parsed from string input.
+// Input is expected in a form accepted by UnmarshalText.
+func FromString(input string) (u UUID, err error) {
+	err = u.UnmarshalText([]byte(input))
+	return
+}
+
+// FromStringOrNil returns UUID parsed from string input.
+// Same behavior as FromString, but returns a Nil UUID on error.
+func FromStringOrNil(input string) UUID {
+	uuid, err := FromString(input)
+	if err != nil {
+		return Nil
+	}
+	return uuid
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+// The encoding is the same as returned by String.
+func (u UUID) MarshalText() (text []byte, err error) {
+	text = []byte(u.String())
+	return
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// Following formats are supported:
+//   "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
+//   "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
+//   "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+//   "6ba7b8109dad11d180b400c04fd430c8"
+// ABNF for supported UUID text representation follows:
+//   uuid := canonical | hashlike | braced | urn
+//   plain := canonical | hashlike
+//   canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
+//   hashlike := 12hexoct
+//   braced := '{' plain '}'
+//   urn := URN ':' UUID-NID ':' plain
+//   URN := 'urn'
+//   UUID-NID := 'uuid'
+//   12hexoct := 6hexoct 6hexoct
+//   6hexoct := 4hexoct 2hexoct
+//   4hexoct := 2hexoct 2hexoct
+//   2hexoct := hexoct hexoct
+//   hexoct := hexdig hexdig
+//   hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
+//             'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
+//             'A' | 'B' | 'C' | 'D' | 'E' | 'F'
+func (u *UUID) UnmarshalText(text []byte) (err error) {
+	switch len(text) {
+	case 32:
+		return u.decodeHashLike(text)
+	case 36:
+		return u.decodeCanonical(text)
+	case 38:
+		return u.decodeBraced(text)
+	case 41:
+		fallthrough
+	case 45:
+		return u.decodeURN(text)
+	default:
+		return fmt.Errorf("uuid: incorrect UUID length: %s", text)
+	}
+}
+
+// decodeCanonical decodes UUID string in format
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
+func (u *UUID) decodeCanonical(t []byte) (err error) {
+	if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
+		return fmt.Errorf("uuid: incorrect UUID format %s", t)
+	}
+
+	src := t[:]
+	dst := u[:]
+
+	for i, byteGroup := range byteGroups {
+		if i > 0 {
+			src = src[1:] // skip dash
+		}
+		_, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup])
+		if err != nil {
+			return
+		}
+		src = src[byteGroup:]
+		dst = dst[byteGroup/2:]
+	}
+
+	return
+}
+
+// decodeHashLike decodes UUID string in format
+// "6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodeHashLike(t []byte) (err error) {
+	src := t[:]
+	dst := u[:]
+
+	if _, err = hex.Decode(dst, src); err != nil {
+		return err
+	}
+	return
+}
+
+// decodeBraced decodes UUID string in format
+// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format
+// "{6ba7b8109dad11d180b400c04fd430c8}".
+func (u *UUID) decodeBraced(t []byte) (err error) {
+	l := len(t)
+
+	if t[0] != '{' || t[l-1] != '}' {
+		return fmt.Errorf("uuid: incorrect UUID format %s", t)
+	}
+
+	return u.decodePlain(t[1 : l-1])
+}
+
+// decodeURN decodes UUID string in format
+// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format
+// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodeURN(t []byte) (err error) {
+	total := len(t)
+
+	urn_uuid_prefix := t[:9]
+
+	if !bytes.Equal(urn_uuid_prefix, urnPrefix) {
+		return fmt.Errorf("uuid: incorrect UUID format: %s", t)
+	}
+
+	return u.decodePlain(t[9:total])
+}
+
+// decodePlain decodes UUID string in canonical format
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
+// "6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodePlain(t []byte) (err error) {
+	switch len(t) {
+	case 32:
+		return u.decodeHashLike(t)
+	case 36:
+		return u.decodeCanonical(t)
+	default:
+		return fmt.Errorf("uuid: incorrrect UUID length: %s", t)
+	}
+}
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (u UUID) MarshalBinary() (data []byte, err error) {
+	data = u.Bytes()
+	return
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+// It will return error if the slice isn't 16 bytes long.
+func (u *UUID) UnmarshalBinary(data []byte) (err error) {
+	if len(data) != Size {
+		err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
+		return
+	}
+	copy(u[:], data)
+
+	return
+}

+ 239 - 0
vendor/github.com/satori/go.uuid/generator.go

@@ -0,0 +1,239 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+	"crypto/md5"
+	"crypto/rand"
+	"crypto/sha1"
+	"encoding/binary"
+	"hash"
+	"net"
+	"os"
+	"sync"
+	"time"
+)
+
+// Difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
+const epochStart = 122192928000000000
+
+var (
+	global = newDefaultGenerator()
+
+	epochFunc = unixTimeFunc
+	posixUID  = uint32(os.Getuid())
+	posixGID  = uint32(os.Getgid())
+)
+
+// NewV1 returns UUID based on current timestamp and MAC address.
+func NewV1() UUID {
+	return global.NewV1()
+}
+
+// NewV2 returns DCE Security UUID based on POSIX UID/GID.
+func NewV2(domain byte) UUID {
+	return global.NewV2(domain)
+}
+
+// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
+func NewV3(ns UUID, name string) UUID {
+	return global.NewV3(ns, name)
+}
+
+// NewV4 returns random generated UUID.
+func NewV4() UUID {
+	return global.NewV4()
+}
+
+// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
+func NewV5(ns UUID, name string) UUID {
+	return global.NewV5(ns, name)
+}
+
+// Generator provides interface for generating UUIDs.
+type Generator interface {
+	NewV1() UUID
+	NewV2(domain byte) UUID
+	NewV3(ns UUID, name string) UUID
+	NewV4() UUID
+	NewV5(ns UUID, name string) UUID
+}
+
+// Default generator implementation.
+type generator struct {
+	storageOnce  sync.Once
+	storageMutex sync.Mutex
+
+	lastTime      uint64
+	clockSequence uint16
+	hardwareAddr  [6]byte
+}
+
+func newDefaultGenerator() Generator {
+	return &generator{}
+}
+
+// NewV1 returns UUID based on current timestamp and MAC address.
+func (g *generator) NewV1() UUID {
+	u := UUID{}
+
+	timeNow, clockSeq, hardwareAddr := g.getStorage()
+
+	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
+	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
+	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
+	binary.BigEndian.PutUint16(u[8:], clockSeq)
+
+	copy(u[10:], hardwareAddr)
+
+	u.SetVersion(V1)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+// NewV2 returns DCE Security UUID based on POSIX UID/GID.
+func (g *generator) NewV2(domain byte) UUID {
+	u := UUID{}
+
+	timeNow, clockSeq, hardwareAddr := g.getStorage()
+
+	switch domain {
+	case DomainPerson:
+		binary.BigEndian.PutUint32(u[0:], posixUID)
+	case DomainGroup:
+		binary.BigEndian.PutUint32(u[0:], posixGID)
+	}
+
+	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
+	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
+	binary.BigEndian.PutUint16(u[8:], clockSeq)
+	u[9] = domain
+
+	copy(u[10:], hardwareAddr)
+
+	u.SetVersion(V2)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
+func (g *generator) NewV3(ns UUID, name string) UUID {
+	u := newFromHash(md5.New(), ns, name)
+	u.SetVersion(V3)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+// NewV4 returns random generated UUID.
+func (g *generator) NewV4() UUID {
+	u := UUID{}
+	g.safeRandom(u[:])
+	u.SetVersion(V4)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
+func (g *generator) NewV5(ns UUID, name string) UUID {
+	u := newFromHash(sha1.New(), ns, name)
+	u.SetVersion(V5)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+func (g *generator) initStorage() {
+	g.initClockSequence()
+	g.initHardwareAddr()
+}
+
+func (g *generator) initClockSequence() {
+	buf := make([]byte, 2)
+	g.safeRandom(buf)
+	g.clockSequence = binary.BigEndian.Uint16(buf)
+}
+
+func (g *generator) initHardwareAddr() {
+	interfaces, err := net.Interfaces()
+	if err == nil {
+		for _, iface := range interfaces {
+			if len(iface.HardwareAddr) >= 6 {
+				copy(g.hardwareAddr[:], iface.HardwareAddr)
+				return
+			}
+		}
+	}
+
+	// Initialize hardwareAddr randomly in case
+	// of real network interfaces absence
+	g.safeRandom(g.hardwareAddr[:])
+
+	// Set multicast bit as recommended in RFC 4122
+	g.hardwareAddr[0] |= 0x01
+}
+
+func (g *generator) safeRandom(dest []byte) {
+	if _, err := rand.Read(dest); err != nil {
+		panic(err)
+	}
+}
+
+// Returns UUID v1/v2 storage state.
+// Returns epoch timestamp, clock sequence, and hardware address.
+func (g *generator) getStorage() (uint64, uint16, []byte) {
+	g.storageOnce.Do(g.initStorage)
+
+	g.storageMutex.Lock()
+	defer g.storageMutex.Unlock()
+
+	timeNow := epochFunc()
+	// Clock changed backwards since last UUID generation.
+	// Should increase clock sequence.
+	if timeNow <= g.lastTime {
+		g.clockSequence++
+	}
+	g.lastTime = timeNow
+
+	return timeNow, g.clockSequence, g.hardwareAddr[:]
+}
+
+// Returns difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and current time.
+// This is default epoch calculation function.
+func unixTimeFunc() uint64 {
+	return epochStart + uint64(time.Now().UnixNano()/100)
+}
+
+// Returns UUID based on hashing of namespace UUID and name.
+func newFromHash(h hash.Hash, ns UUID, name string) UUID {
+	u := UUID{}
+	h.Write(ns[:])
+	h.Write([]byte(name))
+	copy(u[:], h.Sum(nil))
+
+	return u
+}

+ 78 - 0
vendor/github.com/satori/go.uuid/sql.go

@@ -0,0 +1,78 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+	"database/sql/driver"
+	"fmt"
+)
+
+// Value implements the driver.Valuer interface.
+func (u UUID) Value() (driver.Value, error) {
+	return u.String(), nil
+}
+
+// Scan implements the sql.Scanner interface.
+// A 16-byte slice is handled by UnmarshalBinary, while
+// a longer byte slice or a string is handled by UnmarshalText.
+func (u *UUID) Scan(src interface{}) error {
+	switch src := src.(type) {
+	case []byte:
+		if len(src) == Size {
+			return u.UnmarshalBinary(src)
+		}
+		return u.UnmarshalText(src)
+
+	case string:
+		return u.UnmarshalText([]byte(src))
+	}
+
+	return fmt.Errorf("uuid: cannot convert %T to UUID", src)
+}
+
+// NullUUID can be used with the standard sql package to represent a
+// UUID value that can be NULL in the database
+type NullUUID struct {
+	UUID  UUID
+	Valid bool
+}
+
+// Value implements the driver.Valuer interface.
+func (u NullUUID) Value() (driver.Value, error) {
+	if !u.Valid {
+		return nil, nil
+	}
+	// Delegate to UUID Value function
+	return u.UUID.Value()
+}
+
+// Scan implements the sql.Scanner interface.
+func (u *NullUUID) Scan(src interface{}) error {
+	if src == nil {
+		u.UUID, u.Valid = Nil, false
+		return nil
+	}
+
+	// Delegate to UUID Scan function
+	u.Valid = true
+	return u.UUID.Scan(src)
+}

+ 161 - 0
vendor/github.com/satori/go.uuid/uuid.go

@@ -0,0 +1,161 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Package uuid provides implementation of Universally Unique Identifier (UUID).
+// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
+// version 2 (as specified in DCE 1.1).
+package uuid
+
+import (
+	"bytes"
+	"encoding/hex"
+)
+
+// Size of a UUID in bytes.
+const Size = 16
+
+// UUID representation compliant with specification
+// described in RFC 4122.
+type UUID [Size]byte
+
+// UUID versions
+const (
+	_ byte = iota
+	V1
+	V2
+	V3
+	V4
+	V5
+)
+
+// UUID layout variants.
+const (
+	VariantNCS byte = iota
+	VariantRFC4122
+	VariantMicrosoft
+	VariantFuture
+)
+
+// UUID DCE domains.
+const (
+	DomainPerson = iota
+	DomainGroup
+	DomainOrg
+)
+
+// String parse helpers.
+var (
+	urnPrefix  = []byte("urn:uuid:")
+	byteGroups = []int{8, 4, 4, 4, 12}
+)
+
+// Nil is special form of UUID that is specified to have all
+// 128 bits set to zero.
+var Nil = UUID{}
+
+// Predefined namespace UUIDs.
+var (
+	NamespaceDNS  = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
+	NamespaceURL  = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
+	NamespaceOID  = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
+	NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
+)
+
+// Equal returns true if u1 and u2 equals, otherwise returns false.
+func Equal(u1 UUID, u2 UUID) bool {
+	return bytes.Equal(u1[:], u2[:])
+}
+
+// Version returns algorithm version used to generate UUID.
+func (u UUID) Version() byte {
+	return u[6] >> 4
+}
+
+// Variant returns UUID layout variant.
+func (u UUID) Variant() byte {
+	switch {
+	case (u[8] >> 7) == 0x00:
+		return VariantNCS
+	case (u[8] >> 6) == 0x02:
+		return VariantRFC4122
+	case (u[8] >> 5) == 0x06:
+		return VariantMicrosoft
+	case (u[8] >> 5) == 0x07:
+		fallthrough
+	default:
+		return VariantFuture
+	}
+}
+
+// Bytes returns bytes slice representation of UUID.
+func (u UUID) Bytes() []byte {
+	return u[:]
+}
+
+// Returns canonical string representation of UUID:
+// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+func (u UUID) String() string {
+	buf := make([]byte, 36)
+
+	hex.Encode(buf[0:8], u[0:4])
+	buf[8] = '-'
+	hex.Encode(buf[9:13], u[4:6])
+	buf[13] = '-'
+	hex.Encode(buf[14:18], u[6:8])
+	buf[18] = '-'
+	hex.Encode(buf[19:23], u[8:10])
+	buf[23] = '-'
+	hex.Encode(buf[24:], u[10:])
+
+	return string(buf)
+}
+
+// SetVersion sets version bits.
+func (u *UUID) SetVersion(v byte) {
+	u[6] = (u[6] & 0x0f) | (v << 4)
+}
+
+// SetVariant sets variant bits.
+func (u *UUID) SetVariant(v byte) {
+	switch v {
+	case VariantNCS:
+		u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
+	case VariantRFC4122:
+		u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
+	case VariantMicrosoft:
+		u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
+	case VariantFuture:
+		fallthrough
+	default:
+		u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
+	}
+}
+
+// Must is a helper that wraps a call to a function returning (UUID, error)
+// and panics if the error is non-nil. It is intended for use in variable
+// initializations such as
+//	var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
+func Must(u UUID, err error) UUID {
+	if err != nil {
+		panic(err)
+	}
+	return u
+}

+ 3 - 0
vendor/modules.txt

@@ -212,6 +212,9 @@ github.com/olekukonko/tablewriter
 # github.com/rivo/uniseg v0.1.0
 # github.com/rivo/uniseg v0.1.0
 ## explicit; go 1.12
 ## explicit; go 1.12
 github.com/rivo/uniseg
 github.com/rivo/uniseg
+# github.com/satori/go.uuid v1.2.0
+## explicit
+github.com/satori/go.uuid
 # github.com/wechatpay-apiv3/wechatpay-go v0.2.18
 # github.com/wechatpay-apiv3/wechatpay-go v0.2.18
 ## explicit; go 1.16
 ## explicit; go 1.16
 github.com/wechatpay-apiv3/wechatpay-go/core
 github.com/wechatpay-apiv3/wechatpay-go/core