diff --git a/api/vote_record/v1/vote_record.go b/api/vote_record/v1/vote_record.go index af81911..bb2e5d8 100644 --- a/api/vote_record/v1/vote_record.go +++ b/api/vote_record/v1/vote_record.go @@ -5,9 +5,16 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) -type GetVoteDetailListRes struct { - VoteList []*GetVoteDetailRes `json:"voteList"` - TotalCount int `json:"totalCount"` +type GetExportFileReq struct { + g.Meta `path:"/getExportVoteDetail" method:"get" tags:"获取投票名单列表"` + VoteId int `p:"voteId" v:"required" dc:"投票活动ID"` + Username string `p:"username" dc:"<用户名>"` + Account string `p:"account" dc:"<精网号>"` + Area string `p:"area" dc:"地区"` + OptionContent string `p:"optionContent" dc:"<选项>"` +} +type GetExportFileRes struct { + VoteList []*GetVoteDetailRes `json:"voteList"` } type GetVoteDetailReq struct { g.Meta `path:"/getAllVoteDetail" method:"get" tags:"获取投票名单列表"` @@ -16,6 +23,7 @@ type GetVoteDetailReq struct { Size int `p:"size" dc:"每页数量" default:"50"` Username string `p:"username" dc:"<用户名>"` Account string `p:"account" dc:"<精网号>"` + Area string `p:"area" dc:"地区"` OptionContent string `p:"optionContent" dc:"<选项>"` } @@ -24,9 +32,14 @@ type GetVoteDetailRes struct { Account string `json:"account" dc:"精网号"` //VoteTitle string `json:"voteTitle" dc:"投票标题"` //ArticleTitle string `json:"articleTitle" dc:"文章/视频标题"` + Area string `json:"area" dc:"地区"` OptionContents string `json:"optionContents" dc:"选项名称"` CreateTime *gtime.Time `json:"createTime" dc:"投票时间"` } +type GetVoteDetailListRes struct { + VoteList []*GetVoteDetailRes `json:"voteList"` + TotalCount int `json:"totalCount"` +} type GetVoteReq struct { g.Meta `path:"/getVote" method:"get" tags:"<获取文章及投票活动>"` ArticleId int `p:"articleId" v:"required" dc:"<文章>ID"` @@ -61,6 +74,7 @@ type GetIndexRes struct { type AddRecordReq struct { g.Meta `path:"/addRecord" method:"post" dc:""` + ArticleId int ` v:"required" json:"articleId" dc:"<ID>"` UserId int `v:"required" json:"userId" dc:"<用户>ID"` VoteId int `v:"required" json:"voteId" dc:"<投票活动>ID"` OptionId []int `v:"required" json:"optionId" dc:"<投票选项>ID"` diff --git a/api/vote_record/vote_record.go b/api/vote_record/vote_record.go index 7e9e2bc..03f5181 100644 --- a/api/vote_record/vote_record.go +++ b/api/vote_record/vote_record.go @@ -11,6 +11,7 @@ import ( ) type IVoteRecordV1 interface { + GetExportFile(ctx context.Context, req *v1.GetExportFileReq) (res *v1.GetExportFileRes, err error) GetVoteDetail(ctx context.Context, req *v1.GetVoteDetailReq) (res *v1.GetVoteDetailListRes, err error) GetVote(ctx context.Context, req *v1.GetVoteReq) (res *v1.GetVoteRes, err error) GetIndex(ctx context.Context, req *v1.GetIndexReq) (res *v1.GetIndexRes, err error) diff --git a/hack/config.yaml b/hack/config.yaml index 2e1a0e6..5837e80 100644 --- a/hack/config.yaml +++ b/hack/config.yaml @@ -4,7 +4,7 @@ gfcli: gen: dao: - - link: "mysql:root:root@tcp(127.0.0.1:3306)/link_test" + - link: "mysql:root:123456@tcp(127.0.0.1:3306)/link_test" descriptionTag: true docker: diff --git a/internal/consts/consts.go b/internal/consts/consts.go index d709a2b..0d60042 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -1 +1,12 @@ package consts + +const ( + BASE_TTL = 600 + RANDOM_RANGE = 60 +) + +const ( + VOTE_DETAIL = "voteDetail" //投票名单查询 + ARTICLE = "article" //文章查询 + EXPORT_FILE = "exportFile" //导出数据查询 +) diff --git a/internal/controller/vote_record/vote_record_v1_get_export_file.go b/internal/controller/vote_record/vote_record_v1_get_export_file.go new file mode 100644 index 0000000..8d92b3c --- /dev/null +++ b/internal/controller/vote_record/vote_record_v1_get_export_file.go @@ -0,0 +1,12 @@ +package vote_record + +import ( + "context" + "practice_ArticleVote_Go/internal/service" + + "practice_ArticleVote_Go/api/vote_record/v1" +) + +func (c *ControllerV1) GetExportFile(ctx context.Context, req *v1.GetExportFileReq) (res *v1.GetExportFileRes, err error) { + return service.NewVoteRecordService().ExportVoteDetail(ctx, req) +} diff --git a/internal/dao/internal/article.go b/internal/dao/internal/article.go index e816d09..2cb4956 100644 --- a/internal/dao/internal/article.go +++ b/internal/dao/internal/article.go @@ -22,7 +22,7 @@ type ArticleDao struct { // ArticleColumns defines and stores column names for the table article. type ArticleColumns struct { Id string // - UserId string // 用户ID + UserId string // ArticleTitle string // 文章/视频标题 ArticleContent string // 文章/视频内容 VoteStatus string // 是否发起投票:1发起,0不发起 diff --git a/internal/dao/internal/user.go b/internal/dao/internal/user.go index 278bdd1..fa0d8d5 100644 --- a/internal/dao/internal/user.go +++ b/internal/dao/internal/user.go @@ -22,9 +22,10 @@ type UserDao struct { // UserColumns defines and stores column names for the table user. type UserColumns struct { Id string // - Account string // 精网号 - Password string // 用户密码 - Username string // 用户名 + Account string // + Password string // + Username string // + Area string // Status string // CreateTime string // UpdateTime string // @@ -36,6 +37,7 @@ var userColumns = UserColumns{ Account: "account", Password: "password", Username: "username", + Area: "area", Status: "status", CreateTime: "create_time", UpdateTime: "update_time", diff --git a/internal/dao/internal/vote_poll.go b/internal/dao/internal/vote_poll.go index 396344d..c7005a3 100644 --- a/internal/dao/internal/vote_poll.go +++ b/internal/dao/internal/vote_poll.go @@ -27,8 +27,8 @@ type VotePollColumns struct { MultiOption string // 是否开启多选:1多选,0不多选 DeadlineTime string // 截止时间 CreateTime string // - UpdateTime string // Status string // 投票活动状态:1:进行中,0已结束 + UpdateTime string // } // votePollColumns holds the columns for the table vote_poll. @@ -39,8 +39,8 @@ var votePollColumns = VotePollColumns{ MultiOption: "multi_option", DeadlineTime: "deadline_time", CreateTime: "create_time", - UpdateTime: "update_time", Status: "status", + UpdateTime: "update_time", } // NewVotePollDao creates and returns a new DAO object for table data access. diff --git a/internal/dao/internal/vote_record.go b/internal/dao/internal/vote_record.go index 42d1b04..b7fb7f1 100644 --- a/internal/dao/internal/vote_record.go +++ b/internal/dao/internal/vote_record.go @@ -22,11 +22,11 @@ type VoteRecordDao struct { // VoteRecordColumns defines and stores column names for the table vote_record. type VoteRecordColumns struct { Id string // - UserId string // 用户ID - VoteId string // 投票活动ID - OptionId string // 投票选项ID - VoteIndex string // 已投票次数 + UserId string // + VoteId string // + OptionId string // CreateTime string // + VoteIndex string // UpdateTime string // } @@ -36,8 +36,8 @@ var voteRecordColumns = VoteRecordColumns{ UserId: "user_id", VoteId: "vote_id", OptionId: "option_id", - VoteIndex: "vote_index", CreateTime: "create_time", + VoteIndex: "vote_index", UpdateTime: "update_time", } diff --git a/internal/logic/vote_record/add_record.go b/internal/logic/vote_record/add_record.go index 3499b32..9e41e77 100644 --- a/internal/logic/vote_record/add_record.go +++ b/internal/logic/vote_record/add_record.go @@ -2,10 +2,14 @@ package vote_record import ( "context" + "fmt" + "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" v1 "practice_ArticleVote_Go/api/vote_record/v1" + "practice_ArticleVote_Go/internal/consts" "practice_ArticleVote_Go/internal/dao" "practice_ArticleVote_Go/internal/model/do" + "practice_ArticleVote_Go/internal/utils" ) func (l *VoteRecordLogic) AddRecord(ctx context.Context, req *v1.AddRecordReq) (res *v1.AddRecordRes, err error) { @@ -22,19 +26,16 @@ func (l *VoteRecordLogic) AddRecord(ctx context.Context, req *v1.AddRecordReq) ( }) } _, err = dao.VoteRecord.Ctx(ctx).Data(records).Insert() - //_, err = dao.VoteRecord. - // Ctx(ctx). - // Data(do.VoteRecord{ - // UserId: req.UserId, - // VoteId: req.VoteId, - // OptionId: req.OptionId, - // VoteIndex: req.VoteIndex, - // CreateTime: gtime.Now(), - // UpdateTime: gtime.Now(), - // }).Insert() if err != nil { return nil, err } + voteDetailPattern := fmt.Sprintf(consts.VOTE_DETAIL+":%d:*", req.VoteId) + _, err = utils.DeleteKeys(ctx, voteDetailPattern) + exportFilePattern := fmt.Sprintf(consts.EXPORT_FILE+":%d:*", req.VoteId) + _, err = utils.DeleteKeys(ctx, exportFilePattern) + articleAndVote := fmt.Sprintf(consts.ARTICLE+":%d", req.ArticleId) + redis := g.Redis() + _, err = redis.Del(ctx, articleAndVote) res = &v1.AddRecordRes{} return res, nil } diff --git a/internal/logic/vote_record/get_export_file.go b/internal/logic/vote_record/get_export_file.go new file mode 100644 index 0000000..59ad9c2 --- /dev/null +++ b/internal/logic/vote_record/get_export_file.go @@ -0,0 +1,87 @@ +package vote_record + +import ( + "context" + "encoding/json" + "fmt" + "github.com/gogf/gf/v2/frame/g" + v1 "practice_ArticleVote_Go/api/vote_record/v1" + "practice_ArticleVote_Go/internal/consts" + "practice_ArticleVote_Go/internal/utils" +) + +func (l *VoteRecordLogic) ExportVoteDetail(ctx context.Context, req *v1.GetExportFileReq) (res *v1.GetExportFileRes, err error) { + redis := g.Redis() + cacheKey := fmt.Sprintf( + consts.EXPORT_FILE+":%d:%s:%s:%s:%s", + req.VoteId, req.Username, req.Account, req.Area, req.OptionContent, + ) + data, _ := redis.Get(ctx, cacheKey) + fmt.Println("data", data) + if data != nil { + var cached v1.GetExportFileRes + err = json.Unmarshal([]byte(data.String()), &cached) + if err == nil { + return &cached, nil + } + } + query := ` + SELECT + u.username, + u.account, + u.area, + uv.option_contents, + uv.create_time + FROM ( + SELECT + vr.user_id, + vr.vote_index, + DATE(vr.create_time) AS vote_date, + MAX(vr.create_time) AS create_time, + GROUP_CONCAT(o.option_content ORDER BY o.id SEPARATOR ',') AS option_contents + FROM vote_record vr + JOIN vote_option o + ON vr.option_id = o.id + WHERE vr.vote_id = ? + GROUP BY vr.user_id, vr.vote_index, vote_date + ) AS uv + JOIN user u ON u.id = uv.user_id + WHERE 1=1 + ` + + conditions := []interface{}{req.VoteId} + + if req.OptionContent != "" { + query += " AND uv.option_contents LIKE ?" + conditions = append(conditions, "%"+req.OptionContent+"%") + } + if req.Username != "" { + query += " AND u.username LIKE ?" + conditions = append(conditions, "%"+req.Username+"%") + } + if req.Account != "" { + query += " AND u.account LIKE ?" + conditions = append(conditions, "%"+req.Account+"%") + } + if req.Area != "" { + query += " AND u.area LIKE ?" + conditions = append(conditions, "%"+req.Area+"%") + } + query += " ORDER BY uv.create_time DESC " + var voteList []*v1.GetVoteDetailRes + err = g.DB().Ctx(ctx). + Raw(query, conditions...). + Scan(&voteList) + if err != nil { + return nil, err + } + res = &v1.GetExportFileRes{ + VoteList: voteList, + } + buf, err := json.Marshal(res) + if err == nil { + ttl := utils.GetCacheTTL() + _ = redis.SetEX(ctx, cacheKey, string(buf), int64(ttl)) + } + return res, err +} diff --git a/internal/logic/vote_record/get_vote.go b/internal/logic/vote_record/get_vote.go index c4827c8..f6a4397 100644 --- a/internal/logic/vote_record/get_vote.go +++ b/internal/logic/vote_record/get_vote.go @@ -2,15 +2,34 @@ package vote_record import ( "context" + "encoding/json" + "fmt" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" v1 "practice_ArticleVote_Go/api/vote_record/v1" + "practice_ArticleVote_Go/internal/consts" "practice_ArticleVote_Go/internal/dao" + "practice_ArticleVote_Go/internal/utils" ) func (l *VoteRecordLogic) GetVote(ctx context.Context, req *v1.GetVoteReq) (res *v1.GetVoteRes, err error) { + redis := g.Redis() + cacheKey := fmt.Sprintf( + consts.ARTICLE+":%d", + req.ArticleId, + ) + fmt.Println(cacheKey) + data, _ := redis.Get(ctx, cacheKey) + fmt.Println("data", data) + if data != nil { + var cached v1.GetVoteRes + err = json.Unmarshal([]byte(data.String()), &cached) + if err == nil { + return &cached, nil + } + } articleRow, err := dao.Article.Ctx(ctx). Fields( dao.Article.Columns().ArticleTitle, @@ -58,10 +77,10 @@ func (l *VoteRecordLogic) GetVote(ctx context.Context, req *v1.GetVoteReq) (res res.DeadlineTime = votePoll[dao.VotePoll.Columns().DeadlineTime].GTime() res.ParticipationNumber = votePoll["totalCount"].Int() res.VotePollStatus = votePoll[dao.VotePoll.Columns().Status].Int() - if res.DeadlineTime.Before(gtime.Now()) && res.VotePollStatus != 0 { - res.VotePollStatus = 0 + if res.DeadlineTime.Before(gtime.Now()) && res.VotePollStatus != 2 { + res.VotePollStatus = 2 _, err = dao.VotePoll.Ctx(ctx).Data(g.Map{ - dao.VotePoll.Columns().Status: 0, + dao.VotePoll.Columns().Status: 2, }).WherePri(res.VoteId).Update() if err != nil { return nil, err @@ -87,5 +106,10 @@ func (l *VoteRecordLogic) GetVote(ctx context.Context, req *v1.GetVoteReq) (res OrderAsc(dao.VoteOption.Columns().OptionIndex). Scan(&res.OptionList) } + buf, err := json.Marshal(res) + if err == nil { + ttl := utils.GetCacheTTL() + _ = redis.SetEX(ctx, cacheKey, string(buf), int64(ttl)) + } return res, nil } diff --git a/internal/logic/vote_record/get_vote_detail.go b/internal/logic/vote_record/get_vote_detail.go index 8afdd34..2ce2f40 100644 --- a/internal/logic/vote_record/get_vote_detail.go +++ b/internal/logic/vote_record/get_vote_detail.go @@ -2,9 +2,12 @@ package vote_record import ( "context" + "encoding/json" "fmt" "github.com/gogf/gf/v2/frame/g" v1 "practice_ArticleVote_Go/api/vote_record/v1" + "practice_ArticleVote_Go/internal/consts" + "practice_ArticleVote_Go/internal/utils" ) func (l *VoteRecordLogic) GetVoteDetail(ctx context.Context, req *v1.GetVoteDetailReq) (res *v1.GetVoteDetailListRes, err error) { @@ -42,10 +45,27 @@ func (l *VoteRecordLogic) GetVoteDetail(ctx context.Context, req *v1.GetVoteDeta // return nil, err //} //return res, nil + redis := g.Redis() + cacheKey := fmt.Sprintf( + consts.VOTE_DETAIL+":%d:%d:%d:%s:%s:%s:%s", + req.VoteId, req.Page, req.Size, + req.Username, req.Account, req.Area, req.OptionContent, + ) + fmt.Println(cacheKey) + data, _ := redis.Get(ctx, cacheKey) + fmt.Println("data", data) + if data != nil { + var cached v1.GetVoteDetailListRes + err = json.Unmarshal([]byte(data.String()), &cached) + if err == nil { + return &cached, nil + } + } query := ` SELECT u.username, u.account, + u.area, uv.option_contents, uv.create_time FROM ( @@ -61,13 +81,10 @@ func (l *VoteRecordLogic) GetVoteDetail(ctx context.Context, req *v1.GetVoteDeta WHERE vr.vote_id = ? GROUP BY vr.user_id, vr.vote_index, vote_date ) AS uv - JOIN ` + "`user`" + ` u - ON u.id = uv.user_id - WHERE 1=1 + JOIN user u ON u.id = uv.user_id + WHERE 1=1 ` - conditions := []interface{}{req.VoteId} - if req.OptionContent != "" { query += " AND uv.option_contents LIKE ?" conditions = append(conditions, "%"+req.OptionContent+"%") @@ -80,6 +97,10 @@ func (l *VoteRecordLogic) GetVoteDetail(ctx context.Context, req *v1.GetVoteDeta query += " AND u.account LIKE ?" conditions = append(conditions, "%"+req.Account+"%") } + if req.Area != "" { + query += " AND u.area LIKE ?" + conditions = append(conditions, "%"+req.Area+"%") + } countQuery := "SELECT COUNT(*) AS cnt FROM ( " + query + " ) AS subquery" var cntResult struct{ Cnt int } err = g.DB().Ctx(ctx).Raw(countQuery, conditions...).Scan(&cntResult) @@ -98,5 +119,10 @@ func (l *VoteRecordLogic) GetVoteDetail(ctx context.Context, req *v1.GetVoteDeta return nil, err } res.VoteList = voteList + buf, merr := json.Marshal(res) + if merr == nil { + ttl := utils.GetCacheTTL() + _ = redis.SetEX(ctx, cacheKey, string(buf), int64(ttl)) + } return res, nil } diff --git a/internal/model/do/article.go b/internal/model/do/article.go index f34c33c..f4994d7 100644 --- a/internal/model/do/article.go +++ b/internal/model/do/article.go @@ -13,7 +13,7 @@ import ( type Article struct { g.Meta `orm:"table:article, do:true"` Id interface{} // - UserId interface{} // 用户ID + UserId interface{} // ArticleTitle interface{} // 文章/视频标题 ArticleContent interface{} // 文章/视频内容 VoteStatus interface{} // 是否发起投票:1发起,0不发起 diff --git a/internal/model/do/user.go b/internal/model/do/user.go index a2b8e80..d3b7707 100644 --- a/internal/model/do/user.go +++ b/internal/model/do/user.go @@ -13,9 +13,10 @@ import ( type User struct { g.Meta `orm:"table:user, do:true"` Id interface{} // - Account interface{} // 精网号 - Password interface{} // 用户密码 - Username interface{} // 用户名 + Account interface{} // + Password interface{} // + Username interface{} // + Area interface{} // Status interface{} // CreateTime *gtime.Time // UpdateTime *gtime.Time // diff --git a/internal/model/do/vote_poll.go b/internal/model/do/vote_poll.go index 54cb5e5..67ea16b 100644 --- a/internal/model/do/vote_poll.go +++ b/internal/model/do/vote_poll.go @@ -18,6 +18,6 @@ type VotePoll struct { MultiOption interface{} // 是否开启多选:1多选,0不多选 DeadlineTime *gtime.Time // 截止时间 CreateTime *gtime.Time // - UpdateTime *gtime.Time // Status interface{} // 投票活动状态:1:进行中,0已结束 + UpdateTime *gtime.Time // } diff --git a/internal/model/do/vote_record.go b/internal/model/do/vote_record.go index 3b9130e..26a7058 100644 --- a/internal/model/do/vote_record.go +++ b/internal/model/do/vote_record.go @@ -13,10 +13,10 @@ import ( type VoteRecord struct { g.Meta `orm:"table:vote_record, do:true"` Id interface{} // - UserId interface{} // 用户ID - VoteId interface{} // 投票活动ID - OptionId interface{} // 投票选项ID - VoteIndex interface{} // 已投票次数 + UserId interface{} // + VoteId interface{} // + OptionId interface{} // CreateTime *gtime.Time // + VoteIndex interface{} // UpdateTime *gtime.Time // } diff --git a/internal/model/entity/article.go b/internal/model/entity/article.go index 9484a4f..0b7ff15 100644 --- a/internal/model/entity/article.go +++ b/internal/model/entity/article.go @@ -11,7 +11,7 @@ import ( // Article is the golang structure for table article. type Article struct { Id int64 `json:"id" orm:"id" description:""` // - UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + UserId int64 `json:"userId" orm:"user_id" description:""` // ArticleTitle string `json:"articleTitle" orm:"article_title" description:"文章/视频标题"` // 文章/视频标题 ArticleContent string `json:"articleContent" orm:"article_content" description:"文章/视频内容"` // 文章/视频内容 VoteStatus int `json:"voteStatus" orm:"vote_status" description:"是否发起投票:1发起,0不发起"` // 是否发起投票:1发起,0不发起 diff --git a/internal/model/entity/user.go b/internal/model/entity/user.go index efbde32..7b8bcb6 100644 --- a/internal/model/entity/user.go +++ b/internal/model/entity/user.go @@ -10,11 +10,12 @@ import ( // User is the golang structure for table user. type User struct { - Id int64 `json:"id" orm:"id" description:""` // - Account string `json:"account" orm:"account" description:"精网号"` // 精网号 - Password string `json:"password" orm:"password" description:"用户密码"` // 用户密码 - Username string `json:"username" orm:"username" description:"用户名"` // 用户名 - Status uint `json:"status" orm:"status" description:""` // - CreateTime *gtime.Time `json:"createTime" orm:"create_time" description:""` // - UpdateTime *gtime.Time `json:"updateTime" orm:"update_time" description:""` // + Id int64 `json:"id" orm:"id" description:""` // + Account string `json:"account" orm:"account" description:""` // + Password string `json:"password" orm:"password" description:""` // + Username string `json:"username" orm:"username" description:""` // + Area string `json:"area" orm:"area" description:""` // + Status uint `json:"status" orm:"status" description:""` // + CreateTime *gtime.Time `json:"createTime" orm:"create_time" description:""` // + UpdateTime *gtime.Time `json:"updateTime" orm:"update_time" description:""` // } diff --git a/internal/model/entity/vote_poll.go b/internal/model/entity/vote_poll.go index 43459dc..192d964 100644 --- a/internal/model/entity/vote_poll.go +++ b/internal/model/entity/vote_poll.go @@ -16,6 +16,6 @@ type VotePoll struct { MultiOption int `json:"multiOption" orm:"multi_option" description:"是否开启多选:1多选,0不多选"` // 是否开启多选:1多选,0不多选 DeadlineTime *gtime.Time `json:"deadlineTime" orm:"deadline_time" description:"截止时间"` // 截止时间 CreateTime *gtime.Time `json:"createTime" orm:"create_time" description:""` // - UpdateTime *gtime.Time `json:"updateTime" orm:"update_time" description:""` // Status int `json:"status" orm:"status" description:"投票活动状态:1:进行中,0已结束"` // 投票活动状态:1:进行中,0已结束 + UpdateTime *gtime.Time `json:"updateTime" orm:"update_time" description:""` // } diff --git a/internal/model/entity/vote_record.go b/internal/model/entity/vote_record.go index 056a44e..a11c458 100644 --- a/internal/model/entity/vote_record.go +++ b/internal/model/entity/vote_record.go @@ -10,11 +10,11 @@ import ( // VoteRecord is the golang structure for table vote_record. type VoteRecord struct { - Id int64 `json:"id" orm:"id" description:""` // - UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID - VoteId int64 `json:"voteId" orm:"vote_id" description:"投票活动ID"` // 投票活动ID - OptionId int64 `json:"optionId" orm:"option_id" description:"投票选项ID"` // 投票选项ID - VoteIndex int `json:"voteIndex" orm:"vote_index" description:"已投票次数"` // 已投票次数 - CreateTime *gtime.Time `json:"createTime" orm:"create_time" description:""` // - UpdateTime *gtime.Time `json:"updateTime" orm:"update_time" description:""` // + Id int64 `json:"id" orm:"id" description:""` // + UserId int64 `json:"userId" orm:"user_id" description:""` // + VoteId int64 `json:"voteId" orm:"vote_id" description:""` // + OptionId int64 `json:"optionId" orm:"option_id" description:""` // + CreateTime *gtime.Time `json:"createTime" orm:"create_time" description:""` // + VoteIndex int `json:"voteIndex" orm:"vote_index" description:""` // + UpdateTime *gtime.Time `json:"updateTime" orm:"update_time" description:""` // } diff --git a/internal/service/vote_record.go b/internal/service/vote_record.go index 339b602..3691286 100644 --- a/internal/service/vote_record.go +++ b/internal/service/vote_record.go @@ -7,6 +7,7 @@ import ( ) type IVoteRecord interface { + ExportVoteDetail(ctx context.Context, req *v1.GetExportFileReq) (res *v1.GetExportFileRes, err error) GetIndex(ctx context.Context, req *v1.GetIndexReq) (res *v1.GetIndexRes, err error) AddRecord(ctx context.Context, req *v1.AddRecordReq) (res *v1.AddRecordRes, err error) GetVote(ctx context.Context, req *v1.GetVoteReq) (res *v1.GetVoteRes, err error) diff --git a/internal/utils/cachettl.go b/internal/utils/cachettl.go new file mode 100644 index 0000000..7f7df19 --- /dev/null +++ b/internal/utils/cachettl.go @@ -0,0 +1,13 @@ +package utils + +import ( + "math/rand" + "practice_ArticleVote_Go/internal/consts" + "time" +) + +func GetCacheTTL() time.Duration { + baseTTL := consts.BASE_TTL + randomNumber := rand.Intn(consts.RANDOM_RANGE) + return time.Duration(baseTTL+randomNumber) * time.Second +} diff --git a/internal/utils/delete_keys.go b/internal/utils/delete_keys.go new file mode 100644 index 0000000..d71fdec --- /dev/null +++ b/internal/utils/delete_keys.go @@ -0,0 +1,45 @@ +package utils + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +func DeleteKeys(ctx context.Context, pattern string) (int, error) { + redis := g.Redis() + var ( + cursor uint64 + totalKeys int + batchSize = 100 + ) + g.Log().Debugf(ctx, "开始删除匹配模式 %q 的缓存键", pattern) + for { + result, err := redis.Do(ctx, "SCAN", cursor, "MATCH", pattern, "COUNT", batchSize) + if err != nil { + return totalKeys, fmt.Errorf("SCAN 失败: %v", err) + } + arr := result.Array() + fmt.Println("arr:", arr) + cursor = gconv.Uint64(arr[0]) + rawKeys := gconv.Strings(arr[1]) + var keys []string + for _, k := range rawKeys { + keys = append(keys, k) + } + fmt.Println("keys:", keys) + if len(keys) > 0 { + deleted, err := redis.Del(ctx, keys...) + if err != nil { + g.Log().Warningf(ctx, "缓存删除异常: %v", err) + } + totalKeys += int(deleted) + g.Log().Debugf(ctx, "本次删除 %d/%d 个键", deleted, len(keys)) + } + if cursor == 0 { + break + } + } + return totalKeys, nil +} diff --git a/main.go b/main.go index dcf78da..81c91e5 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,8 @@ import ( "github.com/gogf/gf/v2/os/gctx" + _ "github.com/gogf/gf/contrib/nosql/redis/v2" + "practice_ArticleVote_Go/internal/cmd" ) diff --git a/manifest/config/config.yaml b/manifest/config/config.yaml index f2fc73d..30c112d 100644 --- a/manifest/config/config.yaml +++ b/manifest/config/config.yaml @@ -14,4 +14,14 @@ database: default: link: "mysql:root:root@tcp(127.0.0.1:3306)/link_test?loc=Local&parseTime=true" createdAt: "create_time" - updatedAt: "update_time" \ No newline at end of file + updatedAt: "update_time" + +redis: + default: # 默认实例,用于常规操作 + address: "127.0.0.1:6379" + db: 0 + password: "" + cache: # 缓存专用实例 + address: "127.0.0.1:6379" + db: 1 + password: ""