Эх сурвалжийг харах

Merge branch 'CRM_15.6'

# Conflicts:
#	models/company/company.go
#	services/statistic_report/company.go
zwxi 1 жил өмнө
parent
commit
17868a31f9

+ 4 - 2
controllers/company_share.go

@@ -332,9 +332,11 @@ func (this *CompanyController) CompanyShareList() {
 		sortStr += fmt.Sprintf(` %s`, sortType)
 	} else {
 		if roleTypeCode == utils.ROLE_TYPE_CODE_ADMIN {
-			sortStr = " ORDER BY sort_status asc, all_view_total desc, a.created_time "
+			//sortStr = " ORDER BY sort_status asc, all_view_total desc, a.created_time "
+			sortStr = " ORDER BY start_date DESC, all_view_total desc, a.created_time "
 		} else {
-			sortStr = " ORDER BY sort_status asc, b.view_total desc, a.created_time  "
+			//sortStr = " ORDER BY sort_status asc, b.view_total desc, a.created_time  "
+			sortStr = " ORDER BY start_date DESC, b.view_total desc, a.created_time "
 		}
 		sortStr += " DESC "
 	}

+ 1 - 1
controllers/roadshow/calendar.go

@@ -973,7 +973,7 @@ func (this *CalendarController) ResearcherList() {
 		return
 	}
 	researcherList, err := roadshow.GetResearcher()
