Parcourir la source

Merge branch 'master' of https://jygit.jydev.jianyu360.cn/moapp/jybase

wangshan il y a 7 mois
Parent
commit
3aa57dbda3
12 fichiers modifiés avec 298 ajouts et 118 suppressions
  1. 16 3
      common/common.go
  2. 12 0
      common/requtil.go
  3. 0 1
      encrypt/encryptarticle.go
  4. 41 62
      es/es_test.go
  5. 59 0
      es/esv7.go
  6. 102 39
      esv7/elasticutil.go
  7. 6 5
      log/log.go
  8. 25 0
      mail/gmail.go
  9. 4 0
      mongodb/mongodb.go
  10. 8 1
      mysql/mysql.go
  11. 10 4
      rpc/weixin.go
  12. 15 3
      sort/sort.go

+ 16 - 3
common/common.go

@@ -293,10 +293,12 @@ func IntAllDef(num interface{}, defaultNum int) int {
 func ObjToString(old interface{}) string {
 	if nil == old {
 		return ""
-	} else {
-		r, _ := old.(string)
-		return r
+	} else if r1, ok1 := old.(string); ok1 {
+		return r1
+	} else if r2, ok2 := old.(*string); ok2 {
+		return *r2
 	}
+	return ""
 }
 
 func ObjToStringDef(old interface{}, defaultstr string) string {
@@ -804,3 +806,14 @@ func ShortenTxt(length int, fixed, shorten string) string {
 	}
 	return ""
 }
+
+//获取问号占位符数量及对应的参数值
+func WhArgs(args []string) (string, []interface{}) {
+	newArgs := make([]interface{}, len(args))
+	wh := make([]string, len(args))
+	for k, v := range args {
+		newArgs[k] = v
+		wh[k] = "?"
+	}
+	return strings.Join(wh, ","), newArgs
+}

+ 12 - 0
common/requtil.go

@@ -8,6 +8,18 @@ import (
 	"strings"
 )
 
+// 获取操作系统类型
+func GetSystem(userAgent string) string {
+	userAgent = strings.ToLower(userAgent)
+	if strings.Contains(userAgent, "android") {
+		return "android"
+	} else if strings.Contains(userAgent, "iphone") || strings.Contains(userAgent, "ipad") || strings.Contains(userAgent, "ipod") {
+		return "ios"
+	} else {
+		return "pc"
+	}
+}
+
 // 获取平台类型
 func GetOS(useros string) string {
 	osVersion := "其他"

+ 0 - 1
encrypt/encryptarticle.go

@@ -35,7 +35,6 @@ func CommonEncodeArticle(stype string, keys ...string) (id string) {
 	case "indexcontent":
 		id = BEncodeArticleId2ByCheck("D", ISE, ISE2, keys...)
 	}
-
 	return
 }
 

+ 41 - 62
es/es_test.go

@@ -3,6 +3,7 @@ package es
 import (
 	"log"
 	"testing"
+	//	es "github.com/olivere/elastic/v7"
 )
 
 type AggregationsBucket struct {
@@ -15,70 +16,26 @@ type AggregationsBucket struct {
 
 func TestGet(t *testing.T) {
 	q := `{
-  "query": {
-    "bool": {
-      "must": [
-        {
-          "bool": {
-            "should": [
-              {
-                "terms": {
-                  "subtype": [
-                    "拟建"
-                  ]
-                }
-              },
-              {
-                "terms": {
-                  "toptype": [
-                    "预告",
-                    "招标",
-                    "结果",
-                    "其它"
-                  ]
-                }
-              }
-            ]
-          }
-        }
-      ],
-      "must_not": []
-    }
-  },
-  "_source": [
-    "_id",
-    "title",
-    "publishtime",
-    "toptype",
-    "subtype",
-    "type",
-    "area",
-    "dataweight",
-    "city",
-    "s_subscopeclass",
-    "bidamount",
-    "budget",
-    "buyerclass",
-    "spidercode",
-    "site",
-    "filetext",
-    "isValidFile"
-  ],
-  "sort": [
-    {
-      "dataweight": "desc"
-    },
-    {
-      "publishtime": "desc"
-    }
-  ],
-  "from": 1,
-  "size": 50
-}`
+	  "query": {
+	    "bool": {
+	      "must": [
+	        {
+	          "multi_match": {
+	            "query": "维护",
+	            "type": "phrase",
+	            "fields": [
+	              "title"
+	            ]
+	          }
+	        }
+	      ]
+	    }
+	  },"size":3
+	}`
 	NewEs("v7", "http://192.168.3.241:9205,http://192.168.3.149:9200", 2, "", "")
 	//NewEs("v1", "http://192.168.3.206:9800", 2, "", "")
-	count, _ := GetWithCount("bidding", "bidding", "", q)
-	log.Println(count)
+	list := Get("bidding", "bidding", q)
+	log.Println(list)
 }
 
 func TestAnalyze(t *testing.T) {
@@ -87,3 +44,25 @@ func TestAnalyze(t *testing.T) {
 	res := Analyze("软件中国", "bidding", "ik_smart")
 	log.Println(res)
 }
+
+func TestScroll(t *testing.T) {
+	NewEs("v7", "http://192.168.3.149:9200", 2, "", "")
+	q := `{
+	  "query": {
+	    "bool": {
+	      "must": {
+	        "range": {
+	          "pici": {
+	            "gt": 1686041829,
+	            "lte": 1716450097
+	          }
+	        }
+	      }
+	    }
+	  },"_source":["id"]
+	}`
+	VarEs.(*EsV7).Scroll("projectset", "5m", q, func(fv map[string]interface{}) bool {
+		log.Println(fv)
+		return true
+	})
+}

+ 59 - 0
es/esv7.go

@@ -3,7 +3,9 @@ package es
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
+	"io"
 	"log"
 	"net/http"
 	"runtime"
@@ -15,6 +17,19 @@ import (
 	es "github.com/olivere/elastic/v7"
 )
 
+type MySource struct {
+	Query string
+}
+
+func (m *MySource) Source() (interface{}, error) {
+	mp := make(map[string]interface{})
+	err := json.Unmarshal([]byte(m.Query), &mp)
+	if err != nil {
+		return nil, err
+	}
+	return mp, nil
+}
+
 type EsV7 struct {
 	Address      string
 	UserName     string
@@ -989,3 +1004,47 @@ func (e *EsV7) analyzeResp(text, analyzer, u string) (*http.Request, error) {
 	req.Header.Set("Content-Type", "application/json")
 	return req, err
 }
+
+func (e *EsV7) Scroll(indexName, scrollTime, query string, f func(fv map[string]interface{}) bool) {
+	client := e.GetEsConn()
+	defer e.DestoryEsConn(client)
+	// 开始滚动查询
+	scrollService := client.Scroll(indexName).Scroll(scrollTime).Body(query)
+	// 滚动 ID 用于追踪滚动上下文
+	var scrollID string
+	for {
+		// 执行滚动查询
+		searchResult, err := scrollService.Do(context.Background())
+		if errors.Is(err, io.EOF) {
+			break
+		} else if err != nil {
+			log.Println("Error executing scroll query: ", err)
+			break
+		}
+		// 获取滚动 ID
+		scrollID = searchResult.ScrollId
+		// 处理查询结果
+		isBreak := false
+		for _, hit := range searchResult.Hits.Hits {
+			// 这里假设文档的源数据是 JSON 字符串
+			var source map[string]interface{}
+			json.Unmarshal(hit.Source, &source)
+			if !f(source) {
+				isBreak = true
+				break
+			}
+		}
+		if isBreak {
+			break
+		}
+		// 更新滚动服务以使用新的滚动 ID
+		scrollService = client.Scroll(indexName).ScrollId(scrollID).Scroll(scrollTime)
+	}
+	if scrollID != "" {
+		// 清理滚动上下文
+		_, err := client.ClearScroll().ScrollId(scrollID).Do(context.Background())
+		if err != nil {
+			log.Println(scrollID, "Error clearing scroll: ", err)
+		}
+	}
+}

+ 102 - 39
esv7/elasticutil.go

@@ -16,7 +16,7 @@ import (
 	es "github.com/olivere/elastic/v7"
 )
 
-//检索库服务地址
+// 检索库服务地址
 var (
 	addrs    []string
 	LocCity  = map[string]string{}
@@ -36,7 +36,7 @@ var ntimeout int
 var syncPool sync.Pool
 var filterReg = regexp.MustCompile(`,\s*"should"\s*:\s*\[\s*\]\s*,\s*"minimum_should_match"\s*:\s*1`)
 
-//初始化全文检索
+// 初始化全文检索
 func InitElastic(addr string) {
 	InitElasticSize(addr, SIZE)
 }
@@ -61,12 +61,12 @@ var httpclient = &http.Client{Transport: &http.Transport{
 //var op = es.SetHttpClient(httpclient)
 var poolsize = int32(20)
 
-//n倍的池
+// n倍的池
 func InitElasticSize(addr string, size int) {
 	InitElasticSizeByAuth(addr, size, "", "")
 }
 
-//初始化es,带有用户名密码认证
+// 初始化es,带有用户名密码认证
 func InitElasticSizeByAuth(addr string, size int, u, p string) {
 	poolsize = int32(3 * size)
 	pool = make(chan *es.Client, poolsize)
@@ -88,7 +88,7 @@ func newClient() (*es.Client, error) {
 	return es.NewClient(opt...)
 }
 
-//关闭连接
+// 关闭连接
 func DestoryEsConn(client *es.Client) {
 	select {
 	case pool <- client:
@@ -106,7 +106,7 @@ var (
 	lastTimeLock = &sync.Mutex{}
 )
 
-//获取连接
+// 获取连接
 func GetEsConn() *es.Client {
 	select {
 	case c := <-pool:
@@ -141,7 +141,7 @@ func GetEsConn() *es.Client {
 	}
 }
 
-//保存对象
+// 保存对象
 func Save(index, itype string, obj interface{}) bool {
 	client := GetEsConn()
 	defer DestoryEsConn(client)
@@ -168,23 +168,48 @@ func Save(index, itype string, obj interface{}) bool {
 	} else {
 		return true
 	}
+}
 
+func SaveNew(index string, obj interface{}) bool {
+	client := GetEsConn()
+	defer DestoryEsConn(client)
+	defer func() {
+		if r := recover(); r != nil {
+			log.Println("[E]", r)
+			for skip := 1; ; skip++ {
+				_, file, line, ok := runtime.Caller(skip)
+				if !ok {
+					break
+				}
+				go log.Printf("%v,%v\n", file, line)
+			}
+		}
+	}()
+	data := objToMap(obj)
+	_id := fmt.Sprint((*data)["id"])
+	_, err := client.Index().Index(index).Id(_id).BodyJson(data).Do(context.TODO())
+	if err != nil {
+		log.Println("保存到ES出错", err.Error(), obj)
+		return false
+	} else {
+		return true
+	}
 }
 
-//通用查询
-//{"query": {"bool":{"must":[{"query_string":{"default_field":"name","query":"*"}}]}}}
-//{"query":{"bool":{"must":{"match":{"content":{"query":"fulltextsearch","operator":"and"}}},"should":[{"match":{"content":{"query":"Elasticsearch","boost":3}}},{"match":{"content":{"query":"Lucene","boost":2}}}]}}}
-//prefix
-//{"query":{"match":{"title":{"query":"brownfox","operator":"and"}}}} //默认为or
-//{"query":{"multi_match":{"query":"PolandStreetW1V","type":"most_fields","fields":["*_street","city^2","country","postcode"]}}}
-//{"query":{"wildcard":{"postcode":"W?F*HW"}}}
-//{"query":{"regexp":{"postcode":"W[0-9].+"}}}
-//{"query":{"filtered":{"filter":{"range":{"price":{"gte":10000}}}}},"aggs":{"single_avg_price":{"avg":{"field":"price"}}}}
-//{"query":{"match":{"make":"ford"}},"aggs":{"colors":{"terms":{"field":"color"}}}}//查fork有几种颜色
-//过滤器不会计算相关度的得分,所以它们在计算上更快一些
-//{"query":{"filtered":{"query":{"match_all":{}},"filter":{"range":{"balance":{"gte":20000,"lte":30000}}}}}}
-//{"query":{"match_all":{}},"from":10,"size":10,"_source":["account_number","balance"],"sort":{"balance":{"order":"desc"}}}
-//{"query":{"match_phrase":{"address":"milllane"}}}和match不同会去匹配整个短语,相当于must[]
+// 通用查询
+// {"query": {"bool":{"must":[{"query_string":{"default_field":"name","query":"*"}}]}}}
+// {"query":{"bool":{"must":{"match":{"content":{"query":"fulltextsearch","operator":"and"}}},"should":[{"match":{"content":{"query":"Elasticsearch","boost":3}}},{"match":{"content":{"query":"Lucene","boost":2}}}]}}}
+// prefix
+// {"query":{"match":{"title":{"query":"brownfox","operator":"and"}}}} //默认为or
+// {"query":{"multi_match":{"query":"PolandStreetW1V","type":"most_fields","fields":["*_street","city^2","country","postcode"]}}}
+// {"query":{"wildcard":{"postcode":"W?F*HW"}}}
+// {"query":{"regexp":{"postcode":"W[0-9].+"}}}
+// {"query":{"filtered":{"filter":{"range":{"price":{"gte":10000}}}}},"aggs":{"single_avg_price":{"avg":{"field":"price"}}}}
+// {"query":{"match":{"make":"ford"}},"aggs":{"colors":{"terms":{"field":"color"}}}}//查fork有几种颜色
+// 过滤器不会计算相关度的得分,所以它们在计算上更快一些
+// {"query":{"filtered":{"query":{"match_all":{}},"filter":{"range":{"balance":{"gte":20000,"lte":30000}}}}}}
+// {"query":{"match_all":{}},"from":10,"size":10,"_source":["account_number","balance"],"sort":{"balance":{"order":"desc"}}}
+// {"query":{"match_phrase":{"address":"milllane"}}}和match不同会去匹配整个短语,相当于must[]
 func GetBySearchType(index, searchType, query string) (int64, *[]map[string]interface{}) {
 	t, _, l := get(index, "", searchType, query, true, true)
 	return t, l
@@ -260,14 +285,14 @@ func GetNoLimit(index, itype, query string) *[]map[string]interface{} {
 	return l
 }
 
-//分页查询
-//{"name":"张三","$and":[{"age":{"$gt":10}},{"age":{"$lte":20}}]}
-//fields直接是 `"_id","title"`
+// 分页查询
+// {"name":"张三","$and":[{"age":{"$gt":10}},{"age":{"$lte":20}}]}
+// fields直接是 `"_id","title"`
 func GetPage(index, itype, query, order, field string, start, limit int) *[]map[string]interface{} {
 	return Get(index, itype, MakeQuery(query, order, field, start, limit))
 }
 
-//openapi
+// openapi
 func GetOAPage(index, itype, query, order, field string, start, limit int) (*[]map[string]interface{}, int) {
 	return GetOA(index, itype, MakeQuery(query, order, field, start, limit))
 }
@@ -294,7 +319,7 @@ func MakeQuery(query, order, fileds string, start, limit int) string {
 	return ""
 }
 
-//{"name":"aaa"}
+// {"name":"aaa"}
 func AnalyQuery(query interface{}, parent string, result string) string {
 	m := make(map[string]interface{})
 	if q1, ok := query.(string); ok {
@@ -416,7 +441,7 @@ func GetByIdField(index, itype, id, fields string) *map[string]interface{} {
 	return nil
 }
 
-//根据id来查询文档
+// 根据id来查询文档
 func GetById(index, itype string, ids ...string) *[]map[string]interface{} {
 	client := GetEsConn()
 	defer DestoryEsConn(client)
@@ -460,7 +485,7 @@ func GetById(index, itype string, ids ...string) *[]map[string]interface{} {
 	return &res
 }
 
-//根据语句更新对象
+// 根据语句更新对象
 func Update(index, itype, id string, updateStr string) bool {
 	client := GetEsConn()
 	defer DestoryEsConn(client)
@@ -545,7 +570,7 @@ func NewBulkUpdate(index string, params ...[]string) bool {
 	return false
 }
 
-//根据id删除索引对象
+// 根据id删除索引对象
 func DelById(index, itype, id string) bool {
 	client := GetEsConn()
 	defer DestoryEsConn(client)
@@ -574,7 +599,7 @@ func DelById(index, itype, id string) bool {
 	return b
 }
 
-//先删除后增
+// 先删除后增
 func UpdateNewDoc(index, itype string, obj ...interface{}) bool {
 	client := GetEsConn()
 	defer DestoryEsConn(client)
@@ -616,6 +641,45 @@ func UpdateNewDoc(index, itype string, obj ...interface{}) bool {
 	return b
 }
 
+func UpdateNew(index string, obj ...interface{}) bool {
+	client := GetEsConn()
+	defer DestoryEsConn(client)
+	b := false
+	if client != nil {
+		defer func() {
+			if r := recover(); r != nil {
+				log.Println("[E]", r)
+				for skip := 1; ; skip++ {
+					_, file, line, ok := runtime.Caller(skip)
+					if !ok {
+						break
+					}
+					go log.Printf("%v,%v\n", file, line)
+				}
+			}
+		}()
+		var err error
+		for _, v := range obj {
+			tempObj := objToMap(v)
+			if tempObj == nil || len(*tempObj) == 0 {
+				continue
+			}
+			_id := fmt.Sprint((*tempObj)["id"])
+			if _id != "" {
+				client.Delete().Index(index).Id(_id).Do(context.TODO())
+			}
+			_, err = client.Index().Index(index).Id(_id).BodyJson(tempObj).Do(context.TODO())
+			if err != nil {
+				log.Println("保存到ES出错", err.Error())
+			} else {
+				b = true
+			}
+		}
+
+	}
+	return b
+}
+
 func BulkSave(index, itype string, obj *[]map[string]interface{}, isDelBefore bool) {
 	client := GetEsConn()
 	defer DestoryEsConn(client)
@@ -801,7 +865,7 @@ const (
 	HL_IK           = `"highlight": {"pre_tags": ["` + IK_pre_tags + `"],"post_tags": ["` + IK_post_tags + `"],"fields": {%s}}`
 )
 
-//替换了"号
+// 替换了"号
 func GetNgramQuery(query interface{}, mustquery, findfields string) (qstr string) {
 	var words []string
 	if q, ok := query.(string); ok {
@@ -894,7 +958,7 @@ func GetByNgram(index, itype string, query interface{}, mustquery, findfields, o
 	return GetByNgramAll(index, itype, query, mustquery, findfields, order, fields, start, limit, false, false)
 }
 
-//增加高亮、过滤查询、高亮截取字数
+// 增加高亮、过滤查询、高亮截取字数
 func GetByNgramOther(index, itype string, query interface{}, mustquery, findfields, order, fields string, start, limit int, highlight bool, filtermode bool, count int) *[]map[string]interface{} {
 	defer catch()
 	qstr := ""
@@ -928,8 +992,8 @@ func GetByNgramOther(index, itype string, query interface{}, mustquery, findfiel
 	}
 }
 
-//增加高亮、过滤查询
-//替换了"号
+// 增加高亮、过滤查询
+// 替换了"号
 func GetByNgramAll(index, itype string, query interface{}, mustquery, findfields, order, fields string, start, limit int, highlight bool, filtermode bool) *[]map[string]interface{} {
 	defer catch()
 	qstr := ""
@@ -965,7 +1029,7 @@ func GetByNgramAll(index, itype string, query interface{}, mustquery, findfields
 	}
 }
 
-//增加高亮、过滤查询
+// 增加高亮、过滤查询
 func GetByNgramAll_New(index, itype string, querystring, querymust interface{}, mustquery, findfields, order, fields string, start, limit int, highlight bool, filtermode bool) *[]map[string]interface{} {
 	defer catch()
 	qstr := ""
@@ -1005,7 +1069,7 @@ type KeyConfig struct {
 	Areas     []string `json:"area"`
 }
 
-//替换了"号
+// 替换了"号
 func GetResForJY(index, itype string, keys []KeyConfig, allquery, findfields, SortQuery, fields string, start, limit int) *[]map[string]interface{} {
 	if len(keys) > 0 {
 		qstr := ""
@@ -1063,7 +1127,6 @@ func ReplaceYH(src string) (rpl string) {
 	return strings.Replace(src, `"`, `\"`, -1)
 }
 
-//
 func GetAllByNgram(index, itype, qstr, findfields, order, fields string, start, limit, count int, highlight bool) *[]map[string]interface{} {
 	if qstr != "" {
 		if highlight {
@@ -1089,7 +1152,7 @@ func GetAllByNgram(index, itype, qstr, findfields, order, fields string, start,
 	}
 }
 
-//数据标记2019-07-10
+// 数据标记2019-07-10
 func GetAllByNgram_MP(index, itype, qstr, findfields, order, fields string, start, limit, count int, highlight bool) *[]map[string]interface{} {
 	if qstr != "" {
 		if highlight {
@@ -1115,7 +1178,7 @@ func GetAllByNgram_MP(index, itype, qstr, findfields, order, fields string, star
 	}
 }
 
-//ik 分词
+// ik 分词
 func GetAllByIk(index, itype, qstr, findfields, order, fields string, start, limit, count int, highlight bool) *[]map[string]interface{} {
 	if qstr != "" {
 		if highlight {

+ 6 - 5
log/log.go

@@ -51,14 +51,15 @@ func getzapLevel(level string) zapcore.Level {
 	}
 }
 
-func newLogWriter(logpath string, maxsize int, compress bool) io.Writer {
+func newLogWriter(logpath string, maxsize, maxbacks int, compress bool) io.Writer {
 	if logpath == "" || logpath == "-" {
 		return os.Stdout
 	}
 	return &lumberjack.Logger{
-		Filename: logpath,
-		MaxSize:  maxsize,
-		Compress: compress,
+		Filename:   logpath,
+		MaxSize:    maxsize,
+		MaxBackups: maxbacks,
+		Compress:   compress,
 	}
 }
 
@@ -80,7 +81,7 @@ func newZapEncoder() zapcore.EncoderConfig {
 	return encoderConfig
 }
 func newLoggerCore(log *logConfig) zapcore.Core {
-	hook := newLogWriter(log.LogPath, log.MaxSize, log.Compress)
+	hook := newLogWriter(log.LogPath, log.MaxSize, log.MaxBackups, log.Compress)
 
 	encoderConfig := newZapEncoder()
 

+ 25 - 0
mail/gmail.go

@@ -73,6 +73,31 @@ func GSendMail(from, to, cc, bcc, subject, body, fname, rename string, auth *Gma
 	return gSend(reTry, auth, m, to)
 }
 
+// 电销 多人
+func GSendMail_dx(from, to, cc, bcc, subject, body, fname, rename string, auth *GmailAuth) bool {
+	m := gomail.NewMessage()
+	m.SetAddressHeader("From", auth.User, from)  // 发件人
+	m.SetHeader("To", strings.Split(to, ",")...) // 收件人
+	if cc != "" {
+		m.SetHeader("Cc", strings.Split(cc, ",")...) //抄送
+	}
+	if bcc != "" {
+		m.SetHeader("Bcc", m.FormatAddress(bcc, "收件人")) // 暗送
+	}
+	m.SetHeader("Subject", subject) // 主题
+	m.SetBody("text/html", body)    // 正文
+	if fname != "" {
+		h := map[string][]string{"Content-Type": {"text/plain; charset=UTF-8"}}
+		m.Attach(fname, gomail.Rename(rename), gomail.SetHeader(h)) //添加附件
+		//m.Attach(fname) //添加附件
+	}
+	reTry := auth.ReTry
+	if reTry == 0 {
+		reTry = 3
+	}
+	return gSend(reTry, auth, m, to)
+}
+
 // 如果附件是byte,用这个
 func GSendMail_B(from, to, cc, bcc, subject, body, fname string, fb []byte, auth *GmailAuth) bool {
 	m := gomail.NewMessage()

+ 4 - 0
mongodb/mongodb.go

@@ -348,6 +348,7 @@ type MongodbSim struct {
 	UserName string
 	Password string
 	ReplSet  string
+	Direct   bool
 }
 
 func (m *MongodbSim) GetMgoConn() *MgoSess {
@@ -371,6 +372,9 @@ func (m *MongodbSim) Destroy() {
 
 func (m *MongodbSim) InitPool() {
 	opts := options.Client()
+	if m.Direct {
+		opts.SetDirect(true)
+	}
 	registry := bson.NewRegistryBuilder().RegisterTypeMapEntry(bson.TypeArray, reflect.TypeOf([]interface{}{})).Build()
 	opts.SetRegistry(registry)
 	opts.SetConnectTimeout(3 * time.Second)

+ 8 - 1
mysql/mysql.go

@@ -514,13 +514,20 @@ func (m *Mysql) Count(tableName string, query map[string]interface{}) int64 {
 	return m.CountBySql(q, values...)
 }
 func (m *Mysql) CountBySql(q string, args ...interface{}) int64 {
+	return m.CountBySqlByTx(nil, q, args...)
+}
+func (m *Mysql) CountBySqlByTx(tx *sql.Tx, q string, args ...interface{}) int64 {
 	var rows *sql.Rows
 	var err error
 	if m.driverName == CLICKHOUSE {
 		rows, err = m.DB.Query(q, args...)
 	} else {
 		var stmtOut *sql.Stmt
-		stmtOut, err = m.DB.Prepare(q)
+		if tx == nil {
+			stmtOut, err = m.DB.Prepare(q)
+		} else {
+			stmtOut, err = tx.Prepare(q)
+		}
 		if err != nil {
 			log.Println(err)
 			return -1

+ 10 - 4
rpc/weixin.go

@@ -48,8 +48,14 @@ type TmplItem struct {
 }
 
 type WxTmplMsg struct {
-	OpenId   string //用户id
-	Url      string
-	TplId    string
-	TmplData map[string]*TmplItem
+	GzhCode     string //公众号代码,碎片化的公众号需要传
+	OpenId      string //用户id
+	Url         string
+	TplId       string
+	TmplData    map[string]*TmplItem
+	MiniProgram *MiniProgram
+}
+type MiniProgram struct {
+	AppId    string `json:"appid,omitempty"`
+	PagePath string `json:"pagepath,omitempty"`
 }

+ 15 - 3
sort/sort.go

@@ -86,11 +86,23 @@ func (s *ComSortList) Less(i, j int) bool {
 			continue
 		}
 		if v.Type == "string" {
-			return ObjToString(i_v) > ObjToString(j_v) && v.Order < 0
+			if v.Order < 0 {
+				return ObjToString(i_v) > ObjToString(j_v)
+			} else {
+				return ObjToString(i_v) < ObjToString(j_v)
+			}
 		} else if v.Type == "float" {
-			return Float64All(i_v) > Float64All(j_v) && v.Order < 0
+			if v.Order < 0 {
+				return Float64All(i_v) > Float64All(j_v)
+			} else {
+				return Float64All(i_v) < Float64All(j_v)
+			}
 		} else {
-			return Int64All(i_v) > Int64All(j_v) && v.Order < 0
+			if v.Order < 0 {
+				return Int64All(i_v) > Int64All(j_v)
+			} else {
+				return Int64All(i_v) < Int64All(j_v)
+			}
 		}
 	}
 	return false