Bladeren bron

Merge branch 'feature/v4.10.9' of https://jygit.jydev.jianyu360.cn/qmx/jy into feature/v4.10.9

wangchuanjin 3 maanden geleden
bovenliggende
commit
edc69c6614
25 gewijzigde bestanden met toevoegingen van 1793 en 265 verwijderingen
  1. 2 0
      src/config.yaml
  2. 8 3
      src/jfw/front/index.go
  3. 6 2
      src/jfw/front/nzjProject.go
  4. 74 0
      src/jfw/modules/app/src/web/templates/frontRouter/activity/free/exchange-success.html
  5. 2 2
      src/jfw/modules/app/src/web/templates/frontRouter/activity/free/exchange.html
  6. 47 3
      src/jfw/modules/subscribepay/src/config.json
  7. 14 0
      src/jfw/modules/subscribepay/src/config.yaml
  8. 20 0
      src/jfw/modules/subscribepay/src/config/config.go
  9. 755 95
      src/jfw/modules/subscribepay/src/entity/equityCode.go
  10. 84 20
      src/jfw/modules/subscribepay/src/service/equityCode.go
  11. 43 0
      src/jfw/modules/subscribepay/src/util/db.go
  12. 281 0
      src/jfw/modules/subscribepay/src/util/userGroupService.go
  13. 115 0
      src/web/staticres/common-module/active/exchange/exchange-success.css
  14. 62 0
      src/web/staticres/common-module/active/exchange/exchange-success.js
  15. 36 13
      src/web/staticres/common-module/active/exchange/exchange.js
  16. BIN
      src/web/staticres/common-module/active/exchange/img/new-header.png
  17. 65 7
      src/web/staticres/common-module/public/head.js
  18. 1 1
      src/web/staticres/js/index/index_swiper.js
  19. 48 21
      src/web/staticres/pccss/index_pc.css
  20. 10 2
      src/web/staticres/public-pc/css/header-nav-mini.css
  21. 1 1
      src/web/templates/common/pc-header-nav-mini.html
  22. 2 2
      src/web/templates/frontRouter/wx/activity/free/exchange.html
  23. 73 51
      src/web/templates/pc/newIndex.html
  24. 24 29
      src/web/templates/pc/template/index/data-service-module.html
  25. 20 13
      src/web/templates/pc/template/index/partners-project-list.html

+ 2 - 0
src/config.yaml

@@ -15,3 +15,5 @@ database:
     debug: true
 
 GuideRegistedate: 1734451200  #该时间之前注册的付费用户不用进订阅向导
+supplyEntNum: 15
+winnerGladNum: 15

+ 8 - 3
src/jfw/front/index.go

