Przeglądaj źródła

Merge branch 'master' into hotfix/v4.8.68.1

lianbingjie 1 rok temu
rodzic
commit
99bde58ab0

+ 1 - 1
src/jfw/front/classificationTag.go

@@ -65,7 +65,7 @@ func GetHotIndustry() (rData []map[string][]map[string]interface{}) {
 	}
 	rData = getkeysMap() //热门行业
 	if bytes, err := json.Marshal(rData); err == nil && bytes != nil {
-		_ = redis.PutBytes(RedisNameNew, "pcIndexHotIndustry", &bytes, 2*60*60)
+		_ = redis.PutBytes(RedisNameNew, "pcIndexHotIndustry", &bytes, RedisTimeout)
 	}
 	return rData
 }

+ 2 - 2
src/jfw/front/dataServiceArea.go

@@ -132,7 +132,7 @@ func GovernmentTender(number int) []argument {
 		}
 
 	}
-	redis.Put(RedisNameNew, redisKey, data, 3600*6)
+	redis.Put(RedisNameNew, redisKey, data, RedisTimeout)
 	return data
 }
 
@@ -336,7 +336,7 @@ func PurchasingData() []map[string]interface{} {
 				"url":     fmt.Sprintf("/datasmt/index_1?searchValue=%s", common.InterfaceToStr(m["keyword"])),
 			})
 		}
-		redis.Put(RedisNameNew, "hotPurchasingData", keyWords, 24*3600*30)
+		redis.Put(RedisNameNew, "hotPurchasingData", keyWords, RedisTimeout)
 	}
 
 	return keyWords

+ 6 - 5
src/jfw/front/index.go

@@ -30,6 +30,7 @@ type NewIndex struct {
 }
 
 var (
+	RedisTimeout   = 2 * 3600
 	routerRelayMap map[string]map[bool]string
 	BiddingTypeUrl = map[int]string{
 		1:  "/list/stype/ZBYG.html",
@@ -317,7 +318,7 @@ func GetRecommendBidZone(typ int, pageSize int) (list []map[string]interface{},
 	}
 	finalArr := FillingBiddingBaseFields(gctx.New(), queryRes.List(), typs)
 	if finalArr != nil && len(finalArr) > 0 {
-		redis.Put(RedisNameNew, rediskey, finalArr, 24*3600)
+		redis.Put(RedisNameNew, rediskey, finalArr, RedisTimeout)
 	}
 	return finalArr, typs
 }
@@ -424,7 +425,7 @@ func GetIndexProjectListRedis(typ, pageSize int) (data []map[string]interface{},
 	}
 	data, _ = GetIndexProjectList(typ, pageSize, []map[string]interface{}{})
 	if data != nil && len(data) > 0 {
-		redis.Put(RedisNameNew, redidKey, data, 24*3600+rand.Intn(100))
+		redis.Put(RedisNameNew, redidKey, data, RedisTimeout+rand.Intn(100))
 	}
 	return data, types
 }
@@ -454,7 +455,7 @@ func GetIndexRecommendProjectList(typ, pageSize int) (data []map[string]interfac
 		data = append(data, v)
 	}
 	if data != nil && len(data) > 0 {
-		redis.Put(RedisNameNew, redidKey, data, 24*3600+rand.Intn(100))
+		redis.Put(RedisNameNew, redidKey, data, RedisTimeout+rand.Intn(100))
 	}
 	return data, types
 }
@@ -499,7 +500,7 @@ func GetBidInfoPublishEnt() (res [][]map[string]interface{}) {
 					res = append(res, once)
 				}
 			}
-			redis.Put(RedisNameNew, "pcIndexBidInfoGoodPublishEnt", res, 24*3600)
+			redis.Put(RedisNameNew, "pcIndexBidInfoGoodPublishEnt", res, RedisTimeout+rand.Intn(100))
 		}
 	}
 	return res
@@ -517,7 +518,7 @@ func GetImportBidding() []*hotKeyWord {
 	randomNumber := rand.Intn(len(subjectMatter) - 30)
 	res := subjectMatter[randomNumber : randomNumber+30]
 	if len(res) > 0 {
-		redis.Put(RedisNameNew, "pcIndexImportBidding", res, 24*3600)
+		redis.Put(RedisNameNew, "pcIndexImportBidding", res, RedisTimeout+rand.Intn(100))
 	}
 	return res
 }

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

@@ -699,7 +699,7 @@ func NewHotEnt(isWinner bool, number int) (data []map[string]interface{}) {
 		} else {
 			data = redisData
 		}
-		redis.Put("newother", redisKey, data, 3600*24)
+		redis.Put("newother", redisKey, data, RedisTimeout)
 	}
 	return
 }
@@ -815,7 +815,7 @@ func GetEsWinner(number int) (data []map[string]interface{}) {
 				k: v,
 			})
 		}
-		redis.Put(RedisNameNew, "bid_winning_news", data, 3600*24)
+		redis.Put(RedisNameNew, "bid_winning_news", data, RedisTimeout+rand.Intn(100))
 	}
 	return
 }
@@ -837,6 +837,9 @@ func IndexNzjProject(number int) (data []map[string]interface{}) {
 				"proposed_id":  encrypt.SE2.Encode2Hex(common.InterfaceToStr(v["proposed_id"])),
 			})
 		}
+		if len(data) > 0 {
+			redis.Put(RedisNameNew, "pcIndexNzjProject", data, RedisTimeout+rand.Intn(100))
+		}
 	}
 	return data
 }

BIN
src/jfw/modules/app/src/web/staticres/jyapp/images/wx/app-cg-detail.png


BIN
src/jfw/modules/app/src/web/staticres/jyapp/images/wx/app-nj-detail.png


+ 1 - 1
src/jfw/modules/app/src/web/templates/me/appVersion.html

