| @@ -17,6 +17,7 @@ require ( | |||
| gitea.com/macaron/macaron v1.4.0 | |||
| gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d | |||
| gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 | |||
| github.com/360EntSecGroup-Skylar/excelize/v2 v2.0.2 | |||
| github.com/BurntSushi/toml v0.3.1 | |||
| github.com/PuerkitoBio/goquery v1.5.0 | |||
| github.com/RichardKnop/machinery v1.6.9 | |||
| @@ -107,7 +108,6 @@ require ( | |||
| github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141 | |||
| github.com/urfave/cli v1.22.1 | |||
| github.com/xanzy/go-gitlab v0.31.0 | |||
| github.com/360EntSecGroup-Skylar/excelize/v2 v2.0.2 | |||
| github.com/yohcop/openid-go v1.0.0 | |||
| github.com/yuin/goldmark v1.1.27 | |||
| github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 | |||
| @@ -22,7 +22,6 @@ var customMigrations = []CustomMigration{ | |||
| } | |||
| var customMigrationsStatic = []CustomMigrationStatic{ | |||
| {"Alter user static table field type ", alterUserStaticTable}, | |||
| {"Delete organization user history data ", deleteNotDisplayUser}, | |||
| {"update issue_fixed_rate to 1 if num_issues is 0 ", updateIssueFixedRate}, | |||
| } | |||
| @@ -59,14 +58,6 @@ func syncTopicStruct(x *xorm.Engine) error { | |||
| return err | |||
| } | |||
| func alterUserStaticTable(x *xorm.Engine, static *xorm.Engine) error { | |||
| alterSql := "alter table public.user_business_analysis alter column open_i_index type double precision" | |||
| _, err := static.Exec(alterSql) | |||
| return err | |||
| } | |||
| func deleteNotDisplayUser(x *xorm.Engine, static *xorm.Engine) error { | |||
| querySQL := "select id,name from public.user where type=1" | |||
| @@ -172,3 +172,10 @@ func UpdateRepoStat(repoStat *RepoStatistic) error { | |||
| _, err := xStatistic.Exec(sql, repoStat.Impact, repoStat.Completeness, repoStat.Liveness, repoStat.ProjectHealth, repoStat.TeamHealth, repoStat.Growth, repoStat.RadarTotal, repoStat.RepoID, repoStat.Date) | |||
| return err | |||
| } | |||
| func UpdateRepoStatVisits(repoStat *RepoStatistic) error { | |||
| sql := "update repo_statistic set num_visits=? where repo_id=? and date=?" | |||
| _, err := xStatistic.Exec(sql, repoStat.NumVisits, repoStat.RepoID, repoStat.Date) | |||
| return err | |||
| } | |||
| @@ -153,6 +153,76 @@ func getLastCountDate() int64 { | |||
| return pageStartTime.Unix() | |||
| } | |||
| func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusinessAnalysis, int64) { | |||
| log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime) + " isAll=" + fmt.Sprint(opts.IsAll)) | |||
| statictisSess := xStatistic.NewSession() | |||
| defer statictisSess.Close() | |||
| resultMap := make(map[int64]*UserBusinessAnalysis) | |||
| var newAndCond = builder.NewCond() | |||
| if len(opts.UserName) > 0 { | |||
| newAndCond = newAndCond.And( | |||
| builder.Like{"name", opts.UserName}, | |||
| ) | |||
| } | |||
| if !opts.IsAll { | |||
| newAndCond = newAndCond.And( | |||
| builder.Gte{"count_date": opts.StartTime}, | |||
| ) | |||
| newAndCond = newAndCond.And( | |||
| builder.Lte{"count_date": opts.EndTime}, | |||
| ) | |||
| } | |||
| allCount, err := statictisSess.Where(newAndCond).Count(new(UserBusinessAnalysis)) | |||
| if err != nil { | |||
| log.Info("query error." + err.Error()) | |||
| return nil, 0 | |||
| } | |||
| log.Info("query return total:" + fmt.Sprint(allCount)) | |||
| pageSize := 200 | |||
| totalPage := int(allCount) / pageSize | |||
| for i := 0; i <= int(totalPage); i++ { | |||
| userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0) | |||
| if err := statictisSess.Table("user_business_analysis").Where(newAndCond).OrderBy("count_date desc").Limit(pageSize, i*pageSize). | |||
| Find(&userBusinessAnalysisList); err != nil { | |||
| return nil, 0 | |||
| } | |||
| log.Info("query " + fmt.Sprint(i+1) + " result size=" + fmt.Sprint(len(userBusinessAnalysisList))) | |||
| for _, userRecord := range userBusinessAnalysisList { | |||
| if _, ok := resultMap[userRecord.ID]; !ok { | |||
| resultMap[userRecord.ID] = userRecord | |||
| } else { | |||
| resultMap[userRecord.ID].CodeMergeCount += userRecord.CodeMergeCount | |||
| resultMap[userRecord.ID].CommitCount += userRecord.CommitCount | |||
| resultMap[userRecord.ID].IssueCount += userRecord.IssueCount | |||
| resultMap[userRecord.ID].CommentCount += userRecord.CommentCount | |||
| resultMap[userRecord.ID].FocusRepoCount += userRecord.FocusRepoCount | |||
| resultMap[userRecord.ID].StarRepoCount += userRecord.StarRepoCount | |||
| resultMap[userRecord.ID].WatchedCount += userRecord.WatchedCount | |||
| resultMap[userRecord.ID].CommitCodeSize += userRecord.CommitCodeSize | |||
| resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize | |||
| resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount | |||
| resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount | |||
| resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount | |||
| resultMap[userRecord.ID].CreateRepoCount += userRecord.CreateRepoCount | |||
| resultMap[userRecord.ID].LoginCount += userRecord.LoginCount | |||
| } | |||
| } | |||
| } | |||
| userBusinessAnalysisReturnList := UserBusinessAnalysisList{} | |||
| for _, v := range resultMap { | |||
| userBusinessAnalysisReturnList = append(userBusinessAnalysisReturnList, v) | |||
| } | |||
| sort.Sort(userBusinessAnalysisReturnList) | |||
| log.Info("return size=" + fmt.Sprint(len(userBusinessAnalysisReturnList))) | |||
| return userBusinessAnalysisReturnList, allCount | |||
| } | |||
| func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusinessAnalysis, int64) { | |||
| log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime) + " isAll=" + fmt.Sprint(opts.IsAll)) | |||
| @@ -219,32 +289,43 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus | |||
| builder.Lte{"count_date": opts.EndTime}, | |||
| ) | |||
| } | |||
| userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0) | |||
| if err := statictisSess.Table("user_business_analysis").Where(newAndCond).OrderBy("count_date desc"). | |||
| Find(&userBusinessAnalysisList); err != nil { | |||
| allCount, err := statictisSess.Where(newAndCond).Count(new(UserBusinessAnalysis)) | |||
| if err != nil { | |||
| log.Info("query error." + err.Error()) | |||
| return nil, 0 | |||
| } | |||
| } | |||
| log.Info("query result size=" + fmt.Sprint(len(userBusinessAnalysisList))) | |||
| for _, userRecord := range userBusinessAnalysisList { | |||
| if _, ok := resultMap[userRecord.ID]; !ok { | |||
| resultMap[userRecord.ID] = userRecord | |||
| } else { | |||
| resultMap[userRecord.ID].CodeMergeCount += userRecord.CodeMergeCount | |||
| resultMap[userRecord.ID].CommitCount += userRecord.CommitCount | |||
| resultMap[userRecord.ID].IssueCount += userRecord.IssueCount | |||
| resultMap[userRecord.ID].CommentCount += userRecord.CommentCount | |||
| resultMap[userRecord.ID].FocusRepoCount += userRecord.FocusRepoCount | |||
| resultMap[userRecord.ID].StarRepoCount += userRecord.StarRepoCount | |||
| resultMap[userRecord.ID].WatchedCount += userRecord.WatchedCount | |||
| resultMap[userRecord.ID].CommitCodeSize += userRecord.CommitCodeSize | |||
| resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize | |||
| resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount | |||
| resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount | |||
| resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount | |||
| resultMap[userRecord.ID].CreateRepoCount += userRecord.CreateRepoCount | |||
| resultMap[userRecord.ID].LoginCount += userRecord.LoginCount | |||
| pageSize := 1000 | |||
| totalPage := int(allCount) / pageSize | |||
| for i := 0; i <= int(totalPage); i++ { | |||
| userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0) | |||
| if err := statictisSess.Table("user_business_analysis").Where(newAndCond).OrderBy("count_date desc").Limit(pageSize, i*pageSize). | |||
| Find(&userBusinessAnalysisList); err != nil { | |||
| return nil, 0 | |||
| } | |||
| log.Info("query result size=" + fmt.Sprint(len(userBusinessAnalysisList))) | |||
| for _, userRecord := range userBusinessAnalysisList { | |||
| if _, ok := resultMap[userRecord.ID]; !ok { | |||
| resultMap[userRecord.ID] = userRecord | |||
| } else { | |||
| resultMap[userRecord.ID].CodeMergeCount += userRecord.CodeMergeCount | |||
| resultMap[userRecord.ID].CommitCount += userRecord.CommitCount | |||
| resultMap[userRecord.ID].IssueCount += userRecord.IssueCount | |||
| resultMap[userRecord.ID].CommentCount += userRecord.CommentCount | |||
| resultMap[userRecord.ID].FocusRepoCount += userRecord.FocusRepoCount | |||
| resultMap[userRecord.ID].StarRepoCount += userRecord.StarRepoCount | |||
| resultMap[userRecord.ID].WatchedCount += userRecord.WatchedCount | |||
| resultMap[userRecord.ID].CommitCodeSize += userRecord.CommitCodeSize | |||
| resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize | |||
| resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount | |||
| resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount | |||
| resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount | |||
| resultMap[userRecord.ID].CreateRepoCount += userRecord.CreateRepoCount | |||
| resultMap[userRecord.ID].LoginCount += userRecord.LoginCount | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -4,6 +4,7 @@ import ( | |||
| "bytes" | |||
| "encoding/base64" | |||
| "encoding/json" | |||
| "fmt" | |||
| "io/ioutil" | |||
| "net/http" | |||
| @@ -113,13 +114,23 @@ func GetResultFromElk(resultInfo ResultInfo, jsonStr []byte) (loaded int, totalV | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| panic(err) | |||
| // panic(err) | |||
| return 0, 0, err | |||
| } | |||
| defer resp.Body.Close() | |||
| body, _ := ioutil.ReadAll(resp.Body) | |||
| errs := json.Unmarshal([]byte(string(body)), &resultInfo) | |||
| log.Info("Get resultJson failed", errs) | |||
| if resp.StatusCode != 200 { | |||
| log.Error("ConnectToElk failed:%s", resp.Status) | |||
| return 0, 0, fmt.Errorf("ConnectToElk failed:%s", resp.Status) | |||
| } | |||
| body, err := ioutil.ReadAll(resp.Body) | |||
| if err != nil { | |||
| return 0, 0, err | |||
| } | |||
| err = json.Unmarshal([]byte(string(body)), &resultInfo) | |||
| if err != nil { | |||
| log.Error("Get resultJson failed", err) | |||
| return 0, 0, err | |||
| } | |||
| return resultInfo.Result.Loaded, resultInfo.Result.RawResponse.Hits.Total, err | |||
| } | |||
| @@ -138,6 +149,7 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje | |||
| var timeRange Range | |||
| timeRange.Timestamptest.Gte = Gte | |||
| timeRange.Timestamptest.Lte = Lte | |||
| timeRange.Timestamptest.Format = "strict_date_optional_time" | |||
| inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[0].Range = &timeRange | |||
| //限定用户 | |||
| var userName FilterMatchPhrase | |||
| @@ -208,9 +220,10 @@ func TagNameInit(MessageInfo string, Tagname string, Gte string, Lte string) (pr | |||
| //向elk发送请求,将获取的结果只保留访问量,输入是初始化后的数据结构,返回访问量 | |||
| func ViewInfo(viewInfo InputInfo) (totalView int, err error) { | |||
| jsons, errs := json.Marshal(viewInfo) | |||
| if errs != nil { | |||
| log.Info("errs:", errs) | |||
| jsons, err := json.Marshal(viewInfo) | |||
| if err != nil { | |||
| log.Error("jsons failed", err) | |||
| return 0, err | |||
| } | |||
| var jsonStr = []byte(jsons) | |||
| var resultInfo ResultInfo | |||
| @@ -221,7 +234,6 @@ func ViewInfo(viewInfo InputInfo) (totalView int, err error) { | |||
| if loaded == 0 { | |||
| loaded_next, totalView, err := GetResultFromElk(resultInfo, jsonStr) | |||
| time++ | |||
| log.Info("time:", time) | |||
| if loaded_next != 0 && time < 100 { | |||
| return totalView, err | |||
| } | |||
| @@ -816,6 +816,9 @@ total_count_get_error=查询总页数失败。 | |||
| last_update_time_error=查询最新更新时间失败。 | |||
| get_repo_stat_error=查询当前仓库的统计信息失败。 | |||
| get_repo_info_error=查询当前仓库信息失败。 | |||
| generate_statistic_file_error=生成文件失败。 | |||
| repo_stat_inspect=项目分析 | |||
| all=所有 | |||
| modelarts.status=状态 | |||
| modelarts.createtime=创建时间 | |||
| @@ -529,6 +529,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/restoreFork", adminReq, repo.RestoreForkNumber) | |||
| m.Get("/downloadAll", adminReq, repo.ServeAllProjectsPeriodStatisticsFile) | |||
| m.Get("/downloadAllOpenI", adminReq, repo.ServeAllProjectsOpenIStatisticsFile) | |||
| m.Group("/project", func() { | |||
| m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics) | |||
| @@ -207,6 +207,71 @@ func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) { | |||
| } | |||
| func ServeAllProjectsOpenIStatisticsFile(ctx *context.Context) { | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| pageSize := 1000 | |||
| _, latestDate, err := models.GetRepoStatLastUpdatedTime() | |||
| if err != nil { | |||
| log.Error("Can not query the last updated time.", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error")) | |||
| return | |||
| } | |||
| date := ctx.QueryTrim("date") | |||
| if date == "" { | |||
| date = latestDate | |||
| } | |||
| countSql := generateOpenICountSql(date) | |||
| total, err := models.CountRepoStatByRawSql(countSql) | |||
| if err != nil { | |||
| log.Error("Can not query total count.", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error")) | |||
| return | |||
| } | |||
| var projectAnalysis = ctx.Tr("repo.repo_stat_inspect") | |||
| fileName := "项目分析_OPENI_" + date + ".xlsx" | |||
| totalPage := getTotalPage(total, pageSize) | |||
| f := excelize.NewFile() | |||
| index := f.NewSheet(projectAnalysis) | |||
| f.DeleteSheet("Sheet1") | |||
| for k, v := range allProjectsOpenIHeader() { | |||
| f.SetCellValue(projectAnalysis, k, v) | |||
| } | |||
| var row = 2 | |||
| for i := 0; i <= totalPage; i++ { | |||
| pageRecords := models.GetRepoStatisticByRawSql(generateTypeAllOpenISql(date, i+1, pageSize)) | |||
| for _, record := range pageRecords { | |||
| for k, v := range allProjectsOpenIValues(row, record, ctx) { | |||
| f.SetCellValue(projectAnalysis, k, v) | |||
| } | |||
| row++ | |||
| } | |||
| } | |||
| f.SetActiveSheet(index) | |||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName)) | |||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
| f.WriteTo(ctx.Resp) | |||
| } | |||
| func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string { | |||
| baseName := projectAnalysis + "_" | |||
| @@ -237,6 +302,32 @@ func allProjectsPeroidValues(row int, rs *models.RepoStatistic, ctx *context.Con | |||
| } | |||
| } | |||
| func allProjectsOpenIHeader() map[string]string { | |||
| return map[string]string{"A1": "ID", "B1": "项目名称", "C1": "拥有者", "D1": "是否私有", "E1": "OpenI指数", | |||
| "F1": "影响力", "G1": "成熟度", "H1": "活跃度", "I1": "项目健康度", "J1": "团队健康度", "K1": "项目发展趋势", | |||
| "L1": "关注数", "M1": "点赞数", "N1": "派生数", "O1": "代码下载量", "P1": "评论数", "Q1": "浏览量", "R1": "已解决任务数", "S1": "版本发布数量", "T1": "有效开发年龄", | |||
| "U1": "数据集", "V1": "模型数", "W1": "百科页面数量", "X1": "提交数", "Y1": "任务数", "Z1": "PR数", "AA1": "版本发布数量", "AB1": "任务完成比例", "AC1": "贡献者数", "AD1": "关键贡献者数", | |||
| "AE1": "新人增长量", "AF1": "代码规模增长量", "AG1": "任务增长量", "AH1": "新人增长量", "AI1": "提交增长量", "AJ1": "评论增长量", | |||
| } | |||
| } | |||
| func allProjectsOpenIValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string { | |||
| return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): rs.Name, getCellName("C", row): rs.OwnerName, getCellName("D", row): getIsPrivateDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64), | |||
| getCellName("F", row): strconv.FormatFloat(rs.Impact, 'f', 2, 64), getCellName("G", row): strconv.FormatFloat(rs.Completeness, 'f', 2, 64), getCellName("H", row): strconv.FormatFloat(rs.Liveness, 'f', 2, 64), getCellName("I", row): strconv.FormatFloat(rs.ProjectHealth, 'f', 2, 64), getCellName("J", row): strconv.FormatFloat(rs.TeamHealth, 'f', 2, 64), getCellName("K", row): strconv.FormatFloat(rs.Growth, 'f', 2, 64), | |||
| getCellName("L", row): strconv.FormatInt(rs.NumWatches, 10), getCellName("M", row): strconv.FormatInt(rs.NumStars, 10), getCellName("N", row): strconv.FormatInt(rs.NumForks, 10), getCellName("O", row): strconv.FormatInt(rs.NumDownloads, 10), | |||
| getCellName("P", row): strconv.FormatInt(rs.NumComments, 10), getCellName("Q", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("R", row): strconv.FormatInt(rs.NumClosedIssues, 10), getCellName("S", row): strconv.FormatInt(rs.NumVersions, 10), | |||
| getCellName("T", row): strconv.FormatInt(rs.NumDevMonths, 10), getCellName("U", row): strconv.FormatInt(rs.DatasetSize, 10), getCellName("V", row): strconv.FormatInt(rs.NumModels, 10), getCellName("W", row): strconv.FormatInt(rs.NumWikiViews, 10), | |||
| getCellName("X", row): strconv.FormatInt(rs.NumCommits, 10), getCellName("Y", row): strconv.FormatInt(rs.NumIssues, 10), getCellName("Z", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("AA", row): strconv.FormatInt(rs.NumVersions, 10), | |||
| getCellName("AB", row): strconv.FormatFloat(float64(rs.IssueFixedRate), 'f', 2, 64), getCellName("AC", row): strconv.FormatInt(rs.NumContributor, 10), getCellName("AD", row): strconv.FormatInt(rs.NumKeyContributor, 10), getCellName("AE", row): strconv.FormatInt(rs.NumContributorsGrowth, 10), | |||
| getCellName("AF", row): strconv.FormatInt(rs.NumCommitLinesGrowth, 10), getCellName("AG", row): strconv.FormatInt(rs.NumIssuesGrowth, 10), getCellName("AH", row): strconv.FormatInt(rs.NumContributorsGrowth, 10), getCellName("AI", row): strconv.FormatInt(rs.NumCommitsGrowth, 10), getCellName("AJ", row): strconv.FormatInt(rs.NumCommentsGrowth, 10), | |||
| } | |||
| } | |||
| func getCellName(col string, row int) string { | |||
| return col + strconv.Itoa(row) | |||
| } | |||
| @@ -381,6 +472,13 @@ func generateCountSql(beginTime time.Time, endTime time.Time, latestDate string, | |||
| return countSql | |||
| } | |||
| func generateOpenICountSql(latestDate string) string { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.repo_statistic where date='" + latestDate + "'" | |||
| return countSql | |||
| } | |||
| func generateTypeAllSql(beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string { | |||
| sql := "SELECT A.repo_id,name,owner_name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " + | |||
| "(SELECT repo_id,sum(num_visits) as num_visits " + | |||
| @@ -396,6 +494,14 @@ func generateTypeAllSql(beginTime time.Time, endTime time.Time, latestDate strin | |||
| return sql | |||
| } | |||
| func generateTypeAllOpenISql(latestDate string, page int, pageSize int) string { | |||
| sql := "SELECT id, repo_id, date, num_watches, num_stars, num_forks, num_downloads, num_comments, num_visits, num_closed_issues, num_versions, num_dev_months, repo_size, dataset_size, num_models, num_wiki_views, num_commits, num_issues, num_pulls, issue_fixed_rate, num_contributor, num_key_contributor, num_contributors_growth, num_commits_growth, num_commit_lines_growth, num_issues_growth, num_comments_growth, impact, completeness, liveness, project_health, team_health, growth, radar_total, name, is_private, owner_name FROM " + | |||
| " public.repo_statistic where date='" + latestDate + "'" | |||
| sql = sql + " order by radar_total desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | |||
| return sql | |||
| } | |||
| func generatePageSql(beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string { | |||
| sql := "SELECT A.repo_id,name,owner_name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " + | |||
| @@ -43,7 +43,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/manager/restart", Restart) | |||
| m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues) | |||
| m.Post("/tool/update_all_repo_commit_cnt", UpdateAllRepoCommitCnt) | |||
| m.Post("/tool/repo_stat", RepoStatisticManually) | |||
| m.Post("/tool/repo_stat/:date", RepoStatisticManually) | |||
| m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit) | |||
| }, CheckInternalToken) | |||
| } | |||
| @@ -39,8 +39,35 @@ func UpdateAllRepoCommitCnt(ctx *macaron.Context) { | |||
| } | |||
| func RepoStatisticManually(ctx *macaron.Context) { | |||
| date := ctx.Query("date") | |||
| date := ctx.Params("date") | |||
| repo.RepoStatisticDaily(date) | |||
| repo.SummaryStatisticDaily(date) | |||
| repo.TimingCountDataByDate(date) | |||
| } | |||
| func UpdateRepoVisit(ctx *macaron.Context) { | |||
| date := ctx.Params("date") | |||
| log.Info("date(%s)", date) | |||
| repos, err := models.GetAllRepositories() | |||
| if err != nil { | |||
| log.Error("GetAllRepositories failed:%v", err.Error(), ctx.Data["MsgID"]) | |||
| ctx.JSON(http.StatusInternalServerError, map[string]string{ | |||
| "error_msg": "GetAllRepositories failed", | |||
| }) | |||
| return | |||
| } | |||
| for i, repoStat := range repos { | |||
| log.Info("%d:begin UpdateRepoVisits(id = %d, name = %s)", i, repoStat.ID, repoStat.Name) | |||
| if err = repo.UpdateRepoVisits(ctx, repoStat, date); err != nil { | |||
| log.Error("UpdateRepoVisits(id = %d, name = %s) failed:%v", repoStat.ID, repoStat.Name, err.Error()) | |||
| continue | |||
| } | |||
| log.Info("%d:finish UpdateRepoVisits(id = %d, name = %s)", i, repoStat.ID, repoStat.Name) | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]string{ | |||
| "error_msg": "", | |||
| }) | |||
| } | |||
| @@ -1,15 +1,17 @@ | |||
| package repo | |||
| import ( | |||
| "errors" | |||
| "time" | |||
| "code.gitea.io/gitea/services/mailer" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/normalization" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/services/mailer" | |||
| "gitea.com/macaron/macaron" | |||
| ) | |||
| func StatisticAuto() { | |||
| @@ -48,7 +50,7 @@ func RepoStatisticDaily(date string) { | |||
| var maxRepoRadar models.RepoStatistic | |||
| for i, repo := range repos { | |||
| log.Info("start statistic: %s", repo.Name) | |||
| log.Info("start statistic: %s", getDistinctProjectName(repo)) | |||
| var numDevMonths, numWikiViews, numContributor, numKeyContributor, numCommitsGrowth, numCommitLinesGrowth, numContributorsGrowth int64 | |||
| repoGitStat, err := models.GetRepoKPIStats(repo) | |||
| if err != nil { | |||
| @@ -230,7 +232,7 @@ func RepoStatisticDaily(date string) { | |||
| } | |||
| log.Info("finish statistic: %s", repo.Name) | |||
| log.Info("finish statistic: %s", getDistinctProjectName(repo)) | |||
| } | |||
| //radar map | |||
| @@ -274,3 +276,29 @@ func getStatTime(timeStr string) (string, string) { | |||
| return beginTime, endTime | |||
| } | |||
| func UpdateRepoVisits(ctx *macaron.Context, repo *models.Repository, date string) error { | |||
| beginTime, endTime := getStatTime(date) | |||
| var numVisits int | |||
| numVisits, err := repository.AppointProjectView(repo.OwnerName, repo.Name, beginTime, endTime) | |||
| if err != nil { | |||
| log.Error("AppointProjectView failed(%s): %v", getDistinctProjectName(repo), err) | |||
| return err | |||
| } | |||
| repoStat, err := models.GetRepoStatisticByDate(date, repo.ID) | |||
| if err != nil { | |||
| log.Error("GetRepoStatisticByDate failed(%s): %v", getDistinctProjectName(repo), err) | |||
| return err | |||
| } else if len(repoStat) != 1 { | |||
| log.Error("GetRepoStatisticByDate failed(%s): %v", getDistinctProjectName(repo), err) | |||
| return errors.New("not find repo") | |||
| } | |||
| repoStat[0].NumVisits = int64(numVisits) | |||
| if err = models.UpdateRepoStatVisits(repoStat[0]); err != nil { | |||
| log.Error("UpdateRepoStatVisits failed(%s): %v", getDistinctProjectName(repo), err) | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| @@ -49,13 +49,13 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
| startTime = time.Now() | |||
| endTime = time.Now() | |||
| } else { | |||
| startTime, _ = time.Parse("2006-01-02", startDate) | |||
| startTime, _ = time.ParseInLocation("2006-01-02", startDate, time.Local) | |||
| settingStartTime, _ := time.Parse("2006-01-02", setting.RadarMap.RecordBeginTime) | |||
| if startTime.Unix() < settingStartTime.Unix() { | |||
| startTime = settingStartTime | |||
| startDate = settingStartTime.Format("2006-01-02") | |||
| } | |||
| endTime, _ = time.Parse("2006-01-02", endDate) | |||
| endTime, _ = time.ParseInLocation("2006-01-02", endDate, time.Local) | |||
| endTime = endTime.AddDate(0, 0, 1) | |||
| isAll = false | |||
| log.Info("startTime=" + fmt.Sprint(startTime.Unix()) + " endDate=" + fmt.Sprint(endTime.Unix())) | |||
| @@ -76,17 +76,15 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
| EndTime: endTime.Unix(), | |||
| IsAll: isAll, | |||
| } | |||
| mapInterface := make(map[string]interface{}) | |||
| re, count := models.QueryUserStaticDataPage(pageOpts) | |||
| mapInterface["data"] = re | |||
| mapInterface["count"] = count | |||
| if IsReturnFile { | |||
| re, count := models.QueryUserStaticDataAll(pageOpts) | |||
| log.Info("return count=" + fmt.Sprint(count)) | |||
| //writer exec file. | |||
| xlsx := excelize.NewFile() | |||
| xlsx.DeleteSheet("Sheet1") | |||
| sheetName := ctx.Tr("user.static.sheetname") | |||
| index := xlsx.NewSheet(sheetName) | |||
| xlsx.DeleteSheet("Sheet1") | |||
| dataHeader := map[string]string{ | |||
| "A1": ctx.Tr("user.static.id"), | |||
| "B1": ctx.Tr("user.static.name"), | |||
| @@ -129,8 +127,12 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
| xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount) | |||
| xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount) | |||
| xlsx.SetCellValue(sheetName, "O"+rows, fmt.Sprintf("%.2f", 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")) | |||
| formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") | |||
| xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) | |||
| formatTime = time.Unix(userRecord.CountDate, 0).Format("2006-01-02 15:04:05") | |||
| xlsx.SetCellValue(sheetName, "Q"+rows, formatTime[0:len(formatTime)-3]) | |||
| } | |||
| //设置默认打开的表单 | |||
| @@ -160,6 +162,10 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
| } | |||
| } else { | |||
| mapInterface := make(map[string]interface{}) | |||
| re, count := models.QueryUserStaticDataPage(pageOpts) | |||
| mapInterface["data"] = re | |||
| mapInterface["count"] = count | |||
| ctx.JSON(http.StatusOK, mapInterface) | |||
| } | |||
| } | |||
| @@ -0,0 +1,42 @@ | |||
| <footer> | |||
| <div class="ui fluid container" style="padding: 0px 10px;"> | |||
| <div class="ui grid"> | |||
| <div class="sixteen wide mobile eight wide tablet eight wide computer column"> | |||
| <div class="ui three column grid"> | |||
| <div class="column ui vertical text menu"> | |||
| <div class="header item">{{.i18n.Tr "custom.head.community"}}</div> | |||
| <a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">{{.i18n.Tr "custom.foot.council"}}</a> | |||
| <a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">{{.i18n.Tr "custom.foot.technical_committee"}}</a> | |||
| <a href="https://openi.org.cn/html/Club/2019/0228/17.html" class="item">{{.i18n.Tr "custom.foot.join"}}</a> | |||
| </div> | |||
| <div class="column ui vertical text menu"> | |||
| <div class="header item">{{.i18n.Tr "custom.foot.news"}}</div> | |||
| <a href="https://openi.org.cn/html/news/dongtai/" class="item">{{.i18n.Tr "custom.foot.community_news"}}</a> | |||
| <a href="https://openi.org.cn/html/news/huodong/" class="item">{{.i18n.Tr "custom.foot.member_news"}}</a> | |||
| <a href="https://openi.org.cn/html/news/zixun/" class="item">{{.i18n.Tr "custom.foot.industry_advisory"}}</a> | |||
| </div> | |||
| <div class="column ui vertical text menu"> | |||
| <div class="header item">{{.i18n.Tr "custom.foot.help"}}</div> | |||
| <div class="ui language bottom floating slide up dropdown link item"> | |||
| <i class="world icon"></i> | |||
| <div class="text">{{.LangName}}</div> | |||
| <div class="menu"> | |||
| {{range .AllLangs}} | |||
| <a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="{{if eq $.Lang .Lang}}#{{else}}{{$.Link}}?lang={{.Lang}}{{end}}">{{.Name}}</a> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| {{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}} | |||
| {{template "custom/extra_links_footer" .}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="sixteen wide mobile eight wide tablet eight wide computer column" style=" margin:2.0rem 0"> | |||
| {{.i18n.Tr "custom.foot.copyright"}} <a href="http://beian.miit.gov.cn/" target="_blank">京ICP备18004880号</a> | |||
| <br> | |||
| {{.i18n.Tr "Powered_by 鹏城实验室云脑、"}}<a href="https://www.trustie.net/" target="_blank">Trustie确实</a>{{.i18n.Tr "、gitea"}} | |||
| <br> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </footer> | |||
| @@ -0,0 +1,48 @@ | |||
| {{/* | |||
| <html> | |||
| <body> | |||
| <div> | |||
| */}} | |||
| {{template "custom/body_inner_post" .}} | |||
| </div> | |||
| {{template "custom/body_outer_post" .}} | |||
| {{template "base/footer_content_fluid" .}} | |||
| <script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script> | |||
| {{if .RequireSimpleMDE}} | |||
| <script src="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.js"></script> | |||
| <script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script> | |||
| <script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/mode/meta.js"></script> | |||
| <script> | |||
| CodeMirror.modeURL = "{{StaticUrlPrefix}}/vendor/plugins/codemirror/mode/%N/%N.js"; | |||
| </script> | |||
| {{end}} | |||
| <!-- Third-party libraries --> | |||
| {{if .RequireMinicolors}} | |||
| <script src="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.min.js"></script> | |||
| {{end}} | |||
| {{if .RequireU2F}} | |||
| <script src="{{StaticUrlPrefix}}/vendor/plugins/u2f/index.js"></script> | |||
| {{end}} | |||
| {{if .EnableCaptcha}} | |||
| {{if eq .CaptchaType "recaptcha"}} | |||
| <script src='{{ URLJoin .RecaptchaURL "api.js"}}' async></script> | |||
| {{end}} | |||
| {{end}} | |||
| {{if .RequireTribute}} | |||
| <script src="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.min.js"></script> | |||
| {{end}} | |||
| {{if .PageIsHome}} | |||
| <script rel="stylesheet" src="{{StaticUrlPrefix}}/vendor/plugins/jquery.particleground/jquery.particleground.min.js"></script> | |||
| {{end}} | |||
| <script src="{{StaticUrlPrefix}}/fomantic/semantic.min.js?v={{MD5 AppVer}}"></script> | |||
| <script src="{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}"></script> | |||
| {{template "custom/footer" .}} | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,208 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="{{.Language}}"> | |||
| <head data-suburl="{{AppSubUrl}}"> | |||
| <meta charset="utf-8"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <meta http-equiv="x-ua-compatible" content="ie=edge"> | |||
| <title>{{if .Title}}{{.Title}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title> | |||
| <link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials"> | |||
| {{if UseServiceWorker}} | |||
| <script> | |||
| if ('serviceWorker' in navigator) { | |||
| navigator.serviceWorker.register('{{AppSubUrl}}/serviceworker.js').then(function(registration) { | |||
| // Registration was successful | |||
| console.info('ServiceWorker registration successful with scope: ', registration.scope); | |||
| }, function(err) { | |||
| // registration failed :( | |||
| console.info('ServiceWorker registration failed: ', err); | |||
| }); | |||
| } | |||
| </script> | |||
| {{else}} | |||
| <script> | |||
| if ('serviceWorker' in navigator) { | |||
| navigator.serviceWorker.getRegistrations().then(function(registrations) { | |||
| registrations.forEach(function(registration) { | |||
| registration.unregister(); | |||
| console.info('ServiceWorker unregistered'); | |||
| }); | |||
| }); | |||
| } | |||
| </script> | |||
| {{end}} | |||
| <meta name="theme-color" content="{{ThemeColorMetaTag}}"> | |||
| <meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}" /> | |||
| <meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}" /> | |||
| <meta name="keywords" content="{{MetaKeywords}}"> | |||
| <meta name="referrer" content="no-referrer" /> | |||
| <meta name="_csrf" content="{{.CsrfToken}}" /> | |||
| {{if .IsSigned}} | |||
| <meta name="_uid" content="{{.SignedUser.ID}}" /> | |||
| {{end}} | |||
| {{if .ContextUser}} | |||
| <meta name="_context_uid" content="{{.ContextUser.ID}}" /> | |||
| {{end}} | |||
| {{if .SearchLimit}} | |||
| <meta name="_search_limit" content="{{.SearchLimit}}" /> | |||
| {{end}} | |||
| {{if .GoGetImport}} | |||
| <meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}"> | |||
| <meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}"> | |||
| {{end}} | |||
| <script> | |||
| {{SafeJS `/* | |||
| @licstart The following is the entire license notice for the | |||
| JavaScript code in this page. | |||
| Copyright (c) 2016 The Gitea Authors | |||
| Copyright (c) 2015 The Gogs Authors | |||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| of this software and associated documentation files (the "Software"), to deal | |||
| in the Software without restriction, including without limitation the rights | |||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| copies of the Software, and to permit persons to whom the Software is | |||
| furnished to do so, subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be included in | |||
| all copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| THE SOFTWARE. | |||
| --- | |||
| Licensing information for additional javascript libraries can be found at: | |||
| {{StaticUrlPrefix}}/vendor/librejs.html | |||
| @licend The above is the entire license notice | |||
| for the JavaScript code in this page. | |||
| */`}} | |||
| </script> | |||
| <script> | |||
| window.config = { | |||
| AppSubUrl: '{{AppSubUrl}}', | |||
| StaticUrlPrefix: '{{StaticUrlPrefix}}', | |||
| csrf: '{{.CsrfToken}}', | |||
| HighlightJS: {{if .RequireHighlightJS}}true{{else}}false{{end}}, | |||
| Minicolors: {{if .RequireMinicolors}}true{{else}}false{{end}}, | |||
| SimpleMDE: {{if .RequireSimpleMDE}}true{{else}}false{{end}}, | |||
| Tribute: {{if .RequireTribute}}true{{else}}false{{end}}, | |||
| U2F: {{if .RequireU2F}}true{{else}}false{{end}}, | |||
| Heatmap: {{if .EnableHeatmap}}true{{else}}false{{end}}, | |||
| heatmapUser: {{if .HeatmapUser}}'{{.HeatmapUser}}'{{else}}null{{end}}, | |||
| NotificationSettings: { | |||
| MinTimeout: {{NotificationSettings.MinTimeout}}, | |||
| TimeoutStep: {{NotificationSettings.TimeoutStep}}, | |||
| MaxTimeout: {{NotificationSettings.MaxTimeout}}, | |||
| EventSourceUpdateTime: {{NotificationSettings.EventSourceUpdateTime}}, | |||
| }, | |||
| {{if .RequireTribute}} | |||
| tributeValues: [ | |||
| {{ range .Assignees }} | |||
| {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', | |||
| name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.RelAvatarLink}}'}, | |||
| {{ end }} | |||
| ], | |||
| {{end}} | |||
| }; | |||
| </script> | |||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
| <link rel="fluid-icon" href="{{StaticUrlPrefix}}/img/gitea-lg.png" title="{{AppName}}"> | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css"> | |||
| <link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
| <link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
| {{if .RequireSimpleMDE}} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css"> | |||
| {{end}} | |||
| {{if .RequireTribute}} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.css"> | |||
| {{end}} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/fomantic/semantic.min.css?v={{MD5 AppVer}}"> | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/index.css?v={{MD5 AppVer}}"> | |||
| <noscript> | |||
| <style> | |||
| .dropdown:hover > .menu { display: block; } | |||
| .ui.secondary.menu .dropdown.item > .menu { margin-top: 0; } | |||
| </style> | |||
| </noscript> | |||
| {{if .RequireMinicolors}} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css"> | |||
| {{end}} | |||
| <style class="list-search-style"></style> | |||
| {{if .PageIsUserProfile}} | |||
| <meta property="og:title" content="{{.Owner.Name}}" /> | |||
| <meta property="og:type" content="profile" /> | |||
| <meta property="og:image" content="{{.Owner.AvatarLink}}" /> | |||
| <meta property="og:url" content="{{.Owner.HTMLURL}}" /> | |||
| {{if .Owner.Description}} | |||
| <meta property="og:description" content="{{.Owner.Description}}"> | |||
| {{end}} | |||
| {{else if .Repository}} | |||
| {{if .Issue}} | |||
| <meta property="og:title" content="{{.Issue.Title}}" /> | |||
| <meta property="og:url" content="{{.Issue.HTMLURL}}" /> | |||
| {{if .Issue.Content}} | |||
| <meta property="og:description" content="{{.Issue.Content}}" /> | |||
| {{end}} | |||
| {{else}} | |||
| <meta property="og:title" content="{{.Repository.Name}}" /> | |||
| <meta property="og:url" content="{{.Repository.HTMLURL}}" /> | |||
| {{if .Repository.Description}} | |||
| <meta property="og:description" content="{{.Repository.Description}}" /> | |||
| {{end}} | |||
| {{end}} | |||
| <meta property="og:type" content="object" /> | |||
| <meta property="og:image" content="{{.Repository.Owner.AvatarLink}}" /> | |||
| {{else}} | |||
| <meta property="og:title" content="{{AppName}}"> | |||
| <meta property="og:type" content="website" /> | |||
| <meta property="og:image" content="{{StaticUrlPrefix}}/img/gitea-lg.png" /> | |||
| <meta property="og:url" content="{{AppUrl}}" /> | |||
| <meta property="og:description" content="{{MetaDescription}}"> | |||
| {{end}} | |||
| <meta property="og:site_name" content="{{AppName}}" /> | |||
| {{if .IsSigned }} | |||
| {{ if ne .SignedUser.Theme "gitea" }} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{.SignedUser.Theme}}.css?v={{MD5 AppVer}}"> | |||
| {{end}} | |||
| {{else if ne DefaultTheme "gitea"}} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{DefaultTheme}}.css?v={{MD5 AppVer}}"> | |||
| {{end}} | |||
| {{template "custom/header" .}} | |||
| <script> | |||
| var _hmt = _hmt || []; | |||
| (function() { | |||
| var hm = document.createElement("script"); | |||
| hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||
| var s = document.getElementsByTagName("script")[0]; | |||
| s.parentNode.insertBefore(hm, s); | |||
| })(); | |||
| </script> | |||
| <script src="/self/func.js" type="text/javascript"></script> | |||
| </head> | |||
| <body> | |||
| {{template "custom/body_outer_pre" .}} | |||
| <div class="full height"> | |||
| <noscript>{{.i18n.Tr "enable_javascript"}}</noscript> | |||
| {{template "custom/body_inner_pre" .}} | |||
| {{if not .PageIsInstall}} | |||
| <div class="ui top secondary stackable main menu following bar dark"> | |||
| {{template "base/head_navbar_fluid" .}} | |||
| </div><!-- end bar --> | |||
| {{end}} | |||
| {{/* | |||
| </div> | |||
| </body> | |||
| </html> | |||
| */}} | |||
| @@ -0,0 +1,177 @@ | |||
| <div class="ui fluid container" style = "padding: 0px 20px;" id="navbar"> | |||
| <div class="item brand" style="justify-content: space-between;"> | |||
| <a href="https://openi.org.cn/"> | |||
| <img class="ui mini image" src="{{StaticUrlPrefix}}/img/logo-w.svg"> | |||
| </a> | |||
| <div class="ui basic icon button mobile-only" id="navbar-expand-toggle"> | |||
| <i class="sidebar icon"></i> | |||
| </div> | |||
| </div> | |||
| <div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div> | |||
| <div class="item brand" style="margin-left: 0.9rem;"> | |||
| <a href="/"> | |||
| <img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg"> | |||
| </a> | |||
| </div> | |||
| {{if .IsSigned}} | |||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| {{if not .UnitIssuesGlobalDisabled}} | |||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| {{end}} | |||
| {{if not .UnitPullsGlobalDisabled}} | |||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| {{end}} | |||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||
| {{end}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsAdmin}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageExplore}} | |||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||
| {{else if .IsLandingPageOrganizations}} | |||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | |||
| {{end}} | |||
| {{template "custom/extra_links" .}} | |||
| {{/* | |||
| <div class="item"> | |||
| <div class="ui icon input"> | |||
| <input class="searchbox" type="text" placeholder="{{.i18n.Tr "search_project"}}"> | |||
| <i class="search icon"></i> | |||
| </div> | |||
| </div> | |||
| */}} | |||
| {{if .IsSigned}} | |||
| <div class="right stackable menu"> | |||
| <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | |||
| <span class="text"> | |||
| <span class="fitted">{{svg "octicon-bell" 16}}</span> | |||
| <span class="sr-mobile-only">{{.i18n.Tr "notifications"}}</span> | |||
| {{$notificationUnreadCount := 0}} | |||
| {{if .NotificationUnreadCount}}{{$notificationUnreadCount = call .NotificationUnreadCount}}{{end}} | |||
| <span class="ui red label {{if not $notificationUnreadCount}}hidden{{end}} notification_count"> | |||
| {{$notificationUnreadCount}} | |||
| </span> | |||
| </span> | |||
| </a> | |||
| <div class="ui dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted"> | |||
| <span class="text"> | |||
| <span class="fitted">{{svg "octicon-plus" 16}}</span> | |||
| <span class="sr-mobile-only">{{.i18n.Tr "create_new"}}</span> | |||
| <span class="fitted not-mobile">{{svg "octicon-triangle-down" 16}}</span> | |||
| </span> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/repo/create"> | |||
| <span class="fitted">{{svg "octicon-plus" 16}}</span> {{.i18n.Tr "new_repo"}} | |||
| </a> | |||
| <a class="item" href="{{AppSubUrl}}/repo/migrate"> | |||
| <span class="fitted">{{svg "octicon-repo-clone" 16}}</span> {{.i18n.Tr "new_migrate"}} | |||
| </a> | |||
| {{if .SignedUser.CanCreateOrganization}} | |||
| <a class="item" href="{{AppSubUrl}}/org/create"> | |||
| <span class="fitted">{{svg "octicon-organization" 16}}</span> {{.i18n.Tr "new_org"}} | |||
| </a> | |||
| {{end}} | |||
| </div><!-- end content create new menu --> | |||
| </div><!-- end dropdown menu create new --> | |||
| <div class="ui dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted"> | |||
| <span class="text"> | |||
| <img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}"> | |||
| <span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span> | |||
| <span class="mobile-only">{{.SignedUser.Name}}</span> | |||
| <span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down" 16}}</span> | |||
| </span> | |||
| <div class="menu user-menu" tabindex="-1"> | |||
| <div class="ui header"> | |||
| {{.i18n.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong> | |||
| </div> | |||
| <div class="divider"></div> | |||
| <a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}"> | |||
| {{svg "octicon-person" 16}} | |||
| {{.i18n.Tr "your_profile"}}<!-- Your profile --> | |||
| </a> | |||
| <a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}?tab=stars"> | |||
| {{svg "octicon-star" 16}} | |||
| {{.i18n.Tr "your_starred"}} | |||
| </a> | |||
| <a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings"> | |||
| {{svg "octicon-settings" 16}} | |||
| {{.i18n.Tr "your_settings"}}<!-- Your settings --> | |||
| </a> | |||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io"> | |||
| {{svg "octicon-question" 16}} | |||
| {{.i18n.Tr "help"}}<!-- Help --> | |||
| </a--> | |||
| {{if .IsAdmin}} | |||
| <div class="divider"></div> | |||
| <a class="{{if .PageIsAdmin}}active{{end}} item" href="{{AppSubUrl}}/admin"> | |||
| <i class="icon settings"></i> | |||
| {{.i18n.Tr "admin_panel"}}<!-- Admin Panel --> | |||
| </a> | |||
| {{end}} | |||
| <div class="divider"></div> | |||
| <a class="item link-action" href data-url="{{AppSubUrl}}/user/logout" data-redirect="{{AppSubUrl}}/"> | |||
| {{svg "octicon-sign-out" 16}} | |||
| {{.i18n.Tr "sign_out"}}<!-- Sign Out --> | |||
| </a> | |||
| </div><!-- end content avatar menu --> | |||
| </div><!-- end dropdown avatar menu --> | |||
| </div><!-- end signed user right menu --> | |||
| {{else}} | |||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
| <div class="right stackable menu"> | |||
| {{if .ShowRegistrationButton}} | |||
| <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | |||
| {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||
| </a> | |||
| {{end}} | |||
| <a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login"> | |||
| {{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}} | |||
| </a> | |||
| </div><!-- end anonymous right menu --> | |||
| {{end}} | |||
| </div> | |||
| @@ -1,14 +1,15 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/head_fluid" .}} | |||
| <div id="data_analysis" style="height: 100%;"> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| {{template "base/footer_fluid" .}} | |||
| <style> | |||
| .full.height { | |||
| flex-grow: 1; | |||
| /* flex-grow: 1; */ | |||
| padding-bottom: 53px; | |||
| } | |||
| </style> | |||
| </style> | |||
| @@ -8,13 +8,13 @@ | |||
| <bar-label :width="'95%'" :height="'500px'"></bar-label> | |||
| <div style="margin-top: 20px;"> | |||
| <span class="sta_iterm">统计周期:</span> | |||
| <button type="button" class='btn' id ="yesterday" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getAllProList('yesterday',1)">昨天</button> | |||
| <button type="button" class='btnFirst' id ="yesterday" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getAllProList('yesterday',1)">昨天</button> | |||
| <button type="button" class='btn' id = "current_week" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getAllProList('current_week',2)">本周</button> | |||
| <button type="button" class='btn' id = "current_month" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getAllProList('current_month',3)">本月</button> | |||
| <button type="button" class='btn' id = "last_month" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getAllProList('last_month',4)">上月</button> | |||
| <button type="button" class='btn' id = "monthly" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getAllProList('monthly',5)">近30天</button> | |||
| <button type="button" class='btn' id = "current_year" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getAllProList('current_year',6)">今年</button> | |||
| <button type="button" class='btn' id = "all" v-bind:class="{colorChange:7==dynamic}" @click="resetPage(),getAllProList('all',7)">所有</button> | |||
| <button type="button" class='btnLast' id = "all" v-bind:class="{colorChange:7==dynamic}" @click="resetPage(),getAllProList('all',7)">所有</button> | |||
| <span style="margin-left: 20px;"> | |||
| <el-date-picker | |||
| v-model="value_time" | |||
| @@ -160,7 +160,7 @@ | |||
| </div> | |||
| <div id ="pro_detail" style="display:none;width: 100%;"> | |||
| <div style="margin-top: 10px;"> | |||
| <b class="pro_item">{{this.ownerName}} / {{this.pro_name}}</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{tableDataIDTotal.lastUpdatedTime}} / 从{{tableDataIDTotal.recordBeginTime}}开始统计</span> | |||
| <a class="pro_item" :href="'../../../'+this.ownerName+'/'+this.pro_name">{{this.ownerName}} / {{this.pro_name}}</a> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{tableDataIDTotal.lastUpdatedTime}} / 从{{tableDataIDTotal.recordBeginTime}}开始统计</span> | |||
| </div> | |||
| <div style="margin-top: 10px;"> | |||
| 项目描述:{{tableDataIDTotal.description | discriptionFun}} | |||
| @@ -207,44 +207,46 @@ | |||
| </el-col> | |||
| <el-col :span=6 > | |||
| <div class="item_r"> | |||
| <div style="font-size:14px;color:rgb(0,0,0);margin:20px 5px;">贡献者TOP10</div> | |||
| <div> | |||
| <el-table | |||
| :data="tableDataContTop10" | |||
| style="width: 100%" | |||
| stripe | |||
| :header-cell-style="tableHeaderStyle" | |||
| > | |||
| <el-table-column | |||
| label="用户名" | |||
| align="left" | |||
| prop="user"> | |||
| <template slot-scope="scope"> | |||
| <a v-if="scope.row.mode!=-1" :href="AppSubUrl +'../../../'+ scope.row.user"><img class="ui avatar s16 image js-popover-card" :src="scope.row.relAvatarLink">{{scope.row.user}} </a> | |||
| <a v-else :href="'mailto:'+ scope.row.email "> <img class="ui avatar s16 image js-popover-card" :avatar="scope.row.email"> {{scope.row.user}}</a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="身份" | |||
| align="center" | |||
| prop="mode" | |||
| v-if='0'> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.mode | showMode}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="pr" | |||
| label="PR" | |||
| align="center"> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="commit" | |||
| label="commit" | |||
| align="center"> | |||
| </el-table-column> | |||
| </el-table> | |||
| <div style="margin:0 5px;"> | |||
| <div style="font-size:14px;color:rgb(0,0,0);margin:10px 0px">贡献者TOP10</div> | |||
| <div> | |||
| <el-table | |||
| :data="tableDataContTop10" | |||
| style="width: 100%" | |||
| stripe | |||
| :header-cell-style="tableHeaderStyle" | |||
| > | |||
| <el-table-column | |||
| label="用户名" | |||
| align="left" | |||
| prop="user"> | |||
| <template slot-scope="scope"> | |||
| <a v-if="scope.row.relAvatarLink!=''" :href="AppSubUrl +'../../../'+ scope.row.user"><img class="ui avatar s16 image js-popover-card" :src="scope.row.relAvatarLink">{{scope.row.user}} </a> | |||
| <a v-else :href="'mailto:'+ scope.row.email "> <img class="ui avatar s16 image js-popover-card" :avatar="scope.row.email"> {{scope.row.user}}</a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="身份" | |||
| align="center" | |||
| prop="mode" | |||
| v-if='0'> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.mode | showMode}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="pr" | |||
| label="PR" | |||
| align="center"> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="commit" | |||
| label="commit" | |||
| align="center"> | |||
| </el-table-column> | |||
| </el-table> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </el-col> | |||
| @@ -252,13 +254,13 @@ | |||
| </div> | |||
| <div style="margin-top: 20px;"> | |||
| <span class="sta_iterm">统计周期:</span> | |||
| <button type="button" class='btn' id ="yesterday_pro" v-bind:class="{colorChange:1==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'yesterday',false,1)">昨天</button> | |||
| <button type="button" class='btnFirst' id ="yesterday_pro" v-bind:class="{colorChange:1==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'yesterday',false,1)">昨天</button> | |||
| <button type="button" class='btn' id = "current_week_pro" v-bind:class="{colorChange:2==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_week',false,2)">本周</button> | |||
| <button type="button" class='btn' id = "current_month_pro" v-bind:class="{colorChange:3==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_month',false,3)">本月</button> | |||
| <button type="button" class='btn' id = "last_month_pro" v-bind:class="{colorChange:4==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'last_month',false,4)">上月</button> | |||
| <button type="button" class='btn' id = "monthly_pro" v-bind:class="{colorChange:5==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'monthly',false,5)">近30天</button> | |||
| <button type="button" class='btn' id = "current_year_pro" v-bind:class="{colorChange:6==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_year',false,6)">今年</button> | |||
| <button type="button" class='btn' id = "all_pro" v-bind:class="{colorChange:7==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'all',false,7)">所有</button> | |||
| <button type="button" class='btnLast' id = "all_pro" v-bind:class="{colorChange:7==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'all',false,7)">所有</button> | |||
| <span style="margin-left: 20px;"> | |||
| <el-date-picker | |||
| v-model="create_time_pro" | |||
| @@ -788,6 +790,10 @@ | |||
| }, | |||
| slpitNumber:5, | |||
| center: ['50%', '50%'], | |||
| splitArea: { // 坐标轴在 grid 区域中的分隔区域 | |||
| show: false, | |||
| }, | |||
| indicator: [{ | |||
| name: '社区影响力', | |||
| max: 100 | |||
| @@ -1170,16 +1176,43 @@ | |||
| color:rgba(187, 187, 187, 100); | |||
| margin-left: 10px; | |||
| } | |||
| .btnFirst{ | |||
| line-height: 1.5; | |||
| margin: -3.5px; | |||
| border: 1px solid #409eff; | |||
| border-right: none; | |||
| background: #FFFF; | |||
| color: #409eff; | |||
| width: 60px; | |||
| height: 30px; | |||
| border-radius:4px 0px 0px 4px; | |||
| } | |||
| .btn{ | |||
| line-height: 1.5; | |||
| margin: -3px; | |||
| margin: -3.5px; | |||
| border: 1px solid #409eff; | |||
| border-right: none; | |||
| background: #FFFF; | |||
| color: #409eff; | |||
| width: 60px; | |||
| height: 30px; | |||
| } | |||
| .btnLast{ | |||
| line-height: 1.5; | |||
| margin: -3.5px; | |||
| border: 1px solid #409eff; | |||
| /* border-right: none; */ | |||
| background: #FFFF; | |||
| color: #409eff; | |||
| width: 60px; | |||
| height: 30px; | |||
| border-radius:4px ; | |||
| border-radius:0px 4px 4px 0px; | |||
| } | |||
| .btnFirst, .btn, .btnLast { | |||
| cursor: pointer; | |||
| } | |||
| /* | |||
| .btn:focus, | |||
| .btn:active{ | |||
| @@ -1203,6 +1236,7 @@ | |||
| .colorChange { | |||
| background-color: #409effd6; | |||
| color: #FFFF; | |||
| cursor: default; | |||
| } | |||
| .items{ | |||
| text-align: center; | |||
| @@ -5,13 +5,13 @@ | |||
| </div> | |||
| <div style="margin-top: 20px;"> | |||
| <span class="sta_iterm">统计周期:</span> | |||
| <button type="button" class='btn' id ="yesterday_usr" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getUserList('yesterday_usr',1)">昨天</button> | |||
| <button type="button" class='btnFirst' id ="yesterday_usr" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getUserList('yesterday_usr',1)">昨天</button> | |||
| <button type="button" class='btn' id = "current_week_usr" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getUserList('current_week_usr',2)">本周</button> | |||
| <button type="button" class='btn' id = "current_month_usr" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getUserList('current_month_usr',3)">本月</button> | |||
| <button type="button" class='btn' id = "last_month_usr" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getUserList('last_month_usr',4)">上月</button> | |||
| <button type="button" class='btn' id = "monthly_usr" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getUserList('monthly_usr',5)">近30天</button> | |||
| <button type="button" class='btn' id = "current_year_usr" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getUserList('current_year_usr',6)">今年</button> | |||
| <button type="button" class='btn' id = "all_usr" v-bind:class="{colorChange:7==dynamic}" @click="resetPage(),getUserList('all_usr',7)">所有</button> | |||
| <button type="button" class='btnLast' id = "all_usr" v-bind:class="{colorChange:7==dynamic}" @click="resetPage(),getUserList('all_usr',7)">所有</button> | |||
| <span style="margin-left: 20px;"> | |||
| <el-date-picker | |||
| v-model="value_time" | |||
| @@ -462,7 +462,7 @@ | |||
| color:rgba(187, 187, 187, 100); | |||
| margin-left: 10px; | |||
| } | |||
| .btn{ | |||
| /* .btn{ | |||
| line-height: 1.5; | |||
| margin: -3px; | |||
| border: 1px solid #409effd6; | |||
| @@ -471,7 +471,43 @@ | |||
| width: 60px; | |||
| height: 30px; | |||
| border-radius:4px ; | |||
| } */ | |||
| .btnFirst{ | |||
| line-height: 1.5; | |||
| margin: -3.5px; | |||
| border: 1px solid #409eff; | |||
| border-right: none; | |||
| background: #FFFF; | |||
| color: #409eff; | |||
| width: 60px; | |||
| height: 30px; | |||
| border-radius:4px 0px 0px 4px; | |||
| } | |||
| .btn{ | |||
| line-height: 1.5; | |||
| margin: -3.5px; | |||
| border: 1px solid #409eff; | |||
| border-right: none; | |||
| background: #FFFF; | |||
| color: #409eff; | |||
| width: 60px; | |||
| height: 30px; | |||
| } | |||
| .btnLast{ | |||
| line-height: 1.5; | |||
| margin: -3.5px; | |||
| border: 1px solid #409eff; | |||
| /* border-right: none; */ | |||
| background: #FFFF; | |||
| color: #409eff; | |||
| width: 60px; | |||
| height: 30px; | |||
| border-radius:0px 4px 4px 0px; | |||
| } | |||
| .btnFirst,.btn,.btnLast { | |||
| cursor: pointer; | |||
| } | |||
| /* .btn:focus, | |||
| .btn:active{ | |||
| @@ -492,8 +528,9 @@ | |||
| } | |||
| .colorChange { | |||
| background-color: #409effd6; | |||
| color: #FFFF; | |||
| background-color: #409effd6; | |||
| color: #FFFF; | |||
| cursor: default; | |||
| } | |||
| </style> | |||