@@ -589,7 +589,7 @@ func GetIndexRecommendProjectList(typ, pageSize int) (data []map[string]interfac
 
 // 优秀供应商
 func GetBidInfoPublishEnt() (res [][]map[string]interface{}) {
-	if l, ok := redis.Get(RedisNameNew, "pcIndexBidInfoGoodPublishEnt").([]interface{}); ok && l != nil && len(l) > 0 {
+	if l, ok := redis.Get(RedisNameNew, "pcIndexBidInfoGoodPublishEnt_new").([]interface{}); ok && l != nil && len(l) > 0 {
 		for _, v := range l {
 			res = append(res, common.ObjArrToMapArr(v.([]interface{})))
 		}
@@ -613,9 +613,14 @@ func GetBidInfoPublishEnt() (res [][]map[string]interface{}) {
 				entData = resData
 			}
 			if len(entData) > 0 {
+				number := 10
+				if n := g.Cfg().MustGet(gctx.New(), "supplyEntNum").Int(); n > 0 {
+					number = n
+				}
+				log.Println("---number:", number)
 				once := []map[string]interface{}{}
 				for _, val := range entData {
-					if len(once) <= 10 {
+					if len(once) <= number {
 						once = append(once, val)
 					} else {
 						res = append(res, once)
@@ -627,7 +632,7 @@ func GetBidInfoPublishEnt() (res [][]map[string]interface{}) {
 					res = append(res, once)
 				}
 			}
-			redis.Put(RedisNameNew, "pcIndexBidInfoGoodPublishEnt", res, RedisTimeout+rand.Intn(100))
+			redis.Put(RedisNameNew, "pcIndexBidInfoGoodPublishEnt_new", res, RedisTimeout+rand.Intn(100))
 		}
 	}
 	return res

+ 6 - 2
src/jfw/front/nzjProject.go

@@ -13,6 +13,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/os/gctx"
 	"jy/src/jfw/config"
 	"math/rand"
 	"sort"
@@ -752,6 +753,9 @@ func NewHotEnt(isWinner bool, number int) (data []map[string]interface{}) {
 
 // 中标喜报
 func WinnerGladTidings(number int) (entBidArr []map[string]interface{}) {
+	if n := g.Cfg().MustGet(gctx.New(), "winnerGladNum").Int(); n > 0 {
+		number = n
+	}
 	entBidArr = GetEsWinner(number)
 	return
 	/*seed := time.Now().UnixNano()
@@ -809,7 +813,7 @@ func WinnerGladTidings(number int) (entBidArr []map[string]interface{}) {
 }
 
 func GetEsWinner(number int) (data []map[string]interface{}) {
-	redisKey := "bid_winning_news"
+	redisKey := "bid_winning_news_new"
 	if dataBy := redis.Get(RedisNameNew, redisKey); dataBy != nil {
 		dataArr, _ := dataBy.([]interface{})
 		data = common.ObjArrToMapArr(dataArr)
@@ -861,7 +865,7 @@ func GetEsWinner(number int) (data []map[string]interface{}) {
 				k: v,
 			})
 		}
-		redis.Put(RedisNameNew, "bid_winning_news", data, RedisTimeout+rand.Intn(100))
+		redis.Put(RedisNameNew, "bid_winning_news_new", data, RedisTimeout+rand.Intn(100))
 	}
 	return
 }

+ 74 - 0
src/jfw/modules/app/src/web/templates/frontRouter/activity/free/exchange-success.html

@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+
+<head>
+  <title>兑换成功</title>
+
+ {{include "/big-member/meta.html"}}
+
+  <!--S-当前页面的css资源-->
+  <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/reset-css/5.0.1/reset.min.css />
+  <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/index.css />
+  <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/icon/local.css />
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/public/css/app-share-sheet.css?v={{Msg "seo" "version"}}' />
+    <link rel="stylesheet" type="text/css" href="{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/account/css/fast-login.css?v={{Msg "seo" "version"}}"/>
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/active/exchange/exchange-success.css?v={{Msg "seo" "version"}}' />
+  <!--E-当前页面的css资源-->
+  <style>
+  </style>
+</head>
+
+<body>
+<div class="j-container app">
+{{include "/big-member/header.html"}}
+  <div class="j-main" id="main-app" v-cloak>
+    <div class="exchange-success-page">
+      <div class="success-header">
+        <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/active/exchange/img/new-header.png?v={{Msg "seo" "version"}}' alt="兑换成功">
+        <div class="success-title">兑换成功</div>
+        <p class="success-desc" v-html="info.success_desc1"></p>
+        <p class="success-desc mt-12">${info.success_desc2}</p>
+      </div>
+      <div class="success-main">
+        <p class="success-main-tip">您需使用如上手机号登录剑鱼标讯平台使用权益</p>
+        <div class="success-item-group">
+          <div class="success-item" v-for="(item, index) in info.list">
+            <div class="success-item-title">
+              <span class="success-item-title-before">方式${titleBefore[index]}</span>
+              <span>${item.label}</span>
+            </div>
+            <div class="success-item-img" v-if="item.img">
+              <img :src="item.img" :alt="item.label">
+            </div>
+            <p class="success-item-desc" v-if="item.desc">${item.desc}</p>
+            <p class="success-item-desc-after" v-if="item.desc_after">${item.desc_after}</p>
+            <div class="success-item-desc-app" v-if="item.app">
+              <a class="highlight-text" href="https://wx.jianyu360.cn/front/downloadapppage/normal?source=H5&f=exchange">去下载 ></a>
+            </div>
+            <div class="success-item-desc-pc" v-if="item.pc">
+              <span class="pc-link">https://www.jianyu360.cn/</span>
+              <span class="highlight-text" @click="doCopy">复制链接</span>
+            </div>
+          </div>
+        </div>
+
+      </div>
+
+    </div>
+  </div>
+</div>
+
+<script src=//cdn-common.jianyu360.com/cdn/lib/vue/2.6.11/vue.min.js> </script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/vant.min.js> </script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/jquery/3.6.0/jquery.min.js> </script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/moment/2.29.1/min/moment.min.js></script>
+{{include "/big-member/commonjs.html"}}
+    <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/js/common.js?v={{Msg "seo" "version"}}'></script>
+    <!-- <script src=//res2.wx.qq.com/open/js/jweixin-1.6.0.js></script> -->
+    <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/public/js/wx-sdk-share.js?v={{Msg "seo" "version"}}'></script>
+    <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/public/js/app-share-sheet.js?v={{Msg "seo" "version"}}'></script>
+    <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/active/exchange/exchange-success.js?v={{Msg "seo" "version"}}'></script>
+{{include "/common/baiducc.html"}}
+</body>
+
+</html>

+ 2 - 2
src/jfw/modules/app/src/web/templates/frontRouter/activity/free/exchange.html

@@ -49,7 +49,7 @@
             maxlength="4"
             type="number"
             >
-            
+
             <template v-slot:button>
               <div class="img-code-box" @click="getImgCode"><img :src="imgcodeUrl" alt="验证码"></div>
             </template>
@@ -108,7 +108,7 @@
           <div class="success-head">
             <div class="success-title">兑换成功</div>
           </div>
-          <p class="success-desc">${dialog.success_desc1}</p>
+          <p class="success-desc" v-html="dialog.success_desc1"></p>
           <p class="success-desc mt-12">${dialog.success_desc2}</p>
           <div class="swiper-box">
             <van-swipe :loop="false" @change="swiperChange" :show-indicators="false" ref="success_swipe">

+ 47 - 3
src/jfw/modules/subscribepay/src/config.json

@@ -211,8 +211,8 @@
     }
   },
   "newOrderTime": 1709827200,
-  "signing_Subject":"北京剑鱼信息技术有限公司",
-  "orderTime":1704038400,
+  "signing_Subject": "北京剑鱼信息技术有限公司",
+  "orderTime": 1704038400,
   "orderEmailReminder": {
     "qmx": "duxin@topnet.net.cn",
     "jianyu": "duxin@topnet.net.cn"
@@ -234,5 +234,49 @@
   "aliProceduresMoney": 0.6,
   "corporateProceduresMoney": 0,
   "vipGiftStartTime": 1709827200,
-  "vipGiftEndTime":1709827200
+  "vipGiftEndTime": 1709827200,
+  "exchangeInfo": {
+    "member": [
+      {
+        "name": "剑鱼标讯App",
+        "qrcode": "https://www.jianyu360.cn/front/downloadJyApp/qr?page=pc_bottom&source=h5dh",
+        "aText": "去下载",
+        "aLink": "https://www.jianyu360.cn/front/downloadapppage/weixin?source=h5dh&code="
+      },
+      {
+        "name": "剑鱼招标网小程序",
+        "qrcode": "https://jy-applet.jianyu360.cn/debrisproduct/official/jyzbw.png",
+        "text": "长按识别进入小程序"
+      },
+      {
+        "name": "剑鱼标讯PC端",
+        "text": "请您复制剑鱼标讯链接在PC端浏览器打开页面,在PC端使用兑换的权益。",
+        "url": "https://www.jianyu360.cn/"
+      }
+    ],
+    "other": [
+      {
+        "name": "剑鱼标讯公众号",
+        "qrcode": "https://www.qmx.top/upload/2025/04/14/202504141703060048JIKuKjG.png",
+        "text": "长按进入公众号",
+        "remark": "如未绑定手机号,绑定兑换手机号即可"
+      },
+      {
+        "name": "剑鱼招标网小程序",
+        "qrcode": "https://jy-applet.jianyu360.cn/debrisproduct/official/jyzbw.png",
+        "text": "长按识别进入小程序"
+      },
+      {
+        "name": "剑鱼标讯App",
+        "qrcode": "https://www.jianyu360.cn/front/downloadJyApp/qr?page=pc_bottom&source=h5dh",
+        "aText": "去下载",
+        "aLink": "https://www.jianyu360.cn/front/downloadapppage/weixin?source=h5dh&code="
+      },
+      {
+        "name": "剑鱼标讯PC端",
+        "text": "请您复制剑鱼标讯链接在PC端浏览器打开页面,在PC端使用兑换的权益。",
+        "url": "https://www.jianyu360.cn/"
+      }
+    ]
+  }
 }

+ 14 - 0
src/jfw/modules/subscribepay/src/config.yaml

@@ -12,6 +12,20 @@ clickhouse:
   DbName: information
   MaxIdleConns: 5
   MaxOpenConns: 5
+clickhousePubtags:
+  Addr: 172.20.45.129:19000
+  UserName: jytop
+  Password: pwdTopJy123
+  DbName: pub_tags
+  MaxIdleConns: 5
+  MaxOpenConns: 5
+convertlabTidb:
+  Addr: 192.168.3.217:4000
+  UserName: root
+  Password: '=PDT49#80Z!RVv52_z'
+  DbName: convertlabsync
+  MaxIdleConns: 5
+  MaxOpenConns: 5
 resourceCenterKey: "resource.rpc" #资源中台
 
 

+ 20 - 0
src/jfw/modules/subscribepay/src/config/config.go

@@ -161,6 +161,26 @@ type config struct {
 	CorporateProceduresMoney float64           `json:"corporateProceduresMoney"`
 	VipGiftEndTime           int64             `json:"vipGiftEndTime"`
 	VipGiftStartTime         int64             `json:"vipGiftStartTime"`
+
+	ExchangeInfo struct {
+		Member []struct {
+			Name   string `json:"name"`
+			Qrcode string `json:"qrcode,omitempty"`
+			AText  string `json:"aText,omitempty"`
+			ALink  string `json:"aLink,omitempty"`
+			Text   string `json:"text,omitempty"`
+			Url    string `json:"url,omitempty"`
+		} `json:"member"`
+		Other []struct {
+			Name   string `json:"name"`
+			Qrcode string `json:"qrcode,omitempty"`
+			Text   string `json:"text,omitempty"`
+			Remark string `json:"remark,omitempty"`
+			AText  string `json:"aText,omitempty"`
+			ALink  string `json:"aLink,omitempty"`
+			Url    string `json:"url,omitempty"`
+		} `json:"other"`
+	} `json:"exchangeInfo"`
 }
 
 type SiteMsgStruct struct {

+ 755 - 95
src/jfw/modules/subscribepay/src/entity/equityCode.go

@@ -3,12 +3,15 @@ package entity
 import (
 	"database/sql"
 	"encoding/json"
+	"errors"
 	"fmt"
+	"github.com/google/uuid"
 	"jy/src/jfw/modules/subscribepay/src/config"
 	"jy/src/jfw/modules/subscribepay/src/pay"
 	util "jy/src/jfw/modules/subscribepay/src/util"
 	"log"
 	"net/http"
+	"strconv"
 	"strings"
 	"time"
 
@@ -20,17 +23,42 @@ import (
 	"app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
 )
 
+const (
+	groupTypeAll       = 1 // 用户群组类型 1-全部
+	groupTypeTags      = 2 // 用户群组类型 2-标签群组
+	groupTypeBackGroup = 3 // 用户群组类型 3-后台群组
+
+)
+
+const (
+	BackGroupNew      = "0"   // 后台分组 新用户
+	BackGroupLimitM   = "lm"  // 后台分组 仅大会员(非超级订阅的大会员)
+	BackGroupLimitV   = "lv"  // 后台分组 仅超级订阅 (非大会员的超级订阅)
+	BackGroupLimitMv  = "lmv" // 后台分组 大会员且超级订阅
+	BackGroupLimitNMV = "nmv" // 后台分组 非大会员非超级订阅
+
+)
+
+var PayBackGroup = map[string]struct{}{BackGroupLimitM: {}, BackGroupLimitMv: {}, BackGroupLimitV: {}}
+
 type EquityCode struct {
-	Code      string        //权益码
-	UserId    string        //用户id
-	OpenId    string        //openId
-	Phone     string        //用户手机号
-	NickName  string        //用户昵称
-	GiftCode  int           //活动产品code
-	EquityId  int           //权益id
-	R         *http.Request //
-	OrderCode string        //订单编号
-	Sess      *httpsession.Session
+	Code           string        //权益码
+	UserId         string        //用户id
+	OpenId         string        //openId
+	Phone          string        //用户手机号
+	NickName       string        //用户昵称
+	GiftCode       int           //活动产品code
+	EquityId       int           //权益id
+	R              *http.Request //
+	OrderCode      string        //订单编号
+	Sess           *httpsession.Session
+	userInfo       map[string]interface{} // 用于保存mgo用户信息
+	xcxAccountId   int
+	groupId        string
+	frequencyLimit int
+	groupType      int
+	source         string // 注册来源企业名称
+	disChannel     string // 分销渠道  h5是在外边初始化好的,兑换中心那兑换的时候再处理
 }
 
 func GetNewEquityCode(code, userId, phone, nickName, openId string, r *http.Request, sess *httpsession.Session) *EquityCode {
@@ -117,6 +145,7 @@ func (e *EquityCode) Exchange() (msg string, b bool) {
 						}
 						if orderCode != "" {
 							util.Mysql.UpdateOrDeleteBySql(`DELETE FROM dataexport_order WHERE order_code = ?`, orderCode)
+							util.Mysql.UpdateOrDeleteBySql(`DELETE FROM order_sale_record WHERE ordercode = ?`, orderCode)
 						}
 					}(e.OrderCode)
 				}
@@ -127,30 +156,85 @@ func (e *EquityCode) Exchange() (msg string, b bool) {
 	}
 	return
 }
+func (e *EquityCode) H5Exchange() (status int, isMemberProduct bool) {
+	var msg string
+	var b bool
+	repeatKey := fmt.Sprintf("equity_action_phone_%s", e.Phone) // h5兑换没有登录 是手机号
+	if ok, err := redis.Exists("other", repeatKey); ok && err == nil {
+		log.Println(fmt.Sprintf("%s 权益码兑换 请求频次过高,请稍后再试", e.Phone))
+		return
+	}
+	//方式重复性请求--1秒内 允许请求一次
+	redis.Put("other", repeatKey, "REPEAT", 1)
+	// 验证用户 没有用户则创建用户
+	if e.userInfo == nil || len(e.userInfo) == 0 {
+		e.UserId, _, _, _ = e.CreateUser("权益码创建剑鱼用户", "")
+		if e.UserId == "" {
+			log.Println("创建用户失败:", e.Phone)
+			return 0, false
+		}
+	}
+	//订单编号
+	e.OrderCode = pay.GetOrderCode(e.UserId)
+	//更新权益码记录表
+	if b = e.UpdateEquityCode(false); b {
+		//下单并赋权限
+		msg, b, status, isMemberProduct = e.H5UseEquityCodeAndAuthority()
+		//下单失败或者权益开通异常,更新权益码记录表 清除记录
+		if msg != "" || !b {
+			//权限开通异常 回滚数据
+			go func(orderCode string) {
+				if updateBool := e.UpdateEquityCode(true); !updateBool {
+					log.Println(fmt.Sprintf("%s 回退权益码信息异常 ", e.UserId))
+				}
+				if orderCode != "" {
+					util.Mysql.UpdateOrDeleteBySql(`DELETE FROM dataexport_order WHERE order_code = ?`, orderCode)
+					util.Mysql.UpdateOrDeleteBySql(`DELETE FROM order_sale_record WHERE ordercode = ?`, orderCode)
+				}
+			}(e.OrderCode)
+		}
+	} else {
+		return 0, false
+	}
+	return
+}
 
 // UpdateEquityCode 更新权益码记录信息
 func (e *EquityCode) UpdateEquityCode(b bool) bool {
-	queryMap := map[string]interface{}{
-		"equityCode": e.Code,
-	}
-	updateMap := map[string]interface{}{
-		"userId":      e.UserId,
-		"receiveTime": NowFormat(Date_Full_Layout),
-		"userPerson":  qu.If(e.Phone != "", e.Phone, e.NickName).(string),
-		"userTime":    NowFormat(Date_Full_Layout),
-		"orderCode":   e.OrderCode,
-	}
-	//订单异常 或 权益异常
-	if b {
-		updateMap = map[string]interface{}{
-			"userId":      "",
-			"receiveTime": nil,
-			"userPerson":  "",
-			"orderCode":   "",
-			"userTime":    nil,
-		}
-	}
-	return util.ActivityMysql.Update("equity_record", queryMap, updateMap)
+	f := util.ActivityMysql.ExecTx("更新兑换码信息", func(tx *sql.Tx) bool {
+		q := "SELECT * FROM jyactivities.equity_record  where equityCode=? for update"
+		rs := util.ActivityMysql.SelectBySqlByTx(tx, q, e.Code)
+		if rs == nil || len(*rs) == 0 {
+			return false
+		}
+		queryMap := map[string]interface{}{
+			"equityCode": e.Code,
+		}
+		updateMap := map[string]interface{}{
+			"userId":      e.UserId,
+			"receiveTime": NowFormat(Date_Full_Layout),
+			"userPerson":  qu.If(e.Phone != "", e.Phone, e.NickName).(string),
+			"userTime":    NowFormat(Date_Full_Layout),
+			"orderCode":   e.OrderCode,
+		}
+		//订单异常 或 权益异常
+		if b { //  //
+			updateMap = map[string]interface{}{
+				"userId":      "",
+				"receiveTime": nil,
+				"userPerson":  "",
+				"orderCode":   "",
+				"userTime":    nil,
+			}
+		} else {
+			// p719 20250411 添加更新前再次验证兑换码没有被使用
+			if qu.ObjToString((*rs)[0]["userId"]) != "" {
+				return false
+			}
+		}
+		return util.ActivityMysql.UpdateByTx(tx, "equity_record", queryMap, updateMap)
+	})
+	return f
 }
 
 type ProductInfoByEquity struct {
@@ -165,7 +249,7 @@ type ProductInfoByEquity struct {
 
 // UseEquityCodeAndAuthority 权益码使用 并 赋权限
 func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
-	gifts := util.ActivityMysql.SelectBySql(`SELECT a.entid,b.* FROM equity a LEFT JOIN gift b ON a.giftCode = b.giftCode WHERE a.giftCode =  ? AND a.state = 1 AND a.id = ?;`, e.GiftCode, e.EquityId)
+	gifts := util.ActivityMysql.SelectBySql(`SELECT a.entid,b.*,c.name as eName FROM equity a LEFT JOIN gift b ON a.giftCode = b.giftCode left join jyactivities.enterprise c on a.entid = c.id WHERE a.giftCode =  ? AND a.state = 1 AND a.id = ?;`, e.GiftCode, e.EquityId)
 	if gifts != nil && len(*gifts) > 0 {
 		gift := (*gifts)[0]
 		productInfo := &ProductInfoByEquity{
@@ -183,16 +267,13 @@ func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
 			baseMsg                           = jy.GetBigVipUserBaseMsg(e.Sess, *config.Middleground)
 			distributionChannel, orderChannel = util.GetJyOrderChannel("", e.R.Header.Get("User-Agent")) //默认剑鱼标讯
 		)
-		//权益公司
-		if productInfo.EntId > 1 {
-			//2:青柠平台
-			switch productInfo.EntId {
-			case 2:
-				orderChannel = "xdqd05"
-				distributionChannel = "x041"
-			}
+		entName := qu.ObjToString(gift["eName"])
+		orderChannel = "xdqd05"
+		distributionChannel = "x045"
+		items := util.ActivityMysql.SelectBySql(`select item_code from jianyu.dict_item where parent_code='x04' and item_name=?`, entName)
+		if items != nil && len(*items) > 0 {
+			distributionChannel = qu.ObjToString((*items)[0]["item_code"])
 		}
-
 		switch productInfo.ParentCode {
 		case 101:
 			/*
@@ -262,13 +343,7 @@ func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
 					OrderType:  orderType,
 					Badge:      "exchange",
 				}
-				switch distributionChannel {
-				case "x041":
-					filter.ZeroOrderType = "权益码兑换"
-				default:
-					filter.ZeroOrderType = "赠送"
-				}
-
+				filter.ZeroOrderType = "权益码兑换"
 				filterStr, _ := json.Marshal(filter)
 				insertMap["filter"] = string(filterStr)
 				insertMap["filter_id"] = JyVipSubStruct.SaveSelectLog(e.UserId, e.OpenId, &filter)
@@ -334,12 +409,8 @@ func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
 					OrderType:  orderType,
 					Badge:      "exchange",
 				}
-				switch distributionChannel {
-				case "x041":
-					filter.ZeroOrderType = "权益码兑换"
-				default:
-					filter.ZeroOrderType = "赠送"
-				}
+				filter.ZeroOrderType = "权益码兑换"
+
 				filterStr, _ := json.Marshal(filter)
 				insertMap["filter"] = string(filterStr)
 				insertMap["filter_id"] = JyVipSubStruct.SaveSelectLog(e.UserId, e.OpenId, &filter)
@@ -414,12 +485,7 @@ func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
 				"level": level,
 				"badge": "exchange",
 			}
-			switch distributionChannel {
-			case "x041":
-				filterMap["zeroOrderType"] = "权益码兑换"
-			default:
-				filterMap["zeroOrderType"] = "赠送"
-			}
+			filterMap["zeroOrderType"] = "权益码兑换"
 			filter, _ := json.Marshal(filterMap)
 			endDate := time.Date(startTime.Year()+cycle, startTime.Month(), startTime.Day(), 23, 59, 59, 0, time.Local)
 			insertObj := map[string]interface{}{
@@ -489,12 +555,7 @@ func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
 				m = "数据量流量包 计算价格异常"
 				return
 			}
-			switch distributionChannel {
-			case "x041":
-				packDetail.ZeroOrderType = "权益码兑换"
-			default:
-				packDetail.ZeroOrderType = "赠送"
-			}
+			packDetail.ZeroOrderType = "权益码兑换"
 			filter, err := json.Marshal(packDetail)
 			if err != nil {
 				m = "数据量流量包 序列化数据异常"
@@ -534,9 +595,403 @@ func (e *EquityCode) UseEquityCodeAndAuthority() (m string, flag bool) {
 				return
 			}
 		}
+		// 走到这说明前面都成功了
+		// 销售记录表
+		util.Mysql.Insert("order_sale_record", map[string]interface{}{
+			"state":                1,
+			"ordercode":            e.OrderCode,
+			"saler_dept":           "运营部",
+			"saler_dept_id":        27103,
+			"saler_name":           "-",
+			"saler_Id":             -1,
+			"money":                0,
+			"change_value":         0,
+			"group_uuid":           uuid.New().String(),
+			"operator":             "系统自动",
+			"change_reason":        "回款成功",
+			"distribution_channel": distributionChannel,
+			"create_time":          NowFormat(Date_Full_Layout),
+			"statistics_time":      NowFormat(Date_Full_Layout),
+		})
+		return "", flag
 	}
 	return "", flag
 }
+func (e *EquityCode) H5UseEquityCodeAndAuthority() (m string, flag bool, status int, isMemberProduct bool) {
+	gifts := util.ActivityMysql.SelectBySql(`SELECT a.entid,b.* FROM equity a LEFT JOIN gift b ON a.giftCode = b.giftCode  WHERE a.giftCode =  ? AND a.state = 1 AND a.id = ?;`, e.GiftCode, e.EquityId)
+	if gifts != nil && len(*gifts) > 0 {
+		gift := (*gifts)[0]
+		productInfo := &ProductInfoByEquity{
+			ParentCode: qu.IntAll(gift["parentCode"]),
+			GiftCode:   e.GiftCode,
+			Name:       qu.ObjToString(gift["name"]),
+			Num:        qu.IntAll(gift["time"]),
+			NumType:    qu.IntAll(gift["timeType"]),
+			Province:   qu.IntAll(gift["province"]), //0:不做限制;-1:全国;
+			EntId:      qu.IntAll(gift["entid"]),
+		}
+		var (
+			startTime = time.Now()
+			endTime   = time.Now()
+		)
+		vipStatus := 0
+		bigStatus := 0
+		if len(e.userInfo) > 0 {
+			vipStatus = qu.IntAll(e.userInfo["i_vip_status"])
+			bigStatus = qu.IntAll(e.userInfo["i_member_status"])
+		}
+		orderChannel := "xdqd05"
+		distributionChannel := e.disChannel
+		switch productInfo.ParentCode {
+		case 101:
+			/*
+				// 超级订阅 计算周期
+				//插入订单信息
+				// cycleUnit(1:年 2:月 3:天 4:季)
+				// cycleCount 数字长度
+			*/
+			var (
+				area = &map[string]interface{}{"北京": []string{}} //默认
+				//jyactivities 库 》gift 表 标准天和年和支付订单表 天和年单位相反
+				cycleUnit = func(numType int) int {
+					switch numType {
+					case 1:
+						numType = 3 //天
+					case 3:
+						numType = 1 //年
+					}
+					return numType
+				}(productInfo.NumType)
+				//默认设置
+				buySet     = JyVipSubStruct.NewBuySet(area, 1, nil, true) //改版后只能购买升级版超级订阅
+				orderType  = qu.If(vipStatus > 0, 1, 0).(int)             //vip订阅-0:试用 1:续费 2:升级(来自数据库字段说明 -- 为什么没有购买类型)
+				totalPrice int
+				userData   *map[string]interface{}
+			)
+			//插入订单
+			insertMap := map[string]interface{}{
+				"order_status":         1,
+				"user_nickname":        e.NickName,
+				"order_code":           e.OrderCode,
+				"product_type":         "VIP订阅",
+				"create_time":          FormatDate(&startTime, Date_Full_Layout),
+				"user_id":              e.UserId,
+				"user_openid":          e.OpenId,
+				"distribution_channel": distributionChannel, //销售渠道
+				"order_channel":        orderChannel,        //下单渠道
+				"audit_status":         3,                   //默认审核通过
+				"vip_starttime":        FormatDate(&startTime, Date_Full_Layout),
+				"vip_type":             orderType,
+				"pay_money":            0, //价格为0
+				//"pay_time":             FormatDate(&startTime, Date_Full_Layout), //支付时间 当前时间
+				"user_phone":         e.Phone,
+				"is_backstage_order": 1, //线下订单
+			}
+			/*
+			   //开通权限
+			*/
+			if vipStatus > 0 { //仅续费
+				userData, buySet, _ = JyVipSubStruct.GetVipDetail(e.UserId)
+				//是否需要判断 地区
+				if productInfo.Province != 0 {
+					if buySet.AreaCount != productInfo.Province {
+						m = "兑换权益与当前用户权益不对等,无法兑换。请直接联系吕经理15136295365。"
+						status = -7
+						return
+					}
+				}
+				totalPrice = JyVipSubStruct.GetSubVipPrice(buySet, productInfo.Num, cycleUnit) //价格
+				insertMap["order_money"] = totalPrice
+				insertMap["original_price"] = totalPrice
+				filter := VipSimpleMsg{
+					Area:       area,
+					Industry:   []string{},
+					Cyclecount: productInfo.Num,
+					Cycleunit:  cycleUnit,
+					NewBuyset:  buySet,
+					OrderType:  orderType,
+					Badge:      "exchange",
+				}
+				filter.ZeroOrderType = "权益码兑换"
+				filterStr, _ := json.Marshal(filter)
+				insertMap["filter"] = string(filterStr)
+				insertMap["filter_id"] = JyVipSubStruct.SaveSelectLog(e.UserId, e.OpenId, &filter)
+				//计算续费时间
+				timeStamp := qu.Int64All((*userData)["l_vip_endtime"])
+				//开始时间
+				startTime = time.Unix(timeStamp, 0)
+				//结束时间
+				endTime = util.GetDATE(cycleUnit, productInfo.Num, timeStamp)
+				insertMap["vip_type"] = 1
+				insertMap["vip_starttime"] = FormatDate(&startTime, Date_Full_Layout)
+				insertMap["vip_endtime"] = FormatDate(&endTime, Date_Full_Layout)
+				if flag = util.Mysql.Insert("dataexport_order", insertMap) > 1; !flag {
+					m = "超级订阅 续费 订单入库异常"
+					status = 0
+					return
+				}
+				//超级订阅续费--#####
+				flag = JyVipSubStruct.RenewSubVip(e.UserId, FormatDate(&endTime, Date_Full_Layout))
+				//延长超级订阅到期时间--资源中台
+				updateT := &UpdateVipTimeStruct{
+					AccountId: e.UserId,
+					VipTime:   endTime.Unix(),
+				}
+				b, err := updateT.UpdateVipEndTime()
+				if !b || err != nil {
+					log.Println(fmt.Sprintf("%s 更新资源中台 超级订阅到期时间 异常:%s", e.UserId, err.Error()))
+					flag = false
+					m = "超级订阅权限开通失败"
+					status = 0
+					go func(userId string, endTime time.Time) {
+						//调整失败  到期时间复原 对应上面 #####
+						JyVipSubStruct.RenewSubVip(userId, FormatDate(&endTime, Date_Full_Layout))
+					}(e.UserId, startTime)
+					return
+				}
+				//修改附件下载包的到期时间
+				b = FilepackEndtime(e.UserId)
+				if !b {
+					log.Println(fmt.Sprintf("%s 更新 附件下载包到期时间 异常", e.UserId))
+					flag = false
+					m = "超级订阅权限开通失败"
+					status = 0
+					go func(userId string, endTime time.Time) {
+						//调整失败  到期时间复原 对应上面 #####
+						JyVipSubStruct.RenewSubVip(userId, FormatDate(&endTime, Date_Full_Layout))
+					}(e.UserId, startTime)
+					return
+				}
+				flag = b
+			} else if vipStatus < 1 { //新订单
+				//兑换 超级订阅 默认一个省
+				buySet.AreaCount = 1
+				if productInfo.Province != 0 {
+					buySet.AreaCount = productInfo.Province
+				}
+				totalPrice = JyVipSubStruct.GetSubVipPrice(buySet, productInfo.Num, cycleUnit) //价格
+				insertMap["order_money"] = totalPrice
+				insertMap["original_price"] = totalPrice
+				filter := VipSimpleMsg{
+					Area:       area,
+					Industry:   []string{},
+					Cyclecount: productInfo.Num,
+					Cycleunit:  cycleUnit,
+					NewBuyset:  buySet,
+					OrderType:  orderType,
+					Badge:      "exchange",
+				}
+				filter.ZeroOrderType = "权益码兑换"
+				filterStr, _ := json.Marshal(filter)
+				insertMap["filter"] = string(filterStr)
+				insertMap["filter_id"] = JyVipSubStruct.SaveSelectLog(e.UserId, e.OpenId, &filter)
+				//计算时长
+				vsm := VipSimpleMsg{
+					OrderType: 1,
+					NewBuyset: &SubvipBuySet{},
+				}
+				//结束时间
+				endTime = util.GetDATE(cycleUnit, productInfo.Num, startTime.Unix())
+				insertMap["vip_endtime"] = FormatDate(&endTime, Date_Full_Layout)
+				if flag = util.Mysql.Insert("dataexport_order", insertMap) > 1; !flag {
+					m = "超级订阅 购买 订单入库异常"
+					status = 0
+					return
+				}
+				//城市 默认 北京
+				vsm.Area = area
+				vsm.NewBuyset.AreaCount = -1
+				if productInfo.Province > 0 {
+					vsm.NewBuyset.AreaCount = productInfo.Province
+				} //-1是全国
+				vsm.NewBuyset.Upgrade = 1          //超级订阅升级版
+				vsm.NewBuyset.BuyerclassCount = -1 //全行业
+				if flag = JyVipSubStruct.StartSubVip(e.UserId, vsm, startTime, endTime, false, 0, 0, 0); !flag {
+					m = "超级订阅权限开通失败"
+					status = 0
+					return
+				}
+			}
+			if flag {
+				//取消其他超级订阅 未完成的订单
+				go PayCancel(e.UserId, "VIP订阅", "")
+			}
+		case 104:
+			isMemberProduct = true
+			/*
+			   //大会员开通权限
+			*/
+			level := productInfo.NumType //1:专业版;2:智慧版;3:商机版;4:试用版 5:试用版 6:商机版2.0 7:专家版2.0
+			cycle := productInfo.Num     //默认年
+			//判断当前是否是大会员
+			if bigStatus > 0 && bigStatus != level {
+				m = "兑换权益与当前用户权益不对等,无法兑换。请直接联系吕经理15136295365。"
+				status = -7
+				return
+			}
+			if c := util.Mysql.Count("dataexport_order", map[string]interface{}{
+				"user_id":       e.UserId,
+				"product_type":  "大会员",
+				"order_status":  0,
+				"course_status": 2,
+			}); c > 0 {
+				m = "大会员有待审核订单"
+				status = 0
+				return
+			}
+			mData, ok := util.MQFW.FindById("user", e.UserId, `{"i_member_status":1,"i_member_endtime":1,"i_member_starttime":1}`)
+			if !ok || len(*mData) == 0 || mData == nil {
+				m = "查询当前用户信息失败"
+				status = 0
+				return
+			}
+			//续费计算时间
+			if (*mData)["i_member_status"] != nil && qu.Int64All((*mData)["i_member_status"]) > 0 {
+				timeStamp := qu.Int64All((*mData)["i_member_endtime"])
+				//开始时间
+				startTime = time.Unix(timeStamp, 0)
+			}
+			//计算价格
+			orderMoney := MemberStruct.GetMoney(e.UserId, level, cycle)
+			filterMap := map[string]interface{}{
+				"cycle": cycle,
+				"level": level,
+				"badge": "exchange",
+			}
+			filterMap["zeroOrderType"] = "权益码兑换"
+			filter, _ := json.Marshal(filterMap)
+			endDate := time.Date(startTime.Year()+cycle, startTime.Month(), startTime.Day(), 23, 59, 59, 0, time.Local)
+			insertObj := map[string]interface{}{
+				"order_money":          orderMoney,
+				"filter":               string(filter),
+				"order_code":           e.OrderCode,
+				"product_type":         "大会员",
+				"create_time":          NowFormat(Date_Full_Layout),
+				"prepay_time":          NowFormat(Date_Full_Layout),
+				"user_id":              e.UserId,
+				"pay_way":              "",
+				"original_price":       orderMoney,
+				"distribution_channel": distributionChannel, //销售渠道
+				"order_channel":        orderChannel,        //下单渠道
+				"audit_status":         3,                   //默认审核通过
+				"user_phone":           e.Phone,
+				"pay_money":            0,
+				//"pay_time":             NowFormat(Date_Full_Layout),
+				"order_status":       1,
+				"vip_starttime":      NowFormat(Date_Full_Layout),
+				"vip_endtime":        FormatDate(&endDate, Date_Full_Layout),
+				"is_backstage_order": 1, //线下订单
+			}
+			if flag = util.Mysql.Insert("dataexport_order", insertObj) > 1; !flag {
+				m = "大会员 订单入库异常"
+				status = 0
+				return
+			}
+			/*
+			   //开通权限
+			*/
+			if bigStatus > 0 {
+				//大会员续费
+				memberRenew(endDate, e.UserId)
+			} else {
+				//开通大会员
+				normal_member(level, endDate, e.UserId, 0, 0, 0, cycle)
+			}
+			//取消其他订单
+			go PayCancel(e.UserId, "大会员", "")
+		case 112:
+			/*
+			               //数据流量包
+			   			//生订单
+			*/
+			packId := ""
+			switch productInfo.NumType {
+			case 4: //标准
+				packId = fmt.Sprintf("%s_%d", "normal", productInfo.Num)
+			case 5: //高级
+				packId = fmt.Sprintf("%s_%d", "senior", productInfo.Num)
+			}
+			if packId == "" {
+				m = "数据流量包 参数异常"
+				status = 0
+				return
+			}
+			//根据id查询流量包价格
+			packDetail, err := JyDataExportPack.GetPackDetailById(packId)
+			log.Println("packDetail:", packDetail)
+			packDetail.GiveCycle = 0
+			packDetail.DisCountId = 0
+			packDetail.Badge = "exchange"
+			if err != nil {
+				m = "数据量流量包 计算价格异常"
+				status = 0
+				return
+			}
+			packDetail.ZeroOrderType = "权益码兑换"
+			filter, err := json.Marshal(packDetail)
+			if err != nil {
+				m = "数据量流量包 序列化数据异常"
+				status = 0
+				return
+			}
+			log.Println("filter:", string(filter))
+			insertMap := map[string]interface{}{
+				"order_money":          packDetail.Price,
+				"service_status":       0,
+				"user_nickname":        e.NickName,
+				"user_openid":          e.OpenId,
+				"user_phone":           e.Phone,
+				"order_code":           e.OrderCode,
+				"product_type":         "数据流量包",
+				"create_time":          FormatDate(&startTime, Date_Full_Layout),
+				"original_price":       packDetail.Price,
+				"filter":               string(filter),
+				"user_id":              e.UserId,            //20190719 移动端数据导出 生订单添加用户id
+				"distribution_channel": distributionChannel, //销售渠道
+				"order_channel":        orderChannel,        //下单渠道
+				"audit_status":         3,                   //默认审核通过
+				"pay_money":            0,
+				//"pay_time":             FormatDate(&startTime, Date_Full_Layout),
+				"order_status":       1,
+				"is_backstage_order": 1, //线下订单
+			}
+			if flag = util.Mysql.Insert("dataexport_order", insertMap) > 0; !flag {
+				m = "数据流量包 创建订单异常"
+				status = 0
+				return
+			}
+			/*
+			               	//调用中台 增加数据包
+			   			   //开通权限
+			*/
+			if flag, err = perRechargePack(e.UserId, startTime.AddDate(2, 0, 0).Format(Date_Short_Layout), &packDetail); !flag || err != nil {
+				m = "资源账户更改异常"
+				status = 0
+				return
+			}
+		}
+		// 走到这说明前面都成功了
+		// 销售记录表
+		util.Mysql.Insert("order_sale_record", map[string]interface{}{
+			"state":                1,
+			"ordercode":            e.OrderCode,
+			"saler_dept":           "运营部",
+			"saler_dept_id":        27103,
+			"saler_name":           "-",
+			"saler_Id":             -1,
+			"money":                0,
+			"change_value":         0,
+			"group_uuid":           uuid.New().String(),
+			"operator":             "系统自动",
+			"change_reason":        "回款成功",
+			"distribution_channel": distributionChannel,
+			"create_time":          NowFormat(Date_Full_Layout),
+			"statistics_time":      NowFormat(Date_Full_Layout),
+		})
+		return "", flag, 1, isMemberProduct
+	}
+	return "", flag, 0, isMemberProduct
+}
 
 type ExchangeRecords struct {
 	Count   int        `json:"count"`
@@ -666,8 +1121,29 @@ func (e *EquityCode) Submit(codes []string, disChannel, productName, industryCod
 			return false
 		}
 		filter := fmt.Sprintf(`{"xcx_account_id":%d,"baseUserId":%d,"area_count":%d,"buyItemCode":["%s"],"industryCode":"%s","fromMiniCode":"%s","cycleCount":%d,"cycleUnit":%d,"originalAmount":0}`, comAccountId, userId, buyNum, strings.Join(codes, `","`), industryCode, codes[0], number, cycleUnit)
-		util.ActivityMysql.InsertBatchByTx(tx, "jianyu.dataexport_order", []string{"order_code", "pay_money", "order_money", "pay_time", "order_status", "create_time", "filter", "original_price", "product_type", "user_phone", "user_id", "vip_starttime", "vip_endtime", "discount_price", "sale_time", "order_channel", "distribution_channel", "audit_status"}, []interface{}{
-			orderCode, 0, 0, nowFormat, 1, nowFormat, filter, 0, productName, e.Phone, positionId, FormatDate(&orderStartTime, Date_Full_Layout), FormatDate(&orderEndTime, Date_Full_Layout), 0, nowFormat, "xdqd05", disChannel, 3})
+		if b, _ := util.ActivityMysql.InsertBatchByTx(tx, "jianyu.dataexport_order", []string{"order_code", "pay_money", "order_money", "pay_time", "order_status", "create_time", "filter", "original_price", "product_type", "user_phone", "user_id", "vip_starttime", "vip_endtime", "discount_price", "sale_time", "order_channel", "distribution_channel", "audit_status"}, []interface{}{
+			orderCode, 0, 0, nowFormat, 1, nowFormat, filter, 0, productName, e.Phone, positionId, FormatDate(&orderStartTime, Date_Full_Layout), FormatDate(&orderEndTime, Date_Full_Layout), 0, nowFormat, "xdqd05", disChannel, 3}); b <= 0 {
+			return false
+		}
+		// 销售记录表
+		if util.ActivityMysql.InsertByTx(tx, "jianyu.order_sale_record", map[string]interface{}{
+			"state":                1,
+			"ordercode":            orderCode,
+			"saler_dept":           "运营部",
+			"saler_dept_id":        27103,
+			"saler_name":           "-",
+			"saler_Id":             -1,
+			"money":                0,
+			"change_value":         0,
+			"group_uuid":           uuid.New().String(),
+			"operator":             "系统自动",
+			"change_reason":        "回款成功",
+			"distribution_channel": disChannel,
+			"create_time":          nowFormat,
+			"statistics_time":      nowFormat,
+		}) <= 0 {
+			return false
+		}
 		return true
 	}) {
 		return 1
@@ -724,37 +1200,40 @@ func (e *EquityCode) CreateUser(msg, miniprogramCode string) (string, int64, int
 				return false
 			}
 		}
-		//小程序公用的账户
-		if xcxAccountRes := util.BaseMysql.SelectBySqlByTx(tx, `select id from base_service.base_account where person_id=? and type=2 and miniprogram_code is null`, xcxPersonId); xcxAccountRes == nil {
-			log.Println(msg, e.Phone, "查询小程序公用的账户失败")
-			return false
-		} else if len(*xcxAccountRes) == 0 {
-			if xcxComAccountId = util.BaseMysql.InsertBySqlByTx(tx, `insert into base_service.base_account (person_id,type) values (?,?)`, xcxPersonId, 2); xcxComAccountId <= 0 {
-				log.Println(msg, e.Phone, "小程序公用的账户保存失败")
+		// 非小程序不需要走这
+		if miniprogramCode != "" {
+			//小程序公用的账户
+			if xcxAccountRes := util.BaseMysql.SelectBySqlByTx(tx, `select id from base_service.base_account where person_id=? and type=2 and miniprogram_code is null`, xcxPersonId); xcxAccountRes == nil {
+				log.Println(msg, e.Phone, "查询小程序公用的账户失败")
 				return false
+			} else if len(*xcxAccountRes) == 0 {
+				if xcxComAccountId = util.BaseMysql.InsertBySqlByTx(tx, `insert into base_service.base_account (person_id,type) values (?,?)`, xcxPersonId, 2); xcxComAccountId <= 0 {
+					log.Println(msg, e.Phone, "小程序公用的账户保存失败")
+					return false
+				}
+			} else {
+				xcxComAccountId = qu.Int64All((*xcxAccountRes)[0]["id"])
 			}
-		} else {
-			xcxComAccountId = qu.Int64All((*xcxAccountRes)[0]["id"])
-		}
-		//小程序的职位
-		positionRes := util.BaseMysql.SelectBySqlByTx(tx, `select id from base_service.base_position where user_id=? and type=2 and miniprogram_code=?`, xcxUserId, miniprogramCode)
-		if positionRes == nil {
-			log.Println(msg, e.Phone, "查询小程序职位失败")
-			return false
-		}
-		if len(*positionRes) == 0 {
-			accountId := util.BaseMysql.InsertBySqlByTx(tx, `insert into base_service.base_account (person_id,type,miniprogram_code) values (?,?,?)`, xcxPersonId, 2, miniprogramCode)
-			if accountId <= 0 {
-				log.Println(msg, e.Phone, miniprogramCode, "小程序的账户保存失败")
+			//小程序的职位
+			positionRes := util.BaseMysql.SelectBySqlByTx(tx, `select id from base_service.base_position where user_id=? and type=2 and miniprogram_code=?`, xcxUserId, miniprogramCode)
+			if positionRes == nil {
+				log.Println(msg, e.Phone, "查询小程序职位失败")
 				return false
 			}
-			xcxPositionId = util.BaseMysql.InsertBySqlByTx(tx, `insert into base_service.base_position (type,account_id,user_id,miniprogram_code,create_time) values (?,?,?,?,?)`, 2, accountId, xcxUserId, miniprogramCode, nowFormat)
-			if xcxPositionId <= 0 {
-				log.Println(msg, e.Phone, miniprogramCode, "小程序的职位保存失败")
-				return false
+			if len(*positionRes) == 0 {
+				accountId := util.BaseMysql.InsertBySqlByTx(tx, `insert into base_service.base_account (person_id,type,miniprogram_code) values (?,?,?)`, xcxPersonId, 2, miniprogramCode)
+				if accountId <= 0 {
+					log.Println(msg, e.Phone, miniprogramCode, "小程序的账户保存失败")
+					return false
+				}
+				xcxPositionId = util.BaseMysql.InsertBySqlByTx(tx, `insert into base_service.base_position (type,account_id,user_id,miniprogram_code,create_time) values (?,?,?,?,?)`, 2, accountId, xcxUserId, miniprogramCode, nowFormat)
+				if xcxPositionId <= 0 {
+					log.Println(msg, e.Phone, miniprogramCode, "小程序的职位保存失败")
+					return false
+				}
+			} else {
+				xcxPositionId = qu.Int64All((*positionRes)[0]["id"])
 			}
-		} else {
-			xcxPositionId = qu.Int64All((*positionRes)[0]["id"])
 		}
 		//
 		if _id == "" {
@@ -773,7 +1252,7 @@ func (e *EquityCode) CreateUser(msg, miniprogramCode string) (string, int64, int
 					"phone":       e.Phone,
 					"way":         "equityCode",
 					"system":      qu.GetSystem(e.R.UserAgent()),
-					"source":      "xcx",
+					"source":      e.source,
 					"ip":          qu.GetIp(e.R),
 					"user_agent":  e.R.UserAgent(),
 					"create_time": nowUnix,
@@ -791,3 +1270,184 @@ func (e *EquityCode) CreateUser(msg, miniprogramCode string) (string, int64, int
 	}
 	return "", 0, 0, 0
 }
+func (e *EquityCode) InitSource(name string) {
+	e.source = name
+}
+func (e *EquityCode) InitGiftCode(giftCode int) {
+	e.GiftCode = giftCode
+}
+func (e *EquityCode) InitDisChannel(disChannel string) {
+	e.disChannel = disChannel
+}
+func (e *EquityCode) InitUserInfo() error {
+	users, ok := util.MQFW.Find("user", map[string]interface{}{
+		"$or": []map[string]interface{}{
+			map[string]interface{}{
+				"s_phone": e.Phone,
+			}, map[string]interface{}{
+				"s_m_phone": e.Phone,
+			},
+		},
+	}, `{"s_phone":-1}`, `{"_id":1,"base_user_id":1,"i_vip_status":1,"i_member_status":1}`, false, 0, 1)
+	if !ok {
+		log.Println("GetUserInfo", e.Phone, "查询mog库user表失败")
+		return errors.New("查询mog库user表失败")
+	}
+	if users != nil && len(*users) > 0 {
+		e.userInfo = (*users)[0]
+		e.UserId = BsonIdToSId(e.userInfo["_id"])
+		//  补充用户小程序accountId
+		baseUserId := qu.Int64All(e.userInfo["base_user_id"])
+		baseUserRes := util.BaseMysql.SelectBySql(`select person_id from base_service.base_user where id=?`, baseUserId)
+		if baseUserRes == nil || len(*baseUserRes) == 0 {
+			log.Println("InitUserInfo", e.Phone, "baseUserId不存在", baseUserId)
+			return errors.New("获取用户失败")
+		}
+		xcxPersonId := qu.Int64All((*baseUserRes)[0]["person_id"])
+		if xcxAccountRes := util.BaseMysql.SelectBySql(`select id from base_service.base_account where person_id=? and type=2 and miniprogram_code is null`, xcxPersonId); xcxAccountRes == nil || len(*xcxAccountRes) == 0 {
+			log.Println("InitUserInfo", e.Phone, "查询小程序公用的账户失败 xcxPersonId:", xcxPersonId) // 说明用户没开通小程序账号
+			return nil
+		} else {
+			e.xcxAccountId = qu.IntAll((*xcxAccountRes)[0]["id"])
+		}
+	}
+	return nil
+}
+
+func (e *EquityCode) InitCheckInfo(groupId string, groupType int, frequencyLimit int, equityId int) {
+	e.groupId = groupId
+	e.groupType = groupType
+	e.frequencyLimit = frequencyLimit
+	e.EquityId = equityId
+}
+
+// CheckFrequencyLimit 校验兑换码次数
+func (e *EquityCode) CheckFrequencyLimit() bool {
+	if e.userInfo == nil || len(e.userInfo) == 0 || e.frequencyLimit == 0 || e.UserId == "" {
+		log.Println("没有用户信息不用校验")
+		// 没有用户信息 说明是新用户  不用校验  或者没有设置验证
+		return true
+	}
+	q := "select count(*) from jyactivities.equity_record where  userId=? and equityId=?"
+	count := int(util.BaseMysql.CountBySql(q, e.UserId, e.EquityId))
+	log.Println("count===", e.UserId, e.EquityId)
+	if count >= e.frequencyLimit {
+		return false
+	}
+	return true
+}
+
+// CheckUserGroup 校验用户群组
+func (e *EquityCode) CheckUserGroup() bool {
+	if e.groupType == groupTypeAll { //全部
+		//不用校验
+		return true
+	}
+	groupIdList := strings.Split(e.groupId, ",")
+	if len(groupIdList) == 0 { // 选择群组但是群组id为空 配置有误
+		log.Printf("EquityId[%v]: 群组id有误 \n", e.EquityId)
+		return false
+	}
+	if e.userInfo == nil || len(e.userInfo) == 0 {
+		// 没有用户信息 说明是还没有创建用户 所以不用匹配标签群组
+		if e.groupType == groupTypeTags { // 直接返回
+			return false
+		}
+		// 判断后台群组是否包含付费群组(目前付费指超级订阅、大会员 后续如果有其他付费群组这里需要同步调整)
+		// 包含付费用户群组则新用户不符合条件 所以直接返回
+		for i := 0; i < len(groupIdList); i++ {
+			if _, ok := PayBackGroup[groupIdList[i]]; ok {
+				return false
+			}
+		}
+		return true
+	}
+	// 已有用户 正常判断
+	switch e.groupType {
+	case groupTypeTags:
+		return e.checkTagsGroup()
+	case groupTypeBackGroup:
+		return e.checkBackGroup()
+	default:
+		log.Printf("异常分组类型:equityId[%v] 异常类型[%v]\n", e.EquityId, e.groupType)
+		return false
+	}
+}
+func (e *EquityCode) checkTagsGroup() bool {
+	// 用户id 不是mongoId    直接返回
+	// 选择标签分组时 只处理个人身份领取优惠券
+	selectGroupId := []int64{}
+	groupIdList := strings.Split(e.groupId, ",")
+	for i := 0; i < len(groupIdList); i++ {
+		tmpId, err := strconv.ParseInt(groupIdList[i], 10, 64)
+		if err != nil {
+			continue
+		}
+		selectGroupId = append(selectGroupId, tmpId)
+	}
+	if len(selectGroupId) == 0 {
+		log.Println("checkTagsGroup 所选用户分组有误", e.EquityId, e.groupType, e.groupId)
+		return false
+	}
+	uic := util.NewUserIdConstructor(selectGroupId, 0, util.ClickhousePubTags, util.ConvertlabMysql)
+	baseUserId := qu.Int64All(e.userInfo["base_user_id"])
+	count := uic.CountUser(baseUserId)
+	return qu.If(count > 0, true, false).(bool)
+}
+func (e *EquityCode) checkBackGroup() bool {
+	groupIdList := strings.Split(e.groupId, ",")
+	xcxNGroupId := []interface{}{}
+	xcxNGroupIdParam := []string{}
+	userAttributesMap := e.findAttributesMap()
+	//xcxHGroupId := []string{}
+	for i := 0; i < len(groupIdList); i++ {
+		if strings.HasPrefix(groupIdList[i], "xcx") {
+			xcxGroupIdList := strings.Split(groupIdList[i], "-")
+			if len(xcxGroupIdList) == 2 && xcxGroupIdList[1] == "n" { // 非xx行业的  多个时匹配上一个即为匹配成功
+				xcxNGroupId = append(xcxNGroupId, xcxGroupIdList[2])
+				xcxNGroupIdParam = append(xcxNGroupIdParam)
+			}
+		} else {
+			if userAttributesMap[groupIdList[i]] { // 匹配上一个就成功  不用再继续了
+				return true
+			}
+		}
+	}
+	// 一个都没有匹配上剑鱼会员身份 再来看一下是否有配置小程序的
+	if len(xcxNGroupId) > 0 {
+		if e.xcxAccountId == 0 {
+			// 没有小程序账户 直接匹配上非xx行业
+			return true
+		}
+		//  匹配小程序身份
+		return e.checkXcxNPower(xcxNGroupId, xcxNGroupIdParam)
+	}
+	return false
+
+}
+
+// 获取用户身份所属后台群组
+func (e *EquityCode) findAttributesMap() (attributesMap map[string]bool) {
+	attributesMap = map[string]bool{}
+	vipStatus := e.userInfo["i_vip_status"]
+	memberStatus := e.userInfo["i_member_status"]
+	if qu.IntAll(vipStatus) <= 0 && qu.IntAll(memberStatus) > 0 { // 仅大会员
+		attributesMap[BackGroupLimitM] = true
+	} else if qu.IntAll(vipStatus) > 0 && qu.IntAll(memberStatus) <= 0 { // 仅超级订阅
+		attributesMap[BackGroupLimitV] = true
+	} else if qu.IntAll(vipStatus) > 0 && qu.IntAll(memberStatus) > 0 { // 超级订阅且大会员
+		attributesMap[BackGroupLimitMv] = true
+	} else { // 非超级订阅非大会员
+		attributesMap[BackGroupLimitNMV] = true
+	}
+	return
+}
+
+// 判断非xx行业或非xx。。。行业小程序会员
+func (e *EquityCode) checkXcxNPower(xcxNGroupId []interface{}, xcxNGroupIdParam []string) bool {
+	value := []interface{}{e.xcxAccountId}
+	value = append(value, xcxNGroupId...)
+	q := fmt.Sprintf("select count(distinct(m.industry_code)) from debris_product.user_power up left join debris_product.miniprogram m on (up.miniprogram_code=m.code) where up.start_time<=now() and up.end_time>=now() and up.account_id=? and  up.industry_code in (%s) ", strings.Join(xcxNGroupIdParam, ","))
+	//查询结果数量小于查询的行业数量,说明存在不是xx行业的 表示匹配成功
+	return util.BaseMysql.CountBySql(q, xcxNGroupId...) < int64(len(xcxNGroupId))
+}

+ 84 - 20
src/jfw/modules/subscribepay/src/service/equityCode.go

@@ -1,6 +1,8 @@
 package service
 
 import (
+	. "app.yhyue.com/moapp/jybase/api"
+	"app.yhyue.com/moapp/jybase/go-xweb/httpsession"
 	"encoding/json"
 	"fmt"
 	"jy/src/jfw/modules/subscribepay/src/config"
@@ -10,7 +12,6 @@ import (
 	"strings"
 	"time"
 
-	. "app.yhyue.com/moapp/jybase/api"
 	qutil "app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/dchest/captcha"
 	"app.yhyue.com/moapp/jybase/go-xweb/xweb"
@@ -104,11 +105,11 @@ func (e *EquityCode) Submit() {
 		} else if reqType == 2 {
 			sessVal := e.Session().GetMultiple()
 			phone := qutil.ObjToString(sessVal["identCodeKey"])
-			if jy.CheckPhoneIdent(e.Session(), e.GetString("identCode")) == "" { //验证码不正确
+			if CheckPhoneIdentNotClear(e.Session(), e.GetString("identCode")) == "" { //验证码不正确
 				return -1 //短信验证码错误
 			}
 			equityCode := e.GetString("equityCode")
-			datas := util.ActivityMysql.SelectBySql(`SELECT a.id,a.userId,a.equityId,a.startTime,a.endTime,a.state,a.number,a.timeType,b.foreignCode,b.productName,c.province,c.name,e.name as eName FROM jyactivities.equity_record a
+			datas := util.ActivityMysql.SelectBySql(`SELECT a.id,a.userId,a.equityId,a.startTime,a.endTime,a.state,a.number,a.timeType,b.foreignCode,b.productName,c.province,c.name,e.name as eName,a.giftCode,d.groupId,d.frequencyLimit,d.groupType FROM jyactivities.equity_record a
 				INNER JOIN jyactivities.product b ON (a.equityCode=? AND a.parentCode=b.productCode)
 				inner join jyactivities.gift c on (a.giftCode=c.giftCode)
 				INNER JOIN jyactivities.equity d ON (a.equityId=d.id)
@@ -143,14 +144,66 @@ func (e *EquityCode) Submit() {
 					}
 				}
 			}
+			jy.ClearPhoneIdentSession(e.Session())
+			log.Println("清除identCode")
+			disChannel := "x045"
+			items := util.ActivityMysql.SelectBySql(`select item_code from jianyu.dict_item where parent_code='x04' and item_name=?`, qutil.ObjToString((*datas)[0]["eName"]))
+			if items != nil && len(*items) > 0 {
+				disChannel = qutil.ObjToString((*items)[0]["item_code"])
+			}
+			groupId := qutil.ObjToString((*datas)[0]["groupId"])
+			frequencyLimit := qutil.IntAll((*datas)[0]["frequencyLimit"])
+			equityId := qutil.IntAll((*datas)[0]["equityId"])
+			groupType := qutil.IntAll((*datas)[0]["groupType"])
+			nec := entity.GetNewEquityCode(equityCode, "", phone, "", "", e.Request, e.Session())
+			err := nec.InitUserInfo()
+			if err != nil {
+				return 0
+			} // 获取用户信息 用于后续校验兑换次数 用户身份
+			nec.InitCheckInfo(groupId, groupType, frequencyLimit, equityId) // 初始化校验条件信息
+			//  验证兑换码次数  使用用户mgoid 验证
+			if !nec.CheckFrequencyLimit() {
+				return -9
+			}
+			//  校验身份
+			if !nec.CheckUserGroup() {
+				return -8
+			}
+			if qutil.ObjToString((*datas)[0]["eName"]) != "" {
+				nec.InitSource(qutil.ObjToString((*datas)[0]["eName"]))
+			}
+			nec.InitDisChannel(disChannel)
+			giftCode := qutil.IntAll((*datas)[0]["giftCode"])
+			nec.InitGiftCode(giftCode) // 为了后边大会员超级订阅数据流量包走兑换中心的代码 才初始化这的
+			ads, ok := util.MQFW.FindOneByField("ad", map[string]interface{}{"s_code": "mini-app-mine-customer"}, `{"a_son":1}`)
+			if ok && ads != nil && len(*ads) > 0 {
+				a_sons, _ := (*ads)["a_son"].([]interface{})
+				if len(a_sons) > 0 {
+					a_son, _ := a_sons[0].(map[string]interface{})
+					result["kfcode"] = qutil.ObjToString(a_son["s_pic"])
+				}
+			}
 			foreignCode := qutil.ObjToString((*datas)[0]["foreignCode"])
+			giftName := qutil.ObjToString((*datas)[0]["name"])
 			if foreignCode == "" {
-				log.Println(phone, equityCode, "没有找到对应的小程序code")
-				return 0
+				result["isxcx"] = 0
+				log.Println(phone, equityCode, "没有找到对应的小程序code,去验证是不是剑鱼产品")
+				//  超级订阅、大会员、数据流量包走其他的
+				status, isMemberProduct := nec.H5Exchange()
+				if status == 1 {
+					result["name"] = giftName
+					if isMemberProduct {
+						//   返回配置
+						result["list"] = config.Config.ExchangeInfo.Member
+					} else {
+						result["list"] = config.Config.ExchangeInfo.Other
+					}
+				}
+				return status
 			}
 			foreignCodes := strings.Split(foreignCode, ",")
-			giftName := qutil.ObjToString((*datas)[0]["name"])
 			wh, args := qutil.WhArgs(foreignCodes)
+			result["isxcx"] = 1
 			mps := util.ActivityMysql.SelectBySql(`select a.name as aName,a.qrcode,b.name as bName,b.code as bCode from debris_product.miniprogram a
 					inner join debris_product.industry b on (a.code in (`+wh+`) and a.industry_code=b.code)`, args...)
 			if mps == nil || len(*mps) == 0 {
@@ -160,12 +213,7 @@ func (e *EquityCode) Submit() {
 			industryCode := qutil.ObjToString((*mps)[0]["bCode"])
 			industry := qutil.ObjToString((*mps)[0]["bName"])
 			//
-			disChannel := "x045"
-			items := util.ActivityMysql.SelectBySql(`select item_code from jianyu.dict_item where parent_code='x04' and item_name=?`, qutil.ObjToString((*datas)[0]["eName"]))
-			if items != nil && len(*items) > 0 {
-				disChannel = qutil.ObjToString((*items)[0]["item_code"])
-			}
-			res := entity.GetNewEquityCode(equityCode, "", phone, "", "", e.Request, e.Session()).Submit(foreignCodes, disChannel, qutil.ObjToString((*datas)[0]["productName"]), industryCode, qutil.IntAll((*datas)[0]["province"]), qutil.IntAll((*datas)[0]["number"]), qutil.IntAll((*datas)[0]["timeType"]))
+			res := nec.Submit(foreignCodes, disChannel, qutil.ObjToString((*datas)[0]["productName"]), industryCode, qutil.IntAll((*datas)[0]["province"]), qutil.IntAll((*datas)[0]["number"]), qutil.IntAll((*datas)[0]["timeType"]))
 			if res == 1 {
 				result["name"] = giftName
 				list := []map[string]interface{}{}
@@ -183,14 +231,6 @@ func (e *EquityCode) Submit() {
 		return 0
 	}()
 	result["status"] = status
-	ads, ok := util.MQFW.FindOneByField("ad", map[string]interface{}{"s_code": "mini-app-mine-customer"}, `{"a_son":1}`)
-	if ok && ads != nil && len(*ads) > 0 {
-		a_sons, _ := (*ads)["a_son"].([]interface{})
-		if len(a_sons) > 0 {
-			a_son, _ := a_sons[0].(map[string]interface{})
-			result["kfcode"] = qutil.ObjToString(a_son["s_pic"])
-		}
-	}
 	e.ServeJson(Result{
 		Data: result,
 	})
@@ -210,3 +250,27 @@ func (e *EquityCode) Captcha() error {
 	w.Header().Set("Content-Type", "image/png")
 	return captcha.WriteImage(w, id, 90, 30)
 }
+
+const (
+	defaultPhoneFlag = "identCode"
+	ExperienceSign   = "EXPERIENCESIGN"
+)
+
+// 短信验证码校验 不清除
+func CheckPhoneIdentNotClear(session *httpsession.Session, code string, sessionKey ...string) string {
+	sessionKeyFlag := defaultPhoneFlag
+	if len(sessionKey) > 0 && sessionKey[0] != "" {
+		sessionKeyFlag = sessionKey[0]
+	}
+	lastSentTime := qutil.Int64All(session.Get(fmt.Sprintf("%sTime", sessionKeyFlag)))
+	// 是否超过三分钟
+	if lastSentTime < 0 || time.Now().Unix()-lastSentTime > 300 {
+		return ""
+	}
+	identCodeValue, _ := session.Get(fmt.Sprintf("%sValue", sessionKeyFlag)).(string)
+	if identCodeValue != "" && identCodeValue == code {
+		identCodeKey, _ := session.Get(fmt.Sprintf("%sKey", sessionKeyFlag)).(string)
+		return identCodeKey
+	}
+	return ""
+}

+ 43 - 0
src/jfw/modules/subscribepay/src/util/db.go

@@ -24,12 +24,15 @@ var Mysql *mysql.Mysql
 var BaseMysql *mysql.Mysql
 var PushMysql *mysql.Mysql
 var InfoMysql *mysql.Mysql
+var ConvertlabMysql *mysql.Mysql
 var ActivityMysql *mysql.Mysql
 var Mgo_bidding mg.MongodbSim
 var Mgo_log mg.MongodbSim
 var ClickhouseConn driver.Conn
+var ClickhousePubTags driver.Conn
 
 func init() {
+	var ctx = context.Background()
 	//初始化elastic
 	elastic.NewEs(Config.ElasticVersion, Config.Elasticsearch, qutil.IntAllDef(Config.ElasticPoolSize, 30), Config.ElasticUserName, Config.ElasticPassword)
 	//初始化redis
@@ -109,6 +112,15 @@ func init() {
 		MaxIdleConns: Config.ActivityMysql.MaxIdleConns,
 	}
 	ActivityMysql.Init()
+	ConvertlabMysql = &mysql.Mysql{
+		Address:      g.Cfg().MustGet(ctx, "convertlabTidb.Addr").String(),
+		UserName:     g.Cfg().MustGet(ctx, "convertlabTidb.UserName").String(),
+		PassWord:     g.Cfg().MustGet(ctx, "convertlabTidb.Password").String(),
+		DBName:       g.Cfg().MustGet(ctx, "convertlabTidb.DbName").String(),
+		MaxOpenConns: g.Cfg().MustGet(ctx, "convertlabTidb.MaxOpenConns").Int(),
+		MaxIdleConns: g.Cfg().MustGet(ctx, "convertlabTidb.MaxIdleConns").Int(),
+	}
+	ConvertlabMysql.Init()
 	//bidding
 	Mgo_bidding = mg.MongodbSim{
 		MongodbAddr: Config.Mongobidding.Address,
@@ -142,6 +154,7 @@ func init() {
 	}
 	ActivityMysql.Init()
 	ConnectClickhouse()
+	ConnectClickhousePubtags()
 }
 func ConnectClickhouse() error {
 	var (
@@ -173,3 +186,33 @@ func ConnectClickhouse() error {
 	}
 	return nil
 }
+func ConnectClickhousePubtags() error {
+	var (
+		ctx = context.Background()
+		err error
+	)
+	ClickhousePubTags, err = clickhouse.Open(&clickhouse.Options{
+		Addr:         []string{g.Cfg().MustGet(ctx, "clickhousePubtags.Addr").String()},
+		DialTimeout:  10 * time.Second,
+		MaxIdleConns: g.Cfg().MustGet(ctx, "clickhousePubtags.MaxIdleConns").Int(),
+		MaxOpenConns: g.Cfg().MustGet(ctx, "clickhousePubtags.MaxOpenConns").Int(),
+		Auth: clickhouse.Auth{
+			Database: g.Cfg().MustGet(ctx, "clickhousePubtags.DbName").String(),
+			Username: g.Cfg().MustGet(ctx, "clickhousePubtags.UserName").String(),
+			Password: g.Cfg().MustGet(ctx, "clickhousePubtags.Password").String(),
+		},
+		Debugf: func(format string, v ...interface{}) {
+			fmt.Printf(format, v)
+		},
+	})
+	if err != nil {
+		return err
+	}
+	if err := ClickhousePubTags.Ping(ctx); err != nil {
+		if exception, ok := err.(*clickhouse.Exception); ok {
+			fmt.Printf("ClickhousePubTags Exception [%d] %s \n%s\n", exception.Code, exception.Message, exception.StackTrace)
+		}
+		return err
+	}
+	return nil
+}

+ 281 - 0
src/jfw/modules/subscribepay/src/util/userGroupService.go

@@ -0,0 +1,281 @@
+package util
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/mysql"
+	"context"
+	"fmt"
+	"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
+	"log"
+	"strings"
+)
+
+const (
+	logicalOperatorNormal = 0                           // 正常运算标签
+	logicalOperatorNot    = 1                           // 非运算标签
+	tagOperatorAnd        = 1                           // 且
+	tagOperatorOr         = 2                           // 或
+	Tabledwd_d_tag        = "pub_tags.dwd_d_tag"        // 标签用户表  todo 后边调整
+	Tabledwd_mgo_position = "pub_tags.dwd_mgo_position" // base_user_id 对应的mgoid
+	FullUserTagSql        = `SELECT groupBitmapAndState(bitobj) as userIds from pub_tags.dwd_d_tag ddt WHERE  ddt.id=2017`
+	andSql                = `SELECT groupBitmapAndState(bitobj) as userIds from pub_tags.dwd_d_tag ddt WHERE  ddt.id in (%s) `
+	orSql                 = `SELECT groupBitmapOrState(bitobj) as userIds from pub_tags.dwd_d_tag ddt WHERE  ddt.id in (%s) `
+	hasAllSql             = ` bitmapHasAll( ddut.bitobj,bitmapBuild([%s])) `
+	hasAnySql             = ` bitmapHasAny( ddut.bitobj,bitmapBuild([%s])) `
+	notHasAllSql          = ` not bitmapHasAll( ddut.bitobj,bitmapBuild([%s])) `
+	notHasAnySql          = ` not bitmapHasAny( ddut.bitobj,bitmapBuild([%s])) `
+	countUserSql          = `SELECT COUNT(1) as count FROM pub_tags.dwd_d_user_tag ddut  WHERE ddut.baseUserId=%v  AND ( %s )`
+)
+
+// UserIdConstructor 用户群组标签转换
+type UserIdConstructor struct {
+	groupFilter      []int64         // 群组过滤条件
+	userGtFilter     int64           // 用户过滤条件  暂停发消息时 用的
+	userGroupTagList []*UserGroupTag // 用户群组标签列表 (整理后的)
+	baseQuerySQL     string          // 查询群组下base_user_id 的sql
+	countUserSQL     string          // 查询用户标签是否符合群组标签的sql
+	clickhouseConn   driver.Conn
+	tidbConn         *mysql.Mysql
+}
+
+type UserGroupTag struct {
+	GroupId     int64   // 群组id
+	TagOperator int64   // 群组内关系
+	NormalTag   []int64 // 正常标签
+	NotTag      []int64 // 非标签
+}
+
+func NewUserIdConstructor(groupFilter []int64, userGtFilter int64, clickHouseConn driver.Conn, tidbConn *mysql.Mysql) (u *UserIdConstructor) {
+	u = &UserIdConstructor{
+		groupFilter:      groupFilter,
+		userGtFilter:     userGtFilter,
+		userGroupTagList: []*UserGroupTag{},
+		clickhouseConn:   clickHouseConn,
+		tidbConn:         tidbConn,
+	}
+	return
+}
+
+// GetGroupTags 获取用户群组标签信息
+func (u *UserIdConstructor) getGroupTags() *[]map[string]interface{} {
+	groupIdFilter := []string{}
+	groupIdValue := []interface{}{}
+	where := ""
+	for i := 0; i < len(u.groupFilter); i++ {
+		groupIdFilter = append(groupIdFilter, "?")
+		groupIdValue = append(groupIdValue, u.groupFilter[i])
+	}
+	where = fmt.Sprintf("where ugt.group_id in (%s)", strings.Join(groupIdFilter, ","))
+	query := fmt.Sprintf(`SELECT ugt.group_id,ug.tag_operator,ugt.tag_id,ugt.logical_operator FROM convertlabsync.user_group_tag ugt left join user_group ug  on (ugt.group_id=ug.id) %s`, where)
+	rs := u.tidbConn.SelectBySql(query, groupIdValue...)
+	return rs
+}
+
+// InitTagList 处理成方便用的数组
+func (u *UserIdConstructor) InitTagList() bool {
+	rs := u.getGroupTags()
+	if rs == nil || len(*rs) == 0 {
+		return false
+	}
+	groupMap := map[int64]*UserGroupTag{}
+	for i := 0; i < len(*rs); i++ {
+		groupId := common.Int64All((*rs)[i]["group_id"])
+		tagOperator := common.Int64All((*rs)[i]["tag_operator"])
+		tagId := common.Int64All((*rs)[i]["tag_id"])
+		logicalOperator := common.IntAll((*rs)[i]["logical_operator"])
+		if _, ok := groupMap[groupId]; !ok {
+			groupMap[groupId] = &UserGroupTag{
+				GroupId:     groupId,
+				TagOperator: tagOperator,
+				NormalTag:   []int64{},
+				NotTag:      []int64{},
+			}
+		}
+		// 追加
+		switch logicalOperator {
+		case logicalOperatorNormal:
+			groupMap[groupId].NormalTag = append(groupMap[groupId].NormalTag, tagId)
+		case logicalOperatorNot:
+			groupMap[groupId].NotTag = append(groupMap[groupId].NotTag, tagId)
+		}
+	}
+	for _, v := range groupMap {
+		u.userGroupTagList = append(u.userGroupTagList, v)
+	}
+	return true
+}
+
+// 转换成sql   这需要判断
+// '正常标签'这里指不是非运算
+// toBaseQuerySQL 转换成查询baseUserId 的sql
+func (u *UserIdConstructor) toBaseQuerySQL() string {
+	sqlList := []string{} // 包含多个群组的sql
+	for i := 0; i < len(u.userGroupTagList); i++ {
+		// 拼接群组内sql
+		groupTag := u.userGroupTagList[i]
+		normalTagSQL, notTagSQL := "", ""
+		tagSql := ""
+		switch groupTag.TagOperator {
+		case tagOperatorAnd:
+			if len(groupTag.NormalTag) > 0 { // 正常标签
+				normalTagList := []string{}
+				for j := 0; j < len(groupTag.NormalTag); j++ {
+					normalTagList = append(normalTagList, fmt.Sprint(groupTag.NormalTag[j]))
+				}
+				normalTagSQL = fmt.Sprintf(andSql, strings.Join(normalTagList, ","))
+			}
+			if len(groupTag.NotTag) > 0 { // 非标签
+				notTagList := []string{}
+				for j := 0; j < len(groupTag.NotTag); j++ {
+					notTagList = append(notTagList, fmt.Sprint(groupTag.NotTag[j]))
+				}
+				notTagSQL = fmt.Sprintf(orSql, strings.Join(notTagList, ","))
+			}
+			// 同时有:  正常标签 - 非标签
+			if normalTagSQL != "" && notTagSQL != "" {
+				tagSql = fmt.Sprintf("SELECT  bitmapAndnot((%s),(%s)) as userIds", normalTagSQL, notTagSQL)
+			} else if normalTagSQL != "" {
+				// 只有正常标签 : 正常标签
+				tagSql = normalTagSQL
+			} else if notTagSQL != "" {
+				// 只有非标签 :   全量标签-非标签
+				tagSql = fmt.Sprintf("SELECT  bitmapAndnot((%s),(%s)) as userIds", FullUserTagSql, notTagSQL)
+			}
+
+		case tagOperatorOr:
+			if len(groupTag.NormalTag) > 0 { // 正常标签
+				normalTagList := []string{}
+				for j := 0; j < len(groupTag.NormalTag); j++ {
+					normalTagList = append(normalTagList, fmt.Sprint(groupTag.NormalTag[j]))
+				}
+				normalTagSQL = fmt.Sprintf(orSql, strings.Join(normalTagList, ","))
+			}
+			if len(groupTag.NotTag) > 0 { // 非标签
+				notTagList := []string{}
+				for j := 0; j < len(groupTag.NotTag); j++ {
+					notTagList = append(notTagList, fmt.Sprint(groupTag.NotTag[j]))
+				}
+				notTagSQL = fmt.Sprintf(andSql, strings.Join(notTagList, ","))
+			}
+			// 同时有:  正常标签 ∪ (U-(B∩C∩D....))  U:全量标签 B、C、D... 非标签
+			if normalTagSQL != "" && notTagSQL != "" {
+				tmpNotTagSql := fmt.Sprintf("SELECT  bitmapAndnot((%s),(%s)) as userIds", FullUserTagSql, notTagSQL)
+				tagSql = fmt.Sprintf("SELECT  bitmapOr((%s),(%s)) as userIds", FullUserTagSql, tmpNotTagSql)
+			} else if normalTagSQL != "" {
+				// 只有正常标签
+				tagSql = normalTagSQL
+			} else if notTagSQL != "" {
+				// 只有非标签:    U-(B∩C∩D....)  U:全量标签 B、C、D... 非标签
+				tagSql = fmt.Sprintf("SELECT  bitmapAndnot((%s),(%s)) as userIds", FullUserTagSql, notTagSQL)
+			}
+		}
+		sqlList = append(sqlList, tagSql)
+	}
+	// 如果用户有过滤
+	if u.userGtFilter > 0 {
+		u.baseQuerySQL = fmt.Sprintf("SELECT  arrayFilter(x -> x >%v,bitmapToArray( groupBitmapOrState(userIds))) as userIds from (%s)", u.userGtFilter, strings.Join(sqlList, " UNION    DISTINCT  "))
+	} else {
+		u.baseQuerySQL = fmt.Sprintf("SELECT  bitmapToArray( groupBitmapOrState(  userIds)) as userIds  from (%s)", strings.Join(sqlList, " UNION    DISTINCT  "))
+	}
+	log.Println("baseQuerySQL:", u.baseQuerySQL)
+	return u.baseQuerySQL
+}
+
+// 从数据库查询
+func (u *UserIdConstructor) QueryBaseUserIdList() (userList []int64) {
+	if !u.InitTagList() {
+		return []int64{}
+	}
+	rows := u.clickhouseConn.QueryRow(context.Background(), u.toBaseQuerySQL())
+	if err := rows.Scan(&userList); err != nil {
+		log.Println("QueryBaseUserIdList err:", err)
+		return
+	}
+	return userList
+}
+
+// 判断活动群组id 和 用户身上的的标签是否匹配
+// 分组之间用 or 连接
+// 分组内
+// 且: 正常标签: bitmapHasAll  and  (not bitmapHasAny )
+// 或:bitmapHasAny  or (not bitmapHasAny())
+func (u *UserIdConstructor) toCountUserSQL(baseUserId int64) string {
+	sqlList := []string{} // 包含多个群组的sql
+	for i := 0; i < len(u.userGroupTagList); i++ {
+		// 拼接群组内sql
+		groupTag := u.userGroupTagList[i]
+		normalTagSQL, notTagSQL := "", ""
+		tagSql := ""
+		switch groupTag.TagOperator {
+		case tagOperatorAnd:
+			if len(groupTag.NormalTag) > 0 { // 正常标签
+				normalTagList := []string{}
+				for j := 0; j < len(groupTag.NormalTag); j++ {
+					normalTagList = append(normalTagList, fmt.Sprintf("toUInt64(%v)", groupTag.NormalTag[j]))
+				}
+				normalTagSQL = fmt.Sprintf(hasAllSql, strings.Join(normalTagList, ","))
+			}
+			if len(groupTag.NotTag) > 0 { // 非标签
+				notTagList := []string{}
+				for j := 0; j < len(groupTag.NotTag); j++ {
+					notTagList = append(notTagList, fmt.Sprintf("toUInt64(%v)", groupTag.NotTag[j]))
+				}
+				notTagSQL = fmt.Sprintf(notHasAnySql, strings.Join(notTagList, ","))
+			}
+			// 同时有:  正常标签 and 非标签
+			if normalTagSQL != "" && notTagSQL != "" {
+				tagSql = fmt.Sprintf("(%s and %s)", normalTagSQL, notTagSQL)
+			} else if normalTagSQL != "" {
+				// 只有正常标签 : 正常标签
+				tagSql = fmt.Sprintf("(%s)", normalTagSQL)
+			} else if notTagSQL != "" {
+				// 只有非标签 :
+				tagSql = fmt.Sprintf("(%s)", notTagSQL)
+			}
+
+		case tagOperatorOr:
+			if len(groupTag.NormalTag) > 0 { // 正常标签
+				normalTagList := []string{}
+				for j := 0; j < len(groupTag.NormalTag); j++ {
+					normalTagList = append(normalTagList, fmt.Sprintf("toUInt64(%v)", groupTag.NormalTag[j]))
+				}
+				normalTagSQL = fmt.Sprintf(hasAnySql, strings.Join(normalTagList, ","))
+			}
+			if len(groupTag.NotTag) > 0 { // 非标签
+				notTagList := []string{}
+				for j := 0; j < len(groupTag.NotTag); j++ {
+					notTagList = append(notTagList, fmt.Sprintf("toUInt64(%v)", groupTag.NotTag[j]))
+				}
+				notTagSQL = fmt.Sprintf(notHasAllSql, strings.Join(notTagList, ","))
+			}
+			// 同时有:  正常标签  or 非标签
+			if normalTagSQL != "" && notTagSQL != "" {
+				tagSql = fmt.Sprintf(" (%s or %s) ", normalTagSQL, notTagSQL)
+			} else if normalTagSQL != "" {
+				// 只有正常标签 : 正常标签
+				tagSql = fmt.Sprintf(" (%s) ", normalTagSQL)
+			} else if notTagSQL != "" {
+				// 只有非标签 :
+				tagSql = fmt.Sprintf(" (%s) ", notTagSQL)
+			}
+		}
+		sqlList = append(sqlList, tagSql)
+	}
+	u.countUserSQL = fmt.Sprintf(countUserSql, baseUserId, strings.Join(sqlList, " or "))
+	log.Println("toCountUserSQL:", u.countUserSQL)
+	return u.countUserSQL
+}
+
+// 从数据库查询
+func (u *UserIdConstructor) CountUser(baseUserId int64) (count uint64) {
+	if !u.InitTagList() {
+		log.Println("InitTagList 异常")
+		return 0
+	}
+	rows := u.clickhouseConn.QueryRow(context.Background(), u.toCountUserSQL(baseUserId))
+	if err := rows.Scan(&count); err != nil {
+		log.Println("QueryBaseUserIdList err:", err)
+		return
+	}
+	return count
+}

+ 115 - 0
src/web/staticres/common-module/active/exchange/exchange-success.css

@@ -0,0 +1,115 @@
+
+#main-app{
+  background-color: #F5F6F7;
+  padding: 0;
+}
+
+.success-title {
+  font-size: 0.4rem;
+  line-height: 0.52rem;
+  color: #171826;
+  text-align: center;
+  margin-top: 0.62rem;
+  margin-bottom: 0.32rem;
+}
+
+.success-desc {
+  color: #171826;
+  font-size: 0.3rem;
+  line-height: 0.44rem;
+  text-align: center;
+}
+
+.success-header {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  background: #fff;
+  margin-bottom: 0.16rem;
+  padding: 0.64rem 0.56rem 0.32rem 0.32rem;
+}
+.success-header img {
+  width: 2.52rem;
+}
+.success-main .success-main-tip {
+  font-size: 0.3rem;
+  line-height: 0.44rem;
+  color: rgba(23, 24, 38, 1);
+  text-align: center;
+}
+
+.success-main {
+  background: #fff;
+  padding: 0.56rem   0.32rem  0.64rem 0.32rem;
+}
+
+.success-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-top: 0.56rem;
+}
+.success-item .success-item-title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  min-width: 4.52rem;
+  height: 0.64rem;
+  font-size: 0.3rem;
+  line-height: 0.64rem;
+  border: 1px solid rgba(135, 223, 234, 1);
+  border-radius: 0.32rem;
+  padding-right: 0.4rem;
+  color: #2cb7ca;
+}
+.success-item .success-item-title-before {
+  display: inline-block;
+  height: 0.64rem;
+  line-height: 0.64rem;
+  padding: 0 0.24rem;
+  color: #fff;
+  border-radius: 0.32rem;
+  margin-right: 0.32rem;
+  background: linear-gradient(7.32deg, #1DB5E6 5.69%, #2ABED1 94.31%);
+}
+.success-item .success-item-desc-after {
+  margin-top: 0.08rem;
+  color: #5f5e64;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.success-item .success-item-desc-pc .pc-link {
+  color: #5f5e64;
+  margin-right: 0.32rem;
+}
+.success-item .success-item-desc-pc {
+  margin-top: 0.24rem;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.success-item .success-item-app {
+  margin-top: 0.24rem;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.success-item .success-item-desc {
+  margin-top: 0.24rem;
+  color: rgba(23, 24, 38, 1);
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+
+}
+.success-item .success-item-desc-app {
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+  margin-top: 0.24rem;
+}
+.success-item .success-item-img {
+  width: 2.62rem;
+  height: 2.62rem;
+  margin-top: 0.32rem;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  border-radius: 0.16rem;
+  overflow: hidden;
+}

+ 62 - 0
src/web/staticres/common-module/active/exchange/exchange-success.js

@@ -0,0 +1,62 @@
+var sVm = new Vue({
+  el: '#main-app',
+  delimiters: ['${', '}'],
+  mixins: [shareMixin],
+  data: {
+    titleBefore: ['一', '二', '三', '四', '五', '六'],
+    info: {
+      success: true,
+      success_desc1:'',
+      success_desc2:'',
+      list: [
+        {
+          label: '剑鱼标讯公众号',
+          img: 'https://www.jianyu360.cn/front/downloadJyApp/qr?page=pc_bottom&source=pc_scan',
+          desc: '长按识别进入公众号',
+          desc_after: '如未绑定手机号,绑定兑换手机号即可'
+        },
+        {
+          label: '剑鱼标讯网小程序',
+          img: 'https://www.jianyu360.cn/front/downloadJyApp/qr?page=pc_bottom&source=pc_scan',
+          desc: '长按识别进入小程序',
+        },
+        {
+          label: '剑鱼标讯App',
+          img: 'https://www.jianyu360.cn/front/downloadJyApp/qr?page=pc_bottom&source=pc_scan',
+          app: true
+        },
+        {
+          label: '剑鱼标讯PC端',
+          img: 'https://www.jianyu360.cn/front/downloadJyApp/qr?page=pc_bottom&source=pc_scan',
+          desc: '请您复制剑鱼标讯链接在PC端浏览器打开页面,在PC端使用兑换的权益。',
+          pc: true
+        }
+      ]
+    },
+  },
+  mounted: function () {
+    this.doLoad()
+  },
+  methods: {
+    doLoad () {
+      const info = JSON.parse(sessionStorage.getItem('ex-success-info') || '{}')
+      if (info.success) {
+        this.info = info
+      } else {
+        window.close()
+      }
+    },
+    doCopy () {
+      this.copyText('https://www.jianyu360.cn/')
+      this.$toast('复制成功')
+    },
+    copyText: function (text) {
+      const input = document.createElement('textarea') // js创建一个input输入框
+      input.value = text // 将需要复制的文本赋值到创建的input输入框中
+      document.body.appendChild(input) // 将输入框暂时创建到实例里面
+      input.select() // 选中输入框中的内容
+      document.execCommand('copy') // 执行复制操作
+      document.body.removeChild(input) // 最后删除实例中临时创建的input输入框,完成复制操作
+    },
+  }
+})

+ 36 - 13
src/web/staticres/common-module/active/exchange/exchange.js

@@ -40,7 +40,7 @@ var exchangeV = new Vue({
     },
     swiperrightShow(){
       return this.swiperIndex + 1 < this.sc_qrlist.length && this.sc_qrlist.length > 1
-      
+
     }
   },
   created: function () {
@@ -55,8 +55,8 @@ var exchangeV = new Vue({
         clearTimeout(this.imgcodeTimer)
       }
       this.imgcodeTimer = setTimeout(() => {
-        this.imgcodeUrl = this.firstUrl + '/jypay/equityCode/captcha?v=' + new Date().getTime()  
-      },300)  
+        this.imgcodeUrl = this.firstUrl + '/jypay/equityCode/captcha?v=' + new Date().getTime()
+      },300)
     },
     finishDownTime () {
       this.isRunDownTime = false
@@ -124,13 +124,32 @@ var exchangeV = new Vue({
             if(res.data.status === 0){
               _this.$toast('提交失败,请重试')
             }else if(res.data.status === 1){
-              _this.swiperIndex = 0
-              _this.dialog.success_desc1 ='您已经成功兑换' + res.data.name + '权益。'
-              _this.dialog.success_desc2 ='您需要前往' + res.data.industry + '相关小程序(行业相关)上去使用。'
-              _this.sc_qrlist = res.data.list
-              _this.dialog.show_success = true  
-              _this.form.identCode = ''
-              _this.form.imgCode = ''
+              if (res.data.isxcx === 1) {
+                _this.swiperIndex = 0
+                _this.dialog.success_desc1 ='您已经成功兑换 <span class="highlight-text">' + res.data.name + '</span> 权益。'
+                _this.dialog.success_desc2 ='您需要前往' + res.data.industry + '相关小程序(行业相关)上去使用。'
+                _this.sc_qrlist = res.data.list
+                _this.dialog.show_success = true
+                _this.form.identCode = ''
+                _this.form.imgCode = ''
+              } else {
+                sessionStorage.setItem('ex-success-info', JSON.stringify({
+                  success: true,
+                  success_desc1: '您已经成功兑换 <span class="highlight-text">' + res.data.name + '</span> 权益',
+                  success_desc2:'兑换所用手机号:' + _this.form.phone,
+                  list: res.data.list.map(function (v) {
+                    return {
+                      label: v.name,
+                      img: v.qrcode || '',
+                      desc: v.text || '',
+                      desc_after: v.remark || '',
+                      app: (v.name || '').toLocaleLowerCase().indexOf('app') !== -1,
+                      pc: Boolean(v.url || false)
+                    }
+                  })
+                }))
+                location.href = './exchange-success'
+              }
             }else if(res.data.status === -1){
               _this.errorTip = '短信验证码错误'
             }else if(res.data.status === -2){
@@ -145,9 +164,13 @@ var exchangeV = new Vue({
               _this.errorTip = '兑换码已过期'
             }else if(res.data.status === -7){
               _this.dialog.kf_qr = res.data.kfcode
-              _this.dialog.show_kf = true 
+              _this.dialog.show_kf = true
               _this.form.identCode = ''
               _this.form.imgCode = ''
+            }else if(res.data.status === -8){
+              _this.errorTip = '手机号用户当前不能兑换'
+            }else if(res.data.status === -9){
+              _this.errorTip = '手机号用户已无剩余可兑换次数'
             }
           } else {
             _this.$toast(res.error_msg || '请稍后重试')
@@ -167,7 +190,7 @@ var exchangeV = new Vue({
     swipeTo(type){
       if(type === 'left'){
         if (this.swiperIndex === 0) {
-          return 
+          return
         }
         this.$refs.success_swipe.swipeTo(this.swiperIndex - 1)
       }else{
@@ -181,4 +204,4 @@ var exchangeV = new Vue({
       return /^1[3-9]\d{9}$/.test(val)
     },
   }
-})
+})

BIN
src/web/staticres/common-module/active/exchange/img/new-header.png


+ 65 - 7
src/web/staticres/common-module/public/head.js

@@ -1,4 +1,62 @@
 ;(function() {
+  function loadJS (url, success, inject) {
+    var scripts = document.getElementsByTagName('script')
+    for (var i = 0; i < scripts.length; i++) {
+      if (scripts[i].src && scripts[i].src.indexOf(url) > -1) {
+        if (success) success();
+        return;
+      }
+    }
+    var domScript = document.createElement('script');
+    domScript.src = url;
+    typeof inject === 'function' ? inject(domScript) : null;
+    success = success || function () {};
+    domScript.onload = domScript.onreadystatechange = function () {
+      if (!this.readyState || 'loaded' === this.readyState || 'complete' === this.readyState) {
+        success();
+        this.onload = this.onreadystatechange = null;
+        //this.parentNode.removeChild(this);
+      }
+    }
+    document.getElementsByTagName('head')[0].appendChild(domScript);
+  }
+  
+  function injectDevTools () {
+  
+    const devToolsAssets = [
+      'https://pagespy.jydev.jianyu360.com/page-spy/index.min.js',
+      'https://pagespy.jydev.jianyu360.com/plugin/data-harbor/index.min.js',
+      'https://pagespy.jydev.jianyu360.com/plugin/rrweb/index.min.js',
+    ]
+    const waitStates = [false, false, false]
+    function checkLoadState () {
+      const result = !waitStates.some(v => !v)
+      if (result) {
+        console.log('注入远程调试依赖成功')
+        window.$harbor = new DataHarborPlugin();
+        window.$rrweb = new RRWebPlugin();
+  
+        [window.$harbor, window.$rrweb].forEach(p => {
+          PageSpy.registerPlugin(p)
+        })
+  
+        window.$pageSpy = new PageSpy();
+      }
+    }
+    function loadToolsSuccess (i) {
+      waitStates[i] = true
+      checkLoadState()
+    }
+    for (let i = 0; i < devToolsAssets.length; i++) {
+      loadJS(devToolsAssets[i], () => {
+        loadToolsSuccess(i)
+      }, (scriptDom) => {
+        scriptDom.crossorigin = 'anonymous'
+      })
+    }
+  }
+  
+  injectDevTools();
   var host = location.host
   var hm = document.createElement("script");
   // 去除query后的location
@@ -113,12 +171,12 @@
 
   }
 
-  // if (document.cookie.indexOf('fid') === -1) {
-  //   try {
-  //     addMaticId()
-  //   } catch (e) {
-  //     console.log(e)
-  //   }
-  // }
+  if (document.cookie.indexOf('fid') === -1) {
+    try {
+      addMaticId()
+    } catch (e) {
+      console.log(e)
+    }
+  }
 
 })();

+ 1 - 1
src/web/staticres/js/index/index_swiper.js

@@ -15,7 +15,7 @@ var pageSwiper = {
     }
     this.partnersInit()
     this.initGongYingShangList()
-    this.initDataServiceScrollList()
+    // this.initDataServiceScrollList()
     console.log('轮播图初始化完成...')
   },
   initSwiper: function (id) {

+ 48 - 21
src/web/staticres/pccss/index_pc.css

@@ -17,6 +17,12 @@
 .mb24 {
     margin-bottom: 24px;
 }
+.mb32 {
+  margin-bottom: 32px;
+}
+.mb40{
+  margin-bottom: 40px;
+}
 .pd-lr20 {
     padding-left: 20px;
     padding-right: 20px;
@@ -54,6 +60,7 @@
 .main-module.mt6 {
     margin-top: 6px;
 }
+
 .main-module.mt8 {
     margin-top: 8px;
 }
@@ -324,7 +331,6 @@
 /* user-info-module */
 /* no-login */
 .user-info-card {
-    margin-bottom: 40px;
     min-height: 328px;
     border-radius: 4px;
 }
@@ -616,8 +622,8 @@
 }
 .search-type-item {
     position: relative;
-    padding: 4px 12px;
-    font-size: 16px;
+    padding: 3px 12px;
+    font-size: 14px;
     line-height: 22px;
     background-color: transparent;
     color: #2ABED1;
@@ -765,7 +771,7 @@
     left: 0;
     top: 0;
     width: 100%;
-    height: 36px;
+    height: 32px;
     background: linear-gradient(90deg, #2ABED1 0%, rgba(27, 143, 250, 0.96) 99.98%);
     z-index: 1;
 }
@@ -783,7 +789,7 @@
     display: flex;
     align-items: center;
     justify-content: center;
-    height: 36px;
+    height: 32px;
     font-size: 16px;
     font-weight: 700;
     line-height: 24px;
@@ -795,7 +801,7 @@
 }
 .zb-module-nav .search-type-children {
     position: relative;
-    padding: 16px 12px;
+    padding: 10px 14px;
     flex: 1;
     float: none;
 }
@@ -819,22 +825,22 @@
 }
 
 .zb-module-nav .search-type-section:nth-of-type(1) {
-    min-width: 220px;
+    min-width: 225px;
 }
 .zb-module-nav .search-type-section:nth-of-type(2) {
-    min-width: 248px;
+    min-width: 253px;
 }
 .zb-module-nav .search-type-section:nth-of-type(3) {
-    min-width: 160px;
+    min-width: 157px;
 }
 .zb-module-nav .search-type-section:nth-of-type(4) {
-    min-width: 160px;
+    min-width: 157px;
 }
 .zb-module-nav .search-type-section:nth-of-type(5) {
-    min-width: 228px;
+    min-width: 253px;
 }
 .zb-module-nav .search-type-section:nth-of-type(6) {
-    min-width: 164px;
+    min-width: 156px;
 }
 
 /* message-module */
@@ -1072,7 +1078,7 @@
 
 #good-supplier-card .notice-card-content {
     margin-top: 12px;
-    height: 388px;
+    height: 564px;
     overflow: hidden;
 }
 #good-supplier-card .notice-card-list {
@@ -1224,12 +1230,20 @@
     line-height: 22px;
 }
 
+.data-service-module-content {
+  display: flex;
+  flex-direction: column;
+}
+
 /* ent-service-module */
 .service-module-content {
     display: flex;
     justify-content: space-between;
     padding-top: 20px;
 }
+.data-service-module .service-module-content-right {
+  margin-left: 0;
+}
 .service-module-content-right {
     margin-left: 20px;
     flex: 1;
@@ -1282,6 +1296,9 @@
     color: #686868;
     text-align: justify;
 }
+.data-service-module-content .service-desc-button {
+  height: 56px;
+}
 .service-desc-button {
     display: flex;
     align-items: center;
@@ -1345,17 +1362,17 @@
 
 /* data-service-module */
 .data-service-module .service-desc-card {
-    width: 288px;
+    /*width: 288px;*/
 }
 .data-service-module .service-tags-main {
     position: relative;
     margin-top: 10px;
     padding-top: 2px;
     padding-bottom: 10px;
-    border-bottom: 1px solid #e0e0e0;
+    /*border-bottom: 1px solid #e0e0e0;*/
 }
 .data-service-module .service-tags-main-content {
-    max-height: 122px;
+    max-height: 52px;
     overflow: hidden;
 }
 .data-service-module .service-desc-footer {
@@ -1372,10 +1389,11 @@
 }
 .data-service-module .service-button-list {
     margin-top: 20px;
+    display: flex;
+    flex-direction: row;
 }
 .data-service-module .service-desc-button:not(:last-of-type) {
-    margin-bottom: 16px;
-    margin-bottom: 20px;
+    margin-right: 23px;
 }
 /* hot-chart */
 .data-service-module .hot-industry-year-chart {
@@ -1545,26 +1563,35 @@
 }
 
 /* partners-project-container */
+.partners-project-container {
+  width: 100%;
+  padding-top: 12px;
+}
 .partners-project-list {
     display: flex;
     align-items: center;
+    justify-content: space-between;
+    flex-direction: row;
+    width: 100%;
 }
 
+
 .partners-project-item {
-    width: 184px;
-    height: 80px;
+    height: 60px;
     border-radius: 8px;
     overflow: hidden;
+    flex: 1;
 }
 
 .partners-project-item:not(:last-of-type) {
-    margin-right: 19px;
+    margin-right: 23px;
 }
 
 .partners-project-item a,
 .partners-project-item img {
     display: block;
     width: 100%;
+    height: 100%;
 }
 
 /* area-nav 底部区域导航 */

+ 10 - 2
src/web/staticres/public-pc/css/header-nav-mini.css

@@ -185,7 +185,7 @@ a.j-s-button:hover {
     display: flex;
     align-items: center;
     justify-content: space-between;
-    height: 52px;
+    height: 42px;
     font-size: 14px;
     line-height: 22px;
     color: #1d1d1d;
@@ -203,6 +203,7 @@ a.j-s-button:hover {
     margin-right: 4px;
 }
 .header-nav-content .nav-home a {
+    font-size: inherit;
     height: 100%;
     color: #444;
 }
@@ -386,6 +387,13 @@ body .menu-vip-button {
 }
 
 /* 各省分站 */
+.menu-item .j-s-button {
+  min-width: 100px;
+}
+.menu-item .j-s-button,
+.header-nav-content .home-site .j-s-button{
+  padding: 1px 15px;
+}
 .header-nav-content .home-site {
     position: relative;
     display: flex;
@@ -472,7 +480,7 @@ body .menu-vip-button {
     top: 76px;
     right: 12px;
 }
-  
+
 #downloadApp img {
     display: block;
     width: 100%;

+ 1 - 1
src/web/templates/common/pc-header-nav-mini.html

@@ -30,7 +30,7 @@
             <div class="h-nav-c-right flex-row-center">
                 <ul class="menu-list flex-row-center">
                     <li class="menu-item">
-                        <a class="menu-vip-button" href="/product/index?serviceType=0" target="_blank"><i class="j-icon base-icon icon-img-vip-v-deep"></i>会员服务列表</a>
+                        <a class="menu-vip-button" href="/product/index?serviceType=0" target="_blank"><i class="j-icon base-icon icon-img-vip-v-deep"></i>服务列表</a>
                     </li>
                     {{$TopMenus :=JyTopMenu .Request.URL.Path}}
                     {{range $menu := $TopMenus.MenuList }}

+ 2 - 2
src/web/templates/frontRouter/wx/activity/free/exchange.html

@@ -48,7 +48,7 @@
             maxlength="4"
             type="number"
             >
-            
+
             <template v-slot:button>
               <div class="img-code-box"  @click="getImgCode"><img :src="imgcodeUrl" alt="验证码"></div>
             </template>
@@ -107,7 +107,7 @@
           <div class="success-head">
             <div class="success-title">兑换成功</div>
           </div>
-          <p class="success-desc">${dialog.success_desc1}</p>
+          <p class="success-desc" v-html="dialog.success_desc1"></p>
           <p class="success-desc mt-12">${dialog.success_desc2}</p>
           <div class="swiper-box">
             <van-swipe :loop="false" @change="swiperChange" :show-indicators="false" ref="success_swipe">

+ 73 - 51
src/web/templates/pc/newIndex.html

@@ -24,7 +24,7 @@
 </head>
 
 {{$global:=.T}}
-<body>
+<body class="new-theme">
   <section class="body-section bg-white">
     <header class="body-header">
       {{include "/common/pchead.html"}}
@@ -32,36 +32,20 @@
     <main class="body-main">
       <section class="w">
         <!-- 头部logo+搜索模块 -->
-        <section class="main-module mt10">
+        <section class="main-module mt0">
           {{include "/pc/template/index/search-module.html"}}
         </section>
         <!-- 招标采购模块 -->
-        <section class="main-module mt6">
+        <section class="main-module mt0">
           {{include "/pc/template/index/zb-nav-module.html"}}
         </section>
-        <!-- banner swiper -->
-        <section class="main-module swiper-module-12">
-          {{$ad_1:=(Ad "new-pc-index-top-ad" -1 .Host (cookie "SESSIONID"))}}
-          {{if $ad_1}}
-          <div class="banner-swiper swiper-container" id="new-pc-index-top-carousel">
-            <div class="swiper-wrapper">
-              {{range $ad := $ad_1}}
-              <a class="swiper-slide" data-exposure="PC首页 banner 轮播图-{{$ad.S_picalt}}" data-exposure-loop target="_blank" {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}}>
-                <img class="img-banner" src='{{$ad.S_pic}}' alt="{{$ad.S_picalt}}">
-              </a>
-              {{end}}
-            </div>
-            <div class="w1200 swiper-pagination custom-dot"></div>
-          </div>
-          {{end}}
-        </section>
         <!-- 13消息中心 -->
         <section class="main-module">
           {{include "/pc/template/index/banner-message.html"}}
         </section>
         <section class="main-module aside-layout-container">
           <main class="aside-layout--main">
-            <section class="aside-main-module flex-row-center mb20 zb-info-list">
+            <section class="aside-main-module flex-row-center zb-info-list">
               <!-- 中标公告 -->
               {{include "/pc/template/index/zb-aside-card.html"}}
               <div class="swiper-module-15">
@@ -81,22 +65,46 @@
                 {{end}}
               </div>
             </section>
+          </main>
+          <aside class="aside-layout--right">
+            <!-- 用户信息卡片 -->
+            <section class="aside-right-module">
+              {{include "/pc/template/index/user-info-card.html"}}
+            </section>
+          </aside>
+        </section>
+        <!-- banner swiper -->
+        <section class="main-module swiper-module-12">
+          {{$ad_1:=(Ad "new-pc-index-top-ad" -1 .Host (cookie "SESSIONID"))}}
+          {{if $ad_1}}
+          <div class="banner-swiper swiper-container" id="new-pc-index-top-carousel">
+            <div class="swiper-wrapper">
+              {{range $ad := $ad_1}}
+              <a class="swiper-slide" data-exposure="PC首页 banner 轮播图-{{$ad.S_picalt}}" data-exposure-loop target="_blank" {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}}>
+                <img class="img-banner" src='{{$ad.S_pic}}' alt="{{$ad.S_picalt}}">
+              </a>
+              {{end}}
+            </div>
+            <div class="w1200 swiper-pagination custom-dot"></div>
+          </div>
+          {{end}}
+        </section>
+
+        <section class="main-module aside-layout-container">
+          <main class="aside-layout--main">
             <!-- 招标动态 -->
             <section class="aside-main-module mb20">
               {{include "/pc/template/index/module-card-list-container.html"}}
             </section>
-            <!-- 项目专区 -->
-            <section class="aside-main-module mb20">
-              {{include "/pc/template/index/project-card-list-container.html"}}
-            </section>
-            <!-- 项目专区下广告位 -->
+
+            <!-- 推荐标讯专区下广告位 -->
             <section class="aside-main-module mb20 swiper-module-21">
               {{$ad_3:=(Ad "new-pc-index-middle-carousel" -1 .Host  (cookie "SESSIONID"))}}
               {{if $ad_3}}
               <div class="banner-swiper swiper-container" id="new-pc-index-middle-carousel">
                 <div class="swiper-wrapper">
                   {{range $ad := $ad_3}}
-                  <a class="swiper-slide banner-remark" data-exposure="PC项目专区下广告位-{{$ad.S_picalt}}" data-exposure-loop target="_blank" {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}}>
+                  <a class="swiper-slide banner-remark" data-exposure="PC推荐标讯专区下广告位-{{$ad.S_picalt}}" data-exposure-loop target="_blank" {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}}>
                     <img class="img-banner" src='{{$ad.S_pic}}' alt="{{$ad.S_picalt}}">
                   </a>
                   {{end}}
@@ -105,11 +113,28 @@
               </div>
               {{end}}
             </section>
-            <!-- 机构专区 -->
+
+            <!-- 企业服务专区 -->
+            <section class="aside-main-module">
+              {{include "/pc/template/index/ent-service-module.html"}}
+            </section>
+
+            <!-- 数据服务 -->
+            <section class="main-module">
+              {{include "/pc/template/index/data-service-module.html"}}
+            </section>
+
+            <!-- 客户合作案例 -->
+            <section class="main-module swiper-module-30 mb20">
+              {{include "/pc/template/index/partners-project-list.html"}}
+            </section>
+
+            <!-- 项目专区 -->
             <section class="aside-main-module mb20">
-              {{include "/pc/template/index/ent-list-module.html"}}
+              {{include "/pc/template/index/project-card-list-container.html"}}
             </section>
-            <!-- 机构专区下广告位 -->
+
+            <!-- 项目专区下广告位 -->
             <section class="aside-main-module mb20 swiper-module-23">
               <div class="swiper-module-23-children">
                 {{$ad_4:=(Ad "new-pc-index-twenty-three-left" -1 .Host  (cookie "SESSIONID"))}}
@@ -117,7 +142,7 @@
                 <div class="banner-swiper swiper-container" id="new-pc-index-twenty-three-left">
                   <div class="swiper-wrapper">
                     {{range $ad := $ad_4}}
-                    <a class="swiper-slide banner-remark" data-exposure="PC首页机构专区下广告位-{{$ad.S_picalt}}" data-exposure-loop target="_blank" {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}}>
+                    <a class="swiper-slide banner-remark" data-exposure="PC首页项目专区下广告位-{{$ad.S_picalt}}" data-exposure-loop target="_blank" {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}}>
                       <img class="img-banner" src='{{$ad.S_pic}}' alt="{{$ad.S_picalt}}">
                     </a>
                     {{end}}
@@ -142,38 +167,36 @@
                 {{end}}
               </div>
             </section>
-            <!-- 企业服务专区 -->
-            <section class="aside-main-module">
-              {{include "/pc/template/index/ent-service-module.html"}}
-            </section>
+
           </main>
           <aside class="aside-layout--right">
-            <!-- 用户信息卡片 -->
-            <section class="aside-right-module mb20">
-              {{include "/pc/template/index/user-info-card.html"}}
+            <!-- 热门行业 -->
+            <section class="aside-right-module mb32">
+              {{include "/pc/template/index/hot-industry-card.html"}}
             </section>
+
             <!-- 中标喜报 -->
-            <section class="aside-right-module mb20">
+            <section class="aside-right-module mb40">
               {{include "/pc/template/index/bidding-good-news-card.html"}}
             </section>
-            <!-- 热门行业 -->
-            <section class="aside-right-module mb24">
-              {{include "/pc/template/index/hot-industry-card.html"}}
-            </section>
+
             <!-- 优秀供应商 -->
-            <section class="aside-right-module mb20">
+            <section class="aside-right-module">
               {{include "/pc/template/index/notice-card.html"}}
             </section>
           </aside>
         </section>
-        <!-- 数据服务 -->
-        <section class="main-module">
-          {{include "/pc/template/index/data-service-module.html"}}
+
+        <!-- 机构专区 -->
+        <section class="aside-main-module mb20">
+          {{include "/pc/template/index/ent-list-module.html"}}
         </section>
-        <!-- 数据服务下轮播图 -->
+
+        <!-- 机构专区下轮播图 -->
         <section class="main-module swiper-module-27">
           {{include "/pc/template/index/banner-module-27.html"}}
         </section>
+
         <!-- 剑鱼文库 -->
         <section class="main-module aside-layout-container">
           <main class="aside-layout--main">
@@ -189,10 +212,9 @@
             {{include "/pc/template/index/cms-card-deep.html"}}
           </aside>
         </section>
-        <!-- 客户合作案例 -->
-        <section class="main-module swiper-module-30">
-          {{include "/pc/template/index/partners-project-list.html"}}
-        </section>
+
+
+
         <!-- 地区导航 -->
         <section class="main-module">
           {{include "/pc/template/index/area-nav-module.html"}}

+ 24 - 29
src/web/templates/pc/template/index/data-service-module.html

@@ -3,35 +3,23 @@
   <header class="module-card-header">
     <h3 class="module-card-title">数据服务专区</h3>
   </header>
-  <main class="module-card-content service-module-content">
-    <div class="service-module-content-left">
-      <section class="service-desc-card pd-lr20">
-        <header class="service-desc-header">
-          <h3 class="title-left-line">热门采购数据</h3>
-        </header>
-        <main class="service-tags-main">
-          <div class="service-tags-main-content">
-            <ul class="service-tags-list clearfix">
-              {{range $v := .T.hotBuyerData}}
-              <li class="service-tags-item">
-                <a class="cms-link" href="{{$v.url}}" target="_blank" title="{{$v.keyword}}">{{$v.keyword}}</a>
-              </li>
-              {{end}}
-            </ul>
-          </div>
-        </main>
-        <footer class="service-desc-footer">
-          <h3 class="title-left-line">数据服务</h3>
-        </footer>
-      </section>
-      <div class="service-button-list clearfix">
-        <a class="service-desc-button button-blink pointer s-plain" href="/front/dataExport/toSieve" target="_blank">数据导出</a>
-        <a class="service-desc-button button-blink pointer s-plain" href="/front/dataMarket/customExport" target="_blank">定制服务</a>
-        <a class="service-desc-button button-blink pointer s-plain" href="/front/dataMarket/dataInterface" target="_blank">对接服务</a>
-        <a class="service-desc-button button-blink pointer s-plain" href="/datasmt/qygssj_1" target="_blank">企业数据</a>
-        <a class="service-desc-button button-blink pointer s-plain" href="/datasmt/cgdwsj_1" target="_blank">业主数据</a>
-      </div>
-    </div>
+  <main class="module-card-content data-service-module-content">
+    <section class="service-desc-card pd-lr20">
+      <header class="service-desc-header">
+        <h3 class="title-left-line">热门采购数据</h3>
+      </header>
+      <main class="service-tags-main">
+        <div class="service-tags-main-content">
+          <ul class="service-tags-list clearfix">
+            {{range $v := .T.hotBuyerData}}
+            <li class="service-tags-item">
+              <a class="cms-link" href="{{$v.url}}" target="_blank" title="{{$v.keyword}}">{{$v.keyword}}</a>
+            </li>
+            {{end}}
+          </ul>
+        </div>
+      </main>
+    </section>
     <div class="service-module-content-right">
       <section class="hot-industry-year-chart">
         <header class="hot-industry-chart-header">
@@ -87,5 +75,12 @@
         </main>
       </section>
     </div>
+    <div class="service-button-list clearfix">
+      <a class="service-desc-button button-blink pointer s-plain" href="/front/dataExport/toSieve" target="_blank">数据导出</a>
+      <a class="service-desc-button button-blink pointer s-plain" href="/front/dataMarket/customExport" target="_blank">定制服务</a>
+      <a class="service-desc-button button-blink pointer s-plain" href="/front/dataMarket/dataInterface" target="_blank">对接服务</a>
+      <a class="service-desc-button button-blink pointer s-plain" href="/datasmt/qygssj_1" target="_blank">企业数据</a>
+      <a class="service-desc-button button-blink pointer s-plain" href="/datasmt/cgdwsj_1" target="_blank">业主数据</a>
+    </div>
   </main>
 </section>

+ 20 - 13
src/web/templates/pc/template/index/partners-project-list.html

@@ -1,15 +1,22 @@
 <!-- 客户合作案例 -->
-<section class="partners-project-container">
-  {{$ad_5:=(Ad "new-pc-index-bottom-ad" -1 .Host (cookie "SESSIONID"))}}
-  {{if $ad_5}}
-  <ul class="partners-project-list clearfix">
-    {{range $ad := $ad_5}}
-    <li class="partners-project-item">
-      <a {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}} target="_blank">
-        <img src="{{$ad.S_pic}}" alt="{{$ad.S_picalt}}">
-      </a>
-    </li>
-    {{end}}
-  </ul>
-  {{end}}
+<section class="module-card-container">
+  <header class="module-card-header">
+    <h3 class="module-card-title">典型案例</h3>
+  </header>
+  <main class="module-card-content">
+    <section class="partners-project-container">
+      {{$ad_5:=(Ad "new-pc-index-bottom-ad" -1 .Host (cookie "SESSIONID"))}}
+      {{if $ad_5}}
+      <ul class="partners-project-list clearfix">
+        {{range $ad := $ad_5}}
+        <li class="partners-project-item">
+          <a {{if $ad.S_link}}href="{{$ad.S_link}}"{{end}} target="_blank">
+            <img src="{{$ad.S_pic}}" alt="{{$ad.S_picalt}}">
+          </a>
+        </li>
+        {{end}}
+      </ul>
+      {{end}}
+    </section>
+  </main>
 </section>