You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
10 KiB
Go

1 month ago
package article
import (
"cls/internal/domain/article"
"cls/internal/domain/column"
1 month ago
"cls/internal/domain/free_trial"
"cls/internal/domain/purchase"
domainUser "cls/internal/domain/user"
"cls/pkg/logger"
"cls/pkg/util/page"
"errors"
"fmt"
1 month ago
"strings"
"time"
"xorm.io/builder"
)
type ArticleService struct {
repo article.ArticleRepository
userRepo domainUser.UserRepository
columnRepo column.ColumnRepository
purchaseRepo purchase.Repository
userAggregateRepo domainUser.UserAggregateRepository
FreeRepo free_trial.FreeTrialRepository
log logger.Logger
1 month ago
}
func NewArticleService(repo article.ArticleRepository,
userRepo domainUser.UserRepository,
purchaseRepo purchase.Repository,
columnRepo column.ColumnRepository,
userAggregateRepo domainUser.UserAggregateRepository,
1 month ago
FreeRepo free_trial.FreeTrialRepository,
log logger.New) *ArticleService {
return &ArticleService{repo,
userRepo,
columnRepo,
1 month ago
purchaseRepo,
userAggregateRepo,
1 month ago
FreeRepo,
log("cls:service:article")}
}
var class_type = map[uint64]string{
1 month ago
20014: "狙击龙虎榜",
20013: "九点特供",
1 month ago
20015: "盘中宝",
20021: "风口研报",
20022: "公告全知道",
20023: "研选",
20025: "财联社早知道",
20026: "电报解读",
20087: "金牌纪要库",
}
var class_type_reverse = map[string]uint64{
1 month ago
"狙击龙虎榜": 20014,
"九点特供": 20013,
1 month ago
"盘中宝": 20015,
"风口研报": 20021,
"公告全知道": 20022,
"研选": 20023,
"财联社早知道": 20025,
"电报解读": 20026,
"金牌纪要库": 20087,
}
var column_class = map[uint64]uint64{
81201: 20015,
81202: 20014,
81204: 20021,
81205: 20013,
81206: 20022,
81208: 20023,
81209: 20025,
81210: 20026,
81232: 20087,
}
1 month ago
func (a *ArticleService) Find(ePhone string, page *page.Page, searchParams map[string]string) error {
conds := make([]builder.Cond, 0)
columnInfo := &column.Column{}
var err error
class := searchParams["search_eq_class"]
1 month ago
if class != "" {
columnInfo, err = a.columnRepo.FindByName(class)
if err != nil {
a.log.Error(err)
}
1 month ago
classCode := class_type_reverse[class]
if classCode != 0 {
conds = append(conds, builder.Eq{"type": classCode})
conds = append(conds, builder.And(builder.Gt{"ctime": time.Now().AddDate(0, 0, -10).Unix()}).And(builder.Eq{"is_free": 0}))
1 month ago
}
} else {
conds = append(conds, builder.And(builder.Gt{"ctime": time.Now().AddDate(0, 0, -2).Unix()}).And(builder.Eq{"is_free": 0}))
1 month ago
}
articles := make([]*article.LianV1Article, 0)
page.Content = &articles
err = a.repo.Find(page, conds)
1 month ago
if err != nil {
a.log.Error(err)
return err
}
purchaseId := make(map[uint64]struct{})
if ePhone != "" {
user, err := a.userRepo.FindByPhone(ePhone)
if err != nil {
a.log.Error(err)
}
if user != nil {
var columnData []*purchase.Purchase
if columnInfo != nil && columnInfo.ID > 0 {
columnData, err = a.purchaseRepo.FindColumnById(user.Id, columnInfo.ID)
} else {
columnData, err = a.purchaseRepo.FindColumnsByUserId(user.Id)
}
columnMap := make(map[uint64]struct{})
if len(columnData) != 0 {
for _, v := range columnData {
columnMap[column_class[v.ContentId]] = struct{}{}
}
}
articleIds := make([]uint64, 0, len(articles))
for _, v := range articles {
_, has := columnMap[v.Type]
if has {
purchaseId[v.Id] = struct{}{}
} else {
articleIds = append(articleIds, v.Id)
}
}
purchaseData, err := a.purchaseRepo.FindArticleById(user.Id, articleIds...)
articleIds = nil
if err != nil {
a.log.Error(err.Error())
}
if purchaseData != nil {
for _, v := range purchaseData {
purchaseId[v.ContentId] = struct{}{}
}
1 month ago
}
articleIds = nil
}
1 month ago
}
1 month ago
result := make([]*ArticleDto, 0, len(articles))
for _, v := range articles {
t := time.Unix(v.Ctime, 0) // 秒数和纳秒数0 表示没有纳秒部分
m, g := a.getMainGrowthBoard(v.Stocks)
_, lock := purchaseId[v.Id]
ad := &ArticleDto{
1 month ago
EventId: v.Id,
Title: v.Title,
Class: class_type[v.Type],
ReleaseDate: t.Format("2006-01-02"),
ReleaseTime: t.Format("15:04"),
Brief: v.Brief,
MainBoard: m,
GrowthBoard: g,
Unlock: lock,
}
if lock {
ad.Stocks = v.Stocks
ad.Content = v.Content
}
result = append(result, ad)
1 month ago
}
purchaseId = nil
1 month ago
articles = nil
page.Content = &result
return nil
}
func (a *ArticleService) FindUnLock(ePhone string, page *page.Page, searchParams map[string]string) error {
user, err := a.userRepo.FindByPhone(ePhone)
if err != nil {
a.log.Error(err)
return err
}
if user == nil {
return errors.New("未找到用户")
}
1 month ago
conds := make([]builder.Cond, 0)
class := searchParams["search_eq_class"]
1 month ago
if class != "" {
classCode := class_type_reverse[class]
if classCode != 0 {
conds = append(conds, builder.Eq{"type": classCode})
}
}
purchaseData, err := a.purchaseRepo.FindArticlesByUserId(user.Id)
if err != nil {
a.log.Error(err)
return err
}
if len(purchaseData) == 0 {
return nil
}
pId := make([]uint64, 0, len(purchaseData))
for _, v := range purchaseData {
pId = append(pId, v.ContentId)
}
conds = append(conds, builder.In("id", pId))
1 month ago
articles := make([]*article.LianV1Article, 0)
page.Content = &articles
err = a.repo.Find(page, conds)
if err != nil {
a.log.Error(err)
return err
}
result := make([]*ArticleDto, 0, len(articles))
for _, v := range articles {
t := time.Unix(v.Ctime, 0) // 秒数和纳秒数0 表示没有纳秒部分
m, g := a.getMainGrowthBoard(v.Stocks)
result = append(result, &ArticleDto{
EventId: v.Id,
Title: v.Title,
Class: class_type[v.Type],
ReleaseDate: t.Format("2006-01-02"),
ReleaseTime: t.Format("15:04"),
Brief: v.Brief,
Content: v.Content,
Stocks: v.Stocks,
MainBoard: m,
GrowthBoard: g,
Unlock: true,
1 month ago
})
}
articles = nil
page.Content = &result
return nil
}
func (a *ArticleService) FindFree(page *page.Page, searchParams map[string]string) error {
conds := make([]builder.Cond, 0)
class := searchParams["search_eq_class"]
1 month ago
if class != "" {
classCode := class_type_reverse[class]
if classCode != 0 {
conds = append(conds, builder.Eq{"type": classCode})
conds = append(conds, builder.And(builder.Lt{"ctime": time.Now().AddDate(0, 0, -10).Unix()}).And(builder.Eq{"is_free": 1}))
1 month ago
}
} else {
conds = append(conds, builder.And(builder.Lt{"ctime": time.Now().AddDate(0, 0, -2).Unix()}).And(builder.Eq{"is_free": 1}))
1 month ago
}
articles := make([]*article.LianV1Article, 0)
page.Content = &articles
err := a.repo.Find(page, conds)
if err != nil {
a.log.Error(err)
return err
}
result := make([]*ArticleDto, 0, len(articles))
for _, v := range articles {
t := time.Unix(v.Ctime, 0) // 秒数和纳秒数0 表示没有纳秒部分
m, g := a.getMainGrowthBoard(v.Stocks)
result = append(result, &ArticleDto{
EventId: v.Id,
Title: v.Title,
Class: class_type[v.Type],
ReleaseDate: t.Format("2006-01-02"),
ReleaseTime: t.Format("15:04"),
Brief: v.Brief,
Stocks: v.Stocks,
Content: v.Content,
MainBoard: m,
GrowthBoard: g,
Unlock: true,
})
}
articles = nil
page.Content = &result
return nil
}
func (a *ArticleService) Detail(userPhone string, id uint64) (*ArticleDto, error) {
user, err := a.userRepo.FindByPhone(userPhone)
if err != nil {
a.log.Error(err)
return nil, err
}
if user == nil {
return nil, errors.New("未找到用户")
}
p, err := a.purchaseRepo.FindArticleWithId(user.Id, id)
1 month ago
if err != nil {
a.log.Error(err)
return nil, err
}
articleDto := &ArticleDto{}
if p.Id < 1 {
1 month ago
articleDto.Unlock = false
return articleDto, nil
}
aInfo, err := a.repo.GetArticleById(id)
1 month ago
if err != nil {
a.log.Error(err)
return nil, err
}
t := time.Unix(aInfo.Ctime, 0)
m, g := a.getMainGrowthBoard(aInfo.Stocks)
1 month ago
return &ArticleDto{
EventId: aInfo.Id,
Title: aInfo.Title,
Class: class_type[aInfo.Type],
1 month ago
ReleaseDate: t.Format("2006-01-02"),
ReleaseTime: t.Format("15:04"),
Stocks: aInfo.Stocks,
Brief: aInfo.Brief,
1 month ago
MainBoard: m,
GrowthBoard: g,
Content: aInfo.Content,
1 month ago
Unlock: true,
}, nil
}
func (a *ArticleService) UnLockArticle(ePhone string, aid uint64) (*ArticleDto, error) {
// 1. 获取用户聚合根
userAggregate, err := a.userAggregateRepo.GetUserAggregate(ePhone)
1 month ago
if err != nil {
return nil, fmt.Errorf("获取用户信息失败: %w", err)
1 month ago
}
u := userAggregate.GetUser()
if u.GiftCount < 1 {
a.log.Errorf("用户【%d】免费次数不够", u.Id)
return nil, errors.New("没有次数了")
}
// 2. 获取文章
article, err := a.repo.GetArticleById(aid)
1 month ago
if err != nil {
return nil, fmt.Errorf("获取文章信息失败: %w", err)
1 month ago
}
// 3. 执行领域逻辑
if err := userAggregate.UnlockArticle(aid); err != nil {
return nil, fmt.Errorf("解锁文章失败: %w", err)
1 month ago
}
// 4. 保存聚合根状态
if err := a.userAggregateRepo.SaveUserAggregate(userAggregate); err != nil {
return nil, fmt.Errorf("保存用户状态失败: %w", err)
1 month ago
}
// 5. 返回结果
1 month ago
return &ArticleDto{
Stocks: article.Stocks,
Content: article.Content,
1 month ago
Unlock: true,
}, nil
}
func (a ArticleService) getMainGrowthBoard(stocks string) (int, int) {
if stocks == "" {
return 0, 0
}
// 将字符串分割成股票代码数组
stockList := strings.Split(stocks, ",")
mainBoardCount := 0 // 主板数量
growthBoardCount := 0 // 创业板数量
for _, stock := range stockList {
// 去除可能的空格
stock = strings.TrimSpace(stock)
// 检查股票代码长度是否合法sz/sh + 6位数字
if len(stock) < 8 {
continue
}
// 获取股票代码(去除市场前缀)
prefix := strings.ToLower(stock[0:2]) // 转换为小写
code := stock[2:]
// 检查前缀是否合法
if prefix != "sz" && prefix != "sh" {
continue
}
switch {
// 创业板: 300xxx 或 301xxx
case strings.HasPrefix(code, "300") || strings.HasPrefix(code, "301"):
growthBoardCount++
// 主板:
// 深圳主板 00xxxx
// 上海主板 60xxxx
case strings.HasPrefix(code, "000") || strings.HasPrefix(code, "001") ||
strings.HasPrefix(code, "002") || strings.HasPrefix(code, "600") ||
strings.HasPrefix(code, "601") || strings.HasPrefix(code, "603") ||
strings.HasPrefix(code, "605"):
mainBoardCount++
}
}
return mainBoardCount, growthBoardCount
}