@@ -119,7 +119,7 @@
             computed:{
               appVersion: function () {
                 if (this.curVersion) {
-                  return 'V' + this.curVersion
+                  return this.curVersion
                 } else {
                   return ''
                 }

+ 46 - 14
src/jfw/modules/app/src/web/templates/weixin/wxinfocontent.html

@@ -127,7 +127,7 @@
           font-weight: 500;
           color: #161826;
           line-height: 0.4rem;
-          margin-bottom: 0.48rem;
+          margin-bottom: 0.24rem;
           align-items: center;
           text-align: center;
       }
@@ -821,17 +821,22 @@
                     {{end}}
                 </ul>
             </div>
-            <div class="mask-zz dialog-tip-group default-dialog hidden">
+            <div class="mask-zz dialog-tip-group default-dialog hidden" id="cg-nj-dialog">
                 <div class="mask-zz">
-                    <div style="position: relative">
-                        <img class="dialog-top-img" src='/jyapp/images/wx/pc_zzt.png?v={{Msg "seo" "version"}}'>
-                        <div id="dialog-tip-title" style="position: absolute;top: 50%;left: 50%; transform: translateX(-50%);height: 26px;color: antiquewhite;font-size: 16px;white-space: nowrap;">超前项目抢先知,中标更容易</div>
-                    </div>
-                    <div style="display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0.48rem 0.32rem;">
-                        <div class="dialog-tip-text">
-                            提前3-12个月获取审批中的新项目,超前项目抢先介入,商机提前掌控。
+                    <div style="position: relative; padding-bottom: .4rem; background: url('/jyapp/big-member/image/openVip.png') no-repeat;min-height: 7.4rem;background-size: contain;">
+                        <!-- <img class="dialog-top-img" src='/jyapp/images/wx/pc_zzt.png?v={{Msg "seo" "version"}}'> -->
+                        <div class="tip-box-example">
+                          <div id="dialog-tip-title" style="height: 26px;color: antiquewhite;font-size: 16px;white-space: nowrap;text-align: center; padding: .48rem 0 .32rem;">${info.headtext}</div>
+                          <div class="dialog-tip-img" style="position: relative;">
+                            <div style="position: absolute;right: .32rem; top: .32rem;padding: .02rem .16rem;background: #E5FCFF;color: #2ABED1;font-size: .26rem;">示例</div>
+                            <img :src="'{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/images/wx/' + info.img +'.png?v={{Msg "seo" "version"}}'" alt="">
+                          </div>
+                        </div>
+                        <div style="display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0 0.32rem;background: #fff;">
+                            <div class="dialog-tip-text" v-html="info.text">
+                            </div>
+                            <button class="free-btn-reword" style="background-color:  #2CB7CA;font-size: 0.32rem;color: white;border:none;width: 100%;height:0.72rem;border-radius: 0.12rem;">${info.btntext}</button>
                         </div>
-                        <button class="free-btn-reword" style="background-color:  #2CB7CA;font-size: 0.32rem;color: white;border:none;width: 100%;height:0.72rem;border-radius: 0.12rem;">点击进入</button>
                     </div>
                 </div>
             </div>
@@ -1636,8 +1641,8 @@
         // 改遮罩文字
         if (advanceProject) {
             if (subtype == '采购意向') {
-                $('#dialog-tip-title').text('项目提前介入,中标更轻松')
-                $(".dialog-tip-text").html('提前1-3个月获取项目信息,及早介入准备更充分')
+                // $('#dialog-tip-title').text('项目提前介入,中标更轻松')
+                // $(".dialog-tip-text").html('提前1-3个月获取项目信息,及早介入准备更充分')
             }
             if(!canRead) {
               $('.default-dialog').removeClass("hidden")
@@ -1700,7 +1705,7 @@
     })
 
     //留资弹窗页面
-    $('.free-btn-reword').on('click', function() {
+    $(document).on('click', '.free-btn-reword', function() {
         var subType = {{.T.obj.subtype}}
         var sourceKey = 'article_slogan'
         if(!canRead) {
@@ -1924,6 +1929,34 @@
     //     }
     //   })
     // }
+    // 采购意向、拟建遮罩弹窗
+    var cgnjDialog = new Vue({
+      delimiters: ['${', '}'],
+      el: '#cg-nj-dialog',
+      data: {
+        info: {}
+      },
+      mounted: function () {
+        if(subtype === '拟建') {
+          this.info = {
+            text: '提前3-12个月获取审批中的新项目,超前项目抢先介入,商机提前掌控。',
+            img: 'app-nj-detail',
+            headtext: '超前项目抢先知,中标更容易',
+          }
+        } else if(subtype === '采购意向') {
+          this.info = {
+            text: '提前1-3个月获取项目信息,<br/>及早介入准备更充分',
+            img: 'app-cg-detail',
+            headtext: '项目提前介入,中标更轻松',
+          }
+        }
+        if(!userId) {
+          this.info.btntext = '登陆后解锁会员查看'
+        } else {
+          this.info.btntext = '点击进入'
+        }
+      }
+    })
     // 参标展示更新投标状态弹窗
     var showUpdateBid = new Vue({
       el: '.refer_stand',
@@ -2187,7 +2220,6 @@
                           location.href = '/jy_mobile/common/order/create/svip?type=buy'
                         }).catch(() => {})
                       }
-                    return
                 }else if (r && r.m === '' && r.r) {
                     var url = r.r.downUrl
                     if (url){

+ 41 - 2
src/jfw/modules/subscribepay/src/config.json

@@ -1,5 +1,4 @@
 {
-  "smsServiceRpc": "192.168.3.149:932",
   "mongodbServers": "192.168.3.206:27080",
   "mongodbPoolSize": 10,
   "mongodbName": "qfw",
@@ -159,5 +158,45 @@
     "key": "powercheck.rpc"
   },
   "taskStartTime": 1698020000,
-  "financeMail": "wanghao@topnet.net.cn"
+  "financeMail": "wanghao@topnet.net.cn",
+  "equityActive": {
+    "open": true,
+    "siteMsg": {
+      "callPlatform": "subscribepay",
+      "msgType": 13,
+      "title": "%s已到账,戳我解锁!",
+      "content": "购买%s产品赠送%s已到账。兑换码%s。兑换截止日期:%s,请前往腾讯视频进行兑换解锁福利。#jy#购买%s赠送%s#jy#兑换码%s。请前往腾讯视频进行兑换解锁福利。",
+      "link": "",
+      "androidUrl": "",
+      "iosUrl": "",
+      "weChatUrl": ""
+    },
+    "mailAlarm": {
+      "to": [
+        "328974233@qq.com"
+      ],
+      "title": "视频会员权益码数据告警",
+      "reTry": 3,
+      "threshold": {
+        "0": {
+          "name": "月度",
+          "value": 30
+        },
+        "1": {
+          "name": "年度",
+          "value": 30
+        }
+      }
+    },
+    "sms": {
+      "args": [
+        "%s。兑换码%s。兑换截止日期:%s",
+        "腾讯视频"
+      ],
+      "tid": "04"
+    },
+    "saleDep": {
+      "040000": true
+    }
+  }
 }

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

@@ -118,6 +118,33 @@ type config struct {
 	BreakRenewTipTime string
 	TaskStartTime     int64
 	FinanceMail       string
+	EquityActive      struct {
+		Open    bool `json:"open"` // 活动开关
+		SiteMsg struct {
+			CallPlatform string `json:"callPlatform"`
+			MsgType      int    `json:"msgType"`
+			Title        string `json:"title"`
+			Content      string `json:"content"`
+			Link         string `json:"link"`
+			AndroidUrl   string `json:"androidUrl"`
+			IosUrl       string `json:"iosUrl"`
+			WeChatUrl    string `json:"weChatUrl"`
+		} `json:"siteMsg"` // 站内信内容配置
+		MailAlarm struct {
+			To        []string `json:"to"`
+			Title     string   `json:"title"`
+			ReTry     int      `json:"reTry"`
+			Threshold map[string]struct {
+				Name  string `json:"name"`
+				Value int    `json:"value"`
+			} `json:"threshold"` // 库存剩余阈值
+		} `json:"mailAlarm"` // 库存告警
+		Sms struct {
+			Args []string `json:"args"` // 短信部分可配置参数
+			Tid  string   `json:"tid"`  // 短信模板id
+		} `json:"sms"` // 短信配置
+		SaleDep map[string]bool // 代用户下单业绩归属部门配置 只有业绩归属为运营部才赠送
+	} `json:"equityActive"` // p459赠送视频权益活动配置
 }
 type mgoConf struct {
 	Address           string

+ 276 - 0
src/jfw/modules/subscribepay/src/entity/equityActive.go

@@ -0,0 +1,276 @@
+package entity
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/date"
+	"app.yhyue.com/moapp/jybase/redis"
+	"app.yhyue.com/moapp/jybase/sms"
+	"fmt"
+	"gopkg.in/mgo.v2/bson"
+	"jy/src/jfw/modules/subscribepay/src/config"
+	"jy/src/jfw/modules/subscribepay/src/util"
+	"log"
+	"regexp"
+	"strings"
+	"sync"
+)
+
+const (
+	TableEquityInfo       = "jyactivities.equity_info"   // 营销权益信息表
+	TableEquityActive     = "jyactivities.equity_active" // 营销权益活动表
+	TableOrder            = "jianyu.dataexport_order"    // 订单表
+	TablebasePosition     = "base_service.base_position" // 用户职位表
+	valueStateGifted      = 1                            // 已赠送状态值
+	valueMoldMonth        = 0                            // 月度
+	valueMoldYear         = 1                            // 年度
+	valueOrderTypeCreate  = 1                            // 超级订阅订单类型: 购买
+	valueOrderTypeRenew   = 2                            // 续费
+	valueOrderTypeUpgrade = 3                            // 升级
+	valueCycleUnitYear    = 1                            // 周期单位为年
+	valueAreaCountAll     = -1                           //  全国
+
+)
+
+var equityStockLock = sync.Mutex{} // 赠送视频权益码库存锁
+// EquityActive 赠送视频会员活动
+type EquityActive struct {
+	UserId           string // id 这边取到的id可能是职位id也可能是mongo库id
+	mgoId            string // mongo库id
+	positionId       string // 职位id
+	Phone            string // 手机号 用于发短信
+	OrderCode        string // 订单号
+	OrderType        int    // 1购买 2升级 3续费
+	CycleUnit        int    // 单位  1-年
+	CycleCount       int    // 数量
+	AreaCount        int    // -1 是全国
+	ProductType      string // 消息中的产品类型
+	OrderProductType string // 订单中的产品类型
+	SaleDep          string // 业绩归属部门  用于处理代用户下单的数据
+}
+
+// GiftVip 赠送腾讯视频会员
+func (e *EquityActive) GiftVip() {
+	//1. 判断活动是否开启
+	open, activeId, activeName := e.activityStart()
+	if !open || activeId <= 0 {
+		return
+	}
+	// 获取 缓存中的用户信息
+	e.setUserID()
+	if e.mgoId == "" {
+		log.Println("equityActive 未获取到有效的mgoId", e.OrderCode)
+		return
+	}
+	//2. 判断是否符合赠送条件
+	ok, mold := e.matchOrder()
+	if !ok {
+		return
+	}
+	equityStockLock.Lock()
+	defer func() {
+		equityStockLock.Unlock()
+	}()
+	//3. 判断库存
+	e.processEquityInfo(activeName, activeId, mold)
+}
+
+// txActivityStart 判断活动是否开启 开启则返回活动id
+func (e *EquityActive) activityStart() (open bool, id int, name string) {
+	now := date.NowFormat(date.Date_Full_Layout)
+	query := fmt.Sprintf("SELECT id,name FROM %s where state=0 and start_time<=? and end_time>=?;", TableEquityActive)
+	rs := util.Mysql.SelectBySql(query, now, now)
+	if rs != nil && len(*rs) > 0 {
+		open = true
+		id = common.IntAll((*rs)[0]["id"])
+		name = common.ObjToString((*rs)[0]["name"])
+		return
+	}
+	return
+}
+
+// 判断订单是否符合条件
+func (e *EquityActive) matchOrder() (ok bool, mold int) {
+	//(购买||续费)
+	if (e.OrderType == valueOrderTypeCreate || e.OrderType == valueOrderTypeRenew) && e.CycleCount > 0 {
+		// 判断购买是否为年度订单
+		if e.CycleUnit != valueCycleUnitYear {
+			return
+		}
+		// 为年度订单则判断是否为全国
+		if e.AreaCount == valueAreaCountAll {
+			ok = true
+			mold = valueMoldYear //全国赠送1年
+		} else {
+			ok = true
+			mold = valueMoldMonth //非全国赠送1月
+		}
+		//其他不赠送
+		return
+	} else if e.OrderType == valueOrderTypeUpgrade {
+		// 升级
+		// 判断是否是年度会员  不是年度会员则不赠送 是则赠送1月
+		if e.isYearVip() {
+			ok = true
+			mold = valueMoldMonth
+		}
+	}
+	return
+}
+
+// 处理库存
+func (e *EquityActive) processEquityInfo(activeName string, activeId, mold int) {
+	count := 0
+	tx, err := util.Mysql.DB.Begin()
+	if err != nil {
+		log.Println("equityActive db Begin:", err)
+		return
+	}
+	countQuery := fmt.Sprintf("SELECT count(*)  FROM %s where state= 0 and mold=? and active_id=? ;", TableEquityInfo)
+	rows, err := tx.Query(countQuery, mold, activeId)
+	if err != nil || rows == nil {
+		log.Println("获取剩余库存数量失败:", err, rows, e.OrderCode)
+		return
+	}
+	defer rows.Close()
+	for rows.Next() {
+		err = rows.Scan(&count)
+		if err != nil {
+			log.Println("遍历剩余库存数量失败:", err, rows)
+			return
+		}
+	}
+	if count <= 0 {
+		log.Println("库存剩余为0:", countQuery, mold, activeId)
+		return
+	}
+	query := fmt.Sprintf("SELECT id,name,code,date_format(ex_end_time,'%%Y-%%m-%%d') as ex_end_time  FROM %s where state= 0 and mold=? and active_id=? limit 1  for update;", TableEquityInfo)
+	data, err := tx.Query(query, mold, activeId)
+	if err != nil || data == nil {
+		tx.Rollback()
+		log.Println("获取视频权益码信息失败:", err, data, e.OrderCode)
+		return
+	}
+	eId, name, code, exEndTime := 0, "", "", ""
+	defer data.Close()
+	for data.Next() {
+		err = data.Scan(&eId, &name, &code, &exEndTime)
+	}
+	if err != nil {
+		log.Println("获取视频权益码失败:", err, data, e.OrderCode)
+		tx.Rollback()
+		return
+	}
+	threshold, b := config.Config.EquityActive.MailAlarm.Threshold[fmt.Sprintf("%v", mold)]
+	if count < 1 || eId <= 0 {
+		tx.Rollback()
+		// 没有库存
+		if b {
+			go e.sendAlarmMail(activeName, activeId, threshold.Name, mold, 0)
+		}
+		return
+	}
+	if b && int(count)-1 <= threshold.Value {
+		// 发库存告警时这减去1是因为这一次消耗一个
+		go e.sendAlarmMail(activeName, activeId, threshold.Name, mold, int(count)-1)
+	}
+	update := fmt.Sprintf("update %s set order_code=?,state=?,update_time=? where id=? ", TableEquityInfo)
+	_, err = tx.Exec(update, e.OrderCode, valueStateGifted, date.NowFormat(date.Date_Full_Layout), eId)
+	if err != nil {
+		tx.Rollback()
+		log.Println("更新视频权益码失败", e.OrderCode, eId, err)
+		return
+	}
+	err = tx.Commit()
+	if err != nil {
+		log.Println("视频权益码commit失败", e.OrderCode, eId, err)
+		return
+	}
+	//6. 发送短信、站内信
+	go e.sendVipMsg(name, code, exEndTime)
+	return
+}
+
+// 根据订单号获取缓存里面的用户id等信息
+func (e *EquityActive) setUserID() {
+	orderKey := fmt.Sprintf("order_%s", e.OrderCode)
+	rs := redis.Get("other", orderKey)
+	info := common.ObjToMap(rs)
+	phone := ""
+	if info != nil && len(*info) > 0 {
+		log.Println("equityActive 未获取到redis保存的用户身份信息:", orderKey, info)
+		e.mgoId = common.ObjToString((*info)["mgoId"])
+		e.positionId = fmt.Sprintf("%v", common.IntAll((*info)["positionId"]))
+		phone = common.ObjToString((*info)["phone"])
+	}
+	if phone != "" {
+		e.Phone = phone
+	}
+	// 如果没有redis取到说明是代用户下单的订单
+	// 代用户下单的现在只有个人版的 所以可以直接从订单里面取用户mgoId
+	// 但是需要再判断业绩归属部门
+	if e.mgoId == "" && bson.IsObjectIdHex(e.UserId) && e.SaleDep != "" {
+		if _, ok := config.Config.EquityActive.SaleDep[e.SaleDep]; ok {
+			e.mgoId = e.UserId
+		}
+	}
+	return
+}
+
+// 发送消息
+func (e *EquityActive) sendVipMsg(eName, code, ex_end_time string) {
+	// 发送短信
+	//  04 短信模板:用户{1}您好,购买{2}产品赠送您{3},请前往{4}进行兑换解锁福利。
+	// 手机号处理
+	if e.Phone != "" {
+		phone := e.Phone
+		var PhoneReg = regexp.MustCompile(`^(100\d{8}|1[3-9]\d{9})$`)
+		if PhoneReg.MatchString(e.Phone) {
+			phone = string(phone[0:3]) + "****" + string(phone[(len(phone)-4):])
+		}
+		smsconfig := config.Config.EquityActive.Sms
+		args3, args4 := "", ""
+		if len(smsconfig.Args) == 2 {
+			args3 = fmt.Sprintf(smsconfig.Args[0], eName, code, ex_end_time)
+			args4 = smsconfig.Args[1]
+		} else {
+			log.Println("equityActive 视频会员活动短信模板内容参数配置异常,请检查配置文件。")
+			return
+		}
+		params := []string{phone, e.ProductType, args3, args4}
+		sms.SendSms(config.Config.SmsServiceRpc, smsconfig.Tid, e.Phone, params...)
+	} else {
+		log.Println("equityActive 未获取到用户手机号,不再发送短信:", e.OrderCode, e.UserId, e.Phone)
+	}
+	siteMsg := config.Config.EquityActive.SiteMsg
+	// 发送站内信
+	p := util.MessageParam{
+		UserIds:     e.mgoId,
+		PositionIds: e.positionId,
+		Title:       fmt.Sprintf(siteMsg.Title, eName),
+		Content:     fmt.Sprintf(siteMsg.Content, e.ProductType, eName, code, ex_end_time, e.ProductType, eName, code),
+		MsgType:     siteMsg.MsgType,
+		SendMode:    2,
+	}
+	util.EquityActiveSend.SendStationMessages(p)
+
+}
+
+// 库存告警
+func (e *EquityActive) sendAlarmMail(activeName string, activeId int, name string, mold, count int) {
+	ma := config.Config.EquityActive.MailAlarm
+	if len(ma.To) == 0 {
+		log.Println("未配置视频会员权益码活动库存告警邮箱")
+		return
+	}
+	to := strings.Join(ma.To, ",")
+	content := fmt.Sprintf("活动:%s(活动id:%d),%s权益(mold:%d)当前库存:%d", activeName, activeId, name, mold, count)
+	util.SendRetryMailMany(ma.ReTry, to, ma.Title, content, "", "", config.GmailAuth)
+}
+
+// 判断是否年度会员
+func (e *EquityActive) isYearVip() bool {
+	query := fmt.Sprintf("select count(*) from %s where user_id=? and order_status=1 and product_type =? and (timestampdiff(day,vip_starttime,vip_endtime)>=365) order by create_time desc limit 1", TableOrder)
+	count := util.Mysql.CountBySql(query, e.UserId, e.OrderProductType)
+	log.Println("isYearVip 判断是否为年度订单:", query, e.UserId, count)
+	return count > 0
+}

+ 66 - 48
src/jfw/modules/subscribepay/src/entity/subscribeVip.go

@@ -113,7 +113,7 @@ type SubvipBuySet struct {
 // 支付完成回调
 func (this *vipSubscribeStruct) PayCallBack(param *CallBackParam) bool {
 	now := time.Now()
-	orderdata := util.Mysql.FindOne("dataexport_order", param.GetPaySuccessOrderQuery(), "user_phone,ent_id,id,filter,order_money,order_code,order_status,user_id,vip_starttime,vip_endtime,vip_type,prepay_time,dis_word,user_id,create_time,d_relation_id,order_channel", "")
+	orderdata := util.Mysql.FindOne("dataexport_order", param.GetPaySuccessOrderQuery(), "saleDep,user_phone,ent_id,id,filter,order_money,order_code,order_status,user_id,vip_starttime,vip_endtime,vip_type,prepay_time,dis_word,user_id,create_time,d_relation_id,order_channel", "")
 	pay_time := FormatDate(&now, Date_Full_Layout)
 	if orderdata == nil {
 		log.Println("未找到订单")
@@ -130,6 +130,8 @@ func (this *vipSubscribeStruct) PayCallBack(param *CallBackParam) bool {
 		return false //
 	}
 	userId := qutil.ObjToString((*orderdata)["user_id"])
+	phone := qutil.ObjToString((*orderdata)["user_phone"])
+	saleDep := qutil.ObjToString((*orderdata)["saleDep"])
 	//优惠码
 	orderCode := qutil.ObjToString((*orderdata)["order_code"])
 	dis_word := qutil.ObjToString((*orderdata)["dis_word"])
@@ -269,6 +271,21 @@ func (this *vipSubscribeStruct) PayCallBack(param *CallBackParam) bool {
 				}
 			}(userId, userLotteryId, orderCode)
 		}
+		//  p459赠送
+		if config.Config.EquityActive.Open {
+			equityActive := EquityActive{UserId: userId,
+				Phone:            phone,
+				OrderCode:        orderCode,
+				OrderType:        vmsg.OrderType,
+				CycleUnit:        vmsg.Cycleunit,
+				ProductType:      "超级订阅",
+				OrderProductType: "VIP订阅",
+				CycleCount:       vmsg.Cyclecount,
+				AreaCount:        vmsg.NewBuyset.AreaCount,
+				SaleDep:          saleDep,
+			}
+			equityActive.GiftVip()
+		}
 	}
 	return flag
 }
@@ -474,59 +491,60 @@ func (this *vipSubscribeStruct) UpgradeSubVip(userId string, vmsg VipSimpleMsg,
 }
 
 // 超级订阅获取购买项
-//func (this *vipSubscribeStruct) NewBuySet(area *map[string]interface{}, industry []string, isUpgrade bool) *SubvipBuySet {
-//	pCount := -1
-//	citys := []int{}
-//	if area != nil {
-//		if (*area)["全国"] != nil {
-//			area = &map[string]interface{}{}
-//		} else if pCount_tmp := qutil.IntAll((*area)["areacount"]); pCount_tmp > 0 {
-//			pCount = pCount_tmp
+//
+//	func (this *vipSubscribeStruct) NewBuySet(area *map[string]interface{}, industry []string, isUpgrade bool) *SubvipBuySet {
+//		pCount := -1
+//		citys := []int{}
+//		if area != nil {
+//			if (*area)["全国"] != nil {
+//				area = &map[string]interface{}{}
+//			} else if pCount_tmp := qutil.IntAll((*area)["areacount"]); pCount_tmp > 0 {
+//				pCount = pCount_tmp
+//			}
 //		}
-//	}
-//	buyset := SubvipBuySet{}
-//	if !isUpgrade {
-//		buyset.Upgrade = 0 //升级版超级订阅标识
-//		if len(*area) > 0 {
-//			pCount = 0
-//			for _, v := range *area {
-//				tmp := v.([]interface{})
-//				if len(tmp) == 0 || len(tmp) > SubVipPrice.Old.CityMaxCount { //省份
-//					pCount++
-//				} else { //城市
-//					citys = append(citys, len(tmp))
+//		buyset := SubvipBuySet{}
+//		if !isUpgrade {
+//			buyset.Upgrade = 0 //升级版超级订阅标识
+//			if len(*area) > 0 {
+//				pCount = 0
+//				for _, v := range *area {
+//					tmp := v.([]interface{})
+//					if len(tmp) == 0 || len(tmp) > SubVipPrice.Old.CityMaxCount { //省份
+//						pCount++
+//					} else { //城市
+//						citys = append(citys, len(tmp))
+//					}
+//				}
+//				//省份数量自动转换全国
+//				if pCount > SubVipPrice.Old.ProvinceMaxCount {
+//					pCount = -1
+//					citys = []int{}
 //				}
 //			}
-//			//省份数量自动转换全国
-//			if pCount > SubVipPrice.Old.ProvinceMaxCount {
-//				pCount = -1
-//				citys = []int{}
-//			}
-//		}
-//		buyset.NewCitys = citys
-//		buyset.AreaCount = pCount //地区
-//		//行业数量自动转换全行业
-//		buyset.BuyerclassCount = len(industry)
-//		if len(industry) > SubVipPrice.Old.BuyerClassMaxCount || len(industry) == 0 {
-//			buyset.BuyerclassCount = -1
-//		}
-//	} else {
-//		buyset.Upgrade = 1 //升级版超级订阅标识
-//		if len(*area) > 0 {
-//			pCount = len(*area)
-//			//省份数量自动转换全国
-//			if pCount > SubVipPrice.New.ProvinceMaxCount {
-//				pCount = -1
+//			buyset.NewCitys = citys
+//			buyset.AreaCount = pCount //地区
+//			//行业数量自动转换全行业
+//			buyset.BuyerclassCount = len(industry)
+//			if len(industry) > SubVipPrice.Old.BuyerClassMaxCount || len(industry) == 0 {
+//				buyset.BuyerclassCount = -1
 //			}
 //		} else {
-//			buyset.AreaCount = -1 //全国
+//			buyset.Upgrade = 1 //升级版超级订阅标识
+//			if len(*area) > 0 {
+//				pCount = len(*area)
+//				//省份数量自动转换全国
+//				if pCount > SubVipPrice.New.ProvinceMaxCount {
+//					pCount = -1
+//				}
+//			} else {
+//				buyset.AreaCount = -1 //全国
+//			}
+//			buyset.AreaCount = pCount   //地区
+//			buyset.NewCitys = citys     //城市,4.4改版不支持购买城市
+//			buyset.BuyerclassCount = -1 //行业,4.4改版只能购买全行业
 //		}
-//		buyset.AreaCount = pCount   //地区
-//		buyset.NewCitys = citys     //城市,4.4改版不支持购买城市
-//		buyset.BuyerclassCount = -1 //行业,4.4改版只能购买全行业
+//		return &buyset
 //	}
-//	return &buyset
-//}
 func (this *vipSubscribeStruct) NewBuySet(area *map[string]interface{}, areaCount int, industry []string, isUpgrade bool) *SubvipBuySet {
 	pCount := -1
 	citys := []int{}
@@ -1104,7 +1122,7 @@ func (this *vipSubscribeStruct) GetNewUpgradeDetail(userId string, newBuySet, ol
 	return totalPrice, subtotals
 }
 
-//获取新版超级订阅升级价格、清单
+// 获取新版超级订阅升级价格、清单
 func getNewUpgradeDetail(userId string, newBuySet, oldBuySet *SubvipBuySet, oldEndtime int64, count, unit int) (totalPrice int, subtotals []map[string]interface{}) {
 	rResult, ok := util.MQFW.Find("vip_upgrade", &bson.M{"s_userid": userId, "i_isvalid": 0}, `{"l_validtime":1}`, `{"o_buyset":1,"l_validtime":1}`, false, -1, -1)
 	if !ok {

+ 16 - 3
src/jfw/modules/subscribepay/src/service/commonAction.go

@@ -26,7 +26,7 @@ import (
 	"github.com/SKatiyar/qr"
 )
 
-//付费公用方法
+// 付费公用方法
 type CommonAction struct {
 	*xweb.Action
 	getwxSdkSign         xweb.Mapper `xweb:"/wx/getwxSdkSign"`             //微信js参数
@@ -105,7 +105,7 @@ func (this *CommonAction) SendMailNote(mailType string) {
 	this.ServeJson(NewResult(rData, errMsg))
 }
 
-//----------------------------申请发票------------------------------------
+// ----------------------------申请发票------------------------------------
 func (d *CommonAction) ApplyInvoice() error {
 	var applyBill_status int
 	var order_code, applyBill_company, applyBill_taxnum, applyBill_type string
@@ -174,7 +174,8 @@ func (d *CommonAction) ApplyInvoice() error {
 	return nil
 }
 
-/**
+/*
+*
 
 根据 id+openid 删除
 */
@@ -493,6 +494,9 @@ func (this *CommonAction) SaveTransferAccounts() {
 func (this *CommonAction) Createorder() {
 	sessVal := this.Session().GetMultiple()
 	userid, _ := sessVal["userId"].(string)
+	phone := qutil.ObjToString(sessVal["phone"])
+	positionId := qutil.IntAll(sessVal["positionId"])
+	mgoId := qutil.ObjToString(sessVal["mgoUserId"])
 	rData, errMsg := func() (interface{}, error) {
 		//参数接收
 		infoMap := map[string]interface{}{}
@@ -616,6 +620,15 @@ func (this *CommonAction) Createorder() {
 		if orderid <= 0 {
 			return nil, fmt.Errorf("创建订单异常")
 		}
+		if product == "VIP订阅" {
+			orderKey := fmt.Sprintf("order_%s", inserMap.OrderCode)
+			uInfo := map[string]interface{}{
+				"mgoId":      mgoId,
+				"positionId": positionId,
+				"phone":      phone,
+			}
+			redis.Put("other", orderKey, uInfo, 60*60*24*3)
+		}
 		if activityType >= 2 {
 			util.FindUserLotteryId(userid, orderid, i_discountId)
 		}

+ 78 - 0
src/jfw/modules/subscribepay/src/util/send.go

@@ -0,0 +1,78 @@
+package util
+
+import (
+	"app.yhyue.com/moapp/jybase/date"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"jy/src/jfw/modules/subscribepay/src/config"
+	"log"
+	"net/http"
+	"net/url"
+)
+
+type StationMessage struct {
+	Action       string
+	Addr         string
+	CallPlatform string
+}
+type MessageParam struct {
+	UserIds     string // 用户mongo库id   用户userId用英文逗号拼接
+	SendTime    string // 发送时间 暂时无用 (2022-03-31 09:08:08  仅发送模式为定时时有效)
+	Title       string // 通知消息	消息标题
+	Content     string // 消息内容
+	Link        string // pc消息链接
+	AndroidUrl  string // 安卓消息链接
+	IosUrl      string // IOS消息链接
+	WeChatUrl   string // 微信消息链接
+	SendMode    int    // 发送模式  1- 定时 2-实时 (所调接口未支持定时)
+	PositionIds string // 职位id 与userIds 对应
+	MsgType     int    // message_class 里的消息分类
+}
+
+var EquityActiveSend *StationMessage
+
+func init() {
+	wp := config.Config.WebSiteParameter
+	callPlatform := config.Config.EquityActive.SiteMsg.CallPlatform
+	EquityActiveSend = NewStationMessage(wp.Addr, wp.Action, callPlatform)
+
+}
+func NewStationMessage(addr string, action string, callPlatform string) *StationMessage {
+	return &StationMessage{
+		Addr:         addr,
+		Action:       action,
+		CallPlatform: callPlatform,
+	}
+}
+
+func (s *StationMessage) SendStationMessages(p MessageParam) {
+	var (
+		ret  MessageRet
+		cont []byte
+	)
+	parms := fmt.Sprintf("_action=%s&userIds=%s&msgType=%v&title=%s&content=%s&link=%s&sendMode=2&sendTime=%s&androidUrl=%s&iosUrl=%s&weChatUrl=%s&_token=12311&reqSource=1&callPlatform=%s&positionIds=%s&menuname=message",
+		s.Action, p.UserIds, p.MsgType, p.Title, p.Content, p.Link, date.NowFormat(date.Date_Short_Layout), p.AndroidUrl, p.IosUrl, p.WeChatUrl, s.CallPlatform, p.PositionIds)
+	paramsEncode := url.PathEscape(parms)
+	url2 := fmt.Sprintf("%s?%s", s.Addr, paramsEncode)
+	resp, err := http.Get(url2)
+	if err != nil {
+		log.Println("发送消息失败:", err)
+		return
+	}
+	defer resp.Body.Close()
+	cont, err = ioutil.ReadAll(resp.Body)
+	if err != nil {
+		log.Println("发送消息错误信息:", string(cont), err)
+		return
+	}
+	err = json.Unmarshal(cont, &ret)
+	if err != nil {
+		log.Println("发送消息反序列化错误信息:", err)
+		return
+	}
+	if ret.Data.Status != 1 {
+		log.Println("发送消息失败:Status != 1", ret)
+	}
+
+}

+ 23 - 5
src/jfw/modules/subscribepay/src/util/sendMail.go

@@ -3,10 +3,10 @@ package util
 //发送邮件
 
 import (
-	"jy/src/jfw/modules/subscribepay/src/config"
+	"app.yhyue.com/moapp/jybase/mail"
 	"fmt"
+	"jy/src/jfw/modules/subscribepay/src/config"
 	"log"
-	"app.yhyue.com/moapp/jybase/mail"
 	"regexp"
 	"time"
 )
@@ -28,7 +28,7 @@ func SendRetryMail(retry int, userMail, subject, content, fName string, bt []byt
 	return false
 }
 
-//发送异常提醒
+// 发送异常提醒
 func SendErrNoteToMail(errContent string) bool {
 	sendSuccess := true
 	for _, audit := range config.ExConf.ErrNote_emails {
@@ -42,7 +42,7 @@ func SendErrNoteToMail(errContent string) bool {
 	return sendSuccess
 }
 
-//发送邮箱验证码
+// 发送邮箱验证码
 func SendMailIdentCode(to, code string, auth []*mail.GmailAuth) bool {
 	html := fmt.Sprintf(`<div>
             <div>
@@ -59,7 +59,7 @@ func SendMailIdentCode(to, code string, auth []*mail.GmailAuth) bool {
             <div>
                   <p>此致</p>
                   <p>剑鱼标讯</p>
-            </div>      
+            </div>
       </div>`, to, code)
 
 	for k, v := range auth {
@@ -77,3 +77,21 @@ func SendMailIdentCode(to, code string, auth []*mail.GmailAuth) bool {
 
 	return false
 }
+
+// SendRetryMailMany 发送邮件  收件人多个使用英文逗号分割
+func SendRetryMailMany(retry int, user_mail, subject, content, fname string, rename string, auth []*mail.GmailAuth) bool {
+	for i := 1; i <= retry; i++ {
+		for _, v := range auth { //使用多个邮箱尝试发送
+			if mail.GSendMail_q("剑鱼标讯", user_mail, "", "", subject, content, fname, rename, v) {
+				return true
+			}
+			t := time.Duration(i) * 30 * time.Second
+			log.Println(user_mail, fmt.Sprintf("第%d轮,使用%s发送邮件失败!%v后重试", i, v.User, t))
+			time.Sleep(t)
+		}
+		if i == retry {
+			log.Println(user_mail, fmt.Sprintf("发送邮件失败"))
+		}
+	}
+	return false
+}

+ 2 - 2
src/web/staticres/common-module/file-pack/js/index.js

@@ -184,7 +184,7 @@ var vm = new Vue({
           $('#clone-image').remove()
           try {
             if (typeof window.__compatibleAppFn === 'function') {
-              window.__compatibleAppFn(JyObj.savePic, _this.picImgUrl, '剑鱼标讯需要您的存储权限、电话权限,将用于帮助您下载、保存图片到本地,将内容成功分享到社交平台。')
+              window.__compatibleAppFn(JyObj.savePic, _this.picImgUrl, '剑鱼标讯需要您的存储权限,将用于下载、保存二维码图片到相册,以便您能及时联系客服,处理附件下载时遇到的问题。')
             }
             _this.$toast('图片已经保存~')
             loading.clear()
@@ -203,7 +203,7 @@ var vm = new Vue({
       }else {
         try {
           if (typeof window.__compatibleAppFn === 'function') {
-            window.__compatibleAppFn(JyObj.savePic, _this.picImgUrl, '剑鱼标讯需要您的存储权限、电话权限,将用于帮助您下载、保存图片到本地,将内容成功分享到社交平台。')
+            window.__compatibleAppFn(JyObj.savePic, _this.picImgUrl, '剑鱼标讯需要您的存储权限,将用于下载、保存二维码图片到相册,以便您能及时联系客服,处理附件下载时遇到的问题。')
           }
           loading.clear()
           _this.$toast('图片已经保存,快去分享吧~')

BIN
src/web/staticres/images/wx/wx-cg-detail.png


BIN
src/web/staticres/images/wx/wx-nj-detail.png


+ 6 - 6
src/web/templates/pc/template/index/activity-dialog.html

@@ -32,12 +32,6 @@
     if (ADList.length>0){
       for (var i=0;i<ADList.length;i++ ){
         var AD=ADList[i]
-        if(AD.s_link){
-          adv_url = AD.s_link
-        }
-        if(AD.s_pic){
-          adv_img = AD.s_pic
-        }
         if (AD.o_extend != undefined) {
           var nowTime = new Date().getTime();
           if (AD.o_extend.startTime!=undefined){
@@ -74,6 +68,12 @@
             adv_background_opacity = AD.o_extend.opacity;
           }
         }
+        if(AD.s_link){
+          adv_url = AD.s_link
+        }
+        if(AD.s_pic){
+          adv_img = AD.s_pic
+        }
         if (adv_img!=""){
           $(".tc_button").remove();
           let isSupportFull = false

+ 47 - 19
src/web/templates/weixin/wxinfocontent_rec.html

@@ -719,7 +719,7 @@ em {
     font-weight: 500;
     color: #161826;
     line-height: 0.4rem;
-    margin-bottom: 0.48rem;
+    margin-bottom: 0.24rem;
     align-items: center;
     text-align: center;
 }
@@ -1270,20 +1270,24 @@ body .loading_ p span {
 			</ul>
 
 		</div>
-		<div class="mask-zz dialog-tip-group default-dialog hidden">
-			<div class="mask-zz">
-				<div style="position: relative">
-					<img class="dialog-top-img" src='/images/wx/pc_zzt.png?v={{Msg "seo" "version"}}'>
-					<div  id="dialog-tip-title" style="position: absolute;top: 50%;left: 50%; transform: translateX(-50%);height: 26px;color: antiquewhite;font-size: 16px;white-space: nowrap;">超前项目抢先知,中标更容易</div>
-				</div>
-				<div style="display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0.48rem 0.32rem;">
-					<div class="dialog-tip-text">
-						提前3-12个月获取审批中的新项目,超前项目抢先介入,商机提前掌控。
-					</div>
-					<button class="free-btn-reword" style="background-color:  #2CB7CA;font-size: 0.32rem;color: white;border:none;width: 100%;height:0.72rem;border-radius: 0.12rem;">点击进入</button>
-				</div>
-			</div>
-		</div>
+      <div class="mask-zz dialog-tip-group default-dialog hidden" id="cg-nj-dialog">
+        <div class="mask-zz">
+            <div style="position: relative; padding-bottom: .4rem; background: url('/big-member/image/openVip.png') no-repeat;min-height: 7.4rem;background-size: contain;">
+                <div class="tip-box-example">
+                  <div id="dialog-tip-title" style="height: 26px;color: antiquewhite;font-size: 16px;white-space: nowrap;text-align: center; padding: .48rem 0 .32rem;">${info.headtext}</div>
+                  <div class="dialog-tip-img" style="position: relative;">
+                    <div style="position: absolute;right: .32rem; top: .32rem;padding: .02rem .16rem;background: #E5FCFF;color: #2ABED1;font-size: .26rem;">示例</div>
+                    <img :src="'{{Msg "seo" "cdn"}}/jyapp/images/wx/' + info.img +'.png?v={{Msg "seo" "version"}}'" alt="">
+                  </div>
+                </div>
+                <div style="display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0 0.32rem;background: #fff;">
+                    <div class="dialog-tip-text" v-html="info.text">
+                    </div>
+                    <button class="free-btn-reword" style="background-color:  #2CB7CA;font-size: 0.32rem;color: white;border:none;width: 100%;height:0.72rem;border-radius: 0.12rem;">${info.btntext}</button>
+                </div>
+            </div>
+        </div>
+      </div>
         <div class="mask-zz dialog-tip-group compare-dialog hidden">
             <div class="mask-zz">
                 <div class="compare-dialog-head">
@@ -1982,8 +1986,8 @@ function checkShowDialog () {
 	if (advanceProject) {
 		// 超前项目
 		if (subtype == '采购意向') {
-			$('#dialog-tip-title').text('项目提前介入,中标更轻松')
-			$(".dialog-tip-text").html('提前1-3个月获取项目信息,及早介入准备更充分')
+			// $('#dialog-tip-title').text('项目提前介入,中标更轻松')
+			// $(".dialog-tip-text").html('提前1-3个月获取项目信息,及早介入准备更充分')
 		}
         if(!canRead) {
           $('.default-dialog').removeClass("hidden")
@@ -2025,7 +2029,7 @@ function showTopAd () {
 }
 
 //留资弹窗页面
-$('.free-btn-reword').on('click', function() {
+$(document).on('click', '.free-btn-reword', function() {
 	var subType = {{.T.obj.subtype}}
 	var sourceKey = 'article_slogan'
   if(!canRead) {
@@ -2293,6 +2297,31 @@ function openFileDown (url) {
 //         }
 //       })
 //     }
+// 采购意向、拟建遮罩弹窗
+    var cgnjDialog = new Vue({
+      delimiters: ['${', '}'],
+      el: '#cg-nj-dialog',
+      data: {
+        info: {}
+      },
+      mounted: function () {
+        if(subtype === '拟建') {
+          this.info = {
+            text: '提前3-12个月获取审批中的新项目,超前项目抢先介入,商机提前掌控。',
+            img: 'app-nj-detail',
+            headtext: '超前项目抢先知,中标更容易',
+            btntext: '点击进入'
+          }
+        } else if(subtype === '采购意向') {
+          this.info = {
+            text: '提前1-3个月获取项目信息,<br/>及早介入准备更充分',
+            img: 'app-cg-detail',
+            headtext: '项目提前介入,中标更轻松',
+            btntext: '点击进入'
+          }
+        }
+      }
+    })
     // 参标展示更新投标状态弹窗
     var showUpdateBid = new Vue({
       el: '.refer_stand',
@@ -2702,7 +2731,6 @@ function downloadFileAjax (fileName, callback) {
             window.location.href="/jy_mobile/common/order/create/svip?type=buy"
           }).catch(() => {})
         }
-        return
       }else if (r && r.m === '' && r.r) {
         var url = r.r.downUrl
         if (url){