Browse Source

Merge remote-tracking branch 'origin/debug'

Roc 2 years ago
parent
commit
13438f5350

+ 60 - 0
controllers/quanshi.go

@@ -1,8 +1,13 @@
 package controllers
 
 import (
+	"encoding/json"
 	"fmt"
+	quanshiReq "hongze/hongze_open_api/models/request/quanshi"
+	"hongze/hongze_open_api/services/quanshi"
+	"hongze/hongze_open_api/services/yb"
 	"hongze/hongze_open_api/utils"
+	"strconv"
 )
 
 // QuanShiControllerCommon 报告模块
@@ -15,7 +20,62 @@ type QuanShiControllerCommon struct {
 // @Description 全时回调接口
 // @router /callback [post]
 func (c *QuanShiControllerCommon) CallBack() {
+	//回调中url参数要做签名(get请求中的参数,按照自己的方式签名,避免链接被别人拿去随意请求)
 	utils.FileLog.Info(fmt.Sprintf("全时回调参数:%s", string(c.Ctx.Input.RequestBody)))
 	//c.OkDetailed("ok", "获取成功")
+
+	activityId, _ := c.GetInt("activity_id")
+	timeInt, _ := c.GetInt("time")
+	paramStr := fmt.Sprintf(`activity_id=%d&time=%d`, activityId, timeInt)
+	signStr := quanshi.GetSign(paramStr)
+	ownSign := c.GetString("sign")
+	if ownSign != signStr {
+		c.FailWithMessage("请求异常")
+		return
+	}
+
+	var req1 quanshiReq.QsCallBackReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req1)
+	if err != nil {
+		c.FailWithMessage("参数解析异常")
+		return
+	}
+	switch req1.Method {
+	case "report":
+		//报告
+		var req quanshiReq.QsCallBackReportReq
+		err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+		if err != nil {
+			c.FailWithMessage("参数解析异常")
+			return
+		}
+		eventId, err := strconv.Atoi(req.Report.EventID)
+		if err != nil {
+			c.FailWithMessage("会议id异常:" + req.Report.EventID)
+			return
+		}
+		err = yb.SyncUser(eventId)
+	case "record":
+		//录制
+		var req quanshiReq.QsCallBackRecordReq
+		err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+		if err != nil {
+			c.FailWithMessage("参数解析异常")
+			return
+		}
+		eventId, err := strconv.Atoi(req.Record.EventID)
+		if err != nil {
+			c.FailWithMessage("会议id异常:" + req.Record.EventID)
+			return
+		}
+		err = yb.SyncVideo(eventId, req.Record.VideoURL)
+	default:
+		c.OkWithMessage("ok")
+		return
+	}
+	if err != nil {
+		c.FailWithMessage("同步数据失败")
+		return
+	}
 	c.Ok()
 }

+ 1 - 3
main.go

@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"github.com/beego/beego/v2/adapter/logs"
 	"github.com/beego/beego/v2/server/web/context"
-	"hongze/hongze_open_api/models"
+	_ "hongze/hongze_open_api/models"
 	_ "hongze/hongze_open_api/routers"
 	"hongze/hongze_open_api/services/alarm_msg"
 	"hongze/hongze_open_api/utils"
@@ -21,8 +21,6 @@ func main() {
 	}
 
 	web.BConfig.RecoverFunc = Recover
-	//数据库初始化
-	models.InitDb()
 	web.Run()
 }
 

+ 1 - 1
models/custom/contract/contract_service.go

@@ -1,7 +1,7 @@
 package contract
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"hongze/hongze_open_api/models/tables/contract_service_detail"
 	"time"
 )

+ 1 - 1
models/custom/wechat.go

@@ -1,6 +1,6 @@
 package custom
 
