xingzai 9 kuukautta sitten
vanhempi
commit
c973d28988

+ 6 - 0
models/admin.go

@@ -33,6 +33,12 @@ func GetAdminByAdminIds(adminIds []int) (items []*Admin, err error) {
 	return
 }
 
+func GetAdminByAdminMobiles(mobiles []string) (items []*Admin, err error) {
+	sql := `SELECT * FROM admin WHERE admin_id in (` + utils.GetOrmInReplace(len(mobiles)) + `) `
+	_, err = orm.NewOrm().Raw(sql, mobiles).QueryRows(&items)
+	return
+}
+
 type AdminView struct {
 	AdminId      int
 	AdminName    string `description:"系统用户名称"`

+ 18 - 0
models/cygx/activity_ask_email.go

@@ -0,0 +1,18 @@
+package cygx
+
+import "github.com/beego/beego/v2/client/orm"
+
+type AskEmailRep struct {
+	Name                string `description:"姓名"`
+	Email               string `description:"邮箱"`
+	Mobile              string `description:"手机号"`
+	ChartPermissionName string `description:"权限名称"`
+	AdminId             int
+}
+
+func GetAskEmailList() (item []*AskEmailRep, err error) {
+	o := orm.NewOrmUsingDB("hz_cygx")
+	sql := `SELECT * FROM cygx_activity_ask_email WHERE    chart_permission_name != ''  ORDER BY sort  DESC`
+	_, err = o.Raw(sql).QueryRows(&item)
+	return
+}

+ 28 - 0
models/roadshow/calendar.go

@@ -2,6 +2,7 @@ package roadshow
 
 import (
 	"github.com/beego/beego/v2/client/orm"
+	"hongze/hongze_task/utils"
 	"time"
 )
 
@@ -107,3 +108,30 @@ func GetRsCalendarResearcherById(rsCalendarId int) (item *RsCalendarResearcher,
 	err = o.Raw(sql, rsCalendarId).QueryRow(&item)
 	return
 }
+
+func GetRsCalendarResearcherByIds(rsCalendarIds []int) (items []*RsCalendarResearcher, err error) {
+	lenArr := len(rsCalendarIds)
+	sql := `SELECT * FROM rs_calendar_researcher WHERE rs_calendar_researcher_id  IN  (` + utils.GetOrmInReplace(lenArr) + `) `
+	o := orm.NewOrm()
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+type ResearcherGroup struct {
+	GroupId        int    `description:"分组id"`
+	GroupName      string `description:"分组名称"`
+	AdminId        int    `description:"研究员id"`
+	RealName       string `description:"研究员名称"`
+	RoleTypeCode   string `description:"角色编码"`
+	Mobile         string `description:"手机号"`
+	ResearcherList []*ResearcherGroup
+}
+
+func GetResearcher() (list []*ResearcherGroup, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM admin AS a
+			WHERE a.role_type_code IN('researcher','rai_researcher','ficc_researcher','ficc_admin')
+			AND a.enabled=1 AND a.real_name<>'于菲' `
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}

+ 84 - 0
models/roadshow/rs_calendar_relation.go

@@ -0,0 +1,84 @@
+package roadshow
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"hongze/hongze_task/utils"
+	"time"
+)
+
+// RsCalendarRelation 自系统路演与第三方路演关系表
+type RsCalendarRelation struct {
+	RelationId       int       `orm:"column(relation_id);pk" description:"关系id"`
+	CalendarType     int8      `description:"日历类型;1:路演;2:事项"`
+	SelfCalendarId   int       `description:"系统内部的日历id,可以是研究员与路演活动的关系id,也可以是事项id"`
+	ThirdCalendarId  int       `description:"第三方路演id"`
+	UserId           int       `description:"关系id"`
+	UserPhone        string    `description:"创建人手机号"`
+	UserName         string    `description:"创建人昵称"`
+	ProjectName      string    `description:"活动名称"`
+	ProjectId        int       `description:"活动id"`
+	CustomerId       int       `description:"客户id"`
+	CustomerName     string    `description:"客户名称"`
+	CustomerSocial   string    `description:"客户社会信用码"`
+	ProjectType      int       `description:"活动类型:1=沙龙,2=路演,3=专家需求,4=研究需求,5=电话,6=面谈,7=专题需求,8=线下沙龙,9=公司调研"`
+	ProjectFormType  int       `description:"服务形式:1=沙龙,2=路演,3=专家需求,4=研究需求,5=电话,6=面谈,7=专题需求"`
+	Room             int       `description:"会议室id"`
+	StartTime        int       `description:"开始时间戳"`
+	EndTime          int       `description:"结束时间戳"`
+	Content          string    `description:"活动内容"`
+	FeedExpert       string    `description:"邀请的专家"`
+	Title            string    `description:"日历显示的标题"`
+	ResearcherMobile string    `description:"研究员+协同人员手机号(多个使用逗号拼接)"`
+	ModifyTime       time.Time `description:"更新时间"`
+	CreateTime       time.Time `description:"关系建立时间"`
+}
+
+// RsCalendarResearcherRelationInfo
+type RsCalendarResearcherRelationInfo struct {
+	RsCalendarResearcherId int    `orm:"column(rs_calendar_researcher_id);pk"`
+	CalendarType           int8   `description:"日历类型;1:路演;2:事项"`
+	ThirdCalendarId        int    `description:"第三方路演id"`
+	RsCalendarId           int    `description:"日历活动id"`
+	ResearcherId           int    `description:"研究员id"`
+	ResearcherName         string `description:"研究员名称"`
+	StartDate              string `description:"开始日期"`
+	EndDate                string `description:"结束日期"`
+	StartTime              string `description:"开始时间"`
+	EndTime                string `description:"结束时间"`
+	StartWeek              string `description:"开始日期对应周"`
+	EndWeek                string `description:"结束日期对应周"`
+	CreateTime             time.Time
+	ModifyTime             time.Time
+	Status                 int       `description:"状态:1:待接受,2:已接受,3:已拒绝,4:已删除,5:已撤回,6:已结束"`
+	RefuseReason           string    `description:"拒绝理由"`
+	RefuseTime             time.Time `description:"拒绝时间"`
+	DeleteReason           string    `description:"删除理由"`
+	DeleteTime             time.Time `description:"删除时间"`
+	ApproveTime            time.Time `description:"接受时间"`
+	IsSynced               int       `description:"是否与上海同步 0:未同步 1:已同步"`
+	ResearcherSort         int       `description:"研究员新增排序"`
+}
+
+// GetRsCalendarRelationListByThirdIds 根据第三方id集合获取所有的关系列表
+func GetRsCalendarRelationListByThirdIds(thirdCalendarIds []int) (items []*RsCalendarRelation, err error) {
+	if len(thirdCalendarIds) <= 0 {
+		return
+	}
+	thirdCalendarIdStr := utils.Implode(thirdCalendarIds)
+	o := orm.NewOrm()
+	sql := `SELECT * FROM rs_calendar_relation WHERE third_calendar_id in (` + thirdCalendarIdStr + `) `
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+// GetRsCalendarResearcherInfoIByResearcherIdAndDate 根据研究员和开始/结束日期获取上海的活动路演
+func GetRsCalendarResearcherInfoIByResearcherIdAndDate(startDate, endDate string) (items []*RsCalendarResearcherRelationInfo, err error) {
+	o := orm.NewOrm()
+	//杭州创建的路演活动,如果上海被删除了,那么也要同步删除杭州的(所以相对于上面的逻辑,下面移除了来源的where条件)
+	sql := `SELECT a.*,c.third_calendar_id,c.calendar_type FROM rs_calendar_researcher a 
+join rs_calendar b on a.rs_calendar_id=b.rs_calendar_id
+join rs_calendar_relation c on a.rs_calendar_researcher_id=c.self_calendar_id
+WHERE a.status=2 and c.calendar_type=1  and start_date>=? and end_date <= ? `
+	_, err = o.Raw(sql, startDate, endDate).QueryRows(&items)
+	return
+}

+ 41 - 0
models/roadshow/shanghai_calendar.go

@@ -0,0 +1,41 @@
+package roadshow
+
+type GetTokenResp struct {
+	Code      int       `json:"code"`
+	Msg       string    `json:"msg"`
+	Time      int       `json:"time"`
+	TokenData TokenData `json:"data"`
+}
+
+type UserCalendar struct {
+	ID               int    `json:"id" description:"关系id" `
+	UserId           int    `json:"user_id" description:"创建人id" `
+	UserPhone        string `json:"user_phone" description:"创建人手机号" `
+	UserName         string `json:"user_name" description:"创建人昵称" `
+	ProjectName      string `json:"project_name" description:"活动名称" `
+	ProjectId        int    `json:"project_id" description:"活动id" `
+	CustomerId       string `json:"customer_id" description:"客户id" `
+	CustomerName     string `json:"customer_name" description:"客户名称" `
+	CustomerSocial   string `json:"customer_social" description:"客户社会信用码" `
+	ProjectType      int    `json:"project_type" description:"活动类型:1=沙龙,2=路演,3=专家需求,4=研究需求,5=电话,6=面谈,7=专题需求,8=线下沙龙,9=公司调研"`
+	ProjectFormType  int    `json:"project_form_type" description:"服务形式:1=沙龙,2=路演,3=专家需求,4=研究需求,5=电话,6=面谈,7=专题需求"`
+	Room             int    `json:"room" description:"会议室id"`
+	StartTime        int    `json:"start_time" description:"开始时间戳"`
+	EndTime          int    `json:"end_time" description:"结束时间戳"`
+	Content          string `json:"content" description:"活动内容"`
+	FeedExpert       string `json:"feed_expert" description:"邀请的专家"`
+	Title            string `json:"title" description:"日历显示的标题"`
+	ResearcherMobile string `json:"researcher_mobile" description:"研究员+协同人员手机号(多个使用逗号拼接)"`
+}
+
+type TokenData struct {
+	AccessToken string `json:"access_token"`
+	ExpireIn    int    `json:"expire_in"`
+}
+
+type UserCalendarList struct {
+	Code int            `json:"code"`
+	Msg  string         `json:"msg"`
+	Time int            `json:"time"`
+	Data []UserCalendar `json:"data"`
+}

+ 569 - 0
services/roadshow/calendar.go

@@ -2,8 +2,19 @@ package roadshow
 
 import (
 	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/http"
+	"hongze/hongze_task/models"
+	"hongze/hongze_task/models/cygx"
 	"hongze/hongze_task/models/roadshow"
+	"hongze/hongze_task/services/alarm_msg"
 	"hongze/hongze_task/utils"
+	"io/ioutil"
+	netHttp "net/http"
+	"net/url"
+	"strings"
 	"sync"
 	"time"
 )
@@ -38,3 +49,561 @@ func ModifyRsCalendarResearcherStatus(cont context.Context) (err error) {
 	lock.Unlock()
 	return err
 }
+
+// ShResponse 上海数据返回结构体
+type ShResponse struct {
+	Code int         `json:"code" description:"1:正常返回;4001:token失效"`
+	Msg  string      `json:"msg" description:"文字描述"`
+	Time int         `json:"time" description:"时间戳"`
+	Data interface{} `json:"data" description:"业务数据"`
+}
+
+// getCurl get请求上海接口
+func getCurl(urlStr string, params url.Values, num int) (body []byte, err error) {
+	if err != nil {
+		go alarm_msg.SendAlarmMsg("get请求上海接口失败,ERR:"+err.Error(), 3)
+		//go utils.SendEmail(utils.APPNAME+"get请求上海接口失败:"+time.Now().Format("2006-01-02 15:04:05"), "get请求上海接口失败:"+err.Error(), utils.EmailSendToUsers)
+	}
+	token, err := GetAccessToken(false)
+	if err != nil {
+		return
+	}
+	params.Add("access_token", token)
+	getUrl := urlStr + "?" + params.Encode()
+	body, err = http.Get(getUrl)
+	if err != nil {
+		utils.FileLog.Info(fmt.Sprint("get Err:", err.Error(), ";url:", getUrl, ";params:", params.Encode(), ";response:", string(body)))
+		err = errors.New("NewRequest Err:" + err.Error())
+		return
+	}
+
+	var response ShResponse
+	err = json.Unmarshal(body, &response)
+	if err != nil {
+		utils.FileLog.Info(fmt.Sprint("get Err:", err.Error(), ";url:", getUrl, ";params:", params.Encode(), ";response:", string(body)))
+		err = errors.New("Unmarshal Err:" + err.Error())
+		return
+	}
+
+	//如果是token失效,同时只是第一次请求(没有尝试强制刷新token,那么重新请求)
+	if response.Code == 4001 && num <= 0 {
+		utils.FileLog.Info(fmt.Sprint("get data err", ";url:", getUrl, ";params:", params.Encode(), ";response:", string(body)))
+
+		//token失效
+		_, tmpErr := refreshAccessToken()
+		if tmpErr != nil {
+			err = tmpErr
+		}
+		num++
+		params.Del("access_token")
+		return getCurl(urlStr, params, num)
+	} else if response.Code != 1 {
+		utils.FileLog.Info(fmt.Sprint("get data err", ";url:", getUrl, ";params:", params.Encode(), ";response:", string(body)))
+		err = errors.New(response.Msg)
+		return
+	}
+	return
+}
+
+// postCurl post请求上海接口
+func postCurl(urlStr string, form url.Values, num int) (body []byte, err error, errMsg string) {
+	logMsg := ``
+	defer func() {
+		if err != nil {
+			if logMsg != `` {
+				errMsg = logMsg
+				go alarm_msg.SendAlarmMsg("post请求上海接口失败,ERR:"+err.Error()+";errMsg:"+errMsg, 3)
+				//go utils.SendEmail(utils.APPNAME+"post请求上海接口失败:"+time.Now().Format("2006-01-02 15:04:05"), "post请求上海接口失败:"+errMsg, utils.EmailSendToUsers)
+			}
+		}
+	}()
+	token, err := GetAccessToken(false)
+	if err != nil {
+		return
+	}
+	finalUrl := urlStr + "?access_token=" + token
+
+	//发送创建请求
+	resp, err := netHttp.PostForm(finalUrl, form)
+	if err != nil {
+		err = errors.New("NewRequest Err:" + err.Error())
+		return
+	}
+
+	defer resp.Body.Close()
+
+	//解析resp并且存入关联表
+	body, err = ioutil.ReadAll(resp.Body)
+	if err != nil {
+		logMsg = fmt.Sprint("post err; request:", form.Encode(), "; errMsg:", err.Error())
+		utils.FileLog.Info(logMsg)
+		return
+	}
+	logMsg = fmt.Sprint("post request:", form.Encode(), "; response:", string(body))
+	utils.FileLog.Info(logMsg)
+
+	var response ShResponse
+	err = json.Unmarshal(body, &response)
+	if err != nil {
+		utils.FileLog.Info("post Err:", err.Error(), ";url:", finalUrl, ";params:", form.Encode(), ";response:", string(body))
+		err = errors.New("Unmarshal Err:" + err.Error())
+		return
+	}
+	utils.FileLog.Info(fmt.Sprint("post request url:", finalUrl, ";params:", form.Encode(), ";response:", string(body)))
+
+	//如果是token失效,同时只是第一次请求(没有尝试强制刷新token,那么重新请求)
+	if response.Code == 4001 && num <= 0 {
+		//token失效
+		_, tmpErr := refreshAccessToken()
+		if tmpErr != nil {
+			err = tmpErr
+		}
+		num++
+		return postCurl(urlStr, form, num)
+	} else if response.Code != 1 {
+		utils.FileLog.Info(fmt.Sprint("post data err", ";url:", finalUrl, ";params:", form.Encode(), ";response:", string(body)))
+		err = errors.New(response.Msg)
+		return
+	}
+	return
+}
+
+// GetAccessToken 获取accessToken
+func GetAccessToken(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("SH_ACCESS_TOKEN")
+	//如果从redis中accessToken 获取失败或者token为空了,再或者需要强制刷新了,那么重新获取accessToken
+	if redisErr != nil || token == `` || isRefresh {
+		return refreshAccessToken()
+	}
+	return
+}
+
+// getAccessToken token内部请求接口
+func getAccessToken() (tokenData roadshow.TokenData, 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)
+		}
+	}()
+	getUrl := fmt.Sprintf(utils.CRM_OPEN_API_URL+"/v1/auth/getAccessToken?app_key=%s&app_secret=%s", utils.CRM_OPEN_API_APP_KEY, utils.CRM_OPEN_API_APP_SECRET)
+	body, err := http.Get(getUrl)
+	if err != nil {
+		err = errors.New("NewRequest Err:" + err.Error())
+		return
+	}
+
+	var tokenResp roadshow.GetTokenResp
+	err = json.Unmarshal(body, &tokenResp)
+	if err != nil {
+		err = errors.New("Unmarshal Err:" + err.Error())
+		return
+	}
+	if tokenResp.Code != 1 {
+		err = errors.New("getAccessToken err:" + tokenResp.Msg)
+		return
+	}
+	tokenData = tokenResp.TokenData
+	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)
+		}
+	}()
+	tokenInfo, tmpErr := getAccessToken()
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	token = tokenInfo.AccessToken
+
+	//token存入redis
+	err = utils.Rc.Put("SH_ACCESS_TOKEN", token, time.Duration(tokenInfo.ExpireIn-600)*time.Second)
+	if err != nil {
+		go alarm_msg.SendAlarmMsg("获取上海的token失败;上海token存入redis失败,ERR:"+err.Error(), 3)
+		//go utils.SendEmail(utils.APPNAME+"获取上海的token失败:"+time.Now().Format("2006-01-02 15:04:05"), "上海token存入redis失败:", utils.EmailSendToUsers)
+	}
+	return
+}
+
+// getCalendarFrom 获取上海方的路演活动列表
+func getCalendarFrom(userPhone, startDate, endDate string) (list []roadshow.UserCalendar, err error) {
+	exUrl := utils.CRM_OPEN_API_URL + "/v1/calendar/userCalendarList"
+	form := url.Values{
+		"user_phone": {userPhone},
+		"start_time": {startDate},
+		"end_time":   {endDate},
+	}
+	body, err := getCurl(exUrl, form, 0)
+	if err != nil {
+		err = errors.New("NewRequest Err:" + err.Error())
+		return
+	}
+	var userCalendarList roadshow.UserCalendarList
+	err = json.Unmarshal(body, &userCalendarList)
+	if err != nil {
+		err = errors.New("Unmarshal Err:" + err.Error())
+		return
+	}
+	list = userCalendarList.Data
+	return
+}
+
+// SyncCalendarFromShanghai 上海路演数据同步到自系统
+func SyncCalendarFromShanghai77() (err error) {
+	errMsgList := make([]string, 0)
+	defer func() {
+		if len(errMsgList) > 0 {
+			//fmt.Println("err:", errMsg)
+			if err != nil {
+				errMsgList = append(errMsgList, fmt.Sprint("ERR:"+err.Error(), ";"))
+			}
+			go alarm_msg.SendAlarmMsg("上海路演数据同步到自系统失败;errMsg:"+strings.Join(errMsgList, "\n"), 3)
+			//go utils.SendEmail(utils.APPNAME+"上海路演数据同步到自系统失败:"+time.Now().Format("2006-01-02 15:04:05"), errMsg, utils.EmailSendToUsers)
+		}
+	}()
+
+	var mobiles []string
+	mobilesMap := make(map[string]bool)
+	researcherList, err := roadshow.GetResearcher()
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	for _, v := range researcherList {
+		if v.Mobile == "" {
+			continue
+		}
+		if mobilesMap[v.Mobile] {
+			continue
+		}
+		mobiles = append(mobiles, v.Mobile)
+		mobilesMap[v.Mobile] = true
+	}
+	askUserList, err := cygx.GetAskEmailList()
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	for _, v := range askUserList {
+		if v.Mobile == "" {
+			continue
+		}
+		if mobilesMap[v.Mobile] {
+			continue
+		}
+		mobiles = append(mobiles, v.Mobile)
+		mobilesMap[v.Mobile] = true
+	}
+
+	//查询管理员信息列表
+	adminList, e := models.GetAdminByAdminMobiles(mobiles)
+	if e != nil {
+		err = fmt.Errorf("查询管理员信息列表失败 Err:%s\n", e)
+
+		return
+	}
+	mapUserInfo := make(map[string]*models.Admin)
+
+	for _, v := range adminList {
+		mapUserInfo[v.Mobile] = v
+	}
+
+	fmt.Println(len(mobiles))
+	//return
+	//userPhone := v
+	startDate := time.Now().AddDate(0, 0, -30).Format(utils.FormatDate)
+	endDate := time.Now().AddDate(0, 0, 30).Format(utils.FormatDate)
+	var userPhone string
+
+	var list []roadshow.UserCalendar
+	for k, v := range mobiles {
+		if v == "" {
+			continue
+		}
+		fmt.Println(k, "___", v)
+
+		//return
+		userPhone = v
+		//以当前日期作为起始日期去同步
+		listSh, err := getCalendarFrom(userPhone, startDate, endDate)
+		if err != nil {
+			errMsgList = append(errMsgList, fmt.Sprint("获取第三方路演日历数据失败,", "userPhone:", userPhone, ";currDay:", startDate, ";endDate:", endDate, ";err:"+err.Error()))
+			return
+		}
+
+		for _, vSh := range listSh {
+			list = append(list, vSh)
+		}
+	}
+
+	////获取当前研究员信息
+	//userPhoneInfo, err := roadshowService.GetAdminInfo(userPhone)
+	//if err != nil {
+	//	errMsgList = append(errMsgList, fmt.Sprint("获取手机号信息失败:手机号:", userPhone, ";err:"+err.Error(), ";"))
+	//	return
+	//}
+
+	//根据研究员和开始/结束日期获取上海的活动路演
+	rsCalendarResearcherList, err := roadshow.GetRsCalendarResearcherInfoIByResearcherIdAndDate(startDate, endDate)
+	if err != nil {
+		errMsgList = append(errMsgList, fmt.Sprint("获取研究员日程信息失败:手机号:", userPhone, ";err:"+err.Error(), ";"))
+		return
+	}
+	//待删除的活动路演
+	deleteRsCalendarResearcherMap := make(map[int][]*roadshow.RsCalendarResearcherRelationInfo)
+	for _, v := range rsCalendarResearcherList {
+		tmpList, ok := deleteRsCalendarResearcherMap[v.ThirdCalendarId]
+		if !ok {
+			tmpList = make([]*roadshow.RsCalendarResearcherRelationInfo, 0)
+		}
+		tmpList = append(tmpList, v)
+
+		deleteRsCalendarResearcherMap[v.ThirdCalendarId] = tmpList
+	}
+
+	thirdIdList := make([]int, 0)
+	if len(list) > 0 {
+		for _, v := range list {
+			thirdIdList = append(thirdIdList, v.ID)
+			//移除还存在的活动,保留不存在的活动
+			delete(deleteRsCalendarResearcherMap, v.ID)
+		}
+		rsCalendarRelationList, tmpErr := roadshow.GetRsCalendarRelationListByThirdIds(thirdIdList)
+		if tmpErr != nil {
+			err = tmpErr
+			errMsgList = append(errMsgList, "获取关联列表失败,err:"+tmpErr.Error())
+			return
+		}
+
+		rsCalendarRelationMap := make(map[int]*roadshow.RsCalendarRelation)
+
+		var selfCalendarIds []int
+		for _, rsCalendarRelation := range rsCalendarRelationList {
+			rsCalendarRelationMap[rsCalendarRelation.ThirdCalendarId] = rsCalendarRelation
+			selfCalendarIds = append(selfCalendarIds, rsCalendarRelation.SelfCalendarId)
+		}
+		rsCalendarResearcherInfoList, tmpErr := roadshow.GetRsCalendarResearcherByIds(selfCalendarIds)
+		if tmpErr != nil {
+			errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", selfCalendarIds, "获取路演研究员信息失败;err:"+tmpErr.Error(), ";"))
+			return
+		}
+		maprsCalendarResearcherInfo := make(map[int]*roadshow.RsCalendarResearcher)
+
+		var rsCalendarIds []int
+		for _, v := range rsCalendarResearcherInfoList {
+			maprsCalendarResearcherInfo[v.RsCalendarResearcherId] = v
+			rsCalendarIds = append(rsCalendarIds, v.RsCalendarId)
+		}
+		for _, v := range list {
+			//展示优先级:1、customer_name 2、project_name 3、title 需求池953
+			if v.CustomerName != "" {
+				v.Title = v.CustomerName
+			} else if v.ProjectName != "" {
+				v.Title = v.ProjectName
+			}
+			if rsCalendarRelation, ok := rsCalendarRelationMap[v.ID]; ok {
+				//存在的话,那么就去查找对应的信息
+				if rsCalendarRelation.CalendarType == 1 {
+					//路演
+					rsCalendarResearcherInfo, tmpErr := roadshow.GetRsCalendarResearcherById(rsCalendarRelation.SelfCalendarId)
+					if tmpErr != nil {
+						errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取路演研究员信息失败;err:"+tmpErr.Error(), ";"))
+						continue
+					}
+					rsCalendarInfo, tmpErr := roadshow.GetRsCalendarById(rsCalendarResearcherInfo.RsCalendarId)
+					if tmpErr != nil {
+						errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取路演信息失败;err:"+tmpErr.Error(), ";"))
+						continue
+					}
+					if rsCalendarInfo.Source == 0 { //自系统创建的路演活动,不需要依靠上海方来修改
+						continue
+					}
+
+					//是否去同步变更数据库
+					isUpdateSync := false
+
+					//是否变更
+					isUpdate := false
+					if v.StartTime != rsCalendarRelation.StartTime {
+						isUpdate = true
+					}
+					if v.EndTime != rsCalendarRelation.EndTime {
+						isUpdate = true
+					}
+					if v.Title != rsCalendarRelation.Title {
+						isUpdate = true
+					}
+					if rsCalendarResearcherInfo.Status == 4 { // 被删除了,现在是需要更新
+						isUpdate = true
+					}
+
+					researcherList := make([]system.AdminItem, 0)
+					researcherMap := make(map[int]system.AdminItem)
+
+					addResearcherList := make([]system.AdminItem, 0)                  // 需要新增的研究员
+					delResearcherIdList := make([]int, 0)                             //需要删除的路演活动与研究员的关系id
+					updateResearcherList := make([]*roadshow.RsCalendarResearcher, 0) //待更新的路演活动中研究员信息
+
+					if v.ResearcherMobile != rsCalendarRelation.ResearcherMobile {
+						//研究员变更了,需要去改表
+						isUpdateSync = true
+
+						researcherMobileList := strings.Split(v.ResearcherMobile, ",")
+						if len(researcherMobileList) > 0 {
+							for _, mobile := range researcherMobileList {
+								researcherInfo, tmpErr := mapUserInfo[mobile]
+								if tmpErr != nil {
+									errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取研究员失败,研究员手机号:", mobile, ";err:"+tmpErr.Error(), ";"))
+									continue
+								}
+								if researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_RESEARCHR ||
+									researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RESEARCHR ||
+									researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_RESEARCHR ||
+									researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_DEPARTMENT ||
+									researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_DEPARTMENT ||
+									researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_SELLER ||
+									researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_ADMIN {
+
+									researcherList = append(researcherList, researcherInfo)
+									researcherMap[researcherInfo.AdminId] = researcherInfo
+								}
+							}
+						}
+
+						//没有研究员
+						if len(researcherList) <= 0 {
+							errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, ";对方研究员信息失败;"))
+							continue
+						}
+
+						rsCalendarResearcherList, tmpErr := roadshow.GetRsCalendarResearcherListByRsCalendarId(rsCalendarInfo.RsCalendarId)
+						if tmpErr != nil {
+							errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取路演活动中的研究员列表失败,路演活动ID:", rsCalendarInfo.RsCalendarId, ";err:"+tmpErr.Error(), ";"))
+							continue
+						}
+
+						//现有活动中的研究员
+						rsCalendarResearcherMap := make(map[int]*roadshow.RsCalendarResearcher)
+						for _, rsCalendarResearcher := range rsCalendarResearcherList {
+							if _, ok := researcherMap[rsCalendarResearcher.ResearcherId]; ok {
+								if isUpdate {
+									updateResearcherList = append(updateResearcherList, rsCalendarResearcher)
+								}
+							} else {
+								delResearcherIdList = append(delResearcherIdList, rsCalendarResearcher.RsCalendarResearcherId)
+							}
+
+							rsCalendarResearcherMap[rsCalendarResearcher.ResearcherId] = rsCalendarResearcher
+						}
+
+						//校验是否需要新增研究员
+						for adminId, researcherInfo := range researcherMap {
+							//如果
+							if _, ok := rsCalendarResearcherMap[adminId]; !ok {
+								addResearcherList = append(addResearcherList, researcherInfo)
+							}
+						}
+					} else if isUpdate { //如果有字段更新,那么需要将所有的研究员信息更新
+						isUpdateSync = true
+
+						rsCalendarResearcherList, tmpErr := roadshow.GetRsCalendarResearcherListByRsCalendarId(rsCalendarInfo.RsCalendarId)
+						if tmpErr != nil {
+							errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取路演活动中的研究员列表失败,路演活动ID:", rsCalendarInfo.RsCalendarId, ";err:"+tmpErr.Error(), ";"))
+							continue
+						}
+						for _, rsCalendarResearcher := range rsCalendarResearcherList {
+							updateResearcherList = append(updateResearcherList, rsCalendarResearcher)
+						}
+					}
+
+					if isUpdateSync {
+						tmpErr = roadshow.UpdateSyncRsCalendarRelation(v, rsCalendarInfo, rsCalendarRelation, updateResearcherList, delResearcherIdList, addResearcherList)
+						if tmpErr != nil {
+							err = tmpErr
+							errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "修改关联关系失败;err:"+tmpErr.Error(), ";"))
+							return
+						}
+					}
+				} else {
+					//事项
+					//事项都是由自系统创建的,不需要依靠上海方来修改
+				}
+			} else {
+				//数据不存在
+				createUser, tmpErr := roadshowService.GetAdminInfo(v.UserPhone)
+				if tmpErr != nil {
+					errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取创建人失败,创建人手机号:", v.UserPhone, ";err:"+tmpErr.Error(), ";"))
+					continue
+				}
+
+				//研究员列表
+				researcherList := make([]system.AdminItem, 0)
+				researcherMobileList := strings.Split(v.ResearcherMobile, ",")
+				if len(researcherMobileList) > 0 {
+					for _, mobile := range researcherMobileList {
+						researcherInfo, tmpErr := roadshowService.GetAdminInfo(mobile)
+						if tmpErr != nil {
+							errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "获取研究员失败,研究员手机号:", mobile, ";err:"+tmpErr.Error(), ";"))
+							continue
+						}
+						if researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_RESEARCHR ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RESEARCHR ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_RESEARCHR ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_DEPARTMENT ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_DEPARTMENT ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_SELLER ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_ADMIN ||
+							researcherInfo.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN {
+							researcherList = append(researcherList, researcherInfo)
+						}
+					}
+				}
+
+				//没有研究员
+				if len(researcherList) <= 0 {
+					continue
+				}
+				//数据入库
+				tmpErr = roadshow.SyncRsCalendarRelation(v, createUser, researcherList)
+				if tmpErr != nil {
+					err = tmpErr
+					errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", v.ID, "绑定关联关系失败;err:"+tmpErr.Error(), ";"))
+					continue
+				}
+				//fmt.Println("createUser:", createUser)
+			}
+
+		}
+	}
+
+	////上海那边已经删除了路演,这边也要同步删除
+	//for _, deleteRsCalendarResearcherList := range deleteRsCalendarResearcherMap {
+	//	for _, deleteRsCalendarResearcher := range deleteRsCalendarResearcherList {
+	//		// 更新路演与研究员关系表的状态字段
+	//		whereParams := make(map[string]interface{})
+	//		updateParams := make(map[string]interface{})
+	//		whereParams["rs_calendar_researcher_id"] = deleteRsCalendarResearcher.RsCalendarResearcherId
+	//		updateParams["status"] = 4
+	//		updateParams["modify_time"] = time.Now()
+	//		tmpErr := roadshow.UpdateCalendarResearcher(whereParams, updateParams)
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			errMsgList = append(errMsgList, fmt.Sprint("第三方日历ID:", deleteRsCalendarResearcher.ThirdCalendarId, "删除关联关系失败;err:"+tmpErr.Error(), ";"))
+	//			continue
+	//		}
+	//	}
+	//}
+	return
+}

+ 16 - 5
utils/common.go

@@ -853,19 +853,21 @@ const (
 	letterIdxBits = 4
 	letterIdxMask = 1<<letterIdxBits - 1
 )
+
 var src = rand.NewSource(time.Now().UnixNano())
 
 var headerNums = [...]string{"139", "138", "137", "136", "135", "134", "159", "158", "157", "150", "151", "152", "188", "187", "182", "183", "184", "178", "130", "131", "132", "156", "155", "186", "185", "176", "133", "153", "189", "180", "181", "177"}
 var headerNumsLen = len(headerNums)
+
 const (
 	headerIdxBits = 6
 	headerIdxMask = 1<<headerIdxBits - 1
 )
 
 func getHeaderIdx(cache int64) int {
-	for cache > 0{
+	for cache > 0 {
 		idx := int(cache & headerIdxMask)
-		if idx < headerNumsLen{
+		if idx < headerNumsLen {
 			return idx
 		}
 		cache >>= headerIdxBits
@@ -877,11 +879,11 @@ func RandomPhone() string {
 	b := make([]byte, 12)
 	cache := src.Int63()
 	headerIdx := getHeaderIdx(cache)
-	for i := 0; i < 3; i++{
+	for i := 0; i < 3; i++ {
 		b[i] = headerNums[headerIdx][i]
 	}
-	for i := 3; i < 12 ; {
-		if cache == 0{
+	for i := 3; i < 12; {
+		if cache == 0 {
 			cache = src.Int63()
 		}
 		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
@@ -914,3 +916,12 @@ func MakePostRequest(url string, body []byte, headers map[string]string) (*http.
 
 	return resp, nil
 }
+
+// Implode php中的implode(用来将int型的切片转为string)
+func Implode(idIntList []int) (str string) {
+	for _, id := range idIntList {
+		str += fmt.Sprint(id, ",")
+	}
+	str = str[:len(str)-1]
+	return
+}

+ 7 - 0
utils/config.go

@@ -94,6 +94,13 @@ var (
 	EDB_LIB_URL string
 )
 
+// 上海crm开放api配置
+var (
+	CRM_OPEN_API_URL        string
+	CRM_OPEN_API_APP_KEY    string
+	CRM_OPEN_API_APP_SECRET string
+)
+
 // 进门财经账号信息
 var (
 	COMEIN_URL                string