-	groupMap := make(map[int][]*roadshow.Researcher)
+	groupMap := make(map[int][]*roadshow.ResearcherGroup)
 	for _, v := range researcherList {
 		//if v.RoleTypeCode == "ficc_admin" {
 		//	findItems := groupMap[1]

+ 419 - 1
controllers/roadshow/report.go

@@ -85,7 +85,7 @@ func (this *CalendarController) ResearcherReportList() {
 		br.ErrMsg = "获取分组信息失败!,GetResearcherV2 Err:" + err.Error()
 		return
 	}
-	groupMap := make(map[int][]*roadshow.Researcher)
+	groupMap := make(map[int][]*roadshow.ResearcherGroup)
 	for _, v := range researcherList {
 		//if v.RoleTypeCode == "ficc_admin" {
 		//	findItems := groupMap[1]
@@ -1280,3 +1280,421 @@ func (this *CalendarController) OverseasCustomCalendarAdminList() {
 	br.Data = list
 	return
 }
+
+// OverseasSellerReportList
+// @Title 海外客户销售路演统计
+// @Description 海外客户销售路演统计接口
+// @Param   DataType   query   string  true       "枚举值:week、month、time_interval、online、offline"
+// @Param   DimensionType   query   string  true       "维度枚举值:company_status、roadshow_type"
+// @Param   StartDate   query   string  true       "开始日期,格式:2022-04-06"
+// @Param   EndDate   query   string  true       "结束日期,格式:2022-04-06"
+// @Success 200 {object} roadshow.RsReportRecordResp
+// @router /overseas_custom/seller/list [get]
+func (this *CalendarController) OverseasSellerReportList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	dataType := this.GetString("DataType")
+	dimensionType := this.GetString("DimensionType")
+	startDate := this.GetString("StartDate")
+	endDate := this.GetString("EndDate")
+
+	if dimensionType == "" {
+		dimensionType = "company_status"
+	}
+
+	var adminDataList []roadshowService.OverseasAdminDataMap
+	var err error
+
+	//获取列表
+	switch dataType {
+	case "week":
+		adminDataList, _, err = roadshowService.GetOverseasWeekDataV2("seller", dimensionType, 6)
+		if err != nil {
+			br.Msg = "数据异常"
+			br.ErrMsg = "数据异常,Err:" + err.Error()
+			return
+		}
+	case "month":
+		adminDataList, _, err = roadshowService.GetOverseasMonthDataV2("seller", dimensionType, 6)
+		if err != nil {
+			br.Msg = "数据异常"
+			br.ErrMsg = "数据异常,Err:" + err.Error()
+			return
+		}
+	case "time_interval":
+		if startDate == `` || endDate == `` {
+			br.Msg = "开始日期或结束日期不能为空"
+			br.ErrMsg = "开始日期或结束日期不能为空,Err:" + err.Error()
+			return
+		}
+		adminDataList, _, err = roadshowService.GetOverseasTimeIntervalData(startDate, endDate, "seller", dimensionType)
+		if err != nil {
+			br.Msg = "数据异常"
+			br.ErrMsg = "数据异常,Err:" + err.Error()
+			return
+		}
+
+	}
+
+	sellerList, err := roadshow.GetOverseaCustomCalendarSellerList()
+
+	adminReportRecordList := make([]roadshow.OverseasAdminReportRecord, 0)
+	rsAllReportRecordNumList := make([]roadshow.RsOverseasReportRecordNum, 0)
+	RsReportRecordResp := roadshow.RsOverseasReportRecordResp{
+		List:                  adminReportRecordList,
+		RsReportRecordNumList: rsAllReportRecordNumList,
+	}
+
+	startDateIndexList := make(map[int]string) //开始时间间隔map
+	endDateIndexList := make(map[int]string)   //结束时间间隔map
+
+	tmpAllTryOutNumMap := make(map[int]int)
+	tmpAllFormalNumMap := make(map[int]int)
+	tmpAllCloseNumMap := make(map[int]int)
+	tmpAllOnlineNumMap := make(map[int]int)
+	tmpAllOfflineNumMap := make(map[int]int)
+
+	for _, researcher := range sellerList {
+		//每个区间的数据
+		tmpAdminRsReportRecordNumList := make([]roadshow.RsOverseasReportRecordNum, 0)
+		for index, adminData := range adminDataList {
+			startDateIndexList[index] = adminData.StartDate
+			endDateIndexList[index] = adminData.EndDate
+
+			var tmpTryOutNum, tmpFormalNum, tmpCloseNum, tmpOnlineNum, tmpOfflineNum int
+			if num, ok := adminData.TryOutMap[researcher.AdminId]; ok {
+				tmpTryOutNum = num
+			}
+			if num, ok := adminData.FormalMap[researcher.AdminId]; ok {
+				tmpFormalNum = num
+			}
+			if num, ok := adminData.CloseMap[researcher.AdminId]; ok {
+				tmpCloseNum = num
+			}
+			if num, ok := adminData.OnlineMap[researcher.AdminId]; ok {
+				tmpOnlineNum = num
+			}
+			if num, ok := adminData.OfflineMap[researcher.AdminId]; ok {
+				tmpOfflineNum = num
+			}
+			tmpAdminRsReportRecordNum := roadshow.RsOverseasReportRecordNum{
+				TryOutNum:  tmpTryOutNum,
+				FormalNum:  tmpFormalNum,
+				CloseNum:   tmpCloseNum,
+				OnlineNum:  tmpOnlineNum,
+				OfflineNum: tmpOfflineNum,
+				StartDate:  adminData.StartDate,
+				EndDate:    adminData.EndDate,
+			}
+			tmpAdminRsReportRecordNumList = append(tmpAdminRsReportRecordNumList, tmpAdminRsReportRecordNum)
+
+			//总数据汇总
+			if _, ok := tmpAllTryOutNumMap[index]; !ok {
+				tmpAllTryOutNumMap[index] = 0
+			}
+			if _, ok := tmpAllFormalNumMap[index]; !ok {
+				tmpAllFormalNumMap[index] = 0
+			}
+			if _, ok := tmpAllCloseNumMap[index]; !ok {
+				tmpAllCloseNumMap[index] = 0
+			}
+			if _, ok := tmpAllOnlineNumMap[index]; !ok {
+				tmpAllOnlineNumMap[index] = 0
+			}
+			if _, ok := tmpAllOfflineNumMap[index]; !ok {
+				tmpAllOfflineNumMap[index] = 0
+			}
+			tmpAllTryOutNumMap[index] += tmpTryOutNum
+			tmpAllFormalNumMap[index] += tmpFormalNum
+			tmpAllCloseNumMap[index] += tmpCloseNum
+			tmpAllOnlineNumMap[index] += tmpOnlineNum
+			tmpAllOfflineNumMap[index] += tmpOfflineNum
+		}
+		tmpAdminReportRecord := roadshow.OverseasAdminReportRecord{
+			Name:                  researcher.RealName,
+			AdminId:               researcher.AdminId,
+			RsReportRecordNumList: tmpAdminRsReportRecordNumList,
+		}
+		RsReportRecordResp.List = append(RsReportRecordResp.List, tmpAdminReportRecord)
+	}
+
+	//总体汇总数据
+	for i := 0; i < len(tmpAllFormalNumMap); i++ {
+		tmpGroupRsReportRecordNum := roadshow.RsOverseasReportRecordNum{
+			TryOutNum:  tmpAllTryOutNumMap[i],
+			FormalNum:  tmpAllFormalNumMap[i],
+			CloseNum:   tmpAllCloseNumMap[i],
+			OnlineNum:  tmpAllOnlineNumMap[i],
+			OfflineNum: tmpAllOfflineNumMap[i],
+			StartDate:  startDateIndexList[i],
+			EndDate:    endDateIndexList[i],
+		}
+		rsAllReportRecordNumList = append(rsAllReportRecordNumList, tmpGroupRsReportRecordNum)
+	}
+	RsReportRecordResp.RsReportRecordNumList = rsAllReportRecordNumList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = RsReportRecordResp
+	return
+}
+
+// OverseasResearcherReportList
+// @Title 研究员路演统计
+// @Description 研究员路演统计接口
+// @Param   DataType   query   string  true       "枚举值:week、month、time_interval"
+// @Param   StartDate   query   string  true       "开始日期,格式:2022-04-06"
+// @Param   EndDate   query   string  true       "结束日期,格式:2022-04-06"
+// @Success 200 {object} roadshow.RsReportRecordResp
+// @router /overseas_custom/researcher/list [get]
+func (this *CalendarController) OverseasResearcherReportList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	dataType := this.GetString("DataType")
+	startDate := this.GetString("StartDate")
+	endDate := this.GetString("EndDate")
+
+	var adminDataList []roadshowService.OverseasAdminDataMap
+	var err error
+	//var firstDate time.Time
+	//获取列表
+	switch dataType {
+	case "week":
+		adminDataList, _, err = roadshowService.GetOverseasWeekData("researcher", "company_status")
+		if err != nil {
+			br.Msg = "数据异常"
+			br.ErrMsg = "数据异常,Err:" + err.Error()
+			return
+		}
+	case "month":
+		adminDataList, _, err = roadshowService.GetOverseasMonthData("researcher", "company_status")
+		if err != nil {
+			br.Msg = "数据异常"
+			br.ErrMsg = "数据异常,Err:" + err.Error()
+			return
+		}
+	case "time_interval":
+		if startDate == `` || endDate == `` {
+			br.Msg = "开始日期或结束日期不能为空"
+			br.ErrMsg = "开始日期或结束日期不能为空,Err:" + err.Error()
+			return
+		}
+		adminDataList, _, err = roadshowService.GetOverseasTimeIntervalData(startDate, endDate, "researcher", "company_status")
+		if err != nil {
+			br.Msg = "数据异常"
+			br.ErrMsg = "数据异常,Err:" + err.Error()
+			return
+		}
+
+	}
+
+	researcherList, err := roadshow.GetOverseaCustomCalendarResearcherList()
+	if err != nil {
+		br.Msg = "获取信息失败!"
+		br.ErrMsg = "获取分组信息失败!,GetResearcherV2 Err:" + err.Error()
+		return
+	}
+
+	adminReportRecordList := make([]roadshow.OverseasAdminReportRecord, 0)
+	rsAllReportRecordNumList := make([]roadshow.RsOverseasReportRecordNum, 0)
+	RsReportRecordResp := roadshow.RsOverseasReportRecordResp{
+		List:                  adminReportRecordList,
+		RsReportRecordNumList: rsAllReportRecordNumList,
+	}
+
+	startDateIndexList := make(map[int]string) //开始时间间隔map
+	endDateIndexList := make(map[int]string)   //结束时间间隔map
+
+	tmpAllTryOutNumMap := make(map[int]int)
+	tmpAllFormalNumMap := make(map[int]int)
+	tmpAllMeetingNumMap := make(map[int]int)
+
+	for _, researcher := range researcherList {
+		//组内研究员数据
+
+		//每个区间的数据
+		tmpAdminRsReportRecordNumList := make([]roadshow.RsOverseasReportRecordNum, 0)
+		for index, adminData := range adminDataList {
+			startDateIndexList[index] = adminData.StartDate
+			endDateIndexList[index] = adminData.EndDate
+
+			var tmpTryOutNum, tmpFormalNum, tmpCloseNum int
+			if num, ok := adminData.TryOutMap[researcher.AdminId]; ok {
+				tmpTryOutNum = num
+			}
+			if num, ok := adminData.FormalMap[researcher.AdminId]; ok {
+				tmpFormalNum = num
+			}
+			if num, ok := adminData.CloseMap[researcher.AdminId]; ok {
+				tmpCloseNum = num
+			}
+			tmpAdminRsReportRecordNum := roadshow.RsOverseasReportRecordNum{
+				TryOutNum: tmpTryOutNum,
+				FormalNum: tmpFormalNum,
+				CloseNum:  tmpCloseNum,
+				StartDate: adminData.StartDate,
+				EndDate:   adminData.EndDate,
+			}
+			tmpAdminRsReportRecordNumList = append(tmpAdminRsReportRecordNumList, tmpAdminRsReportRecordNum)
+
+			//总数据汇总
+			if _, ok := tmpAllTryOutNumMap[index]; !ok {
+				tmpAllTryOutNumMap[index] = 0
+			}
+			if _, ok := tmpAllFormalNumMap[index]; !ok {
+				tmpAllFormalNumMap[index] = 0
+			}
+			if _, ok := tmpAllMeetingNumMap[index]; !ok {
+				tmpAllMeetingNumMap[index] = 0
+			}
+			tmpAllTryOutNumMap[index] += tmpTryOutNum
+			tmpAllFormalNumMap[index] += tmpFormalNum
+			tmpAllMeetingNumMap[index] += tmpCloseNum
+		}
+		tmpAdminReportRecord := roadshow.OverseasAdminReportRecord{
+			Name:                  researcher.RealName,
+			AdminId:               researcher.AdminId,
+			RsReportRecordNumList: tmpAdminRsReportRecordNumList,
+		}
+		RsReportRecordResp.List = append(RsReportRecordResp.List, tmpAdminReportRecord)
+	}
+
+	//总体汇总数据
+	for i := 0; i < len(tmpAllFormalNumMap); i++ {
+		tmpGroupRsReportRecordNum := roadshow.RsOverseasReportRecordNum{
+			TryOutNum: tmpAllTryOutNumMap[i],
+			FormalNum: tmpAllFormalNumMap[i],
+			CloseNum:  tmpAllMeetingNumMap[i],
+			StartDate: startDateIndexList[i],
+			EndDate:   endDateIndexList[i],
+		}
+		rsAllReportRecordNumList = append(rsAllReportRecordNumList, tmpGroupRsReportRecordNum)
+	}
+	RsReportRecordResp.RsReportRecordNumList = rsAllReportRecordNumList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = RsReportRecordResp
+	return
+}
+
+// OverseasCalendarList
+// @Title 海外客户路演详情列表
+// @Description 海外客户路演详情列表接口
+// @Param   AdminType   query   string  true       "枚举值:researcher、seller、 special:专项路演"
+// @Param   DataType   query   string  true       "枚举值:try_out、formal、close、online、offline"
+// @Param   AdminIds   query   string  true       "用户ids"
+// @Param   StartDate   query   string  true       "开始日期,格式:2022-04-06"
+// @Param   EndDate   query   string  true       "结束日期,格式:2022-04-06"
+// @Success 200 {object} []roadshow.RsReportRecordList
+// @router /overseas/calendar/list [get]
+func (this *CalendarController) OverseasCalendarList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	adminType := this.GetString("AdminType")
+	dataType := this.GetString("DataType")
+	startDate := this.GetString("StartDate")
+	endDate := this.GetString("EndDate")
+	adminIds := this.GetString("AdminIds")
+	if adminIds == "" {
+		br.Msg = "请传入对应的人员"
+		return
+	}
+
+	adminIdsArr := make([]int, 0)
+	adminIdSlice := strings.Split(adminIds, ",")
+	for _, v := range adminIdSlice {
+		id,_ := strconv.Atoi(v)
+		adminIdsArr = append(adminIdsArr, id)
+	}
+
+	//正式客户
+	var condition string
+	var pars []interface{}
+	condition = ` and a.start_date >= ? and a.end_date <= ? `
+	pars = append(pars, startDate, endDate)
+
+	//选择的人员类型(发起人还是被发起人)
+	if adminType == "seller" {
+		condition += ` and a.seller_id IN (` + utils.GetOrmInReplace(len(adminIdsArr)) + `)`
+	} else if adminType == "special" {
+		condition += ` and a.seller_id (` + utils.GetOrmInReplace(len(adminIdsArr)) + `)`
+		detail, err := company.GetConfigDetailByCode("choice_researcher_adminid")
+		if err != nil {
+			br.Msg = "获取研究员信息失败!"
+			br.ErrMsg = "选择研究员失败,Err:" + err.Error()
+			return
+		}
+		condition += ` and a.researcher_id IN (` + detail.ConfigValue + `) `
+	} else {
+		condition += ` and a.researcher_id IN (` + utils.GetOrmInReplace(len(adminIdsArr)) + `)`
+	}
+	pars = append(pars, adminIdsArr)
+
+	//获取列表
+	switch dataType {
+	case "try_out":
+		condition += ` and a.company_status = ? `
+		pars = append(pars, "试用")
+	case "formal":
+		condition += ` and a.company_status = ? `
+		pars = append(pars, "正式")
+	case "close":
+		condition += ` and a.company_status = ? `
+		pars = append(pars, "关闭")
+	case "online":
+		condition += ` and a.roadshow_type = ? `
+		pars = append(pars, "线上")
+	case "offline":
+		condition += ` and a.roadshow_type = ? `
+		pars = append(pars, "线下")
+	default:
+		br.Msg = "请传入类型"
+		br.ErrMsg = "请传入类型DataType"
+		return
+	}
+
+	list, err := roadshow.GetRsReportRecordList(condition, pars)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,ERR:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+	return
+}

