diff --git a/models/user_business_analysis.go b/models/user_business_analysis.go index 00d8e3f8a..fb639459f 100644 --- a/models/user_business_analysis.go +++ b/models/user_business_analysis.go @@ -7,7 +7,6 @@ import ( "time" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) @@ -23,7 +22,7 @@ type UserBusinessAnalysis struct { //action :ActionCommitRepo // 5 CommitCount int `xorm:"NOT NULL DEFAULT 0"` - //action :ActionCommentIssue // 10 + //action :ActionCreateIssue // 10 IssueCount int `xorm:"NOT NULL DEFAULT 0"` //comment table current date @@ -160,10 +159,10 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus ) } cond = cond.And( - builder.Gte{"count_date": fmt.Sprint(pageStartTime)}, + builder.Gte{"count_date": pageStartTime.Unix()}, ) cond = cond.And( - builder.Lte{"count_date": fmt.Sprint(pageEndTime)}, + builder.Lte{"count_date": pageEndTime.Unix()}, ) count, err := statictisSess.Where(cond).Count(new(UserBusinessAnalysis)) @@ -183,7 +182,7 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus } statictisSess.OrderBy("count_date desc") - userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0, setting.UI.IssuePagingNum) + userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0) if err := statictisSess.Table("user_business_analysis").Where(cond). Find(&userBusinessAnalysisList); err != nil { return nil, 0 @@ -191,27 +190,29 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus resultMap := make(map[int64]*UserBusinessAnalysis) - var newAndCond = builder.NewCond() - var newOrCond = builder.NewCond() - for _, userRecord := range userBusinessAnalysisList { - newOrCond.Or( - builder.Eq{"id": userRecord.ID}, + if opts.Page >= 0 && opts.PageSize > 0 { + var newAndCond = builder.NewCond() + var newOrCond = builder.NewCond() + for _, userRecord := range userBusinessAnalysisList { + newOrCond = newOrCond.Or( + builder.Eq{"id": userRecord.ID}, + ) + } + newAndCond = newAndCond.And( + newOrCond, + ) + newAndCond = newAndCond.And( + builder.Gte{"count_date": opts.StartTime}, + ) + newAndCond = newAndCond.And( + builder.Lte{"count_date": opts.EndTime}, ) - } - newAndCond = newAndCond.And( - newOrCond, - ) - newAndCond = newAndCond.And( - builder.Gte{"count_date": fmt.Sprint(opts.StartTime)}, - ) - newAndCond = newAndCond.And( - builder.Lte{"count_date": fmt.Sprint(opts.EndTime)}, - ) - userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0) - if err := statictisSess.Table("user_business_analysis").Where(newAndCond). - Find(&userBusinessAnalysisList); err != nil { - return nil, 0 + userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0) + if err := statictisSess.Table("user_business_analysis").Where(newAndCond). + Find(&userBusinessAnalysisList); err != nil { + return nil, 0 + } } log.Info("query result size=" + fmt.Sprint(len(userBusinessAnalysisList))) @@ -245,7 +246,8 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus return userBusinessAnalysisReturnList, count } -func CounDataByDate(wikiCountMap map[string]int, startTime time.Time, endTime time.Time) { +func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, endTime time.Time, isReCount bool) { + log.Info("start to count other user info data") sess := x.NewSession() defer sess.Close() @@ -263,12 +265,15 @@ func CounDataByDate(wikiCountMap map[string]int, startTime time.Time, endTime ti //endTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location()) end_unix := endTime.Unix() - CountDate := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 1, 0, 0, currentTimeNow.Location()) + if isReCount { + CountDate = time.Date(startTime.Year(), startTime.Month(), startTime.Day(), 0, 1, 0, 0, currentTimeNow.Location()) + } + DataDate := startTime.Format("2006-01-02") CodeMergeCountMap := queryPullRequest(start_unix, end_unix) CommitCountMap := queryAction(start_unix, end_unix, 5) - IssueCountMap := queryAction(start_unix, end_unix, 10) + IssueCountMap := queryAction(start_unix, end_unix, 6) CommentCountMap := queryComment(start_unix, end_unix) FocusRepoCountMap := queryWatch(start_unix, end_unix) @@ -394,6 +399,10 @@ func CounDataByDate(wikiCountMap map[string]int, startTime time.Time, endTime ti } +func CounDataByDate(wikiCountMap map[string]int, startTime time.Time, endTime time.Time) { + CounDataByDateAndReCount(wikiCountMap, startTime, endTime, false) +} + func querySolveIssue(start_unix int64, end_unix int64) map[int64]int { //select issue_assignees.* from issue_assignees,issue where issue.is_closed=true and issue.id=issue_assignees.issue_id sess := x.NewSession() @@ -665,5 +674,8 @@ func subMonth(t1, t2 time.Time) (month int) { } monthInterval %= 12 month = yearInterval*12 + monthInterval + if month == 0 { + month = 1 + } return month } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 9a4cd191b..cac2153bb 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -402,6 +402,26 @@ form.name_reserved = The username '%s' is reserved. form.name_pattern_not_allowed = The pattern '%s' is not allowed in a username. form.name_chars_not_allowed = User name '%s' contains invalid characters. +static.sheetname=User Analysis +static.id=ID +static.name=User Name +static.codemergecount=PR Count +static.commitcount=Commit Count +static.issuecount=Issue Count +static.commentcount=Comment Count +static.focusrepocount=Focus Repo Count +static.starrepocount=Repo Star Count +static.logincount=Login Count +static.watchedcount=Watched Count +static.commitcodesize=Commit Code Line +static.solveissuecount=Solve Issue Count +static.encyclopediascount=Encyclopedias Count +static.createrepocount=Create Repo Count +static.openiindex=OpenI Index +static.registdate=Regist Date +static.countdate=Count Date + + [settings] profile = Profile account = Account diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index d37bd61c7..9918d47e0 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -405,6 +405,24 @@ form.name_reserved='%s' 用户名被保留。 form.name_pattern_not_allowed=用户名中不允许使用 "%s"。 form.name_chars_not_allowed=用户名 '%s' 包含无效字符。 +static.sheetname=用户分析 +static.id=ID +static.name=用户名 +static.codemergecount=PR数 +static.commitcount=commit次数 +static.issuecount=提出任务数 +static.commentcount=评论数 +static.focusrepocount=关注项目数 +static.starrepocount=点赞项目数 +static.logincount=登录次数 +static.watchedcount=关注者数 +static.commitcodesize=commit代码行数 +static.solveissuecount=已解决任务数 +static.encyclopediascount=百科页面贡献次数 +static.createrepocount=创建项目数 +static.openiindex=OpenI指数 +static.registdate=用户注册时间 +static.countdate=系统统计时间 [settings] profile=个人信息 account=账号 diff --git a/routers/repo/user_data_analysis.go b/routers/repo/user_data_analysis.go index 3742cf67c..134896177 100755 --- a/routers/repo/user_data_analysis.go +++ b/routers/repo/user_data_analysis.go @@ -3,6 +3,8 @@ package repo import ( "fmt" "net/http" + "net/url" + "strings" "time" "code.gitea.io/gitea/models" @@ -10,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "github.com/360EntSecGroup-Skylar/excelize/v2" ) func QueryUserStaticData(ctx *context.Context) { @@ -35,6 +38,7 @@ func QueryUserStaticDataPage(ctx *context.Context) { pageSize = setting.UI.IssuePagingNum } userName := ctx.Query("userName") + IsReturnFile := ctx.QueryBool("IsReturnFile") log.Info("startDate=" + startDate + " endDate=" + endDate + " userName=" + userName + " page=" + fmt.Sprint(page)) startTime, _ := time.Parse("2006-01-02", startDate) @@ -42,6 +46,11 @@ func QueryUserStaticDataPage(ctx *context.Context) { endTime = endTime.AddDate(0, 0, 1) log.Info("startTime=" + fmt.Sprint(startTime.Unix()) + " endDate=" + fmt.Sprint(endTime.Unix())) + if IsReturnFile { + page = -1 + pageSize = -1 + } + pageOpts := &models.UserBusinessAnalysisQueryOptions{ ListOptions: models.ListOptions{ Page: page, @@ -55,11 +64,76 @@ func QueryUserStaticDataPage(ctx *context.Context) { re, count := models.QueryUserStaticDataPage(pageOpts) mapInterface["data"] = re mapInterface["count"] = count - ctx.JSON(http.StatusOK, mapInterface) -} + if IsReturnFile { + //writer exec file. + xlsx := excelize.NewFile() + sheetName := ctx.Tr("user.static.sheetname") + index := xlsx.NewSheet(sheetName) + dataHeader := map[string]string{ + "A1": ctx.Tr("user.static.id"), + "B1": ctx.Tr("user.static.name"), + "C1": ctx.Tr("user.static.codemergecount"), + "D1": ctx.Tr("user.static.commitcount"), + "E1": ctx.Tr("user.static.issuecount"), + "F1": ctx.Tr("user.static.commentcount"), + "G1": ctx.Tr("user.static.focusrepocount"), + "H1": ctx.Tr("user.static.starrepocount"), + "I1": ctx.Tr("user.static.logincount"), + "J1": ctx.Tr("user.static.watchedcount"), + "K1": ctx.Tr("user.static.commitcodesize"), + "L1": ctx.Tr("user.static.solveissuecount"), + "M1": ctx.Tr("user.static.encyclopediascount"), + "N1": ctx.Tr("user.static.createrepocount"), + "O1": ctx.Tr("user.static.openiindex"), + "P1": ctx.Tr("user.static.registdate"), + "Q1": ctx.Tr("user.static.countdate"), + } + for k, v := range dataHeader { + //设置单元格的值 + xlsx.SetCellValue(sheetName, k, v) + } -func TimingCountDataByDate(date string) { + for i, userRecord := range re { + rows := fmt.Sprint(i + 2) + + xlsx.SetCellValue(sheetName, "A"+rows, userRecord.ID) + xlsx.SetCellValue(sheetName, "B"+rows, userRecord.Name) + xlsx.SetCellValue(sheetName, "C"+rows, userRecord.CodeMergeCount) + xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CommitCount) + xlsx.SetCellValue(sheetName, "E"+rows, userRecord.IssueCount) + xlsx.SetCellValue(sheetName, "F"+rows, userRecord.CommentCount) + xlsx.SetCellValue(sheetName, "G"+rows, userRecord.FocusRepoCount) + xlsx.SetCellValue(sheetName, "H"+rows, userRecord.StarRepoCount) + xlsx.SetCellValue(sheetName, "I"+rows, userRecord.LoginCount) + xlsx.SetCellValue(sheetName, "J"+rows, userRecord.WatchedCount) + xlsx.SetCellValue(sheetName, "K"+rows, userRecord.CommitCodeSize) + xlsx.SetCellValue(sheetName, "L"+rows, userRecord.SolveIssueCount) + xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount) + xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount) + xlsx.SetCellValue(sheetName, "O"+rows, userRecord.OpenIIndex) + xlsx.SetCellValue(sheetName, "P"+rows, userRecord.RegistDate.Format("2006-01-02")) + xlsx.SetCellValue(sheetName, "Q"+rows, time.Unix(userRecord.CountDate, 0).Format("2006-01-02")) + } + + //设置默认打开的表单 + xlsx.SetActiveSheet(index) + filename := sheetName + "_" + strings.ReplaceAll(startDate, "-", "") + "_" + strings.ReplaceAll(endDate, "-", "") + ".xlsx" + if len(userName) > 0 { + filename = sheetName + "_" + userName + "_" + strings.ReplaceAll(startDate, "-", "") + "_" + strings.ReplaceAll(endDate, "-", "") + ".xlsx" + } + ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename)) + ctx.Resp.Header().Set("Content-Type", "application/octet-stream") + if _, err := xlsx.WriteTo(ctx.Resp); err != nil { + log.Info("writer exel error." + err.Error()) + } + + } else { + ctx.JSON(http.StatusOK, mapInterface) + } +} + +func TimingCountDataByDateAndReCount(date string, isReCount bool) { t, _ := time.Parse("2006-01-02", date) startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) @@ -106,16 +180,17 @@ func TimingCountDataByDate(date string) { } } //other user info data - models.CounDataByDate(wikiMap, startTime, endTime) + models.CounDataByDateAndReCount(wikiMap, startTime, endTime, isReCount) +} +func TimingCountDataByDate(date string) { + TimingCountDataByDateAndReCount(date, true) } func TimingCountData() { - log.Info("start to time count data") currentTimeNow := time.Now() log.Info("current time:" + currentTimeNow.Format("2006-01-02 15:04:05")) startTime := currentTimeNow.AddDate(0, 0, -1).Format("2006-01-02") - - TimingCountDataByDate(startTime) + TimingCountDataByDateAndReCount(startTime, false) } diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 67d8fc1b7..49b3181e7 100755 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -37,7 +37,9 @@ {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} {{.i18n.Tr "explore.images"}} - {{.i18n.Tr "explore.data_analysis"}} + {{if .IsAdmin}} + {{.i18n.Tr "explore.data_analysis"}} + {{end}} {{else if .IsLandingPageHome}} @@ -53,6 +55,9 @@ {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} {{.i18n.Tr "explore.images"}} + {{if .IsAdmin}} + {{.i18n.Tr "explore.data_analysis"}} + {{end}} {{else if .IsLandingPageExplore}} diff --git a/templates/base/head_navbar_home.tmpl b/templates/base/head_navbar_home.tmpl index e334efba8..c94ff269f 100644 --- a/templates/base/head_navbar_home.tmpl +++ b/templates/base/head_navbar_home.tmpl @@ -29,7 +29,9 @@ {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} {{.i18n.Tr "explore.images"}} - {{.i18n.Tr "explore.data_analysis"}} + {{if .IsAdmin}} + {{.i18n.Tr "explore.data_analysis"}} + {{end}} {{else if .IsLandingPageHome}} @@ -45,6 +47,9 @@ {{.i18n.Tr "explore.users"}} {{.i18n.Tr "explore.organizations"}} {{.i18n.Tr "explore.images"}} + {{if .IsAdmin}} + {{.i18n.Tr "explore.data_analysis"}} + {{end}} {{else if .IsLandingPageExplore}} diff --git a/web_src/js/components/ProAnalysis.vue b/web_src/js/components/ProAnalysis.vue index 8d4f25084..2a42f189c 100755 --- a/web_src/js/components/ProAnalysis.vue +++ b/web_src/js/components/ProAnalysis.vue @@ -2,24 +2,24 @@