@@ -353,6 +353,7 @@ type FlavorInfos struct { | |||
type FlavorInfo struct { | |||
Id int `json:"id"` | |||
Value string `json:"value"` | |||
Desc string `json:"desc"` | |||
} | |||
type PoolInfos struct { | |||
@@ -1356,6 +1356,15 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { | |||
return accum, nil | |||
} | |||
func GetPullCountByUserAndRepoId(repoId int64, userId int64) int64 { | |||
issue := new(Issue) | |||
total, err := x.Where("is_pull=true and repo_id=? and poster_id=?", repoId, userId).Count(issue) | |||
if err != nil { | |||
return 0 | |||
} | |||
return total | |||
} | |||
func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, error) { | |||
stats := &IssueStats{} | |||
@@ -182,6 +182,7 @@ func CreateOrganization(org, owner *User) (err error) { | |||
if _, err = sess.Insert(&OrgUser{ | |||
UID: owner.ID, | |||
OrgID: org.ID, | |||
IsPublic: setting.Service.DefaultOrgMemberVisible, | |||
}); err != nil { | |||
return fmt.Errorf("insert org-user relation: %v", err) | |||
} | |||
@@ -210,9 +210,12 @@ type Repository struct { | |||
Balance string `xorm:"NOT NULL DEFAULT '0'"` | |||
BlockChainStatus RepoBlockChainStatus `xorm:"NOT NULL DEFAULT 0"` | |||
// git clone total count | |||
// git clone and git pull total count | |||
CloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
// only git clone total count | |||
GitCloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
@@ -2473,6 +2476,24 @@ func (repo *Repository) IncreaseCloneCnt() { | |||
return | |||
} | |||
func (repo *Repository) IncreaseGitCloneCnt() { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return | |||
} | |||
if _, err := sess.Exec("UPDATE `repository` SET git_clone_cnt = git_clone_cnt + 1 WHERE id = ?", repo.ID); err != nil { | |||
return | |||
} | |||
if err := sess.Commit(); err != nil { | |||
return | |||
} | |||
return | |||
} | |||
func UpdateRepositoryCommitNum(repo *Repository) error { | |||
if _, err := x.Exec("UPDATE `repository` SET num_commit = ? where id = ?", repo.NumCommit, repo.ID); err != nil { | |||
return err | |||
@@ -2,12 +2,19 @@ package models | |||
import ( | |||
"fmt" | |||
"sort" | |||
"strings" | |||
"time" | |||
"code.gitea.io/gitea/modules/git" | |||
) | |||
type ContributorWithUserId struct { | |||
git.Contributor | |||
UserId int64 | |||
IsAdmin bool | |||
} | |||
func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) { | |||
wikiPath := "" | |||
if repo.HasWiki() { | |||
@@ -63,22 +70,39 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error | |||
} | |||
if recentlyContributors != nil { | |||
resentlyContributorDistinctDict := make(map[string]int, 0) | |||
for _, recentlyContributor := range recentlyContributors { | |||
user, err := GetUserByActivateEmail(recentlyContributor.Email) | |||
var ok bool | |||
if err == nil { | |||
_, ok = contributorDistinctDict[user.Email] | |||
value, ok := resentlyContributorDistinctDict[user.Email] | |||
if !ok { | |||
resentlyContributorDistinctDict[user.Email] = recentlyContributor.CommitCnt | |||
} else { | |||
resentlyContributorDistinctDict[user.Email] = value + recentlyContributor.CommitCnt | |||
} | |||
} else { | |||
_, ok = contributorDistinctDict[recentlyContributor.Email] | |||
value, ok := resentlyContributorDistinctDict[recentlyContributor.Email] | |||
if !ok { | |||
resentlyContributorDistinctDict[recentlyContributor.Email] = recentlyContributor.CommitCnt | |||
} else { | |||
resentlyContributorDistinctDict[recentlyContributor.Email] = value + recentlyContributor.CommitCnt | |||
} | |||
} | |||
if !ok { | |||
} | |||
for k, v := range resentlyContributorDistinctDict { | |||
count, ok := contributorDistinctDict[k] | |||
if ok && count == v { | |||
stats.ContributorsAdded++ | |||
newContributersDict[recentlyContributor.Email] = struct{}{} | |||
} | |||
} | |||
} | |||
stats.Contributors = int64(len(contributorDistinctDict)) | |||
@@ -101,6 +125,66 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error | |||
} | |||
func GetTop10Contributor(repoPath string) ([]ContributorWithUserId, error) { | |||
contributors, err := git.GetContributors(repoPath) | |||
if err != nil { | |||
return make([]ContributorWithUserId, 0), err | |||
} | |||
contributorDistinctDict := make(map[string]ContributorWithUserId, 0) | |||
if contributors != nil { | |||
for _, contributor := range contributors { | |||
if strings.Compare(contributor.Email, "") == 0 { | |||
continue | |||
} | |||
user, err := GetUserByActivateEmail(contributor.Email) | |||
if err == nil { | |||
value, ok := contributorDistinctDict[user.Email] | |||
if !ok { | |||
contributorDistinctDict[user.Email] = ContributorWithUserId{ | |||
contributor, | |||
user.ID, | |||
user.IsAdmin, | |||
} | |||
} else { | |||
value.CommitCnt += contributor.CommitCnt | |||
} | |||
} else { | |||
value, ok := contributorDistinctDict[contributor.Email] | |||
if !ok { | |||
contributorDistinctDict[contributor.Email] = ContributorWithUserId{ | |||
contributor, | |||
-1, | |||
false, | |||
} | |||
} else { | |||
value.CommitCnt += contributor.CommitCnt | |||
} | |||
} | |||
} | |||
v := make([]ContributorWithUserId, 0, len(contributorDistinctDict)) | |||
for _, value := range contributorDistinctDict { | |||
v = append(v, value) | |||
} | |||
sort.Slice(v, func(i, j int) bool { | |||
return v[i].CommitCnt > v[j].CommitCnt | |||
}) | |||
if len(v) <= 10 { | |||
return v, nil | |||
} else { | |||
return v[0:10], nil | |||
} | |||
} | |||
return make([]ContributorWithUserId, 0), nil | |||
} | |||
func setKeyContributerDict(contributorDistinctDict map[string]int, email string, keyContributorsDict map[string]struct{}) { | |||
if contributorDistinctDict[email] >= 3 { | |||
_, ok := keyContributorsDict[email] | |||
@@ -114,6 +114,17 @@ func (repo *Repository) isCollaborator(e Engine, userID int64) (bool, error) { | |||
return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID}) | |||
} | |||
func (repo *Repository) GetCollaboratorMode(userID int64) int { | |||
collaboration := &Collaboration{RepoID: repo.ID, UserID: userID} | |||
has, err := x.Get(&collaboration) | |||
if err != nil || !has { | |||
return -1 | |||
} else { | |||
return int(collaboration.Mode) | |||
} | |||
} | |||
// IsCollaborator check if a user is a collaborator of a repository | |||
func (repo *Repository) IsCollaborator(userID int64) (bool, error) { | |||
return repo.isCollaborator(x, userID) | |||
@@ -9,56 +9,56 @@ import ( | |||
// RepoStatistic statistic info of all repository | |||
type RepoStatistic struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
RepoID int64 `xorm:"unique(s) NOT NULL"` | |||
Name string `xorm:"INDEX"` | |||
IsPrivate bool | |||
Date string `xorm:"unique(s) NOT NULL"` | |||
NumWatches int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumStars int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumForks int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumDownloads int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumComments int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumVisits int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumVersions int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0"` | |||
RepoSize int64 `xorm:"NOT NULL DEFAULT 0"` | |||
DatasetSize int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumModels int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumCommits int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumIssues int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumPulls int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
IssueFixedRate float32 `xorm:"NOT NULL"` | |||
NumContributor int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
Impact float64 `xorm:"NOT NULL DEFAULT 0"` | |||
Completeness float64 `xorm:"NOT NULL DEFAULT 0"` | |||
Liveness float64 `xorm:"NOT NULL DEFAULT 0"` | |||
ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0"` | |||
TeamHealth float64 `xorm:"NOT NULL DEFAULT 0"` | |||
Growth float64 `xorm:"NOT NULL DEFAULT 0"` | |||
RadarTotal float64 `xorm:"NOT NULL DEFAULT 0"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
ID int64 `xorm:"pk autoincr" json:"-"` | |||
RepoID int64 `xorm:"unique(s) NOT NULL" json:"repo_id"` | |||
Name string `xorm:"INDEX" json:"name"` | |||
IsPrivate bool `json:"isPrivate"` | |||
Date string `xorm:"unique(s) NOT NULL" json:"date"` | |||
NumWatches int64 `xorm:"NOT NULL DEFAULT 0" json:"watch"` | |||
NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumStars int64 `xorm:"NOT NULL DEFAULT 0" json:"star"` | |||
NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumForks int64 `xorm:"NOT NULL DEFAULT 0" json:"fork"` | |||
NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDownloads int64 `xorm:"NOT NULL DEFAULT 0" json:"download"` | |||
NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumComments int64 `xorm:"NOT NULL DEFAULT 0" json:"comment"` | |||
NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumVisits int64 `xorm:"NOT NULL DEFAULT 0" json:"view"` | |||
NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issueClosed"` | |||
NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumVersions int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
RepoSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
DatasetSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumModels int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommits int64 `xorm:"NOT NULL DEFAULT 0" json:"commit"` | |||
NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issue"` | |||
NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumPulls int64 `xorm:"NOT NULL DEFAULT 0" json:"pr"` | |||
NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
IssueFixedRate float32 `xorm:"NOT NULL" json:"issueClosedRatio"` | |||
NumContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"contributor"` | |||
NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
Impact float64 `xorm:"NOT NULL DEFAULT 0" json:"impact"` | |||
Completeness float64 `xorm:"NOT NULL DEFAULT 0" json:"completeness"` | |||
Liveness float64 `xorm:"NOT NULL DEFAULT 0" json:"liveness"` | |||
ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"projectHealth"` | |||
TeamHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"teamHealth"` | |||
Growth float64 `xorm:"NOT NULL DEFAULT 0" json:"growth"` | |||
RadarTotal float64 `xorm:"NOT NULL DEFAULT 0" json:"openi"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"-"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"-"` | |||
} | |||
func DeleteRepoStatDaily(date string) error { | |||
@@ -81,9 +81,60 @@ func DeleteRepoStatDaily(date string) error { | |||
return nil | |||
} | |||
func GetRepoStatisticByDate(date string) ([]*RepoStatistic, error) { | |||
func CountRepoStatByRawSql(sql string) (int64, error) { | |||
return xStatistic.SQL(sql).Count() | |||
} | |||
func GetRepoStatisticByRawSql(sql string) []*RepoStatistic { | |||
repoStatistics := make([]*RepoStatistic, 0) | |||
err := xStatistic.Where("date = ?", date).Find(&repoStatistics) | |||
xStatistic.SQL(sql).Find(&repoStatistics) | |||
return repoStatistics | |||
} | |||
func GetRepoStatLastUpdatedTime(repoId ...string) (string, string, error) { | |||
repoStatistic := new(RepoStatistic) | |||
var has bool | |||
var err error | |||
if len(repoId) == 0 { | |||
has, err = xStatistic.Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic) | |||
} else { | |||
has, err = xStatistic.Where("repo_id=?", repoId[0]).Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic) | |||
} | |||
if err != nil { | |||
return "", "", err | |||
} else { | |||
if has { | |||
return repoStatistic.CreatedUnix.Format("2006-01-02 15:04:05"), repoStatistic.Date, nil | |||
} else { | |||
return "", "", fmt.Errorf("Can not get the latest record.") | |||
} | |||
} | |||
} | |||
func GetRepoStatisticByDateAndRepoId(date string, repoId int64) (*RepoStatistic, error) { | |||
repoStatistic := new(RepoStatistic) | |||
has, err := xStatistic.Where("date=? and repo_id=?", date, repoId).Get(repoStatistic) | |||
if err != nil { | |||
return nil, err | |||
} else { | |||
if has { | |||
return repoStatistic, nil | |||
} else { | |||
return nil, fmt.Errorf("The num of return records is 0.") | |||
} | |||
} | |||
} | |||
func GetRepoStatisticByDate(date string, repoId int64) ([]*RepoStatistic, error) { | |||
repoStatistics := make([]*RepoStatistic, 0) | |||
err := xStatistic.Where("date = ? and repo_id=?", date, repoId).Find(&repoStatistics) | |||
return repoStatistics, err | |||
} | |||
@@ -107,6 +158,13 @@ func InsertRepoStat(repoStat *RepoStatistic) (int64, error) { | |||
return xStatistic.Insert(repoStat) | |||
} | |||
func RestoreRepoStatFork(numForks int64, repoId int64) error { | |||
sql := "update repo_statistic set num_forks=? where repo_id=?" | |||
_, err := xStatistic.Exec(sql, numForks, repoId) | |||
return err | |||
} | |||
func UpdateRepoStat(repoStat *RepoStatistic) error { | |||
sql := "update repo_statistic set impact=?,completeness=?,liveness=?,project_health=?,team_health=?,growth=?,radar_total=? where repo_id=? and date=?" | |||
@@ -19,6 +19,7 @@ type CreateModelArtsNotebookForm struct { | |||
JobName string `form:"job_name" binding:"Required"` | |||
Attachment string `form:"attachment"` | |||
Description string `form:"description"` | |||
Flavor string `form:"flavor"` | |||
} | |||
func (f *CreateModelArtsNotebookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
@@ -11,6 +11,7 @@ import ( | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/migrations" | |||
repository_service "code.gitea.io/gitea/modules/repository" | |||
api_repo "code.gitea.io/gitea/routers/api/v1/repo" | |||
"code.gitea.io/gitea/routers/repo" | |||
mirror_service "code.gitea.io/gitea/services/mirror" | |||
) | |||
@@ -195,6 +196,17 @@ func registerHandleUserStatistic() { | |||
}) | |||
} | |||
func registerHandleClearRepoStatisticFile() { | |||
RegisterTaskFatal("handle_repo_clear_statistic_file", &BaseConfig{ | |||
Enabled: true, | |||
RunAtStart: false, | |||
Schedule: "@daily", | |||
}, func(ctx context.Context, _ *models.User, _ Config) error { | |||
api_repo.ClearUnusedStatisticsFile() | |||
return nil | |||
}) | |||
} | |||
func initBasicTasks() { | |||
registerUpdateMirrorTask() | |||
registerRepoHealthCheck() | |||
@@ -99,7 +99,7 @@ type ResourcePool struct { | |||
} `json:"resource_pool"` | |||
} | |||
func GenerateTask(ctx *context.Context, jobName, uuid, description string) error { | |||
func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor string) error { | |||
var dataActualPath string | |||
if uuid != "" { | |||
dataActualPath = setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | |||
@@ -128,7 +128,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description string) error | |||
JobName: jobName, | |||
Description: description, | |||
ProfileID: setting.ProfileID, | |||
Flavor: setting.Flavor, | |||
Flavor: flavor, | |||
Pool: models.Pool{ | |||
ID: poolInfos.PoolInfo[0].PoolId, | |||
Name: poolInfos.PoolInfo[0].PoolName, | |||
@@ -163,6 +163,7 @@ var ( | |||
// UI settings | |||
UI = struct { | |||
ExplorePagingNum int | |||
ContributorPagingNum int | |||
IssuePagingNum int | |||
RepoSearchPagingNum int | |||
MembersPagingNum int | |||
@@ -203,19 +204,20 @@ var ( | |||
Keywords string | |||
} `ini:"ui.meta"` | |||
}{ | |||
ExplorePagingNum: 20, | |||
IssuePagingNum: 10, | |||
RepoSearchPagingNum: 10, | |||
MembersPagingNum: 20, | |||
FeedMaxCommitNum: 5, | |||
GraphMaxCommitNum: 100, | |||
CodeCommentLines: 4, | |||
ReactionMaxUserNum: 10, | |||
ThemeColorMetaTag: `#6cc644`, | |||
MaxDisplayFileSize: 8388608, | |||
DefaultTheme: `gitea`, | |||
Themes: []string{`gitea`, `arc-green`}, | |||
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, | |||
ExplorePagingNum: 20, | |||
ContributorPagingNum: 50, | |||
IssuePagingNum: 10, | |||
RepoSearchPagingNum: 10, | |||
MembersPagingNum: 20, | |||
FeedMaxCommitNum: 5, | |||
GraphMaxCommitNum: 100, | |||
CodeCommentLines: 4, | |||
ReactionMaxUserNum: 10, | |||
ThemeColorMetaTag: `#6cc644`, | |||
MaxDisplayFileSize: 8388608, | |||
DefaultTheme: `gitea`, | |||
Themes: []string{`gitea`, `arc-green`}, | |||
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, | |||
Notification: struct { | |||
MinTimeout time.Duration | |||
TimeoutStep time.Duration | |||
@@ -544,6 +546,8 @@ var ( | |||
GrowthContributors float64 | |||
GrowthCommit float64 | |||
GrowthComments float64 | |||
RecordBeginTime string | |||
Path string | |||
}{} | |||
) | |||
@@ -1324,6 +1328,8 @@ func SetRadarMapConfig() { | |||
RadarMap.GrowthContributors = sec.Key("growth_contributors").MustFloat64(0.2) | |||
RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2) | |||
RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2) | |||
RadarMap.RecordBeginTime = sec.Key("record_beigin_time").MustString("2021-11-05") | |||
RadarMap.Path = sec.Key("PATH").MustString("data/projectborad") | |||
} | |||
@@ -10,11 +10,11 @@ import ( | |||
"strconv" | |||
"strings" | |||
"github.com/unknwon/com" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/obs" | |||
"code.gitea.io/gitea/modules/setting" | |||
"github.com/unknwon/com" | |||
) | |||
type FileInfo struct { | |||
@@ -178,30 +178,45 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) { | |||
input := &obs.ListObjectsInput{} | |||
input.Bucket = setting.Bucket | |||
input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | |||
strPrefix := strings.Split(input.Prefix, "/") | |||
output, err := ObsCli.ListObjects(input) | |||
fileInfos := make([]FileInfo, 0) | |||
if err == nil { | |||
for _, val := range output.Contents { | |||
str1 := strings.Split(val.Key, "/") | |||
var isDir bool | |||
var fileName,nextParentDir string | |||
var fileName, nextParentDir string | |||
if strings.HasSuffix(val.Key, "/") { | |||
//dirs in next level dir | |||
if len(str1)-len(strPrefix) > 2 { | |||
continue | |||
} | |||
fileName = str1[len(str1)-2] | |||
isDir = true | |||
nextParentDir = fileName | |||
if fileName == parentDir || (fileName + "/") == setting.OutPutPath { | |||
if parentDir == "" { | |||
nextParentDir = fileName | |||
} else { | |||
nextParentDir = parentDir + "/" + fileName | |||
} | |||
if fileName == strPrefix[len(strPrefix)-1] || (fileName+"/") == setting.OutPutPath { | |||
continue | |||
} | |||
} else { | |||
//files in next level dir | |||
if len(str1)-len(strPrefix) > 1 { | |||
continue | |||
} | |||
fileName = str1[len(str1)-1] | |||
isDir = false | |||
nextParentDir = parentDir | |||
} | |||
fileInfo := FileInfo{ | |||
ModTime: val.LastModified.Format("2006-01-02 15:04:05"), | |||
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | |||
FileName: fileName, | |||
Size: val.Size, | |||
IsDir:isDir, | |||
Size: val.Size, | |||
IsDir: isDir, | |||
ParenDir: nextParentDir, | |||
} | |||
fileInfos = append(fileInfos, fileInfo) | |||
@@ -242,7 +257,7 @@ func GetObsCreateSignedUrl(jobName, parentDir, fileName string) (string, error) | |||
input := &obs.CreateSignedUrlInput{} | |||
input.Bucket = setting.Bucket | |||
input.Key = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir, fileName), "/") | |||
input.Expires = 60 * 60 | |||
input.Method = obs.HttpMethodGet | |||
@@ -218,6 +218,7 @@ show_only_private = Showing only private | |||
show_only_public = Showing only public | |||
issues.in_your_repos = In your repositories | |||
contributors = Contributors | |||
[explore] | |||
repos = Repositories | |||
@@ -755,6 +756,7 @@ unit_disabled = The site administrator has disabled this repository section. | |||
language_other = Other | |||
datasets = Datasets | |||
datasets.desc = Enable Dataset | |||
cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc. | |||
debug=Debug | |||
stop=Stop | |||
@@ -785,7 +787,12 @@ cloudbrain_operate = Operate | |||
cloudbrain_status_createtime = Status/Createtime | |||
cloudbrain_status_runtime = Running Time | |||
record_begintime_get_err=Can not get the record begin time. | |||
parameter_is_wrong=The input parameter is wrong. | |||
total_count_get_error=Can not get the total page. | |||
last_update_time_error=Can not get the last updated time. | |||
get_repo_stat_error=Can not get the statistics of the repository. | |||
get_repo_info_error=Can not get the information of the repository. | |||
modelarts.notebook=Debug Task | |||
modelarts.train_job=Train Task | |||
modelarts.train_job.new_debug= New Debug Task | |||
@@ -2152,6 +2159,19 @@ repos.stars = Stars | |||
repos.forks = Forks | |||
repos.issues = Issues | |||
repos.size = Size | |||
repos.id=ID | |||
repos.projectName=Project Name | |||
repos.isPrivate=Private | |||
repos.openi=OpenI | |||
repos.visit=Visit | |||
repos.download=Code Download | |||
repos.pr=PR | |||
repos.commit=Commit | |||
repos.closedIssues=Closed Issue | |||
repos.contributor=Contributor | |||
repos.yes=Yes | |||
repos.no=No | |||
datasets.dataset_manage_panel= Dataset Manage | |||
datasets.owner=Owner | |||
@@ -220,6 +220,8 @@ show_only_public=只显示公开的 | |||
issues.in_your_repos=属于该用户项目的 | |||
contributors=贡献者 | |||
[explore] | |||
repos=项目 | |||
users=用户 | |||
@@ -227,6 +229,7 @@ organizations=组织 | |||
images = 云脑镜像 | |||
search=搜索 | |||
code=代码 | |||
data_analysis=数字看板 | |||
repo_no_results=未找到匹配的项目。 | |||
dataset_no_results = 未找到匹配的数据集。 | |||
user_no_results=未找到匹配的用户。 | |||
@@ -757,6 +760,7 @@ unit_disabled=站点管理员已禁用此项目单元。 | |||
language_other=其它 | |||
datasets=数据集 | |||
datasets.desc=数据集功能 | |||
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | |||
debug=调试 | |||
stop=停止 | |||
@@ -787,6 +791,12 @@ cloudbrain_status_createtime=状态/创建时间 | |||
cloudbrain_status_runtime = 运行时长 | |||
cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 | |||
record_begintime_get_err=无法获取统计开始时间。 | |||
parameter_is_wrong=输入参数错误,请检查输入参数。 | |||
total_count_get_error=查询总页数失败。 | |||
last_update_time_error=查询最新更新时间失败。 | |||
get_repo_stat_error=查询当前仓库的统计信息失败。 | |||
get_repo_info_error=查询当前仓库信息失败。 | |||
modelarts.notebook=调试任务 | |||
modelarts.train_job=训练任务 | |||
modelarts.train_job.new_debug=新建调试任务 | |||
@@ -0,0 +1,41 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | |||
viewBox="0 0 96 17.3" style="enable-background:new 0 0 96 17.3;" xml:space="preserve"> | |||
<style type="text/css"> | |||
.st0{fill:#5BB973;} | |||
</style> | |||
<g> | |||
<path class="st0" d="M5.9,12.5l-1,3.8h-3L6.6,1.5H10l4.7,14.8h-3.1l-1-3.8H5.9z M6.5,10.2H10L9.6,8.5C9.4,7.8,9.1,7,8.9,6.1 | |||
C8.7,5.3,8.5,4.5,8.3,3.7H8.2C8,4.5,7.8,5.3,7.6,6.2S7.2,7.8,6.9,8.5L6.5,10.2z"/> | |||
<path class="st0" d="M19.5,1.5v14.8h-3V1.5H19.5z"/> | |||
<path class="st0" d="M27.7,6.6v10.6h-2.1V6.6h-1.8v-2h1.8V0.3h2.1v4.3h1.7v2H27.7z M31.6,7.4c-0.2,0.9-0.5,1.8-0.8,2.7 | |||
c-0.3,0.9-0.7,1.6-1.1,2.2c-0.1-0.1-0.2-0.2-0.4-0.3s-0.3-0.2-0.4-0.3c-0.2-0.1-0.3-0.2-0.5-0.3c-0.2-0.1-0.3-0.2-0.4-0.2 | |||
c0.4-0.5,0.7-1.1,1-1.9s0.5-1.5,0.6-2.3L31.6,7.4z M34.6,5.8c0,0.9-0.1,1.9-0.3,2.9c-0.1,1-0.4,2-0.7,3s-0.8,2-1.4,2.9 | |||
c-0.6,0.9-1.4,1.8-2.4,2.6c-0.1-0.1-0.2-0.2-0.3-0.4c-0.1-0.1-0.3-0.3-0.4-0.4c-0.1-0.1-0.3-0.3-0.4-0.4s-0.3-0.2-0.4-0.3 | |||
c0.9-0.7,1.6-1.5,2.1-2.3c0.6-0.8,1-1.7,1.3-2.5c0.3-0.9,0.5-1.7,0.7-2.6s0.2-1.7,0.3-2.5h-2.7V3.7h2.7V0.5h2v3.2h3.7 | |||
c0,0.1,0,0.3,0,0.4c0,0.1,0,0.2,0,0.3s0,0.2,0,0.3l-0.1,2.7l1.3-0.3c0.1,0.4,0.3,0.9,0.4,1.3c0.1,0.5,0.3,0.9,0.4,1.4 | |||
c0.1,0.5,0.2,0.9,0.3,1.3c0.1,0.4,0.2,0.8,0.2,1.1L39,12.8c-0.1-0.5-0.2-1.1-0.3-1.8s-0.3-1.4-0.5-2.1c0,1.2-0.1,2.1-0.1,3 | |||
c0,0.8-0.1,1.5-0.2,2.1c-0.1,0.6-0.1,1-0.2,1.4c-0.1,0.3-0.2,0.6-0.3,0.8c-0.2,0.3-0.4,0.5-0.7,0.7c-0.2,0.1-0.5,0.2-0.8,0.3 | |||
C35.6,17,35.3,17,34.8,17s-0.9,0-1.3,0c0-0.3-0.1-0.6-0.2-1c-0.1-0.4-0.3-0.7-0.4-1c0.4,0,0.9,0.1,1.2,0.1c0.4,0,0.7,0,0.8,0 | |||
c0.2,0,0.3,0,0.4-0.1c0.1,0,0.2-0.1,0.3-0.2c0.1-0.1,0.2-0.4,0.3-0.8c0.1-0.4,0.1-0.9,0.2-1.6s0.1-1.6,0.1-2.7 | |||
c0-1.1,0.1-2.4,0.1-3.9H34.6z"/> | |||
<path class="st0" d="M47.8,1.1C47.6,1.7,47.3,2.4,47,3c-0.3,0.6-0.6,1.2-0.9,1.9v12.4h-2.2v-9c-0.2,0.2-0.4,0.5-0.6,0.7 | |||
S43,9.3,42.8,9.5c0-0.1-0.1-0.3-0.2-0.5c-0.1-0.2-0.2-0.4-0.3-0.6c-0.1-0.2-0.2-0.4-0.3-0.6s-0.2-0.4-0.3-0.5 | |||
c0.4-0.4,0.8-0.9,1.2-1.4c0.4-0.5,0.8-1.1,1.1-1.6c0.4-0.6,0.7-1.2,1-1.8c0.3-0.6,0.6-1.3,0.8-1.9L47.8,1.1z M53.5,13.2v4h-2.2V5.3 | |||
h-0.7c-0.4,0.7-0.7,1.3-1.1,1.9s-0.8,1.1-1.2,1.6c-0.1-0.1-0.2-0.2-0.3-0.4c-0.1-0.1-0.3-0.3-0.4-0.4S47.2,7.8,47,7.7 | |||
c-0.2-0.1-0.3-0.2-0.4-0.3C47,6.9,47.4,6.5,47.8,6c0.4-0.5,0.7-1.1,1-1.7s0.6-1.2,0.9-1.8c0.3-0.6,0.5-1.3,0.7-1.9l2.1,0.5 | |||
c-0.1,0.4-0.3,0.8-0.4,1.1s-0.3,0.7-0.5,1.1h7v2h-5.1v1.9h4.7v1.9h-4.7v2h4.9v2H53.5z"/> | |||
<path class="st0" d="M69.3,11.3v6h-2.2v-6h-7V9.1h7V3.6H61V1.5h14.4v2.1h-6v5.5h7.1v2.2H69.3z M64.1,4.2c0.1,0.3,0.3,0.6,0.4,0.9 | |||
s0.3,0.6,0.4,1c0.1,0.3,0.2,0.6,0.4,0.9c0.1,0.3,0.2,0.6,0.2,0.8l-2.1,0.6c0-0.2-0.1-0.5-0.2-0.8s-0.2-0.6-0.3-1 | |||
c-0.1-0.3-0.2-0.7-0.4-1c-0.1-0.3-0.3-0.7-0.4-1L64.1,4.2z M74.6,4.7c-0.3,0.7-0.7,1.4-1,2.1c-0.3,0.7-0.7,1.2-1,1.7l-1.9-0.5 | |||
c0.1-0.3,0.3-0.6,0.4-0.9s0.3-0.6,0.4-1c0.1-0.3,0.3-0.7,0.4-1c0.1-0.3,0.2-0.6,0.3-0.9L74.6,4.7z"/> | |||
<path class="st0" d="M89.4,2c0.4,0.4,0.9,0.8,1.3,1.3c0.5,0.5,0.9,0.9,1.3,1.4s0.8,0.9,1.2,1.4c0.4,0.5,0.7,0.9,0.9,1.3l-1.8,1.3 | |||
c-0.1-0.2-0.3-0.4-0.4-0.6c-0.2-0.2-0.3-0.5-0.5-0.7c-1.6,0.1-3,0.1-4.1,0.2c-1.2,0.1-2.1,0.1-3,0.2c-0.8,0-1.5,0.1-2,0.1 | |||
s-1,0.1-1.3,0.1s-0.6,0.1-0.8,0.1c-0.2,0-0.4,0.1-0.5,0.1c0-0.1-0.1-0.2-0.1-0.4c-0.1-0.2-0.1-0.4-0.2-0.6 | |||
c-0.1-0.2-0.1-0.4-0.2-0.6C79,6.3,78.9,6.2,78.9,6c0.3-0.1,0.6-0.2,0.9-0.5c0.3-0.3,0.7-0.6,1-1c0.4-0.4,0.7-0.8,1.1-1.2 | |||
c0.4-0.4,0.7-0.9,1-1.3c0.3-0.4,0.6-0.8,0.8-1.2c0.2-0.4,0.4-0.6,0.5-0.8L86.4,1c-0.6,0.8-1.2,1.7-1.9,2.4s-1.4,1.5-2,2.2l7.4-0.2 | |||
c-0.3-0.4-0.7-0.8-1.1-1.2c-0.4-0.4-0.7-0.7-1-1.1L89.4,2z M82.4,16.3v0.9h-2.2V9.3h12.2v7.9H90v-0.9H82.4z M82.4,14.2H90v-2.9 | |||
h-7.6V14.2z"/> | |||
</g> | |||
</svg> |
@@ -0,0 +1 @@ | |||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636355832057" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8359" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M1024 767.6928c0 7.168-2.8672 12.0832-8.4992 14.9504L571.2896 1021.8496 569.1392 1021.8496C567.7056 1023.2832 565.5552 1024 562.688 1024c-2.8672 0-5.0176-0.7168-6.4512-2.1504L554.1888 1021.8496 109.9776 782.6432C104.2432 779.776 101.376 774.8608 101.376 767.6928L101.376 255.1808 101.376 253.0304c0-1.3312 0.7168-2.8672 2.1504-4.3008L103.5264 246.5792l4.3008-4.3008 2.1504-2.1504L554.1888 1.024c5.7344-1.3312 11.3664-1.3312 17.1008 0l444.2112 239.2064 2.1504 2.1504 4.3008 4.3008 0 2.1504L1024 253.0304l0 2.1504L1024 767.6928zM135.5776 757.0432l410.0096 222.1056 0-474.112L135.5776 282.9312 135.5776 757.0432zM154.8288 255.1808 562.688 475.136l407.8592-219.9552L562.688 35.2256 154.8288 255.1808zM989.7984 757.0432l0-474.112L579.7888 505.0368l0 474.112L989.7984 757.0432z" p-id="8360"></path></svg> |
@@ -523,6 +523,22 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
Get(notify.GetThread). | |||
Patch(notify.ReadThread) | |||
}, reqToken()) | |||
adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | |||
//Project board | |||
m.Group("/projectboard", func() { | |||
m.Get("/restoreFork", adminReq, repo.RestoreForkNumber) | |||
m.Group("/project", func() { | |||
m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics) | |||
m.Get("/download", adminReq, repo.ServeAllProjectsPeriodStatisticsFile) | |||
m.Group("/:id", func() { | |||
m.Get("", adminReq, repo.GetProjectLatestStatistics) | |||
m.Get("/period", adminReq, repo.GetProjectPeriodStatistics) | |||
}) | |||
}) | |||
}) | |||
// Users | |||
m.Group("/users", func() { | |||
@@ -0,0 +1,509 @@ | |||
package repo | |||
import ( | |||
"encoding/csv" | |||
"fmt" | |||
"io/ioutil" | |||
"net/http" | |||
"os" | |||
"path" | |||
"strconv" | |||
"time" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/setting" | |||
) | |||
const DEFAULT_PAGE_SIZE = 10 | |||
const DATE_FORMAT = "2006-01-02" | |||
type ProjectsPeriodData struct { | |||
RecordBeginTime string `json:"recordBeginTime"` | |||
LastUpdatedTime string `json:"lastUpdatedTime"` | |||
PageSize int `json:"pageSize"` | |||
TotalPage int `json:"totalPage"` | |||
TotalCount int64 `json:"totalCount"` | |||
PageRecords []*models.RepoStatistic `json:"pageRecords"` | |||
} | |||
type UserInfo struct { | |||
User string `json:"user"` | |||
Mode int `json:"mode"` | |||
PR int64 `json:"pr"` | |||
Commit int `json:"commit"` | |||
} | |||
type ProjectLatestData struct { | |||
RecordBeginTime string `json:"recordBeginTime"` | |||
LastUpdatedTime string `json:"lastUpdatedTime"` | |||
CreatTime string `json:"creatTime"` | |||
OpenI float64 `json:"openi"` | |||
Comment int64 `json:"comment"` | |||
View int64 `json:"view"` | |||
Download int64 `json:"download"` | |||
IssueClosedRatio float32 `json:"issueClosedRatio"` | |||
Impact float64 `json:"impact"` | |||
Completeness float64 `json:"completeness"` | |||
Liveness float64 `json:"liveness"` | |||
ProjectHealth float64 `json:"projectHealth"` | |||
TeamHealth float64 `json:"teamHealth"` | |||
Growth float64 `json:"growth"` | |||
Description string `json:"description"` | |||
Top10 []UserInfo `json:"top10"` | |||
} | |||
func RestoreForkNumber(ctx *context.Context) { | |||
repos, err := models.GetAllRepositories() | |||
if err != nil { | |||
log.Error("GetAllRepositories failed: %v", err.Error()) | |||
return | |||
} | |||
for _, repo := range repos { | |||
models.RestoreRepoStatFork(int64(repo.NumForks), repo.ID) | |||
} | |||
ctx.JSON(http.StatusOK, struct{}{}) | |||
} | |||
func GetAllProjectsPeriodStatistics(ctx *context.Context) { | |||
recordBeginTime, err := getRecordBeginTime() | |||
if err != nil { | |||
log.Error("Can not get record begin time", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
return | |||
} | |||
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) | |||
if err != nil { | |||
log.Error("Parameter is wrong", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong")) | |||
return | |||
} | |||
q := ctx.QueryTrim("q") | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
pageSize := ctx.QueryInt("pagesize") | |||
if pageSize <= 0 { | |||
pageSize = DEFAULT_PAGE_SIZE | |||
} | |||
orderBy := getOrderBy(ctx) | |||
latestUpdatedTime, 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 | |||
} | |||
countSql := generateCountSql(beginTime, endTime, latestDate, q) | |||
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 | |||
} | |||
projectsPeriodData := ProjectsPeriodData{ | |||
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), | |||
PageSize: pageSize, | |||
TotalPage: getTotalPage(total, pageSize), | |||
TotalCount: total, | |||
LastUpdatedTime: latestUpdatedTime, | |||
PageRecords: models.GetRepoStatisticByRawSql(generatePageSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)), | |||
} | |||
ctx.JSON(http.StatusOK, projectsPeriodData) | |||
} | |||
func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) { | |||
recordBeginTime, err := getRecordBeginTime() | |||
if err != nil { | |||
log.Error("Can not get record begin time", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
return | |||
} | |||
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) | |||
if err != nil { | |||
log.Error("Parameter is wrong", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong")) | |||
return | |||
} | |||
q := ctx.QueryTrim("q") | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
pageSize := 1000 | |||
orderBy := getOrderBy(ctx) | |||
_, 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 | |||
} | |||
countSql := generateCountSql(beginTime, endTime, latestDate, q) | |||
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 | |||
} | |||
fileName := getFileName(ctx, beginTime, endTime) | |||
if err := os.MkdirAll(setting.RadarMap.Path, os.ModePerm); err != nil { | |||
ctx.Error(http.StatusBadRequest, fmt.Errorf("Failed to create dir %s: %v", setting.AvatarUploadPath, err).Error()) | |||
} | |||
totalPage := getTotalPage(total, pageSize) | |||
f, e := os.Create(fileName) | |||
defer f.Close() | |||
if e != nil { | |||
log.Warn("Failed to create file", e) | |||
} | |||
writer := csv.NewWriter(f) | |||
writer.Write(allProjectsPeroidHeader(ctx)) | |||
for i := 0; i <= totalPage; i++ { | |||
pageRecords := models.GetRepoStatisticByRawSql(generatePageSql(beginTime, endTime, latestDate, q, orderBy, i+1, pageSize)) | |||
for _, record := range pageRecords { | |||
e = writer.Write(allProjectsPeroidValues(record, ctx)) | |||
if e != nil { | |||
log.Warn("Failed to write record", e) | |||
} | |||
} | |||
writer.Flush() | |||
} | |||
ctx.ServeFile(fileName) | |||
} | |||
func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time) string { | |||
baseName := setting.RadarMap.Path + "/" | |||
if ctx.QueryTrim("type") != "" { | |||
baseName = baseName + ctx.QueryTrim("type") + "_" | |||
} | |||
if ctx.QueryTrim("q") != "" { | |||
baseName = baseName + ctx.QueryTrim("q") + "_" | |||
} | |||
baseName = baseName + beginTime.AddDate(0, 0, -1).Format(DATE_FORMAT) + "_to_" + endTime.AddDate(0, 0, -1).Format(DATE_FORMAT) + "_" + strconv.FormatInt(time.Now().Unix(), 10) + ".csv" | |||
return baseName | |||
} | |||
func ClearUnusedStatisticsFile() { | |||
fileInfos, err := ioutil.ReadDir(setting.RadarMap.Path) | |||
if err != nil { | |||
log.Warn("can not read dir: "+setting.RadarMap.Path, err) | |||
return | |||
} | |||
for _, fileInfo := range fileInfos { | |||
if !fileInfo.IsDir() && fileInfo.ModTime().Before(time.Now().AddDate(0, 0, -1)) { | |||
os.Remove(path.Join(setting.RadarMap.Path, fileInfo.Name())) | |||
} | |||
} | |||
} | |||
func allProjectsPeroidHeader(ctx *context.Context) []string { | |||
return []string{ctx.Tr("repos.id"), ctx.Tr("repos.projectName"), ctx.Tr("repos.isPrivate"), ctx.Tr("repos.openi"), ctx.Tr("repos.visit"), ctx.Tr("repos.download"), ctx.Tr("repos.pr"), ctx.Tr("repos.commit"), | |||
ctx.Tr("repos.watches"), ctx.Tr("repos.stars"), ctx.Tr("repos.forks"), ctx.Tr("repos.issues"), ctx.Tr("repos.closedIssues"), ctx.Tr("repos.contributor")} | |||
} | |||
func allProjectsPeroidValues(rs *models.RepoStatistic, ctx *context.Context) []string { | |||
return []string{strconv.FormatInt(rs.RepoID, 10), rs.Name, getIsPrivateDisplay(rs.IsPrivate, ctx), strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64), | |||
strconv.FormatInt(rs.NumVisits, 10), strconv.FormatInt(rs.NumDownloads, 10), strconv.FormatInt(rs.NumPulls, 10), strconv.FormatInt(rs.NumCommits, 10), | |||
strconv.FormatInt(rs.NumWatches, 10), strconv.FormatInt(rs.NumStars, 10), strconv.FormatInt(rs.NumForks, 10), strconv.FormatInt(rs.NumIssues, 10), | |||
strconv.FormatInt(rs.NumClosedIssues, 10), strconv.FormatInt(rs.NumContributor, 10), | |||
} | |||
} | |||
func getIsPrivateDisplay(private bool, ctx *context.Context) string { | |||
if private { | |||
return ctx.Tr("repos.yes") | |||
} else { | |||
return ctx.Tr("repos.no") | |||
} | |||
} | |||
func GetProjectLatestStatistics(ctx *context.Context) { | |||
repoId := ctx.Params(":id") | |||
recordBeginTime, err := getRecordBeginTime() | |||
if err != nil { | |||
log.Error("Can not get record begin time", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
return | |||
} | |||
latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime(repoId) | |||
repoIdInt, _ := strconv.ParseInt(repoId, 10, 64) | |||
repoStat, err := models.GetRepoStatisticByDateAndRepoId(latestDate, repoIdInt) | |||
if err != nil { | |||
log.Error("Can not get the repo statistics "+repoId, err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_stat_error")) | |||
return | |||
} | |||
repository, err := models.GetRepositoryByID(repoIdInt) | |||
if err != nil { | |||
log.Error("Can not get the repo info "+repoId, err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_info_error")) | |||
return | |||
} | |||
projectLatestData := ProjectLatestData{ | |||
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), | |||
CreatTime: time.Unix(int64(repository.CreatedUnix), 0).Format(DATE_FORMAT), | |||
LastUpdatedTime: latestUpdatedTime, | |||
OpenI: repoStat.RadarTotal, | |||
Comment: repoStat.NumComments, | |||
View: repoStat.NumVisits, | |||
Download: repoStat.NumDownloads, | |||
IssueClosedRatio: repoStat.IssueFixedRate, | |||
Impact: repoStat.Impact, | |||
Completeness: repoStat.Completeness, | |||
Liveness: repoStat.Liveness, | |||
ProjectHealth: repoStat.ProjectHealth, | |||
TeamHealth: repoStat.TeamHealth, | |||
Growth: repoStat.Growth, | |||
Description: repository.Description, | |||
} | |||
contributors, err := models.GetTop10Contributor(repository.RepoPath()) | |||
if err != nil { | |||
log.Error("can not get contributors", err) | |||
} | |||
users := make([]UserInfo, 0) | |||
for _, contributor := range contributors { | |||
mode := repository.GetCollaboratorMode(contributor.UserId) | |||
if mode == -1 { | |||
if contributor.IsAdmin { | |||
mode = int(models.AccessModeAdmin) | |||
} | |||
if contributor.UserId == repository.OwnerID { | |||
mode = int(models.AccessModeOwner) | |||
} | |||
} | |||
pr := models.GetPullCountByUserAndRepoId(repoIdInt, contributor.UserId) | |||
userInfo := UserInfo{ | |||
User: contributor.Committer, | |||
Commit: contributor.CommitCnt, | |||
Mode: mode, | |||
PR: pr, | |||
} | |||
users = append(users, userInfo) | |||
} | |||
projectLatestData.Top10 = users | |||
ctx.JSON(http.StatusOK, projectLatestData) | |||
} | |||
func GetProjectPeriodStatistics(ctx *context.Context) { | |||
repoId := ctx.Params(":id") | |||
recordBeginTime, err := getRecordBeginTime() | |||
if err != nil { | |||
log.Error("Can not get record begin time", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
return | |||
} | |||
repoIdInt, _ := strconv.ParseInt(repoId, 10, 64) | |||
if err != nil { | |||
log.Error("Can not get record begin time", err) | |||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
return | |||
} | |||
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) | |||
isOpenI := ctx.QueryBool("openi") | |||
var repositorys []*models.RepoStatistic | |||
if isOpenI { | |||
repositorys = models.GetRepoStatisticByRawSql(generateRadarSql(beginTime, endTime, repoIdInt)) | |||
} else { | |||
repositorys = models.GetRepoStatisticByRawSql(generateTargetSql(beginTime, endTime, repoIdInt)) | |||
} | |||
ctx.JSON(http.StatusOK, repositorys) | |||
} | |||
func generateRadarSql(beginTime time.Time, endTime time.Time, repoId int64) string { | |||
sql := "SELECT date, impact, completeness, liveness, project_health, team_health, growth, radar_total FROM repo_statistic" + | |||
" where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) | |||
return sql | |||
} | |||
func generateTargetSql(beginTime time.Time, endTime time.Time, repoId int64) string { | |||
sql := "SELECT date, num_visits,num_downloads,num_commits FROM repo_statistic" + | |||
" where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) | |||
return sql | |||
} | |||
func generateCountSql(beginTime time.Time, endTime time.Time, yesterday string, q string) string { | |||
countSql := "SELECT count(*) FROM " + | |||
"(SELECT repo_id FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," + | |||
"(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" + | |||
" where A.repo_id=B.repo_id" | |||
if q != "" { | |||
countSql = countSql + " and B.name like '%" + q + "%'" | |||
} | |||
return countSql | |||
} | |||
func generatePageSql(beginTime time.Time, endTime time.Time, yesterday string, q string, orderBy string, page int, pageSize int) string { | |||
countSql := "SELECT A.repo_id,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_watches_added) as num_watches,sum(num_visits) as num_visits, sum(num_downloads_added) as num_downloads,sum(num_pulls_added) as num_pulls,sum(num_commits_added) as num_commits,sum(num_stars_added) as num_stars,sum(num_forks_added) num_forks,sum(num_issues_added) as num_issues,sum(num_closed_issues_added) as num_closed_issues,sum(num_contributor_added) as num_contributor " + | |||
" FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," + | |||
"(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" + | |||
" where A.repo_id=B.repo_id" | |||
if q != "" { | |||
countSql = countSql + " and B.name like '%" + q + "%'" | |||
} | |||
countSql = countSql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | |||
return countSql | |||
} | |||
func getOrderBy(ctx *context.Context) string { | |||
orderBy := "" | |||
switch ctx.Query("sort") { | |||
case "openi": | |||
orderBy = "B.radar_total" | |||
case "view": | |||
orderBy = "A.num_visits" | |||
case "download": | |||
orderBy = "A.num_downloads" | |||
case "pr": | |||
orderBy = "A.num_pulls" | |||
case "commit": | |||
orderBy = "A.num_commits" | |||
case "watch": | |||
orderBy = "A.num_watches" | |||
case "star": | |||
orderBy = "A.num_stars" | |||
case "fork": | |||
orderBy = "A.num_forks" | |||
case "issue": | |||
orderBy = "A.num_issues" | |||
case "issue_closed": | |||
orderBy = "A.num_closed_issues" | |||
case "contributor": | |||
orderBy = "A.num_contributor" | |||
default: | |||
orderBy = "B.radar_total" | |||
} | |||
return orderBy | |||
} | |||
func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) { | |||
queryType := ctx.QueryTrim("type") | |||
now := time.Now() | |||
recordBeginTimeTemp := recordBeginTime.AddDate(0, 0, 1) | |||
beginTimeStr := ctx.QueryTrim("beginTime") | |||
endTimeStr := ctx.QueryTrim("endTime") | |||
var beginTime time.Time | |||
var endTime time.Time | |||
var err error | |||
if queryType != "" { | |||
if queryType == "all" { | |||
beginTime = recordBeginTimeTemp | |||
endTime = now | |||
} else if queryType == "yesterday" { | |||
endTime = now | |||
beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location()) | |||
} else if queryType == "current_week" { | |||
beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+1) | |||
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) | |||
endTime = now | |||
} else if queryType == "current_month" { | |||
endTime = now | |||
beginTime = time.Date(endTime.Year(), endTime.Month(), 2, 0, 0, 0, 0, now.Location()) | |||
} else if queryType == "monthly" { | |||
endTime = now | |||
beginTime = now.AddDate(0, -1, 1) | |||
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) | |||
} else if queryType == "current_year" { | |||
endTime = now | |||
beginTime = time.Date(endTime.Year(), 1, 2, 0, 0, 0, 0, now.Location()) | |||
} else if queryType == "last_month" { | |||
lastMonthTime := now.AddDate(0, -1, 0) | |||
beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 2, 0, 0, 0, 0, now.Location()) | |||
endTime = time.Date(now.Year(), now.Month(), 2, 0, 0, 0, 0, now.Location()) | |||
} else { | |||
return now, now, fmt.Errorf("The value of type parameter is wrong.") | |||
} | |||
} else { | |||
if beginTimeStr == "" || endTimeStr == "" { | |||
//如果查询类型和开始时间结束时间都未设置,按queryType=all处理 | |||
beginTime = recordBeginTimeTemp | |||
endTime = now | |||
} else { | |||
beginTime, err = time.Parse("2006-01-02", beginTimeStr) | |||
if err != nil { | |||
return now, now, err | |||
} | |||
endTime, err = time.Parse("2006-01-02", endTimeStr) | |||
if err != nil { | |||
return now, now, err | |||
} | |||
beginTime = beginTime.AddDate(0, 0, 1) | |||
endTime = endTime.AddDate(0, 0, 1) | |||
} | |||
} | |||
if beginTime.Before(recordBeginTimeTemp) { | |||
beginTime = recordBeginTimeTemp | |||
} | |||
return beginTime, endTime, nil | |||
} | |||
func getRecordBeginTime() (time.Time, error) { | |||
return time.Parse(DATE_FORMAT, setting.RadarMap.RecordBeginTime) | |||
} | |||
func getTotalPage(total int64, pageSize int) int { | |||
another := 0 | |||
if int(total)%pageSize != 0 { | |||
another = 1 | |||
} | |||
return int(total)/pageSize + another | |||
} |
@@ -33,8 +33,9 @@ const ( | |||
// tplExploreOrganizations explore organizations page template | |||
tplExploreOrganizations base.TplName = "explore/organizations" | |||
// tplExploreCode explore code page template | |||
tplExploreCode base.TplName = "explore/code" | |||
tplExploreImages base.TplName = "explore/images" | |||
tplExploreCode base.TplName = "explore/code" | |||
tplExploreImages base.TplName = "explore/images" | |||
tplExploreExploreDataAnalysis base.TplName = "explore/data_analysis" | |||
) | |||
// Home render home page | |||
@@ -146,7 +147,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | |||
ctx.Data["SortType"] = "hot" | |||
orderBy = models.SearchOrderByHot | |||
} | |||
orderBy = orderBy + ",id" | |||
//todo:support other topics | |||
keyword := strings.Trim(ctx.Query("q"), " ") | |||
topic := strings.Trim(ctx.Query("topic"), " ") | |||
@@ -501,6 +502,10 @@ func ExploreImages(ctx *context.Context) { | |||
ctx.HTML(200, tplExploreImages) | |||
} | |||
func ExploreDataAnalysis(ctx *context.Context) { | |||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||
} | |||
// NotFound render 404 page | |||
func NotFound(ctx *context.Context) { | |||
ctx.Data["Title"] = "Page Not Found" | |||
@@ -204,7 +204,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
resourceSpecId := form.ResourceSpecId | |||
if !jobNamePattern.MatchString(jobName) { | |||
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplModelArtsNew, &form) | |||
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplCloudBrainNew, &form) | |||
return | |||
} | |||
@@ -317,6 +317,12 @@ func HTTP(ctx *context.Context) { | |||
go repo.IncreaseCloneCnt() | |||
} | |||
if ctx.Req.Method == "POST" { | |||
if strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { | |||
go repo.IncreaseGitCloneCnt() | |||
} | |||
} | |||
w := ctx.Resp | |||
r := ctx.Req.Request | |||
cfg := &serviceConfig{ | |||
@@ -27,15 +27,10 @@ import ( | |||
) | |||
const ( | |||
// tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index" | |||
tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index" | |||
tplModelArtsNotebookNew base.TplName = "repo/modelarts/notebook/new" | |||
tplModelArtsNotebookShow base.TplName = "repo/modelarts/notebook/show" | |||
tplModelArtsIndex base.TplName = "repo/modelarts/index" | |||
tplModelArtsNew base.TplName = "repo/modelarts/new" | |||
tplModelArtsShow base.TplName = "repo/modelarts/show" | |||
tplModelArtsTrainJobIndex base.TplName = "repo/modelarts/trainjob/index" | |||
tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" | |||
tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" | |||
@@ -50,229 +45,6 @@ func MustEnableModelArts(ctx *context.Context) { | |||
} | |||
} | |||
func ModelArtsIndex(ctx *context.Context) { | |||
MustEnableModelArts(ctx) | |||
repo := ctx.Repo.Repository | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.IssuePagingNum, | |||
}, | |||
RepoID: repo.ID, | |||
Type: models.TypeCloudBrainTwo, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("Cloudbrain", err) | |||
return | |||
} | |||
for i, task := range ciTasks { | |||
if task.Status == string(models.JobRunning) { | |||
ciTasks[i].CanDebug = true | |||
} else { | |||
ciTasks[i].CanDebug = false | |||
} | |||
ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||
} | |||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
pager.SetDefaultParams(ctx) | |||
ctx.Data["Page"] = pager | |||
ctx.Data["PageIsCloudBrain"] = true | |||
ctx.Data["Tasks"] = ciTasks | |||
ctx.HTML(200, tplModelArtsIndex) | |||
} | |||
func ModelArtsNew(ctx *context.Context) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
t := time.Now() | |||
var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
ctx.Data["job_name"] = jobName | |||
attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID) | |||
if err != nil { | |||
ctx.ServerError("GetAllUserAttachments failed:", err) | |||
return | |||
} | |||
ctx.Data["attachments"] = attachs | |||
ctx.Data["dataset_path"] = modelarts.DataSetMountPath | |||
ctx.Data["env"] = modelarts.NotebookEnv | |||
ctx.Data["notebook_type"] = modelarts.NotebookType | |||
if modelarts.FlavorInfos == nil { | |||
json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos) | |||
} | |||
ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo | |||
ctx.HTML(200, tplModelArtsNew) | |||
} | |||
func ModelArtsCreate(ctx *context.Context, form auth.CreateModelArtsForm) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
jobName := form.JobName | |||
uuid := form.Attachment | |||
description := form.Description | |||
//repo := ctx.Repo.Repository | |||
if !jobNamePattern.MatchString(jobName) { | |||
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplModelArtsNew, &form) | |||
return | |||
} | |||
err := modelarts.GenerateTask(ctx, jobName, uuid, description) | |||
if err != nil { | |||
ctx.RenderWithErr(err.Error(), tplModelArtsNew, &form) | |||
return | |||
} | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts") | |||
} | |||
func ModelArtsShow(ctx *context.Context) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
var jobID = ctx.Params(":jobid") | |||
task, err := models.GetCloudbrainByJobID(jobID) | |||
if err != nil { | |||
ctx.Data["error"] = err.Error() | |||
ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) | |||
return | |||
} | |||
result, err := modelarts.GetJob(jobID) | |||
if err != nil { | |||
ctx.Data["error"] = err.Error() | |||
ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) | |||
return | |||
} | |||
if result != nil { | |||
task.Status = result.Status | |||
err = models.UpdateJob(task) | |||
if err != nil { | |||
ctx.Data["error"] = err.Error() | |||
ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) | |||
return | |||
} | |||
createTime, _ := com.StrTo(result.CreationTimestamp).Int64() | |||
result.CreateTime = time.Unix(int64(createTime/1000), 0).Format("2006-01-02 15:04:05") | |||
endTime, _ := com.StrTo(result.LatestUpdateTimestamp).Int64() | |||
result.LatestUpdateTime = time.Unix(int64(endTime/1000), 0).Format("2006-01-02 15:04:05") | |||
result.QueuingInfo.BeginTime = time.Unix(int64(result.QueuingInfo.BeginTimestamp/1000), 0).Format("2006-01-02 15:04:05") | |||
result.QueuingInfo.EndTime = time.Unix(int64(result.QueuingInfo.EndTimestamp/1000), 0).Format("2006-01-02 15:04:05") | |||
} | |||
ctx.Data["task"] = task | |||
ctx.Data["jobID"] = jobID | |||
ctx.Data["result"] = result | |||
ctx.HTML(200, tplModelArtsShow) | |||
} | |||
func ModelArtsDebug(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
_, err := models.GetCloudbrainByJobID(jobID) | |||
if err != nil { | |||
ctx.ServerError("GetCloudbrainByJobID failed", err) | |||
return | |||
} | |||
result, err := modelarts.GetJob(jobID) | |||
if err != nil { | |||
ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) | |||
return | |||
} | |||
res, err := modelarts.GetJobToken(jobID) | |||
if err != nil { | |||
ctx.RenderWithErr(err.Error(), tplModelArtsIndex, nil) | |||
return | |||
} | |||
urls := strings.Split(result.Spec.Annotations.Url, "/") | |||
urlPrefix := result.Spec.Annotations.TargetDomain | |||
for i, url := range urls { | |||
if i > 2 { | |||
urlPrefix += "/" + url | |||
} | |||
} | |||
//urlPrefix := result.Spec.Annotations.TargetDomain + "/modelarts/internal/hub/notebook/user/" + task.JobID | |||
log.Info(urlPrefix) | |||
debugUrl := urlPrefix + "?token=" + res.Token | |||
ctx.Redirect(debugUrl) | |||
} | |||
func ModelArtsStop(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
log.Info(jobID) | |||
task, err := models.GetCloudbrainByJobID(jobID) | |||
if err != nil { | |||
ctx.ServerError("GetCloudbrainByJobID failed", err) | |||
return | |||
} | |||
if task.Status != string(models.JobRunning) { | |||
log.Error("the job(%s) is not running", task.JobName) | |||
ctx.ServerError("the job is not running", errors.New("the job is not running")) | |||
return | |||
} | |||
param := models.NotebookAction{ | |||
Action: models.ActionStop, | |||
} | |||
res, err := modelarts.StopJob(jobID, param) | |||
if err != nil { | |||
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.ServerError("StopJob failed", err) | |||
return | |||
} | |||
task.Status = res.CurrentStatus | |||
err = models.UpdateJob(task) | |||
if err != nil { | |||
ctx.ServerError("UpdateJob failed", err) | |||
return | |||
} | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts") | |||
} | |||
func ModelArtsDel(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
task, err := models.GetCloudbrainByJobID(jobID) | |||
if err != nil { | |||
ctx.ServerError("GetCloudbrainByJobID failed", err) | |||
return | |||
} | |||
if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) { | |||
log.Error("the job(%s) has not been stopped", task.JobName) | |||
ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped")) | |||
return | |||
} | |||
_, err = modelarts.DelJob(jobID) | |||
if err != nil { | |||
log.Error("DelJob(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.ServerError("DelJob failed", err) | |||
return | |||
} | |||
err = models.DeleteJob(task) | |||
if err != nil { | |||
ctx.ServerError("DeleteJob failed", err) | |||
return | |||
} | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts") | |||
} | |||
func NotebookIndex(ctx *context.Context) { | |||
MustEnableModelArts(ctx) | |||
repo := ctx.Repo.Repository | |||
@@ -342,8 +114,9 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) | |||
jobName := form.JobName | |||
uuid := form.Attachment | |||
description := form.Description | |||
flavor := form.Flavor | |||
err := modelarts.GenerateTask(ctx, jobName, uuid, description) | |||
err := modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) | |||
if err != nil { | |||
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) | |||
return | |||
@@ -93,6 +93,7 @@ func RepoStatisticDaily(date string) { | |||
IsPrivate: repo.IsPrivate, | |||
NumWatches: int64(repo.NumWatches), | |||
NumStars: int64(repo.NumStars), | |||
NumForks: int64(repo.NumForks), | |||
NumDownloads: repo.CloneCnt, | |||
NumComments: numComments, | |||
NumVisits: int64(numVisits), | |||
@@ -115,7 +116,7 @@ func RepoStatisticDaily(date string) { | |||
} | |||
dayBeforeDate := t.AddDate(0, 0, -1).Format("2006-01-02") | |||
repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate) | |||
repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate, repo.ID) | |||
if err != nil { | |||
log.Error("get data of day before the date failed ", err) | |||
@@ -1,13 +1,27 @@ | |||
package repo | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"time" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/log" | |||
) | |||
func QueryUserStaticData(ctx *context.Context) { | |||
startDate := ctx.Query("startDate") | |||
endDate := ctx.Query("endDate") | |||
log.Info("startDate=" + startDate + " endDate=" + endDate) | |||
startTime, _ := time.Parse("2006-01-02", startDate) | |||
endTime, _ := time.Parse("2006-01-02", endDate) | |||
log.Info("startTime=" + fmt.Sprint(startTime.Unix()) + " endDate=" + fmt.Sprint(endTime.Unix())) | |||
ctx.JSON(http.StatusOK, models.QueryUserStaticData(startTime.Unix(), endTime.Unix())) | |||
} | |||
func TimingCountDataByDate(date string) { | |||
t, _ := time.Parse("2006-01-02", date) | |||
@@ -12,6 +12,7 @@ import ( | |||
"fmt" | |||
gotemplate "html/template" | |||
"io/ioutil" | |||
"net/http" | |||
"net/url" | |||
"path" | |||
"strings" | |||
@@ -31,11 +32,12 @@ import ( | |||
) | |||
const ( | |||
tplRepoEMPTY base.TplName = "repo/empty" | |||
tplRepoHome base.TplName = "repo/home" | |||
tplWatchers base.TplName = "repo/watchers" | |||
tplForks base.TplName = "repo/forks" | |||
tplMigrating base.TplName = "repo/migrating" | |||
tplRepoEMPTY base.TplName = "repo/empty" | |||
tplRepoHome base.TplName = "repo/home" | |||
tplWatchers base.TplName = "repo/watchers" | |||
tplForks base.TplName = "repo/forks" | |||
tplMigrating base.TplName = "repo/migrating" | |||
tplContributors base.TplName = "repo/contributors" | |||
) | |||
type namedBlob struct { | |||
@@ -243,6 +245,11 @@ func renderDirectory(ctx *context.Context, treeLink string) { | |||
ctx.Data["ReadmeInList"] = true | |||
ctx.Data["ReadmeExist"] = true | |||
ctx.Data["FileIsSymlink"] = readmeFile.isSymlink | |||
ctx.Data["ReadmeName"] = readmeFile.name | |||
if ctx.Repo.CanEnableEditor() { | |||
ctx.Data["CanEditFile"] = true | |||
} | |||
dataRc, err := readmeFile.blob.DataAsync() | |||
if err != nil { | |||
@@ -570,19 +577,29 @@ func safeURL(address string) string { | |||
} | |||
type ContributorInfo struct { | |||
UserInfo *models.User // nil for contributor who is not a registered user | |||
Email string | |||
CommitCnt int | |||
UserInfo *models.User // nil for contributor who is not a registered user | |||
RelAvatarLink string `json:"rel_avatar_link"` | |||
UserName string `json:"user_name"` | |||
Email string `json:"email"` | |||
CommitCnt int `json:"commit_cnt"` | |||
} | |||
type GetContributorsInfo struct { | |||
ErrorCode int `json:"error_code"` | |||
ErrorMsg string `json:"error_msg"` | |||
Count int `json:"count"` | |||
ContributorInfo []*ContributorInfo `json:"contributor_info"` | |||
} | |||
func getContributorInfo(contributorInfos []*ContributorInfo, email string) *ContributorInfo{ | |||
func getContributorInfo(contributorInfos []*ContributorInfo, email string) *ContributorInfo { | |||
for _, c := range contributorInfos { | |||
if strings.Compare(c.Email,email) == 0 { | |||
if strings.Compare(c.Email, email) == 0 { | |||
return c | |||
} | |||
} | |||
return nil | |||
} | |||
// Home render repository home page | |||
func Home(ctx *context.Context) { | |||
if len(ctx.Repo.Units) > 0 { | |||
@@ -591,35 +608,41 @@ func Home(ctx *context.Context) { | |||
if err == nil && contributors != nil { | |||
startTime := time.Now() | |||
var contributorInfos []*ContributorInfo | |||
contributorInfoHash:= make(map[string]*ContributorInfo) | |||
contributorInfoHash := make(map[string]*ContributorInfo) | |||
count := 0 | |||
for _, c := range contributors { | |||
if strings.Compare(c.Email,"") == 0 { | |||
if count >= 25 { | |||
continue | |||
} | |||
if strings.Compare(c.Email, "") == 0 { | |||
continue | |||
} | |||
// get user info from committer email | |||
user, err := models.GetUserByActivateEmail(c.Email) | |||
if err == nil { | |||
// committer is system user, get info through user's primary email | |||
if existedContributorInfo,ok:=contributorInfoHash[user.Email];ok { | |||
if existedContributorInfo, ok := contributorInfoHash[user.Email]; ok { | |||
// existed: same primary email, different committer name | |||
existedContributorInfo.CommitCnt += c.CommitCnt | |||
}else{ | |||
} else { | |||
// new committer info | |||
var newContributor = &ContributorInfo{ | |||
user, user.Email,c.CommitCnt, | |||
user, user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt, | |||
} | |||
contributorInfos = append(contributorInfos, newContributor ) | |||
count++ | |||
contributorInfos = append(contributorInfos, newContributor) | |||
contributorInfoHash[user.Email] = newContributor | |||
} | |||
} else { | |||
// committer is not system user | |||
if existedContributorInfo,ok:=contributorInfoHash[c.Email];ok { | |||
if existedContributorInfo, ok := contributorInfoHash[c.Email]; ok { | |||
// existed: same primary email, different committer name | |||
existedContributorInfo.CommitCnt += c.CommitCnt | |||
}else{ | |||
} else { | |||
var newContributor = &ContributorInfo{ | |||
user, c.Email,c.CommitCnt, | |||
user, "", "",c.Email, c.CommitCnt, | |||
} | |||
count++ | |||
contributorInfos = append(contributorInfos, newContributor) | |||
contributorInfoHash[c.Email] = newContributor | |||
} | |||
@@ -627,7 +650,7 @@ func Home(ctx *context.Context) { | |||
} | |||
ctx.Data["ContributorInfo"] = contributorInfos | |||
var duration = time.Since(startTime) | |||
log.Info("getContributorInfo cost: %v seconds",duration.Seconds()) | |||
log.Info("getContributorInfo cost: %v seconds", duration.Seconds()) | |||
} | |||
if ctx.Repo.Repository.IsBeingCreated() { | |||
task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) | |||
@@ -694,13 +717,13 @@ func renderLicense(ctx *context.Context) { | |||
log.Error("failed to get license content: %v, err:%v", f, err) | |||
continue | |||
} | |||
if bytes.Compare(buf,license) == 0 { | |||
log.Info("got matched license:%v",f) | |||
if bytes.Compare(buf, license) == 0 { | |||
log.Info("got matched license:%v", f) | |||
ctx.Data["LICENSE"] = f | |||
return | |||
} | |||
} | |||
log.Info("not found matched license,repo:%v",ctx.Repo.Repository.Name) | |||
log.Info("not found matched license,repo:%v", ctx.Repo.Repository.Name) | |||
} | |||
func renderLanguageStats(ctx *context.Context) { | |||
@@ -801,31 +824,31 @@ func renderCode(ctx *context.Context) { | |||
baseGitRepo, err := git.OpenRepository(ctx.Repo.Repository.BaseRepo.RepoPath()) | |||
defer baseGitRepo.Close() | |||
if err != nil { | |||
log.Error("error open baseRepo:%s",ctx.Repo.Repository.BaseRepo.RepoPath()) | |||
log.Error("error open baseRepo:%s", ctx.Repo.Repository.BaseRepo.RepoPath()) | |||
ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error | |||
}else{ | |||
if _,error:= baseGitRepo.GetBranch(ctx.Repo.BranchName);error==nil{ | |||
} else { | |||
if _, error := baseGitRepo.GetBranch(ctx.Repo.BranchName); error == nil { | |||
//base repo has the same branch, then compare between current repo branch and base repo's branch | |||
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.BranchName | |||
ctx.SetParams("*",compareUrl) | |||
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.BranchName | |||
ctx.SetParams("*", compareUrl) | |||
ctx.Data["UpstreamSameBranchName"] = true | |||
}else{ | |||
} else { | |||
//else, compare between current repo branch and base repo's default branch | |||
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.Repository.BaseRepo.DefaultBranch | |||
ctx.SetParams("*",compareUrl) | |||
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.Repository.BaseRepo.DefaultBranch | |||
ctx.SetParams("*", compareUrl) | |||
ctx.Data["UpstreamSameBranchName"] = false | |||
} | |||
_, _, headGitRepo, compareInfo, _, _ := ParseCompareInfo(ctx) | |||
defer headGitRepo.Close() | |||
if compareInfo!= nil { | |||
if compareInfo.Commits!=nil { | |||
log.Info("compareInfoCommits数量:%d",compareInfo.Commits.Len()) | |||
if compareInfo != nil { | |||
if compareInfo.Commits != nil { | |||
log.Info("compareInfoCommits数量:%d", compareInfo.Commits.Len()) | |||
ctx.Data["FetchUpstreamCnt"] = compareInfo.Commits.Len() | |||
}else{ | |||
} else { | |||
log.Info("compareInfo nothing different") | |||
ctx.Data["FetchUpstreamCnt"] = 0 | |||
} | |||
}else{ | |||
} else { | |||
ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error | |||
} | |||
} | |||
@@ -893,3 +916,64 @@ func Forks(ctx *context.Context) { | |||
ctx.HTML(200, tplForks) | |||
} | |||
func Contributors(ctx *context.Context) { | |||
ctx.HTML(http.StatusOK, tplContributors) | |||
} | |||
func ContributorsAPI(ctx *context.Context) { | |||
count := 0 | |||
errorCode := 0 | |||
errorMsg := "" | |||
contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath()) | |||
var contributorInfos []*ContributorInfo | |||
if err == nil && contributors != nil { | |||
contributorInfoHash := make(map[string]*ContributorInfo) | |||
for _, c := range contributors { | |||
if strings.Compare(c.Email, "") == 0 { | |||
continue | |||
} | |||
// get user info from committer email | |||
user, err := models.GetUserByActivateEmail(c.Email) | |||
if err == nil { | |||
// committer is system user, get info through user's primary email | |||
if existedContributorInfo, ok := contributorInfoHash[user.Email]; ok { | |||
// existed: same primary email, different committer name | |||
existedContributorInfo.CommitCnt += c.CommitCnt | |||
} else { | |||
// new committer info | |||
var newContributor = &ContributorInfo{ | |||
user, user.RelAvatarLink(),user.Name, user.Email,c.CommitCnt, | |||
} | |||
count++ | |||
contributorInfos = append(contributorInfos, newContributor) | |||
contributorInfoHash[user.Email] = newContributor | |||
} | |||
} else { | |||
// committer is not system user | |||
if existedContributorInfo, ok := contributorInfoHash[c.Email]; ok { | |||
// existed: same primary email, different committer name | |||
existedContributorInfo.CommitCnt += c.CommitCnt | |||
} else { | |||
var newContributor = &ContributorInfo{ | |||
user, "", "",c.Email,c.CommitCnt, | |||
} | |||
count++ | |||
contributorInfos = append(contributorInfos, newContributor) | |||
contributorInfoHash[c.Email] = newContributor | |||
} | |||
} | |||
} | |||
} else { | |||
log.Error("GetContributors failed: %v", err) | |||
errorCode = -1 | |||
errorMsg = err.Error() | |||
} | |||
ctx.JSON(http.StatusOK, GetContributorsInfo{ | |||
ErrorCode: errorCode, | |||
ErrorMsg: errorMsg, | |||
Count: count, | |||
ContributorInfo: contributorInfos, | |||
}) | |||
} |
@@ -311,7 +311,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Head("/", func() string { | |||
return "" | |||
}) | |||
m.Get("/", routers.Dashboard) | |||
m.Get("/", routers.Home) | |||
m.Get("/dashboard", routers.Dashboard) | |||
m.Group("/explore", func() { | |||
m.Get("", func(ctx *context.Context) { | |||
@@ -325,6 +325,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/organizations", routers.ExploreOrganizations) | |||
m.Get("/code", routers.ExploreCode) | |||
m.Get("/images", routers.ExploreImages) | |||
m.Get("/data_analysis", routers.ExploreDataAnalysis) | |||
}, ignSignIn) | |||
m.Combo("/install", routers.InstallInit).Get(routers.Install). | |||
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) | |||
@@ -615,6 +616,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
//reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) | |||
// ***** START: Organization ***** | |||
m.Group("/org", func() { | |||
m.Group("/:org", func() { | |||
m.Get("/members", org.Members) | |||
}, context.OrgAssignment()) | |||
}) | |||
m.Group("/org", func() { | |||
m.Group("", func() { | |||
m.Get("/create", org.Create) | |||
@@ -625,7 +631,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/dashboard", user.Dashboard) | |||
m.Get("/^:type(issues|pulls)$", user.Issues) | |||
m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) | |||
m.Get("/members", org.Members) | |||
//m.Get("/members", org.Members) | |||
m.Post("/members/action/:action", org.MembersAction) | |||
m.Get("/teams", org.Teams) | |||
@@ -786,9 +792,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) | |||
m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) | |||
m.Get("/tool/query_user_static", repo.QueryUserStaticData) | |||
// Grouping for those endpoints not requiring authentication | |||
m.Group("/:username/:reponame", func() { | |||
m.Get("/contributors", repo.Contributors) | |||
m.Get("/contributors/list", repo.ContributorsAPI) | |||
m.Group("/milestone", func() { | |||
m.Get("/:id", repo.MilestoneIssuesAndPulls) | |||
}, reqRepoIssuesOrPullsReader, context.RepoRef()) | |||
@@ -544,7 +544,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR | |||
if err := models.UpdateUserCols(u, "language"); err != nil { | |||
log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language)) | |||
return setting.AppSubURL + "/" | |||
return setting.AppSubURL + "/dashboard" | |||
} | |||
} else { | |||
// Language setting of the user use the one previously set | |||
@@ -562,7 +562,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR | |||
u.SetLastLogin() | |||
if err := models.UpdateUserCols(u, "last_login_unix"); err != nil { | |||
ctx.ServerError("UpdateUserCols", err) | |||
return setting.AppSubURL + "/" | |||
return setting.AppSubURL + "/dashboard" | |||
} | |||
if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) { | |||
@@ -574,9 +574,9 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR | |||
} | |||
if obeyRedirect { | |||
ctx.Redirect(setting.AppSubURL + "/") | |||
ctx.Redirect(setting.AppSubURL + "/dashboard") | |||
} | |||
return setting.AppSubURL + "/" | |||
return setting.AppSubURL + "/dashboard" | |||
} | |||
// SignInOAuth handles the OAuth2 login buttons | |||
@@ -180,8 +180,8 @@ | |||
var _hmt = _hmt || []; | |||
(function() { | |||
var hm = document.createElement("script"); | |||
hm.src = "https://hm.baidu.com/hm.js?7c4ef0a24be6109ab22e63c832ab21cf"; | |||
var s = document.getElementsByTagName("script")[0]; | |||
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||
var s = document.getElementsByTagName("script")[0]; | |||
s.parentNode.insertBefore(hm, s); | |||
})(); | |||
</script> | |||
@@ -181,8 +181,8 @@ | |||
var _hmt = _hmt || []; | |||
(function() { | |||
var hm = document.createElement("script"); | |||
hm.src = "https://hm.baidu.com/hm.js?7c4ef0a24be6109ab22e63c832ab21cf"; | |||
var s = document.getElementsByTagName("script")[0]; | |||
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||
var s = document.getElementsByTagName("script")[0]; | |||
s.parentNode.insertBefore(hm, s); | |||
})(); | |||
</script> | |||
@@ -7,6 +7,14 @@ | |||
<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> | |||
@@ -29,6 +37,7 @@ | |||
<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> | |||
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
@@ -29,6 +29,7 @@ | |||
<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> | |||
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
@@ -0,0 +1,14 @@ | |||
{{template "base/head" .}} | |||
<div id="data_analysis" style="height: 100%;"> | |||
</div> | |||
{{template "base/footer" .}} | |||
<style> | |||
.full.height { | |||
flex-grow: 1; | |||
padding-bottom: 53px; | |||
} | |||
</style> |
@@ -7,7 +7,11 @@ | |||
</div> | |||
</h1> | |||
<p class="am-lh-18">免费私有代码仓库,免费计算资源,大容量数据存储,<br>多类型硬件环境(GPU、NPU),AI开发流水线(开发-调试-训练-迭代)</p> | |||
<a class="circular ui secondary button" href="{{AppSubUrl}}/user/sign_up">立即使用 <i class="right arrow icon"></i></a> | |||
{{if .IsSigned}} | |||
<a class="circular ui secondary button" href="{{AppSubUrl}}/dashboard">立即使用 <i class="right arrow icon"></i></a> | |||
{{else}} | |||
<a class="circular ui secondary button" href="{{AppSubUrl}}/user/login">立即使用 <i class="right arrow icon"></i></a> | |||
{{end}} | |||
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div> | |||
</div> | |||
</div><!-- end segment --> | |||
@@ -38,11 +38,12 @@ | |||
<div class="ui sixteen wide mobile six wide tablet five wide computer column"> | |||
<h4 class="ui top attached header"> | |||
<strong>{{.i18n.Tr "org.people"}}</strong> | |||
{{if .IsOrganizationMember}} | |||
<div class="ui right"> | |||
<a class="text grey" href="{{.OrgLink}}/members">{{.Org.NumMembers}} {{svg "octicon-chevron-right" 16}}</a> | |||
</div> | |||
{{end}} | |||
<div class="ui right"> | |||
<a class="text grey" href="{{.OrgLink}}/members">{{.MembersTotal}} {{svg "octicon-chevron-right" 16}}</a> | |||
</div> | |||
<!-- {{if .IsOrganizationMember}} --> | |||
<!-- {{end}} --> | |||
</h4> | |||
<div class="ui attached segment members"> | |||
{{$isMember := .IsOrganizationMember}} | |||
@@ -3,10 +3,10 @@ | |||
<a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}"> | |||
{{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | |||
</a> | |||
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||
{{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||
</a> | |||
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | |||
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||
{{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||
</a> | |||
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | |||
{{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | |||
</a> | |||
@@ -23,10 +23,10 @@ | |||
{{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | |||
</a> | |||
{{end}} | |||
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||
{{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||
</a> | |||
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | |||
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||
{{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||
</a> | |||
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | |||
{{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | |||
</a> | |||
@@ -2,8 +2,18 @@ | |||
<div class="repository commits"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<h2 class="ui header">{{.DateFrom}} - {{.DateUntil}} | |||
<div class="ui right"> | |||
<div class="ui three column stackable grid" style="align-items: center;"> | |||
<div class="column"> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="active section" href="{{.RepoLink}}/activity">{{.i18n.Tr "repo.activity"}}</div> | |||
</div> | |||
</div> | |||
<div class="column center aligned" style="font-weight: 800;"> | |||
{{.DateFrom}} - {{.DateUntil}} | |||
</div> | |||
<div class="column right aligned"> | |||
<!-- Period --> | |||
<div class="ui floating dropdown jump filter"> | |||
<div class="ui basic compact button"> | |||
@@ -23,7 +33,7 @@ | |||
</div> | |||
</div> | |||
</div> | |||
</h2> | |||
</div> | |||
<div class="ui divider"></div> | |||
{{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}} | |||
@@ -0,0 +1,9 @@ | |||
{{template "base/head" .}} | |||
<div class="repository watchers"> | |||
{{template "repo/header" .}} | |||
<div class="ui container" id="Contributors"> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -92,16 +92,27 @@ | |||
{{if not .Repository.IsBeingCreated}} | |||
<div class="ui tabular stackable menu navbar"> | |||
{{if .Permission.CanRead $.UnitTypeCode}} | |||
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}"> | |||
{{svg "octicon-code" 16}} {{.i18n.Tr "repo.code"}} | |||
<div class="dropdown-menu"> | |||
<a class="{{if or .PageIsViewCode .PageIsReleaseList .PageIsWiki .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}"> | |||
<span>{{svg "octicon-code" 16}} {{.i18n.Tr "repo.code"}} <i class="dropdown icon"></i></span> | |||
</a> | |||
{{end}} | |||
<div class="dropdown-content"> | |||
<a style="border: none;" class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases"> | |||
{{svg "octicon-tag" 16}} {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span> | |||
</a> | |||
<a style="border: none;" class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Permission.CanRead $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}> | |||
{{svg "octicon-book" 16}} {{.i18n.Tr "repo.wiki"}} | |||
</a> | |||
<a style="border: none;" class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity"> | |||
{{svg "octicon-pulse" 16}} {{.i18n.Tr "repo.activity"}} | |||
</a> | |||
{{if .Permission.CanRead $.UnitTypeDatasets}} | |||
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0"> | |||
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}} | |||
</a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{if .Permission.CanRead $.UnitTypeIssues}} | |||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues"> | |||
@@ -109,11 +120,11 @@ | |||
</a> | |||
{{end}} | |||
{{if .Permission.CanRead $.UnitTypeExternalTracker}} | |||
<!-- {{if .Permission.CanRead $.UnitTypeExternalTracker}} | |||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer"> | |||
{{svg "octicon-link-external" 16}} {{.i18n.Tr "repo.issues"}} </span> | |||
</a> | |||
{{end}} | |||
{{end}} --> | |||
{{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}} | |||
<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls"> | |||
@@ -121,35 +132,22 @@ | |||
</a> | |||
{{end}} | |||
{{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo) }} | |||
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases"> | |||
{{svg "octicon-tag" 16}} {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span> | |||
{{if .Permission.CanRead $.UnitTypeDatasets}} | |||
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0"> | |||
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}} | |||
</a> | |||
{{end}} | |||
{{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}} | |||
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Permission.CanRead $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}> | |||
{{svg "octicon-book" 16}} {{.i18n.Tr "repo.wiki"}} | |||
</a> | |||
{{end}} | |||
{{if and (.Permission.CanReadAny $.UnitTypePullRequests $.UnitTypeIssues $.UnitTypeReleases) (not .IsEmptyRepo)}} | |||
<a class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity"> | |||
{{svg "octicon-pulse" 16}} {{.i18n.Tr "repo.activity"}} | |||
</a> | |||
{{end}} | |||
{{if .Permission.CanRead $.UnitTypeCloudBrain}} | |||
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain"> | |||
{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}} | |||
<span>{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}}<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i></span> | |||
</a> | |||
{{end}} | |||
{{if .IsSigned}} | |||
<!-- {{if .IsSigned}} | |||
<a class="{{if .PageIsBlockChain}}active{{end}} item " href="{{.RepoLink}}/blockchain"> | |||
{{svg "octicon-law" 16}} | |||
{{.i18n.Tr "repo.balance"}} | |||
</a> | |||
{{end}} | |||
{{end}} --> | |||
{{template "custom/extra_tabs" .}} | |||
@@ -243,4 +241,9 @@ | |||
window.location.href = repolink + "/datasets?type=" + checked_radio | |||
}) | |||
}) | |||
$('.question.circle.icon').hover(function(){ | |||
$(this).popup('show') | |||
$('.ui.popup.mini.top.center').css({"border-color":'rgba(50, 145, 248, 100)',"color":"rgba(3, 102, 214, 100)","border-radius":"5px"}) | |||
}); | |||
</script> |
@@ -4,7 +4,7 @@ | |||
font-size: 1.0em; | |||
margin-bottom: 1.0rem; | |||
} | |||
#contributorInfo > a:nth-child(n+25){ | |||
#contributorInfo > a:nth-child(n+26){ | |||
display:none; | |||
} | |||
#contributorInfo > a{ | |||
@@ -329,9 +329,15 @@ | |||
<div> | |||
<h4 class="ui header"> | |||
{{$lenCon := len .ContributorInfo}} | |||
{{if lt $lenCon 25 }} | |||
<strong>贡献者 ({{len .ContributorInfo}})</strong> | |||
{{else}} | |||
<strong>贡献者 ({{len .ContributorInfo}}+)</strong> | |||
{{end}} | |||
<div class="ui right"> | |||
<a class="membersmore text grey" href="javascript:;">全部 {{svg "octicon-chevron-right" 16}}</a> | |||
<a class="membersmore text grey" href="{{.RepoLink}}/contributors">全部 {{svg "octicon-chevron-right" 16}}</a> | |||
</div> | |||
</h4> | |||
<div class="ui members" id="contributorInfo"> | |||
@@ -353,10 +359,10 @@ | |||
</div> | |||
<script type="text/javascript"> | |||
$(document).ready(function(){ | |||
$(".membersmore").click(function(){ | |||
$("#contributorInfo > a:nth-child(n+25)").show(); | |||
}); | |||
}); | |||
// $(document).ready(function(){ | |||
// $(".membersmore").click(function(){ | |||
// $("#contributorInfo > a:nth-child(n+25)").show(); | |||
// }); | |||
// }); | |||
</script> | |||
{{template "base/footer" .}} |
@@ -1,485 +0,0 @@ | |||
<!-- 头部导航栏 --> | |||
{{template "base/head" .}} | |||
<style> | |||
.selectcloudbrain .active.item{ | |||
color: #0087f5 !important; | |||
border: 1px solid #0087f5; | |||
margin: -1px; | |||
background: #FFF !important; | |||
} | |||
#deletemodel { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
/* 弹窗 */ | |||
#mask { | |||
position: fixed; | |||
top: 0px; | |||
left: 0px; | |||
right: 0px; | |||
bottom: 0px; | |||
filter: alpha(opacity=60); | |||
background-color: #777; | |||
z-index: 1000; | |||
display: none; | |||
opacity: 0.8; | |||
-moz-opacity: 0.5; | |||
padding-top: 100px; | |||
color: #000000 | |||
} | |||
#loadingPage { | |||
margin: 200px auto; | |||
width: 50px; | |||
height: 40px; | |||
text-align: center; | |||
font-size: 10px; | |||
display: block; | |||
} | |||
#loadingPage>div { | |||
background-color: green; | |||
height: 100%; | |||
width: 6px; | |||
display: inline-block; | |||
-webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||
animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||
} | |||
#loadingPage .rect2 { | |||
-webkit-animation-delay: -1.1s; | |||
animation-delay: -1.1s; | |||
} | |||
#loadingPage .rect3 { | |||
-webkit-animation-delay: -1.0s; | |||
animation-delay: -1.0s; | |||
} | |||
#loadingPage .rect4 { | |||
-webkit-animation-delay: -0.9s; | |||
animation-delay: -0.9s; | |||
} | |||
#loadingPage .rect5 { | |||
-webkit-animation-delay: -0.8s; | |||
animation-delay: -0.8s; | |||
} | |||
@-webkit-keyframes sk-stretchdelay { | |||
0%, | |||
40%, | |||
100% { | |||
-webkit-transform: scaleY(0.4) | |||
} | |||
20% { | |||
-webkit-transform: scaleY(1.0) | |||
} | |||
} | |||
@keyframes sk-stretchdelay { | |||
0%, | |||
40%, | |||
100% { | |||
transform: scaleY(0.4); | |||
-webkit-transform: scaleY(0.4); | |||
} | |||
20% { | |||
transform: scaleY(1.0); | |||
-webkit-transform: scaleY(1.0); | |||
} | |||
} | |||
/* 消息框 */ | |||
.alert { | |||
display: none; | |||
position: fixed; | |||
width: 100%; | |||
z-index: 1001; | |||
padding: 15px; | |||
border: 1px solid transparent; | |||
border-radius: 4px; | |||
text-align: center; | |||
font-weight: bold; | |||
} | |||
.alert-success { | |||
color: #3c763d; | |||
background-color: #dff0d8; | |||
border-color: #d6e9c6; | |||
} | |||
.alert-info { | |||
color: #31708f; | |||
background-color: #d9edf7; | |||
border-color: #bce8f1; | |||
} | |||
.alert-warning { | |||
color: #8a6d3b; | |||
background-color: #fcf8e3; | |||
border-color: #faebcc; | |||
} | |||
.alert-danger { | |||
color: #a94442; | |||
background-color: #f2dede; | |||
border-color: #ebccd1; | |||
} | |||
.pusher { | |||
width: calc(100% - 260px); | |||
box-sizing: border-box; | |||
} | |||
/* 弹窗 (background) */ | |||
#imageModal { | |||
display: none; | |||
position: fixed; | |||
z-index: 1; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
overflow: auto; | |||
background-color: rgb(0, 0, 0); | |||
background-color: rgba(0, 0, 0, 0.4); | |||
} | |||
/* 弹窗内容 */ | |||
.modal-content { | |||
background-color: #fefefe; | |||
margin: 15% auto; | |||
padding: 20px; | |||
border: 1px solid #888; | |||
width: 30%; | |||
} | |||
/* 关闭按钮 */ | |||
.close { | |||
color: #aaa; | |||
float: right; | |||
font-size: 28px; | |||
font-weight: bold; | |||
} | |||
.close:hover, | |||
.close:focus { | |||
color: black; | |||
text-decoration: none; | |||
cursor: pointer; | |||
} | |||
.dis { | |||
margin-bottom: 20px; | |||
} | |||
.disabled { | |||
cursor: pointer; | |||
pointer-events: none; | |||
} | |||
</style> | |||
<!-- 弹窗 --> | |||
<div id="mask"> | |||
<div id="loadingPage"> | |||
<div class="rect1"></div> | |||
<div class="rect2"></div> | |||
<div class="rect3"></div> | |||
<div class="rect4"></div> | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<!-- 提示框 --> | |||
<div class="alert"></div> | |||
<div class="repository release dataset-list view"> | |||
{{template "repo/header" .}} | |||
<!-- 列表容器 --> | |||
<div class="ui container"> | |||
<!-- 中间云脑和新建任务按钮 --> | |||
<div class="ui two column stackable grid "> | |||
<div class="column"> | |||
<div class="ui blue small menu compact selectcloudbrain"> | |||
<a class="active item" href="{{.RepoLink}}/modelarts/notebook">调试任务</a> | |||
<a class="item" href="{{.RepoLink}}/modelarts/train-job">训练任务</a> | |||
</div> | |||
</div> | |||
<div class="column right aligned"> | |||
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||
{{svg "octicon-server" 16}} | |||
<div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div> | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a> | |||
<a class="item" href="{{.RepoLink}}/modelarts" data-value="22">Ascend NPU</a> | |||
</div> | |||
</div> | |||
<a class="ui green button" href="{{.RepoLink}}/modelarts/create">新建调试任务</a> | |||
</div> | |||
</div> | |||
<!-- 中下列表展示区 --> | |||
<div class="ui grid"> | |||
<div class="row"> | |||
<div class="ui sixteen wide column"> | |||
<!-- 排序区 --> | |||
<!-- <div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
</div> | |||
<div class="column right aligned"> | |||
<div class="ui right dropdown type jump item"> | |||
<span class="text"> | |||
{{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||
</span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> --> | |||
<!-- 任务展示 --> | |||
<div class="dataset list"> | |||
<!-- 表头 --> | |||
<div class="ui grid stackable" style="background: #f0f0f0;;"> | |||
<div class="row"> | |||
<div class="five wide column"> | |||
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||
</div> | |||
<div class="three wide column"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_status_createtime"}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||
</div> | |||
<div class="seven wide column text center"> | |||
<span style="margin-left: 10rem;">{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
</div> | |||
</div> | |||
</div> | |||
{{range .Tasks}} | |||
<div class="ui grid stackable item"> | |||
<div class="row"> | |||
<!-- 任务名 --> | |||
<div class="five wide column"> | |||
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 15px;"> | |||
<span class="fitted" style="vertical-align: middle;">{{svg "octicon-tasklist" 16}}</span> | |||
<span class="fitted" style="width: 90%;vertical-align: middle;margin-left: 0.4rem;">{{.JobName}}</span> | |||
</a> | |||
</div> | |||
<div class="three wide column"> | |||
<!--任务状态 --> | |||
<!-- <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
{{.Status}} | |||
</span> --> | |||
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
<span><i style="vertical-align: middle;" class="{{.Status}}"></i><span style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||
</span> | |||
<!-- 任务创建时间 --> | |||
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
{{if .User.Name}} | |||
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||
{{else}} | |||
<a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | |||
{{end}} | |||
</div> | |||
<div class="seven wide column text right"> | |||
<div class="ui compact buttons" style="margin-right:10px;"> | |||
<a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}"> | |||
查看 | |||
</a> | |||
<a class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||
调试 | |||
</a> | |||
<form id="stopForm-{{.JobID}}" action="{{if ne .Status "RUNNING"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/stop{{end}}" method="post" style="margin-left:-1px;"> | |||
{{$.CsrfTokenHtml}} | |||
<a class="ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
停止 | |||
</a> | |||
</form> | |||
</div> | |||
<!-- 删除任务 --> | |||
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if not .CanDel}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
{{$.CsrfTokenHtml}} | |||
<a class="ui compact {{if not .CanDel}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
删除 | |||
</a> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
{{end}} {{template "base/paginate" .}} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 确认模态框 --> | |||
<div id="deletemodel"> | |||
<div class="ui basic modal"> | |||
<div class="ui icon header"> | |||
<i class="trash icon"></i> 删除任务 | |||
</div> | |||
<div class="content"> | |||
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p> | |||
</div> | |||
<div class="actions"> | |||
<div class="ui red basic inverted cancel button"> | |||
<i class="remove icon"></i> 取消操作 | |||
</div> | |||
<div class="ui green basic inverted ok button"> | |||
<i class="checkmark icon"></i> 确定操作 | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
<script> | |||
// 调试和评分新开窗口 | |||
function stop(obj) { | |||
if (obj.style.color != "rgb(204, 204, 204)") { | |||
obj.target = '_blank' | |||
} else { | |||
return | |||
} | |||
} | |||
// 删除时用户确认 | |||
function assertDelete(obj) { | |||
if (obj.style.color == "rgb(204, 204, 204)") { | |||
return | |||
} else { | |||
var delId = obj.parentNode.id | |||
flag = 1; | |||
$('.ui.basic.modal') | |||
.modal({ | |||
onDeny: function() { | |||
flag = false | |||
}, | |||
onApprove: function() { | |||
document.getElementById(delId).submit() | |||
flag = true | |||
}, | |||
onHidden: function() { | |||
if (flag == false) { | |||
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||
} | |||
} | |||
}) | |||
.modal('show') | |||
} | |||
} | |||
// 加载任务状态 | |||
var timeid = window.setInterval(loadJobStatus, 15000); | |||
$(document).ready(loadJobStatus); | |||
function loadJobStatus() { | |||
$(".job-status").each((index, job) => { | |||
const jobID = job.dataset.jobid; | |||
const repoPath = job.dataset.repopath; | |||
if (job.textContent.trim() == 'STOPPED' || job.textContent.trim() == 'START_FAILED' || job.textContent.trim() == 'CREATE_FAILED') { | |||
return | |||
} | |||
$.get(`/api/v1/repos/${repoPath}/modelarts/${jobID}`, (data) => { | |||
const jobID = data.JobID | |||
const status = data.JobStatus | |||
if (status != job.textContent.trim()) { | |||
//$('#' + jobID).text(status) | |||
//if (status == 'STOPPED') { | |||
window.location.reload() | |||
//} | |||
} | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
}); | |||
}; | |||
// 获取弹窗 | |||
var modal = document.getElementById('imageModal'); | |||
// 打开弹窗的按钮对象 | |||
var btns = document.getElementsByClassName("imageBtn"); | |||
// 获取 <span> 元素,用于关闭弹窗 | |||
var spans = document.getElementsByClassName('close'); | |||
// 点击按钮打开弹窗 | |||
for (i = 0; i < btns.length; i++) { | |||
btns[i].onclick = function() { | |||
modal.style.display = "block"; | |||
} | |||
} | |||
// 点击 <span> (x), 关闭弹窗 | |||
for (i = 0; i < spans.length; i++) { | |||
spans[i].onclick = function() { | |||
modal.style.display = "none"; | |||
} | |||
} | |||
// 在用户点击其他地方时,关闭弹窗 | |||
window.onclick = function(event) { | |||
if (event.target == modal) { | |||
modal.style.display = "none"; | |||
} | |||
} | |||
// 显示弹窗,弹出相应的信息 | |||
function showmask() { | |||
$('#imageModal').css('display', 'none') | |||
$('#mask').css('display', 'block') | |||
$("iframe[name=iframeContent]").on("load", function() { | |||
var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; | |||
var json1 = JSON.parse(responseText) | |||
$('#mask').css('display', 'none') | |||
parent.location.href | |||
if (json1.result_code === "0") { | |||
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); | |||
} else { | |||
$('.alert').html(json1.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(5000).fadeOut(); | |||
} | |||
}) | |||
} | |||
</script> |
@@ -1,240 +0,0 @@ | |||
{{template "base/head" .}} | |||
<style> | |||
/* 遮罩层css效果图 */ | |||
#mask { | |||
position: fixed; | |||
top: 0px; | |||
left: 0px; | |||
right: 0px; | |||
bottom: 0px; | |||
filter: alpha(opacity=60); | |||
background-color: #777; | |||
z-index: 1000; | |||
display: none; | |||
opacity: 0.8; | |||
-moz-opacity: 0.5; | |||
padding-top: 100px; | |||
color: #000000 | |||
} | |||
/* 加载圈css效果图 */ | |||
#loadingPage { | |||
margin: 200px auto; | |||
width: 50px; | |||
height: 40px; | |||
text-align: center; | |||
font-size: 10px; | |||
display: block; | |||
} | |||
#loadingPage>div { | |||
background-color: green; | |||
height: 100%; | |||
width: 6px; | |||
display: inline-block; | |||
-webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||
animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||
} | |||
#loadingPage .rect2 { | |||
-webkit-animation-delay: -1.1s; | |||
animation-delay: -1.1s; | |||
} | |||
#loadingPage .rect3 { | |||
-webkit-animation-delay: -1.0s; | |||
animation-delay: -1.0s; | |||
} | |||
#loadingPage .rect4 { | |||
-webkit-animation-delay: -0.9s; | |||
animation-delay: -0.9s; | |||
} | |||
#loadingPage .rect5 { | |||
-webkit-animation-delay: -0.8s; | |||
animation-delay: -0.8s; | |||
} | |||
@-webkit-keyframes sk-stretchdelay { | |||
0%, | |||
40%, | |||
100% { | |||
-webkit-transform: scaleY(0.4) | |||
} | |||
20% { | |||
-webkit-transform: scaleY(1.0) | |||
} | |||
} | |||
@keyframes sk-stretchdelay { | |||
0%, | |||
40%, | |||
100% { | |||
transform: scaleY(0.4); | |||
-webkit-transform: scaleY(0.4); | |||
} | |||
20% { | |||
transform: scaleY(1.0); | |||
-webkit-transform: scaleY(1.0); | |||
} | |||
} | |||
.inline.required.field.cloudbrain_benchmark { | |||
display: none; | |||
} | |||
</style> | |||
<div id="mask"> | |||
<div id="loadingPage"> | |||
<div class="rect1"></div> | |||
<div class="rect2"></div> | |||
<div class="rect3"></div> | |||
<div class="rect4"></div> | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="repository new repo ui middle very relaxed page grid"> | |||
<div class="column"> | |||
{{template "base/alert" .}} | |||
<div class="ui negative message" id="messageInfo"> | |||
<p></p> | |||
</div> | |||
<form class="ui form" id="form_id" action="{{.Link}}" method="post"> | |||
{{.CsrfTokenHtml}} | |||
<h3 class="ui top attached header"> | |||
{{.i18n.Tr "repo.cloudbrain.new"}} | |||
</h3> | |||
<div class="ui attached segment"> | |||
<!-- <br> --> | |||
<div class="inline required field"> | |||
<label>任务名称</label> | |||
<input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="255"> | |||
</div> | |||
<div class="inline field"> | |||
<label>数据集</label> | |||
<input type="text" list="cloudbrain_dataset" placeholder="选择数据集" name="" id="answerInput" autofocus maxlength="36"> | |||
<datalist id="cloudbrain_dataset" class="ui search" style='width:385px' name="attachment"> | |||
{{range .attachments}} | |||
<option name="attachment" data-value="{{.UUID}}">{{.Attachment.Name}}</option> | |||
{{end}} | |||
</datalist> | |||
<input type="hidden" name="attachment" id="answerInput-hidden"> | |||
</div> | |||
<div class="inline required field"> | |||
<label>工作环境</label> | |||
<input name="de" id="cloudbrain_de" value="{{.env}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
</div> | |||
<div class="inline required field"> | |||
<label>类型</label> | |||
<input name="job_type" id="cloudbrain_job_type" value="{{.notebook_type}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
</div> | |||
<div class="inline required field"> | |||
<label>规格</label> | |||
<select id="cloudbrain_flavor" class="ui search dropdown" placeholder="选择规格" style='width:385px' name="flavor"> | |||
{{range .flavors}} | |||
<option name="flavor" value="{{.Value}}">{{.Value}}</option> | |||
{{end}} | |||
</select> | |||
</div> | |||
<div class="inline required field"> | |||
<label>数据集存放路径</label> | |||
<input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
</div> | |||
<div class="inline field"> | |||
<label>描述</label> | |||
<input name="description" id="cloudbrain_description" tabindex="3" autofocus maxlength="255"> | |||
</div> | |||
<div class="inline field"> | |||
<label></label> | |||
<button class="ui green button"> | |||
{{.i18n.Tr "repo.cloudbrain.new"}} | |||
</button> | |||
<a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
<script> | |||
// 取消创建跳转 | |||
let url_href = window.location.pathname.split('create')[0] | |||
$(".ui.button").attr('href',url_href) | |||
// 判断必填选项是否填写正确 | |||
let form = document.getElementById('form_id'); | |||
$('#messageInfo').css('display','none') | |||
form.onsubmit = function(e){ | |||
let value_task = $("input[name='job_name']").val() | |||
let re = /^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/ | |||
let flag = re.test(value_task) | |||
if(!flag){ | |||
$('#messageInfo').css('display','block') | |||
let str = '只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。' | |||
$('#messageInfo p').text(str) | |||
return false | |||
} | |||
let min_value_task = value_task.toLowerCase() | |||
$("input[name='job_name']").attr("value",min_value_task) | |||
document.getElementById("mask").style.display = "block" | |||
} | |||
// 点击按钮后遮罩层显示 | |||
// function showmask() { | |||
// document.getElementById("mask").style.display = "block" | |||
// } | |||
// 页面加载完毕后遮罩层隐藏 | |||
document.onreadystatechange = function() { | |||
if (document.readyState === "complete") { | |||
document.getElementById("mask").style.display = "none" | |||
} | |||
} | |||
$('select.dropdown') | |||
.dropdown(); | |||
$(function() { | |||
$("#cloudbrain_job_type").change(function() { | |||
if ($(this).val() == 'BENCHMARK') { | |||
$(".cloudbrain_benchmark").show(); | |||
} else { | |||
$(".cloudbrain_benchmark").hide(); | |||
} | |||
}) | |||
}) | |||
document.querySelector('input[list]').addEventListener('input',function(e){ | |||
var input = e.target, | |||
list = input.getAttribute('list'), | |||
options = document.querySelectorAll('#'+list+' option'), | |||
hiddenInput = document.getElementById(input.getAttribute('id')+'-hidden'), | |||
inputValue = input.value; | |||
hiddenInput.value = inputValue; | |||
for (let i=0;i<options.length;i++){ | |||
var option = options[i] | |||
if(option.innerText===inputValue){ | |||
hiddenInput.value = option.getAttribute('data-value'); | |||
break | |||
} | |||
} | |||
}) | |||
</script> |
@@ -138,7 +138,7 @@ | |||
<label>规格</label> | |||
<select id="cloudbrain_flavor" class="ui search dropdown" placeholder="选择规格" style='width:385px' name="flavor"> | |||
{{range .flavors}} | |||
<option name="flavor" value="{{.Value}}">{{.Value}}</option> | |||
<option name="flavor" value="{{.Value}}">{{.Desc}}</option> | |||
{{end}} | |||
</select> | |||
@@ -1,122 +0,0 @@ | |||
{{template "base/head" .}} | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="repository new repo ui middle very relaxed page grid"> | |||
<div class="column"> | |||
{{template "base/alert" .}} | |||
<h4 class="ui header" id="vertical-segment"> | |||
<a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> | |||
</h4> | |||
<div> | |||
<div class="ui yellow segment"> | |||
{{with .task}} | |||
<p>任务名称: {{.JobName}}</p> | |||
{{end}} | |||
</div> | |||
<div class="ui green segment"> | |||
<p>任务结果:</p> | |||
{{with .result}} | |||
<table class="ui celled striped table"> | |||
<tbody> | |||
<tr> | |||
<td class="four wide"> 状态 </td> | |||
<td> {{.Status}} </td> | |||
</tr> | |||
<tr> | |||
<td> 开始时间 </td> | |||
<td>{{.CreateTime}}</td> | |||
</tr> | |||
<tr> | |||
<td> 最后更新时间 </td> | |||
<td>{{.LatestUpdateTime}}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
{{end}} | |||
</div> | |||
<div class="ui blue segment"> | |||
{{with .result}} | |||
<table class="ui celled striped table"> | |||
<thead> | |||
<tr> <th colspan="2"> 配置信息 </th> </tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td class="four wide"> 开发环境类型 </td> | |||
<td>{{.Profile.DeType}}</td> | |||
</tr> | |||
<tr> | |||
<td> 硬件类型 </td> | |||
<td>{{.Profile.FlavorType}}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<table class="ui celled striped table"> | |||
<thead> | |||
<tr> <th colspan="2"> 机器规格详情 </th> </tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td class="four wide"> 机器规格 </td> | |||
<td> {{.Flavor}} </td> | |||
</tr> | |||
<tr> | |||
<td> 规格名称 </td> | |||
<td>{{.FlavorDetails.Name}}</td> | |||
</tr> | |||
<tr> | |||
<td> 规格销售状态 </td> | |||
<td>{{.FlavorDetails.Status}}</td> | |||
</tr> | |||
<tr> | |||
<td> 排队个数 </td> | |||
<td>{{.FlavorDetails.QueuingNum}}</td> | |||
</tr> | |||
<tr> | |||
<td> 排到队的剩余时间(秒) </td> | |||
<td>{{.FlavorDetails.QueueLeftTime}}</td> | |||
</tr> | |||
<tr> | |||
<td> 自动停止时间(秒) </td> | |||
<td>{{.FlavorDetails.Duration}}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<table class="ui celled striped table" {{if eq .QueuingInfo.RemainTime 0}}hidden{{end}}> | |||
<thead> | |||
<tr> <th colspan="2"> 排队信息 </th> </tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td> 实例状态 </td> | |||
<td>{{.QueuingInfo.Status}}</td> | |||
</tr> | |||
<tr> | |||
<td> 实例排队的开始时间 </td> | |||
<td>{{.QueuingInfo.BeginTime}}</td> | |||
</tr> | |||
<tr> | |||
<td> 排到队的剩余时间(秒) </td> | |||
<td>{{.QueuingInfo.RemainTime}}</td> | |||
</tr> | |||
<tr> | |||
<td> 实例排队的预计停止时间 </td> | |||
<td>{{.QueuingInfo.EndTime}}</td> | |||
</tr> | |||
<tr> | |||
<td> 实例在队列中的排位 </td> | |||
<td>{{.QueuingInfo.Rank}}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
{{end}} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -4,7 +4,11 @@ | |||
<div class="ui container"> | |||
{{template "base/alert" .}} | |||
<h2 class="ui header"> | |||
{{.i18n.Tr "repo.release.releases"}} | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="active section" href="{{.RepoLink}}/releases">{{.i18n.Tr "repo.releases"}}</div> | |||
</div> | |||
{{if .CanCreateRelease}} | |||
<div class="ui right"> | |||
<a class="ui small green button" href="{{$.RepoLink}}/releases/new"> | |||
@@ -34,6 +34,21 @@ | |||
</div> | |||
{{end}} | |||
</div> | |||
{{if .ReadmeInList}} | |||
<div class="file-header-right"> | |||
<div class="ui right file-actions"> | |||
{{if .Repository.CanEnableEditor}} | |||
{{if .CanEditFile}} | |||
<a href="{{.RepoLink}}/_edit/{{EscapePound .BranchName}}/{{EscapePound .ReadmeName}}"><span class="btn-octicon poping up" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span></a> | |||
{{else}} | |||
<span class="btn-octicon poping up disabled" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span> | |||
{{end}} | |||
{{end}} | |||
</div> | |||
</div> | |||
{{end}} | |||
{{if not .ReadmeInList}} | |||
<div class="file-header-right"> | |||
<div class="ui right file-actions"> | |||
@@ -2,6 +2,13 @@ | |||
<div class="repository wiki start"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<h2 class="ui header"> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="active section" href="{{.RepoLink}}/wiki">{{.i18n.Tr "repo.wiki"}}</div> | |||
</div> | |||
</h2> | |||
<div class="ui center segment"> | |||
{{svg "octicon-book" 32}} | |||
<h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2> | |||
@@ -3,6 +3,14 @@ | |||
{{template "repo/header" .}} | |||
{{ $title := .title}} | |||
<div class="ui container"> | |||
<h2 class="ui header"> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="active section" href="{{.RepoLink}}/wiki">{{.i18n.Tr "repo.wiki"}}</div> | |||
</div> | |||
</h2> | |||
<div class="ui divider"></div> | |||
<div class="ui stackable grid"> | |||
<div class="ui ten wide column"> | |||
<div class="choose page"> | |||
@@ -28,7 +36,7 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui six wide column"> | |||
<div class="ui six wide column right aligned"> | |||
<div class="ui action small input" id="clone-panel"> | |||
{{if not $.DisableHTTP}} | |||
<button class="ui basic clone button" id="repo-clone-https" data-link="{{.WikiCloneLink.HTTPS}}"> | |||
@@ -0,0 +1,109 @@ | |||
<template> | |||
<div class="ui container"> | |||
<div class="row git-user-content"> | |||
<h3 class="ui header"> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="/">代码</a> | |||
<div class="divider"> / </div> | |||
<div class="active section" >贡献者({{totalNum}})</div> | |||
</div> | |||
</h3> | |||
<div class="ui horizontal relaxed list"> | |||
<div class="item user-list-item" v-for="(contributor,i) in contributors_list_page" > | |||
<a v-if="contributor.user_name" :href="AppSubUrl +'/'+ contributor.user_name"><img class="ui avatar s16 image js-popover-card" :src="contributor.rel_avatar_link"></a> | |||
<a v-else :href="'mailto:' + contributor.email "><img class="ui avatar s16 image js-popover-card" :avatar="contributor.email"></a> | |||
<div class="content"> | |||
<div class="header" > | |||
<a v-if="contributor.user_name" :href="AppSubUrl +'/'+ contributor.user_name">{{contributor.user_name}}</a> | |||
<a v-else :href="'mailto:' + contributor.email ">{{contributor.email}}</a> | |||
</div> | |||
<span class="commit-btn">Commits: {{contributor.commit_cnt}}</span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui container" style="margin-top:50px;text-align:center"> | |||
<el-pagination | |||
background | |||
@current-change="handleCurrentChange" | |||
:current-page="currentPage" | |||
:page-size="pageSize" | |||
layout="total, prev, pager, next" | |||
:total="totalNum"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||
export default { | |||
data() { | |||
return { | |||
url:'', | |||
contributors_list:[], | |||
contributors_list_page:[], | |||
currentPage:1, | |||
pageSize:50, | |||
totalNum:0, | |||
AppSubUrl:AppSubUrl | |||
}; | |||
}, | |||
methods: { | |||
getContributorsList(){ | |||
this.$axios.get(this.url+'/contributors/list').then((res)=>{ | |||
this.contributors_list = res.data.contributor_info | |||
this.totalNum = this.contributors_list.length | |||
this.contributors_list_page = this.contributors_list.slice(0,this.pageSize) | |||
}) | |||
}, | |||
handleCurrentChange(val){ | |||
this.contributors_list_page = this.contributors_list.slice((val-1)*this.pageSize,val*this.pageSize) | |||
}, | |||
}, | |||
computed:{ | |||
}, | |||
watch: { | |||
}, | |||
created(){ | |||
this.url=document.head.querySelector("[property~='og:url'][content]").content | |||
this.getContributorsList() | |||
}, | |||
updated(){ | |||
if(document.querySelectorAll('img[avatar]').length!==0){ | |||
window.LetterAvatar.transform() | |||
} | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
/deep/ .el-pagination.is-background .el-pager li:not(.disabled).active { | |||
background-color: #5bb973; | |||
color: #FFF; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li.active { | |||
color: #fff; | |||
cursor: default; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:hover { | |||
color: #5bb973; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover { | |||
color: #5bb973; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover { | |||
background-color: #5bb973; | |||
color: #FFF; | |||
} | |||
</style> |
@@ -0,0 +1,123 @@ | |||
<template> | |||
<div style="height:100%"> | |||
<el-tabs tab-position="left" v-model="activeName" style="height:100%" @tab-click="handleClick" > | |||
<el-tab-pane label="概览" name="first" > | |||
<span slot="label"> | |||
<el-image style="width: 13px; height: 13px" src="/img/overview.png"> | |||
</el-image> | |||
概览 | |||
</span> | |||
<div >概览.......</div> | |||
<div >概览.......</div> | |||
<div >概览.......</div><div >概览.......</div> | |||
<div >概览.......</div> | |||
</el-tab-pane> | |||
<el-tab-pane label="项目分析" name="second" id="second" > | |||
<ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis> | |||
<span slot="label"> | |||
<el-image style="width: 13px; height: 13px" src="/img/pro.svg"> | |||
</el-image> | |||
项目分析 | |||
</span> | |||
</el-tab-pane> | |||
<el-tab-pane name="third" > | |||
<span slot='label'> | |||
<el-image style="width: 13px; height: 13px" src="/img/name.png"> | |||
</el-image> | |||
用户分析 | |||
</span> | |||
<UserAnalysis ref='UserAnalysis' id ="usr"></UserAnalysis> | |||
</el-tab-pane> | |||
</el-tabs> | |||
</div> | |||
</template> | |||
<script> | |||
import ProAnalysis from './ProAnalysis.vue' | |||
import UserAnalysis from './UserAnalysis.vue' | |||
export default { | |||
components:{ | |||
'ProAnalysis':ProAnalysis, | |||
'UserAnalysis':UserAnalysis, | |||
}, | |||
data() { | |||
return { | |||
activeName:"second", | |||
loading:true, | |||
loading1:true, | |||
isRouterAlive: true, | |||
isSecond:true, | |||
isThird:false, | |||
} | |||
}, | |||
methods:{ | |||
handleClick(tab, event){ | |||
if(tab.name=="second"){ | |||
this.reload() | |||
//document.getElementById('usr').style.display="none" | |||
//document.getElementById("pro").style.display='block' | |||
//this.$refs.ProAnalysis.getAllProList("all",7) | |||
this.isSecond = true | |||
this.isThird = false | |||
this.$refs.ProAnalysis.getAllProList("all",7) | |||
} | |||
if(tab.name=="third"){ | |||
// document.getElementById('usr').style.display="block" | |||
// document.getElementById("pro").style.display='none' | |||
//this.$refs.UserAnalysis.getUserList("all_usr",7) | |||
this.isSecond = false | |||
this.isThird = true | |||
} | |||
}, | |||
reload () { | |||
this.isRouterAlive = false | |||
this.$nextTick(() => (this.isRouterAlive = true)) | |||
} | |||
}, | |||
} | |||
</script> | |||
<style scoped> | |||
/deep/ .is-active{ | |||
color: #238BFC ; | |||
background-color: #FFFF ; | |||
} | |||
/deep/ .ui-container{ | |||
background-color: #FFFF; | |||
} | |||
/deep/ .el-tabs--left .el-tabs__header.is-left{ | |||
background-color:#F5F5F6; | |||
width: 12.43%; | |||
} | |||
.el-tabs--left .el-tabs__header.is-left | |||
html, | |||
body, | |||
/deep/ .el-container { | |||
padding: 0px; | |||
margin: 0px; | |||
height: 100%; | |||
} | |||
/deep/ .el-tabs--left .el-tabs__item.is-left { | |||
text-align: left; | |||
} | |||
/deep/ .el-tabs__item { | |||
padding: 0px 20px 0px 20px; | |||
} | |||
</style> |
@@ -1,9 +1,9 @@ | |||
<template> | |||
<div> | |||
<h4 id="about-desc" class="ui header">简介 | |||
<!-- <a class="edit-icon" href="javascript:void(0)" @click="editClick"> | |||
<i class="gray edit outline icon"></i> | |||
</a> --> | |||
<h4 id="about-desc" class="ui header desc-home">简介 | |||
<a class="edit-icon" href="javascript:void(0)" @click="editClick"> | |||
<i class="gray edit outline icon" style="margin-right: 0;"></i> | |||
</a> | |||
</h4> | |||
<edit-dialog-cmpt | |||
:vmContext="vmContext" | |||
@@ -11,8 +11,8 @@ | |||
v-model="editDataDialog" | |||
:deleteCallback="editDataFunc" | |||
:deleteLoading ="editDataListLoading" | |||
deleteParam = "ruleForm" | |||
@input="initForm" | |||
deleteParam = "ruleForm" | |||
@input="initForm" | |||
> | |||
<div slot="title"> | |||
@@ -20,7 +20,7 @@ | |||
<div slot="content"> | |||
<el-form label-position="top" :model="info" :rules="rule" ref="ruleForm"> | |||
<el-form-item label="简介" prop="desc"> | |||
<el-input v-model="info.desc" type="textarea" :autosize="{minRows:2,maxRows:6}"></el-input> | |||
<el-input v-model="info.desc" type="textarea" placeholder="请输入内容" :autosize="{minRows:4,maxRows:6}" maxlength="255" show-word-limit></el-input> | |||
</el-form-item> | |||
<el-form-item label="主页" prop="index_web" > | |||
<el-input v-model="info.index_web" placeholder="主页(eg: https://git.openi.org.cn)"></el-input> | |||
@@ -70,7 +70,7 @@ export default { | |||
this.info.desc = el; | |||
}, | |||
getWeb() { | |||
const el = $('a.link').text(); | |||
const el = $('a.link.edit-link').text(); | |||
this.info.index_web = el; | |||
}, | |||
getRepoName() { | |||
@@ -79,7 +79,6 @@ export default { | |||
}, | |||
initForm(diaolog) { | |||
if (diaolog === false) { | |||
console.log("--watch----------") | |||
this.getRepoName(); | |||
this.getDesc(); | |||
this.getWeb(); | |||
@@ -133,12 +132,11 @@ export default { | |||
<style scoped> | |||
.edit-icon{ | |||
float: right; | |||
font-size: 16px; | |||
display: block; | |||
top: -2px; | |||
color: #8c92a4; | |||
background-color: transparent; | |||
} | |||
} | |||
.desc-home{ | |||
display: flex; | |||
justify-content: space-between; | |||
} | |||
</style> |
@@ -0,0 +1,923 @@ | |||
<template> | |||
<div style="width: 100%;"> | |||
<div id = "pro_main"> | |||
<div style="margin-top: 10px;"> | |||
<b class="pro_item">项目分析</b> <span class="update_time">数据更新时间:{{lastUpdatedTime}}/{{recordBeginTime}}</span> | |||
</div> | |||
<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="getAllProList('yesterday',1)">昨天</button> | |||
<button type="button" class='btn' id = "current_week" v-bind:class="{colorChange:2==dynamic}" @click="getAllProList('current_week',2)">本周</button> | |||
<button type="button" class='btn' id = "current_month" v-bind:class="{colorChange:3==dynamic}" @click="getAllProList('current_month',3)">本月</button> | |||
<button type="button" class='btn' id = "last_month" v-bind:class="{colorChange:4==dynamic}" @click="getAllProList('last_month',4)">上月</button> | |||
<button type="button" class='btn' id = "monthly" v-bind:class="{colorChange:5==dynamic}" @click="getAllProList('monthly',5)">近30天</button> | |||
<button type="button" class='btn' id = "current_year" v-bind:class="{colorChange:6==dynamic}" @click="getAllProList('current_year',6)">今年</button> | |||
<button type="button" class='btn' id = "all" v-bind:class="{colorChange:7==dynamic}" @click="getAllProList('all',7)">所有</button> | |||
<span style="margin-left: 20px;"> | |||
<el-date-picker | |||
v-model="value_time" | |||
prefix-icon="el-icon-time" | |||
@change="getAllProList('',0)" | |||
type="daterange" | |||
size='small' | |||
range-separator="至" | |||
start-placeholder="开始日期" | |||
end-placeholder="结束日期"> | |||
</el-date-picker> | |||
</span> | |||
<span style="float:right; margin-right: 20px;"> | |||
<div style="display:inline-block;margin-left: 20px; "> | |||
<i class="el-icon-download"></i> | |||
<span ><a>下载报告</a> </span> | |||
</div> | |||
<span style="display:inline-block;margin-left: 20px; "> | |||
<el-input size="small" placeholder="输入项目关键字搜索" v-model="search" class="input-with-select" @keyup.enter.native="searchName() "><i slot="suffix" class="el-input__icon el-icon-search"></i> | |||
</el-input> | |||
</span> | |||
</span> | |||
</div> | |||
<div style="margin-top: 30px;"> | |||
<el-table | |||
:data="tableData" | |||
style="width: 100%" | |||
:header-cell-style="tableHeaderStyle" | |||
:cell-style='cellStyle'> | |||
<el-table-column | |||
label="ID" | |||
align="center" | |||
prop="repo_id" | |||
stripe | |||
> | |||
</el-table-column> | |||
<el-table-column | |||
label="项目名称" | |||
width="125px" | |||
align="center" | |||
prop="name" | |||
style="color:#0366D6 100%;" | |||
> | |||
<template slot-scope="scope"> | |||
<a @click=goToDetailPage(scope.row.repo_id,scope.row.name)>{{scope.row.name}} </a> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="isPrivate" | |||
label="私有" | |||
align="center"> | |||
<template slot-scope="scope"> | |||
{{scope.row.isPrivate|changeType}} | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="openi" | |||
label="OpenI指数" | |||
align="center"> | |||
<template slot-scope="scope"> | |||
{{scope.row.openi | rounding}} | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="view" | |||
label="浏览量" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="download" | |||
label="代码下载量" | |||
align="center"> | |||
</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-column | |||
prop="watch" | |||
label="关注数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="star" | |||
label="点赞数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="fork" | |||
label="派生数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="issue" | |||
label="任务数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="issueClosed" | |||
label="已解决任务" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="contributor" | |||
label="贡献者数" | |||
align="center"> | |||
</el-table-column> | |||
</el-table> | |||
</div> | |||
<div style="margin-top:50px;text-align:center"> | |||
<el-pagination | |||
background | |||
@current-change="handleCurrentChange" | |||
:current-page="page" | |||
:page-size="pageSize" | |||
layout="prev, pager, next" | |||
:total="totalNum"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
<div id ="pro_detail" style="display:none;width: 100%;"> | |||
<div style="margin-top: 10px;"> | |||
<b class="pro_item">OpenI / {{this.pro_name}}</b> <span class="update_time">数据更新时间:{{tableDataIDTotal.lastUpdatedTime}}/{{tableDataIDTotal.recordBeginTime}}</span> | |||
</div> | |||
<div style="margin-top: 10px;"> | |||
项目描述:{{tableDataIDTotal.description | discriptionFun}} | |||
</div> | |||
<div style="margin-top:20px"> | |||
<el-row > | |||
<el-col :span='4' class="items"> | |||
项目创建时间 </br> | |||
{{tableDataIDTotal.creatTime}} | |||
</el-col> | |||
<el-col :span='4' class="items"> | |||
OPenI指数 </br> | |||
{{tableDataIDTotal.openi | rounding}} | |||
</el-col> | |||
<el-col :span='4' class="items"> | |||
评论数 </br> | |||
{{tableDataIDTotal.comment}} | |||
</el-col> | |||
<el-col :span='4' class="items"> | |||
浏览数 </br> | |||
{{tableDataIDTotal.view}} | |||
</el-col> | |||
<el-col :span='4' class="items"> | |||
代码下载量 </br> | |||
{{tableDataIDTotal.download}} | |||
</el-col> | |||
<el-col :span='4' style="text-align: center;"> | |||
任务完成比例 </br> | |||
{{tableDataIDTotal.issueClosedRatio}} | |||
</el-col> | |||
</el-row> | |||
</div> | |||
<div style="margin-top:30px;"> | |||
<el-row :gutter="20"> | |||
<el-col :span=18 > | |||
<div class="item_l" id="charts"> | |||
<div style="font-size:14px;color:#409eff;margin:20px 5px;">OpenI指数:{{tableDataIDTotal.openi | rounding}}</div> | |||
<div > | |||
<el-col :span='8' id="radar_openi" :style="{width: '400px', height: '300px'}"></el-col> | |||
<el-col :span='16' id="line_openi" :style="{width: '600px', height: '300px',float:'right'}"></el-col> | |||
</div> | |||
</div> | |||
</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="center" | |||
prop="user"> | |||
</el-table-column> | |||
<el-table-column | |||
label="身份" | |||
align="center" | |||
prop="mode"> | |||
<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> | |||
</el-col> | |||
</el-row> | |||
</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="getOneProList(pro_id,'yesterday',true,1),getOneProList(pro_id,'yesterday',false,1)">昨天</button> | |||
<button type="button" class='btn' id = "current_week_pro" v-bind:class="{colorChange:2==dynamic_pro}" @click="getOneProList(pro_id,'current_week',true,2),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="getOneProList(pro_id,'current_month',true,3),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="getOneProList(pro_id,'last_month',true,4),getOneProList(pro_id,'last_month',false,4)">上月</button> | |||
<button type="button" class='btn' id = "monthly_pro" v-bind:class="{colorChange:5==dynamic_pro}" @click="getOneProList(pro_id,'monthly',true,5),getOneProList(pro_id,'monthly',false,5)">近30天</button> | |||
<button type="button" class='btn' id = "current_year_pro" v-bind:class="{colorChange:6==dynamic}" @click="getOneProList(pro_id,'current_year',true,6),getOneProList(pro_id,'current_year',false,6)">今年</button> | |||
<button type="button" class='btn' id = "all_pro" v-bind:class="{colorChange:7==dynamic_pro}" @click="getOneProList(pro_id,'all',true,7),getOneProList(pro_id,'all',false,7)">所有</button> | |||
<span style="margin-left: 20px;"> | |||
<el-date-picker | |||
v-model="create_time_pro" | |||
prefix-icon="el-icon-time" | |||
@change="getOneProList(pro_id,'',true,0),getOneProList(pro_id,'',false,0)" | |||
type="daterange" | |||
size='small' | |||
range-separator="至" | |||
start-placeholder="开始日期" | |||
end-placeholder="结束日期"> | |||
</el-date-picker> | |||
</span> | |||
<span style="float:right; margin-right: 20px;"> | |||
<div style="display:inline-block;margin-left: 20px; "> | |||
<i class="el-icon-download"></i> | |||
<span ><a>下载报告</a> </span> | |||
</div> | |||
</span> | |||
</div> | |||
<div class="item_echart" id ='linecharts'> | |||
<div style="margin-top:10px;margin-left: 5px;"> | |||
<label for="label" @change='clickCheckBox'> | |||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="浏览量"/>浏览量 | |||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="下载量"/>下载量 | |||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="commit"/>commit | |||
</label> | |||
</div> | |||
<div id ="selectData" style="width: 1280px;height: 300px;"> | |||
</div> | |||
</div> | |||
<div style="margin-top: 30px;"> | |||
<el-table | |||
:data="tableDataID.slice((currentPage-1)*pageSize,currentPage*pageSize)" | |||
style="width: 100%" | |||
:header-cell-style="tableHeaderStyle" | |||
:cell-style='cellStyle'> | |||
<el-table-column | |||
label="日期" | |||
align="center" | |||
prop="date" | |||
stripe | |||
> | |||
</el-table-column> | |||
<el-table-column | |||
label="浏览量" | |||
align="center" | |||
prop="view"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="download" | |||
label="下载量" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="commit" | |||
label="commit" | |||
align="center"> | |||
</el-table-column> | |||
</el-table> | |||
</div> | |||
<div style="margin-top:50px;text-align:center"> | |||
<el-pagination | |||
background | |||
@current-change="handleCurrentChangeID" | |||
:current-page="currentPage" | |||
:page-size="pageSize1" | |||
layout="prev, pager, next" | |||
:total="tableDataID.length"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
// import barLabel from './basic/barLabel.vue'; | |||
export default{ | |||
name:'ProAnalysis', | |||
components: { | |||
// barLabel, | |||
}, | |||
data() { | |||
return { | |||
recordBeginTime:'', | |||
lastUpdatedTime:'', | |||
page:1, | |||
pageSize:10, | |||
params:{type:'all',page:1,pagesize:10,beginTime:'',endTime:'',q:'',sort:'openi'}, | |||
tableData: [], | |||
totalPage:0, | |||
totalNum:0, | |||
pickerOptions: { | |||
}, | |||
value_time: '', | |||
search:'', | |||
dynamic:7, | |||
//单个项目参数 | |||
currentPage:1, | |||
pageSize1:10, | |||
paramsID:{type:'all' ,beginTime:'',endTime:'',openi:'false'}, | |||
tableDataIDTotal: [], | |||
tableDataID: [], | |||
tableDataIDOpenI:[], | |||
tableDataContTop10:[], | |||
create_time_pro: '', | |||
dynamic_pro:7, | |||
pro_name:'', | |||
pro_id:'', | |||
radarOpenI:'', | |||
echartsOITd:'', | |||
echartsSelectData:'', | |||
option:'', | |||
}; | |||
}, | |||
methods: { | |||
handleCurrentChange(val){ | |||
console.log(val) | |||
this.params.page = val | |||
switch(this.params.type){ | |||
case "yesterday":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,1) | |||
break | |||
} | |||
case "current_week":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,2) | |||
break | |||
} | |||
case "current_month":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,3) | |||
break | |||
} | |||
case "last_month":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,4) | |||
break | |||
} | |||
case "monthly":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,5) | |||
break | |||
} | |||
case "current_year":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,6) | |||
break | |||
} | |||
case "all":{ | |||
this.value_time='' | |||
this.getAllProList(this.params.type,7) | |||
break | |||
} | |||
case "":{ | |||
// this.value_time='' | |||
this.getAllProList(this.params.type,0) | |||
break | |||
} | |||
} | |||
}, | |||
formatDate(myyear,mymonth,myweekday) { | |||
// var myyear = this.date.getFullYear(); | |||
// var mymonth = this.date.getMonth() + 1; | |||
// var myweekday = this.date.getDate(); | |||
if (mymonth < 10) { | |||
mymonth = "0" + mymonth; | |||
} | |||
if (myweekday < 10) { | |||
myweekday = "0" + myweekday; | |||
} | |||
return (myyear + "-" + mymonth + "-" + myweekday); | |||
}, | |||
getAllProList(type_val,index){ | |||
console.log("类型:"+type_val) | |||
this.dynamic = index | |||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | |||
this.params.type='' | |||
this.params.beginTime=this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate()) | |||
this.params.endTime=this.formatDate(this.value_time[1].getFullYear(),this.value_time[1].getMonth() + 1,this.value_time[1].getDate()) | |||
}else{ | |||
this.params.type=type_val | |||
this.params.beginTime='' | |||
this.params.endTime='' | |||
this.value_time=[] | |||
} | |||
this.$axios.get('../api/v1/projectboard/project',{ | |||
params:this.params | |||
}).then((res)=>{ | |||
this.recordBeginTime=res.data.recordBeginTime | |||
this.lastUpdatedTime=res.data.lastUpdatedTime | |||
this.tableData = res.data.pageRecords | |||
this.totalPage=res.data.totalPage | |||
this.totalNum = this.totalPage*this.params.pagesize | |||
console.log("this.totalPage:"+this.totalPage) | |||
}) | |||
}, | |||
searchName(){ | |||
this.params.q = this.search | |||
this.params.page = 1 | |||
this.getAllProList("all",7) | |||
}, | |||
goToDetailPage(pro_id,pro_name){ | |||
document.getElementById("pro_main").style.display="none"; | |||
document.getElementById("pro_detail").style.display="block"; | |||
console.log(pro_id) | |||
console.log(pro_name) | |||
this.pro_name=pro_name; | |||
this.pro_id=pro_id; | |||
this.getOneProData(pro_id); | |||
this.getOneProList(pro_id,"monthly",true,5); | |||
this.getOneProList(pro_id,"monthly",false,5); | |||
}, | |||
tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
if(rowIndex===0){ | |||
return 'background:#f5f5f6;color:#606266' | |||
} | |||
}, | |||
cellStyle({row,column,rowIndex,columnIndex}){ | |||
if(rowIndex%2 === 1){ | |||
return 'background:#f5f5f6;color:#606266' | |||
} | |||
}, | |||
handleCurrentChangeID(currentPage){ | |||
this.currentPage = currentPage; | |||
}, | |||
getOneProData(pro_id){ | |||
this.$axios.get('../api/v1/projectboard/project/'+pro_id,{ | |||
}).then((res)=>{ | |||
this.tableDataIDTotal = res.data | |||
this.tableDataContTop10=res.data.top10 | |||
// this.drawLine() | |||
this.drawRadarOpenI() | |||
}) | |||
}, | |||
getOneProList(pro_id,type_val,bool_val,index){ | |||
this.dynamic_pro=index | |||
console.log("日期类型:"+type_val) | |||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | |||
this.paramsID.type='' | |||
this.paramsID.beginTime= this.formatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate()) | |||
this.paramsID.endTime=this.formatDate(this.create_time_pro[1].getFullYear(),this.create_time_pro[1].getMonth() + 1,this.create_time_pro[1].getDate()) | |||
}else{ | |||
this.create_time_pro=[] | |||
this.paramsID.type=type_val | |||
this.paramsID.beginTime='' | |||
this.paramsID.endTime='' | |||
} | |||
this.paramsID.openi=bool_val | |||
this.$axios.get('../api/v1/projectboard/project/'+pro_id+"/period",{ | |||
params:this.paramsID | |||
}).then((res)=>{ | |||
if (bool_val){ | |||
this.tableDataIDOpenI = res.data | |||
this.drawOpenItrend() | |||
}else{ | |||
this.tableDataID = res.data | |||
this.drawSelectData() | |||
} | |||
}) | |||
}, | |||
drawRadarOpenI(){ | |||
var ydata = [this.roundingF(this.tableDataIDTotal.impact),this.roundingF(this.tableDataIDTotal.completeness),this.roundingF(this.tableDataIDTotal.liveness),this.tableDataIDTotal.projectHealth,this.roundingF(this.tableDataIDTotal.teamHealth),this.roundingF(this.tableDataIDTotal.growth)] | |||
console.log("ydata:",ydata) | |||
var i = -1; | |||
var option = { | |||
titile:{ | |||
text:"" | |||
}, | |||
tooltip: { | |||
trigger: 'item', | |||
backgroundColor:'rgba(255,255,255,0.8)', | |||
color:'black', | |||
borderWidth:'1', | |||
borderColor:'gray', | |||
textStyle:{ | |||
color:'black' | |||
}, | |||
position: 'right' | |||
},//提示层 | |||
legend: { | |||
data: ['name1'] | |||
}, | |||
radar: { | |||
name: { | |||
textStyle: { | |||
color: 'rgb(0,0,0)', //字体颜色 | |||
borderRadius: 3, //圆角 | |||
padding: [3, 5] //padding | |||
} | |||
}, | |||
slpitNumber:5, | |||
center: ['50%', '50%'], | |||
indicator: [{ | |||
name: '社区影响力', | |||
max: 100 | |||
}, | |||
{ | |||
name: '项目成熟度', | |||
max: 100 | |||
}, | |||
{ | |||
name: '开发活跃度', | |||
max: 100 | |||
}, | |||
{ | |||
name: '项目健康度', | |||
max: 100 | |||
}, | |||
{ | |||
name: '团队健康度', | |||
max: 100 | |||
}, | |||
{ | |||
name: '项目发展趋势', | |||
max: 100 | |||
} | |||
], | |||
}, | |||
series: [{ | |||
type: 'radar', | |||
lineStyle:{ | |||
width:2, | |||
color: 'rgb(0,255,0)' | |||
}, | |||
data: [{ | |||
value: ydata, | |||
}] | |||
}] | |||
} | |||
this.radarOpenI.setOption(option) | |||
}, | |||
drawOpenItrend(){ | |||
var xdata_openI=[] | |||
var ydata_openI=[] | |||
for(var i =0;i<this.tableDataIDOpenI.length;i++){ | |||
xdata_openI.push(this.tableDataIDOpenI[this.tableDataIDOpenI.length-1-i].date); | |||
ydata_openI.push(this.roundingF(this.tableDataIDOpenI[i].openi)) | |||
} | |||
console.log("ydata_openI:"+ydata_openI) | |||
console.log(xdata_openI) | |||
var option = { | |||
title : { | |||
text: 'OpenI指数趋势', | |||
textStyle: { | |||
fontSize: 12, | |||
}, | |||
left:'center', | |||
top:'bottom', | |||
subtext: '', | |||
}, | |||
tooltip : { | |||
trigger: 'axis', | |||
backgroundColor:'rgba(255,255,255,0.8)', | |||
color:'black', | |||
borderWidth:'1', | |||
borderColor:'gray', | |||
textStyle:{ | |||
color:'black' | |||
}, | |||
}, | |||
legend: { | |||
orient: 'vertical', | |||
top:'top', | |||
}, | |||
// calculable : true, | |||
xAxis : [ | |||
{ | |||
type : 'category', | |||
boundaryGap: false, | |||
data : xdata_openI, | |||
} | |||
], | |||
yAxis : [ | |||
{ | |||
type : 'value', | |||
} | |||
], | |||
series : [ | |||
{ | |||
data: ydata_openI, | |||
type: 'line', | |||
areaStyle: { | |||
color:'red', | |||
opacity: 0.3, | |||
origin:"start" | |||
}, | |||
// lineStyle:{ | |||
// width:2, | |||
// color: '#409effd6' | |||
// }, | |||
} | |||
] | |||
}; | |||
this.echartsOITd.setOption(option) | |||
}, | |||
drawSelectData(){ | |||
var xdata=[] | |||
var ydata_view=[] | |||
var ydata_download=[] | |||
var ydata_commit=[] | |||
for(var i =0;i<this.tableDataIDOpenI.length;i++){ | |||
xdata.push(this.tableDataIDOpenI[this.tableDataID.length-1-i].date); | |||
ydata_view.push(this.roundingF(this.tableDataID[i].view)) | |||
ydata_download.push(this.roundingF(this.tableDataID[i].download)) | |||
ydata_commit.push(this.roundingF(this.tableDataID[i].commit)) | |||
} | |||
console.log("ydata_openI:"+ydata_download) | |||
console.log(xdata) | |||
this.option = { | |||
title : { | |||
text: '', | |||
textStyle: { | |||
fontSize: 12, | |||
}, | |||
left:'center', | |||
top:'bottom', | |||
subtext: '', | |||
}, | |||
tooltip : { | |||
trigger: 'axis', | |||
backgroundColor:'rgba(255,255,255,0.8)', | |||
color:'black', | |||
borderWidth:'1', | |||
borderColor:'gray', | |||
textStyle:{ | |||
color:'black' | |||
}, | |||
}, | |||
legend: { | |||
data:['浏览量','下载量','commit'], | |||
// orient: 'vertical', | |||
// top:'top', | |||
}, | |||
toolbox: { | |||
show : false, | |||
feature : { | |||
mark : {show: true}, | |||
dataView : {show: false, readOnly: false}, | |||
magicType : {show: true, type: ['line', 'bar']}, | |||
restore : {show: false}, | |||
saveAsImage : {show: true} | |||
} | |||
}, | |||
calculable : true, | |||
xAxis : [ | |||
{ | |||
type : 'category', | |||
data : xdata, | |||
} | |||
], | |||
yAxis : [ | |||
{ | |||
type : 'value', | |||
} | |||
], | |||
series : [ | |||
{ name:"浏览量", | |||
data: ydata_view, | |||
type: 'line', | |||
areaStyle: {}, | |||
}, | |||
{ | |||
name:"下载量", | |||
data: ydata_download, | |||
type: 'line', | |||
areaStyle: {}, | |||
}, | |||
{ | |||
name:"commit", | |||
data: ydata_commit, | |||
type: 'line', | |||
areaStyle: {}, | |||
}, | |||
] | |||
}; | |||
this.echartsSelectData.setOption(this.option) | |||
// // 使用刚指定的选择项数据显示图表。 | |||
// var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值 | |||
// var checkboxs=document.getElementsByName('checkboxchart'); | |||
// $(".checkboxchart").click(function(){ | |||
// var obj = {}; | |||
// for(var i=0; i<checkboxs.length; i++){ | |||
// if(checkboxs[i].checked){ | |||
// obj[selectArr[i]] = true; | |||
// }else{ | |||
// obj[selectArr[i]] = false; | |||
// } | |||
// } | |||
// option.legend.selected = obj; | |||
// this.echartsSelectData.setOption(option); | |||
// }); | |||
}, | |||
roundingF(value){ | |||
return Number(value).toFixed(2) | |||
}, | |||
clickCheckBox(){ | |||
// 使用刚指定的选择项数据显示图表。 | |||
var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值 | |||
var checkboxs=document.getElementsByName('checkboxchart'); | |||
// $(".checkboxchart").click(function(){ | |||
var obj = {}; | |||
for(var i=0; i<checkboxs.length; i++){ | |||
if(checkboxs[i].checked){ | |||
obj[selectArr[i]] = true; | |||
}else{ | |||
obj[selectArr[i]] = false; | |||
} | |||
} | |||
this.option.legend.selected = obj; | |||
this.echartsSelectData.setOption(this.option); | |||
// }); | |||
} | |||
}, | |||
filters:{ | |||
rounding (value) { | |||
return Number(value).toFixed(2) | |||
}, | |||
changeType(value){ | |||
if(value=='false'){ | |||
return "否" | |||
}else{ | |||
return "是" | |||
} | |||
}, | |||
discriptionFun(value){ | |||
if(value==''){ | |||
return "暂无描述" | |||
} | |||
}, | |||
showMode(value){ | |||
if(value==1){ | |||
return "可读权限" | |||
}else if(value==2){ | |||
return "可写权限" | |||
}else if(value==3){ | |||
return "管理员" | |||
}else if(value==4){ | |||
return "所有者" | |||
}else{ | |||
return "未定义" | |||
} | |||
} | |||
}, | |||
mounted() { | |||
// document.getElementById("all").style.outline="none" | |||
// document.getElementById("all").focus() | |||
this.getAllProList("all",7) | |||
console.log("id:"+this.pro_id); | |||
// document.getElementById('radar_openi').style.width = document.getElementById('charts').offsetWidth*0.4+'px' | |||
// document.getElementById('line_openi').style.width = document.getElementById('charts').offsetWidth*0.6+'px' | |||
// document.getElementById('selectData').style.width = document.getElementById('linecharts').offsetWidth+'px' | |||
this.radarOpenI = this.$echarts.init(document.getElementById('radar_openi')) | |||
this.echartsOITd = this.$echarts.init(document.getElementById('line_openi')) | |||
this.echartsSelectData = this.$echarts.init(document.getElementById('selectData')) | |||
// window.onresize=function(){ | |||
// this.radarOpenI.resize(); | |||
// this.echartsOITd.resize(); | |||
// this.echartsSelectData.resize(); | |||
// } | |||
// console.log("this.radarOpenI:"+this.radarOpenI) | |||
}, | |||
created() { | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
.pro_item{ | |||
font-size: 16px; | |||
color: rgba(16, 16, 16, 100); | |||
font-family: SourceHanSansSC-bold; | |||
} | |||
.sta_item{ | |||
font-size: 14px; | |||
color: rgb(0 0 0); | |||
font-family: SourceHanSansSC-bold; | |||
} | |||
.update_time{ | |||
line-height: 17px; | |||
font-size: 12px; | |||
color:rgba(187, 187, 187, 100); | |||
margin-left: 10px; | |||
} | |||
.btn{ | |||
line-height: 1.5; | |||
margin: -3px; | |||
border: 1px solid #409eff; | |||
background: #FFFF; | |||
color: #409eff; | |||
width: 60px; | |||
height: 30px; | |||
border-radius:4px ; | |||
} | |||
.btn:focus, | |||
.btn:active{ | |||
background-color:#409effd6 ; | |||
} | |||
/deep/ .el-date-picker { | |||
width: 200px; | |||
} | |||
.colorChange { | |||
background-color: #409effd6; | |||
} | |||
.items{ | |||
text-align: center; | |||
border-right:2px solid rgba(219, 219, 219, 100); | |||
} | |||
.item_l{ | |||
margin-right: 5px; | |||
border:1px solid rgba(219, 219, 219, 100); | |||
height: 370px; | |||
width: 100%; | |||
} | |||
.item_r{ | |||
margin-right:5px; | |||
border:1px solid rgba(219, 219, 219, 100); | |||
height: 370px; | |||
} | |||
.item_echart{ | |||
margin-top: 10px; | |||
margin-right: 5px; | |||
border:1px solid rgba(219, 219, 219, 100); | |||
height: 350px; | |||
width: 100%; | |||
} | |||
</style> |
@@ -0,0 +1,415 @@ | |||
<template> | |||
<div> | |||
<div style="margin-top: 10px;"> | |||
<b class="pro_item">用户分析</b> <span class="update_time">数据更新时间:{{lastUpdatedTime}}/{{recordBeginTime}}</span> | |||
</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="getUserList('yesterday_usr',1)">昨天</button> | |||
<button type="button" class='btn' id = "current_week_usr" v-bind:class="{colorChange:2==dynamic}" @click="getUserList('current_week_usr',2)">本周</button> | |||
<button type="button" class='btn' id = "current_month_usr" v-bind:class="{colorChange:3==dynamic}" @click="getUserList('current_month_usr',3)">本月</button> | |||
<button type="button" class='btn' id = "last_month_usr" v-bind:class="{colorChange:4==dynamic}" @click="getUserList('last_month_usr',4)">上月</button> | |||
<button type="button" class='btn' id = "monthly_usr" v-bind:class="{colorChange:5==dynamic}" @click="getUserList('monthly_usr',5)">近30天</button> | |||
<button type="button" class='btn' id = "current_year_usr" v-bind:class="{colorChange:6==dynamic}" @click="getUserList('current_year_usr',6)">今年</button> | |||
<button type="button" class='btn' id = "all_usr" v-bind:class="{colorChange:7==dynamic}" @click="getUserList('all_usr',7)">所有</button> | |||
<span style="margin-left: 20px;"> | |||
<el-date-picker | |||
v-model="value_time" | |||
prefix-icon="el-icon-time" | |||
@change="getUserList('',0)" | |||
type="daterange" | |||
size='small' | |||
unlink-panels | |||
range-separator="至" | |||
start-placeholder="开始日期" | |||
end-placeholder="结束日期"> | |||
</el-date-picker> | |||
</span> | |||
<span style="float:right; margin-right: 20px;"> | |||
<a style="display:inline-block;margin-left: 20px; " id = 'download'> | |||
<i class="el-icon-download"></i> | |||
<span ><a @click="exportData()">下载报告</a> </span> | |||
</a> | |||
<span style="display:inline-block;margin-left: 20px; "> | |||
<el-input size="small" placeholder="输入用户名搜索" v-model="search" class="input-with-select" @keyup.enter.native="searchName() "><i slot="suffix" class="el-input__icon el-icon-search"></i> | |||
</el-input> | |||
</span> | |||
</span> | |||
</div> | |||
<div style="margin-top: 30px;"> | |||
<el-table | |||
:data="tableData.slice((currentPage-1)*pageSize,currentPage*pageSize)" | |||
style="width: 100%" | |||
:header-cell-style="tableHeaderStyle" | |||
:cell-style='cellStyle'> | |||
<el-table-column | |||
label="ID" | |||
prop="ID" | |||
align="center" | |||
stripe | |||
> | |||
</el-table-column> | |||
<el-table-column | |||
label="用户名" | |||
align="center" | |||
prop="Name" | |||
width="100px"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="CodeMergeCount" | |||
label="PR数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="CommitCount" | |||
label="commit数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="IssueCount" | |||
label="提出任务数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="CommentCount" | |||
label="评论数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="FocusRepoCount" | |||
label="关注项目数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="StarRepoCount" | |||
label="点赞项目数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="LoginCount" | |||
label="登录次数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="WatchedCount" | |||
label="关注者数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="CommitCodeSize" | |||
label="commit代码行数" | |||
width="115px" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="SolveIssueCount" | |||
label="已解决任务数" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="EncyclopediasCount" | |||
label="百科页面贡献次数" | |||
width="130px" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="CreateRepoCount" | |||
label="创建项目" | |||
align="center"> | |||
</el-table-column> | |||
<el-table-column | |||
prop="RegistDate" | |||
label="用户注册时间" | |||
width="120px" | |||
align="center"> | |||
<template slot-scope="scope"> | |||
{{scope.row.RegistDate | transformTimestamp}} | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="CountDate" | |||
label="系统统计时间" | |||
width="120px" | |||
align="center"> | |||
<template slot-scope="scope"> | |||
{{scope.row.CountDate | transformTimestamp}} | |||
</template> | |||
</el-table-column> | |||
</el-table> | |||
</div> | |||
<div style="margin-top:50px;text-align:center"> | |||
<el-pagination | |||
background | |||
@current-change="handleCurrentChange" | |||
:current-page="currentPage" | |||
:page-size="pageSize" | |||
layout="prev, pager, next" | |||
:total="tableData.length"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { export2Excel } from '../excel/util.js' | |||
export default{ | |||
name:'UserAnalysis', | |||
data() { | |||
return { | |||
type_val:'', | |||
recordBeginTime:'', | |||
lastUpdatedTime:'', | |||
currentPage:1, | |||
pageSize:10, | |||
params:{startDate:'',endDate:''}, | |||
tableData: [], | |||
pickerOptions: { | |||
}, | |||
value_time: '', | |||
search:'', | |||
data:'', | |||
columns: [{title: 'ID',key: 'ID'},{title: '用户名',key: 'Name'},{title: 'PR数',key: 'CommitCount'},{title: '提出任务数',key: 'IssueCount'},{title: '评论数',key: 'CommentCount'},{title: '关注项目数',key: 'FocusRepoCount'},{title: '点赞项目数',key: 'StarRepoCount'},{title: '登录次数',key: 'LoginCount'},{title:'关注者数',key:'WatchedCount'},{title:'commit代码行数',key:'CommitCodeSize'},{title:'已解决任务数',key:'SolveIssueCount'},{title:'百科页面贡献次数',key:'EncyclopediasCount'},{title:'创建项目',key:'CreateRepoCount'},{title:'加入时间',key:'RegistDate'}], | |||
blob:'', | |||
fileName:'', | |||
dynamic:7, | |||
params_pro:{type:'all',page:1,pagesize:10,beginTime:'',endTime:'',q:'',sort:'openi'}, | |||
}; | |||
}, | |||
methods: { | |||
exportData(){ | |||
export2Excel(this.columns,this.tableData,"测试下载excel") | |||
}, | |||
handleCurrentChange(currentPage){ | |||
this.currentPage = currentPage; | |||
}, | |||
formatDate(myyear,mymonth,myweekday) { | |||
// var myyear = this.date.getFullYear(); | |||
// var mymonth = this.date.getMonth() + 1; | |||
// var myweekday = this.date.getDate(); | |||
if (mymonth < 10) { | |||
mymonth = "0" + mymonth; | |||
} | |||
if (myweekday < 10) { | |||
myweekday = "0" + myweekday; | |||
} | |||
return (myyear + "-" + mymonth + "-" + myweekday); | |||
}, | |||
// 获得某月的天数 | |||
getMonthDays(nowYear,month){ | |||
let monthStartDate = new Date(nowYear, month, 1); | |||
let monthEndDate = new Date(nowYear, month + 1, 1); | |||
let days = (monthEndDate - monthStartDate)/(1000 * 60 * 60 * 24); | |||
return days; | |||
}, | |||
getUserList(type_val,index){ | |||
this.dynamic = index; | |||
console.log("dj:"+type_val) | |||
var now = new Date(); // 当前日期 | |||
var nowDayOfWeek = now.getDay(); // 今天本周的第几天 | |||
var nowDay = now.getDate(); // 当前日 | |||
var nowMonth = now.getMonth(); // 当前月 | |||
var nowYear = now.getFullYear(); // 当前年 | |||
var today = this.formatDate(nowYear,nowMonth+1,nowDay); | |||
let lastMonthDate = new Date(); // 上月日期 | |||
lastMonthDate.setDate(1); | |||
lastMonthDate.setMonth(lastMonthDate.getMonth()-1); | |||
let lastYear = lastMonthDate.getYear(); | |||
let lastMonth = lastMonthDate.getMonth(); | |||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | |||
this.params.startDate= this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate()); | |||
this.params.endDate = this.formatDate(this.value_time[1].getFullYear(),this.value_time[1].getMonth() + 1,this.value_time[1].getDate()); | |||
}else{ | |||
switch(type_val){ | |||
case "yesterday_usr":{ | |||
var now = new Date(); | |||
var tmp = new Date(now.setTime(now.getTime()-24*60*60*1000)); | |||
var yesterday = this.formatDate(tmp.getFullYear(),tmp.getMonth()+1,tmp.getDate()); | |||
this.params.startDate = yesterday | |||
this.params.endDate = yesterday | |||
this.value_time=[] | |||
document.getElementById("yesterday_usr").style.backgroundColor="409effd6" | |||
document.getElementById("current_week_usr") | |||
break | |||
} | |||
case "current_week_usr":{ | |||
var now = new Date(); // 当前日期 | |||
var nowDayOfWeek = now.getDay(); // 今天本周的第几天 | |||
var day = nowDayOfWeek || 7; | |||
this.params.startDate = this.formatDate(now.getFullYear(), nowMonth+1, nowDay + 1 - day); | |||
this.params.endDate = today | |||
this.value_time=[] | |||
break | |||
} | |||
case "current_month_usr":{ | |||
this.params.startDate = this.formatDate(nowYear,nowMonth+1,1); | |||
this.params.endDate = today | |||
this.value_time=[] | |||
break | |||
} | |||
case "last_month_usr":{ | |||
this.params.startDate=this.formatDate(nowYear, lastMonth+1, 1); | |||
this.params.endDate=this.formatDate(nowYear, lastMonth+1, this.getMonthDays(nowYear,lastMonth)); | |||
this.value_time=[] | |||
break | |||
} | |||
case "monthly_usr":{ | |||
var temp=new Date(now - 1000 * 60 * 60 * 24 * 30) | |||
this.params.startDate = this.formatDate(temp.getFullYear(),temp.getMonth()+1,temp.getDate()); | |||
this.params.endDate = today | |||
this.value_time=[] | |||
break | |||
} | |||
case "current_year_usr":{ | |||
this.params.startDate = this.formatDate(now.getFullYear(), 1, 1); | |||
this.params.endDate = today | |||
this.value_time=[] | |||
break | |||
} | |||
case "all_usr":{ | |||
console.log("e:"+today) | |||
this.params.startDate = this.formatDate(2000, 1, 1); //this.recordBeginTime// | |||
this.params.endDate = today | |||
this.value_time=[] | |||
break | |||
} | |||
} | |||
}; | |||
this.$axios.get('../tool/query_user_static',{ | |||
params:this.params | |||
}).then((res)=>{ | |||
this.currentPage = 1 | |||
this.tableData = res.data | |||
}) | |||
this.$axios.get('../api/v1/projectboard/project',{ | |||
params:this.params_pro | |||
}).then((res)=>{ | |||
this.recordBeginTime=res.data.recordBeginTime | |||
this.lastUpdatedTime=res.data.lastUpdatedTime | |||
}) | |||
}, | |||
searchName(){ | |||
// this.params.q = this.search | |||
// this.params.page = 1 | |||
// this.getUserList("all_usr") | |||
var search = this.search; | |||
this.getUserList("all_usr",7) | |||
this.tableData = this.tableData.filter(data => !search || data.Name.toLowerCase().includes(search.toLowerCase())) | |||
}, | |||
goToDetailPage(pro_id,pro_name){ | |||
sessionStorage.setItem("pro_id",pro_id); | |||
sessionStorage.setItem("pro_name",pro_name); | |||
document.getElementById("pro_main").style.display="none"; | |||
document.getElementById("pro_detail").style.display="block"; | |||
}, | |||
tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
if(rowIndex===0){ | |||
return 'background:#f5f5f6;color:#606266' | |||
} | |||
}, | |||
cellStyle({row,column,rowIndex,columnIndex}){ | |||
if(rowIndex%2 === 1){ | |||
return 'background:#f5f5f6;color:#606266' | |||
} | |||
}, | |||
}, | |||
filters:{ | |||
transformTimestamp(timestamp){ | |||
console.log("timestamp",timestamp) | |||
let a = new Date(timestamp*1000); | |||
const date = new Date(a); | |||
const Y = date.getFullYear() + '/'; | |||
const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/'; | |||
const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' '; | |||
const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':'; | |||
const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes());// + ':' ; | |||
// const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒 | |||
const dateString = Y + M + D + h + m ;//+ s; | |||
console.log('dateString', dateString); // > dateString 2021-07-06 14:23 | |||
return dateString; | |||
}, | |||
// transformTimestamp(timestamp){ | |||
// var dateString= new Date(timestamp); | |||
// return dateString.toLocaleDateString().replace(/\//g, "-") + " " + dateString.toTimeString().substr(0, 8); | |||
// }, | |||
}, | |||
mounted() { | |||
document.getElementById("all_usr").style.outline="none" | |||
document.getElementById("all_usr").focus() | |||
this.getUserList("all_usr",7) | |||
}, | |||
created() { | |||
}, | |||
watch:{ | |||
search(val){ | |||
if(!val){ | |||
this.getUserList("all_usr",7) | |||
} | |||
} | |||
}, | |||
} | |||
</script> | |||
<style scoped> | |||
.pro_item{ | |||
font-size: 16px; | |||
color: rgba(16, 16, 16, 100); | |||
font-family: SourceHanSansSC-bold; | |||
} | |||
.sta_item{ | |||
font-size: 14px; | |||
color: rgb(0 0 0); | |||
font-family: SourceHanSansSC-bold; | |||
} | |||
.update_time{ | |||
line-height: 17px; | |||
font-size: 12px; | |||
color:rgba(187, 187, 187, 100); | |||
margin-left: 10px; | |||
} | |||
.btn{ | |||
line-height: 1.5; | |||
margin: -3px; | |||
border: 1px solid #409effd6; | |||
background: #FFFF; | |||
color: #409eff; | |||
width: 60px; | |||
height: 30px; | |||
border-radius:4px ; | |||
} | |||
.btn:focus, | |||
.btn:active{ | |||
background-color:#409effd6 ; | |||
} | |||
/deep/ .el-date-picker { | |||
width: 200px; | |||
} | |||
/deep/ .el-table { | |||
font-size: 12px; | |||
} | |||
.colorChange { | |||
background-color: #409effd6; | |||
} | |||
</style> |
@@ -14,8 +14,11 @@ | |||
<slot name="content"></slot> | |||
<div slot="footer" class="dialog-footer"> | |||
<el-button @click="deleteDialog = false">{{"取消"}}</el-button> | |||
<el-button type="primary" @click="deleteCallback.call(vmContext,deleteParam)">{{"确定"}}</el-button> | |||
<button class="ui button" @click="deleteDialog = false">{{"取消"}}</button> | |||
<button class="ui green button" @click="deleteCallback.call(vmContext,deleteParam)">{{"确定"}}</button> | |||
<!-- <el-button size="small" style="font-size: 1rem;padding: .78571429em 1.5em .78571429em;border-radius: .28571429rem;" @click="deleteDialog = false">{{"取消"}}</el-button> | |||
<el-button size="small" style="background-color: #21ba45;color: #fff;font-size: 1rem;padding: .78571429em 1.5em .78571429em;border-radius: .28571429rem;" @click="deleteCallback.call(vmContext,deleteParam)">{{"确定"}}</el-button> --> | |||
</div> | |||
</el-dialog> | |||
</template> | |||
@@ -80,26 +83,31 @@ export default { | |||
.message-box__content .message-box-title{font-size:16px;padding:2px 0;color:#333;} | |||
.message-box__content .message-box-p{font-size:16px;padding:20px 0;color:#333;} | |||
.message-box__content .message-box-info{color:#999;padding:2px 0;} | |||
.dialog-footer,.el-message-box__btns{text-align:center;} | |||
/deep/ .el-dialog__body{ | |||
padding: 1rem; | |||
} | |||
/deep/ .el-dialog__header { | |||
background: #0067b3; | |||
padding: 12px 30px; | |||
line-height: 25px;} | |||
background: #f0f0f0; | |||
padding: 1rem; | |||
} | |||
/deep/ .el-dialog__title { | |||
font-family: PingFangSC-Regular; | |||
font-size: 18px; | |||
color: #fff; | |||
font-size: 1.28571429rem; | |||
color: rgba(0,0,0,.87); | |||
font-weight: 200; | |||
line-height: 25px; | |||
height: 25px; | |||
} | |||
/deep/ .el-dialog__footer { | |||
background: #eff3f9; | |||
padding: 20px 30px; | |||
padding: 1rem; | |||
} | |||
/deep/ .el-dialog{ | |||
width: 40%; | |||
width: 30%; | |||
} | |||
/deep/ .el-form-item__label{ | |||
padding: 0; | |||
} | |||
</style> |
@@ -0,0 +1,179 @@ | |||
/* eslint-disable */ | |||
/* Blob.js | |||
* A Blob implementation. | |||
* 2014-05-27 | |||
* | |||
* By Eli Grey, http://eligrey.com | |||
* By Devin Samarin, https://github.com/eboyjr | |||
* License: X11/MIT | |||
* See LICENSE.md | |||
*/ | |||
/*global self, unescape */ | |||
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, | |||
plusplus: true */ | |||
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ | |||
(function (view) { | |||
"use strict"; | |||
view.URL = view.URL || view.webkitURL; | |||
if (view.Blob && view.URL) { | |||
try { | |||
new Blob; | |||
return; | |||
} catch (e) {} | |||
} | |||
// Internally we use a BlobBuilder implementation to base Blob off of | |||
// in order to support older browsers that only have BlobBuilder | |||
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { | |||
var | |||
get_class = function(object) { | |||
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; | |||
} | |||
, FakeBlobBuilder = function BlobBuilder() { | |||
this.data = []; | |||
} | |||
, FakeBlob = function Blob(data, type, encoding) { | |||
this.data = data; | |||
this.size = data.length; | |||
this.type = type; | |||
this.encoding = encoding; | |||
} | |||
, FBB_proto = FakeBlobBuilder.prototype | |||
, FB_proto = FakeBlob.prototype | |||
, FileReaderSync = view.FileReaderSync | |||
, FileException = function(type) { | |||
this.code = this[this.name = type]; | |||
} | |||
, file_ex_codes = ( | |||
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " | |||
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" | |||
).split(" ") | |||
, file_ex_code = file_ex_codes.length | |||
, real_URL = view.URL || view.webkitURL || view | |||
, real_create_object_URL = real_URL.createObjectURL | |||
, real_revoke_object_URL = real_URL.revokeObjectURL | |||
, URL = real_URL | |||
, btoa = view.btoa | |||
, atob = view.atob | |||
, ArrayBuffer = view.ArrayBuffer | |||
, Uint8Array = view.Uint8Array | |||
; | |||
FakeBlob.fake = FB_proto.fake = true; | |||
while (file_ex_code--) { | |||
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; | |||
} | |||
if (!real_URL.createObjectURL) { | |||
URL = view.URL = {}; | |||
} | |||
URL.createObjectURL = function(blob) { | |||
var | |||
type = blob.type | |||
, data_URI_header | |||
; | |||
if (type === null) { | |||
type = "application/octet-stream"; | |||
} | |||
if (blob instanceof FakeBlob) { | |||
data_URI_header = "data:" + type; | |||
if (blob.encoding === "base64") { | |||
return data_URI_header + ";base64," + blob.data; | |||
} else if (blob.encoding === "URI") { | |||
return data_URI_header + "," + decodeURIComponent(blob.data); | |||
} if (btoa) { | |||
return data_URI_header + ";base64," + btoa(blob.data); | |||
} else { | |||
return data_URI_header + "," + encodeURIComponent(blob.data); | |||
} | |||
} else if (real_create_object_URL) { | |||
return real_create_object_URL.call(real_URL, blob); | |||
} | |||
}; | |||
URL.revokeObjectURL = function(object_URL) { | |||
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { | |||
real_revoke_object_URL.call(real_URL, object_URL); | |||
} | |||
}; | |||
FBB_proto.append = function(data/*, endings*/) { | |||
var bb = this.data; | |||
// decode data to a binary string | |||
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { | |||
var | |||
str = "" | |||
, buf = new Uint8Array(data) | |||
, i = 0 | |||
, buf_len = buf.length | |||
; | |||
for (; i < buf_len; i++) { | |||
str += String.fromCharCode(buf[i]); | |||
} | |||
bb.push(str); | |||
} else if (get_class(data) === "Blob" || get_class(data) === "File") { | |||
if (FileReaderSync) { | |||
var fr = new FileReaderSync; | |||
bb.push(fr.readAsBinaryString(data)); | |||
} else { | |||
// async FileReader won't work as BlobBuilder is sync | |||
throw new FileException("NOT_READABLE_ERR"); | |||
} | |||
} else if (data instanceof FakeBlob) { | |||
if (data.encoding === "base64" && atob) { | |||
bb.push(atob(data.data)); | |||
} else if (data.encoding === "URI") { | |||
bb.push(decodeURIComponent(data.data)); | |||
} else if (data.encoding === "raw") { | |||
bb.push(data.data); | |||
} | |||
} else { | |||
if (typeof data !== "string") { | |||
data += ""; // convert unsupported types to strings | |||
} | |||
// decode UTF-16 to binary string | |||
bb.push(unescape(encodeURIComponent(data))); | |||
} | |||
}; | |||
FBB_proto.getBlob = function(type) { | |||
if (!arguments.length) { | |||
type = null; | |||
} | |||
return new FakeBlob(this.data.join(""), type, "raw"); | |||
}; | |||
FBB_proto.toString = function() { | |||
return "[object BlobBuilder]"; | |||
}; | |||
FB_proto.slice = function(start, end, type) { | |||
var args = arguments.length; | |||
if (args < 3) { | |||
type = null; | |||
} | |||
return new FakeBlob( | |||
this.data.slice(start, args > 1 ? end : this.data.length) | |||
, type | |||
, this.encoding | |||
); | |||
}; | |||
FB_proto.toString = function() { | |||
return "[object Blob]"; | |||
}; | |||
FB_proto.close = function() { | |||
this.size = this.data.length = 0; | |||
}; | |||
return FakeBlobBuilder; | |||
}(view)); | |||
view.Blob = function Blob(blobParts, options) { | |||
var type = options ? (options.type || "") : ""; | |||
var builder = new BlobBuilder(); | |||
if (blobParts) { | |||
for (var i = 0, len = blobParts.length; i < len; i++) { | |||
builder.append(blobParts[i]); | |||
} | |||
} | |||
return builder.getBlob(type); | |||
}; | |||
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); |
@@ -0,0 +1,141 @@ | |||
/* eslint-disable */ | |||
require('script-loader!file-saver'); | |||
require('./Blob'); | |||
require('script-loader!xlsx/dist/xlsx.core.min'); | |||
function generateArray(table) { | |||
var out = []; | |||
var rows = table.querySelectorAll('tr'); | |||
var ranges = []; | |||
for (var R = 0; R < rows.length; ++R) { | |||
var outRow = []; | |||
var row = rows[R]; | |||
var columns = row.querySelectorAll('td'); | |||
for (var C = 0; C < columns.length; ++C) { | |||
var cell = columns[C]; | |||
var colspan = cell.getAttribute('colspan'); | |||
var rowspan = cell.getAttribute('rowspan'); | |||
var cellValue = cell.innerText; | |||
if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue; | |||
//Skip ranges | |||
ranges.forEach(function (range) { | |||
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) { | |||
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null); | |||
} | |||
}); | |||
//Handle Row Span | |||
if (rowspan || colspan) { | |||
rowspan = rowspan || 1; | |||
colspan = colspan || 1; | |||
ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}}); | |||
} | |||
; | |||
//Handle Value | |||
outRow.push(cellValue !== "" ? cellValue : null); | |||
//Handle Colspan | |||
if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null); | |||
} | |||
out.push(outRow); | |||
} | |||
return [out, ranges]; | |||
}; | |||
function datenum(v, date1904) { | |||
if (date1904) v += 1462; | |||
var epoch = Date.parse(v); | |||
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); | |||
} | |||
function sheet_from_array_of_arrays(data, opts) { | |||
var ws = {}; | |||
var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}}; | |||
for (var R = 0; R != data.length; ++R) { | |||
for (var C = 0; C != data[R].length; ++C) { | |||
if (range.s.r > R) range.s.r = R; | |||
if (range.s.c > C) range.s.c = C; | |||
if (range.e.r < R) range.e.r = R; | |||
if (range.e.c < C) range.e.c = C; | |||
var cell = {v: data[R][C]}; | |||
if (cell.v == null) continue; | |||
var cell_ref = XLSX.utils.encode_cell({c: C, r: R}); | |||
if (typeof cell.v === 'number') cell.t = 'n'; | |||
else if (typeof cell.v === 'boolean') cell.t = 'b'; | |||
else if (cell.v instanceof Date) { | |||
cell.t = 'n'; | |||
cell.z = XLSX.SSF._table[14]; | |||
cell.v = datenum(cell.v); | |||
} | |||
else cell.t = 's'; | |||
ws[cell_ref] = cell; | |||
} | |||
} | |||
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range); | |||
return ws; | |||
} | |||
function Workbook() { | |||
if (!(this instanceof Workbook)) return new Workbook(); | |||
this.SheetNames = []; | |||
this.Sheets = {}; | |||
} | |||
function s2ab(s) { | |||
var buf = new ArrayBuffer(s.length); | |||
var view = new Uint8Array(buf); | |||
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; | |||
return buf; | |||
} | |||
export function export_table_to_excel(id) { | |||
var theTable = document.getElementById(id); | |||
console.log('a') | |||
var oo = generateArray(theTable); | |||
var ranges = oo[1]; | |||
/* original data */ | |||
var data = oo[0]; | |||
var ws_name = "SheetJS"; | |||
console.log(data); | |||
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); | |||
/* add ranges to worksheet */ | |||
// ws['!cols'] = ['apple', 'banan']; | |||
ws['!merges'] = ranges; | |||
/* add worksheet to workbook */ | |||
wb.SheetNames.push(ws_name); | |||
wb.Sheets[ws_name] = ws; | |||
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); | |||
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx") | |||
} | |||
function formatJson(jsonData) { | |||
console.log(jsonData) | |||
} | |||
export function export_json_to_excel(th, jsonData, defaultTitle) { | |||
/* original data */ | |||
var data = jsonData; | |||
data.unshift(th); | |||
var ws_name = "SheetJS"; | |||
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); | |||
/* add worksheet to workbook */ | |||
wb.SheetNames.push(ws_name); | |||
wb.Sheets[ws_name] = ws; | |||
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); | |||
var title = defaultTitle || '列表' | |||
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx") | |||
} |
@@ -0,0 +1,17 @@ | |||
export function export2Excel(columns,list,filename){ | |||
require.ensure([], () => { | |||
const { export_json_to_excel } = require('./Export2Excel'); | |||
let tHeader = [] | |||
let filterVal = [] | |||
console.log(columns) | |||
if(!columns){ | |||
return; | |||
} | |||
columns.forEach(item =>{ | |||
tHeader.push(item.title) | |||
filterVal.push(item.key) | |||
}) | |||
const data = list.map(v => filterVal.map(j => v[j])) | |||
export_json_to_excel(tHeader, data, filename); | |||
}) | |||
} |
@@ -0,0 +1,74 @@ | |||
/** | |||
* LetterAvatar | |||
* | |||
* Artur Heinze | |||
* Create Letter avatar based on Initials | |||
* based on https://gist.github.com/leecrossley/6027780 | |||
*/ | |||
(function(w, d){ | |||
function LetterAvatar (name, size, color) { | |||
name = name || ''; | |||
size = size || 60; | |||
var colours = [ | |||
"#1abc9c", "#2ecc71", "#3498db", "#9b59b6", "#34495e", "#16a085", "#27ae60", "#2980b9", "#8e44ad", "#2c3e50", | |||
"#f1c40f", "#e67e22", "#e74c3c", "#00bcd4", "#95a5a6", "#f39c12", "#d35400", "#c0392b", "#bdc3c7", "#7f8c8d" | |||
], | |||
nameSplit = String(name).split(' '), | |||
initials, charIndex, colourIndex, canvas, context, dataURI; | |||
if (nameSplit.length == 1) { | |||
initials = nameSplit[0] ? nameSplit[0].charAt(0):'?'; | |||
} else { | |||
initials = nameSplit[0].charAt(0) + nameSplit[1].charAt(0); | |||
} | |||
if (w.devicePixelRatio) { | |||
size = (size * w.devicePixelRatio); | |||
} | |||
charIndex = (initials == '?' ? 72 : initials.charCodeAt(0)) - 64; | |||
colourIndex = charIndex % 20; | |||
canvas = d.createElement('canvas'); | |||
canvas.width = size; | |||
canvas.height = size; | |||
context = canvas.getContext("2d"); | |||
context.fillStyle = color ? color : colours[colourIndex - 1]; | |||
context.fillRect (0, 0, canvas.width, canvas.height); | |||
context.font = Math.round(canvas.width/2)+"px 'Microsoft Yahei'"; | |||
context.textAlign = "center"; | |||
context.fillStyle = "#FFF"; | |||
context.fillText(initials, size / 2, size / 1.5); | |||
dataURI = canvas.toDataURL(); | |||
canvas = null; | |||
return dataURI; | |||
} | |||
LetterAvatar.transform = function() { | |||
Array.prototype.forEach.call(d.querySelectorAll('img[avatar]'), function(img, name, color) { | |||
name = img.getAttribute('avatar'); | |||
color = img.getAttribute('color'); | |||
img.src = LetterAvatar(name, img.getAttribute('width'), color); | |||
img.removeAttribute('avatar'); | |||
img.setAttribute('alt', name); | |||
}); | |||
}; | |||
// AMD support | |||
if (typeof define === 'function' && define.amd) { | |||
define(function () { return LetterAvatar; }); | |||
// CommonJS and Node.js module support. | |||
} else if (typeof exports !== 'undefined') { | |||
// Support Node.js specific `module.exports` (which can be a function) | |||
if (typeof module != 'undefined' && module.exports) { | |||
exports = module.exports = LetterAvatar; | |||
} | |||
// But always support CommonJS module 1.1.1 spec (`exports` cannot be a function) | |||
exports.LetterAvatar = LetterAvatar; | |||
} else { | |||
window.LetterAvatar = LetterAvatar; | |||
d.addEventListener('DOMContentLoaded', function(event) { | |||
LetterAvatar.transform(); | |||
}); | |||
} | |||
})(window, document); |
@@ -4,7 +4,7 @@ | |||
import './publicpath.js'; | |||
import './polyfills.js'; | |||
import './features/letteravatar.js' | |||
import Vue from 'vue'; | |||
import ElementUI from 'element-ui'; | |||
import 'element-ui/lib/theme-chalk/index.css'; | |||
@@ -13,7 +13,7 @@ import qs from 'qs'; | |||
import 'jquery.are-you-sure'; | |||
import './vendor/semanticdropdown.js'; | |||
import {svg} from './utils.js'; | |||
import echarts from 'echarts' | |||
import initContextPopups from './features/contextpopup.js'; | |||
import initGitGraph from './features/gitgraph.js'; | |||
import initClipboard from './features/clipboard.js'; | |||
@@ -35,14 +35,20 @@ import {createCodeEditor} from './features/codeeditor.js'; | |||
import MinioUploader from './components/MinioUploader.vue'; | |||
import ObsUploader from './components/ObsUploader.vue'; | |||
import EditAboutInfo from './components/EditAboutInfo.vue'; | |||
import Images from './components/Images.vue' | |||
import EditTopics from './components/EditTopics.vue' | |||
import Images from './components/Images.vue'; | |||
import EditTopics from './components/EditTopics.vue'; | |||
import DataAnalysis from './components/DataAnalysis.vue' | |||
import Contributors from './components/Contributors.vue' | |||
Vue.use(ElementUI); | |||
Vue.prototype.$axios = axios; | |||
Vue.prototype.qs = qs; | |||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||
Object.defineProperty(Vue.prototype, '$echarts', { | |||
value: echarts | |||
}) | |||
function htmlEncode(text) { | |||
return jQuery('<div />') | |||
.text(text) | |||
@@ -2969,7 +2975,9 @@ $(document).ready(async () => { | |||
initObsUploader(); | |||
initVueEditAbout(); | |||
initVueEditTopic(); | |||
initVueContributors(); | |||
initVueImages(); | |||
initVueDataAnalysis(); | |||
initTeamSettings(); | |||
initCtrlEnterSubmit(); | |||
initNavbarContentToggle(); | |||
@@ -3682,6 +3690,21 @@ function initVueEditTopic() { | |||
render:h=>h(EditTopics) | |||
}) | |||
} | |||
function initVueContributors() { | |||
const el = document.getElementById('Contributors'); | |||
if (!el) { | |||
return; | |||
} | |||
new Vue({ | |||
el:'#Contributors', | |||
render:h=>h(Contributors) | |||
}) | |||
} | |||
function initVueImages() { | |||
const el = document.getElementById('images'); | |||
console.log("el",el) | |||
@@ -3696,7 +3719,20 @@ function initVueImages() { | |||
render: h => h(Images) | |||
}); | |||
} | |||
function initVueDataAnalysis() { | |||
const el = document.getElementById('data_analysis'); | |||
console.log("el",el) | |||
if (!el) { | |||
return; | |||
} | |||
new Vue({ | |||
el: '#data_analysis', | |||
render: h => h(DataAnalysis) | |||
}); | |||
} | |||
// 新增 | |||
function initObsUploader() { | |||
const el = document.getElementById('obsUploader'); | |||
@@ -243,4 +243,77 @@ footer .column{margin-bottom:0!important; padding-bottom:0!important;} | |||
display: inline-block; | |||
width: 100%; | |||
} | |||
.git-user-content{ | |||
margin-bottom: 16px; | |||
word-break: break-all; | |||
} | |||
.row.git-user-content .ui.avatar.s16.image { | |||
width: 50px !important; | |||
height: 50px !important; | |||
vertical-align: middle; | |||
border-radius: 500rem;} | |||
.user-list-item { | |||
padding: 0.3em 0px !important; | |||
margin: 15px 0 !important; | |||
width: 220px !important; | |||
} | |||
.row.git-user-content .content { | |||
margin-left: 6px; | |||
display: inline-block; | |||
vertical-align: top !important; | |||
overflow: hidden; | |||
} | |||
.row.git-user-content .content .header { | |||
font-weight: bold; | |||
} | |||
.item.user-list-item .header { | |||
line-height: 23px !important; | |||
font-size: 16px !important; | |||
text-overflow: ellipsis; | |||
overflow: hidden; | |||
width: 145px; | |||
white-space:nowrap; | |||
} | |||
.item.user-list-item .header a { | |||
color: #587284 !important; | |||
} | |||
.row.git-user-content .content .commit-btn { | |||
margin-top: 6px; | |||
float: left; | |||
font-size: 11px; | |||
color: #40485b !important; | |||
} | |||
.dropdown-menu { | |||
position: relative; | |||
display: inline-block; | |||
margin-top: 4px; | |||
} | |||
.dropdown-menu:hover .dropdown-content { | |||
display: block; | |||
} | |||
.dropdown-content{ | |||
display: none; | |||
position: absolute; | |||
background-color: #ffffff; | |||
min-width: 180px; | |||
z-index: 999; | |||
border: 1px solid transparent; | |||
border-color: #d4d4d5; | |||
border-top: none; | |||
} | |||
.dropdown-content a { | |||
color: black; | |||
padding: 12px 16px; | |||
text-decoration: none; | |||
display: block; | |||
} | |||
.dropdown-content a:hover {background-color: #f1f1f1} | |||
.cloudbrain-question{ | |||
margin-left: 4px !important; | |||
color: #3291F8; | |||
} |