+ 23 - 2
models/company/company.go

@@ -213,6 +213,8 @@ type CompanyItem struct {
 	CloseReason      string               `description:"关闭原因"`
 	CloseTime        string               `description:"关闭时间"`
 	Nation           string               `description:"所属国家"`
+	LatestServiceRecord time.Time            `description:"最近沟通时间"`
+	FirstDate           time.Time            `description:"首次服务时间"`
 }
 
 type CompanyListItem struct {
@@ -384,9 +386,21 @@ as sort_todo_end_time,
 			SUM(b.view_total) as all_view_total,
 			SUM(b.try_out_day_total) as all_try_out_day_total,
 			IF(LEFT(GROUP_CONCAT(DISTINCT b.last_view_time ORDER BY b.product_id), 19) >= "` + t + `", 1, 0) AS week_view_active,
-			a.nation
+			a.nation,
+			c.latest_service_record,
+			d.first_date 
 			FROM company AS a
 			INNER JOIN company_product AS b ON a.company_id=b.company_id
+			LEFT JOIN (
+    SELECT company_id, MAX(create_time) AS latest_service_record
+    FROM company_service_record
+    GROUP BY company_id
+) AS c ON a.company_id = c.company_id
+			LEFT JOIN (
+    SELECT company_id,MIN(start_date) AS first_date
+    FROM company_contract WHERE status=1 
+    GROUP BY company_id
+) AS d ON a.company_id = d.company_id 
 			WHERE a.enabled=1  `
 	if condition != "" {
 		sql += condition
@@ -1730,7 +1744,7 @@ func GetShareCompanyList(condition, sortStr string, pars []interface{}, startSiz
 	t := time.Now().Local().AddDate(0, 0, -7).Format(utils.FormatDate)
 
 	sql := `SELECT a.company_id,a.company_name,a.credit_code,a.company_code,a.created_time,a.province,a.city,
-a.address,a.region_type,b.group_id,b.road_show_total,b.is_share,
+a.address,a.region_type,b.group_id,b.road_show_total,b.is_share,b.share_seller_id,b.share_seller,
 			CASE 
      WHEN GROUP_CONCAT(b.status) LIKE "%永续%" THEN 1
 	 WHEN GROUP_CONCAT(b.status) LIKE "%正式%" THEN 2
@@ -1939,3 +1953,10 @@ func GetCompanyListByCondition(condition string, pars []interface{}, fieldArr []
 	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
 }
+
+func GetOverseasCompanys() (items []*Company, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM company where region_type= '海外' `
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}

+ 39 - 0
models/overseas_custom/custom.go

@@ -354,3 +354,42 @@ GROUP BY a.company_id `
 	_, err = o.Raw(sql, keyword, keyword, keyword, keyword).QueryRows(&companyIds)
 	return
 }
+
+func GetOverseasCustomList(condition string, pars []interface{}) (list []*Custom, err error) {
+	o := orm.NewOrm()
+	sql := ``
+	var databaseName string
+	if utils.RunMode == "debug" {
+		databaseName = "test_v2_hongze_rddp"
+	} else {
+		databaseName = "hongze_rddp"
+	}
+
+	sql = `SELECT * FROM (
+				SELECT a.company_id,a.company_name,a.nation,b.seller_id,b.seller_name,
+				b.view_total,b.road_show_total,a.created_time AS create_time,b.last_view_time,a.is_hide,a.overseas_status,
+				2 AS source,b.overseas_label,a.reset_btn
+				FROM company AS a
+				INNER JOIN company_product AS b ON a.company_id=b.company_id
+				INNER JOIN overseas_custom_seller AS c ON b.seller_id=c.seller_id
+				WHERE b.product_id=1 AND b.is_overseas = 0`
+	sql += `
+				UNION ALL
+				SELECT t.company_id+10000000,t.company_name,t.nation,t.seller_id,t.seller_name,
+				t.view_total,t.road_show_total,t.create_time,t.last_view_time,t.is_hide,t.overseas_status,
+				1 AS source,t.overseas_label,t.reset_btn
+				FROM %s.english_company AS t
+				INNER JOIN overseas_custom_seller AS n ON t.seller_id=n.seller_id
+             WHERE 1=1 AND t.is_deleted=0 `
+
+	sql += `		)AS m WHERE 1=1 `
+
+	if condition != "" {
+		sql += condition
+	}
+
+
+	sql = fmt.Sprintf(sql, databaseName)
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
+}

+ 7 - 3
models/roadshow/calendar.go

@@ -159,9 +159,13 @@ type ResearcherIds struct {
 type ResearcherGroup struct {
 	GroupId        int    `description:"分组id"`
 	GroupName      string `description:"分组名称"`
-	ResearcherList []*Researcher
+	AdminId        int    `description:"研究员id"`
+	RealName       string `description:"研究员名称"`
+	RoleTypeCode   string `description:"角色编码"`
+	ResearcherList []*ResearcherGroup
 }
 
+
 func GetResearcherGroup() (list []*ResearcherGroup, err error) {
 	o := orm.NewOrm()
 	sql := ` SELECT group_id,group_name FROM admin AS a
@@ -175,7 +179,7 @@ func GetResearcherGroup() (list []*ResearcherGroup, err error) {
 	return
 }
 
-func GetResearcher() (list []*Researcher, err error) {
+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')
@@ -192,7 +196,7 @@ func GetChoiceResearcher(adminIds string) (list []*Researcher, err error) {
 }
 
 // GetResearcherV2 获取研究员列表(冻结的也要)
-func GetResearcherV2() (list []*Researcher, err error) {
+func GetResearcherV2() (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')

+ 42 - 0
models/roadshow/report_record.go

@@ -229,3 +229,45 @@ func GetBusinessTripList(adminId int, startDate, endDate string) (list []*Busine
 	}
 	return
 }
+
+// GetOverseasGroupSellerRecordList 获取销售分组数据
+func GetOverseasGroupSellerRecordList(condition string, pars []interface{}) (list []*RsReportRecordGroup, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT seller_id as admin_id,seller_group_id as group_id,seller_name admin_name,count(1) num
+				FROM  rs_report_record 
+				WHERE 1=1 and rs_calendar_researcher_status = 2 
+ `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` GROUP BY seller_id`
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+
+	return
+}
+
+// OverseasAdminReportRecord 系统用户统计信息
+type OverseasAdminReportRecord struct {
+	Name                  string                      `description:"系统用户名"`
+	AdminId               int                         `description:"系统用户id"`
+	RsReportRecordNumList []RsOverseasReportRecordNum `description:"统计次数"`
+}
+
+// RsOverseasReportRecordNum 系统用户统计信息
+type RsOverseasReportRecordNum struct {
+	TryOutNum  int    `description:"试用路演次数"`
+	FormalNum  int    `description:"正式路演次数"`
+	CloseNum   int    `description:"关闭客户次数"`
+	OnlineNum  int    `description:"线上路演次数"`
+	OfflineNum int    `description:"线上路演次数"`
+	StartDate  string `description:"开始日期"`
+	EndDate    string `description:"结束日期"`
+	IsLook     bool   `description:"是否可以查看详情"`
+}
+
+// RsOverseasReportRecordResp 总统计信息
+type RsOverseasReportRecordResp struct {
+	List                  []OverseasAdminReportRecord `description:"系统用户分组信息"`
+	RsReportRecordNumList []RsOverseasReportRecordNum `description:"统计次数"`
+}
+

+ 4 - 1
models/statistic_report/report.go

@@ -62,7 +62,10 @@ func GetTryGroupCompanyReportRecordGroupList(date time.Time, productId int) (lis
 type IncrementalCompanyListReq struct {
 	PageSize     int `description:"每页数据条数"`
 	CurrentIndex int `description:"当前页页码,从1开始"`
-	SortParam    string `description:"排序字段参数,用来排序的字段, 枚举值:'viewTotal':总阅读次数 、 'viewTime':阅读时间 、 'roadShowTotal':累计路演次数 、'expireDay':到期时间 、 'createTime':创建时间 、 'formalTime': 转正时间 、 'freezeTime':冻结时间 、'lossTime':流失时间" 、'deadline':距离未完成的任务的截止日期的天数`
+	SortParam    string `description:"排序字段参数,用来排序的字段, 枚举值:'viewTotal':总阅读次数 、 
+'viewTime':阅读时间 、 'roadShowTotal':累计路演次数 、'expireDay':到期时间 、 'createTime':创建时间 、
+'formalTime': 转正时间 、 'freezeTime':冻结时间 、'lossTime':流失时间 、
+'deadline':距离未完成的任务的截止日期的天数、sellerName:所属销售、shareSellerName:分配销售、status:客户状态"`
 	SortType     string `description:"如何排序,是正序还是倒序,枚举值:asc 正序,desc 倒叙 "`
 	CompanyIds   string `description:"标签,多个标签用、隔开;长度255"`
 }

+ 27 - 0
routers/commentsRouter.go

@@ -7414,6 +7414,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"],
+        beego.ControllerComments{
+            Method: "OverseasCalendarList",
+            Router: `/overseas/calendar/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"],
         beego.ControllerComments{
             Method: "OverseasCustomReportCalendarList",
@@ -7423,6 +7432,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"],
+        beego.ControllerComments{
+            Method: "OverseasResearcherReportList",
+            Router: `/overseas_custom/researcher/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"],
+        beego.ControllerComments{
+            Method: "OverseasSellerReportList",
+            Router: `/overseas_custom/seller/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/roadshow:CalendarController"],
         beego.ControllerComments{
             Method: "OverseasCustomCalendarAdminList",

+ 496 - 0
services/roadshow/report.go

@@ -1,7 +1,9 @@
 package roadshow
 
 import (
+	"fmt"
 	"hongze/hz_crm_api/models/company"
+	"hongze/hz_crm_api/models/overseas_custom"
 	"hongze/hz_crm_api/models/roadshow"
 	"hongze/hz_crm_api/utils"
 	"time"
@@ -447,3 +449,497 @@ func getSellerSectionData(startDate, endDate time.Time, dimensionType string) (a
 	}
 	return
 }
+
+type OverseasAdminDataMap struct {
+	TryOutMap  map[int]int `description:"试用路演次数"`
+	FormalMap  map[int]int `description:"正式路演次数"`
+	CloseMap   map[int]int `description:"关闭客户次数"`
+	OnlineMap  map[int]int `description:"线上路演次数"`
+	OfflineMap map[int]int `description:"线上路演次数"`
+	StartDate  string      `description:"开始日期"`
+	EndDate    string      `description:"开始日期"`
+}
+
+// GetOverseasWeekDataV2 周度数据
+func GetOverseasWeekDataV2(adminType, dimensionType string, weekNum int) (adminDataList []OverseasAdminDataMap, firstDate time.Time, err error) {
+	nowWeekMonday := utils.GetNowWeekMonday() //本周周一
+	//fmt.Println(nowWeekMonday)
+	nowWeekSunday := nowWeekMonday.AddDate(0, 0, 7).Add(-1 * time.Second) //本周周日
+	chanList := make([]chan OverseasAdminDataMap, 0)
+	for i := 0; i < weekNum; i++ {
+		tmpCh := make(chan OverseasAdminDataMap, 0)
+		chanList = append(chanList, tmpCh)
+
+		lastWeekMonday := nowWeekMonday.AddDate(0, 0, -7*i)
+		lastWeekSunday := nowWeekSunday.AddDate(0, 0, -7*i)
+
+		// 第一个开始日期
+		firstDate = lastWeekMonday
+		go getOverseasSectionData(lastWeekMonday, lastWeekSunday, adminType, dimensionType, tmpCh)
+	}
+
+	adminDataList = make([]OverseasAdminDataMap, 0)
+	for _, vChan := range chanList {
+		var weekAdminDataMap OverseasAdminDataMap
+		weekAdminDataMap = <-vChan
+		close(vChan)
+		adminDataList = append(adminDataList, weekAdminDataMap)
+	}
+
+	return
+}
+
+// getOverseasSectionData 获取周期数据
+func getOverseasSectionData(startDate, endDate time.Time, adminType, dimensionType string, ch chan OverseasAdminDataMap) (adminDataMap OverseasAdminDataMap, err error) {
+	defer func() {
+		ch <- adminDataMap
+	}()
+	//adminType := `seller`
+	switch adminType {
+	case "researcher":
+		adminDataMap, err = getOverseasResearcherSectionData(startDate, endDate)
+	case "seller":
+		adminDataMap, err = getOverseasSellerSectionData(startDate, endDate, dimensionType)
+	}
+	return
+}
+
+// getOverseasSellerSectionData 获取销售周期数据
+func getOverseasSellerSectionData(startDate, endDate time.Time, dimensionType string) (adminDataMap OverseasAdminDataMap, err error) {
+	tryOutMap := make(map[int]int)
+	formalMap := make(map[int]int)
+	closeMap := make(map[int]int)
+	onlineMap := make(map[int]int)
+	offlineMap := make(map[int]int)
+	//fmt.Println()
+	//客户状态维度
+	companylist, err := overseas_custom.GetOverseasCustomList("", nil)
+	if err != nil {
+		return
+	}
+	formalIdsArr := make([]int, 0)
+	tryoutIdsArr := make([]int, 0)
+	closeIdsArr := make([]int, 0)
+	for _, v := range companylist {
+		if v.OverseasStatus == "正式" {
+			formalIdsArr = append(formalIdsArr, v.CompanyId)
+		} else if v.OverseasStatus == "试用" {
+			tryoutIdsArr = append(tryoutIdsArr, v.CompanyId)
+		} else if v.OverseasStatus == "关闭" {
+			closeIdsArr = append(closeIdsArr, v.CompanyId)
+		}
+	}
+	if dimensionType == "company_status" {
+		//正式客户
+		{
+			var condition string
+			var pars []interface{}
+			condition = ` and start_date >= ? and end_date <= ?  and company_status = ? and company_id IN (` + utils.GetOrmInReplace(len(formalIdsArr)) + `)`
+			pars = append(pars, startDate, endDate, "正式", formalIdsArr)
+			data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range data {
+				fmt.Println(v)
+				formalMap[v.AdminId] = v.Num
+			}
+		}
+
+		//试用客户
+		{
+			var condition string
+			var pars []interface{}
+			condition = ` and start_date >= ? and end_date <= ? and company_status = ? and company_id IN (` + utils.GetOrmInReplace(len(tryoutIdsArr)) + `)`
+			pars = append(pars, startDate, endDate, "试用", tryoutIdsArr)
+			data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range data {
+				//fmt.Println(v)
+				tryOutMap[v.AdminId] = v.Num
+			}
+		}
+
+		//关闭客户
+		{
+			var condition string
+			var pars []interface{}
+			condition = ` and start_date >= ? and end_date <= ? and company_status = ? and company_id IN (` + utils.GetOrmInReplace(len(closeIdsArr)) + `)`
+			pars = append(pars, startDate, endDate, "关闭", closeIdsArr)
+			data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range data {
+				//fmt.Println(v)
+				closeMap[v.AdminId] = v.Num
+			}
+		}
+	}
+
+	//路演形式维度
+	//if dimensionType == "roadshow_type" {
+	//	//线上路演
+	//	{
+	//		var condition string
+	//		var pars []interface{}
+	//		condition = ` and start_date >= ? and end_date <= ? and roadshow_type = ? and company_id IN (` + utils.GetOrmInReplace(len(idsArr)) + `)`
+	//		pars = append(pars, startDate, endDate, "线上", idsArr)
+	//		data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			return
+	//		}
+	//		for _, v := range data {
+	//			//fmt.Println(v)
+	//			onlineMap[v.AdminId] = v.Num
+	//		}
+	//	}
+	//
+	//	//线下路演
+	//	{
+	//		var condition string
+	//		var pars []interface{}
+	//		condition = ` and start_date >= ? and end_date <= ? and roadshow_type = ? and company_id IN (` + utils.GetOrmInReplace(len(idsArr)) + `)`
+	//		pars = append(pars, startDate, endDate, "线下", idsArr)
+	//		data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			return
+	//		}
+	//		for _, v := range data {
+	//			//fmt.Println(v)
+	//			offlineMap[v.AdminId] = v.Num
+	//		}
+	//	}
+	//}
+
+	////销售专项路演统计
+	//if dimensionType == "seller_special" {
+	//
+	//	detail, errdetail := company.GetConfigDetailByCode("choice_researcher_adminid")
+	//	if errdetail != nil {
+	//		err = errdetail
+	//		return
+	//	}
+	//	//正式客户
+	//	{
+	//		var condition string
+	//		var pars []interface{}
+	//		condition = ` and start_date >= ? and end_date <= ?  and company_status = ? ` + ` and researcher_id IN (` + detail.ConfigValue + `) `
+	//		pars = append(pars, startDate, endDate, "正式")
+	//		data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			return
+	//		}
+	//		for _, v := range data {
+	//			formalMap[v.AdminId] = v.Num
+	//		}
+	//	}
+	//
+	//	//试用客户
+	//	{
+	//		var condition string
+	//		var pars []interface{}
+	//		condition = ` and start_date >= ? and end_date <= ? and company_status = ? ` + ` and researcher_id IN (` + detail.ConfigValue + `) `
+	//		pars = append(pars, startDate, endDate, "试用")
+	//		data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+	//
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			return
+	//		}
+	//		for _, v := range data {
+	//			//fmt.Println(v)
+	//			tryOutMap[v.AdminId] = v.Num
+	//		}
+	//	}
+	//
+	//	//公开会议
+	//	{
+	//		var condition string
+	//		var pars []interface{}
+	//		condition = ` and start_date >= ? and end_date <= ? and activity_type = ? ` + ` and researcher_id IN (` + detail.ConfigValue + `) `
+	//		pars = append(pars, startDate, endDate, "公开会议")
+	//		data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			return
+	//		}
+	//		for _, v := range data {
+	//			//fmt.Println(v)
+	//			meetingMap[v.AdminId] = v.Num
+	//		}
+	//	}
+	//} else {
+	//	//公开会议
+	//	{
+	//		var condition string
+	//		var pars []interface{}
+	//		condition = ` and start_date >= ? and end_date <= ? and activity_type = ? `
+	//		pars = append(pars, startDate, endDate, "公开会议")
+	//		data, tmpErr := roadshow.GetOverseasGroupSellerRecordList(condition, pars)
+	//		if tmpErr != nil {
+	//			err = tmpErr
+	//			return
+	//		}
+	//		for _, v := range data {
+	//			//fmt.Println(v)
+	//			meetingMap[v.AdminId] = v.Num
+	//		}
+	//	}
+	//}
+
+	adminDataMap = OverseasAdminDataMap{
+		TryOutMap:  tryOutMap,
+		FormalMap:  formalMap,
+		CloseMap:   closeMap,
+		OfflineMap: offlineMap,
+		OnlineMap:  onlineMap,
+		StartDate:  startDate.Format(utils.FormatDate),
+		EndDate:    endDate.Format(utils.FormatDate),
+	}
+	return
+}
+
+// getOverseasResearcherSectionData 获取研究员周期数据
+func getOverseasResearcherSectionData(startDate, endDate time.Time) (adminDataMap OverseasAdminDataMap, err error) {
+	tryOutMap := make(map[int]int)
+	formalMap := make(map[int]int)
+	closemap := make(map[int]int)
+
+	companylist, err := overseas_custom.GetOverseasCustomList("", nil)
+	if err != nil {
+		return
+	}
+	formalIdsArr := make([]int, 0)
+	tryoutIdsArr := make([]int, 0)
+	closeIdsArr := make([]int, 0)
+	for _, v := range companylist {
+		if v.OverseasStatus == "正式" {
+			formalIdsArr = append(formalIdsArr, v.CompanyId)
+		} else if v.OverseasStatus == "试用" {
+			tryoutIdsArr = append(tryoutIdsArr, v.CompanyId)
+		} else if v.OverseasStatus == "关闭" {
+			closeIdsArr = append(closeIdsArr, v.CompanyId)
+		}
+	}
+	//正式客户
+	{
+		var condition string
+		var pars []interface{}
+		condition = ` and start_date >= ? and end_date <= ?  and company_status = ? and company_id IN (` + utils.GetOrmInReplace(len(formalIdsArr)) + `)`
+		pars = append(pars, startDate, endDate, "正式", formalIdsArr)
+		data, tmpErr := roadshow.GetGroupResearcherRecordList(condition, pars)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range data {
+			formalMap[v.AdminId] = v.Num
+		}
+	}
+
+	//试用客户
+	{
+		var condition string
+		var pars []interface{}
+		condition = ` and start_date >= ? and end_date <= ? and company_status = ? and company_id IN (` + utils.GetOrmInReplace(len(tryoutIdsArr)) + `)`
+		pars = append(pars, startDate, endDate, "试用", tryoutIdsArr)
+		data, tmpErr := roadshow.GetGroupResearcherRecordList(condition, pars)
+
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range data {
+			//fmt.Println(v)
+			tryOutMap[v.AdminId] = v.Num
+		}
+	}
+
+	//试用客户
+	{
+		var condition string
+		var pars []interface{}
+		condition = ` and start_date >= ? and end_date <= ? and company_status = ? and company_id IN (` + utils.GetOrmInReplace(len(closeIdsArr)) + `)`
+		pars = append(pars, startDate, endDate, "关闭", closeIdsArr)
+		data, tmpErr := roadshow.GetGroupResearcherRecordList(condition, pars)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range data {
+			//fmt.Println(v)
+			closemap[v.AdminId] = v.Num
+		}
+	}
+
+	adminDataMap = OverseasAdminDataMap{
+		TryOutMap: tryOutMap,
+		FormalMap: formalMap,
+		CloseMap:  closemap,
+		StartDate: startDate.Format(utils.FormatDate),
+		EndDate:   endDate.Format(utils.FormatDate),
+	}
+	return
+}
+
+// GetOverseasMonthDataV2 月度数据
+func GetOverseasMonthDataV2(adminType, dimensionType string, dataNum int) (adminDataMapList []OverseasAdminDataMap, firstDate time.Time, err error) { //三个协程返回
+	nowMonthFirstDay := utils.GetNowMonthFirstDay() //本月第一天
+	//nowMonthLastDay := nowMonthFirstDay.AddDate(0, 1, 0).Add(-1 * time.Second) //本月最后一天
+
+	chanList := make([]chan OverseasAdminDataMap, 0)
+	for i := 0; i < dataNum; i++ {
+		tmpCh := make(chan OverseasAdminDataMap, 0)
+		chanList = append(chanList, tmpCh)
+
+		lastMonthFirstDay := nowMonthFirstDay.AddDate(0, -1*i, 0)                          //上个月第一天
+		lastMonthLastDay := nowMonthFirstDay.AddDate(0, -1*(i-1), 0).Add(-1 * time.Second) //上个月最后一天
+
+		// 第一个开始日期
+		firstDate = lastMonthFirstDay
+		go getOverseasSectionData(lastMonthFirstDay, lastMonthLastDay, adminType, dimensionType, tmpCh)
+	}
+
+	adminDataMapList = make([]OverseasAdminDataMap, 0)
+	for _, vChan := range chanList {
+		var monthAdminDataMap OverseasAdminDataMap
+		monthAdminDataMap = <-vChan
+		close(vChan)
+		adminDataMapList = append(adminDataMapList, monthAdminDataMap)
+	}
+
+	return
+}
+
+// GetOverseasTimeIntervalData 区间数据
+func GetOverseasTimeIntervalData(startDate, endDate, adminType, dimensionType string) (adminDataMapList []OverseasAdminDataMap, firstDate time.Time, err error) { //三个协程返回
+	startDateTimer, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+	endDateTimer, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+	endDateTimer = endDateTimer.AddDate(0, 0, 1).Add(-1 * time.Second) //本月最后一天
+
+	//最早的一天
+	firstDate = startDateTimer
+
+	ch1 := make(chan OverseasAdminDataMap, 0)
+
+	go getOverseasSectionData(startDateTimer, endDateTimer, adminType, dimensionType, ch1)
+
+	var adminDataMap OverseasAdminDataMap
+
+	adminDataMap = <-ch1
+	close(ch1)
+
+	adminDataMapList = make([]OverseasAdminDataMap, 0)
+	adminDataMapList = append(adminDataMapList, adminDataMap)
+	return
+}
+
+// GetOverseasWeekData 周度数据
+func GetOverseasWeekData(adminType, dimensionType string) (adminDataList []OverseasAdminDataMap, firstDate time.Time, err error) {
+	nowWeekMonday := utils.GetNowWeekMonday() //本周周一
+	//fmt.Println(nowWeekMonday)
+	nowWeekSunday := nowWeekMonday.AddDate(0, 0, 7).Add(-1 * time.Second) //本周周日
+	//fmt.Println(nowWeekSunday)
+
+	//nowWeekMonday = nowWeekMonday.AddDate(0, 0, -30) //上周周一
+	//nowWeekSunday = nowWeekSunday.AddDate(0, 0, -30) //上周周日
+
+	//adminDataMap, err := getSectionData(nowWeekMonday, nowWeekSunday)
+	//if err != nil {
+	//	fmt.Println(err)
+	//	return
+	//}
+	//fmt.Println(adminDataMap)
+
+	lastWeekMonday := nowWeekMonday.AddDate(0, 0, -7) //上周周一
+	//fmt.Println(lastWeekMonday)
+	//最早的一天
+	firstDate = lastWeekMonday
+	lastWeekSunday := nowWeekSunday.AddDate(0, 0, -7) //上周周日
+	//fmt.Println(lastWeekSunday)
+
+	nextWeekMonday := nowWeekMonday.AddDate(0, 0, 7) //下周周一
+	//fmt.Println(nextWeekMonday)
+	nextWeekSunday := nowWeekSunday.AddDate(0, 0, 7) //下周周日
+	//fmt.Println(nextWeekSunday)
+
+	ch1 := make(chan OverseasAdminDataMap, 0)
+	ch2 := make(chan OverseasAdminDataMap, 0)
+	ch3 := make(chan OverseasAdminDataMap, 0)
+
+	go getOverseasSectionData(lastWeekMonday, lastWeekSunday, adminType, dimensionType, ch1)
+	go getOverseasSectionData(nowWeekMonday, nowWeekSunday, adminType, dimensionType, ch2)
+	go getOverseasSectionData(nextWeekMonday, nextWeekSunday, adminType, dimensionType, ch3)
+
+	var nowWeekAdminDataMap, lastWeekAdminDataMap, nextWeekAdminDataMap OverseasAdminDataMap
+
+	lastWeekAdminDataMap = <-ch1
+	close(ch1)
+
+	nowWeekAdminDataMap = <-ch2
+	close(ch2)
+
+	nextWeekAdminDataMap = <-ch3
+	close(ch3)
+
+	adminDataList = make([]OverseasAdminDataMap, 0)
+	adminDataList = append(adminDataList, lastWeekAdminDataMap, nowWeekAdminDataMap, nextWeekAdminDataMap)
+	return
+}
+
+// GetOverseasMonthData 月度数据
+func GetOverseasMonthData(adminType, dimensionType string) (adminDataMapList []OverseasAdminDataMap, firstDate time.Time, err error) { //三个协程返回
+	nowMonthFirstDay := utils.GetNowMonthFirstDay()                            //本月第一天
+	nowMonthLastDay := nowMonthFirstDay.AddDate(0, 1, 0).Add(-1 * time.Second) //本月最后一天
+
+	lastMonthFirstDay1 := nowMonthFirstDay.AddDate(0, -1, 0)                       //上个月第一天
+	lastMonthLastDay1 := lastMonthFirstDay1.AddDate(0, 1, 0).Add(-1 * time.Second) //上个月最后一天
+
+	lastMonthFirstDay2 := nowMonthFirstDay.AddDate(0, -2, 0)                       //上上个月第一天
+	lastMonthLastDay2 := lastMonthFirstDay2.AddDate(0, 1, 0).Add(-1 * time.Second) //上上个月最后一天
+
+	lastMonthFirstDay3 := nowMonthFirstDay.AddDate(0, -3, 0)                       //上上上个月第一天
+	lastMonthLastDay3 := lastMonthFirstDay3.AddDate(0, 1, 0).Add(-1 * time.Second) //上上上个月最后一天
+
+	//最早的一天
+	firstDate = lastMonthFirstDay3
+
+	ch1 := make(chan OverseasAdminDataMap, 0)
+	ch2 := make(chan OverseasAdminDataMap, 0)
+	ch3 := make(chan OverseasAdminDataMap, 0)
+	ch4 := make(chan OverseasAdminDataMap, 0)
+
+	go getOverseasSectionData(nowMonthFirstDay, nowMonthLastDay, adminType, dimensionType, ch1)
+	go getOverseasSectionData(lastMonthFirstDay1, lastMonthLastDay1, adminType, dimensionType, ch2)
+	go getOverseasSectionData(lastMonthFirstDay2, lastMonthLastDay2, adminType, dimensionType, ch3)
+	go getOverseasSectionData(lastMonthFirstDay3, lastMonthLastDay3, adminType, dimensionType, ch4)
+
+	var nowMonthAdminDataMap, lastMonthAdminDataMap1, lastMonthAdminDataMap2, lastMonthAdminDataMap3 OverseasAdminDataMap
+
+	nowMonthAdminDataMap = <-ch1
+	close(ch1)
+
+	lastMonthAdminDataMap1 = <-ch2
+	close(ch2)
+
+	lastMonthAdminDataMap2 = <-ch3
+	close(ch3)
+
+	lastMonthAdminDataMap3 = <-ch4
+	close(ch4)
+
+	adminDataMapList = make([]OverseasAdminDataMap, 0)
+	adminDataMapList = append(adminDataMapList, nowMonthAdminDataMap, lastMonthAdminDataMap1, lastMonthAdminDataMap2, lastMonthAdminDataMap3)
+	return
+}

+ 33 - 9
services/statistic_report/company.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/shopspring/decimal"
 	"hongze/hz_crm_api/models/company"
 	statisticModels "hongze/hz_crm_api/models/statistic_report"
 	"hongze/hz_crm_api/models/system"
@@ -106,7 +107,17 @@ func CompanyList(sysUser *system.Admin, req statisticModels.IncrementalCompanyLi
 			} else {
 				sortStr = " ORDER BY sort_todo_end_time asc, b.view_total desc, a.created_time desc"
 			}
-		} else {
+		} else if sortParam == "sellerName" {
+			sortStr = " ORDER BY b.seller_name "
+		} else if sortParam == "shareSellerName" {
+			sortStr = " ORDER BY b.share_seller "
+		} else if sortParam == "status" {
+			sortStr = " ORDER BY b.status "
+		}  else if sortParam == "serviceYears" {
+			sortStr = " ORDER BY d.first_date"
+		} else if sortParam == "latestServiceRecord" {
+			sortStr = " ORDER BY c.latest_service_record "
+		}else {
 			errMsg = "排序字段传入数据异常:" + sortParam
 			err = errors.New("获取失败")
 			return
@@ -126,21 +137,20 @@ func CompanyList(sysUser *system.Admin, req statisticModels.IncrementalCompanyLi
 	} else {
 		//2、客户列表选择“全部”时,支持按照“创建时间”对“全部”分类下所有客户列表进行升降序排列;选择“正式”时按照“转正时间”、选择“冻结”时按照“冻结时间”、选择“流失”时按照“流失时间”、选择“永续”时按照“创建时间”;
 		if status == "全部" || status == "永续" {
-			sortStr = " ORDER BY a.created_time "
+			sortStr = " ORDER BY c.latest_service_record ASC"
 		} else if status == "正式" {
-			sortStr = " ORDER BY b.formal_time "
+			sortStr = " ORDER BY b.formal_time DESC"
 		} else if status == "冻结" {
-			sortStr = " ORDER BY b.freeze_time "
+			sortStr = " ORDER BY b.freeze_time DESC"
 		} else if status == "流失" {
-			sortStr = " ORDER BY b.loss_time "
+			sortStr = " ORDER BY b.loss_time DESC"
 		} else if status == "试用" {
 			if roleTypeCode == utils.ROLE_TYPE_CODE_ADMIN {
-				sortStr = " ORDER BY all_view_total "
+				sortStr = " ORDER BY all_view_total DESC"
 			} else {
-				sortStr = " ORDER BY b.view_total "
+				sortStr = " ORDER BY b.view_total DESC"
 			}
 		}
-		sortStr += " DESC "
 	}
 
 	list, err := company.GetCompanyList(condition, status, sortStr, pars, startSize, pageSize)
@@ -500,6 +510,17 @@ func CompanyList(sysUser *system.Admin, req statisticModels.IncrementalCompanyLi
 				}
 			}
 
+			// 计算合同开始日期和结束日期之间的小时差
+			duration := time.Since(v.FirstDate).Hours()
+			hoursDiff := decimal.NewFromFloat(duration)
+
+			// 计算总小时数
+			const hoursPerYear = 24 * 365
+			totalHours := decimal.NewFromInt(hoursPerYear)
+
+			// 计算相差的年数,保留一位小数
+			numYearDecimal := hoursDiff.Div(totalHours).Round(1)
+
 			companyList := &CompanyListItem{
 				CompanyId:        v.CompanyId,
 				CompanyName:      v.CompanyName,
@@ -556,7 +577,10 @@ func CompanyList(sysUser *system.Admin, req statisticModels.IncrementalCompanyLi
 				IsShow:          isShow,
 				TryStageSlice:   tryStageSlice,
 				ShareSeller:     v.ShareSeller,
-				ShareSellerId: v.ShareSellerId,
+				ShareSellerId:   v.ShareSellerId,
+				ShareSeller:     v.ShareSeller,
+				LatestServiceRecord: v.LatestServiceRecord.Format(utils.FormatDate2),
+				ServiceYears: numYearDecimal.String(),
 			}
 			if strings.Contains(companyList.ApproveStatus, "已审批") {
 				companyList.ApproveStatus = ""

+ 57 - 55
services/statistic_report/reponse.go

@@ -95,61 +95,63 @@ type CollectListItem struct {
 }
 
 type CompanyListItem struct {
-	CompanyId        int                         `orm:"column(company_id);pk"`
-	CompanyName      string                      `description:"客户名称"`
-	CreditCode       string                      `description:"社会统一信用码"`
-	CompanyCode      string                      `description:"客户编码"`
-	StartDate        string                      `description:"合同开始日期"`
-	EndDate          string                      `description:"合同结束日期"`
-	LoseReason       string                      `description:"流失原因"`
-	RenewalReason    string                      `description:"续约说明"`
-	FreezeReason     string                      `description:"冻结理由"`
-	LossTime         string                      `description:"流失时间"`
-	Status           string                      `description:"客户状态:'试用','永续','冻结','流失','正式' "`
-	CompanyType      string                      `description:"客户类型:ficc/权益"`
-	ApproveStatus    string                      `description:"审批状态:'待审批','已审批','驳回' 审批状态为空时,表示没有审批申请"`
-	SellerName       string                      `description:"销售:吉根龙/颖丹"`
-	SellerId         int                         `description:"销售ID"`
-	SellerIds        string                      `description:"销售ID集合,包含ficc和权益的销售id"`
-	FiccPackageType  int                         `description:"ficc的套餐类型"`
-	ExpireDay        string                      `description:"到期天数"`
-	FreezeTime       string                      `description:"冻结时间"`
-	GroupId          int                         `description:"分组id"`
-	GroupIds         string                      `description:"分组id集合,包含ficc和权益的小组id" json:"-"`
-	DepartmentId     int                         `description:"部门id"`
-	IndustryName     string                      `description:"所属行业"`
-	IsSuspend        int                         `description:"是否暂停:1:暂停,0:启用 "`
-	CreatedTime      string                      `description:"创建时间"`
-	Source           string                      `description:"客户来源"`
-	Province         string                      `description:"省"`
-	City             string                      `description:"市"`
-	Address          string                      `description:"详细地址"`
-	Reasons          string                      `description:"新增理由"`
-	FreezeStartDate  string                      `description:"冻结开始日期"`
-	FreezeEndDate    string                      `description:"冻结结束日期"`
-	FreezeExpireDays int                         `description:"冻结到期天数"`
-	ProductId        int                         `json:"-"`
-	FormalTime       string                      `description:"转正时间"`
-	IsShared         bool                        `description:"是否共享客户"`
-	RegionType       string                      `description:"区域:国内,海外"`
-	FiccView         int                         `description:"Ficc报告阅读次数"`
-	RaiView          int                         `description:"权益报告阅读次数"`
-	FiccLastViewTime string                      `description:"ficc最近一次阅读时间"`
-	RaiLastViewTime  string                      `description:"权益最近一次阅读时间"`
-	RoadShowTotal    int                         `description:"累计路演次数"`
-	TodoStatus       bool                        `description:"是否存在进行中任务,true:存在待处理的任务"`
-	CanConfirm       bool                        `description:"是否允许完成任务,true:允许完成任务"`
-	HiddenConfirm    bool                        `description:"是否隐藏完成任务按钮,true:隐藏完成任务按钮"`
-	HiddenCreate     bool                        `description:"是否隐藏新增/编辑按钮,true:隐藏新增/编辑按钮"`
-	TodoButtonColor  string                      `description:"任务按钮颜色:red,green,gray"`
-	AllViewTotal     int                         `description:"总阅读数"`
-	Deadline         string                      `description:"未完成的todo任务的截止日期,截止目前还剩余的天数"`
-	IsShow           bool                        `description:"是否有权限展示(是否属于本组或自己下面的客户)"`
-	TryStageSlice    []company.TryStageSliceItem `description:"试用状态相关"`
-	FiccTryOutDay    int                         `description:"Ficc总试用天数"`
-	RaiTryOutDay     int                         `description:"权益总试用天数"`
-	ShareSellerId    int                         `description:"分配的咨询组销售ID"`
-	ShareSeller      string                      `description:"分配的咨询组销售名称"`
+	CompanyId           int                         `orm:"column(company_id);pk"`
+	CompanyName         string                      `description:"客户名称"`
+	CreditCode          string                      `description:"社会统一信用码"`
+	CompanyCode         string                      `description:"客户编码"`
+	StartDate           string                      `description:"合同开始日期"`
+	EndDate             string                      `description:"合同结束日期"`
+	LoseReason          string                      `description:"流失原因"`
+	RenewalReason       string                      `description:"续约说明"`
+	FreezeReason        string                      `description:"冻结理由"`
+	LossTime            string                      `description:"流失时间"`
+	Status              string                      `description:"客户状态:'试用','永续','冻结','流失','正式' "`
+	CompanyType         string                      `description:"客户类型:ficc/权益"`
+	ApproveStatus       string                      `description:"审批状态:'待审批','已审批','驳回' 审批状态为空时,表示没有审批申请"`
+	SellerName          string                      `description:"销售:吉根龙/颖丹"`
+	SellerId            int                         `description:"销售ID"`
+	SellerIds           string                      `description:"销售ID集合,包含ficc和权益的销售id"`
+	FiccPackageType     int                         `description:"ficc的套餐类型"`
+	ExpireDay           string                      `description:"到期天数"`
+	FreezeTime          string                      `description:"冻结时间"`
+	GroupId             int                         `description:"分组id"`
+	GroupIds            string                      `description:"分组id集合,包含ficc和权益的小组id" json:"-"`
+	DepartmentId        int                         `description:"部门id"`
+	IndustryName        string                      `description:"所属行业"`
+	IsSuspend           int                         `description:"是否暂停:1:暂停,0:启用 "`
+	CreatedTime         string                      `description:"创建时间"`
+	Source              string                      `description:"客户来源"`
+	Province            string                      `description:"省"`
+	City                string                      `description:"市"`
+	Address             string                      `description:"详细地址"`
+	Reasons             string                      `description:"新增理由"`
+	FreezeStartDate     string                      `description:"冻结开始日期"`
+	FreezeEndDate       string                      `description:"冻结结束日期"`
+	FreezeExpireDays    int                         `description:"冻结到期天数"`
+	ProductId           int                         `json:"-"`
+	FormalTime          string                      `description:"转正时间"`
+	IsShared            bool                        `description:"是否共享客户"`
+	RegionType          string                      `description:"区域:国内,海外"`
+	FiccView            int                         `description:"Ficc报告阅读次数"`
+	RaiView             int                         `description:"权益报告阅读次数"`
+	FiccLastViewTime    string                      `description:"ficc最近一次阅读时间"`
+	RaiLastViewTime     string                      `description:"权益最近一次阅读时间"`
+	RoadShowTotal       int                         `description:"累计路演次数"`
+	TodoStatus          bool                        `description:"是否存在进行中任务,true:存在待处理的任务"`
+	CanConfirm          bool                        `description:"是否允许完成任务,true:允许完成任务"`
+	HiddenConfirm       bool                        `description:"是否隐藏完成任务按钮,true:隐藏完成任务按钮"`
+	HiddenCreate        bool                        `description:"是否隐藏新增/编辑按钮,true:隐藏新增/编辑按钮"`
+	TodoButtonColor     string                      `description:"任务按钮颜色:red,green,gray"`
+	AllViewTotal        int                         `description:"总阅读数"`
+	Deadline            string                      `description:"未完成的todo任务的截止日期,截止目前还剩余的天数"`
+	IsShow              bool                        `description:"是否有权限展示(是否属于本组或自己下面的客户)"`
+	TryStageSlice       []company.TryStageSliceItem `description:"试用状态相关"`
+	FiccTryOutDay       int                         `description:"Ficc总试用天数"`
+	RaiTryOutDay        int                         `description:"权益总试用天数"`
+	ShareSellerId       int                         `description:"分配的咨询组销售ID"`
+	ShareSeller         string                      `description:"分配的咨询组销售名称"`
+	ServiceYears        string                      `description:"客户服务年限"`
+	LatestServiceRecord string                      `description:"最近沟通时间"`
 }
 
 // CompanyRenewRecordResp 总统计信息

+ 1 - 0
utils/constants.go

@@ -10,6 +10,7 @@ const (
 	FormatTime                 = "15:04:05"                //时间格式
 	FormatTimeHm               = "15:04"                   //时间格式
 	FormatDate                 = "2006-01-02"              //日期格式
+	FormatDate2                = "06-01-02"                //日期格式
 	FormatDateUnSpace          = "20060102"                //日期格式
 	FormatDateTime             = "2006-01-02 15:04:05"     //完整时间格式
 	HlbFormatDateTime          = "2006-01-02_15:04:05.999" //完整时间格式