package user import ( "encoding/json" "errors" logger "eta/eta_mini_ht_api/common/component/log" "eta/eta_mini_ht_api/common/exception" "eta/eta_mini_ht_api/common/utils/page" permissionService "eta/eta_mini_ht_api/domian/config" analystService "eta/eta_mini_ht_api/domian/financial_analyst" reportDomian "eta/eta_mini_ht_api/domian/report" userService "eta/eta_mini_ht_api/domian/user" merchantDao "eta/eta_mini_ht_api/models/merchant" userDao "eta/eta_mini_ht_api/models/user" "eta/eta_mini_ht_api/service/config" "gorm.io/gorm" "sort" "sync" "time" ) const ( RiskValid = "valid" RiskExpired = "expired" RiskUnTest = "unTest" SubscribeExpired = "expired" UnSubscribe = "unSubscribe" Subscribing = "Subscribing" ReportBookMark = "report" ChartBookMark = "chart" ) type User struct { Id int `json:"id"` Username string `json:"username"` AreaCode string `json:"areaCode"` Mobile string `json:"mobile"` OpenId string `json:"openId,omitempty"` } type AnalystDetail struct { AnalystName string `json:"analystName"` HeadImgUrl string `json:"headImgUrl"` HeadOriginImgUrl string `json:"headOriginImgUrl"` Introduction string `json:"introduction"` Followed string `json:"followed"` Position string `json:"position"` InvestmentCertificate string `json:"investmentCertificate"` ProfessionalCertificate string `json:"professionalCertificate"` } type UserProfile struct { Mobile string `json:"mobile"` RiskLevel string `json:"riskLevel"` RiskLevelStatus string `json:"riskLevelStatus"` UserName string `json:"userName"` } func CheckUserRiskMatchStatus(userId int) (riskLevel string, userRiskLevelStatus string, err error) { if userId <= 0 { err = exception.New(exception.IllegalTemplateUserId) return } userProfile, userErr := GetUserProfile(userId) if userErr != nil { if errors.Is(userErr, gorm.ErrRecordNotFound) { err = exception.New(exception.TemplateUserNotFound) } else { err = exception.New(exception.TemplateUserFoundFailed) } logger.Error("获取临时客户信息失败:%v", err) return } userRiskLevelStatus = userProfile.RiskLevelStatus //获取产品风险等级 if userProfile.RiskLevelStatus == RiskUnTest { logger.Warn("客户未做风险等级测评,mobile:%v", userProfile.Mobile) } if userProfile.RiskLevelStatus == RiskExpired { logger.Warn("客户风险等级已过期,mobile:%v", userProfile.Mobile) } if userProfile.RiskLevel != "" && userProfile.RiskLevelStatus == RiskValid { var mapping permissionService.CustomerProductRiskMappingDTO mapping, err = permissionService.GetRiskMappingByCustomerRiskLevel(userProfile.RiskLevel) if err != nil { logger.Error("查询产品风险等级映射失败:%v", err) return } riskLevel = mapping.ProductRiskLevel } return } // GetRiskLevelPermissionList 删选掉没有配置风险等级的品种,并校验客户的风险等级,riskLevel只有在客户 func GetRiskLevelPermissionList(permissionIds []int, isLogin bool, userId int) (filterPermissionIds []int, riskLevel string, userRiskStatus string, err error) { if isLogin { userProfile, userErr := GetUserProfile(userId) if userErr != nil { if errors.Is(userErr, gorm.ErrRecordNotFound) { err = exception.New(exception.TemplateUserNotFound) } else { err = exception.New(exception.TemplateUserFoundFailed) } logger.Error("获取临时客户信息失败:%v", err) return } var permissionList []permissionService.PermissionDTO if len(permissionIds) == 0 { //获取所有设置风险等级的品种 permissionList, err = permissionService.GetPermissionListWithRisk() } else { //更具id过滤设置了风险等级的品种 permissionList, err = permissionService.GetPermissionListByIds(permissionIds) } if err != nil { logger.Error("查询有风险等级的品种列表失败:%v", err) return } userRiskStatus = userProfile.RiskLevelStatus //获取产品风险等级 if userProfile.RiskLevelStatus == RiskUnTest { logger.Warn("客户未做风险等级测评,mobile:%v", userProfile.Mobile) //err = exception.New(exception.RiskUnTestError) } if userProfile.RiskLevelStatus == RiskExpired { logger.Warn("客户风险等级已过期,mobile:%v", userProfile.Mobile) //err = exception.New(exception.RiskExpiredError) } if userProfile.RiskLevel != "" && userProfile.RiskLevelStatus == RiskValid { var mapping permissionService.CustomerProductRiskMappingDTO mapping, err = permissionService.GetRiskMappingByCustomerRiskLevel(userProfile.RiskLevel) if err != nil { logger.Error("查询产品风险等级映射失败:%v", err) return } permissionList = filterPermissionsByRisk(permissionList, mapping.ProductRiskLevel) riskLevel = mapping.ProductRiskLevel } for _, permission := range permissionList { filterPermissionIds = append(filterPermissionIds, permission.PermissionId) } return } else { //没有登录的时候展示所有设置了风险等级的品种报告,筛选的时候过滤传入ID中没有设置风险等级的品种 var permissionList []permissionService.PermissionDTO if len(permissionIds) == 0 { //获取所有设置风险等级的品种 permissionList, err = permissionService.GetPermissionListWithRisk() } else { //更具id过滤设置了风险等级的品种 permissionList, err = permissionService.GetPermissionListByIds(permissionIds) } if err != nil { logger.Error("查询有风险等级的品种列表失败:%v", err) return } for _, permission := range permissionList { filterPermissionIds = append(filterPermissionIds, permission.PermissionId) } return } } func filterPermissionsByRisk(permissionList []permissionService.PermissionDTO, riskLevel string) (resultList []permissionService.PermissionDTO) { if riskLevel != "" { riskLevelNum, err := config.ParseRiskLevel(riskLevel) if err != nil { logger.Error("风险等级解析失败:%v", err) return } for _, permission := range permissionList { pRiskNum, riskErr := config.ParseRiskLevel(permission.RiskLevel) if riskErr != nil { logger.Error("解析品种风险等级失败 permission:%d,risk:%v", permission.PermissionId, permission.RiskLevel) continue } if pRiskNum <= riskLevelNum { resultList = append(resultList, permission) } } } else { resultList = permissionList } return } func convertUserDTOToProfile(dto userService.UserDTO) (profile UserProfile) { profile = UserProfile{ Mobile: dto.Mobile, RiskLevel: dto.RiskLevel, UserName: dto.Username, } if profile.UserName == "" { profile.UserName = dto.Mobile } if dto.RiskLevel == "" { profile.RiskLevelStatus = RiskUnTest return } date, err := time.Parse(time.DateOnly, dto.RiskValidEndDate) if err != nil { logger.Error("解析日期失败:%v", err) profile.RiskLevelStatus = RiskExpired return } currentDate := time.Now().Truncate(24 * time.Hour) expiryDate := date.Truncate(24 * time.Hour) if expiryDate.Before(currentDate) { profile.RiskLevelStatus = RiskExpired return } profile.RiskLevelStatus = RiskValid return } func GetUserProfile(userId int) (userProfile UserProfile, err error) { userDTO, err := userService.GetUserById(userId) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { logger.Error("用户不存在,用户Id:%d", userId) err = exception.New(exception.TemplateUserNotFound) } else { logger.Error("获取用户信息失败:%v", err) err = exception.New(exception.TemplateUserFoundFailed) } return } userProfile = convertUserDTOToProfile(userDTO) return } func GetAnalystDetail(userId int, analystId int) (analystDetail AnalystDetail, err error) { analyst, err := analystService.GetAnalystById(analystId) if err != nil { logger.Error("研究员信息不存在:%v", err) err = exception.New(exception.AnalystNotFound) } analystDetail = convertToAnalystDetail(analyst) //研究员关注状态 analystDetail.Followed = userService.GetFollowed(userId, analystId) return } func convertToAnalystDetail(dto analystService.FinancialAnalystDTO) AnalystDetail { return AnalystDetail{ AnalystName: dto.Name, HeadImgUrl: dto.HeadImgUrl, HeadOriginImgUrl: dto.HeadOriginImgUrl, Introduction: dto.Introduction, Position: dto.Position, InvestmentCertificate: dto.InvestmentCertificate, ProfessionalCertificate: dto.ProfessionalCertificate, } } func FollowAnalystsByName(userId int, analystNames []string, followType string) (err error) { var followlist []userService.FollowDTO for _, analystName := range analystNames { FinancialAnalystDTO, followErr := analystService.GetAnalystByName(analystName) if followErr != nil { err = exception.New(exception.AnalystNotFound) } if FinancialAnalystDTO.Id == 0 || FinancialAnalystDTO.Name == "" { continue } followDTO := userService.FollowDTO{ UserId: userId, AnalystId: FinancialAnalystDTO.Id, AnalystName: FinancialAnalystDTO.Name, FollowType: followType, } followlist = append(followlist, followDTO) } err = userService.FollowAnalystsByName(userId, followlist, followType) if err != nil { logger.Error("批量关注研究员失败:%v", err) err = exception.New(exception.BatchFollowingAnalystFailed) } return } func CheckFollowStatusByNames(userId int, names []string) (list []userService.FollowDTO, err error) { list, err = userService.CheckFollowStatusByNames(userId, names) if err != nil { logger.Error("获取关注状态失败:%v", err) err = exception.New(exception.CheckFollowStatusByNamesFailed) } return } func FollowAnalyst(userId int, analystId int, followType string) (err error) { FinancialAnalystDTO, err := analystService.GetAnalystById(analystId) if err != nil { err = exception.New(exception.AnalystNotFound) } if FinancialAnalystDTO.Id == 0 || FinancialAnalystDTO.Name == "" { err = exception.New(exception.AnalystNotFound) return } followDTO := userService.FollowDTO{ UserId: userId, AnalystId: analystId, AnalystName: FinancialAnalystDTO.Name, FollowType: followType, } err = userService.FollowAnalyst(followDTO) if err != nil { logger.Error("关注研究员失败:%v", err) err = exception.New(exception.UserFollowAnalystFailed) } return } func GetFollowingAnalystList(userId int) (analysts []FollowAnalystDTO, err error) { logger.Info("用户ID:%d", userId) dtoList, err := userService.GetFollowingAnalystList(userId) if err != nil { logger.Error("获取关注列表失败:%v", err) err = exception.New(exception.GetFollowingAnalystListFailed) return } analysts, err = convertToAnalystList(dtoList) var wg sync.WaitGroup wg.Add(len(analysts)) for i := 0; i < len(analysts); i++ { go func(followDTo *FollowAnalystDTO) { defer wg.Done() followDTo.NeedNotice = userService.NeedNotice(userId, followDTo.AnalystId) var analystsDTO analystService.FinancialAnalystDTO analystsDTO, err = analystService.GetAnalystById(followDTo.AnalystId) if err != nil { logger.Error("获取研究员信息失败") } else { followDTo.HeadImgUrl = analystsDTO.HeadImgUrl } }(&analysts[i]) } wg.Wait() //排序 sort.Slice(analysts, func(i, j int) bool { // 首先按 NeedNotice 排序 if analysts[i].NeedNotice == analysts[j].NeedNotice { // 对于 NeedNotice 相同的情况下,进行倒序排列 return analysts[i].FollowedTime.After(analysts[j].FollowedTime) } // NeedNotice 为 true 的排在 false 的前面 return analysts[i].NeedNotice }) //if err != nil { // logger.Error("转换研究员列表失败:%v", err) // err = exception.New(exception.TransferFollowingAnalystListFailed) //} return } func GetUnReadMessageList(userId int) (messages []userService.MyMessage, err error) { messages, err = userService.GetUnReadMessageList(userId) if err != nil { err = exception.New(exception.GetUserUnReadMsgFailed) } return } func ReadMessage(userId int, messageId int) bool { return userService.ReadMessage(userId, messageId) } func ReadMessages(userId int, analystId int) bool { return userService.ReadMessages(userId, analystId) } type FollowAnalystDTO struct { AnalystId int `json:"analystId"` AnalystName string `json:"analystName"` HeadImgUrl string `json:"headImgUrl"` FollowedTime time.Time `json:"followedTime"` NeedNotice bool `json:"needNotice"` } func convertToAnalystList(dtoList []userService.FollowDTO) (list []FollowAnalystDTO, err error) { for _, dto := range dtoList { analyst := FollowAnalystDTO{ AnalystId: dto.AnalystId, AnalystName: dto.AnalystName, FollowedTime: dto.FollowedTime, NeedNotice: false, } list = append(list, analyst) } return } func FollowAnalystByName(userId int, analystName string, followType string) (err error) { FinancialAnalystDTO, err := analystService.GetAnalystByName(analystName) if err != nil { err = exception.New(exception.AnalystNotFound) } if FinancialAnalystDTO.Id == 0 || FinancialAnalystDTO.Name == "" { err = exception.New(exception.AnalystNotFound) return } followDTO := userService.FollowDTO{ UserId: userId, AnalystId: FinancialAnalystDTO.Id, AnalystName: FinancialAnalystDTO.Name, FollowType: followType, } err = userService.FollowAnalyst(followDTO) if err != nil { logger.Error("关注研究员失败:%v", err) err = exception.New(exception.UserFollowAnalystFailed) } return } func FeedBack(userId int, mobile string, message string) (err error) { feedback := userService.FeedbackDTO{ UserId: userId, Mobile: mobile, Message: message, } err = userService.FeedBack(feedback) if err != nil { err = exception.New(exception.FeedBackError) } return } func GetUserByMobile(mobile string) (user User, err error) { userDTO, err := userService.GetUserByMobile(mobile) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { err = exception.New(exception.TemplateUserNotFound) } else { err = exception.New(exception.TemplateUserFoundFailed) } } user = convertToUser(userDTO) return } func GetUserByOpenId(openId string) (user User, err error) { userDTO, err := userService.GetUserByOpenId(openId) if err != nil { return } user = convertToUser(userDTO) return } func convertToUser(userDTO userService.UserDTO) User { return User{ Id: userDTO.Id, Username: userDTO.Username, OpenId: userDTO.OpenId, AreaCode: userDTO.AreaCode, Mobile: userDTO.Mobile, } } func GetUserByTemplateUserId(templateUserId int) (officialUser userService.OfficialUserDTO, err error) { officialUser, err = userService.GetUserByTemplateUserId(templateUserId) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { err = exception.New(exception.OfficialUserNotFound) logger.Info("用户未开户:%v", templateUserId) } else { err = exception.NewWithException(exception.OfficialUserFoundError, err.Error()) logger.Error("获取正式用户信息失败:%v", err) } } return } func GetUserScribeStatus(productId int, templateUserId int) (subscribe string) { userSubscribe, err := userService.GetUserSubscribe([]int{productId}, templateUserId) if err != nil { logger.Error("获取用户订阅状态失败:%v", err) return UnSubscribe } if len(userSubscribe) == 0 { return UnSubscribe } if userSubscribe[0].ProductType != merchantDao.Package && userSubscribe[0].Status == merchantDao.SubscribeExpired { logger.Error("用户订阅状态异常:%v,单品状态为过期,productId:%d", productId) return UnSubscribe } switch userSubscribe[0].Status { case merchantDao.SubscribeClose: return UnSubscribe case merchantDao.SubscribeExpired: return SubscribeExpired case merchantDao.SubscribeValid: return Subscribing default: return UnSubscribe } } func BookMark(templateUserId int, sourceId int, sourceType string) error { return userService.BookMark(templateUserId, sourceId, sourceType) } func UnBookMark(templateUserId int, sourceId int, sourceType string) error { return userService.UnBookMark(templateUserId, sourceId, sourceType) } func CheckBookMarkStatus(templateUserId int, sourceId int, sourceType string) (isBookMarked bool, err error) { status, err := userService.CheckBookMarkStatus(templateUserId, sourceId, sourceType) if err != nil { logger.Error("获取收藏状态失败:%v", err) return } isBookMarked = status == string(userDao.Marked) return } func GetTotalBookMarkPageBySourceType(userId int, sourceType string) (total int64, sourceIds []int, err error) { return userService.GetTotalBookMarkPageBySourceType(userId, sourceType) } func GetBookMarkPageBySourceType(userId int, pageInfo page.PageInfo, sourceType string) (sourceIds []int, err error) { return userService.GetBookMarkPageBySourceType(userId, sourceType, pageInfo) } func GetBookMarkListBySourceType(userId int, sourceType string) (sourceIds []int, err error) { return userService.GetBookMarkListBySourceType(userId, sourceType) } func GetBookMarkPageRangeBySourceType(userId int, pageInfo page.PageInfo, sourceType string, sourceIds []int) (filterSourceIds []int, err error) { return userService.GetBookMarkPageRangeBySourceType(userId, sourceType, pageInfo, sourceIds) } func GetReportBookMarked(sourceId int, templateUserId int) (collected bool, err error) { bookMark, err := userService.GetBookMarkedBySource(sourceId, templateUserId, ReportBookMark) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return } if errors.Is(err, gorm.ErrRecordNotFound) { err = nil return } collected = bookMark.Status == string(userDao.Marked) return } type BookMarkChart struct { ChartName string `json:"chartName"` ChartImage string `json:"chartImage"` UniqueCode string `json:"uniqueCode"` ChartInfoId int `json:"chartInfoId"` } type BookMarkInterface interface { GetID() int GetSourceType() string } type BookMarkReport struct { Type string `json:"type"` ReportID int `json:"reportId"` OrgId int `json:"orgId"` Title string `json:"title"` Author string `json:"author"` AuthorInfo []reportDomian.Anthor `json:"authorInfo"` Source string `json:"source"` Abstract string `json:"abstract"` PublishedTime string `json:"publishedTime"` RiskLevel string `json:"riskLevel"` PlateName string `json:"-"` ClassifyId int `json:"-"` SecondPermission map[int]string `json:"-"` Permissions map[int]string `json:"-"` PermissionNames interface { } `json:"permissionNames"` Highlight []string `json:"highlight"` Detail json.RawMessage `json:"detail"` PdfUrl string `json:"pdfUrl"` CoverSrc int `json:"coverSrc"` CoverUrl string `json:"coverUrl"` Login bool `json:"login"` RiskLevelStatus string `json:"riskLevelStatus"` IsFree bool `json:"isFree"` IsSubscribe bool `json:"isSubscribe"` SubscribeStatus string `json:"subscribeStatus"` Price string `json:"price"` ProductId int `json:"productId"` IsPackage bool `json:"isPackage"` Score float64 `json:"score"` Show bool `json:"-"` } func (bk BookMarkReport) GetID() int { return bk.ReportID } func (bk BookMarkReport) GetSourceType() string { return ReportBookMark } func (bk BookMarkChart) GetID() int { return bk.ChartInfoId } func (bk BookMarkChart) GetSourceType() string { return ChartBookMark } // func SearchBookMark(key string, sourceType string, ids []int, pageInfo page.PageInfo, userId int) (list []BookMarkInterface, err error) { // // }