-import "github.com/rdlucklib/rdluck_tools/orm"
+import "github.com/beego/beego/v2/client/orm"
 
 type WechatSign struct {
 	AppId     string

+ 29 - 4
models/db_init.go

@@ -1,13 +1,17 @@
 package models
 
 import (
+	"github.com/beego/beego/v2/client/orm"
 	_ "github.com/go-sql-driver/mysql"
-	"github.com/rdlucklib/rdluck_tools/orm"
 	"hongze/hongze_open_api/models/tables/admin"
 	"hongze/hongze_open_api/models/tables/article"
 	"hongze/hongze_open_api/models/tables/company"
+	"hongze/hongze_open_api/models/tables/company_product"
 	"hongze/hongze_open_api/models/tables/open_api_user"
+	"hongze/hongze_open_api/models/tables/qs_event"
+	"hongze/hongze_open_api/models/tables/qs_event_user"
 	"hongze/hongze_open_api/models/tables/wx_user"
+	"hongze/hongze_open_api/models/tables/yb_activity"
 	"hongze/hongze_open_api/utils"
 	"time"
 )
@@ -31,12 +35,33 @@ func init() {
 	//注册对象
 	orm.RegisterModel(
 		new(open_api_user.OpenApiUser),    //开放API用户表
-		new(company.Company),              //company客户表
-		new(wx_user.WxUser),               //微信用户表
 		new(admin.Admin),                  //系统用户表
 		new(article.CygxArticleCeluePush), //策略平台推送过来更新的文章
 	)
+	orm.Debug = true
+	orm.DebugLog = orm.NewLog(utils.Binlog)
 
+	// 注册研报相关的表
+	initYb()
+
+	// 注册客户相关的表
+	initCompany()
+}
+
+// initYb 研报活动相关
+func initYb() {
+	orm.RegisterModel(
+		new(yb_activity.Activity),      //研报活动
+		new(qs_event.QsEvent),          //全时与ficc研报活动的关系表
+		new(qs_event_user.QsEventUser), //全时参会信息
+	)
 }
 
-func InitDb() {}
+// initCompany 注册客户相关的
+func initCompany() {
+	orm.RegisterModel(
+		new(company.Company),                //company客户表
+		new(company_product.CompanyProduct), //company_product客户产品表
+		new(wx_user.WxUser),                 //微信用户表
+	)
+}

+ 65 - 0
models/request/quanshi/quanshi.go

@@ -0,0 +1,65 @@
+package quanshi
+
+// QsCallBackReq 全时请求
+type QsCallBackReq struct {
+	CustomerCode string `json:"customerCode"`
+	Method       string `json:"method"`
+	MsgID        string `json:"msgId"`
+	SiteID       int64  `json:"siteId"`
+	Timestamp    int64  `json:"timestamp"`
+}
+
+// QsCallBackMeetingReq 全时会议通知请求
+type QsCallBackMeetingReq struct {
+	CustomerCode string `json:"customerCode"`
+	Meetinginfo  struct {
+		AttendeeJoinURL string `json:"attendeeJoinUrl"`
+		BillingCode     string `json:"billingCode"`
+		ConfID          string `json:"confId"`
+		EventID         string `json:"eventId"`
+		HostID          string `json:"hostId"`
+		HostJoinURL     string `json:"hostJoinUrl"`
+	} `json:"meetinginfo"`
+	Method    string `json:"method"`
+	MsgID     string `json:"msgId"`
+	SiteID    int64  `json:"siteId"`
+	Timestamp int64  `json:"timestamp"`
+}
+
+// QsCallBackReportReq 全时会议报告通知请求
+type QsCallBackReportReq struct {
+	CustomerCode string `json:"customerCode"`
+	Report       struct {
+		AttendeeJoinURL string `json:"attendeeJoinUrl"`
+		ConfID          string `json:"confId"`
+		DownloadURL     string `json:"downloadUrl"`
+		EventID         string `json:"eventId"`
+		HostID          string `json:"hostId"`
+		HostJoinURL     string `json:"hostJoinUrl"`
+		ReportName      string `json:"reportName"`
+	} `json:"report"`
+	Method    string `json:"method"`
+	MsgID     string `json:"msgId"`
+	SiteID    int64  `json:"siteId"`
+	Timestamp int64  `json:"timestamp"`
+}
+
+// QsCallBackRecordReq 全时会议录制信息通知请求
+type QsCallBackRecordReq struct {
+	CustomerCode string `json:"customerCode"`
+	Record       struct {
+		AttendeeJoinURL string `json:"attendeeJoinUrl"`
+		ConfID          string `json:"confId"`
+		EventID         string `json:"eventId"`
+		HostJoinURL     string `json:"hostJoinUrl"`
+		OperatorID      string `json:"operatorId"`
+		Thumbnail       string `json:"thumbnail"`
+		VideoLength     int64  `json:"videoLength"`
+		VideoSize       int64  `json:"videoSize"`
+		VideoURL        string `json:"videoURL"`
+	} `json:"record"`
+	Method    string `json:"method"`
+	MsgID     string `json:"msgId"`
+	SiteID    int64  `json:"siteId"`
+	Timestamp int64  `json:"timestamp"`
+}

+ 1 - 1
models/tables/admin/admin.go

@@ -1,7 +1,7 @@
 package admin
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
 

+ 1 - 1
models/tables/article/cygx_article_celue_push.go

@@ -1,7 +1,7 @@
 package article
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
 

+ 9 - 1
models/tables/company/company.go

@@ -1,7 +1,7 @@
 package company
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
 
@@ -41,6 +41,14 @@ type CompanyList struct {
 	Status      string `description:"客户状态" json:"status"`
 }
 
+// GetCompanyById 根据企业id获取企业信息
+func GetCompanyById(companyId int) (items *Company, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM company where company_id= ? `
+	err = o.Raw(sql, companyId).QueryRow(&items)
+	return
+}
+
 // GetList 获取客户列表
 func GetList(condition string, pars []interface{}, startSize, pageSize int) (total int, list []*CompanyList, err error) {
 	o := orm.NewOrm()

+ 62 - 0
models/tables/company_product/company_product.go

@@ -0,0 +1,62 @@
+package company_product
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type CompanyProduct struct {
+	CompanyProductId    int       `orm:"column(company_product_id);pk" description:"客户产品id"`
+	CompanyId           int       `description:"客户id"`
+	ProductId           int       `description:"产品id"`
+	ProductName         string    `description:"产品名称"`
+	CompanyName         string    `description:"客户名称"`
+	Source              string    `description:"来源"`
+	Reasons             string    `description:"新增理由"`
+	Status              string    `description:"客户状态"`
+	IndustryId          int       `description:"行业id"`
+	IndustryName        string    `description:"行业名称"`
+	SellerId            int       `description:"销售id"`
+	SellerName          string    `description:"销售名称"`
+	GroupId             int       `description:"销售分组id"`
+	DepartmentId        int       `description:"销售部门id"`
+	IsSuspend           int       `description:"1:暂停,0:启用"`
+	SuspendTime         time.Time `description:"暂停启用时间"`
+	TryOutTime          time.Time `description:"正式转试用时间"`
+	RenewalReason       string    `description:"正式转试用后的续约情况说明"`
+	LastDescriptionTime time.Time `description:"上次添加说明时间"`
+	RenewalIntention    int       `description:"是否勾选无续约意向,1:确认,0:未确认"`
+	ApproveStatus       string    `description:"审批状态:'审批中','通过','驳回'"`
+	FreezeTime          time.Time `description:"冻结时间"`
+	FreezeReason        time.Time `description:"冻结理由"`
+	Remark              string    `description:"备注信息"`
+	CreateTime          time.Time `description:"创建时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+	StartDate           string    `description:"开始日期"`
+	EndDate             string    `description:"结束日期"`
+	ContractEndDate     time.Time `description:"合同结束日期"`
+	LoseReason          string    `description:"流失原因"`
+	LossTime            time.Time `description:"流失时间"`
+	CompanyType         string    `description:"客户类型"`
+	OpenCode            string    `description:"开放给第三方的编码,不让第三方定位我们的客户信息"`
+	Scale               string    `description:"管理规模,空不填,1::50亿以下,2:50~100亿,3:100亿以上。"`
+	ViewTotal           int       `description:"总阅读次数"`
+	RoadShowTotal       int       `description:"累计路演次数"`
+	LastViewTime        time.Time `description:"最后一次阅读时间"`
+	PackageType         int       `description:"套餐类型"`
+	IsFormal            int       `description:"是否已经转正式,0是没有转正式,1是已经转过正式"`
+	TodoStatus          string    `description:"任务处理状态;枚举值:'无任务','未完成','已完成'"`
+	TodoCreateTime      time.Time `description:"任务创建时间"`
+	TodoApproveTime     time.Time `description:"任务审批时间"`
+	TryStage            int       `description:"试用客户子标签:1未分类、2  推进、3 跟踪、4 预备"`
+}
+
+// GetCompanyProductByCompanyIdAndProductId 根据客户id和产品id获取客户产品信息
+func GetCompanyProductByCompanyIdAndProductId(companyId, productId int) (item *CompanyProduct, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT b.* FROM company AS a
+			INNER JOIN company_product AS b ON a.company_id=b.company_id
+			WHERE a.company_id=? AND b.product_id=? LIMIT 1 `
+	err = o.Raw(sql, companyId, productId).QueryRow(&item)
+	return
+}

+ 1 - 1
models/tables/company_report_permission/custom_query.go

@@ -2,7 +2,7 @@ package company_report_permission
 
 import (
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"strings"
 	"time"
 )

+ 3 - 5
models/tables/company_user.go

@@ -2,7 +2,7 @@ package tables
 
 import (
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"hongze/hongze_open_api/utils"
 	"time"
 )
@@ -450,16 +450,14 @@ func GetCountUserViewHistoryByEmails(emails string) (items []*UserViewEmailTotal
 }
 
 func GetReportViewMaxTimeByMobile(dayStr string) (items []*UserViewMobileTotalSlice, err error) {
-	o := orm.NewOrm()
-	o.Using("rddp")
+	o := orm.NewOrmUsingDB("rddp")
 	rddpSql := `SELECT mobile,MAX(create_time) AS created_time,COUNT(1) AS total FROM report_view_record WHERE create_time >= ? and mobile !="" group by mobile`
 	_, err = o.Raw(rddpSql, dayStr+" 00:00:00").QueryRows(&items)
 	return
 }
 
 func GetReportViewMaxTimeByEmails(emails string) (items []*UserViewEmailTotalSlice, err error) {
-	o := orm.NewOrm()
-	o.Using("rddp")
+	o := orm.NewOrmUsingDB("rddp")
 	rddpSql := `SELECT mobile,MAX(create_time) AS created_time,COUNT(1) AS total FROM report_view_record WHERE email in (` + emails + `) group by email`
 	_, err = o.Raw(rddpSql).QueryRows(&items)
 	return

+ 1 - 1
models/tables/open_api_user/open_api_user.go

@@ -1,7 +1,7 @@
 package open_api_user
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 )
 
 type OpenApiUser struct {

+ 51 - 0
models/tables/qs_event/qs_event.go

@@ -0,0 +1,51 @@
+package qs_event
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// QsEvent 全时会议表
+type QsEvent struct {
+	QsId         int       `orm:"column(qs_id);pk" description:"自增id"`
+	YbActivityId int       `orm:"column(yb_activity_id)" description:"活动ID"`
+	QsEventId    int       `description:"全时会议id"`
+	Time         int       `description:"会议时长,单位:分"`
+	StartTime    time.Time `description:"会议开始时间"`
+	EndTime      time.Time `description:"会议结束时间"`
+	People       int       `description:"参会人数"`
+	QsStatus     int       `description:"全时会议状态,0:未开始,1:进行中,2:已完成,3:已取消"`
+	Status       int       `description:"状态,0:未同步,1:已创建,2:已取消"`
+	VideoUrl     string    `description:"录制的流媒体文件下载地址"`
+	IsSync       int8      `description:"是否已经同步,0:未同步,1:已同步"`
+	ModifyTime   time.Time `description:"修改时间"`
+	CreateTime   time.Time `description:"创建时间"`
+}
+
+// TableName 表名变更
+func (qsEventInfo *QsEvent) TableName() string {
+	return "qs_event"
+}
+
+// GetQsEventByActivityId 根据活动id获取已同步的全时会议(已同步)
+func GetQsEventByActivityId(activityId int) (item *QsEvent, err error) {
+	o := orm.NewOrm()
+	sql := "select * from qs_event where yb_activity_id=? AND status = 1 "
+	err = o.Raw(sql, activityId).QueryRow(&item)
+	return
+}
+
+// GetQsEventByQsEventId 根据全时会议id获取全时会议(已同步)
+func GetQsEventByQsEventId(qsEventId int) (item *QsEvent, err error) {
+	o := orm.NewOrm()
+	sql := "select * from qs_event where qs_event_id=? "
+	err = o.Raw(sql, qsEventId).QueryRow(&item)
+	return
+}
+
+// Update 更新全时会议
+func (qsEventInfo *QsEvent) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(qsEventInfo, cols...)
+	return
+}

+ 61 - 0
models/tables/qs_event_user/qs_event_user.go

@@ -0,0 +1,61 @@
+package qs_event_user
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// QsEventUser 全时会议用户表
+type QsEventUser struct {
+	QsUserId         int       `orm:"column(qs_user_id);pk" description:"自增id"`
+	QsId             int       `orm:"column(qs_id)" description:"活动与全时会议的关系id"`
+	UserId           int       `description:"用户id"`
+	Mobile           string    `description:"手机号"`
+	Email            string    `description:"邮箱"`
+	Name             string    `description:"姓名"`
+	RegisterTime     time.Time `description:"用户注册时间"`
+	ViewTotal        int       `description:"报告累计阅读次数"`
+	LastViewTime     time.Time `description:"报告最近一次阅读时间"`
+	CompanyId        int       `description:"客户id"`
+	ProductId        int       `description:"产品id"`
+	CompanyName      string    `description:"客户名称"`
+	Status           string    `description:"客户产品状态"`
+	SellerId         int       `description:"所属销售id"`
+	SellerName       string    `description:"所属销售名称"`
+	CompanyViewTotal int       `description:"客户总计阅读次数"`
+	CompanyRoadTotal int       `description:"客户路演次数"`
+	CreateTime       time.Time `description:"记录创建时间"`
+}
+
+// TableName 表名变更
+func (qsEventUserInfo *QsEventUser) TableName() string {
+	return "qs_event_user"
+}
+
+// AddQsEventUser 新增全时会议用户
+func AddQsEventUser(qsEventUser *QsEventUser) (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(qsEventUser)
+	if err != nil {
+		return
+	}
+	qsEventUser.QsUserId = int(id)
+	return
+}
+
+// GetQsUserList 获取到会用户列表数据
+func GetQsUserList(condition string, pars []interface{}, startSize, pageSize int) (total int, list []*QsEventUser, err error) {
+	o := orm.NewOrm()
+	sql := "select * from qs_event_user a where 1=1 "
+	sql += condition
+	sql += ` order by a.qs_user_id desc`
+
+	totalSql := `select count(1) total from (` + sql + `) z `
+	err = o.Raw(totalSql, pars).QueryRow(&total)
+	if err != nil {
+		return
+	}
+	sql += ` LIMIT ?,? `
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&list)
+	return
+}

+ 6 - 6
models/tables/report/report.go

@@ -1,18 +1,18 @@
 package report
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"hongze/hongze_open_api/models/tables/company_report_permission"
 	"hongze/hongze_open_api/utils"
 	"time"
 )
 
 type ReportList struct {
-	ResearchReportId   int    `json:"research_report_id",orm:"column(research_report_id)";description:"报告Id"`
-	ResearchReportName string `json:"research_report_name",orm:"column(research_report_name)"description:"标题"`
-	Periods            int    `json:"periods",description:"期数"`
-	ResearchReportDate string `json:"research_report_date",description:"发布时间"`
-	HttpUrl            string `json:"http_url",description:"报告详情"`
+	ResearchReportId   int    `json:"research_report_id" orm:"column(research_report_id)" description:"报告Id"`
+	ResearchReportName string `json:"research_report_name" orm:"column(research_report_name)" description:"标题"`
+	Periods            int    `json:"periods" description:"期数"`
+	ResearchReportDate string `json:"research_report_date" description:"发布时间"`
+	HttpUrl            string `json:"http_url" description:"报告详情"`
 }
 
 type ReportListResp struct {

+ 1 - 1
models/tables/report/user_report_power.go

@@ -1,7 +1,7 @@
 package report
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 )
 
 func GetUserReportFiccCount(mobile string) (count int, err error) {

+ 16 - 1
models/tables/user_view_statistics/user_view_statistics.go

@@ -1,7 +1,7 @@
 package user_view_statistics
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
 
@@ -34,3 +34,18 @@ func GetUserViewListByDate(dayStr string) (list []*UserViewMobileTotalSlice, err
 	_, err = o.Raw(sql, dayStr).QueryRows(&list)
 	return
 }
+
+// UserViewStatisticsInfo 根据用户手机号字符串获取用户的浏览数和最晚阅读次数
+type UserViewStatisticsInfo struct {
+	Mobile       string    `description:"用户手机号"`
+	Total        int       `description:"总阅读数"`
+	LastViewTime time.Time `description:"用户浏览时间"`
+}
+
+// GetUserViewStatisticsByMobile 根据手机号获取联系人的浏览次数
+func GetUserViewStatisticsByMobile(mobile string) (item *UserViewStatisticsInfo, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT mobile,sum(view_num) view_total,max(last_view_time) last_view_time FROM  user_view_statistics  WHERE mobile = ? `
+	err = o.Raw(sql, mobile).QueryRow(&item)
+	return
+}

+ 11 - 1
models/tables/wx_user/wx_user.go

@@ -1,7 +1,7 @@
 package wx_user
 
 import (
-	"github.com/rdlucklib/rdluck_tools/orm"
+	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
 
@@ -87,3 +87,13 @@ func GetWxUserByMobileStr(mobile string) (item *WxUserItem, err error) {
 	err = orm.NewOrm().Raw(sql).QueryRow(&item)
 	return
 }
+
+// GetWxUserByMobileCountryCode 根据手机号和区号获取用户信息
+func GetWxUserByMobileCountryCode(mobile, countryCode string) (item *WxUser, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_user WHERE mobile = ? `
+	sql += ` and country_code in ("","` + countryCode + `") `
+	sql += ` LIMIT 1 `
+	err = o.Raw(sql, mobile).QueryRow(&item)
+	return
+}

+ 65 - 0
models/tables/yb_activity/yb_activity.go

@@ -0,0 +1,65 @@
+package yb_activity
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// Activity 活动表
+type Activity struct {
+	ActivityId            int       `orm:"column(activity_id);pk" description:"活动ID"`
+	FirstActivityTypeId   int       `description:"第一级的活动类型ID"`
+	FirstActivityTypeName string    `description:"第一级的活动类型名称"`
+	ActivityTypeId        int       `description:"活动类型ID"`
+	ActivityTypeName      string    `description:"活动类型名称"`
+	ActivityName          string    `description:"活动标题"`
+	StartTime             time.Time `description:"活动开始时间"`
+	EndTime               time.Time `description:"活动结束时间"`
+	Speaker               string    `description:"主讲人"`
+	SpeakerHeadPic        string    `description:"主讲人头像"`
+	SpeakerBackgroundPic  string    `description:"主讲人背景图"`
+	MainlandTel           string    `description:"大陆拨入"`
+	HongKongTel           string    `description:"香港拨入"`
+	TaiwanTel             string    `description:"台湾拨入"`
+	AmericaTel            string    `description:"美国拨入"`
+	SingaporeTel          string    `description:"新加坡拨入"`
+	ParticipationCode     string    `description:"参会密码"`
+	LinkParticipants      string    `description:"参会链接"`
+	IsLimitPeople         int8      `description:"是否限制人数 1是,0否"`
+	LimitPeopleNum        int       `description:"限制人数数量"`
+	ReportId              int       `description:"报告链接所关联的文章ID"`
+	ReportLink            string    `description:"报告链接"`
+	ReportName            string    `description:"报告标题"`
+	City                  string    `description:"城市"`
+	Address               string    `description:"活动地址"`
+	Remarks               string    `description:"备注"`
+	UserId                int       `description:"创建者id"`
+	PublishStatus         int8      `description:"发布状态,0未发布,1已发布"`
+	IsSendWxMsg           int8      `description:"是否推送过会议提醒微信消息,未推送:0,已推送:1"`
+	IsSendSalonWxMsg      int8      `description:"是否推送过沙龙提醒微信消息,未推送:0,已推送:1"`
+	IsDelete              int8      `description:"是否删除,0:未删除,1:已删除"`
+	ModifyTime            time.Time `description:"修改时间"`
+	CreateTime            time.Time `description:"创建时间"`
+	QsId                  int       `description:"全时会议关系id"`
+	HostCode              string    `description:"主持人入会密码"`
+}
+
+// TableName 表名变更
+func (activityInfo *Activity) TableName() string {
+	return "yb_activity"
+}
+
+// GetById 根据id获取活动详情
+func GetById(activityId int) (item *Activity, err error) {
+	o := orm.NewOrm()
+	sql := "select * from yb_activity where activity_id=? AND is_delete = 0 "
+	err = o.Raw(sql, activityId).QueryRow(&item)
+	return
+}
+
+// Update 更新活动
+func (activityInfo *Activity) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(activityInfo, cols...)
+	return
+}

+ 793 - 0
services/quanshi/quanshi.go

@@ -0,0 +1,793 @@
+package quanshi
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"hongze/hongze_open_api/services/alarm_msg"
+	"hongze/hongze_open_api/utils"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const (
+	QsAppID     = "ed1cc7c87c97089263fc899fbab193b0"
+	QsSecretKey = "d92b91265dbbc5e3af44edfb82503635"
+
+	//UserId   = 9821234
+	//UserName = "hzhu@hzinsights.com"
+
+	UserId   = 19896481
+	UserName = "pyan@hzinsights.com"
+	//UserId   = 20804877
+	//UserName = "ljjiang@hzinsights.com"
+
+	//有效期24小时
+	Token = "8563737a3c6be564b91be8cab8881058"
+)
+
+// QsResp 全时数据返回结构体
+type QsResp struct {
+	Code      int64       `json:"code"`
+	Data      interface{} `json:"data"`
+	Msg       string      `json:"msg"`
+	RequestID string      `json:"requestId"`
+	TimeStamp int64       `json:"timeStamp"`
+}
+
+// TokenResp 获取token的结构体
+type TokenResp struct {
+	CreateDate   string      `json:"createDate"`
+	CreateTime   int64       `json:"createTime"`
+	CustomerCode string      `json:"customerCode"`
+	Expire       int64       `json:"expire"`
+	ProductID    interface{} `json:"productId"`
+	Token        string      `json:"token"`
+	UserID       int64       `json:"userId"`
+	UserName     string      `json:"userName"`
+}
+
+// getToken 获取token
+func getToken() (dataResp TokenResp, err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("获取全时token失败;ERR:"+err.Error(), 3)
+		}
+	}()
+	user := new(QsUser)
+	user.UserId = UserId
+	user.UserName = UserName
+
+	postData, err := json.Marshal(user)
+	if err != nil {
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	utils.FileLog.Info("Qs PostData:" + string(postData))
+
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/token/create`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, false)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// postCurl post请求上海接口
+func postCurl(urlStr string, postDataStr string, num int, isNeedToken bool) (respData QsResp, err error, errMsg string) {
+	logMsg := ``
+	utils.FileLog.Info("Qs PostData:" + postDataStr)
+	client := &http.Client{}
+	req, err := http.NewRequest("POST", urlStr, strings.NewReader(postDataStr))
+	if err != nil {
+		// handle error
+	}
+	nonce := utils.GetRandStringNoSpecialChar(32)
+	curTime := time.Now().Local().UnixNano() / 1e6
+	curTimeStr := strconv.FormatInt(curTime, 10)
+	checkSumStr := QsSecretKey + nonce + curTimeStr
+	checkSum := utils.Sha1(checkSumStr)
+
+	if isNeedToken {
+		token, tmpErr := GetQsToken(false)
+		if tmpErr != nil {
+			err = tmpErr
+		}
+		req.Header.Set("token", token)
+	}
+	req.Header.Set("AppKey", QsAppID)
+	req.Header.Set("Content-Type", "application/json")
+	req.Header.Set("accept", "application/json")
+	req.Header.Set("Nonce", nonce)
+	req.Header.Set("CurTime", curTimeStr)
+	req.Header.Set("CheckSum", checkSum)
+
+	resp, err := client.Do(req)
+	if err != nil {
+		logMsg = fmt.Sprint("post err; request:", postDataStr, "; errMsg:", err.Error())
+		utils.FileLog.Info(logMsg)
+		return
+	}
+
+	defer resp.Body.Close()
+
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		logMsg = fmt.Sprint("post err; request:", postDataStr, "; errMsg:", err.Error())
+		utils.FileLog.Info(logMsg)
+		return
+	}
+	utils.FileLog.Info(fmt.Sprint("Qs Post Result", ";url:", urlStr, ";\nparams:", postDataStr, ";\nresponse:", string(body)))
+	err = json.Unmarshal(body, &respData)
+	if err != nil {
+		utils.FileLog.Info("post Err:", err.Error(), ";url:", urlStr, ";params:", postDataStr, ";response:", string(body))
+		err = errors.New("Unmarshal Err:" + err.Error())
+		return
+	}
+
+	//如果是token失效,同时只是第一次请求(没有尝试强制刷新token,那么重新请求)
+	if respData.Code == 4100 && num <= 0 {
+		//token失效
+		_, tmpErr := refreshAccessToken()
+		if tmpErr != nil {
+			err = tmpErr
+		}
+		num++
+		return postCurl(urlStr, postDataStr, num, isNeedToken)
+	} else if respData.Code != 200 {
+		utils.FileLog.Info(fmt.Sprint("post data err", ";url:", urlStr, ";params:", postDataStr, ";response:", string(body)))
+		err = errors.New(respData.Msg)
+		return
+	}
+	return
+}
+
+// refreshAccessToken 强制刷新获取accessToken
+func refreshAccessToken() (token string, err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("刷新上海的token失败;ERR:"+err.Error(), 3)
+			//go utils.SendEmail(utils.APPNAME+"刷新上海的token失败:"+time.Now().Format("2006-01-02 15:04:05"), err.Error(), utils.EmailSendToUsers)
+		}
+	}()
+	tokenResp, tmpErr := getToken()
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	token = tokenResp.Token
+
+	//token存入redis
+	err = utils.Rc.Put("QS_TOKEN", token, time.Duration(tokenResp.Expire-600)*time.Second)
+	if err != nil {
+		go alarm_msg.SendAlarmMsg("获取全时的token失败;全时token存入redis失败,ERR:"+err.Error(), 3)
+	}
+	return
+}
+
+type QsUser struct {
+	UserId   int    `json:"userId"`
+	UserName string `json:"userName"`
+}
+
+// GetQsToken 获取全时的token
+func GetQsToken(isRefresh bool) (token string, err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("获取上海的token失败,ERR:"+err.Error(), 3)
+			//go utils.SendEmail(utils.APPNAME+"获取上海的token失败:"+time.Now().Format("2006-01-02 15:04:05"), err.Error(), utils.EmailSendToUsers)
+		}
+	}()
+	token, redisErr := utils.Rc.RedisString("QS_TOKEN")
+	//如果从redis中accessToken 获取失败或者token为空了,再或者需要强制刷新了,那么重新获取accessToken
+	if redisErr != nil || token == `` || isRefresh {
+		return refreshAccessToken()
+	}
+	return
+}
+
+// EventListParam 获取会议列表请求参数据结构
+type EventListParam struct {
+	//Token string `json:"token"`
+	//HostId    int `description:"主持人ID 如果主持人ID为空,则查询所有创建的直播会议" json:"hostId"`
+	StartTime int64 `description:"查询开始时间(时间戳,单位秒)默认为当前时间" json:"startTime"`
+	EndTime   int64 `description:"查询结束时间(时间戳,单位秒)默认为当前时间之后3个月" json:"endTime"`
+	Limit     int   `description:"每页返回多少条记录,默认值10" json:"limit"`
+}
+
+// EventListResp 会议列表返回数据结构
+type EventListResp struct {
+	AllowH323        int64       `json:"allowH323" description:""`
+	AttendeeJoinURL  string      `json:"attendeeJoinUrl" description:"参会人入会链接"`
+	AudienceUnionURL string      `json:"audienceUnionUrl" description:"观众落地页链接"`
+	BillingCode      string      `json:"billingCode" description:"云会议计费BC"`
+	CallbackURL      string      `json:"callbackUrl" description:"会议回调地址"`
+	ConfNodeType     int64       `json:"confNodeType" description:"会议节点类型 0: 保密会议,1: 标准会议(默认)"`
+	ConferenceID     string      `json:"conferenceId" description:"云会议ID"`
+	CustomStr        interface{} `json:"customStr" description:"自定义内容"`
+	CustomerCode     string      `json:"customerCode" description:"客户编码"`
+	EndDate          string      `json:"endDate" description:"会议结束时间(格式:年月日时分秒)"`
+	EndTime          int64       `json:"endTime" description:"会议结束时间(时间戳,单位秒)"`
+	EventForm        int64       `json:"eventForm" description:"会议形式 1: 电话活动,3: 网络会议,7: 大型直播活动"`
+	EventID          int64       `json:"eventId" description:"直播会议ID"`
+	EventWatchword   string      `json:"eventWatchword" description:""`
+	GuestJoinURL     string      `json:"guestJoinUrl" description:"嘉宾入会链接"`
+	HostID           int64       `json:"hostId" description:"主持人ID"`
+	HostJoinURL      string      `json:"hostJoinUrl" description:"创建人入会链接"`
+	HostName         string      `json:"hostName" description:"主持人姓名"`
+	JoinHostURL      string      `json:"joinHostUrl" description:"助理主持人链接"`
+	JointHostURL     string      `json:"jointHostUrl" description:""`
+	Labels           []string    `json:"labels" description:"活动标签"`
+	Length           int64       `json:"length" description:"会议时长(时间戳,单位分钟)"`
+	LiveCover        string      `json:"liveCover" description:"活动间(直播)封面图URL"`
+	LiveLag          int64       `json:"liveLag" description:"直播延迟设置(0:正常延迟,1:无延迟,默认0)"`
+	LiveOpenFlag     int64       `json:"liveOpenFlag" description:"开启实时互动直播 0: 否, 1: 是(默认值0,仅针对eventForm=3有效)"`
+	LivePullURL      string      `json:"livePullUrl" description:"直播链接"`
+	LiveScreen       int64       `json:"liveScreen" description:"云活动手机屏幕显示方式,0:横屏(默认)1:竖屏"`
+	ManualService    int64       `json:"manualService" description:"是否需要项目经理开关,1:开启,2:关闭,默认2"`
+	ModifyDate       string      `json:"modifyDate" description:""`
+	ModifyTime       int64       `json:"modifyTime" description:""`
+	OpenWatchword    int64       `json:"openWatchword" description:""`
+	Pcode1           string      `json:"pcode1" description:""`
+	Pcode2           string      `json:"pcode2" description:""`
+	StartDate        string      `json:"startDate" description:"会议开始时间(格式:年月日时分秒)"`
+	StartTime        int64       `json:"startTime" description:"会议开始时间(时间戳,单位秒)"`
+	Summary          string      `json:"summary" description:"会议概要"`
+	Title            string      `json:"title" description:"会议主题"`
+	WcallURL         string      `json:"wcallUrl" description:"云会议电话会议链接"`
+	WebMeetURL       string      `json:"webMeetUrl" description:""`
+	WebRTCUrl        string      `json:"webRTCUrl" description:"webRTC 入会链接"`
+}
+
+// GetQsEventList 获取会议列表
+func GetQsEventList(createTime, endTime time.Time) (dataResp []EventListResp, err error) {
+	params := EventListParam{
+		//HostId:    0,
+		StartTime: createTime.Unix(),
+		EndTime:   endTime.Unix(),
+		Limit:     10,
+	}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	fmt.Println("postData:" + string(postData))
+	utils.FileLog.Info("Qs PostData:" + string(postData))
+
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/list`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// EventCreateParams 全时会议创建请求参数据结构
+type EventCreateParams struct {
+	HostId        int64  `json:"hostId" description:"主持人ID"`
+	Title         string `json:"title" description:"会议主题, 主题不能超过30个字"`
+	StartTime     int64  `json:"startTime" description:"开始时间(时间戳,单位秒)"`
+	Length        int    `json:"length" description:"会议时长(单位分钟)会议时长的取值只接受30的倍数,并且最大为720分钟. 如果填写的时长不符合要求,系统自动取最接近的分钟数. 例如输入时长40分钟,则系统自动转换成30分钟;而输入时长50分钟,系统会调整为60分钟"`
+	EventForm     int    `json:"eventForm" description:"会议形式 1: 电话会议,3: 网络会议,7: 大型直播活动;电话会议 :通过电话的方式召开的活动,可进行声音的实时互动,无资料共享。;网络会议:适用于有资料共享的实时互动活动,所有参会用户都可查看共享的资料,可选择电话/网络语音进行互动讨论。;大型直播活动:适用于宣讲路演、带货推广、年会、在线发布会,所有参会用户可通过网页/小程序观看直播,可通过文字或举手方式进行互动讨论。"`
+	CallbackUrl   string `json:"callbackUrl" description:"会议回调地址"`
+	JoinLimit     int    `json:"joinLimit" description:"观众直播入会限制 0: 公开, 1: 白名单(默认, 并且非白名单(电话入会)拒绝入会)"`
+	ManualService int    `json:"manualService" description:"是否需要项目经理开关,1: 开启,2: 关闭(默认1)"`
+}
+
+// EventCreateResp 全时会议创建 返回 参数据结构
+type EventCreateResp struct {
+	AttendeeJoinURL  string   `json:"attendeeJoinUrl" description:"参会人入会链接"`
+	AudienceUnionURL string   `json:"audienceUnionUrl" description:"观众落地页链接"`
+	BillingCode      string   `json:"billingCode" description:"云会议计费BC"`
+	CallbackURL      string   `json:"callbackUrl" description:"会议回调地址"`
+	ConfNodeType     int64    `json:"confNodeType" description:"会议节点类型 0: 保密会议,1: 标准会议(默认)"`
+	ConferenceID     string   `json:"conferenceId" description:"云会议ID"`
+	CustomStr        string   `json:"customStr" description:"自定义内容"`
+	EventForm        int64    `json:"eventForm" description:"会议形式 1: 电话活动,3: 网络会议,7: 大型直播活动"`
+	EventID          int64    `json:"eventId" description:"直播会议ID"`
+	GuestJoinURL     string   `json:"guestJoinUrl" description:"嘉宾入会链接"`
+	HostID           int64    `json:"hostId" description:"主持人ID"`
+	HostJoinURL      string   `json:"hostJoinUrl" description:"主持人入会链接"`
+	JoinHostURL      string   `json:"joinHostUrl" description:"助理主持人链接"`
+	JoinLimit        int64    `json:"joinLimit" description:"观众直播入会限制 0: 公开, 1: 白名单(默认值1, 并且非白名单(电话入会)拒绝入会)"`
+	Labels           []string `json:"labels" description:"活动标签"`
+	Length           int64    `json:"length" description:"会议时长(单位分钟);会议时长的取值只接受30的倍数,并且最大为720分钟. 如果填写的时长不符合要求,系统自动取最接近的分钟数. 例如输入时长40分钟,则系统自动转换成30分钟;而输入时长50分钟,系统会调整为60分钟"`
+	LiveCover        string   `json:"liveCover" description:"会议封面图URL 尺寸1280x720px 图片小于2MB(jpg、png)"`
+	LiveLag          int64    `json:"liveLag" description:"直播延迟设置 0: 正常延迟,1: 无延迟(默认0)"`
+	LiveOpenFlag     int64    `json:"liveOpenFlag" description:"开启实时互动直播 0: 否, 1: 是(默认值0,仅针对eventForm=3有效)"`
+	LiveScreen       int64    `json:"liveScreen" description:"云活动手机屏幕显示方式,0: 横屏,1: 竖屏(默认0)"`
+	ManualService    int64    `json:"manualService" description:"是否需要项目经理开关,1: 开启,2: 关闭(默认2)"`
+	Pcode1           string   `json:"pcode1" description:"主持人入会密码"`
+	Pcode2           string   `json:"pcode2" description:"参会人入会密码"`
+	StartTime        int64    `json:"startTime" description:"会议开始时间(时间戳,单位秒)"`
+	Summary          string   `json:"summary" description:"会议概要"`
+	Title            string   `json:"title" description:"会议主题"`
+	Wcallurl         string   `json:"wcallurl" description:"云会议电话会议链接"`
+}
+
+// QsEventCreate 全时会议创建
+func QsEventCreate(title string, meetingTime, eventForm int, startTime time.Time, callbackUrl string) (dataResp EventCreateResp, err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("创建全时会议失败;ERR:"+err.Error(), 3)
+		}
+	}()
+	isManualService := 2 //是否需要项目经理提醒(默认不需要)
+	joinLimit := 0
+	params := EventCreateParams{
+		HostId:        UserId,
+		Title:         title,
+		StartTime:     startTime.Unix(),
+		Length:        meetingTime,
+		EventForm:     eventForm,
+		CallbackUrl:   callbackUrl,
+		JoinLimit:     joinLimit,
+		ManualService: isManualService,
+	}
+	postData, err := json.Marshal(params)
+	if err != nil {
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/create`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// EventCancelParams 全时会议取消请求参数据结构
+type EventCancelParams struct {
+	EventId int64 `json:"eventId" description:"全时会议id"`
+}
+
+// QsEventCancel 取消全时会议
+func QsEventCancel(eventId int) (err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("取消全时会议失败;ERR:"+err.Error(), 3)
+		}
+	}()
+	params := EventCancelParams{
+		EventId: int64(eventId),
+	}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/cancel`
+	_, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+	return
+}
+
+// EventUpdateParams 全时会议修改请求参数据结构
+type EventUpdateParams struct {
+	Title          string `json:"title"`
+	StartTime      int64  `json:"startTime"`
+	Length         int    `json:"length"`
+	EventId        int64  `json:"eventId"`
+	UseWaitingRoom int64  `json:"useWaitingRoom"`
+}
+
+// EventUpdateResp 全时会议修改 返回 数据结构
+type EventUpdateResp struct {
+	AttendeeJoinURL  string   `json:"attendeeJoinUrl"`
+	AudienceUnionURL string   `json:"audienceUnionUrl"`
+	BillingCode      string   `json:"billingCode"`
+	CallbackURL      string   `json:"callbackUrl"`
+	ConfNodeType     int64    `json:"confNodeType"`
+	ConferenceID     string   `json:"conferenceId"`
+	CustomStr        string   `json:"customStr"`
+	EventForm        int64    `json:"eventForm"`
+	EventID          int64    `json:"eventId"`
+	GuestJoinURL     string   `json:"guestJoinUrl"`
+	HostID           int64    `json:"hostId"`
+	HostJoinURL      string   `json:"hostJoinUrl"`
+	JoinHostURL      string   `json:"joinHostUrl"`
+	JoinLimit        int64    `json:"joinLimit"`
+	Labels           []string `json:"labels"`
+	Length           int64    `json:"length"`
+	LiveCover        string   `json:"liveCover"`
+	LiveLag          int64    `json:"liveLag"`
+	LiveOpenFlag     int64    `json:"liveOpenFlag"`
+	LiveScreen       int64    `json:"liveScreen"`
+	ManualService    int64    `json:"manualService"`
+	Pcode1           string   `json:"pcode1"`
+	Pcode2           string   `json:"pcode2"`
+	StartTime        int64    `json:"startTime"`
+	Summary          string   `json:"summary"`
+	Title            string   `json:"title"`
+	Wcallurl         string   `json:"wcallurl"`
+}
+
+// QsEventUpdate 全时会议修改
+func QsEventUpdate(eventId, length int, title string, startTime time.Time) (dataResp EventUpdateResp, err error) {
+	params := EventUpdateParams{
+		EventId:   int64(eventId),
+		Title:     title,
+		StartTime: startTime.Unix(),
+		Length:    length,
+	}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/update`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// UserEmailParams 全时 根据邮箱获取用户信息 请求参数据结构
+type UserEmailParams struct {
+	Email string `json:"email"`
+}
+
+// UserInfoResp 全时用户信息 返回 数据结构
+type UserInfoResp struct {
+	AccountType   int64  `json:"accountType" description:"账号类型 0: 个人账号(个人站点或电商站点下的账号); 1: 企业账号(非个人站点、电商站点的账号)"`
+	CountryCode   string `json:"countryCode" description:"国家码"`
+	CustomerCode  string `json:"customerCode" description:"客户编码"`
+	CustomerName  string `json:"customerName" description:"客户名称"`
+	DisplayName   string `json:"displayName" description:"显示名称"`
+	Email         string `json:"email" description:"邮箱"`
+	FirstName     string `json:"firstName" description:"首部名称"`
+	LastName      string `json:"lastName" description:"尾部名称"`
+	LoginName     string `json:"loginName" description:"登录名"`
+	MiddleName    string `json:"middleName" description:"中间名称"`
+	Mobile        string `json:"mobile" description:"手机"`
+	ProductStatus int64  `json:"productStatus" description:"产品类型 0: 未知状态 1: 已开通 2: 未开通 默认为0"`
+	Products      []struct {
+		AccountCostStatus int64 `json:"accountCostStatus" description:"费用状态 82-正式,9-试用,91-过期,81-欠费,71-合同终止;过期或者欠费的不能启用产品,需要先由qsboss系统修改为正式或者试用账号,61-免费账号,62-付费账号"`
+		AccountStatus     int64 `json:"accountStatus" description:"账号状态 9:试用 82:正式 91:过期 81:欠费 0:禁用"`
+		ProductID         int64 `json:"productId" description:"	产品ID"`
+	} `json:"products" description:"产品列表"`
+	UserID     int64 `json:"userId" description:"用户ID"`
+	UserStatus int64 `json:"userStatus" description:"用户状态 0:未激活; 1:已激活; 2:已关闭"`
+}
+
+// GetQsUserInfoByEmail 根据邮箱号获取全时用户信息
+func GetQsUserInfoByEmail(email string) (dataResp UserInfoResp, err error) {
+	userEmailItem := UserEmailParams{
+		Email: email,
+	}
+	postData, err := json.Marshal(userEmailItem)
+	if err != nil {
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/user/search/email`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+type UserInfo struct {
+	Mobiles []*UserMobile `json:"mobiles"`
+}
+
+type UserMobile struct {
+	PhoneNumber string `json:"phoneNumber"`
+}
+
+func GetQsUserInfoByPhone() {
+	userMobileItem := new(UserMobile)
+	userMobileItem.PhoneNumber = "17521741003"
+
+	userInfoItem := new(UserInfo)
+	userInfoItem.Mobiles = append(userInfoItem.Mobiles, userMobileItem)
+
+	postData, err := json.Marshal(userInfoItem)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	fmt.Println("postData:" + string(postData))
+	utils.FileLog.Info("Qs PostData:" + string(postData))
+
+	client := &http.Client{}
+	postUrl := `https://events-openapi.quanshi.com//eventopenapi/user/search/mobiles`
+	req, err := http.NewRequest("POST", postUrl, strings.NewReader(string(postData)))
+	if err != nil {
+		// handle error
+	}
+	nonce := utils.GetRandStringNoSpecialChar(32)
+	curTime := time.Now().Local().UnixNano() / 1e6
+	curTimeStr := strconv.FormatInt(curTime, 10)
+	checkSumStr := QsSecretKey + nonce + curTimeStr
+	checkSum := utils.Sha1(checkSumStr)
+
+	req.Header.Set("AppKey", QsAppID)
+	req.Header.Set("Content-Type", "application/json")
+	req.Header.Set("accept", "application/json")
+	req.Header.Set("Nonce", nonce)
+	req.Header.Set("CurTime", curTimeStr)
+	req.Header.Set("CheckSum", checkSum)
+
+	resp, err := client.Do(req)
+
+	defer resp.Body.Close()
+
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		// handle error
+	}
+
+	utils.FileLog.Info("Qs Result:" + string(body))
+
+	fmt.Println(string(body))
+}
+
+// EventStatusParams 查看会议状态请求结构体
+type EventStatusParams struct {
+	EventId int64 `json:"eventId"`
+}
+
+// EventStatusResp 查看会议状态结果返回结构体
+type EventStatusResp struct {
+	AdvanceHours string `json:"advanceHours"`
+	Attendees    int64  `json:"attendees"`
+	EventID      int64  `json:"eventId"`
+	EventStatus  int64  `json:"eventStatus"`
+	MayJoin      int64  `json:"mayJoin"`
+}
+
+// QsEventStatus 查看会议状态
+func QsEventStatus(eventId int64) (dataResp EventStatusResp, err error) {
+	params := EventStatusParams{EventId: eventId}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/status`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// EventDetailParams 查看会议详情请求结构体
+type EventDetailParams struct {
+	EventId int64 `json:"eventId"`
+}
+
+// EventDetailResp 查看会议详情结果返回结构体
+type EventDetailResp struct {
+	AdvanceHours string `json:"advanceHours"`
+	Attendees    int64  `json:"attendees"`
+	EventID      int64  `json:"eventId"`
+	EventStatus  int64  `json:"eventStatus"`
+	MayJoin      int64  `json:"mayJoin"`
+}
+
+// QsEventDetail 查看会议详情
+func QsEventDetail(eventId int64) (dataResp EventUpdateResp, err error) {
+	params := EventDetailParams{EventId: eventId}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/info`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// QsEventReportSummaryParams 查看会议汇总数据请求结构体
+type QsEventReportSummaryParams struct {
+	EventId int64  `json:"eventId" description:"直播会议ID"`
+	SortBy  string `json:"sortBy" description:"汇总去重条件 默认值 extId; email: 根据邮箱汇总; mobile: 根据手机汇总; name: 根据姓名汇总; extId: 根据第三方ID汇总"`
+}
+
+// QsEventReportSummaryResp 查看会议汇总数据结果返回结构体
+type QsEventReportSummaryResp struct {
+	EventID int64  `json:"eventId"`
+	SortBy  string `json:"sortBy"`
+	Summary map[string]struct {
+		BillingCode  string `json:"billingCode"`
+		ConferenceID string `json:"conferenceId"`
+		Duration     int64  `json:"duration"`
+		Email        string `json:"email"`
+		ExtID        string `json:"extId"`
+		HostID       string `json:"hostId"`
+		Mobile       string `json:"mobile"`
+		Name         string `json:"name"`
+		OfflineDate  string `json:"offline_date"`
+		OfflineTime  int64  `json:"offline_time"`
+		OnlineDate   string `json:"online_date"`
+		OnlineTime   int64  `json:"online_time"`
+	} `json:"summary"`
+}
+
+// QsEventReportSummary 查看会议汇总数据
+func QsEventReportSummary(eventId int) (dataResp QsEventReportSummaryResp, err error) {
+	sortBy := `mobile`
+	params := QsEventReportSummaryParams{
+		EventId: int64(eventId),
+		SortBy:  sortBy,
+	}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/report/summary`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// QsEventReportQueryParams 批量查询会议状态和录制数据请求结构体
+type QsEventReportQueryParams struct {
+	EventIds   []int64 `json:"eventIds" description:"直播会议ID"`
+	QueryType  int64   `json:"queryType" description:"查询的数据类别(1: 会议状态; 2: 会议录制; 3: 会议状态+会议录制)"`
+	RecordType int     `json:"recordType" description:"录制类型(queryType=2时有效)1:会议录制或电话录制; 5:直播录制; 默认全查"`
+}
+
+// QsEventReportQueryResp 批量查询会议状态和录制数据结果返回结构体
+type QsEventReportQueryResp struct {
+	Records map[string]struct {
+		RecordID           int64  `json:"recordId"`
+		RecordType         int64  `json:"recordType"`
+		RecordingEndDate   string `json:"recordingEndDate"`
+		RecordingEndtime   int64  `json:"recordingEndtime"`
+		RecordingStartDate string `json:"recordingStartDate"`
+		RecordingStarttime int64  `json:"recordingStarttime"`
+		Thumb              string `json:"thumb"`
+		Title              string `json:"title"`
+		VideoLength        int64  `json:"videoLength"`
+		VideoSize          int64  `json:"videoSize"`
+		VideoStreamURL     string `json:"videoStreamUrl"`
+		VideoURL           string `json:"videoURL"`
+	} `json:"records"`
+	Status map[string]struct {
+		ConferenceID     string `json:"conferenceId"`
+		Status           int64  `json:"status"`
+		TempConferenceID string `json:"tempConferenceId"`
+		UserID           int64  `json:"userId"`
+	} `json:"status"`
+}
+
+// QsEventReportQueryVideo 批量查询会议录制数据
+func QsEventReportQueryVideo(eventId int64) (dataResp QsEventReportQueryResp, err error) {
+	params := QsEventReportQueryParams{
+		EventIds:   []int64{eventId},
+		QueryType:  2,
+		RecordType: 1,
+	}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/report/query`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// QsEventReportQuery 批量查询会议状态和录制数据
+func QsEventReportQuery(eventId, queryType int64) (dataResp QsEventReportQueryResp, err error) {
+	//recordType := 0
+	params := QsEventReportQueryParams{
+		EventIds:  []int64{eventId},
+		QueryType: queryType,
+		//RecordType: recordType,
+	}
+
+	postData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("PostData json.Marshal Err:" + err.Error())
+		utils.FileLog.Info("PostData json.Marshal Err:" + err.Error())
+		return
+	}
+	postUrl := `https://events-openapi.quanshi.com/eventopenapi/event/report/query`
+	respData, err, errMsg := postCurl(postUrl, string(postData), 1, true)
+	if err != nil {
+		fmt.Println("err:", err, ";errMsg:", errMsg)
+		return
+	}
+
+	bodyBytes, _ := json.Marshal(respData.Data)
+	err = json.Unmarshal(bodyBytes, &dataResp)
+	return
+}
+
+// 弘则全时的回调签名秘钥
+const QS_HONGZE_KEY = "hongZe20220601QSROc"
+
+// GetSign 获取签名
+func GetSign(signStr string) string {
+	signStr += "&key=" + QS_HONGZE_KEY
+	return utils.MD5(signStr)
+}
+
+//func Qsinit() {
+//	fmt.Println("start")
+//	nonce := utils.GetRandStringNoSpecialChar(32)
+//	curTime := time.Now().Local().UnixNano()/1e6
+//	curTimeStr := strconv.FormatInt(curTime, 10)
+//	checkSumStr := QsSecretKey + nonce + curTimeStr
+//	fmt.Println("nonce:" + nonce)
+//	fmt.Println("curTimeStr:" + curTimeStr)
+//	fmt.Println("QsSecretKey:" + QsSecretKey)
+//	checkSum := utils.Sha1(checkSumStr)
+//	fmt.Println(checkSum)
+//	fmt.Println("end")
+//}

+ 144 - 0
services/yb/activity.go

@@ -0,0 +1,144 @@
+package yb
+
+import (
+	"fmt"
+	"hongze/hongze_open_api/models/tables/company"
+	"hongze/hongze_open_api/models/tables/company_product"
+	"hongze/hongze_open_api/models/tables/qs_event"
+	"hongze/hongze_open_api/models/tables/qs_event_user"
+	"hongze/hongze_open_api/models/tables/user_view_statistics"
+	"hongze/hongze_open_api/models/tables/wx_user"
+	"hongze/hongze_open_api/services/quanshi"
+	"strings"
+	"time"
+)
+
+// SyncUser 用户同步
+func SyncUser(qsEventId int) (err error) {
+	qsEventInfo, err := qs_event.GetQsEventByQsEventId(qsEventId)
+	if err != nil {
+		return
+	}
+
+	if qsEventInfo.IsSync == 1 {
+		return
+	}
+	//获取全时的参会人员信息
+	qsData, err := quanshi.QsEventReportSummary(qsEventId)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	companyProductMap := make(map[string]*company_product.CompanyProduct)
+	companyMap := make(map[string]*company.Company)
+	people := 0 //参与人数
+	if qsData.Summary != nil {
+		for _, v := range qsData.Summary {
+			if v.Mobile == "" { //如果手机号为空,那么就不处理了,进入下一个循环
+				continue
+			}
+			people++
+			mobile := v.Mobile
+			trimMobile := mobile
+			countryCode := "86"
+			var companyProductInfo *company_product.CompanyProduct
+			var companyInfo *company.Company
+			var wxUserInfo *wx_user.WxUser
+			if mobile != "" {
+				trimMobileSlice := strings.Split(v.Mobile, "-")
+				lenTrimMobileSlice := len(trimMobileSlice)
+				if lenTrimMobileSlice > 1 {
+					trimMobile = trimMobileSlice[1]
+					countryCode = strings.Replace(trimMobileSlice[0], "+", "", -1)
+				}
+				wxUserInfo, _ = wx_user.GetWxUserByMobileCountryCode(trimMobile, countryCode)
+				if wxUserInfo != nil && wxUserInfo.CompanyId != 1 {
+					//获取客户产品信息
+					key := fmt.Sprint(wxUserInfo.CompanyId, "_", 1)
+					if tmpCompanyProductInfo, ok := companyProductMap[key]; ok {
+						companyProductInfo = tmpCompanyProductInfo
+					} else {
+						companyProductInfo, _ = company_product.GetCompanyProductByCompanyIdAndProductId(wxUserInfo.CompanyId, 1)
+						if companyProductInfo != nil {
+							companyProductMap[key] = companyProductInfo
+						}
+
+					}
+
+					if tmpCompanyInfo, ok := companyMap[key]; ok {
+						companyInfo = tmpCompanyInfo
+					} else {
+						companyInfo, _ = company.GetCompanyById(wxUserInfo.CompanyId)
+						if companyProductInfo != nil {
+							companyMap[key] = companyInfo
+						}
+					}
+				}
+			}
+
+			name := ``
+			if v.Mobile != v.Name {
+				name = v.Name
+			}
+			qsEventUserInfo := &qs_event_user.QsEventUser{
+				QsId:   qsEventInfo.QsId,
+				UserId: 0,
+				Mobile: v.Mobile,
+				Email:  v.Email,
+				Name:   name,
+				//RegisterTime:     time.Time{},
+				ViewTotal: 0,
+				//LastViewTime:     time.Time{},
+				CompanyId:        0,
+				ProductId:        0,
+				CompanyName:      "",
+				Status:           "",
+				SellerId:         0,
+				SellerName:       "",
+				CompanyViewTotal: 0,
+				CompanyRoadTotal: 0,
+				CreateTime:       time.Now(),
+			}
+			//这个时候是系统用户了,美滋滋
+			if companyProductInfo != nil {
+				qsEventUserInfo.RegisterTime = wxUserInfo.RegisterTime
+
+				userViewStatisticsInfo, _ := user_view_statistics.GetUserViewStatisticsByMobile(trimMobile) //用户阅读信息
+				if userViewStatisticsInfo != nil {
+					qsEventUserInfo.ViewTotal = userViewStatisticsInfo.Total
+					qsEventUserInfo.LastViewTime = userViewStatisticsInfo.LastViewTime
+				}
+
+				qsEventUserInfo.UserId = int(wxUserInfo.UserId)
+				qsEventUserInfo.Name = wxUserInfo.RealName
+				qsEventUserInfo.CompanyId = companyProductInfo.CompanyId
+				qsEventUserInfo.ProductId = companyProductInfo.ProductId
+				qsEventUserInfo.CompanyName = companyInfo.CompanyName
+				qsEventUserInfo.Status = companyProductInfo.Status
+				qsEventUserInfo.SellerId = companyProductInfo.SellerId
+				qsEventUserInfo.SellerName = companyProductInfo.SellerName
+				qsEventUserInfo.CompanyViewTotal = companyProductInfo.ViewTotal
+				qsEventUserInfo.CompanyRoadTotal = companyProductInfo.RoadShowTotal
+			}
+			_ = qs_event_user.AddQsEventUser(qsEventUserInfo)
+		}
+	}
+
+	qsEventInfo.IsSync = 1
+	qsEventInfo.QsStatus = 2
+	qsEventInfo.People = people
+	err = qsEventInfo.Update([]string{"IsSync", "QsStatus", "People"})
+	return
+}
+
+// SyncVideo 录音同步
+func SyncVideo(qsEventId int, videoUrl string) (err error) {
+	qsEventInfo, err := qs_event.GetQsEventByQsEventId(qsEventId)
+	if err != nil {
+		return
+	}
+	qsEventInfo.VideoUrl = videoUrl
+	err = qsEventInfo.Update([]string{"VideoUrl"})
+	return
+}

+ 45 - 0
utils/logs.go

@@ -1,12 +1,57 @@
 package utils
 
 import (
+	"encoding/json"
 	"github.com/beego/beego/v2/adapter/logs"
+	"os"
 )
 
 var FileLog *logs.BeeLogger
+var Binlog *logs.BeeLogger
 
 func init() {
 	FileLog = logs.NewLogger(1000000)
 	FileLog.SetLogger(logs.AdapterFile, `{"filename":"./rdlucklog/hongze_open_api.log"}`)
+
+	//初始化binlog日志
+	initBinlog()
+}
+
+func initBinlog() {
+	//binlog日志
+	binLogDir := `./binlog`
+	os.MkdirAll(binLogDir, os.ModePerm)
+	Binlog = logs.NewLogger(1000000)
+	logConfig := getDefaultLogConfig()
+	logConfig.FileName = "./binlog/binlog.log"
+	logConfig.MaxLines = 10000000
+	logConfig.Rotate = true
+	b, _ := json.Marshal(logConfig)
+	Binlog.SetLogger(logs.AdapterFile, string(b))
+	Binlog.EnableFuncCallDepth(true)
+}
+
+type logConfig struct {
+	FileName string `json:"filename" description:"保存的文件名"`
+	MaxLines int    `json:"maxlines"  description:"每个文件保存的最大行数,默认值 1000000"`
+	MaxSize  int    `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
+	Daily    bool   `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
+	MaxDays  int    `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
+	Rotate   bool   `json:"rotate" description:"是否开启 logrotate,默认是 true"`
+	Level    int    `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
+	Color    bool   `json:"color" description:"日志是否输出颜色"`
+	//Perm     string `json:"perm" description:"日志文件权限"`
+}
+
+func getDefaultLogConfig() logConfig {
+	return logConfig{
+		FileName: "",
+		MaxLines: 0,
+		MaxSize:  1 << 28,
+		Daily:    true,
+		MaxDays:  31, //我就是喜欢31天,咋滴,不喜欢你就自己改-_-!
+		Rotate:   true,
+		Level:    logs.LevelTrace,
+		//Perm:     "",
+	}
 }