| @@ -33,6 +33,7 @@ type AiModelManage struct { | |||||
| CodeBranch string `xorm:"varchar(400) NULL" json:"codeBranch"` | CodeBranch string `xorm:"varchar(400) NULL" json:"codeBranch"` | ||||
| CodeCommitID string `xorm:"NULL" json:"codeCommitID"` | CodeCommitID string `xorm:"NULL" json:"codeCommitID"` | ||||
| UserId int64 `xorm:"NOT NULL" json:"userId"` | UserId int64 `xorm:"NOT NULL" json:"userId"` | ||||
| IsPrivate bool `xorm:"DEFAULT true" json:"isPrivate"` | |||||
| UserName string `json:"userName"` | UserName string `json:"userName"` | ||||
| UserRelAvatarLink string `json:"userRelAvatarLink"` | UserRelAvatarLink string `json:"userRelAvatarLink"` | ||||
| TrainTaskInfo string `xorm:"text NULL" json:"trainTaskInfo"` | TrainTaskInfo string `xorm:"text NULL" json:"trainTaskInfo"` | ||||
| @@ -40,6 +41,7 @@ type AiModelManage struct { | |||||
| UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"` | UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"` | ||||
| IsCanOper bool `json:"isCanOper"` | IsCanOper bool `json:"isCanOper"` | ||||
| IsCanDelete bool `json:"isCanDelete"` | IsCanDelete bool `json:"isCanDelete"` | ||||
| IsCanDownload bool `json:"isCanDownload"` | |||||
| } | } | ||||
| type AiModelConvert struct { | type AiModelConvert struct { | ||||
| @@ -84,8 +86,10 @@ type AiModelQueryOptions struct { | |||||
| SortType string | SortType string | ||||
| New int | New int | ||||
| // JobStatus CloudbrainStatus | // JobStatus CloudbrainStatus | ||||
| Type int | |||||
| Status int | |||||
| Type int | |||||
| Status int | |||||
| IsOnlyThisRepo bool | |||||
| IsQueryPrivate bool | |||||
| } | } | ||||
| func (a *AiModelConvert) IsGpuTrainTask() bool { | func (a *AiModelConvert) IsGpuTrainTask() bool { | ||||
| @@ -217,6 +221,19 @@ func SaveModelToDb(model *AiModelManage) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func QueryModelConvertByName(name string, repoId int64) ([]*AiModelConvert, error) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| sess.Select("*").Table(new(AiModelConvert)). | |||||
| Where("name='" + name + "' and repo_id=" + fmt.Sprint(repoId)).OrderBy("created_unix desc") | |||||
| aiModelManageConvertList := make([]*AiModelConvert, 0) | |||||
| err := sess.Find(&aiModelManageConvertList) | |||||
| if err == nil { | |||||
| return aiModelManageConvertList, nil | |||||
| } | |||||
| return nil, err | |||||
| } | |||||
| func QueryModelConvertById(id string) (*AiModelConvert, error) { | func QueryModelConvertById(id string) (*AiModelConvert, error) { | ||||
| sess := x.NewSession() | sess := x.NewSession() | ||||
| defer sess.Close() | defer sess.Close() | ||||
| @@ -288,15 +305,30 @@ func ModifyModelDescription(id string, description string) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func ModifyLocalModel(id string, name, label, description string, engine int) error { | |||||
| func ModifyModelPrivate(id string, isPrivate bool) error { | |||||
| var sess *xorm.Session | |||||
| sess = x.ID(id) | |||||
| defer sess.Close() | |||||
| re, err := sess.Cols("is_private").Update(&AiModelManage{ | |||||
| IsPrivate: isPrivate, | |||||
| }) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| log.Info("success to update isPrivate from db.re=" + fmt.Sprint((re))) | |||||
| return nil | |||||
| } | |||||
| func ModifyLocalModel(id string, name, label, description string, engine int, isPrivate bool) error { | |||||
| var sess *xorm.Session | var sess *xorm.Session | ||||
| sess = x.ID(id) | sess = x.ID(id) | ||||
| defer sess.Close() | defer sess.Close() | ||||
| re, err := sess.Cols("name", "label", "description", "engine").Update(&AiModelManage{ | |||||
| re, err := sess.Cols("name", "label", "description", "engine", "is_private").Update(&AiModelManage{ | |||||
| Description: description, | Description: description, | ||||
| Name: name, | Name: name, | ||||
| Label: label, | Label: label, | ||||
| Engine: int64(engine), | Engine: int64(engine), | ||||
| IsPrivate: isPrivate, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| @@ -411,7 +443,11 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||||
| builder.Eq{"ai_model_manage.status": opts.Status}, | builder.Eq{"ai_model_manage.status": opts.Status}, | ||||
| ) | ) | ||||
| } | } | ||||
| if !opts.IsQueryPrivate { | |||||
| cond = cond.And( | |||||
| builder.Eq{"ai_model_manage.is_private": false}, | |||||
| ) | |||||
| } | |||||
| count, err := sess.Where(cond).Count(new(AiModelManage)) | count, err := sess.Where(cond).Count(new(AiModelManage)) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, 0, fmt.Errorf("Count: %v", err) | return nil, 0, fmt.Errorf("Count: %v", err) | ||||
| @@ -1061,6 +1061,9 @@ type UserImageConfig struct { | |||||
| CreateVersion bool `json:"create_version"` | CreateVersion bool `json:"create_version"` | ||||
| Flavor Flavor `json:"flavor"` | Flavor Flavor `json:"flavor"` | ||||
| PoolID string `json:"pool_id"` | PoolID string `json:"pool_id"` | ||||
| ShareAddr string `json:"nas_share_addr"` | |||||
| MountPath string `json:"nas_mount_path"` | |||||
| NasType string `json:"nas_type"` | |||||
| } | } | ||||
| type CreateTrainJobParams struct { | type CreateTrainJobParams struct { | ||||
| @@ -1084,13 +1087,18 @@ type Config struct { | |||||
| CreateVersion bool `json:"create_version"` | CreateVersion bool `json:"create_version"` | ||||
| Flavor Flavor `json:"flavor"` | Flavor Flavor `json:"flavor"` | ||||
| PoolID string `json:"pool_id"` | PoolID string `json:"pool_id"` | ||||
| ShareAddr string `json:"nas_share_addr"` | |||||
| MountPath string `json:"nas_mount_path"` | |||||
| NasType string `json:"nas_type"` | |||||
| } | } | ||||
| type CreateInferenceJobParams struct { | type CreateInferenceJobParams struct { | ||||
| JobName string `json:"job_name"` | JobName string `json:"job_name"` | ||||
| Description string `json:"job_desc"` | Description string `json:"job_desc"` | ||||
| InfConfig InfConfig `json:"config"` | InfConfig InfConfig `json:"config"` | ||||
| WorkspaceID string `json:"workspace_id"` | WorkspaceID string `json:"workspace_id"` | ||||
| } | } | ||||
| type CreateInfUserImageParams struct { | type CreateInfUserImageParams struct { | ||||
| JobName string `json:"job_name"` | JobName string `json:"job_name"` | ||||
| Description string `json:"job_desc"` | Description string `json:"job_desc"` | ||||
| @@ -1148,6 +1156,9 @@ type TrainJobVersionConfig struct { | |||||
| Flavor Flavor `json:"flavor"` | Flavor Flavor `json:"flavor"` | ||||
| PoolID string `json:"pool_id"` | PoolID string `json:"pool_id"` | ||||
| PreVersionId int64 `json:"pre_version_id"` | PreVersionId int64 `json:"pre_version_id"` | ||||
| ShareAddr string `json:"nas_share_addr"` | |||||
| MountPath string `json:"nas_mount_path"` | |||||
| NasType string `json:"nas_type"` | |||||
| } | } | ||||
| type TrainJobVersionUserImageConfig struct { | type TrainJobVersionUserImageConfig struct { | ||||
| @@ -1163,6 +1174,9 @@ type TrainJobVersionUserImageConfig struct { | |||||
| PreVersionId int64 `json:"pre_version_id"` | PreVersionId int64 `json:"pre_version_id"` | ||||
| UserImageUrl string `json:"user_image_url"` | UserImageUrl string `json:"user_image_url"` | ||||
| UserCommand string `json:"user_command"` | UserCommand string `json:"user_command"` | ||||
| ShareAddr string `json:"nas_share_addr"` | |||||
| MountPath string `json:"nas_mount_path"` | |||||
| NasType string `json:"nas_type"` | |||||
| } | } | ||||
| type CreateConfigParams struct { | type CreateConfigParams struct { | ||||
| @@ -1178,6 +1192,7 @@ type CreateConfigParams struct { | |||||
| LogUrl string `json:"log_url"` | LogUrl string `json:"log_url"` | ||||
| Flavor Flavor `json:"flavor"` | Flavor Flavor `json:"flavor"` | ||||
| PoolID string `json:"pool_id"` | PoolID string `json:"pool_id"` | ||||
| Volumes []Volumes `json:"volumes"` | |||||
| } | } | ||||
| type Parameter struct { | type Parameter struct { | ||||
| @@ -1862,6 +1877,7 @@ func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { | |||||
| session.Commit() | session.Commit() | ||||
| go IncreaseDatasetUseCount(cloudbrain.Uuid) | go IncreaseDatasetUseCount(cloudbrain.Uuid) | ||||
| go OperateRepoAITaskNum(cloudbrain.RepoID, 1) | |||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -2017,9 +2033,29 @@ func DeleteJob(job *Cloudbrain) error { | |||||
| func deleteJob(e Engine, job *Cloudbrain) error { | func deleteJob(e Engine, job *Cloudbrain) error { | ||||
| _, err := e.ID(job.ID).Delete(job) | _, err := e.ID(job.ID).Delete(job) | ||||
| if err == nil { | |||||
| go updateAITaskNumWhenDeleteJob(job) | |||||
| } | |||||
| return err | return err | ||||
| } | } | ||||
| func updateAITaskNumWhenDeleteJob(job *Cloudbrain) { | |||||
| repoId := job.RepoID | |||||
| if repoId == 0 { | |||||
| t := &Cloudbrain{} | |||||
| _, tempErr := x.ID(job.ID).Unscoped().Get(t) | |||||
| if tempErr != nil { | |||||
| log.Error("updateAITaskNumWhenDeleteJob error.%v", tempErr) | |||||
| return | |||||
| } | |||||
| repoId = t.RepoID | |||||
| } | |||||
| if repoId > 0 { | |||||
| go OperateRepoAITaskNum(repoId, -1) | |||||
| } | |||||
| } | |||||
| func GetCloudbrainByName(jobName string) (*Cloudbrain, error) { | func GetCloudbrainByName(jobName string) (*Cloudbrain, error) { | ||||
| cb := &Cloudbrain{JobName: jobName} | cb := &Cloudbrain{JobName: jobName} | ||||
| return getRepoCloudBrain(cb) | return getRepoCloudBrain(cb) | ||||
| @@ -2222,7 +2258,6 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||||
| } | } | ||||
| go IncreaseDatasetUseCount(new.Uuid) | go IncreaseDatasetUseCount(new.Uuid) | ||||
| return nil | return nil | ||||
| } | } | ||||
| func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | ||||
| @@ -10,6 +10,26 @@ import ( | |||||
| "xorm.io/xorm" | "xorm.io/xorm" | ||||
| ) | ) | ||||
| type AvailablePageSize int | |||||
| const ( | |||||
| PageSize15 AvailablePageSize = 15 | |||||
| PageSize30 AvailablePageSize = 30 | |||||
| PageSize50 AvailablePageSize = 50 | |||||
| ) | |||||
| func (s AvailablePageSize) IsLegal() bool { | |||||
| switch s { | |||||
| case PageSize30, PageSize50, PageSize15: | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| func (s AvailablePageSize) Int() int { | |||||
| return int(s) | |||||
| } | |||||
| // ListOptions options to paginate results | // ListOptions options to paginate results | ||||
| type ListOptions struct { | type ListOptions struct { | ||||
| PageSize int | PageSize int | ||||
| @@ -231,10 +231,43 @@ type Repository struct { | |||||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | ||||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | ||||
| Hot int64 `xorm:"-"` | |||||
| Active int64 `xorm:"-"` | |||||
| Alias string `xorm:"INDEX"` | |||||
| LowerAlias string `xorm:"INDEX"` | |||||
| Hot int64 `xorm:"-"` | |||||
| Active int64 `xorm:"-"` | |||||
| Alias string `xorm:"INDEX"` | |||||
| LowerAlias string `xorm:"INDEX"` | |||||
| AiTaskCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
| ModelCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
| DatasetCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
| LastMonthVisits int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
| LastFourMonthCommits int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | |||||
| // Repository4Card format for front display | |||||
| type Repository4Card struct { | |||||
| ID int64 | |||||
| OwnerID int64 | |||||
| OwnerName string | |||||
| LowerName string | |||||
| Name string | |||||
| Alias string | |||||
| NumWatches int | |||||
| NumStars int | |||||
| NumForks int | |||||
| Description string | |||||
| Topics []string | |||||
| AiTaskCnt int64 | |||||
| ModelCnt int64 | |||||
| DatasetCnt int64 | |||||
| CreatedUnix timeutil.TimeStamp | |||||
| UpdatedUnix timeutil.TimeStamp | |||||
| PrimaryLanguage *LanguageStat | |||||
| RelAvatarLink string | |||||
| Contributors []*ContributorInfo | |||||
| IsPrivate bool | |||||
| IsFork bool | |||||
| IsMirror bool | |||||
| IsOwnerPrivate bool | |||||
| IsArchived bool | |||||
| } | } | ||||
| type RepositoryShow struct { | type RepositoryShow struct { | ||||
| @@ -243,6 +276,47 @@ type RepositoryShow struct { | |||||
| Alias string | Alias string | ||||
| } | } | ||||
| func (repo *Repository) ToCardFormat() *Repository4Card { | |||||
| link := repo.RelAvatarLink() | |||||
| var isOwnerPrivate bool | |||||
| if repo.Owner != nil && repo.Owner.Visibility.IsPrivate() { | |||||
| isOwnerPrivate = true | |||||
| } | |||||
| result := &Repository4Card{ | |||||
| ID: repo.ID, | |||||
| OwnerID: repo.OwnerID, | |||||
| OwnerName: repo.OwnerName, | |||||
| LowerName: repo.LowerName, | |||||
| Name: repo.Name, | |||||
| NumWatches: repo.NumWatches, | |||||
| NumStars: repo.NumStars, | |||||
| NumForks: repo.NumForks, | |||||
| Description: repo.Description, | |||||
| Topics: repo.Topics, | |||||
| AiTaskCnt: repo.AiTaskCnt, | |||||
| ModelCnt: repo.ModelCnt, | |||||
| DatasetCnt: repo.DatasetCnt, | |||||
| CreatedUnix: repo.CreatedUnix, | |||||
| UpdatedUnix: repo.UpdatedUnix, | |||||
| PrimaryLanguage: repo.PrimaryLanguage, | |||||
| RelAvatarLink: link, | |||||
| Alias: repo.Alias, | |||||
| IsPrivate: repo.IsPrivate, | |||||
| IsFork: repo.IsFork, | |||||
| IsMirror: repo.IsMirror, | |||||
| IsOwnerPrivate: isOwnerPrivate, | |||||
| IsArchived: repo.IsArchived, | |||||
| } | |||||
| return result | |||||
| } | |||||
| type ContributorInfo struct { | |||||
| RelAvatarLink string | |||||
| UserName string | |||||
| Email string | |||||
| CommitCnt int | |||||
| } | |||||
| // SanitizedOriginalURL returns a sanitized OriginalURL | // SanitizedOriginalURL returns a sanitized OriginalURL | ||||
| func (repo *Repository) SanitizedOriginalURL() string { | func (repo *Repository) SanitizedOriginalURL() string { | ||||
| if repo.OriginalURL == "" { | if repo.OriginalURL == "" { | ||||
| @@ -2379,6 +2453,75 @@ func CheckRepoStats(ctx context.Context) error { | |||||
| } | } | ||||
| } | } | ||||
| // ***** END: Repository.NumForks ***** | // ***** END: Repository.NumForks ***** | ||||
| // ***** START: Repository.DatasetCnt ***** | |||||
| desc = "repository count 'dataset_cnt'" | |||||
| results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.dataset_cnt!=(select count(1) from attachment inner join dataset on attachment.dataset_id = dataset.id where dataset.repo_id = repository.id)") | |||||
| if err != nil { | |||||
| log.Error("Select %s: %v", desc, err) | |||||
| } else { | |||||
| for _, result := range results { | |||||
| id := com.StrTo(result["id"]).MustInt64() | |||||
| select { | |||||
| case <-ctx.Done(): | |||||
| log.Warn("CheckRepoStats: Cancelled") | |||||
| return ErrCancelledf("during %s for repo ID %d", desc, id) | |||||
| default: | |||||
| } | |||||
| log.Trace("Updating %s: %d", desc, id) | |||||
| err = ResetRepoDatasetNum(id) | |||||
| if err != nil { | |||||
| log.Error("Update %s[%d]: %v", desc, id, err) | |||||
| } | |||||
| } | |||||
| } | |||||
| // ***** END: Repository.DatasetCnt ***** | |||||
| // ***** START: Repository.ModelCnt ***** | |||||
| desc = "repository count 'model_cnt'" | |||||
| results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.model_cnt!=(select count(1) from ai_model_manage where repository.id = ai_model_manage.repo_id and ai_model_manage.size > 0 )") | |||||
| if err != nil { | |||||
| log.Error("Select %s: %v", desc, err) | |||||
| } else { | |||||
| for _, result := range results { | |||||
| id := com.StrTo(result["id"]).MustInt64() | |||||
| select { | |||||
| case <-ctx.Done(): | |||||
| log.Warn("CheckRepoStats: Cancelled") | |||||
| return ErrCancelledf("during %s for repo ID %d", desc, id) | |||||
| default: | |||||
| } | |||||
| log.Trace("Updating %s: %d", desc, id) | |||||
| err = ResetRepoModelNum(id) | |||||
| if err != nil { | |||||
| log.Error("Update %s[%d]: %v", desc, id, err) | |||||
| } | |||||
| } | |||||
| } | |||||
| // ***** END: Repository.ModelCnt ***** | |||||
| // ***** START: Repository.AiTaskCnt ***** | |||||
| desc = "repository count 'ai_task_cnt'" | |||||
| results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.ai_task_cnt!=(select count(1) from cloudbrain where repository.id = cloudbrain.repo_id and (cloudbrain.deleted_at is null or cloudbrain.deleted_at = '0001-01-01 00:00:00') )") | |||||
| if err != nil { | |||||
| log.Error("Select %s: %v", desc, err) | |||||
| } else { | |||||
| for _, result := range results { | |||||
| id := com.StrTo(result["id"]).MustInt64() | |||||
| select { | |||||
| case <-ctx.Done(): | |||||
| log.Warn("CheckRepoStats: Cancelled") | |||||
| return ErrCancelledf("during %s for repo ID %d", desc, id) | |||||
| default: | |||||
| } | |||||
| log.Trace("Updating %s: %d", desc, id) | |||||
| err = ResetRepoAITaskNum(id) | |||||
| if err != nil { | |||||
| log.Error("Update %s[%d]: %v", desc, id, err) | |||||
| } | |||||
| } | |||||
| } | |||||
| // ***** END: Repository.AiTaskCnt ***** | |||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -2775,3 +2918,85 @@ func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFi | |||||
| } | } | ||||
| return &RepoFile{CommitId: commitId, Content: d}, nil | return &RepoFile{CommitId: commitId, Content: d}, nil | ||||
| } | } | ||||
| func ResetRepoAITaskNum(repoId int64) error { | |||||
| n, err := x.Where("repo_id = ? ", repoId).Count(&Cloudbrain{}) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| r := Repository{ | |||||
| AiTaskCnt: n, | |||||
| } | |||||
| _, err = x.Cols("ai_task_cnt").Where("id = ?", repoId).Update(&r) | |||||
| return err | |||||
| } | |||||
| func ResetRepoDatasetNum(repoId int64) error { | |||||
| n, err := x.Table("attachment").Join("inner", "dataset", "attachment.dataset_id = dataset.id").Where("dataset.repo_id = ?", repoId).Count() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| r := Repository{ | |||||
| DatasetCnt: n, | |||||
| } | |||||
| _, err = x.Cols("dataset_cnt").Where("id = ?", repoId).Update(&r) | |||||
| return err | |||||
| } | |||||
| func ResetRepoModelNum(repoId int64) error { | |||||
| _, err := x.Exec("update repository set model_cnt = (select count(1) from ai_model_manage where ai_model_manage.repo_id = ? and size > 0) where id = ?", repoId, repoId) | |||||
| return err | |||||
| } | |||||
| func operateRepoCol(repoId int64, colName string, amount int64, engines ...*xorm.Engine) error { | |||||
| var err error | |||||
| if amount == 0 { | |||||
| return nil | |||||
| } | |||||
| var ee *xorm.Engine | |||||
| if len(engines) == 0 { | |||||
| ee = x | |||||
| } else { | |||||
| ee = engines[0] | |||||
| } | |||||
| if amount > 0 { | |||||
| _, err = ee.Exec(fmt.Sprintf("update repository set %s = %s + ? where id = ?", colName, colName), amount, repoId) | |||||
| } else { | |||||
| _, err = ee.Exec(fmt.Sprintf("update repository set %s = %s - ? where id = ?", colName, colName), -1*amount, repoId) | |||||
| } | |||||
| return err | |||||
| } | |||||
| func OperateRepoDatasetNum(repoId int64, amount int64, engines ...*xorm.Engine) error { | |||||
| return operateRepoCol(repoId, "dataset_cnt", amount, engines...) | |||||
| } | |||||
| func OperateRepoModelNum(repoId int64, amount int64, engines ...*xorm.Engine) error { | |||||
| return operateRepoCol(repoId, "model_cnt", amount, engines...) | |||||
| } | |||||
| func OperateRepoAITaskNum(repoId int64, amount int64, engines ...*xorm.Engine) error { | |||||
| return operateRepoCol(repoId, "ai_task_cnt", amount, engines...) | |||||
| } | |||||
| func UpdateRepositoryLastFourMonthCommits(repoID int64, amount int64) error { | |||||
| _, err := x.Exec("update repository set last_four_month_commits = ? where id = ?", amount, repoID) | |||||
| return err | |||||
| } | |||||
| func UpdateRepositoryLastMonthVisits(repoID int64, amount int64) error { | |||||
| _, err := x.Exec("update repository set last_month_visits = ? where id = ?", amount, repoID) | |||||
| return err | |||||
| } | |||||
| func SyncStatDataToRepo(repo *Repository) { | |||||
| //Save the visit number of repository in the last month | |||||
| if lv, err := SumLastMonthNumVisits(repo.ID); err == nil { | |||||
| UpdateRepositoryLastMonthVisits(repo.ID, lv) | |||||
| } | |||||
| //Save the commits number of repository in the last four month | |||||
| if lc, err := SumLastFourMonthNumCommits(repo.ID); err == nil { | |||||
| UpdateRepositoryLastFourMonthCommits(repo.ID, lc) | |||||
| } | |||||
| } | |||||
| @@ -201,29 +201,41 @@ func (s SearchOrderBy) String() string { | |||||
| return string(s) | return string(s) | ||||
| } | } | ||||
| type FindReposResponse struct { | |||||
| Repos []*Repository4Card | |||||
| Page int | |||||
| PageSize int | |||||
| Total int64 | |||||
| } | |||||
| // Strings for sorting result | // Strings for sorting result | ||||
| const ( | const ( | ||||
| SearchOrderByAlphabetically SearchOrderBy = "name ASC" | |||||
| SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" | |||||
| SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" | |||||
| SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" | |||||
| SearchOrderByOldest SearchOrderBy = "created_unix ASC" | |||||
| SearchOrderByNewest SearchOrderBy = "created_unix DESC" | |||||
| SearchOrderBySize SearchOrderBy = "size ASC" | |||||
| SearchOrderBySizeReverse SearchOrderBy = "size DESC" | |||||
| SearchOrderByID SearchOrderBy = "id ASC" | |||||
| SearchOrderByIDReverse SearchOrderBy = "id DESC" | |||||
| SearchOrderByStars SearchOrderBy = "num_stars ASC" | |||||
| SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" | |||||
| SearchOrderByForks SearchOrderBy = "num_forks ASC" | |||||
| SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" | |||||
| SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" | |||||
| SearchOrderByUseCount SearchOrderBy = "use_count ASC" | |||||
| SearchOrderByUseCountReverse SearchOrderBy = "use_count DESC" | |||||
| SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" | |||||
| SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" | |||||
| SearchOrderByWatches SearchOrderBy = "num_watches DESC" | |||||
| SearchOrderByDefault SearchOrderBy = "recommend desc,num_stars DESC,updated_unix DESC" | |||||
| SearchOrderByAlphabetically SearchOrderBy = "name ASC" | |||||
| SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" | |||||
| SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" | |||||
| SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" | |||||
| SearchOrderByOldest SearchOrderBy = "created_unix ASC" | |||||
| SearchOrderByNewest SearchOrderBy = "created_unix DESC" | |||||
| SearchOrderBySize SearchOrderBy = "size ASC" | |||||
| SearchOrderBySizeReverse SearchOrderBy = "size DESC" | |||||
| SearchOrderByID SearchOrderBy = "id ASC" | |||||
| SearchOrderByIDReverse SearchOrderBy = "id DESC" | |||||
| SearchOrderByStars SearchOrderBy = "num_stars ASC" | |||||
| SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" | |||||
| SearchOrderByForks SearchOrderBy = "num_forks ASC" | |||||
| SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" | |||||
| SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" | |||||
| SearchOrderByUseCount SearchOrderBy = "use_count ASC" | |||||
| SearchOrderByUseCountReverse SearchOrderBy = "use_count DESC" | |||||
| SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" | |||||
| SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" | |||||
| SearchOrderByWatches SearchOrderBy = "num_watches DESC" | |||||
| SearchOrderByDefault SearchOrderBy = "recommend desc,num_stars DESC,updated_unix DESC" | |||||
| SearchOrderByAiTaskCntReverse SearchOrderBy = "ai_task_cnt desc" | |||||
| SearchOrderByModelCntReverse SearchOrderBy = "model_cnt desc" | |||||
| SearchOrderByDatasetCntReverse SearchOrderBy = "dataset_cnt desc" | |||||
| SearchOrderByLastMonthVisitsReverse SearchOrderBy = "last_month_visits desc" | |||||
| SearchOrderByLastFourMonthCommitsReverse SearchOrderBy = "last_four_month_commits desc" | |||||
| ) | ) | ||||
| // SearchRepositoryCondition creates a query condition according search repository options | // SearchRepositoryCondition creates a query condition according search repository options | ||||
| @@ -200,3 +200,23 @@ func UpdateRepoStatVisits(repoStat *RepoStatistic) error { | |||||
| _, err := xStatistic.Exec(sql, repoStat.NumVisits, repoStat.RepoID, repoStat.Date) | _, err := xStatistic.Exec(sql, repoStat.NumVisits, repoStat.RepoID, repoStat.Date) | ||||
| return err | return err | ||||
| } | } | ||||
| func SumRepoStatColumn(begin, end time.Time, repoId int64, columnName string) (int64, error) { | |||||
| res, err := xStatistic.Where("created_unix <= ? and created_unix >= ? and repo_id = ? ", end.Unix(), begin.Unix(), repoId).Sum(&RepoStatistic{}, columnName) | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| return int64(res), nil | |||||
| } | |||||
| func SumLastMonthNumVisits(repoId int64) (int64, error) { | |||||
| end := time.Now() | |||||
| begin := end.AddDate(0, 0, -30) | |||||
| return SumRepoStatColumn(begin, end, repoId, "num_visits") | |||||
| } | |||||
| func SumLastFourMonthNumCommits(repoId int64) (int64, error) { | |||||
| end := time.Now() | |||||
| begin := end.AddDate(0, 0, -120) | |||||
| return SumRepoStatColumn(begin, end, repoId, "num_commits_added") | |||||
| } | |||||
| @@ -4,6 +4,7 @@ import ( | |||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
| "fmt" | "fmt" | ||||
| "xorm.io/builder" | |||||
| ) | ) | ||||
| type OfficialTag struct { | type OfficialTag struct { | ||||
| @@ -166,3 +167,33 @@ func GetAllOfficialTags() ([]OfficialTag, error) { | |||||
| } | } | ||||
| return o, nil | return o, nil | ||||
| } | } | ||||
| type FindSelectedReposOpts struct { | |||||
| ListOptions | |||||
| OrgId int64 | |||||
| OnlyPublic bool | |||||
| } | |||||
| func GetSelectedRepos(opts FindSelectedReposOpts) ([]*Repository, error) { | |||||
| if opts.Page < 1 { | |||||
| opts.Page = 1 | |||||
| } | |||||
| var cond = builder.NewCond() | |||||
| cond = cond.And(builder.Eq{"official_tag.code": "selected"}) | |||||
| if opts.OrgId > 0 { | |||||
| cond = cond.And(builder.Eq{"official_tag_repos.org_id": opts.OrgId}) | |||||
| } | |||||
| if opts.OnlyPublic { | |||||
| cond = cond.And(builder.Eq{"repository.is_private": false}) | |||||
| } | |||||
| t := make([]*Repository, 0) | |||||
| err := x.Join("inner", "official_tag_repos", "repository.id = official_tag_repos.repo_id"). | |||||
| Join("inner", "official_tag", "official_tag.id = official_tag_repos.tag_id"). | |||||
| Where(cond).OrderBy("repository.updated_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&t) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return t, nil | |||||
| } | |||||
| @@ -9,6 +9,7 @@ import ( | |||||
| "regexp" | "regexp" | ||||
| "strings" | "strings" | ||||
| "unicode/utf8" | "unicode/utf8" | ||||
| "xorm.io/xorm" | |||||
| "code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
| @@ -337,3 +338,16 @@ func GetOrgTopics(orgId int64) ([]Topic, error) { | |||||
| return result, nil | return result, nil | ||||
| } | } | ||||
| func UpdateRepoTopics(repoID int64, topicNames []string, sess ...*xorm.Engine) error { | |||||
| e := x | |||||
| if len(sess) > 0 { | |||||
| e = sess[0] | |||||
| } | |||||
| if _, err := e.ID(repoID).Cols("topics").Update(&Repository{ | |||||
| Topics: topicNames, | |||||
| }); err != nil { | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| @@ -198,6 +198,40 @@ type SearchOrganizationsOptions struct { | |||||
| All bool | All bool | ||||
| } | } | ||||
| type User4Front struct { | |||||
| ID int64 | |||||
| LowerName string `xorm:"UNIQUE NOT NULL"` | |||||
| Name string `xorm:"UNIQUE NOT NULL"` | |||||
| FullName string | |||||
| Email string `xorm:"NOT NULL"` | |||||
| Language string `xorm:"VARCHAR(5)"` | |||||
| Description string | |||||
| RelAvatarLink string | |||||
| NumMembers int | |||||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||||
| } | |||||
| func (u *User) ToFrontFormat() *User4Front { | |||||
| uf := &User4Front{ | |||||
| ID: u.ID, | |||||
| LowerName: u.LowerName, | |||||
| Name: u.Name, | |||||
| FullName: u.FullName, | |||||
| Email: u.Email, | |||||
| Language: u.Language, | |||||
| Description: u.Description, | |||||
| CreatedUnix: u.CreatedUnix, | |||||
| UpdatedUnix: u.UpdatedUnix, | |||||
| NumMembers: u.NumMembers, | |||||
| } | |||||
| if !u.KeepEmailPrivate { | |||||
| uf.Email = u.Email | |||||
| } | |||||
| uf.RelAvatarLink = u.RelAvatarLink() | |||||
| return uf | |||||
| } | |||||
| // GenerateRandomAvatar generates a random avatar for user. | // GenerateRandomAvatar generates a random avatar for user. | ||||
| func (u *User) IsBindWechat() bool { | func (u *User) IsBindWechat() bool { | ||||
| return u.WechatOpenId != "" | return u.WechatOpenId != "" | ||||
| @@ -449,3 +449,20 @@ func QueryUserLoginInfo(userIds []int64) []*UserLoginLog { | |||||
| return loginList | return loginList | ||||
| } | } | ||||
| func QueryUserAnnualReport(userId int64) *UserSummaryCurrentYear { | |||||
| statictisSess := xStatistic.NewSession() | |||||
| defer statictisSess.Close() | |||||
| log.Info("userId=" + fmt.Sprint(userId)) | |||||
| reList := make([]*UserSummaryCurrentYear, 0) | |||||
| err := statictisSess.Select("*").Table(new(UserSummaryCurrentYear)).Where("id=" + fmt.Sprint(userId)).Find(&reList) | |||||
| if err == nil { | |||||
| if len(reList) > 0 { | |||||
| return reList[0] | |||||
| } | |||||
| } else { | |||||
| log.Info("error:=" + err.Error()) | |||||
| } | |||||
| return nil | |||||
| } | |||||
| @@ -132,11 +132,17 @@ func makeResultForMonth(allUserInfo []*UserMetrics, count int) []*UserMetrics { | |||||
| if count > 0 { | if count > 0 { | ||||
| for _, userMetrics := range allUserInfo { | for _, userMetrics := range allUserInfo { | ||||
| dateTime := time.Unix(userMetrics.CountDate, 0) | dateTime := time.Unix(userMetrics.CountDate, 0) | ||||
| month := fmt.Sprint(dateTime.Year()) + "-" + fmt.Sprint(int(dateTime.Month())) | |||||
| mInt := int(dateTime.Month()) | |||||
| mString := fmt.Sprint(mInt) | |||||
| if mInt < 10 { | |||||
| mString = "0" + mString | |||||
| } | |||||
| month := fmt.Sprint(dateTime.Year()) + "-" + mString | |||||
| if _, ok := monthMap[month]; !ok { | if _, ok := monthMap[month]; !ok { | ||||
| monthUserMetrics := &UserMetrics{ | monthUserMetrics := &UserMetrics{ | ||||
| DisplayDate: month, | DisplayDate: month, | ||||
| ActivateRegistUser: userMetrics.ActivateRegistUser, | ActivateRegistUser: userMetrics.ActivateRegistUser, | ||||
| RegistActivityUser: userMetrics.RegistActivityUser, | |||||
| NotActivateRegistUser: userMetrics.NotActivateRegistUser, | NotActivateRegistUser: userMetrics.NotActivateRegistUser, | ||||
| TotalUser: userMetrics.TotalUser, | TotalUser: userMetrics.TotalUser, | ||||
| TotalNotActivateRegistUser: userMetrics.TotalUser - userMetrics.TotalActivateRegistUser, | TotalNotActivateRegistUser: userMetrics.TotalUser - userMetrics.TotalActivateRegistUser, | ||||
| @@ -152,6 +158,7 @@ func makeResultForMonth(allUserInfo []*UserMetrics, count int) []*UserMetrics { | |||||
| value.ActivateRegistUser += userMetrics.ActivateRegistUser | value.ActivateRegistUser += userMetrics.ActivateRegistUser | ||||
| value.NotActivateRegistUser += userMetrics.NotActivateRegistUser | value.NotActivateRegistUser += userMetrics.NotActivateRegistUser | ||||
| value.HasActivityUser += userMetrics.HasActivityUser | value.HasActivityUser += userMetrics.HasActivityUser | ||||
| value.RegistActivityUser += userMetrics.RegistActivityUser | |||||
| value.TotalRegistUser += userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser | value.TotalRegistUser += userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser | ||||
| value.ActivateIndex = float64(value.ActivateRegistUser) / float64(value.TotalRegistUser) | value.ActivateIndex = float64(value.ActivateRegistUser) / float64(value.TotalRegistUser) | ||||
| value.DaysForMonth += 1 | value.DaysForMonth += 1 | ||||
| @@ -348,6 +355,7 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi | |||||
| OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix) | OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix) | ||||
| CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | ||||
| AiModelManageMap := queryUserModel(start_unix, end_unix) | AiModelManageMap := queryUserModel(start_unix, end_unix) | ||||
| AiModelConvertMap := queryUserModelConvert(start_unix, end_unix) | |||||
| CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix) | CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix) | ||||
| RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix) | RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix) | ||||
| @@ -420,6 +428,7 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi | |||||
| dateRecord.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | dateRecord.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | ||||
| dateRecord.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | dateRecord.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | ||||
| dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap) | dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap) | ||||
| dateRecord.ModelConvertCount = getMapValue(dateRecord.ID, AiModelConvertMap) | |||||
| dateRecord.CollectDataset = getMapValue(dateRecord.ID, CollectDataset) | dateRecord.CollectDataset = getMapValue(dateRecord.ID, CollectDataset) | ||||
| dateRecord.CollectedDataset = getMapValue(dateRecord.ID, CollectedDataset) | dateRecord.CollectedDataset = getMapValue(dateRecord.ID, CollectedDataset) | ||||
| @@ -539,6 +548,7 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus | |||||
| resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize | resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize | ||||
| resultMap[userRecord.ID].CommitDatasetNum += userRecord.CommitDatasetNum | resultMap[userRecord.ID].CommitDatasetNum += userRecord.CommitDatasetNum | ||||
| resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount | resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount | ||||
| resultMap[userRecord.ID].ModelConvertCount += userRecord.ModelConvertCount | |||||
| resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount | resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount | ||||
| resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount | resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount | ||||
| resultMap[userRecord.ID].CreateRepoCount += userRecord.CreateRepoCount | resultMap[userRecord.ID].CreateRepoCount += userRecord.CreateRepoCount | ||||
| @@ -576,7 +586,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||||
| startTime := currentTimeNow.AddDate(0, 0, -1) | startTime := currentTimeNow.AddDate(0, 0, -1) | ||||
| CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | ||||
| CommitCountMap, mostActiveMap := queryCommitAction(start_unix, end_unix, 5) | |||||
| CommitCountMap, _ := queryCommitAction(start_unix, end_unix, 5) | |||||
| IssueCountMap := queryCreateIssue(start_unix, end_unix) | IssueCountMap := queryCreateIssue(start_unix, end_unix) | ||||
| CommentCountMap := queryComment(start_unix, end_unix) | CommentCountMap := queryComment(start_unix, end_unix) | ||||
| @@ -592,29 +602,25 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||||
| //log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson)) | //log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson)) | ||||
| } | } | ||||
| //CommitCodeSizeMap := queryCommitCodeSize(StartTimeNextDay.Unix(), EndTimeNextDay.Unix()) | //CommitCodeSizeMap := queryCommitCodeSize(StartTimeNextDay.Unix(), EndTimeNextDay.Unix()) | ||||
| CommitDatasetSizeMap, CommitDatasetNumMap, dataSetDownloadMap := queryDatasetSize(start_unix, end_unix) | |||||
| CommitDatasetSizeMap, CommitDatasetNumMap, _ := queryDatasetSize(start_unix, end_unix) | |||||
| SolveIssueCountMap := querySolveIssue(start_unix, end_unix) | SolveIssueCountMap := querySolveIssue(start_unix, end_unix) | ||||
| CreateRepoCountMap, DetailInfoMap, MostDownloadMap := queryUserCreateRepo(start_unix, end_unix) | |||||
| CreateRepoCountMap, _, _ := queryUserCreateRepo(start_unix, end_unix) | |||||
| LoginCountMap := queryLoginCount(start_unix, end_unix) | LoginCountMap := queryLoginCount(start_unix, end_unix) | ||||
| OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix) | OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix) | ||||
| CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | ||||
| AiModelManageMap := queryUserModel(start_unix, end_unix) | AiModelManageMap := queryUserModel(start_unix, end_unix) | ||||
| AiModelConvertMap := queryUserModelConvert(start_unix, end_unix) | |||||
| CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix) | CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix) | ||||
| RecommendDataset, CreatedDataset := queryRecommedDataSet(start_unix, end_unix) | |||||
| RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix) | |||||
| CollectImage, CollectedImage := queryImageStars(start_unix, end_unix) | CollectImage, CollectedImage := queryImageStars(start_unix, end_unix) | ||||
| RecommendImage := queryRecommedImage(start_unix, end_unix) | RecommendImage := queryRecommedImage(start_unix, end_unix) | ||||
| InvitationMap := queryUserInvitationCount(start_unix, end_unix) | InvitationMap := queryUserInvitationCount(start_unix, end_unix) | ||||
| DataDate := currentTimeNow.Format("2006-01-02") + " 00:01" | DataDate := currentTimeNow.Format("2006-01-02") + " 00:01" | ||||
| bonusMap := make(map[string]map[string]int) | |||||
| if tableName == "user_business_analysis_current_year" { | |||||
| bonusMap = getBonusMap() | |||||
| log.Info("truncate all data from table:user_summary_current_year ") | |||||
| statictisSess.Exec("TRUNCATE TABLE user_summary_current_year") | |||||
| } | |||||
| cond := "type != 1 and is_active=true" | cond := "type != 1 and is_active=true" | ||||
| count, err := sess.Where(cond).Count(new(User)) | count, err := sess.Where(cond).Count(new(User)) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -680,6 +686,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||||
| dateRecordAll.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | dateRecordAll.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | ||||
| dateRecordAll.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | dateRecordAll.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | ||||
| dateRecordAll.CommitModelCount = getMapValue(dateRecordAll.ID, AiModelManageMap) | dateRecordAll.CommitModelCount = getMapValue(dateRecordAll.ID, AiModelManageMap) | ||||
| dateRecordAll.ModelConvertCount = getMapValue(dateRecordAll.ID, AiModelConvertMap) | |||||
| dateRecordAll.CollectDataset = getMapValue(dateRecordAll.ID, CollectDataset) | dateRecordAll.CollectDataset = getMapValue(dateRecordAll.ID, CollectDataset) | ||||
| dateRecordAll.CollectedDataset = getMapValue(dateRecordAll.ID, CollectedDataset) | dateRecordAll.CollectedDataset = getMapValue(dateRecordAll.ID, CollectedDataset) | ||||
| dateRecordAll.RecommendDataset = getMapValue(dateRecordAll.ID, RecommendDataset) | dateRecordAll.RecommendDataset = getMapValue(dateRecordAll.ID, RecommendDataset) | ||||
| @@ -712,37 +719,6 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||||
| userMetrics["TotalHasActivityUser"] = getMapKeyStringValue("TotalHasActivityUser", userMetrics) + 1 | userMetrics["TotalHasActivityUser"] = getMapKeyStringValue("TotalHasActivityUser", userMetrics) + 1 | ||||
| } | } | ||||
| } | } | ||||
| if tableName == "user_business_analysis_current_year" { | |||||
| //年度数据 | |||||
| subTime := time.Now().UTC().Sub(dateRecordAll.RegistDate.AsTime().UTC()) | |||||
| mostActiveDay := "" | |||||
| if userInfo, ok := mostActiveMap[dateRecordAll.ID]; ok { | |||||
| mostActiveDay = getMostActiveJson(userInfo) | |||||
| } | |||||
| scoreMap := make(map[string]float64) | |||||
| repoInfo := getRepoDetailInfo(DetailInfoMap, dateRecordAll.ID, MostDownloadMap) | |||||
| dataSetInfo, datasetscore := getDataSetInfo(dateRecordAll.ID, CreatedDataset, dataSetDownloadMap, CommitDatasetNumMap, CollectedDataset) | |||||
| scoreMap["datasetscore"] = datasetscore | |||||
| codeInfo, codescore := getCodeInfo(dateRecordAll) | |||||
| scoreMap["codescore"] = codescore | |||||
| cloudBrainInfo := getCloudBrainInfo(dateRecordAll, CloudBrainTaskItemMap, scoreMap) | |||||
| playARoll := getPlayARoll(bonusMap, dateRecordAll.Name, scoreMap) | |||||
| re := &UserSummaryCurrentYear{ | |||||
| ID: dateRecordAll.ID, | |||||
| Name: dateRecordAll.Name, | |||||
| Email: dateRecordAll.Email, | |||||
| Phone: dateRecordAll.Phone, | |||||
| RegistDate: dateRecordAll.RegistDate, | |||||
| DateCount: int(subTime.Hours()) / 24, | |||||
| MostActiveDay: mostActiveDay, | |||||
| RepoInfo: repoInfo, | |||||
| DataSetInfo: dataSetInfo, | |||||
| CodeInfo: codeInfo, | |||||
| CloudBrainInfo: cloudBrainInfo, | |||||
| PlayARoll: playARoll, | |||||
| } | |||||
| statictisSess.Insert(re) | |||||
| } | |||||
| } | } | ||||
| if len(dateRecordBatch) > 0 { | if len(dateRecordBatch) > 0 { | ||||
| err := insertTable(dateRecordBatch, tableName, statictisSess) | err := insertTable(dateRecordBatch, tableName, statictisSess) | ||||
| @@ -772,6 +748,138 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||||
| log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount)) | log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount)) | ||||
| } | } | ||||
| func RefreshUserYearTable(pageStartTime time.Time, pageEndTime time.Time) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| log.Info("RefreshUserYearTable start....") | |||||
| statictisSess := xStatistic.NewSession() | |||||
| defer statictisSess.Close() | |||||
| log.Info("UserYear StartTime:" + pageStartTime.Format("2006-01-02 15:04:05")) | |||||
| log.Info("UserYear EndTime time:" + pageEndTime.Format("2006-01-02 15:04:05")) | |||||
| start_unix := pageStartTime.Unix() | |||||
| end_unix := pageEndTime.Unix() | |||||
| CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||||
| CommitCountMap, mostActiveMap := queryCommitAction(start_unix, end_unix, 5) | |||||
| IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||||
| CommentCountMap := queryComment(start_unix, end_unix) | |||||
| CommitCodeSizeMap, err := GetAllUserKPIStats(pageStartTime, pageEndTime) | |||||
| if err != nil { | |||||
| log.Info("query commit code errr.") | |||||
| } else { | |||||
| log.Info("query commit code size, len=" + fmt.Sprint(len(CommitCodeSizeMap))) | |||||
| } | |||||
| CommitDatasetSizeMap, CommitDatasetNumMap, dataSetDownloadMap := queryDatasetSize(start_unix, end_unix) | |||||
| SolveIssueCountMap := querySolveIssue(start_unix, end_unix) | |||||
| CreateRepoCountMap, DetailInfoMap, MostDownloadMap := queryUserCreateRepo(start_unix, end_unix) | |||||
| CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | |||||
| _, CollectedDataset := queryDatasetStars(start_unix, end_unix) | |||||
| _, CreatedDataset := queryRecommedDataSet(start_unix, end_unix) | |||||
| bonusMap := getBonusMap() | |||||
| log.Info("truncate all data from table:user_summary_current_year ") | |||||
| statictisSess.Exec("TRUNCATE TABLE user_summary_current_year") | |||||
| cond := "type != 1 and is_active=true" | |||||
| count, err := sess.Where(cond).Count(new(User)) | |||||
| if err != nil { | |||||
| log.Info("query user error. return.") | |||||
| return | |||||
| } | |||||
| var indexTotal int64 | |||||
| indexTotal = 0 | |||||
| for { | |||||
| sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||||
| userList := make([]*User, 0) | |||||
| sess.Find(&userList) | |||||
| for _, userRecord := range userList { | |||||
| var dateRecordAll UserBusinessAnalysisAll | |||||
| dateRecordAll.ID = userRecord.ID | |||||
| dateRecordAll.Email = userRecord.Email | |||||
| dateRecordAll.Phone = userRecord.PhoneNumber | |||||
| dateRecordAll.RegistDate = userRecord.CreatedUnix | |||||
| dateRecordAll.Name = userRecord.Name | |||||
| dateRecordAll.CodeMergeCount = getMapValue(dateRecordAll.ID, CodeMergeCountMap) | |||||
| dateRecordAll.CommitCount = getMapValue(dateRecordAll.ID, CommitCountMap) | |||||
| dateRecordAll.IssueCount = getMapValue(dateRecordAll.ID, IssueCountMap) | |||||
| dateRecordAll.CommentCount = getMapValue(dateRecordAll.ID, CommentCountMap) | |||||
| if _, ok := CommitCodeSizeMap[dateRecordAll.Email]; !ok { | |||||
| dateRecordAll.CommitCodeSize = 0 | |||||
| } else { | |||||
| dateRecordAll.CommitCodeSize = int(CommitCodeSizeMap[dateRecordAll.Email].CommitLines) | |||||
| } | |||||
| //dateRecordAll.CommitCodeSize = getMapValue(dateRecordAll.ID, CommitCodeSizeMap) | |||||
| dateRecordAll.CommitDatasetSize = getMapValue(dateRecordAll.ID, CommitDatasetSizeMap) | |||||
| dateRecordAll.CommitDatasetNum = getMapValue(dateRecordAll.ID, CommitDatasetNumMap) | |||||
| dateRecordAll.SolveIssueCount = getMapValue(dateRecordAll.ID, SolveIssueCountMap) | |||||
| dateRecordAll.CreateRepoCount = getMapValue(dateRecordAll.ID, CreateRepoCountMap) | |||||
| dateRecordAll.CloudBrainTaskNum = getMapValue(dateRecordAll.ID, CloudBrainTaskMap) | |||||
| dateRecordAll.GpuDebugJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuDebugJob", CloudBrainTaskItemMap) | |||||
| dateRecordAll.NpuDebugJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_NpuDebugJob", CloudBrainTaskItemMap) | |||||
| dateRecordAll.GpuTrainJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuTrainJob", CloudBrainTaskItemMap) | |||||
| dateRecordAll.NpuTrainJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_NpuTrainJob", CloudBrainTaskItemMap) | |||||
| dateRecordAll.NpuInferenceJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_NpuInferenceJob", CloudBrainTaskItemMap) | |||||
| dateRecordAll.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | |||||
| dateRecordAll.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | |||||
| //年度数据 | |||||
| subTime := time.Now().UTC().Sub(dateRecordAll.RegistDate.AsTime().UTC()) | |||||
| mostActiveDay := "" | |||||
| if userInfo, ok := mostActiveMap[dateRecordAll.ID]; ok { | |||||
| mostActiveDay = getMostActiveJson(userInfo) | |||||
| } | |||||
| scoreMap := make(map[string]float64) | |||||
| repoInfo := getRepoDetailInfo(DetailInfoMap, dateRecordAll.ID, MostDownloadMap) | |||||
| dataSetInfo, datasetscore := getDataSetInfo(dateRecordAll.ID, CreatedDataset, dataSetDownloadMap, CommitDatasetNumMap, CollectedDataset) | |||||
| scoreMap["datasetscore"] = datasetscore | |||||
| codeInfo, codescore := getCodeInfo(dateRecordAll) | |||||
| scoreMap["codescore"] = codescore | |||||
| cloudBrainInfo := getCloudBrainInfo(dateRecordAll, CloudBrainTaskItemMap, scoreMap) | |||||
| playARoll := getPlayARoll(bonusMap, dateRecordAll.Name, scoreMap) | |||||
| re := &UserSummaryCurrentYear{ | |||||
| ID: dateRecordAll.ID, | |||||
| Name: dateRecordAll.Name, | |||||
| Email: dateRecordAll.Email, | |||||
| Phone: dateRecordAll.Phone, | |||||
| RegistDate: dateRecordAll.RegistDate, | |||||
| DateCount: int(subTime.Hours()) / 24, | |||||
| MostActiveDay: mostActiveDay, | |||||
| RepoInfo: repoInfo, | |||||
| DataSetInfo: dataSetInfo, | |||||
| CodeInfo: codeInfo, | |||||
| CloudBrainInfo: cloudBrainInfo, | |||||
| PlayARoll: playARoll, | |||||
| } | |||||
| statictisSess.Insert(re) | |||||
| } | |||||
| indexTotal += PAGE_SIZE | |||||
| if indexTotal >= count { | |||||
| break | |||||
| } | |||||
| } | |||||
| log.Info("update user year data finished. ") | |||||
| } | |||||
| func isUserYearData(tableName string) bool { | |||||
| if tableName == "user_business_analysis_current_year" { | |||||
| currentTimeNow := time.Now() | |||||
| if currentTimeNow.Year() >= 2023 { | |||||
| return false | |||||
| } | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| func getBonusMap() map[string]map[string]int { | func getBonusMap() map[string]map[string]int { | ||||
| bonusMap := make(map[string]map[string]int) | bonusMap := make(map[string]map[string]int) | ||||
| url := setting.RecommentRepoAddr + "bonus/record.txt" | url := setting.RecommentRepoAddr + "bonus/record.txt" | ||||
| @@ -794,6 +902,7 @@ func getBonusMap() map[string]map[string]int { | |||||
| record, ok := bonusMap[userName] | record, ok := bonusMap[userName] | ||||
| if !ok { | if !ok { | ||||
| record = make(map[string]int) | record = make(map[string]int) | ||||
| bonusMap[userName] = record | |||||
| } | } | ||||
| record["times"] = getMapKeyStringValue("times", record) + getIntValue(aLine[3]) | record["times"] = getMapKeyStringValue("times", record) + getIntValue(aLine[3]) | ||||
| record["total_bonus"] = getMapKeyStringValue("total_bonus", record) + getIntValue(aLine[4]) | record["total_bonus"] = getMapKeyStringValue("total_bonus", record) + getIntValue(aLine[4]) | ||||
| @@ -979,7 +1088,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||||
| insertBatchSql := "INSERT INTO public." + tableName + | insertBatchSql := "INSERT INTO public." + tableName + | ||||
| "(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + | "(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + | ||||
| "commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive,phone,invitation_user_num) " + | |||||
| "commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive,phone,invitation_user_num,model_convert_count) " + | |||||
| "VALUES" | "VALUES" | ||||
| for i, record := range dateRecords { | for i, record := range dateRecords { | ||||
| @@ -988,7 +1097,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||||
| ", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) + | ", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) + | ||||
| ", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) + | ", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) + | ||||
| ", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "'," + fmt.Sprint(record.CloudBrainTaskNum) + "," + fmt.Sprint(record.GpuDebugJob) + "," + fmt.Sprint(record.NpuDebugJob) + "," + fmt.Sprint(record.GpuTrainJob) + "," + fmt.Sprint(record.NpuTrainJob) + "," + fmt.Sprint(record.NpuInferenceJob) + "," + fmt.Sprint(record.GpuBenchMarkJob) + "," + fmt.Sprint(record.CloudBrainRunTime) + "," + fmt.Sprint(record.CommitDatasetNum) + "," + fmt.Sprint(record.UserIndex) + ",'" + record.UserLocation + "'," + | ", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "'," + fmt.Sprint(record.CloudBrainTaskNum) + "," + fmt.Sprint(record.GpuDebugJob) + "," + fmt.Sprint(record.NpuDebugJob) + "," + fmt.Sprint(record.GpuTrainJob) + "," + fmt.Sprint(record.NpuTrainJob) + "," + fmt.Sprint(record.NpuInferenceJob) + "," + fmt.Sprint(record.GpuBenchMarkJob) + "," + fmt.Sprint(record.CloudBrainRunTime) + "," + fmt.Sprint(record.CommitDatasetNum) + "," + fmt.Sprint(record.UserIndex) + ",'" + record.UserLocation + "'," + | ||||
| fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ",'" + record.Phone + "'" + "," + fmt.Sprint(record.InvitationUserNum) + ")" | |||||
| fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ",'" + record.Phone + "'" + "," + fmt.Sprint(record.InvitationUserNum) + "," + fmt.Sprint(record.ModelConvertCount) + ")" | |||||
| if i < (len(dateRecords) - 1) { | if i < (len(dateRecords) - 1) { | ||||
| insertBatchSql += "," | insertBatchSql += "," | ||||
| } | } | ||||
| @@ -1079,6 +1188,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||||
| OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix) | OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix) | ||||
| CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix) | ||||
| AiModelManageMap := queryUserModel(start_unix, end_unix) | AiModelManageMap := queryUserModel(start_unix, end_unix) | ||||
| AiModelConvertMap := queryUserModelConvert(start_unix, end_unix) | |||||
| CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix) | CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix) | ||||
| RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix) | RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix) | ||||
| @@ -1160,7 +1270,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||||
| dateRecord.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | dateRecord.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | ||||
| dateRecord.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | dateRecord.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap) | ||||
| dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap) | dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap) | ||||
| dateRecord.ModelConvertCount = getMapValue(dateRecord.ID, AiModelConvertMap) | |||||
| dateRecord.CollectDataset = getMapValue(dateRecord.ID, CollectDataset) | dateRecord.CollectDataset = getMapValue(dateRecord.ID, CollectDataset) | ||||
| dateRecord.CollectedDataset = getMapValue(dateRecord.ID, CollectedDataset) | dateRecord.CollectedDataset = getMapValue(dateRecord.ID, CollectedDataset) | ||||
| dateRecord.RecommendDataset = getMapValue(dateRecord.ID, RecommendDataset) | dateRecord.RecommendDataset = getMapValue(dateRecord.ID, RecommendDataset) | ||||
| @@ -1349,6 +1459,7 @@ func getUserIndexFromAnalysisAll(dateRecord UserBusinessAnalysisAll, ParaWeight | |||||
| result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05) | result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05) | ||||
| result += float64(dateRecord.CloudBrainTaskNum) * getParaWeightValue("CloudBrainTaskNum", ParaWeight, 0.3) | result += float64(dateRecord.CloudBrainTaskNum) * getParaWeightValue("CloudBrainTaskNum", ParaWeight, 0.3) | ||||
| result += float64(dateRecord.CommitModelCount) * getParaWeightValue("CommitModelCount", ParaWeight, 0.2) | result += float64(dateRecord.CommitModelCount) * getParaWeightValue("CommitModelCount", ParaWeight, 0.2) | ||||
| result += float64(dateRecord.ModelConvertCount) * getParaWeightValue("ModelConvertCount", ParaWeight, 0.2) | |||||
| result += dateRecord.OpenIIndex * getParaWeightValue("OpenIIndex", ParaWeight, 0.1) | result += dateRecord.OpenIIndex * getParaWeightValue("OpenIIndex", ParaWeight, 0.1) | ||||
| result += float64(dateRecord.CollectDataset) * getParaWeightValue("CollectDataset", ParaWeight, 0.1) | result += float64(dateRecord.CollectDataset) * getParaWeightValue("CollectDataset", ParaWeight, 0.1) | ||||
| @@ -1374,6 +1485,7 @@ func getUserActivateAll(dateRecord UserBusinessAnalysisAll) int { | |||||
| result += dateRecord.CreateRepoCount | result += dateRecord.CreateRepoCount | ||||
| result += dateRecord.CloudBrainTaskNum | result += dateRecord.CloudBrainTaskNum | ||||
| result += dateRecord.CommitModelCount | result += dateRecord.CommitModelCount | ||||
| result += dateRecord.ModelConvertCount | |||||
| result += dateRecord.CommitDatasetNum | result += dateRecord.CommitDatasetNum | ||||
| result += dateRecord.FocusOtherUser | result += dateRecord.FocusOtherUser | ||||
| result += dateRecord.CollectDataset | result += dateRecord.CollectDataset | ||||
| @@ -1395,6 +1507,7 @@ func getUserActivate(dateRecord UserBusinessAnalysis) int { | |||||
| result += dateRecord.CreateRepoCount | result += dateRecord.CreateRepoCount | ||||
| result += dateRecord.CloudBrainTaskNum | result += dateRecord.CloudBrainTaskNum | ||||
| result += dateRecord.CommitModelCount | result += dateRecord.CommitModelCount | ||||
| result += dateRecord.ModelConvertCount | |||||
| result += dateRecord.CommitDatasetNum | result += dateRecord.CommitDatasetNum | ||||
| result += dateRecord.FocusOtherUser | result += dateRecord.FocusOtherUser | ||||
| result += dateRecord.CollectDataset | result += dateRecord.CollectDataset | ||||
| @@ -1431,6 +1544,7 @@ func getUserIndex(dateRecord UserBusinessAnalysis, ParaWeight map[string]float64 | |||||
| result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05) | result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05) | ||||
| result += float64(dateRecord.CloudBrainTaskNum) * getParaWeightValue("CloudBrainTaskNum", ParaWeight, 0.3) | result += float64(dateRecord.CloudBrainTaskNum) * getParaWeightValue("CloudBrainTaskNum", ParaWeight, 0.3) | ||||
| result += float64(dateRecord.CommitModelCount) * getParaWeightValue("CommitModelCount", ParaWeight, 0.2) | result += float64(dateRecord.CommitModelCount) * getParaWeightValue("CommitModelCount", ParaWeight, 0.2) | ||||
| result += float64(dateRecord.ModelConvertCount) * getParaWeightValue("ModelConvertCount", ParaWeight, 0.2) | |||||
| result += dateRecord.OpenIIndex * getParaWeightValue("OpenIIndex", ParaWeight, 0.1) | result += dateRecord.OpenIIndex * getParaWeightValue("OpenIIndex", ParaWeight, 0.1) | ||||
| result += float64(dateRecord.CollectDataset) * getParaWeightValue("CollectDataset", ParaWeight, 0.1) | result += float64(dateRecord.CollectDataset) * getParaWeightValue("CollectDataset", ParaWeight, 0.1) | ||||
| @@ -1475,10 +1589,6 @@ func getInt(str string) int { | |||||
| return int(re) | return int(re) | ||||
| } | } | ||||
| func CounDataByDate(wikiCountMap map[string]int, startTime time.Time, endTime time.Time) { | |||||
| CounDataByDateAndReCount(wikiCountMap, startTime, endTime, false) | |||||
| } | |||||
| func querySolveIssue(start_unix int64, end_unix int64) map[int64]int { | func querySolveIssue(start_unix int64, end_unix int64) map[int64]int { | ||||
| sess := x.NewSession() | sess := x.NewSession() | ||||
| defer sess.Close() | defer sess.Close() | ||||
| @@ -2259,6 +2369,38 @@ func queryUserModel(start_unix int64, end_unix int64) map[int64]int { | |||||
| return resultMap | return resultMap | ||||
| } | } | ||||
| func queryUserModelConvert(start_unix int64, end_unix int64) map[int64]int { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| resultMap := make(map[int64]int) | |||||
| cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||||
| count, err := sess.Where(cond).Count(new(AiModelConvert)) | |||||
| if err != nil { | |||||
| log.Info("query AiModelConvert error. return.") | |||||
| return resultMap | |||||
| } | |||||
| var indexTotal int64 | |||||
| indexTotal = 0 | |||||
| for { | |||||
| sess.Select("id,user_id").Table("ai_model_convert").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||||
| aiModelList := make([]*AiModelConvert, 0) | |||||
| sess.Find(&aiModelList) | |||||
| log.Info("query AiModelConvert size=" + fmt.Sprint(len(aiModelList))) | |||||
| for _, aiModelRecord := range aiModelList { | |||||
| if _, ok := resultMap[aiModelRecord.UserId]; !ok { | |||||
| resultMap[aiModelRecord.UserId] = 1 | |||||
| } else { | |||||
| resultMap[aiModelRecord.UserId] += 1 | |||||
| } | |||||
| } | |||||
| indexTotal += PAGE_SIZE | |||||
| if indexTotal >= count { | |||||
| break | |||||
| } | |||||
| } | |||||
| return resultMap | |||||
| } | |||||
| func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[string]int) { | func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[string]int) { | ||||
| sess := x.NewSession() | sess := x.NewSession() | ||||
| defer sess.Close() | defer sess.Close() | ||||
| @@ -2424,3 +2566,9 @@ func GetContentFromPromote(url string) (string, error) { | |||||
| allLineStr := string(bytes) | allLineStr := string(bytes) | ||||
| return allLineStr, nil | return allLineStr, nil | ||||
| } | } | ||||
| func QueryLast30DaysHighestIndexUsers(size int) ([]int64, error) { | |||||
| userIds := make([]int64, 0) | |||||
| err := xStatistic.Table("user_business_analysis_last30_day").Cols("id").OrderBy("user_index desc").Limit(size).Find(&userIds) | |||||
| return userIds, err | |||||
| } | |||||
| @@ -89,6 +89,7 @@ type UserBusinessAnalysisCurrentYear struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysisLast30Day struct { | type UserBusinessAnalysisLast30Day struct { | ||||
| @@ -157,6 +158,7 @@ type UserBusinessAnalysisLast30Day struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysisLastMonth struct { | type UserBusinessAnalysisLastMonth struct { | ||||
| @@ -225,6 +227,7 @@ type UserBusinessAnalysisLastMonth struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysisCurrentMonth struct { | type UserBusinessAnalysisCurrentMonth struct { | ||||
| @@ -293,6 +296,7 @@ type UserBusinessAnalysisCurrentMonth struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysisCurrentWeek struct { | type UserBusinessAnalysisCurrentWeek struct { | ||||
| @@ -362,6 +366,7 @@ type UserBusinessAnalysisCurrentWeek struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysisYesterday struct { | type UserBusinessAnalysisYesterday struct { | ||||
| @@ -431,6 +436,7 @@ type UserBusinessAnalysisYesterday struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysisLastWeek struct { | type UserBusinessAnalysisLastWeek struct { | ||||
| @@ -500,6 +506,7 @@ type UserBusinessAnalysisLastWeek struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserAnalysisPara struct { | type UserAnalysisPara struct { | ||||
| @@ -616,6 +623,7 @@ type UserBusinessAnalysisAll struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| type UserBusinessAnalysis struct { | type UserBusinessAnalysis struct { | ||||
| @@ -704,4 +712,5 @@ type UserBusinessAnalysis struct { | |||||
| Phone string `xorm:"NULL"` | Phone string `xorm:"NULL"` | ||||
| InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | ||||
| ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| @@ -13,6 +13,7 @@ type Invitation struct { | |||||
| SrcUserID int64 `xorm:"NOT NULL DEFAULT 0"` | SrcUserID int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
| UserID int64 `xorm:"NOT NULL DEFAULT 0"` | UserID int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
| Phone string `xorm:"INDEX"` | Phone string `xorm:"INDEX"` | ||||
| Email string `xorm:"-"` | |||||
| Avatar string `xorm:"-"` | Avatar string `xorm:"-"` | ||||
| Name string `xorm:"-"` | Name string `xorm:"-"` | ||||
| InvitationUserNum int `xorm:"-"` | InvitationUserNum int `xorm:"-"` | ||||
| @@ -281,7 +281,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin | |||||
| return nil | return nil | ||||
| } | } | ||||
| func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string,autoStopDurationInMs int64) (string, error) { | |||||
| func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string, autoStopDurationInMs int64) (string, error) { | |||||
| if poolInfos == nil { | if poolInfos == nil { | ||||
| json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | ||||
| } | } | ||||
| @@ -379,6 +379,9 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||||
| Parameter: req.Parameters, | Parameter: req.Parameters, | ||||
| UserImageUrl: req.UserImageUrl, | UserImageUrl: req.UserImageUrl, | ||||
| UserCommand: req.UserCommand, | UserCommand: req.UserCommand, | ||||
| ShareAddr: setting.ModelArtsShareAddr, | |||||
| MountPath: setting.ModelArtsMountPath, | |||||
| NasType: setting.ModelArtsNasType, | |||||
| }, | }, | ||||
| }) | }) | ||||
| } else { | } else { | ||||
| @@ -399,6 +402,9 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||||
| Code: req.Spec.SourceSpecId, | Code: req.Spec.SourceSpecId, | ||||
| }, | }, | ||||
| Parameter: req.Parameters, | Parameter: req.Parameters, | ||||
| ShareAddr: setting.ModelArtsShareAddr, | |||||
| MountPath: setting.ModelArtsMountPath, | |||||
| NasType: setting.ModelArtsNasType, | |||||
| }, | }, | ||||
| }) | }) | ||||
| } | } | ||||
| @@ -517,6 +523,9 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||||
| PreVersionId: req.PreVersionId, | PreVersionId: req.PreVersionId, | ||||
| UserImageUrl: req.UserImageUrl, | UserImageUrl: req.UserImageUrl, | ||||
| UserCommand: req.UserCommand, | UserCommand: req.UserCommand, | ||||
| ShareAddr: setting.ModelArtsShareAddr, | |||||
| MountPath: setting.ModelArtsMountPath, | |||||
| NasType: setting.ModelArtsNasType, | |||||
| }, | }, | ||||
| }, jobId) | }, jobId) | ||||
| } else { | } else { | ||||
| @@ -536,6 +545,9 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||||
| }, | }, | ||||
| Parameter: req.Parameters, | Parameter: req.Parameters, | ||||
| PreVersionId: req.PreVersionId, | PreVersionId: req.PreVersionId, | ||||
| ShareAddr: setting.ModelArtsShareAddr, | |||||
| MountPath: setting.ModelArtsMountPath, | |||||
| NasType: setting.ModelArtsNasType, | |||||
| }, | }, | ||||
| }, jobId) | }, jobId) | ||||
| } | } | ||||
| @@ -972,14 +984,14 @@ func getJupyterBaseUrl(url string) string { | |||||
| } | } | ||||
| func getCookiesAndCsrf(jupyterUrl string) ([]*http.Cookie, string) { | func getCookiesAndCsrf(jupyterUrl string) ([]*http.Cookie, string) { | ||||
| log.Info("jupyter url:"+jupyterUrl) | |||||
| log.Info("jupyter url:" + jupyterUrl) | |||||
| var cookies []*http.Cookie | var cookies []*http.Cookie | ||||
| const retryTimes = 10 | const retryTimes = 10 | ||||
| for i := 0; i < retryTimes; i++ { | for i := 0; i < retryTimes; i++ { | ||||
| res, err := http.Get(jupyterUrl) | res, err := http.Get(jupyterUrl) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("browser jupyterUrl failed.",err) | |||||
| if i==retryTimes-1{ | |||||
| log.Error("browser jupyterUrl failed.", err) | |||||
| if i == retryTimes-1 { | |||||
| return cookies, "" | return cookies, "" | ||||
| } | } | ||||
| @@ -497,7 +497,7 @@ sendjob: | |||||
| } | } | ||||
| req, _ := json.Marshal(createJobParams) | req, _ := json.Marshal(createJobParams) | ||||
| log.Info("%s", req) | |||||
| log.Info("postapi json: %s", req) | |||||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | ||||
| retry++ | retry++ | ||||
| @@ -543,6 +543,8 @@ func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.Create | |||||
| var result models.CreateTrainJobResult | var result models.CreateTrainJobResult | ||||
| retry := 0 | retry := 0 | ||||
| req, _ := json.Marshal(createJobParams) | |||||
| log.Info("postapi json: %s", req) | |||||
| sendjob: | sendjob: | ||||
| res, err := client.R(). | res, err := client.R(). | ||||
| @@ -0,0 +1,9 @@ | |||||
| package redis_key | |||||
| import "fmt" | |||||
| const REPO_PREFIX = "repo" | |||||
| func RepoTopNContributors(repoId int64, N int) string { | |||||
| return KeyJoin(REPO_PREFIX, fmt.Sprint(repoId), fmt.Sprint(N), "top_n_contributor") | |||||
| } | |||||
| @@ -585,6 +585,9 @@ var ( | |||||
| TrainJobFLAVORINFOS string | TrainJobFLAVORINFOS string | ||||
| ModelArtsSpecialPools string | ModelArtsSpecialPools string | ||||
| ModelArtsMultiNode string | ModelArtsMultiNode string | ||||
| ModelArtsShareAddr string | |||||
| ModelArtsMountPath string | |||||
| ModelArtsNasType string | |||||
| //kanban | //kanban | ||||
| IsCloudbrainTimingEnabled bool | IsCloudbrainTimingEnabled bool | ||||
| @@ -677,6 +680,10 @@ var ( | |||||
| CloudbrainStoppedTitle string | CloudbrainStoppedTitle string | ||||
| CloudbrainStoppedRemark string | CloudbrainStoppedRemark string | ||||
| //repo square config | |||||
| IncubationSourceOrgName string | |||||
| PaperRepoTopicName string | |||||
| //nginx proxy | //nginx proxy | ||||
| PROXYURL string | PROXYURL string | ||||
| RadarMap = struct { | RadarMap = struct { | ||||
| @@ -1553,6 +1560,9 @@ func NewContext() { | |||||
| TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("") | TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("") | ||||
| ModelArtsSpecialPools = sec.Key("SPECIAL_POOL").MustString("") | ModelArtsSpecialPools = sec.Key("SPECIAL_POOL").MustString("") | ||||
| ModelArtsMultiNode = sec.Key("MULTI_NODE").MustString("") | ModelArtsMultiNode = sec.Key("MULTI_NODE").MustString("") | ||||
| ModelArtsShareAddr = sec.Key("ModelArts_Share_Addr").MustString("192.168.0.30:/") | |||||
| ModelArtsMountPath = sec.Key("ModelArts_Mount_Path").MustString("/cache/sfs") | |||||
| ModelArtsNasType = sec.Key("ModelArts_Nas_Type").MustString("nfs") | |||||
| sec = Cfg.Section("elk") | sec = Cfg.Section("elk") | ||||
| ElkUrl = sec.Key("ELKURL").MustString("") | ElkUrl = sec.Key("ELKURL").MustString("") | ||||
| @@ -1585,6 +1595,10 @@ func NewContext() { | |||||
| CloudbrainStoppedTitle = sec.Key("CLOUDBRAIN_STOPPED_TITLE").MustString("您好,您申请的算力资源已结束使用,任务已完成运行,状态为%s,请您关注运行结果") | CloudbrainStoppedTitle = sec.Key("CLOUDBRAIN_STOPPED_TITLE").MustString("您好,您申请的算力资源已结束使用,任务已完成运行,状态为%s,请您关注运行结果") | ||||
| CloudbrainStoppedRemark = sec.Key("CLOUDBRAIN_STOPPED_REMARK").MustString("感谢您的耐心等待。") | CloudbrainStoppedRemark = sec.Key("CLOUDBRAIN_STOPPED_REMARK").MustString("感谢您的耐心等待。") | ||||
| sec = Cfg.Section("repo-square") | |||||
| IncubationSourceOrgName = sec.Key("INCUBATION_ORG_NAME").MustString("OpenI") | |||||
| PaperRepoTopicName = sec.Key("PAPER_REPO_TOPIC_NAME").MustString("openi-paper") | |||||
| sec = Cfg.Section("point") | sec = Cfg.Section("point") | ||||
| CloudBrainPaySwitch = sec.Key("CLOUDBRAIN_PAY_SWITCH").MustBool(false) | CloudBrainPaySwitch = sec.Key("CLOUDBRAIN_PAY_SWITCH").MustBool(false) | ||||
| CloudBrainPayDelay = sec.Key("CLOUDBRAIN_PAY_DELAY").MustDuration(30 * time.Minute) | CloudBrainPayDelay = sec.Key("CLOUDBRAIN_PAY_DELAY").MustDuration(30 * time.Minute) | ||||
| @@ -0,0 +1,23 @@ | |||||
| package structs | |||||
| type Pipeline struct { | |||||
| ID int64 `json:"id"` | |||||
| Name string `json:"name"` | |||||
| Status string `json:"status"` | |||||
| } | |||||
| type NodeInfo struct { | |||||
| Name string `json:"name"` | |||||
| Status string `json:"status"` | |||||
| Code string `json:"code"` | |||||
| Message string `json:"message"` | |||||
| } | |||||
| type PipelineNotification struct { | |||||
| Type int `json:"type"` | |||||
| Username string `json:"username"` | |||||
| Reponame string `json:"reponame"` | |||||
| Pipeline Pipeline `json:"pipeline"` | |||||
| PipelineRunId string `json:"pipeline_run_id"` | |||||
| Node NodeInfo `json:"node"` | |||||
| OccurTime int64 `json:"occur_time"` | |||||
| } | |||||
| @@ -1307,6 +1307,11 @@ model.manage.select.engine=Select model engine | |||||
| model.manage.modelfile=Model file | model.manage.modelfile=Model file | ||||
| model.manage.modellabel=Model label | model.manage.modellabel=Model label | ||||
| model.manage.modeldesc=Model description | model.manage.modeldesc=Model description | ||||
| model.manage.modelaccess=Model Access | |||||
| model.manage.modelaccess.public=Public | |||||
| model.manage.modelaccess.private=Private | |||||
| model.manage.modelaccess.setpublic=Set Public | |||||
| model.manage.modelaccess.setprivate=Set Private | |||||
| model.manage.baseinfo=Base Information | model.manage.baseinfo=Base Information | ||||
| modelconvert.notcreate=No model conversion task has been created. | modelconvert.notcreate=No model conversion task has been created. | ||||
| modelconvert.importfirst1=Please import the | modelconvert.importfirst1=Please import the | ||||
| @@ -1320,6 +1320,11 @@ model.manage.select.engine=选择模型框架 | |||||
| model.manage.modelfile=模型文件 | model.manage.modelfile=模型文件 | ||||
| model.manage.modellabel=模型标签 | model.manage.modellabel=模型标签 | ||||
| model.manage.modeldesc=模型描述 | model.manage.modeldesc=模型描述 | ||||
| model.manage.modelaccess=模型权限 | |||||
| model.manage.modelaccess.public=公开 | |||||
| model.manage.modelaccess.private=私有 | |||||
| model.manage.modelaccess.setpublic=设为公开 | |||||
| model.manage.modelaccess.setprivate=设为私有 | |||||
| model.manage.baseinfo=基本信息 | model.manage.baseinfo=基本信息 | ||||
| modelconvert.notcreate=未创建过模型转换任务 | modelconvert.notcreate=未创建过模型转换任务 | ||||
| modelconvert.importfirst1=请您先导入 | modelconvert.importfirst1=请您先导入 | ||||
| @@ -17,11 +17,12 @@ | |||||
| "core-js": "3.6.5", | "core-js": "3.6.5", | ||||
| "css-loader": "3.5.3", | "css-loader": "3.5.3", | ||||
| "cssnano": "4.1.10", | "cssnano": "4.1.10", | ||||
| "dayjs": "1.10.7", | |||||
| "domino": "2.1.5", | "domino": "2.1.5", | ||||
| "dropzone": "5.7.2", | "dropzone": "5.7.2", | ||||
| "echarts": "3.8.5", | "echarts": "3.8.5", | ||||
| "element-ui": "2.15.5", | "element-ui": "2.15.5", | ||||
| "esdk-obs-browserjs": "3.20.7", | |||||
| "esdk-obs-browserjs": "3.22.3", | |||||
| "esdk-obs-nodejs": "3.20.11", | "esdk-obs-nodejs": "3.20.11", | ||||
| "fast-glob": "3.2.2", | "fast-glob": "3.2.2", | ||||
| "file-loader": "6.0.0", | "file-loader": "6.0.0", | ||||
| @@ -622,20 +622,12 @@ function displayRepo(json){ | |||||
| for (var i = 0, iLen = repos.length; i < iLen; i++) { | for (var i = 0, iLen = repos.length; i < iLen; i++) { | ||||
| if (i >= 4) break; | if (i >= 4) break; | ||||
| var repo = repos[i]; | var repo = repos[i]; | ||||
| // <i class="ri-star-line"></i>${repo["NumStars"]}<i class="ri-git-branch-line am-ml-10"></i>${repo["NumForks"]}</span> <div class="ui tags nowrap am-mt-10"></div> | |||||
| html += `<div class="ui fluid card" style="border-radius:6px;"> | html += `<div class="ui fluid card" style="border-radius:6px;"> | ||||
| <div class="content"> | |||||
| ${repo["Avatar"] ? `<img class="left floated mini ui image" src="${repo["Avatar"]}">` : `<img class="left floated mini ui image" avatar="${repo["OwnerName"]}">`} | |||||
| <div class="content" style="position:relative;"> | |||||
| ${repo["Avatar"] ? `<img style="border-radius:100%;" class="left floated mini ui image" src="${repo["Avatar"]}">` : `<img style="border-radius:100%;" class="left floated mini ui image" avatar="${repo["OwnerName"]}">`} | |||||
| <a class="header nowrap" style="color:rgb(50, 145, 248);font-size:14px;" href="/${repo["OwnerName"]}/${repo["Name"]}" title="${repo["Alias"]}">${repo["Alias"]}</a> | <a class="header nowrap" style="color:rgb(50, 145, 248);font-size:14px;" href="/${repo["OwnerName"]}/${repo["Name"]}" title="${repo["Alias"]}">${repo["Alias"]}</a> | ||||
| <div class="description nowrap-2" style="rgba(136,136,136,1);;font-size:12px;" title="${repo["Description"]}">${repo["Description"]}</div> | <div class="description nowrap-2" style="rgba(136,136,136,1);;font-size:12px;" title="${repo["Description"]}">${repo["Description"]}</div> | ||||
| `; | |||||
| // if (repo["Topics"] != null) { | |||||
| // for(var j = 0; j < repo["Topics"].length; j++){ | |||||
| // var topic = repo["Topics"][j]; | |||||
| // var url = "/explore/repos?q=" + (topic) + "&topic=" | |||||
| // html += `<a class="ui small label topic" href=" ${url}">${topic}</a>`; | |||||
| // } | |||||
| // } | |||||
| <a href="/${repo["OwnerName"]}/${repo["Name"]}" style="height:100%;width:100%;position:absolute;left:0;top:0"></a>`; | |||||
| html += ` | html += ` | ||||
| </div> | </div> | ||||
| </div>`; | </div>`; | ||||
| @@ -307,3 +307,37 @@ func RefreshHistorySpec(ctx *context.Context) { | |||||
| r["total"] = total | r["total"] = total | ||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | ||||
| } | } | ||||
| func RefreshReposHistoryCnt(ctx *context.Context) { | |||||
| scope := ctx.Query("scope") | |||||
| list := ctx.Query("list") | |||||
| var scopeAll = false | |||||
| if scope == "all" { | |||||
| scopeAll = true | |||||
| } | |||||
| var ids = make([]int64, 0) | |||||
| if list != "" { | |||||
| strs := strings.Split(list, "|") | |||||
| for _, s := range strs { | |||||
| i, err := strconv.ParseInt(s, 10, 64) | |||||
| if err != nil { | |||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
| return | |||||
| } | |||||
| ids = append(ids, i) | |||||
| } | |||||
| } | |||||
| total, success, err := resource.RefreshHistorySpec(scopeAll, ids) | |||||
| if err != nil { | |||||
| log.Error("RefreshHistorySpec error. %v", err) | |||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
| return | |||||
| } | |||||
| r := make(map[string]interface{}, 0) | |||||
| r["success"] = success | |||||
| r["total"] = total | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | |||||
| } | |||||
| @@ -543,6 +543,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/get_multipart_url", repo.GetMultipartUploadUrl) | m.Get("/get_multipart_url", repo.GetMultipartUploadUrl) | ||||
| m.Post("/complete_multipart", repo.CompleteMultipart) | m.Post("/complete_multipart", repo.CompleteMultipart) | ||||
| }, reqToken()) | |||||
| m.Group("/pipeline", func() { | |||||
| m.Post("/notification", bind(api.PipelineNotification{}), notify.PipelineNotify) | |||||
| }, reqToken()) | }, reqToken()) | ||||
| // Notifications | // Notifications | ||||
| @@ -610,6 +614,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/query_invitation_yesterday", operationReq, repo_ext.QueryInvitationYesterday) | m.Get("/query_invitation_yesterday", operationReq, repo_ext.QueryInvitationYesterday) | ||||
| m.Get("/query_invitation_all", operationReq, repo_ext.QueryInvitationAll) | m.Get("/query_invitation_all", operationReq, repo_ext.QueryInvitationAll) | ||||
| m.Get("/query_invitation_userdefine", operationReq, repo_ext.QueryUserDefineInvitationPage) | m.Get("/query_invitation_userdefine", operationReq, repo_ext.QueryUserDefineInvitationPage) | ||||
| m.Get("/query_user_annual_report", repo_ext.QueryUserAnnualReport) | |||||
| m.Get("/download_invitation_detail", operationReq, repo_ext.DownloadInvitationDetail) | m.Get("/download_invitation_detail", operationReq, repo_ext.DownloadInvitationDetail) | ||||
| @@ -758,6 +763,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Group("/:username/:reponame", func() { | m.Group("/:username/:reponame", func() { | ||||
| m.Get("/right", reqToken(), repo.GetRight) | m.Get("/right", reqToken(), repo.GetRight) | ||||
| m.Get("/tagger", reqToken(), repo.ListTagger) | m.Get("/tagger", reqToken(), repo.ListTagger) | ||||
| m.Get("/cloudBrainJobId", repo.GetCloudBrainJobId) | |||||
| m.Combo("").Get(reqAnyRepoReader(), repo.Get). | m.Combo("").Get(reqAnyRepoReader(), repo.Get). | ||||
| Delete(reqToken(), reqOwner(), repo.Delete). | Delete(reqToken(), reqOwner(), repo.Delete). | ||||
| Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRef(), repo.Edit) | Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRef(), repo.Edit) | ||||
| @@ -994,6 +1000,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/detail", reqToken(), reqRepoReader(models.UnitTypeCloudBrain), repo.CloudBrainShow) | m.Get("/detail", reqToken(), reqRepoReader(models.UnitTypeCloudBrain), repo.CloudBrainShow) | ||||
| m.Get("/model_list", repo.CloudBrainModelList) | m.Get("/model_list", repo.CloudBrainModelList) | ||||
| m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop) | m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop) | ||||
| m.Put("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.GeneralCloudBrainJobStop) | |||||
| }) | }) | ||||
| }) | }) | ||||
| m.Group("/inference-job", func() { | m.Group("/inference-job", func() { | ||||
| @@ -1014,12 +1021,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Delete("/delete_model", repo.DeleteModel) | m.Delete("/delete_model", repo.DeleteModel) | ||||
| m.Get("/downloadall", repo.DownloadModel) | m.Get("/downloadall", repo.DownloadModel) | ||||
| m.Get("/query_model_byId", repo.QueryModelById) | m.Get("/query_model_byId", repo.QueryModelById) | ||||
| m.Get("/query_model_byName", repo.QueryModelByName) | |||||
| m.Get("/query_model_for_predict", repo.QueryModelListForPredict) | m.Get("/query_model_for_predict", repo.QueryModelListForPredict) | ||||
| m.Get("/query_modelfile_for_predict", repo.QueryModelFileForPredict) | m.Get("/query_modelfile_for_predict", repo.QueryModelFileForPredict) | ||||
| m.Get("/query_train_model", repo.QueryTrainModelList) | m.Get("/query_train_model", repo.QueryTrainModelList) | ||||
| m.Post("/create_model_convert", repo.CreateModelConvert) | m.Post("/create_model_convert", repo.CreateModelConvert) | ||||
| m.Post("/convert_stop", repo.StopModelConvert) | |||||
| m.Get("/show_model_convert_page", repo.ShowModelConvertPage) | m.Get("/show_model_convert_page", repo.ShowModelConvertPage) | ||||
| m.Get("/query_model_convert_byId", repo.QueryModelConvertById) | m.Get("/query_model_convert_byId", repo.QueryModelConvertById) | ||||
| m.Get("/query_model_convert_byName", repo.QueryModelConvertByName) | |||||
| m.Get("/:id", repo.GetCloudbrainModelConvertTask) | m.Get("/:id", repo.GetCloudbrainModelConvertTask) | ||||
| m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog) | m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog) | ||||
| @@ -0,0 +1,15 @@ | |||||
| package notify | |||||
| import ( | |||||
| "net/http" | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/context" | |||||
| api "code.gitea.io/gitea/modules/structs" | |||||
| ) | |||||
| func PipelineNotify(ctx *context.APIContext, form api.PipelineNotification) { | |||||
| ctx.JSON(http.StatusOK, models.BaseOKMessageApi) | |||||
| } | |||||
| @@ -17,6 +17,8 @@ import ( | |||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/grampus" | |||||
| cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | ||||
| "code.gitea.io/gitea/modules/convert" | "code.gitea.io/gitea/modules/convert" | ||||
| @@ -80,6 +82,30 @@ func CloudBrainShow(ctx *context.APIContext) { | |||||
| ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)}) | ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)}) | ||||
| } | } | ||||
| func GeneralCloudBrainJobStop(ctx *context.APIContext) { | |||||
| task := ctx.Cloudbrain | |||||
| if task.IsTerminal() { | |||||
| ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("cloudbrain.Already_stopped")) | |||||
| return | |||||
| } | |||||
| var err error | |||||
| if ctx.Cloudbrain.Type == models.TypeCloudBrainOne { | |||||
| err = cloudbrain.StopJob(task.JobID) | |||||
| } else if ctx.Cloudbrain.Type == models.TypeCloudBrainTwo { | |||||
| _, err = modelarts.StopTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10)) | |||||
| } else { | |||||
| _, err = grampus.StopJob(task.JobID) | |||||
| } | |||||
| if err != nil { | |||||
| log.Warn("cloud brain stopped failed.", err) | |||||
| ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("cloudbrain.Stopped_failed")) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, models.BaseOKMessageApi) | |||||
| } | |||||
| func CreateFileNoteBook(ctx *context.APIContext, option api.CreateFileNotebookJobOption) { | func CreateFileNoteBook(ctx *context.APIContext, option api.CreateFileNotebookJobOption) { | ||||
| cloudbrainTask.FileNotebookCreate(ctx.Context, option) | cloudbrainTask.FileNotebookCreate(ctx.Context, option) | ||||
| } | } | ||||
| @@ -69,3 +69,17 @@ func GetRight(ctx *context.APIContext) { | |||||
| }) | }) | ||||
| } | } | ||||
| func GetCloudBrainJobId(ctx *context.APIContext) { | |||||
| cloudbrains, err := models.GetCloudbrainsByDisplayJobName(ctx.Repo.Repository.ID, ctx.Query("jobType"), ctx.Query("name")) | |||||
| if err != nil { | |||||
| log.Warn("get cloudbrain by display name failed", err) | |||||
| ctx.JSON(http.StatusOK, map[string]string{"jobId": ""}) | |||||
| return | |||||
| } | |||||
| if len(cloudbrains) > 0 { | |||||
| ctx.JSON(http.StatusOK, map[string]string{"jobId": cloudbrains[0].JobID}) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, map[string]string{"jobId": ""}) | |||||
| } | |||||
| @@ -43,8 +43,14 @@ func QueryModelById(ctx *context.APIContext) { | |||||
| routerRepo.QueryModelById(ctx.Context) | routerRepo.QueryModelById(ctx.Context) | ||||
| } | } | ||||
| func QueryModelByName(ctx *context.APIContext) { | |||||
| log.Info("QueryModelByName by api.") | |||||
| routerRepo.ShowSingleModel(ctx.Context) | |||||
| } | |||||
| func QueryModelListForPredict(ctx *context.APIContext) { | func QueryModelListForPredict(ctx *context.APIContext) { | ||||
| log.Info("QueryModelListForPredict by api.") | log.Info("QueryModelListForPredict by api.") | ||||
| ctx.Context.SetParams("isOnlyThisRepo", "true") | |||||
| routerRepo.QueryModelListForPredict(ctx.Context) | routerRepo.QueryModelListForPredict(ctx.Context) | ||||
| } | } | ||||
| @@ -88,6 +94,11 @@ func CreateModelConvert(ctx *context.APIContext) { | |||||
| routerRepo.SaveModelConvert(ctx.Context) | routerRepo.SaveModelConvert(ctx.Context) | ||||
| } | } | ||||
| func StopModelConvert(ctx *context.APIContext) { | |||||
| log.Info("StopModelConvert by api.") | |||||
| routerRepo.StopModelConvertApi(ctx.Context) | |||||
| } | |||||
| func ShowModelConvertPage(ctx *context.APIContext) { | func ShowModelConvertPage(ctx *context.APIContext) { | ||||
| log.Info("ShowModelConvertPage by api.") | log.Info("ShowModelConvertPage by api.") | ||||
| modelResult, count, err := routerRepo.GetModelConvertPageData(ctx.Context) | modelResult, count, err := routerRepo.GetModelConvertPageData(ctx.Context) | ||||
| @@ -113,3 +124,12 @@ func QueryModelConvertById(ctx *context.APIContext) { | |||||
| ctx.JSON(http.StatusOK, nil) | ctx.JSON(http.StatusOK, nil) | ||||
| } | } | ||||
| } | } | ||||
| func QueryModelConvertByName(ctx *context.APIContext) { | |||||
| modelResult, err := routerRepo.GetModelConvertByName(ctx.Context) | |||||
| if err == nil { | |||||
| ctx.JSON(http.StatusOK, modelResult) | |||||
| } else { | |||||
| ctx.JSON(http.StatusOK, nil) | |||||
| } | |||||
| } | |||||
| @@ -177,13 +177,25 @@ func AddTopic(ctx *context.APIContext) { | |||||
| return | return | ||||
| } | } | ||||
| _, err = models.AddTopic(ctx.Repo.Repository.ID, topicName) | |||||
| topic, err := models.AddTopic(ctx.Repo.Repository.ID, topicName) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("AddTopic failed: %v", err) | log.Error("AddTopic failed: %v", err) | ||||
| ctx.InternalServerError(err) | ctx.InternalServerError(err) | ||||
| return | return | ||||
| } | } | ||||
| found := false | |||||
| topicNames := make([]string, len(topics)) | |||||
| for i, t := range topics { | |||||
| topicNames[i] = t.Name | |||||
| if strings.EqualFold(topic.Name, t.Name) { | |||||
| found = true | |||||
| break | |||||
| } | |||||
| } | |||||
| if !found && topic.Name != "" { | |||||
| topicNames = append(topicNames, topic.Name) | |||||
| } | |||||
| models.UpdateRepoTopics(ctx.Repo.Repository.ID, topicNames) | |||||
| ctx.Status(http.StatusNoContent) | ctx.Status(http.StatusNoContent) | ||||
| } | } | ||||
| @@ -7,6 +7,7 @@ package routers | |||||
| import ( | import ( | ||||
| "bytes" | "bytes" | ||||
| "code.gitea.io/gitea/routers/response" | |||||
| "encoding/json" | "encoding/json" | ||||
| "net/http" | "net/http" | ||||
| "strconv" | "strconv" | ||||
| @@ -43,6 +44,8 @@ const ( | |||||
| tplHomeTerm base.TplName = "terms" | tplHomeTerm base.TplName = "terms" | ||||
| tplHomePrivacy base.TplName = "privacy" | tplHomePrivacy base.TplName = "privacy" | ||||
| tplResoruceDesc base.TplName = "resource_desc" | tplResoruceDesc base.TplName = "resource_desc" | ||||
| tplRepoSquare base.TplName = "explore/repos/square" | |||||
| tplRepoSearch base.TplName = "explore/repos/search" | |||||
| ) | ) | ||||
| // Home render home page | // Home render home page | ||||
| @@ -296,6 +299,109 @@ func ExploreRepos(ctx *context.Context) { | |||||
| }) | }) | ||||
| } | } | ||||
| func GetRepoSquarePage(ctx *context.Context) { | |||||
| ctx.Data["SquareBanners"] = repository.GetBanners() | |||||
| ctx.Data["SquareTopics"] = repository.GetTopics() | |||||
| ctx.Data["SquareRecommendRepos"] = repository.GetRecommendRepos() | |||||
| repos, _ := repository.GetPreferredRepos() | |||||
| ctx.Data["SquarePreferredRepos"] = repos | |||||
| ctx.HTML(200, tplRepoSquare) | |||||
| } | |||||
| func GetRepoSearchPage(ctx *context.Context) { | |||||
| ctx.Data["SquareTopics"] = repository.GetTopics() | |||||
| ctx.HTML(200, tplRepoSearch) | |||||
| } | |||||
| func RepoSquare(ctx *context.Context) { | |||||
| var result []*models.Repository4Card | |||||
| var err error | |||||
| switch ctx.Query("type") { | |||||
| case "preferred": | |||||
| result, err = repository.GetPreferredRepos() | |||||
| case "incubation": | |||||
| result, err = repository.GetIncubationRepos() | |||||
| case "hot-paper": | |||||
| result, err = repository.GetHotPaperRepos() | |||||
| default: | |||||
| result, err = repository.GetPreferredRepos() | |||||
| } | |||||
| if err != nil { | |||||
| ctx.JSON(http.StatusOK, response.ResponseError(err)) | |||||
| return | |||||
| } | |||||
| resultMap := make(map[string]interface{}, 0) | |||||
| resultMap["Repos"] = result | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(resultMap)) | |||||
| } | |||||
| func ActiveUser(ctx *context.Context) { | |||||
| var err error | |||||
| var currentUserId int64 | |||||
| if ctx.User != nil { | |||||
| currentUserId = ctx.User.ID | |||||
| } | |||||
| result, err := repository.GetActiveUser4Square(currentUserId) | |||||
| if err != nil { | |||||
| log.Error("ActiveUser err. %v", err) | |||||
| ctx.JSON(http.StatusOK, response.Success()) | |||||
| return | |||||
| } | |||||
| resultMap := make(map[string]interface{}, 0) | |||||
| resultMap["Users"] = result | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(resultMap)) | |||||
| } | |||||
| func ActiveOrg(ctx *context.Context) { | |||||
| result, err := repository.GetActiveOrgs() | |||||
| if err != nil { | |||||
| log.Error("ActiveOrg err. %v", err) | |||||
| ctx.JSON(http.StatusOK, response.Success()) | |||||
| return | |||||
| } | |||||
| resultMap := make(map[string]interface{}, 0) | |||||
| resultMap["Orgs"] = result | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(resultMap)) | |||||
| } | |||||
| func RepoFind(ctx *context.Context) { | |||||
| keyword := strings.Trim(ctx.Query("q"), " ") | |||||
| topic := strings.Trim(ctx.Query("topic"), " ") | |||||
| sort := strings.Trim(ctx.Query("sort"), " ") | |||||
| page := ctx.QueryInt("page") | |||||
| pageSize := ctx.QueryInt("pageSize") | |||||
| if pageSize == 0 { | |||||
| pageSize = 15 | |||||
| } | |||||
| if pageSize > 100 { | |||||
| ctx.JSON(http.StatusOK, response.ServerError("pageSize illegal")) | |||||
| return | |||||
| } | |||||
| if page <= 0 { | |||||
| page = 1 | |||||
| } | |||||
| var ownerID int64 | |||||
| if ctx.User != nil && !ctx.User.IsAdmin { | |||||
| ownerID = ctx.User.ID | |||||
| } | |||||
| result, err := repository.FindRepos(repository.FindReposOptions{ | |||||
| ListOptions: models.ListOptions{Page: page, PageSize: pageSize}, | |||||
| Actor: ctx.User, | |||||
| Sort: sort, | |||||
| Keyword: keyword, | |||||
| Topic: topic, | |||||
| Private: ctx.User != nil, | |||||
| OwnerID: ownerID, | |||||
| }) | |||||
| if err != nil { | |||||
| log.Error("RepoFind error. %v", err) | |||||
| ctx.JSON(http.StatusOK, response.ResponseError(err)) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(result)) | |||||
| } | |||||
| func ExploreDatasets(ctx *context.Context) { | func ExploreDatasets(ctx *context.Context) { | ||||
| ctx.Data["Title"] = ctx.Tr("explore") | ctx.Data["Title"] = ctx.Tr("explore") | ||||
| ctx.Data["PageIsExplore"] = true | ctx.Data["PageIsExplore"] = true | ||||
| @@ -6,6 +6,7 @@ | |||||
| package private | package private | ||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/services/repository" | |||||
| "strings" | "strings" | ||||
| "code.gitea.io/gitea/routers/admin" | "code.gitea.io/gitea/routers/admin" | ||||
| @@ -55,7 +56,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Post("/task/history_handle/duration", repo.HandleTaskWithNoDuration) | m.Post("/task/history_handle/duration", repo.HandleTaskWithNoDuration) | ||||
| m.Post("/task/history_handle/aicenter", repo.HandleTaskWithAiCenter) | m.Post("/task/history_handle/aicenter", repo.HandleTaskWithAiCenter) | ||||
| m.Post("/resources/specification/handle_historical_task", admin.RefreshHistorySpec) | m.Post("/resources/specification/handle_historical_task", admin.RefreshHistorySpec) | ||||
| m.Post("/repos/cnt_stat/handle_historical_task", admin.RefreshHistorySpec) | |||||
| m.Post("/duration_statisctic/history_handle", repo.CloudbrainUpdateHistoryData) | m.Post("/duration_statisctic/history_handle", repo.CloudbrainUpdateHistoryData) | ||||
| m.Post("/square/repo/stat/refresh", repository.RefreshRepoStatData) | |||||
| }, CheckInternalToken) | }, CheckInternalToken) | ||||
| } | } | ||||
| @@ -573,13 +573,10 @@ func deleteCloudBrainTask(task *models.AiModelConvert) { | |||||
| } | } | ||||
| } | } | ||||
| func StopModelConvert(ctx *context.Context) { | |||||
| id := ctx.Params(":id") | |||||
| log.Info("stop model convert start.id=" + id) | |||||
| func stopModelConvert(id string) error { | |||||
| job, err := models.QueryModelConvertById(id) | job, err := models.QueryModelConvertById(id) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("Not found task.", err) | |||||
| return | |||||
| return err | |||||
| } | } | ||||
| if job.IsGpuTrainTask() { | if job.IsGpuTrainTask() { | ||||
| err = cloudbrain.StopJob(job.CloudBrainTaskId) | err = cloudbrain.StopJob(job.CloudBrainTaskId) | ||||
| @@ -600,6 +597,35 @@ func StopModelConvert(ctx *context.Context) { | |||||
| err = models.UpdateModelConvert(job) | err = models.UpdateModelConvert(job) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("UpdateModelConvert failed:", err) | log.Error("UpdateModelConvert failed:", err) | ||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func StopModelConvertApi(ctx *context.Context) { | |||||
| id := ctx.Query("id") | |||||
| log.Info("stop model convert start.id=" + id) | |||||
| err := stopModelConvert(id) | |||||
| if err == nil { | |||||
| ctx.JSON(200, map[string]string{ | |||||
| "code": "0", | |||||
| "msg": "succeed", | |||||
| }) | |||||
| } else { | |||||
| ctx.JSON(200, map[string]string{ | |||||
| "code": "1", | |||||
| "msg": err.Error(), | |||||
| }) | |||||
| } | |||||
| } | |||||
| func StopModelConvert(ctx *context.Context) { | |||||
| id := ctx.Params(":id") | |||||
| log.Info("stop model convert start.id=" + id) | |||||
| err := stopModelConvert(id) | |||||
| if err != nil { | |||||
| ctx.ServerError("Not found task.", err) | |||||
| return | |||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model") | ||||
| } | } | ||||
| @@ -620,7 +646,7 @@ func ShowModelConvertInfo(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| ctx.Data["Name"] = job.Name | ctx.Data["Name"] = job.Name | ||||
| ctx.Data["canDownload"] = isOper(ctx, job.UserId) | |||||
| ctx.Data["canDownload"] = isOperModifyOrDelete(ctx, job.UserId) | |||||
| user, err := models.GetUserByID(job.UserId) | user, err := models.GetUserByID(job.UserId) | ||||
| if err == nil { | if err == nil { | ||||
| job.UserName = user.Name | job.UserName = user.Name | ||||
| @@ -732,6 +758,11 @@ func GetModelConvertById(ctx *context.Context) (*models.AiModelConvert, error) { | |||||
| return models.QueryModelConvertById(id) | return models.QueryModelConvertById(id) | ||||
| } | } | ||||
| func GetModelConvertByName(ctx *context.Context) ([]*models.AiModelConvert, error) { | |||||
| name := ctx.Query("name") | |||||
| return models.QueryModelConvertByName(name, ctx.Repo.Repository.ID) | |||||
| } | |||||
| func GetModelConvertPageData(ctx *context.Context) ([]*models.AiModelConvert, int64, error) { | func GetModelConvertPageData(ctx *context.Context) ([]*models.AiModelConvert, int64, error) { | ||||
| page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
| if page <= 0 { | if page <= 0 { | ||||
| @@ -755,7 +786,7 @@ func GetModelConvertPageData(ctx *context.Context) ([]*models.AiModelConvert, in | |||||
| } | } | ||||
| userIds := make([]int64, len(modelResult)) | userIds := make([]int64, len(modelResult)) | ||||
| for i, model := range modelResult { | for i, model := range modelResult { | ||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId) | |||||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | model.IsCanDelete = isCanDelete(ctx, model.UserId) | ||||
| userIds[i] = model.UserId | userIds[i] = model.UserId | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package repo | |||||
| import ( | import ( | ||||
| "archive/zip" | "archive/zip" | ||||
| "code.gitea.io/gitea/services/repository" | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| @@ -93,7 +94,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||||
| log.Info("accuracyJson=" + string(accuracyJson)) | log.Info("accuracyJson=" + string(accuracyJson)) | ||||
| aiTask.ContainerIp = "" | aiTask.ContainerIp = "" | ||||
| aiTaskJson, _ := json.Marshal(aiTask) | aiTaskJson, _ := json.Marshal(aiTask) | ||||
| isPrivate := ctx.QueryBool("isPrivate") | |||||
| model := &models.AiModelManage{ | model := &models.AiModelManage{ | ||||
| ID: id, | ID: id, | ||||
| Version: version, | Version: version, | ||||
| @@ -114,6 +115,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||||
| TrainTaskInfo: string(aiTaskJson), | TrainTaskInfo: string(aiTaskJson), | ||||
| Accuracy: string(accuracyJson), | Accuracy: string(accuracyJson), | ||||
| Status: STATUS_COPY_MODEL, | Status: STATUS_COPY_MODEL, | ||||
| IsPrivate: isPrivate, | |||||
| } | } | ||||
| err = models.SaveModelToDb(model) | err = models.SaveModelToDb(model) | ||||
| @@ -169,10 +171,17 @@ func updateStatus(id string, modelSize int64, status int, modelPath string, stat | |||||
| if len(statusDesc) > 400 { | if len(statusDesc) > 400 { | ||||
| statusDesc = statusDesc[0:400] | statusDesc = statusDesc[0:400] | ||||
| } | } | ||||
| m, _ := models.QueryModelById(id) | |||||
| err := models.ModifyModelStatus(id, modelSize, status, modelPath, statusDesc) | err := models.ModifyModelStatus(id, modelSize, status, modelPath, statusDesc) | ||||
| if err != nil { | if err != nil { | ||||
| log.Info("update status error." + err.Error()) | log.Info("update status error." + err.Error()) | ||||
| } | } | ||||
| if m != nil { | |||||
| if modelSize > 0 && m.Size == 0 { | |||||
| go repository.ResetRepoModelNum(m.RepoId) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| func SaveNewNameModel(ctx *context.Context) { | func SaveNewNameModel(ctx *context.Context) { | ||||
| @@ -216,6 +225,7 @@ func SaveLocalModel(ctx *context.Context) { | |||||
| description := ctx.Query("description") | description := ctx.Query("description") | ||||
| engine := ctx.QueryInt("engine") | engine := ctx.QueryInt("engine") | ||||
| taskType := ctx.QueryInt("type") | taskType := ctx.QueryInt("type") | ||||
| isPrivate := ctx.QueryBool("isPrivate") | |||||
| modelActualPath := "" | modelActualPath := "" | ||||
| if taskType == models.TypeCloudBrainOne { | if taskType == models.TypeCloudBrainOne { | ||||
| destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/" | destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/" | ||||
| @@ -262,6 +272,7 @@ func SaveLocalModel(ctx *context.Context) { | |||||
| TrainTaskInfo: "", | TrainTaskInfo: "", | ||||
| Accuracy: "", | Accuracy: "", | ||||
| Status: STATUS_FINISHED, | Status: STATUS_FINISHED, | ||||
| IsPrivate: isPrivate, | |||||
| } | } | ||||
| err := models.SaveModelToDb(model) | err := models.SaveModelToDb(model) | ||||
| @@ -305,13 +316,14 @@ func getSize(files []storage.FileInfo) int64 { | |||||
| func UpdateModelSize(modeluuid string) { | func UpdateModelSize(modeluuid string) { | ||||
| model, err := models.QueryModelById(modeluuid) | model, err := models.QueryModelById(modeluuid) | ||||
| if err == nil { | if err == nil { | ||||
| var size int64 | |||||
| if model.Type == models.TypeCloudBrainOne { | if model.Type == models.TypeCloudBrainOne { | ||||
| if strings.HasPrefix(model.Path, setting.Attachment.Minio.Bucket+"/"+Model_prefix) { | if strings.HasPrefix(model.Path, setting.Attachment.Minio.Bucket+"/"+Model_prefix) { | ||||
| files, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, model.Path[len(setting.Attachment.Minio.Bucket)+1:]) | files, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, model.Path[len(setting.Attachment.Minio.Bucket)+1:]) | ||||
| if err != nil { | if err != nil { | ||||
| log.Info("Failed to query model size from minio. id=" + modeluuid) | log.Info("Failed to query model size from minio. id=" + modeluuid) | ||||
| } | } | ||||
| size := getSize(files) | |||||
| size = getSize(files) | |||||
| models.ModifyModelSize(modeluuid, size) | models.ModifyModelSize(modeluuid, size) | ||||
| } | } | ||||
| } else if model.Type == models.TypeCloudBrainTwo { | } else if model.Type == models.TypeCloudBrainTwo { | ||||
| @@ -320,10 +332,13 @@ func UpdateModelSize(modeluuid string) { | |||||
| if err != nil { | if err != nil { | ||||
| log.Info("Failed to query model size from obs. id=" + modeluuid) | log.Info("Failed to query model size from obs. id=" + modeluuid) | ||||
| } | } | ||||
| size := getSize(files) | |||||
| size = getSize(files) | |||||
| models.ModifyModelSize(modeluuid, size) | models.ModifyModelSize(modeluuid, size) | ||||
| } | } | ||||
| } | } | ||||
| if model.Size == 0 && size > 0 { | |||||
| go repository.ResetRepoModelNum(model.RepoId) | |||||
| } | |||||
| } else { | } else { | ||||
| log.Info("not found model,uuid=" + modeluuid) | log.Info("not found model,uuid=" + modeluuid) | ||||
| } | } | ||||
| @@ -438,13 +453,14 @@ func DeleteModelFile(ctx *context.Context) { | |||||
| fileName := ctx.Query("fileName") | fileName := ctx.Query("fileName") | ||||
| model, err := models.QueryModelById(id) | model, err := models.QueryModelById(id) | ||||
| if err == nil { | if err == nil { | ||||
| var totalSize int64 | |||||
| if model.ModelType == MODEL_LOCAL_TYPE { | if model.ModelType == MODEL_LOCAL_TYPE { | ||||
| if model.Type == models.TypeCloudBrainOne { | if model.Type == models.TypeCloudBrainOne { | ||||
| bucketName := setting.Attachment.Minio.Bucket | bucketName := setting.Attachment.Minio.Bucket | ||||
| objectName := model.Path[len(bucketName)+1:] + fileName | objectName := model.Path[len(bucketName)+1:] + fileName | ||||
| log.Info("delete bucket=" + bucketName + " path=" + objectName) | log.Info("delete bucket=" + bucketName + " path=" + objectName) | ||||
| if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) { | if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) { | ||||
| totalSize := storage.MinioGetFilesSize(bucketName, []string{objectName}) | |||||
| totalSize = storage.MinioGetFilesSize(bucketName, []string{objectName}) | |||||
| err := storage.Attachments.DeleteDir(objectName) | err := storage.Attachments.DeleteDir(objectName) | ||||
| if err != nil { | if err != nil { | ||||
| log.Info("Failed to delete model. id=" + id) | log.Info("Failed to delete model. id=" + id) | ||||
| @@ -464,7 +480,7 @@ func DeleteModelFile(ctx *context.Context) { | |||||
| objectName := model.Path[len(setting.Bucket)+1:] + fileName | objectName := model.Path[len(setting.Bucket)+1:] + fileName | ||||
| log.Info("delete bucket=" + setting.Bucket + " path=" + objectName) | log.Info("delete bucket=" + setting.Bucket + " path=" + objectName) | ||||
| if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) { | if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) { | ||||
| totalSize := storage.ObsGetFilesSize(bucketName, []string{objectName}) | |||||
| totalSize = storage.ObsGetFilesSize(bucketName, []string{objectName}) | |||||
| err := storage.ObsRemoveObject(bucketName, objectName) | err := storage.ObsRemoveObject(bucketName, objectName) | ||||
| if err != nil { | if err != nil { | ||||
| log.Info("Failed to delete model. id=" + id) | log.Info("Failed to delete model. id=" + id) | ||||
| @@ -481,6 +497,9 @@ func DeleteModelFile(ctx *context.Context) { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (model.Size - totalSize) <= 0 { | |||||
| go repository.ResetRepoModelNum(model.RepoId) | |||||
| } | |||||
| } | } | ||||
| ctx.JSON(200, map[string]string{ | ctx.JSON(200, map[string]string{ | ||||
| "code": "0", | "code": "0", | ||||
| @@ -549,25 +568,14 @@ func deleteModelByID(ctx *context.Context, id string) error { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if model.Size > 0 { | |||||
| go repository.ResetRepoModelNum(model.RepoId) | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| return err | return err | ||||
| } | } | ||||
| func QueryModelByParameters(repoId int64, page int) ([]*models.AiModelManage, int64, error) { | |||||
| return models.QueryModel(&models.AiModelQueryOptions{ | |||||
| ListOptions: models.ListOptions{ | |||||
| Page: page, | |||||
| PageSize: setting.UI.IssuePagingNum, | |||||
| }, | |||||
| RepoID: repoId, | |||||
| Type: -1, | |||||
| New: MODEL_LATEST, | |||||
| Status: -1, | |||||
| }) | |||||
| } | |||||
| func DownloadMultiModelFile(ctx *context.Context) { | func DownloadMultiModelFile(ctx *context.Context) { | ||||
| log.Info("DownloadMultiModelFile start.") | log.Info("DownloadMultiModelFile start.") | ||||
| id := ctx.Query("id") | id := ctx.Query("id") | ||||
| @@ -578,7 +586,7 @@ func DownloadMultiModelFile(ctx *context.Context) { | |||||
| ctx.ServerError("no such model:", err) | ctx.ServerError("no such model:", err) | ||||
| return | return | ||||
| } | } | ||||
| if !isOper(ctx, task.UserId) { | |||||
| if !isCanDownload(ctx, task) { | |||||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | ||||
| return | return | ||||
| } | } | ||||
| @@ -806,7 +814,7 @@ func DownloadSingleModelFile(ctx *context.Context) { | |||||
| ctx.ServerError("no such model:", err) | ctx.ServerError("no such model:", err) | ||||
| return | return | ||||
| } | } | ||||
| if !isOper(ctx, task.UserId) { | |||||
| if !isCanDownload(ctx, task) { | |||||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | ||||
| return | return | ||||
| } | } | ||||
| @@ -874,8 +882,9 @@ func QueryModelById(ctx *context.Context) { | |||||
| id := ctx.Query("id") | id := ctx.Query("id") | ||||
| model, err := models.QueryModelById(id) | model, err := models.QueryModelById(id) | ||||
| if err == nil { | if err == nil { | ||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId) | |||||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | model.IsCanDelete = isCanDelete(ctx, model.UserId) | ||||
| model.IsCanDownload = isCanDownload(ctx, model) | |||||
| removeIpInfo(model) | removeIpInfo(model) | ||||
| ctx.JSON(http.StatusOK, model) | ctx.JSON(http.StatusOK, model) | ||||
| } else { | } else { | ||||
| @@ -891,7 +900,8 @@ func ShowSingleModel(ctx *context.Context) { | |||||
| userIds := make([]int64, len(models)) | userIds := make([]int64, len(models)) | ||||
| for i, model := range models { | for i, model := range models { | ||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId) | |||||
| model.IsCanDownload = isCanDownload(ctx, model) | |||||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | model.IsCanDelete = isCanDelete(ctx, model.UserId) | ||||
| userIds[i] = model.UserId | userIds[i] = model.UserId | ||||
| } | } | ||||
| @@ -941,7 +951,8 @@ func ShowOneVersionOtherModel(ctx *context.Context) { | |||||
| userIds := make([]int64, len(aimodels)) | userIds := make([]int64, len(aimodels)) | ||||
| for i, model := range aimodels { | for i, model := range aimodels { | ||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId) | |||||
| model.IsCanDownload = isCanDownload(ctx, model) | |||||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | model.IsCanDelete = isCanDelete(ctx, model.UserId) | ||||
| userIds[i] = model.UserId | userIds[i] = model.UserId | ||||
| } | } | ||||
| @@ -964,6 +975,7 @@ func ShowOneVersionOtherModel(ctx *context.Context) { | |||||
| } | } | ||||
| func SetModelCount(ctx *context.Context) { | func SetModelCount(ctx *context.Context) { | ||||
| isQueryPrivate := isQueryPrivateModel(ctx) | |||||
| repoId := ctx.Repo.Repository.ID | repoId := ctx.Repo.Repository.ID | ||||
| Type := -1 | Type := -1 | ||||
| _, count, _ := models.QueryModel(&models.AiModelQueryOptions{ | _, count, _ := models.QueryModel(&models.AiModelQueryOptions{ | ||||
| @@ -971,10 +983,12 @@ func SetModelCount(ctx *context.Context) { | |||||
| Page: 1, | Page: 1, | ||||
| PageSize: 2, | PageSize: 2, | ||||
| }, | }, | ||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| Status: -1, | |||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| IsOnlyThisRepo: true, | |||||
| Status: -1, | |||||
| IsQueryPrivate: isQueryPrivate, | |||||
| }) | }) | ||||
| ctx.Data["MODEL_COUNT"] = count | ctx.Data["MODEL_COUNT"] = count | ||||
| } | } | ||||
| @@ -1001,27 +1015,87 @@ func isQueryRight(ctx *context.Context) bool { | |||||
| } | } | ||||
| } | } | ||||
| func isCanDownload(ctx *context.Context, task *models.AiModelManage) bool { | |||||
| if ctx.User == nil { | |||||
| return false | |||||
| } | |||||
| isCollaborator, err := ctx.Repo.Repository.IsCollaborator(ctx.User.ID) | |||||
| if err != nil { | |||||
| log.Info("query error.") | |||||
| } | |||||
| isTeamMember, err := ctx.Repo.Repository.IsInRepoTeam(ctx.User.ID) | |||||
| if err != nil { | |||||
| log.Info("query IsInRepoTeam error." + err.Error()) | |||||
| } | |||||
| if ctx.User.IsAdmin || ctx.User.ID == task.UserId || isCollaborator || isTeamMember { | |||||
| return true | |||||
| } | |||||
| if ctx.Repo.IsOwner() { | |||||
| return true | |||||
| } | |||||
| if !task.IsPrivate { | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| func isQueryPrivateModel(ctx *context.Context) bool { | |||||
| if ctx.User == nil { | |||||
| return false | |||||
| } | |||||
| isCollaborator, err := ctx.Repo.Repository.IsCollaborator(ctx.User.ID) | |||||
| if err != nil { | |||||
| log.Info("query IsCollaborator error." + err.Error()) | |||||
| } | |||||
| isTeamMember, err := ctx.Repo.Repository.IsInRepoTeam(ctx.User.ID) | |||||
| if err != nil { | |||||
| log.Info("query IsInRepoTeam error." + err.Error()) | |||||
| } | |||||
| if ctx.User.IsAdmin || isCollaborator || isTeamMember { | |||||
| return true | |||||
| } | |||||
| if ctx.Repo.IsOwner() { | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| func isCanDelete(ctx *context.Context, modelUserId int64) bool { | func isCanDelete(ctx *context.Context, modelUserId int64) bool { | ||||
| if ctx.User == nil { | if ctx.User == nil { | ||||
| return false | return false | ||||
| } | } | ||||
| if ctx.User.IsAdmin || ctx.User.ID == modelUserId { | |||||
| if ctx.User.ID == modelUserId { | |||||
| return true | |||||
| } | |||||
| return isAdminRight(ctx) | |||||
| } | |||||
| func isAdminRight(ctx *context.Context) bool { | |||||
| if ctx.User.IsAdmin { | |||||
| return true | return true | ||||
| } | } | ||||
| if ctx.Repo.IsOwner() { | if ctx.Repo.IsOwner() { | ||||
| return true | return true | ||||
| } | } | ||||
| permission, err := models.GetUserRepoPermission(ctx.Repo.Repository, ctx.User) | |||||
| if err != nil { | |||||
| log.Error("GetUserRepoPermission failed:%v", err.Error()) | |||||
| return false | |||||
| } | |||||
| if permission.AccessMode >= models.AccessModeAdmin { | |||||
| return true | |||||
| } | |||||
| return false | return false | ||||
| } | } | ||||
| func isOper(ctx *context.Context, modelUserId int64) bool { | |||||
| func isOperModifyOrDelete(ctx *context.Context, modelUserId int64) bool { | |||||
| if ctx.User == nil { | if ctx.User == nil { | ||||
| return false | return false | ||||
| } | } | ||||
| if ctx.User.IsAdmin || ctx.User.ID == modelUserId { | if ctx.User.IsAdmin || ctx.User.ID == modelUserId { | ||||
| return true | return true | ||||
| } | } | ||||
| return false | |||||
| return isAdminRight(ctx) | |||||
| } | } | ||||
| func ShowModelPageInfo(ctx *context.Context) { | func ShowModelPageInfo(ctx *context.Context) { | ||||
| @@ -1038,6 +1112,7 @@ func ShowModelPageInfo(ctx *context.Context) { | |||||
| if pageSize <= 0 { | if pageSize <= 0 { | ||||
| pageSize = setting.UI.IssuePagingNum | pageSize = setting.UI.IssuePagingNum | ||||
| } | } | ||||
| isQueryPrivate := isQueryPrivateModel(ctx) | |||||
| repoId := ctx.Repo.Repository.ID | repoId := ctx.Repo.Repository.ID | ||||
| Type := -1 | Type := -1 | ||||
| modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | ||||
| @@ -1045,10 +1120,12 @@ func ShowModelPageInfo(ctx *context.Context) { | |||||
| Page: page, | Page: page, | ||||
| PageSize: pageSize, | PageSize: pageSize, | ||||
| }, | }, | ||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| Status: -1, | |||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| IsOnlyThisRepo: true, | |||||
| Status: -1, | |||||
| IsQueryPrivate: isQueryPrivate, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("Cloudbrain", err) | ctx.ServerError("Cloudbrain", err) | ||||
| @@ -1057,8 +1134,9 @@ func ShowModelPageInfo(ctx *context.Context) { | |||||
| userIds := make([]int64, len(modelResult)) | userIds := make([]int64, len(modelResult)) | ||||
| for i, model := range modelResult { | for i, model := range modelResult { | ||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId) | |||||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | model.IsCanDelete = isCanDelete(ctx, model.UserId) | ||||
| model.IsCanDownload = isCanDownload(ctx, model) | |||||
| userIds[i] = model.UserId | userIds[i] = model.UserId | ||||
| } | } | ||||
| @@ -1089,6 +1167,37 @@ func ModifyModel(id string, description string) error { | |||||
| return err | return err | ||||
| } | } | ||||
| func ModifyModelPrivate(ctx *context.Context) { | |||||
| id := ctx.Query("id") | |||||
| isPrivate := ctx.QueryBool("isPrivate") | |||||
| re := map[string]string{ | |||||
| "code": "-1", | |||||
| } | |||||
| task, err := models.QueryModelById(id) | |||||
| if err != nil || task == nil { | |||||
| re["msg"] = err.Error() | |||||
| log.Error("no such model!", err.Error()) | |||||
| ctx.JSON(200, re) | |||||
| return | |||||
| } | |||||
| if !isOperModifyOrDelete(ctx, task.UserId) { | |||||
| re["msg"] = "No right to operation." | |||||
| ctx.JSON(200, re) | |||||
| return | |||||
| } | |||||
| err = models.ModifyModelPrivate(id, isPrivate) | |||||
| if err == nil { | |||||
| re["code"] = "0" | |||||
| ctx.JSON(200, re) | |||||
| log.Info("modify success.") | |||||
| } else { | |||||
| re["msg"] = err.Error() | |||||
| ctx.JSON(200, re) | |||||
| log.Info("Failed to modify.id=" + id + " isprivate=" + fmt.Sprint(isPrivate) + " error:" + err.Error()) | |||||
| } | |||||
| } | |||||
| func ModifyModelInfo(ctx *context.Context) { | func ModifyModelInfo(ctx *context.Context) { | ||||
| log.Info("modify model start.") | log.Info("modify model start.") | ||||
| id := ctx.Query("id") | id := ctx.Query("id") | ||||
| @@ -1102,7 +1211,7 @@ func ModifyModelInfo(ctx *context.Context) { | |||||
| ctx.JSON(200, re) | ctx.JSON(200, re) | ||||
| return | return | ||||
| } | } | ||||
| if !isOper(ctx, task.UserId) { | |||||
| if !isOperModifyOrDelete(ctx, task.UserId) { | |||||
| re["msg"] = "No right to operation." | re["msg"] = "No right to operation." | ||||
| ctx.JSON(200, re) | ctx.JSON(200, re) | ||||
| return | return | ||||
| @@ -1112,6 +1221,7 @@ func ModifyModelInfo(ctx *context.Context) { | |||||
| label := ctx.Query("label") | label := ctx.Query("label") | ||||
| description := ctx.Query("description") | description := ctx.Query("description") | ||||
| engine := ctx.QueryInt("engine") | engine := ctx.QueryInt("engine") | ||||
| isPrivate := ctx.QueryBool("isPrivate") | |||||
| aimodels := models.QueryModelByName(name, task.RepoId) | aimodels := models.QueryModelByName(name, task.RepoId) | ||||
| if aimodels != nil && len(aimodels) > 0 { | if aimodels != nil && len(aimodels) > 0 { | ||||
| if len(aimodels) == 1 { | if len(aimodels) == 1 { | ||||
| @@ -1126,14 +1236,14 @@ func ModifyModelInfo(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| err = models.ModifyLocalModel(id, name, label, description, engine) | |||||
| err = models.ModifyLocalModel(id, name, label, description, engine, isPrivate) | |||||
| } else { | } else { | ||||
| label := ctx.Query("label") | label := ctx.Query("label") | ||||
| description := ctx.Query("description") | description := ctx.Query("description") | ||||
| engine := task.Engine | engine := task.Engine | ||||
| name := task.Name | name := task.Name | ||||
| err = models.ModifyLocalModel(id, name, label, description, int(engine)) | |||||
| err = models.ModifyLocalModel(id, name, label, description, int(engine), task.IsPrivate) | |||||
| } | } | ||||
| if err != nil { | if err != nil { | ||||
| @@ -1148,15 +1258,27 @@ func ModifyModelInfo(ctx *context.Context) { | |||||
| func QueryModelListForPredict(ctx *context.Context) { | func QueryModelListForPredict(ctx *context.Context) { | ||||
| repoId := ctx.Repo.Repository.ID | repoId := ctx.Repo.Repository.ID | ||||
| page := ctx.QueryInt("page") | |||||
| if page <= 0 { | |||||
| page = -1 | |||||
| } | |||||
| pageSize := ctx.QueryInt("pageSize") | |||||
| if pageSize <= 0 { | |||||
| pageSize = -1 | |||||
| } | |||||
| isQueryPrivate := isQueryPrivateModel(ctx) | |||||
| //IsOnlyThisRepo := ctx.QueryBool("isOnlyThisRepo") | |||||
| modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | ||||
| ListOptions: models.ListOptions{ | ListOptions: models.ListOptions{ | ||||
| Page: -1, | |||||
| PageSize: -1, | |||||
| Page: page, | |||||
| PageSize: pageSize, | |||||
| }, | }, | ||||
| RepoID: repoId, | |||||
| Type: ctx.QueryInt("type"), | |||||
| New: -1, | |||||
| Status: 0, | |||||
| RepoID: repoId, | |||||
| Type: ctx.QueryInt("type"), | |||||
| New: -1, | |||||
| Status: 0, | |||||
| IsOnlyThisRepo: true, | |||||
| IsQueryPrivate: isQueryPrivate, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("Cloudbrain", err) | ctx.ServerError("Cloudbrain", err) | ||||
| @@ -1168,7 +1290,9 @@ func QueryModelListForPredict(ctx *context.Context) { | |||||
| nameMap := make(map[string][]*models.AiModelManage) | nameMap := make(map[string][]*models.AiModelManage) | ||||
| for _, model := range modelResult { | for _, model := range modelResult { | ||||
| removeIpInfo(model) | |||||
| model.TrainTaskInfo = "" | |||||
| model.Accuracy = "" | |||||
| //removeIpInfo(model) | |||||
| if _, value := nameMap[model.Name]; !value { | if _, value := nameMap[model.Name]; !value { | ||||
| models := make([]*models.AiModelManage, 0) | models := make([]*models.AiModelManage, 0) | ||||
| models = append(models, model) | models = append(models, model) | ||||
| @@ -847,6 +847,9 @@ func createForGPU(ctx *context.Context, jobName string) error { | |||||
| codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath | codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath | ||||
| os.RemoveAll(codePath) | os.RemoveAll(codePath) | ||||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||||
| commitID, _ := gitRepo.GetBranchCommitID(cloudbrain.DefaultBranchName) | |||||
| if err := downloadCode(repo, codePath, cloudbrain.DefaultBranchName); err != nil { | if err := downloadCode(repo, codePath, cloudbrain.DefaultBranchName); err != nil { | ||||
| log.Error("downloadCode failed, %v", err, ctx.Data["MsgID"]) | log.Error("downloadCode failed, %v", err, ctx.Data["MsgID"]) | ||||
| return errors.New("system error") | return errors.New("system error") | ||||
| @@ -891,7 +894,7 @@ func createForGPU(ctx *context.Context, jobName string) error { | |||||
| BranchName: cloudbrain.DefaultBranchName, | BranchName: cloudbrain.DefaultBranchName, | ||||
| BootFile: BootFile, | BootFile: BootFile, | ||||
| Params: Params, | Params: Params, | ||||
| CommitID: "", | |||||
| CommitID: commitID, | |||||
| ModelName: modelName, | ModelName: modelName, | ||||
| ModelVersion: modelVersion, | ModelVersion: modelVersion, | ||||
| CkptName: CkptName, | CkptName: CkptName, | ||||
| @@ -29,6 +29,7 @@ import ( | |||||
| "code.gitea.io/gitea/modules/storage" | "code.gitea.io/gitea/modules/storage" | ||||
| "code.gitea.io/gitea/modules/upload" | "code.gitea.io/gitea/modules/upload" | ||||
| "code.gitea.io/gitea/modules/worker" | "code.gitea.io/gitea/modules/worker" | ||||
| repo_service "code.gitea.io/gitea/services/repository" | |||||
| gouuid "github.com/satori/go.uuid" | gouuid "github.com/satori/go.uuid" | ||||
| ) | ) | ||||
| @@ -180,6 +181,7 @@ func DeleteAttachment(ctx *context.Context) { | |||||
| ctx.Error(500, fmt.Sprintf("DeleteAttachment: %v", err)) | ctx.Error(500, fmt.Sprintf("DeleteAttachment: %v", err)) | ||||
| return | return | ||||
| } | } | ||||
| go repo_service.DecreaseRepoDatasetNum(attach.DatasetID) | |||||
| attachjson, _ := json.Marshal(attach) | attachjson, _ := json.Marshal(attach) | ||||
| labelmsg.SendDeleteAttachToLabelSys(string(attachjson)) | labelmsg.SendDeleteAttachToLabelSys(string(attachjson)) | ||||
| @@ -894,6 +896,7 @@ func CompleteMultipart(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| attachment.UpdateDatasetUpdateUnix() | attachment.UpdateDatasetUpdateUnix() | ||||
| go repo_service.IncreaseRepoDatasetNum(dataset.ID) | |||||
| repository, _ := models.GetRepositoryByID(dataset.RepoID) | repository, _ := models.GetRepositoryByID(dataset.RepoID) | ||||
| notification.NotifyOtherTask(ctx.User, repository, fmt.Sprint(repository.IsPrivate, attachment.IsPrivate), attachment.Name, models.ActionUploadAttachment) | notification.NotifyOtherTask(ctx.User, repository, fmt.Sprint(repository.IsPrivate, attachment.IsPrivate), attachment.Name, models.ActionUploadAttachment) | ||||
| if attachment.DatasetID != 0 { | if attachment.DatasetID != 0 { | ||||
| @@ -14,7 +14,13 @@ import ( | |||||
| ) | ) | ||||
| func CloudbrainDurationStatisticHour() { | func CloudbrainDurationStatisticHour() { | ||||
| if setting.IsCloudbrainTimingEnabled { | |||||
| defer func() { | |||||
| err := recover() | |||||
| if err == nil { | |||||
| return | |||||
| } | |||||
| }() | |||||
| if setting.IsCloudbrainTimingEnabled { | |||||
| var statisticTime time.Time | var statisticTime time.Time | ||||
| var count int64 | var count int64 | ||||
| recordDurationUpdateTime, err := models.GetDurationRecordUpdateTime() | recordDurationUpdateTime, err := models.GetDurationRecordUpdateTime() | ||||
| @@ -2337,7 +2337,7 @@ func InferenceJobIndex(ctx *context.Context) { | |||||
| tasks[i].ComputeResource = models.NPUResource | tasks[i].ComputeResource = models.NPUResource | ||||
| } | } | ||||
| } | } | ||||
| isQueryPrivate := isQueryPrivateModel(ctx) | |||||
| repoId := ctx.Repo.Repository.ID | repoId := ctx.Repo.Repository.ID | ||||
| Type := -1 | Type := -1 | ||||
| _, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{ | _, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{ | ||||
| @@ -2345,10 +2345,12 @@ func InferenceJobIndex(ctx *context.Context) { | |||||
| Page: 1, | Page: 1, | ||||
| PageSize: 2, | PageSize: 2, | ||||
| }, | }, | ||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| Status: 0, | |||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| IsOnlyThisRepo: true, | |||||
| Status: 0, | |||||
| IsQueryPrivate: isQueryPrivate, | |||||
| }) | }) | ||||
| ctx.Data["MODEL_COUNT"] = model_count | ctx.Data["MODEL_COUNT"] = model_count | ||||
| @@ -2417,7 +2419,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error { | |||||
| return err | return err | ||||
| } | } | ||||
| ctx.Data["config_list"] = configList.ParaConfigs | ctx.Data["config_list"] = configList.ParaConfigs | ||||
| isQueryPrivate := isQueryPrivateModel(ctx) | |||||
| repoId := ctx.Repo.Repository.ID | repoId := ctx.Repo.Repository.ID | ||||
| Type := -1 | Type := -1 | ||||
| _, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{ | _, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{ | ||||
| @@ -2425,10 +2427,12 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error { | |||||
| Page: 1, | Page: 1, | ||||
| PageSize: 2, | PageSize: 2, | ||||
| }, | }, | ||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| Status: 0, | |||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| IsOnlyThisRepo: true, | |||||
| Status: 0, | |||||
| IsQueryPrivate: isQueryPrivate, | |||||
| }) | }) | ||||
| ctx.Data["MODEL_COUNT"] = model_count | ctx.Data["MODEL_COUNT"] = model_count | ||||
| ctx.Data["datasetType"] = models.TypeCloudBrainTwo | ctx.Data["datasetType"] = models.TypeCloudBrainTwo | ||||
| @@ -166,6 +166,8 @@ func RepoStatisticDaily(date string) { | |||||
| repoStat.NumIssuesGrowth = repoStat.NumIssues - repoStatisticFourMonthsAgo.NumIssues | repoStat.NumIssuesGrowth = repoStat.NumIssues - repoStatisticFourMonthsAgo.NumIssues | ||||
| } | } | ||||
| models.SyncStatDataToRepo(repo) | |||||
| if _, err = models.InsertRepoStat(&repoStat); err != nil { | if _, err = models.InsertRepoStat(&repoStat); err != nil { | ||||
| log.Error("InsertRepoStat failed(%s): %v", projectName, err) | log.Error("InsertRepoStat failed(%s): %v", projectName, err) | ||||
| log.Error("failed statistic: %s", projectName) | log.Error("failed statistic: %s", projectName) | ||||
| @@ -21,6 +21,7 @@ import ( | |||||
| const ( | const ( | ||||
| PAGE_SIZE = 2000 | PAGE_SIZE = 2000 | ||||
| Excel_File_Path = "/useranalysis/" | Excel_File_Path = "/useranalysis/" | ||||
| USER_YEAR = 2022 | |||||
| ) | ) | ||||
| func getUserMetricsExcelHeader(ctx *context.Context) map[string]string { | func getUserMetricsExcelHeader(ctx *context.Context) map[string]string { | ||||
| @@ -104,6 +105,7 @@ func getExcelHeader(ctx *context.Context) map[string]string { | |||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.CloudBrainRunTime")) | excelHeader = append(excelHeader, ctx.Tr("user.static.CloudBrainRunTime")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.CommitDatasetNum")) | excelHeader = append(excelHeader, ctx.Tr("user.static.CommitDatasetNum")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.CommitModelCount")) | excelHeader = append(excelHeader, ctx.Tr("user.static.CommitModelCount")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.ModelConvertCount")) | |||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.FocusOtherUser")) | excelHeader = append(excelHeader, ctx.Tr("user.static.FocusOtherUser")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.CollectDataset")) | excelHeader = append(excelHeader, ctx.Tr("user.static.CollectDataset")) | ||||
| @@ -178,6 +180,8 @@ func writeExcel(row int, xlsx *excelize.File, sheetName string, userRecord *mode | |||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitModelCount) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitModelCount) | ||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.ModelConvertCount) | |||||
| tmp = tmp + 1 | |||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.FocusOtherUser) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.FocusOtherUser) | ||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CollectDataset) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CollectDataset) | ||||
| @@ -256,6 +260,8 @@ func writeExcelPage(row int, xlsx *excelize.File, sheetName string, userRecord * | |||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitModelCount) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitModelCount) | ||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.ModelConvertCount) | |||||
| tmp = tmp + 1 | |||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.FocusOtherUser) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.FocusOtherUser) | ||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CollectDataset) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CollectDataset) | ||||
| @@ -714,6 +720,12 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) { | |||||
| log.Info("startTime time:" + startTime.Format("2006-01-02 15:04:05")) | log.Info("startTime time:" + startTime.Format("2006-01-02 15:04:05")) | ||||
| log.Info("endTime time:" + endTime.Format("2006-01-02 15:04:05")) | log.Info("endTime time:" + endTime.Format("2006-01-02 15:04:05")) | ||||
| warnEmailMessage := "用户统计信息入库失败,请尽快定位。" | warnEmailMessage := "用户统计信息入库失败,请尽快定位。" | ||||
| startYear := time.Date(USER_YEAR, 1, 1, 0, 0, 0, 1, t.Location()) | |||||
| endYear := startYear.AddDate(1, 0, 0) | |||||
| models.RefreshUserYearTable(startYear, endYear) | |||||
| //query wiki data | //query wiki data | ||||
| log.Info("start to time count data") | log.Info("start to time count data") | ||||
| wikiMap, err := queryWikiCountMap(startTime, endTime) | wikiMap, err := queryWikiCountMap(startTime, endTime) | ||||
| @@ -907,3 +919,9 @@ func QueryUserLoginInfo(ctx *context.Context) { | |||||
| log.Info("writer exel error." + err.Error()) | log.Info("writer exel error." + err.Error()) | ||||
| } | } | ||||
| } | } | ||||
| func QueryUserAnnualReport(ctx *context.Context) { | |||||
| log.Info("start to QueryUserAnnualReport ") | |||||
| result := models.QueryUserAnnualReport(ctx.User.ID) | |||||
| ctx.JSON(http.StatusOK, result) | |||||
| } | |||||
| @@ -49,9 +49,10 @@ func getInvitationDetailExcelHeader(ctx *context.Context) map[string]string { | |||||
| excelHeader := make([]string, 0) | excelHeader := make([]string, 0) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.id")) | excelHeader = append(excelHeader, ctx.Tr("user.static.id")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.name")) | excelHeader = append(excelHeader, ctx.Tr("user.static.name")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.srcUserId")) | |||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.email")) | |||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.phone")) | excelHeader = append(excelHeader, ctx.Tr("user.static.phone")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.registdate")) | excelHeader = append(excelHeader, ctx.Tr("user.static.registdate")) | ||||
| excelHeader = append(excelHeader, ctx.Tr("user.static.srcUserId")) | |||||
| excelHeaderMap := make(map[string]string, 0) | excelHeaderMap := make(map[string]string, 0) | ||||
| var i byte | var i byte | ||||
| @@ -92,8 +93,7 @@ func writeInvitationDetailExcel(row int, xlsx *excelize.File, sheetName string, | |||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Name) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Name) | ||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.SrcUserID) | |||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Email) | |||||
| tmp = tmp + 1 | tmp = tmp + 1 | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone) | ||||
| @@ -101,7 +101,9 @@ func writeInvitationDetailExcel(row int, xlsx *excelize.File, sheetName string, | |||||
| formatTime := userRecord.CreatedUnix.Format("2006-01-02 15:04:05") | formatTime := userRecord.CreatedUnix.Format("2006-01-02 15:04:05") | ||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime[0:len(formatTime)-3]) | xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime[0:len(formatTime)-3]) | ||||
| tmp = tmp + 1 | |||||
| xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.SrcUserID) | |||||
| } | } | ||||
| func DownloadInvitationDetail(ctx *context.Context) { | func DownloadInvitationDetail(ctx *context.Context) { | ||||
| @@ -413,6 +415,7 @@ func queryData(ctx *context.Context, startTime time.Time, endTime time.Time) { | |||||
| invi.Name = tmpUser.Name | invi.Name = tmpUser.Name | ||||
| invi.Phone = tmpUser.PhoneNumber | invi.Phone = tmpUser.PhoneNumber | ||||
| invi.CreatedUnix = tmpUser.CreatedUnix | invi.CreatedUnix = tmpUser.CreatedUnix | ||||
| invi.Email = tmpUser.Email | |||||
| } else { | } else { | ||||
| invi.Name = "已注销" | invi.Name = "已注销" | ||||
| } | } | ||||
| @@ -371,7 +371,18 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/images/custom", repo.GetCustomImages) | m.Get("/images/custom", repo.GetCustomImages) | ||||
| m.Get("/images/star", repo.GetStarImages) | m.Get("/images/star", repo.GetStarImages) | ||||
| m.Get("/repos", routers.ExploreRepos) | |||||
| m.Group("/repos", func() { | |||||
| //m.Get("", routers.ExploreRepos) | |||||
| m.Get("", routers.GetRepoSearchPage) | |||||
| m.Group("/square", func() { | |||||
| m.Get("", routers.GetRepoSquarePage) | |||||
| m.Get("/tab", routers.RepoSquare) | |||||
| m.Get("/active-user", routers.ActiveUser) | |||||
| m.Get("/active-org", routers.ActiveOrg) | |||||
| }) | |||||
| m.Get("/search", routers.RepoFind) | |||||
| }) | |||||
| m.Get("/datasets", routers.ExploreDatasets) | m.Get("/datasets", routers.ExploreDatasets) | ||||
| m.Get("/users", routers.ExploreUsers) | m.Get("/users", routers.ExploreUsers) | ||||
| m.Get("/organizations", routers.ExploreOrganizations) | m.Get("/organizations", routers.ExploreOrganizations) | ||||
| @@ -1251,6 +1262,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Post("/delete_model_convert/:id", repo.DeleteModelConvert) | m.Post("/delete_model_convert/:id", repo.DeleteModelConvert) | ||||
| m.Post("/convert_stop/:id", repo.StopModelConvert) | m.Post("/convert_stop/:id", repo.StopModelConvert) | ||||
| m.Put("/modify_model", repo.ModifyModelInfo) | m.Put("/modify_model", repo.ModifyModelInfo) | ||||
| m.Put("/modify_model_status", repo.ModifyModelPrivate) | |||||
| m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) | m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) | ||||
| m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate) | m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate) | ||||
| m.Get("/show_model_info", repo.ShowModelInfo) | m.Get("/show_model_info", repo.ShowModelInfo) | ||||
| @@ -63,7 +63,7 @@ func InviationTpl(ctx *context.Context) { | |||||
| ctx.HTML(200, tplInvitation) | ctx.HTML(200, tplInvitation) | ||||
| } | } | ||||
| func RegisteUserByInvitaionCode(invitationcode string, newUserId int64, newPhoneNumber string) error { | |||||
| func RegisteUserByInvitaionCode(invitationcode string, newUserId int64, newPhoneNumber string, email string) error { | |||||
| user := parseInvitaionCode(invitationcode) | user := parseInvitaionCode(invitationcode) | ||||
| if user == nil { | if user == nil { | ||||
| return errors.New("The invitated user not existed.") | return errors.New("The invitated user not existed.") | ||||
| @@ -85,6 +85,7 @@ func RegisteUserByInvitaionCode(invitationcode string, newUserId int64, newPhone | |||||
| SrcUserID: user.ID, | SrcUserID: user.ID, | ||||
| UserID: newUserId, | UserID: newUserId, | ||||
| Phone: newPhoneNumber, | Phone: newPhoneNumber, | ||||
| Email: email, | |||||
| } | } | ||||
| err := models.InsertInvitaion(invitation) | err := models.InsertInvitaion(invitation) | ||||
| @@ -1382,7 +1382,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo | |||||
| log.Info("enter here, and form.InvitaionCode =" + invitationCode) | log.Info("enter here, and form.InvitaionCode =" + invitationCode) | ||||
| if invitationCode != "" { | if invitationCode != "" { | ||||
| RegisteUserByInvitaionCode(invitationCode, u.ID, u.PhoneNumber) | |||||
| RegisteUserByInvitaionCode(invitationCode, u.ID, u.PhoneNumber, u.Email) | |||||
| } | } | ||||
| err := models.AddEmailAddress(&models.EmailAddress{ | err := models.AddEmailAddress(&models.EmailAddress{ | ||||
| @@ -0,0 +1,88 @@ | |||||
| package repository | |||||
| import ( | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/git" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/redis/redis_client" | |||||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||||
| "encoding/json" | |||||
| "github.com/patrickmn/go-cache" | |||||
| "time" | |||||
| ) | |||||
| var repoContributorCache = cache.New(5*time.Minute, 1*time.Minute) | |||||
| type ContributorCacheVal struct { | |||||
| Contributors []*models.ContributorInfo | |||||
| Total int | |||||
| } | |||||
| func GetRepoTopNContributors(repo *models.Repository, N int) ([]*models.ContributorInfo, int) { | |||||
| val, _ := redis_client.Get(redis_key.RepoTopNContributors(repo.ID, N)) | |||||
| if val != "" { | |||||
| log.Debug("Get RepoTopNContributors from redis,repo.ID = %d value = %v", repo.ID, val) | |||||
| temp := &ContributorCacheVal{} | |||||
| json.Unmarshal([]byte(val), temp) | |||||
| return temp.Contributors, temp.Total | |||||
| } | |||||
| contributorInfos, total := getRepoTopNContributorsFromDisk(repo, N) | |||||
| log.Debug("Get RepoTopNContributors from disk,repo.ID = %d ", repo.ID) | |||||
| jsonVal, err := json.Marshal(&ContributorCacheVal{Contributors: contributorInfos, Total: total}) | |||||
| if err == nil { | |||||
| redis_client.Setex(redis_key.RepoTopNContributors(repo.ID, N), string(jsonVal), 2*time.Minute) | |||||
| } | |||||
| return contributorInfos, total | |||||
| } | |||||
| func getRepoTopNContributorsFromDisk(repo *models.Repository, N int) ([]*models.ContributorInfo, int) { | |||||
| contributorInfos := make([]*models.ContributorInfo, 0) | |||||
| branchName := GetDefaultBranchName(repo) | |||||
| if branchName == "" { | |||||
| return contributorInfos, 0 | |||||
| } | |||||
| contributors, err := git.GetContributors(repo.RepoPath(), branchName) | |||||
| if err == nil && contributors != nil { | |||||
| contributorInfoHash := make(map[string]*models.ContributorInfo) | |||||
| for _, c := range contributors { | |||||
| if len(contributorInfos) >= N { | |||||
| break | |||||
| } | |||||
| if c.Email == "" { | |||||
| 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 = &models.ContributorInfo{ | |||||
| user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt, | |||||
| } | |||||
| 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 = &models.ContributorInfo{ | |||||
| "", "", c.Email, c.CommitCnt, | |||||
| } | |||||
| contributorInfos = append(contributorInfos, newContributor) | |||||
| contributorInfoHash[c.Email] = newContributor | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return contributorInfos, len(contributors) | |||||
| } | |||||
| @@ -5,18 +5,19 @@ | |||||
| package repository | package repository | ||||
| import ( | import ( | ||||
| "fmt" | |||||
| "io/ioutil" | |||||
| "net/http" | |||||
| "os" | |||||
| "strings" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/git" | |||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/notification" | "code.gitea.io/gitea/modules/notification" | ||||
| repo_module "code.gitea.io/gitea/modules/repository" | repo_module "code.gitea.io/gitea/modules/repository" | ||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| pull_service "code.gitea.io/gitea/services/pull" | pull_service "code.gitea.io/gitea/services/pull" | ||||
| "fmt" | |||||
| "io/ioutil" | |||||
| "net/http" | |||||
| "os" | |||||
| "strings" | |||||
| "xorm.io/xorm" | |||||
| ) | ) | ||||
| const SHELL_FLAG_ON = 1 | const SHELL_FLAG_ON = 1 | ||||
| @@ -328,3 +329,47 @@ func IsUploadFileInvalidErr(err error) bool { | |||||
| _, ok := err.(UploadFileInvalidErr) | _, ok := err.(UploadFileInvalidErr) | ||||
| return ok | return ok | ||||
| } | } | ||||
| func IncreaseRepoDatasetNum(datasetID int64, engines ...*xorm.Engine) error { | |||||
| dataset, err := models.GetDatasetByID(datasetID) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| return models.OperateRepoDatasetNum(dataset.RepoID, 1, engines...) | |||||
| } | |||||
| func IncreaseRepoModelNum(repoId int64, engines ...*xorm.Engine) error { | |||||
| return models.OperateRepoModelNum(repoId, 1, engines...) | |||||
| } | |||||
| func ResetRepoModelNum(repoId int64) error { | |||||
| return models.ResetRepoModelNum(repoId) | |||||
| } | |||||
| func DecreaseRepoDatasetNum(datasetID int64, engines ...*xorm.Engine) error { | |||||
| dataset, err := models.GetDatasetByID(datasetID) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| return models.OperateRepoDatasetNum(dataset.RepoID, -1, engines...) | |||||
| } | |||||
| func DecreaseRepoModelNum(repoId int64, engines ...*xorm.Engine) error { | |||||
| return models.OperateRepoModelNum(repoId, -1, engines...) | |||||
| } | |||||
| func GetDefaultBranchName(repo *models.Repository) string { | |||||
| gitRepo, err := git.OpenRepository(repo.RepoPath()) | |||||
| if err != nil { | |||||
| return "" | |||||
| } | |||||
| defer gitRepo.Close() | |||||
| if len(repo.DefaultBranch) > 0 && gitRepo.IsBranchExist(repo.DefaultBranch) { | |||||
| return repo.DefaultBranch | |||||
| } | |||||
| brs, _, err := gitRepo.GetBranches(0, 0) | |||||
| if len(brs) > 0 { | |||||
| return brs[0] | |||||
| } | |||||
| return "" | |||||
| } | |||||
| @@ -0,0 +1,315 @@ | |||||
| package repository | |||||
| import ( | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "encoding/json" | |||||
| "github.com/patrickmn/go-cache" | |||||
| "time" | |||||
| ) | |||||
| var repoSquareCache = cache.New(2*time.Minute, 1*time.Minute) | |||||
| const ( | |||||
| RREFERED_CACHE = "PreferredRepos" | |||||
| REPO_BANNER_CACHE = "RepoBanner" | |||||
| TOPICS_CACHE = "RepoTopics" | |||||
| RECOMMEND_CACHE = "RecommendRepos" | |||||
| ) | |||||
| func GetBanners() []map[string]string { | |||||
| v, success := repoSquareCache.Get(REPO_BANNER_CACHE) | |||||
| if success { | |||||
| log.Debug("GetBanners from cache,value = %v", v) | |||||
| if v == nil { | |||||
| return nil | |||||
| } | |||||
| r := v.([]map[string]string) | |||||
| return r | |||||
| } | |||||
| repoMap := getMapContent("repos/square_banner") | |||||
| repoSquareCache.Set(REPO_BANNER_CACHE, repoMap, 1*time.Minute) | |||||
| return repoMap | |||||
| } | |||||
| func GetTopics() []string { | |||||
| v, success := repoSquareCache.Get(TOPICS_CACHE) | |||||
| if success { | |||||
| log.Debug("GetTopics from cache,value = %v", v) | |||||
| if v == nil { | |||||
| return nil | |||||
| } | |||||
| r := v.([]string) | |||||
| return r | |||||
| } | |||||
| topics := getArrayContent("repos/recommend_topics") | |||||
| repoSquareCache.Set(TOPICS_CACHE, topics, 1*time.Minute) | |||||
| return topics | |||||
| } | |||||
| func getMapContent(fileName string) []map[string]string { | |||||
| url := setting.RecommentRepoAddr + fileName | |||||
| result, err := RecommendContentFromPromote(url) | |||||
| remap := make([]map[string]string, 0) | |||||
| if err == nil { | |||||
| json.Unmarshal([]byte(result), &remap) | |||||
| } | |||||
| return remap | |||||
| } | |||||
| func getArrayContent(fileName string) []string { | |||||
| url := setting.RecommentRepoAddr + fileName | |||||
| result, err := RecommendContentFromPromote(url) | |||||
| r := make([]string, 0) | |||||
| if err == nil { | |||||
| json.Unmarshal([]byte(result), &r) | |||||
| } | |||||
| return r | |||||
| } | |||||
| func GetRecommendRepos() []map[string]interface{} { | |||||
| v, success := repoSquareCache.Get(RECOMMEND_CACHE) | |||||
| if success { | |||||
| log.Debug("GetRecommendRepos from cache,value = %v", v) | |||||
| if v == nil { | |||||
| return nil | |||||
| } | |||||
| r := v.([]map[string]interface{}) | |||||
| return r | |||||
| } | |||||
| repoMap := getMapContent("home/projects") | |||||
| r, _ := GetRecommendRepoFromPromote(repoMap) | |||||
| repoSquareCache.Set(RECOMMEND_CACHE, r, 1*time.Minute) | |||||
| return r | |||||
| } | |||||
| func GetPreferredRepos() ([]*models.Repository4Card, error) { | |||||
| v, success := repoSquareCache.Get(RREFERED_CACHE) | |||||
| if success { | |||||
| log.Debug("GetPreferredRepos from cache,value = %v", v) | |||||
| if v == nil { | |||||
| return nil, nil | |||||
| } | |||||
| r := v.([]*models.Repository4Card) | |||||
| return r, nil | |||||
| } | |||||
| repos, err := models.GetSelectedRepos(models.FindSelectedReposOpts{ | |||||
| ListOptions: models.ListOptions{ | |||||
| PageSize: 10, | |||||
| Page: 1, | |||||
| }, | |||||
| OnlyPublic: true, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| result := make([]*models.Repository4Card, len(repos)) | |||||
| for i, r := range repos { | |||||
| result[i] = r.ToCardFormat() | |||||
| } | |||||
| repoSquareCache.Set(RREFERED_CACHE, result, 1*time.Minute) | |||||
| return result, nil | |||||
| } | |||||
| func GetIncubationRepos() ([]*models.Repository4Card, error) { | |||||
| org, err := models.GetOrgByName(setting.IncubationSourceOrgName) | |||||
| if models.IsErrOrgNotExist(err) { | |||||
| return make([]*models.Repository4Card, 0), nil | |||||
| } | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| repos, err := models.GetSelectedRepos(models.FindSelectedReposOpts{ | |||||
| ListOptions: models.ListOptions{ | |||||
| PageSize: 10, | |||||
| Page: 1, | |||||
| }, | |||||
| OrgId: org.ID, | |||||
| OnlyPublic: true, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| result := make([]*models.Repository4Card, len(repos)) | |||||
| for i, r := range repos { | |||||
| result[i] = r.ToCardFormat() | |||||
| } | |||||
| return result, nil | |||||
| } | |||||
| func GetHotPaperRepos() ([]*models.Repository4Card, error) { | |||||
| rlist, _, err := models.SearchRepository(&models.SearchRepoOptions{ | |||||
| ListOptions: models.ListOptions{ | |||||
| Page: 1, | |||||
| PageSize: 10, | |||||
| }, | |||||
| OrderBy: models.SearchOrderByLastMonthVisitsReverse + "," + models.SearchOrderByRecentUpdated, | |||||
| TopicOnly: true, | |||||
| TopicName: setting.PaperRepoTopicName, | |||||
| AllPublic: true, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| result := make([]*models.Repository4Card, len(rlist)) | |||||
| for i, r := range rlist { | |||||
| result[i] = r.ToCardFormat() | |||||
| } | |||||
| return result, nil | |||||
| } | |||||
| type FindReposOptions struct { | |||||
| models.ListOptions | |||||
| Actor *models.User | |||||
| Sort string | |||||
| Keyword string | |||||
| Topic string | |||||
| Private bool | |||||
| OwnerID int64 | |||||
| } | |||||
| func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) { | |||||
| var ( | |||||
| repos []*models.Repository | |||||
| count int64 | |||||
| err error | |||||
| orderBy models.SearchOrderBy | |||||
| ) | |||||
| switch opts.Sort { | |||||
| //1.近期热门:按最近1个月浏览量倒序排序,最近1个月浏览量>最近更新>项目名称升序 | |||||
| case "mostpopular": | |||||
| orderBy = models.SearchOrderByLastMonthVisitsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //2.近期活跃:按提交增长量(最近4个月commit数)倒序排序,提交增长量>最近更新>项目名称升序。 | |||||
| case "mostactive": | |||||
| orderBy = models.SearchOrderByLastFourMonthCommitsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //3.最近更新:按最近更新>项目名称升序排序。 | |||||
| case "recentupdate": | |||||
| orderBy = models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //4.最近创建:按项目创建时间排序,最近的排前面。最近创建>项目名称升序。 | |||||
| case "newest": | |||||
| orderBy = models.SearchOrderByNewest + "," + models.SearchOrderByAlphabetically | |||||
| //5.点赞最多:按点赞数倒序排序。点赞数>最近更新>项目名称升序。 | |||||
| case "moststars": | |||||
| orderBy = models.SearchOrderByStarsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //6.派生最多:按派生数倒序排序。派生数>最近更新>项目名称升序。 | |||||
| case "mostforks": | |||||
| orderBy = models.SearchOrderByForksReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //7.数据集最多:按项目包含的数据集文件数量倒序排序,数据集文件数>最近更新>项目名称升序。 | |||||
| case "mostdatasets": | |||||
| orderBy = models.SearchOrderByDatasetCntReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //8.AI任务最多:按项目包含的AI任务数量倒序排序,AI任务数>最近更新>项目名称升序。 | |||||
| case "mostaitasks": | |||||
| orderBy = models.SearchOrderByAiTaskCntReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| //9.模型最多:按项目包含的模型数量倒序排序,模型大小为0则不统计。模型数>最近更新>项目名称升序。 | |||||
| case "mostmodels": | |||||
| orderBy = models.SearchOrderByModelCntReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| default: | |||||
| orderBy = models.SearchOrderByLastMonthVisitsReverse + "," + models.SearchOrderByRecentUpdated + "," + models.SearchOrderByAlphabetically | |||||
| } | |||||
| repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ | |||||
| ListOptions: opts.ListOptions, | |||||
| Actor: opts.Actor, | |||||
| OrderBy: orderBy, | |||||
| Private: opts.Private, | |||||
| Keyword: opts.Keyword, | |||||
| OwnerID: opts.OwnerID, | |||||
| AllPublic: true, | |||||
| AllLimited: true, | |||||
| TopicName: opts.Topic, | |||||
| IncludeDescription: setting.UI.SearchRepoDescription, | |||||
| }) | |||||
| if err != nil { | |||||
| log.Error("FindRepos error when SearchRepository.%v", err) | |||||
| return nil, err | |||||
| } | |||||
| result := make([]*models.Repository4Card, len(repos)) | |||||
| for i, r := range repos { | |||||
| t := r.ToCardFormat() | |||||
| contributors, _ := GetRepoTopNContributors(r, 6) | |||||
| t.Contributors = contributors | |||||
| result[i] = t | |||||
| } | |||||
| return &models.FindReposResponse{ | |||||
| Repos: result, | |||||
| Total: count, | |||||
| Page: opts.Page, | |||||
| PageSize: opts.PageSize, | |||||
| }, nil | |||||
| } | |||||
| type ActiveUser struct { | |||||
| User *models.User4Front | |||||
| Followed bool | |||||
| ShowButton bool | |||||
| } | |||||
| func GetActiveUser4Square(currentUserId int64) ([]*ActiveUser, error) { | |||||
| result := make([]*ActiveUser, 0) | |||||
| userIds, err := models.QueryLast30DaysHighestIndexUsers(5) | |||||
| if err != nil { | |||||
| log.Error("ActiveUser err. %v", err) | |||||
| return result, err | |||||
| } | |||||
| if len(userIds) == 0 { | |||||
| return result, nil | |||||
| } | |||||
| users, err := models.GetUsersByIDs(userIds) | |||||
| if err != nil { | |||||
| return result, nil | |||||
| } | |||||
| usersMap := make(map[int64]*models.User) | |||||
| for _, v := range users { | |||||
| usersMap[v.ID] = v | |||||
| } | |||||
| for i := 0; i < len(userIds); i++ { | |||||
| userId := userIds[i] | |||||
| user := usersMap[userId] | |||||
| if user == nil { | |||||
| continue | |||||
| } | |||||
| isFollowed := false | |||||
| if currentUserId != 0 { | |||||
| isFollowed = models.IsFollowing(currentUserId, userId) | |||||
| } | |||||
| a := &ActiveUser{ | |||||
| Followed: isFollowed, | |||||
| User: user.ToFrontFormat(), | |||||
| ShowButton: currentUserId != userId, | |||||
| } | |||||
| result = append(result, a) | |||||
| } | |||||
| return result, nil | |||||
| } | |||||
| func GetActiveOrgs() ([]*models.User4Front, error) { | |||||
| orgScores, err := models.FindTopNOpenIOrgs(5) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| orgs := make([]*models.User4Front, len(orgScores)) | |||||
| for i, v := range orgScores { | |||||
| orgs[i] = v.ToFrontFormat() | |||||
| } | |||||
| return orgs, nil | |||||
| } | |||||
| func RefreshRepoStatData() { | |||||
| repos, err := models.GetAllRepositories() | |||||
| if err != nil { | |||||
| log.Error("RefreshRepoStatData GetAllRepositories failed: %v", err.Error()) | |||||
| return | |||||
| } | |||||
| for _, repo := range repos { | |||||
| models.SyncStatDataToRepo(repo) | |||||
| } | |||||
| } | |||||
| @@ -35,7 +35,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -48,7 +48,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -75,7 +75,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -89,7 +89,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu" > | <div class="menu" > | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -100,7 +100,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "home"}}</a> | |||||
| {{else if .IsLandingPageOrganizations}} | {{else if .IsLandingPageOrganizations}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | ||||
| {{end}} | {{end}} | ||||
| @@ -32,7 +32,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -45,7 +45,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -71,7 +71,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -84,7 +84,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -95,7 +95,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "home"}}</a> | |||||
| {{else if .IsLandingPageOrganizations}} | {{else if .IsLandingPageOrganizations}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | ||||
| {{end}} | {{end}} | ||||
| @@ -24,7 +24,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -37,7 +37,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -64,7 +64,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -77,7 +77,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -88,7 +88,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "home"}}</a> | |||||
| {{else if .IsLandingPageOrganizations}} | {{else if .IsLandingPageOrganizations}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | ||||
| {{end}} | {{end}} | ||||
| @@ -34,7 +34,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
| <div class="ui simple dropdown item" > | <div class="ui simple dropdown item" > | ||||
| {{.i18n.Tr "repo.model_manager"}} | {{.i18n.Tr "repo.model_manager"}} | ||||
| @@ -47,7 +47,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -87,7 +87,7 @@ | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu" > | <div class="menu" > | ||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>--> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsOperator}} | {{if .IsOperator}} | ||||
| @@ -98,7 +98,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos/square">{{.i18n.Tr "home"}}</a> | |||||
| {{else if .IsLandingPageOrganizations}} | {{else if .IsLandingPageOrganizations}} | ||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | ||||
| {{end}} | {{end}} | ||||
| @@ -1,6 +1,6 @@ | |||||
| <div class="tablet only mobile only sixteen wide mobile sixteen wide tablet column row"> | <div class="tablet only mobile only sixteen wide mobile sixteen wide tablet column row"> | ||||
| <div class="ui secondary pointing tabular top attached borderless menu navbar"> | <div class="ui secondary pointing tabular top attached borderless menu navbar"> | ||||
| <a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore/repos"> | |||||
| <a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore/repos/square"> | |||||
| {{svg "octicon-repo" 16}} {{.i18n.Tr "explore.repos"}} | {{svg "octicon-repo" 16}} {{.i18n.Tr "explore.repos"}} | ||||
| </a> | </a> | ||||
| <a class="{{if .PageIsDatasets}}active{{end}} item" href="{{AppSubUrl}}/explore/datasets"> | <a class="{{if .PageIsDatasets}}active{{end}} item" href="{{AppSubUrl}}/explore/datasets"> | ||||
| @@ -24,7 +24,7 @@ | |||||
| <div class="computer only three wide computer column"> | <div class="computer only three wide computer column"> | ||||
| <div class="ui grid"> | <div class="ui grid"> | ||||
| <div class="sixteen wide column ui secondary sticky pointing tabular vertical menu"> | <div class="sixteen wide column ui secondary sticky pointing tabular vertical menu"> | ||||
| <a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore/repos"> | |||||
| <a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore/repos/square"> | |||||
| {{svg "octicon-repo" 16}} {{.i18n.Tr "explore.repos"}} | {{svg "octicon-repo" 16}} {{.i18n.Tr "explore.repos"}} | ||||
| </a> | </a> | ||||
| <a class="{{if .PageIsDatasets}}active{{end}} item" href="{{AppSubUrl}}/explore/datasets"> | <a class="{{if .PageIsDatasets}}active{{end}} item" href="{{AppSubUrl}}/explore/datasets"> | ||||
| @@ -0,0 +1,8 @@ | |||||
| {{template "base/head_home" .}} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-repos-search.css?v={{MD5 AppVer}}" /> | |||||
| <script> | |||||
| var staticSquareTopics = {{ .SquareTopics }}; | |||||
| </script> | |||||
| <div id="__vue-root"></div> | |||||
| <script src="{{StaticUrlPrefix}}/js/vp-repos-search.js?v={{MD5 AppVer}}"></script> | |||||
| {{template "base/footer" .}} | |||||
| @@ -0,0 +1,16 @@ | |||||
| {{template "base/head_home" .}} | |||||
| {{ if .SquareBanners }} | |||||
| {{ range .SquareBanners }} | |||||
| <img preload style="height:0;width:0;position:absolute;left:-2000px;" src="{{.src}}" /> | |||||
| {{ end }} | |||||
| {{ end }} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-repos-square.css?v={{MD5 AppVer}}" /> | |||||
| <script> | |||||
| var staticSquareBanners = {{ .SquareBanners }}; | |||||
| var staticSquarePreferredRepos = {{ .SquarePreferredRepos }}; | |||||
| var staticSquareTopics = {{ .SquareTopics }}; | |||||
| var staticSquareRecommendRepos = {{ .SquareRecommendRepos }}; | |||||
| </script> | |||||
| <div id="__vue-root"></div> | |||||
| <script src="{{StaticUrlPrefix}}/js/vp-repos-square.js?v={{MD5 AppVer}}"></script> | |||||
| {{template "base/footer" .}} | |||||
| @@ -647,6 +647,23 @@ | |||||
| <input style="width: 83%;margin-left: 7px;" id="label" name="label" maxlength="255" | <input style="width: 83%;margin-left: 7px;" id="label" name="label" maxlength="255" | ||||
| placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | ||||
| </div> | </div> | ||||
| <div class="inline fields"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess"}} </label> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" checked="checked" value="false"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.public"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" value="true"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.private"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label> | <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label> | ||||
| <textarea style="width: 83%;margin-left: 7px;" id="description" name="description" rows="3" | <textarea style="width: 83%;margin-left: 7px;" id="description" name="description" rows="3" | ||||
| @@ -849,6 +866,10 @@ | |||||
| } | } | ||||
| let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | ||||
| let data = $("#formId").serialize() | let data = $("#formId").serialize() | ||||
| var radio = document.getElementsByName("isPrivate"); | |||||
| if(radio == null || radio.length == 0){ | |||||
| data +="&isPrivate=true"; | |||||
| } | |||||
| $("#mask").css({ "display": "block", "z-index": "9999" }) | $("#mask").css({ "display": "block", "z-index": "9999" }) | ||||
| $.ajax({ | $.ajax({ | ||||
| url: url_href, | url: url_href, | ||||
| @@ -679,6 +679,23 @@ | |||||
| <input style="width: 83%;margin-left: 7px;" id="label" name="label" maxlength="255" | <input style="width: 83%;margin-left: 7px;" id="label" name="label" maxlength="255" | ||||
| placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | ||||
| </div> | </div> | ||||
| <div class="inline fields"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess"}} </label> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" checked="checked" value="false"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.public"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" value="true"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.private"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label> | <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label> | ||||
| <textarea style="width: 83%;margin-left: 7px;" id="description" name="description" rows="3" | <textarea style="width: 83%;margin-left: 7px;" id="description" name="description" rows="3" | ||||
| @@ -910,6 +927,10 @@ | |||||
| } | } | ||||
| let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | ||||
| let data = $("#formId").serialize() | let data = $("#formId").serialize() | ||||
| var radio = document.getElementsByName("isPrivate"); | |||||
| if(radio == null || radio.length == 0){ | |||||
| data +="&isPrivate=true"; | |||||
| } | |||||
| $("#mask").css({ "display": "block", "z-index": "9999" }) | $("#mask").css({ "display": "block", "z-index": "9999" }) | ||||
| $.ajax({ | $.ajax({ | ||||
| url: url_href, | url: url_href, | ||||
| @@ -703,6 +703,25 @@ | |||||
| <input style="width: 83%;margin-left: 7px;" id="label" name="label" maxlength="255" | <input style="width: 83%;margin-left: 7px;" id="label" name="label" maxlength="255" | ||||
| placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | ||||
| </div> | </div> | ||||
| {{if eq $.Repository.IsPrivate false}} | |||||
| <div class="inline fields"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess"}} </label> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" checked="checked" value="false"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.public"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" value="true"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.private"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{end}} | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label> | <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label> | ||||
| <textarea style="width: 83%;margin-left: 7px;" id="description" name="description" rows="3" | <textarea style="width: 83%;margin-left: 7px;" id="description" name="description" rows="3" | ||||
| @@ -930,6 +949,10 @@ | |||||
| } | } | ||||
| let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | ||||
| let data = $("#formId").serialize() | let data = $("#formId").serialize() | ||||
| var radio = document.getElementsByName("isPrivate"); | |||||
| if(radio == null || radio.length == 0){ | |||||
| data +="&isPrivate=true"; | |||||
| } | |||||
| $("#mask").css({ "display": "block", "z-index": "9999" }) | $("#mask").css({ "display": "block", "z-index": "9999" }) | ||||
| $.ajax({ | $.ajax({ | ||||
| url: url_href, | url: url_href, | ||||
| @@ -487,7 +487,7 @@ | |||||
| } | } | ||||
| function loadModelList(){ | function loadModelList(){ | ||||
| $.get(`${repolink}/modelmanage/query_model_for_predict?repoId=${repoId}&type=-1`, (data) => { | |||||
| $.get(`${repolink}/modelmanage/query_model_for_predict?repoId=${repoId}&type=-1&isOnlyThisRepo=true`, (data) => { | |||||
| modelData = data | modelData = data | ||||
| let nameList = data.nameList | let nameList = data.nameList | ||||
| const n_length = nameList.length | const n_length = nameList.length | ||||
| @@ -2,6 +2,7 @@ | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create-1.css?v={{MD5 AppVer}}" /> | <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create-1.css?v={{MD5 AppVer}}" /> | ||||
| <div class="repository release dataset-list view"> | <div class="repository release dataset-list view"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <script>var REPO_IS_PRIVATE = {{$.Repository.IsPrivate}};</script> | |||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <div id="__vue-root"></div> | <div id="__vue-root"></div> | ||||
| </div> | </div> | ||||
| @@ -135,6 +135,25 @@ | |||||
| <input class="ays-ignore" id="label" name="label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | <input class="ays-ignore" id="label" name="label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{if eq $.Repository.IsPrivate false}} | |||||
| <div class="inline fields"> | |||||
| <div class="two wide field right aligned"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess"}}  </label> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" checked="checked" value="false"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.public"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="isPrivate" value="true"> | |||||
| <label>{{.i18n.Tr "repo.model.manage.modelaccess.private"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{end}} | |||||
| <div class="inline fields"> | <div class="inline fields"> | ||||
| <div class="two wide field right aligned"> | <div class="two wide field right aligned"> | ||||
| <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}  </label> | <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}  </label> | ||||
| @@ -549,6 +568,10 @@ | |||||
| let cName = $("input[name='name']").val(); | let cName = $("input[name='name']").val(); | ||||
| let version = $("input[name='version']").val(); | let version = $("input[name='version']").val(); | ||||
| let data = $("#formId").serialize(); | let data = $("#formId").serialize(); | ||||
| var radio = document.getElementsByName("isPrivate"); | |||||
| if(radio == null || radio.length == 0){ | |||||
| data +="&isPrivate=true"; | |||||
| } | |||||
| const initModel = $("input[name='initModel']").val(); | const initModel = $("input[name='initModel']").val(); | ||||
| let url_href = location.href.split("create_online_model")[0] + 'create_new_model'; | let url_href = location.href.split("create_online_model")[0] + 'create_new_model'; | ||||
| $("#mask").css({ display: "block", "z-index": "9999" }); | $("#mask").css({ display: "block", "z-index": "9999" }); | ||||
| @@ -44,7 +44,7 @@ | |||||
| } | } | ||||
| </style> | </style> | ||||
| <link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css"> | <link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css"> | ||||
| <script>var REPO_IS_PRIVATE = {{.Repository.IsPrivate}};</script> | |||||
| <!-- 弹窗 --> | <!-- 弹窗 --> | ||||
| <div id="mask"> | <div id="mask"> | ||||
| @@ -57,6 +57,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{$repository := .Repository.ID}} | {{$repository := .Repository.ID}} | ||||
| <!-- 提示框 --> | <!-- 提示框 --> | ||||
| <div class="alert"></div> | <div class="alert"></div> | ||||
| @@ -234,6 +235,7 @@ | |||||
| <input id="label" name="label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | <input id="label" name="label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="inline fields"> | <div class="inline fields"> | ||||
| <div class="two wide field right aligned"> | <div class="two wide field right aligned"> | ||||
| <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}  </label> | <label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}  </label> | ||||
| @@ -10,7 +10,7 @@ | |||||
| {{.i18n.Tr "home.wecome_AI_plt"}} | {{.i18n.Tr "home.wecome_AI_plt"}} | ||||
| </div> | </div> | ||||
| <div class="content"> | <div class="content"> | ||||
| <p class="ui text grey">{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p> | |||||
| <p class="ui text grey">{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos/square"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p> | |||||
| <p><span class="ui text grey">{{.i18n.Tr "home.use_plt__fuction"}}</span> <a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p> | <p><span class="ui text grey">{{.i18n.Tr "home.use_plt__fuction"}}</span> <a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p> | ||||
| <p class="ui text grey">{{.i18n.Tr "home.provide_resoure"}}</p> | <p class="ui text grey">{{.i18n.Tr "home.provide_resoure"}}</p> | ||||
| </div> | </div> | ||||
| @@ -32,18 +32,7 @@ | |||||
| > | > | ||||
| </template> | </template> | ||||
| </el-table-column> | </el-table-column> | ||||
| <el-table-column | |||||
| prop="status" | |||||
| :label="i18n.model_status" | |||||
| align="center" | |||||
| min-width="6.5%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over" :title="scope.row.status_title"> | |||||
| <i style="vertical-align: middle" :class="scope.row.status"></i | |||||
| ></span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | <el-table-column | ||||
| prop="version" | prop="version" | ||||
| :label="i18n.model_version" | :label="i18n.model_version" | ||||
| @@ -101,6 +90,22 @@ | |||||
| <span class="text-over">{{ scope.row.computeResource }}</span> | <span class="text-over">{{ scope.row.computeResource }}</span> | ||||
| </template> | </template> | ||||
| </el-table-column> | </el-table-column> | ||||
| <el-table-column | |||||
| prop="isPrivate" | |||||
| :label="i18n.model_status" | |||||
| align="center" | |||||
| min-width="6.75%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over" :title="scope.row.status_title"> | |||||
| <i style="vertical-align: middle" :class="scope.row.status"></i | |||||
| ></span> | |||||
| <span style="color: #fa8c16;" v-if="scope.row.isPrivate">{{ i18n.modelaccess_private }}</span> | |||||
| <span style="color: #13c28d;" v-else="!scope.row.isPrivate">{{ i18n.modelaccess_public }}</span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | <el-table-column | ||||
| prop="createdUnix" | prop="createdUnix" | ||||
| :label="i18n.model_create_time" | :label="i18n.model_create_time" | ||||
| @@ -137,29 +142,23 @@ | |||||
| > | > | ||||
| <template slot-scope="scope"> | <template slot-scope="scope"> | ||||
| <div class="space-around" > | <div class="space-around" > | ||||
| <!--<a | |||||
| :style="{ | |||||
| visibility: !scope.row.Children ? 'visible' : 'hidden', | |||||
| }" | |||||
| :class="{ disabled: !scope.row.isCanOper }" | |||||
| @click=" | |||||
| showcreateVue( | |||||
| scope.row.name, | |||||
| scope.row.version, | |||||
| scope.row.label | |||||
| ) | |||||
| " | |||||
| >{{ i18n.model_create_new_ver }}</a | |||||
| >--> | |||||
| <a class="op-btn" | <a class="op-btn" | ||||
| v-show="scope.row.modelType == 1" | v-show="scope.row.modelType == 1" | ||||
| :href="url + 'create_local_model_1?type=1&name=' + encodeURIComponent(scope.row.name) + '&id=' + scope.row.id" | :href="url + 'create_local_model_1?type=1&name=' + encodeURIComponent(scope.row.name) + '&id=' + scope.row.id" | ||||
| :class="{ disabled: !scope.row.isCanOper }" | :class="{ disabled: !scope.row.isCanOper }" | ||||
| >{{ i18n.modify }}</a> | >{{ i18n.modify }}</a> | ||||
| <a class="op-btn" v-show="scope.row.modelType != 1" style="color:transparent;cursor:default;" >{{ i18n.modify }}</a> | |||||
| <a class="op-btn" v-show="scope.row.modelType != 1" style="color:transparent;cursor:default;" >{{ i18n.modify }}</a> | |||||
| <a class="op-btn" style="color: #13c28d;" v-show="repoIsPrivate == false && scope.row.isPrivate==true && scope.row.isCanOper" @click=" | |||||
| modifyModelStatus(scope.row.id, scope.row.cName, scope.row.rowKey,false) | |||||
| ">{{ i18n.modelaccess_setpublic }}</a> | |||||
| <a class="op-btn" style="color: #fa8c16;" v-show="repoIsPrivate == false && scope.row.isPrivate==false && scope.row.isCanOper" @click=" | |||||
| modifyModelStatus(scope.row.id, scope.row.cName, scope.row.rowKey,true) | |||||
| ">{{ i18n.modelaccess_setprivate }}</a> | |||||
| <a class="op-btn" | <a class="op-btn" | ||||
| :href="loadhref + scope.row.id" | :href="loadhref + scope.row.id" | ||||
| :class="{ disabled: !scope.row.isCanOper }" | |||||
| :class="{ disabled: !scope.row.isCanDownload }" | |||||
| >{{ i18n.model_download }}</a> | >{{ i18n.model_download }}</a> | ||||
| <a class="op-btn" | <a class="op-btn" | ||||
| :class="{ disabled: !scope.row.isCanDelete }" | :class="{ disabled: !scope.row.isCanDelete }" | ||||
| @@ -190,8 +189,9 @@ | |||||
| </template> | </template> | ||||
| <script> | <script> | ||||
| import { modifyModelStatus } from '~/apis/modules/modelmanage'; | |||||
| const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config; | const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config; | ||||
| const REPOISPRIVATE = window.REPO_IS_PRIVATE; | |||||
| export default { | export default { | ||||
| components: {}, | components: {}, | ||||
| data() { | data() { | ||||
| @@ -206,11 +206,13 @@ export default { | |||||
| isLoading: true, | isLoading: true, | ||||
| loadNodeMap: new Map(), | loadNodeMap: new Map(), | ||||
| submitId: {}, | submitId: {}, | ||||
| repo: location.pathname.split('/').slice(0, 3).join('/'), | |||||
| defaultAvatar: "/user/avatar/Ghost/-1", | defaultAvatar: "/user/avatar/Ghost/-1", | ||||
| defaultAvatarName: "Ghost", | defaultAvatarName: "Ghost", | ||||
| data: "", | data: "", | ||||
| timer: null, | timer: null, | ||||
| timerFlag: false, | timerFlag: false, | ||||
| repoIsPrivate: REPOISPRIVATE, | |||||
| }; | }; | ||||
| }, | }, | ||||
| methods: { | methods: { | ||||
| @@ -403,6 +405,26 @@ export default { | |||||
| } | } | ||||
| } | } | ||||
| }, | }, | ||||
| modifyModelStatus(id, name, rowKey,isPrivate) { | |||||
| let data = {'id':id,'isPrivate':isPrivate,'repo':this.repo}; | |||||
| modifyModelStatus(data).then(res => { | |||||
| res = res.data; | |||||
| if (res && res.code == '0') { | |||||
| this.getModelList(); | |||||
| } else { | |||||
| this.$message({ | |||||
| type: 'error', | |||||
| message: this.$t('modelManage.infoModificationFailed'), | |||||
| }); | |||||
| } | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| this.$message({ | |||||
| type: 'error', | |||||
| message: this.$t('modelManage.infoModificationFailed'), | |||||
| }); | |||||
| }); | |||||
| }, | |||||
| deleteModel(id, name, rowKey) { | deleteModel(id, name, rowKey) { | ||||
| let row = { cName: name, id: id, rowKey: rowKey }; | let row = { cName: name, id: id, rowKey: rowKey }; | ||||
| let _this = this; | let _this = this; | ||||
| @@ -542,6 +564,14 @@ export default { | |||||
| showinfoHref() { | showinfoHref() { | ||||
| return this.url + "show_model_info?name="; | return this.url + "show_model_info?name="; | ||||
| }, | }, | ||||
| transStatus(){ | |||||
| return function (state) { | |||||
| if(state){ | |||||
| return this.i18n.modelaccess_private; | |||||
| } | |||||
| return this.i18n.modelaccess_public; | |||||
| } | |||||
| }, | |||||
| transTime() { | transTime() { | ||||
| return function (time) { | return function (time) { | ||||
| let date = new Date(time * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000 | let date = new Date(time * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000 | ||||
| @@ -92,6 +92,11 @@ export const i18nVue = { | |||||
| model_create_time: "创建时间", | model_create_time: "创建时间", | ||||
| model_creator: "创建者", | model_creator: "创建者", | ||||
| model_operation: "操作", | model_operation: "操作", | ||||
| model_access: "权限", | |||||
| modelaccess_public:"公开", | |||||
| modelaccess_private:"私有", | |||||
| modelaccess_setpublic:"设为公开", | |||||
| modelaccess_setprivate:"设为私有", | |||||
| model_create_new_ver: "创建新版本", | model_create_new_ver: "创建新版本", | ||||
| model_download: "下载", | model_download: "下载", | ||||
| model_delete: "删除", | model_delete: "删除", | ||||
| @@ -208,6 +213,11 @@ export const i18nVue = { | |||||
| model_create_time: "Created Time", | model_create_time: "Created Time", | ||||
| model_creator: "Creator", | model_creator: "Creator", | ||||
| model_operation: "Operation", | model_operation: "Operation", | ||||
| model_access: "Access", | |||||
| modelaccess_public:"Public", | |||||
| modelaccess_private:"Private", | |||||
| modelaccess_setpublic:"Set Public", | |||||
| modelaccess_setprivate:"Set Private", | |||||
| model_create_new_ver: "New Version", | model_create_new_ver: "New Version", | ||||
| model_download: "Download", | model_download: "Download", | ||||
| model_delete: "Delete", | model_delete: "Delete", | ||||
| @@ -50,7 +50,7 @@ import initImage from "./features/images.js"; | |||||
| import selectDataset from "./components/dataset/selectDataset.vue"; | import selectDataset from "./components/dataset/selectDataset.vue"; | ||||
| import referenceDataset from "./components/dataset/referenceDataset.vue"; | import referenceDataset from "./components/dataset/referenceDataset.vue"; | ||||
| // import $ from 'jquery.js' | // import $ from 'jquery.js' | ||||
| import router from "./router/index.js"; | |||||
| // import router from "./router/index.js"; | |||||
| import { Message } from "element-ui"; | import { Message } from "element-ui"; | ||||
| import { i18nVue } from "./features/i18nVue.js"; | import { i18nVue } from "./features/i18nVue.js"; | ||||
| @@ -5214,7 +5214,7 @@ function initTopToHome() { | |||||
| $(window).scroll(function (e) { | $(window).scroll(function (e) { | ||||
| const scrollTop = $(document).scrollTop(); | const scrollTop = $(document).scrollTop(); | ||||
| const winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; | const winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; | ||||
| if (scrollTop > winHeight * 1.2) { | |||||
| if (scrollTop > winHeight * 0.5) { | |||||
| topToHomeEl.fadeIn(); | topToHomeEl.fadeIn(); | ||||
| } else { | } else { | ||||
| topToHomeEl.fadeOut(); | topToHomeEl.fadeOut(); | ||||
| @@ -0,0 +1,12 @@ | |||||
| import service from '../service'; | |||||
| // 获取promote配置数据 | |||||
| export const getPromoteData = (filePathName) => { | |||||
| return service({ | |||||
| url: '/dashboard/invitation', | |||||
| method: 'get', | |||||
| params: { | |||||
| filename: filePathName | |||||
| }, | |||||
| }); | |||||
| } | |||||
| @@ -24,6 +24,16 @@ export const modifyModel = (data) => { | |||||
| }); | }); | ||||
| }; | }; | ||||
| export const modifyModelStatus = (data) => { | |||||
| return service({ | |||||
| url: `${data.repo}/modelmanage/modify_model_status`, | |||||
| method: 'put', | |||||
| headers: { 'Content-type': 'application/x-www-form-urlencoded' }, | |||||
| params: {}, | |||||
| data: Qs.stringify(data), | |||||
| }); | |||||
| }; | |||||
| // 求模型信息 | // 求模型信息 | ||||
| export const getModelInfoByName = (params) => { | export const getModelInfoByName = (params) => { | ||||
| return service({ | return service({ | ||||
| @@ -0,0 +1,69 @@ | |||||
| import service from '../service'; | |||||
| // 获取首页数据 | |||||
| export const getHomePageData = () => { | |||||
| return service({ | |||||
| url: '/recommend/home', | |||||
| method: 'get', | |||||
| params: {}, | |||||
| }); | |||||
| } | |||||
| // 获取项目广场上方tab数据 tab=preferred 项目优选|incubation 启智孵化管道|hot-paper 热门论文项目 | |||||
| export const getReposSquareTabData = (tab) => { | |||||
| return service({ | |||||
| url: '/explore/repos/square/tab', | |||||
| method: 'get', | |||||
| params: { | |||||
| type: tab | |||||
| }, | |||||
| }); | |||||
| } | |||||
| // 搜索项目 | |||||
| // q string 否 关键词 | |||||
| // topic string 否 标签名 | |||||
| // sort string 是 mostpopular 近期热门 | mostactive 近期活跃 | recentupdate 最近更新 | newest 最近创建 | |||||
| // moststars 点赞最多 | mostforks 派生最多 | mostdatasets 数据集最多 | mostaitasks AI任务最多 | mostmodels 模型最多 | |||||
| // pageSize int 是 每页大小,可选值为15 | 30 | 50 | |||||
| // page int 是 页码 | |||||
| export const getReposListData = (params) => { | |||||
| return service({ | |||||
| url: '/explore/repos/search', | |||||
| method: 'get', | |||||
| params: { | |||||
| q: params.q || '', | |||||
| topic: params.topic || '', | |||||
| sort: params.sort || 'mostpopular', | |||||
| pageSize: params.pageSize || 15, | |||||
| page: params.page || 1, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| // 获取活跃用户列表 | |||||
| export const getActiveUsers = () => { | |||||
| return service({ | |||||
| url: '/explore/repos/square/active-user', | |||||
| method: 'get', | |||||
| params: {}, | |||||
| }); | |||||
| } | |||||
| // 关注用户 | |||||
| export const followingUsers = (userName, isFollowing) => { | |||||
| return service({ | |||||
| url: `/api/v1/user/following/${userName}`, | |||||
| method: isFollowing ? 'put' : 'delete', | |||||
| params: {}, | |||||
| }); | |||||
| } | |||||
| // 获取活跃组织列表 | |||||
| export const getActiveOrgs = () => { | |||||
| return service({ | |||||
| url: '/explore/repos/square/active-org', | |||||
| method: 'get', | |||||
| params: {}, | |||||
| }); | |||||
| } | |||||
| @@ -177,21 +177,21 @@ const en = { | |||||
| Activated: 'Activated', | Activated: 'Activated', | ||||
| notActive: 'Not active', | notActive: 'Not active', | ||||
| }, | }, | ||||
| tranformImageFailed:'Picture desensitization failed', | |||||
| originPicture:'Origin picture', | |||||
| desensitizationPicture:'Desensitization picture', | |||||
| desensitizationObject:'Desensitization object', | |||||
| example:'Example', | |||||
| startDesensitization:'Start desensitization', | |||||
| all:'All', | |||||
| onlyFace:'Only face', | |||||
| onlyLicensePlate:'Only license plate', | |||||
| dragThePictureHere:'Drag the picture here', | |||||
| or:' or ', | |||||
| clickUpload:'Click upload', | |||||
| dataDesensitizationModelExperience:'Data desensitization model experience', | |||||
| dataDesensitizationModelDesc:'Use AI technology to desensitize the face and license plate number in the picture. For more information about this model, please visit the project', | |||||
| limitFilesUpload:'Only jpg/jpeg/png files can be uploaded', | |||||
| tranformImageFailed: 'Picture desensitization failed', | |||||
| originPicture: 'Origin picture', | |||||
| desensitizationPicture: 'Desensitization picture', | |||||
| desensitizationObject: 'Desensitization object', | |||||
| example: 'Example', | |||||
| startDesensitization: 'Start desensitization', | |||||
| all: 'All', | |||||
| onlyFace: 'Only face', | |||||
| onlyLicensePlate: 'Only license plate', | |||||
| dragThePictureHere: 'Drag the picture here', | |||||
| or: ' or ', | |||||
| clickUpload: 'Click upload', | |||||
| dataDesensitizationModelExperience: 'Data desensitization model experience', | |||||
| dataDesensitizationModelDesc: 'Use AI technology to desensitize the face and license plate number in the picture. For more information about this model, please visit the project', | |||||
| limitFilesUpload: 'Only jpg/jpeg/png files can be uploaded', | |||||
| limitSizeUpload: 'The size of the uploaded file cannot exceed 20M!', | limitSizeUpload: 'The size of the uploaded file cannot exceed 20M!', | ||||
| notebook: { | notebook: { | ||||
| createNewNotebook: "Create new notebook debug task", | createNewNotebook: "Create new notebook debug task", | ||||
| @@ -281,6 +281,62 @@ const en = { | |||||
| infoModificationFailed: 'Information modify failed', | infoModificationFailed: 'Information modify failed', | ||||
| deleteModelFileConfirmTips: 'Are you sure you want to delete the current model file?', | deleteModelFileConfirmTips: 'Are you sure you want to delete the current model file?', | ||||
| modelFileDeleteFailed: 'Model file delete failed', | modelFileDeleteFailed: 'Model file delete failed', | ||||
| modelAccess:'Model Access', | |||||
| modelAccessPublic:'Public', | |||||
| modelAccessPrivate:'Private', | |||||
| }, | |||||
| repos: { | |||||
| activeOrganization: 'Active Organization', | |||||
| activeUsers: 'Active Users', | |||||
| follow: 'Follow', | |||||
| unFollow: 'Unfollow', | |||||
| selectedFields: 'Recommend Repositories', | |||||
| mostPopular: 'Most Popular', | |||||
| mostActive: 'Most Active', | |||||
| newest: 'Newest', | |||||
| recentlyUpdated: 'Recently Updated', | |||||
| mostStars: 'Most Stars', | |||||
| mostForks: 'Most Forks', | |||||
| mostDatasets: 'Most Datasets', | |||||
| mostAiTasks: 'Most AI Tasks', | |||||
| mostModels: 'Most Models', | |||||
| dataset: 'Datasets', | |||||
| model: 'Models', | |||||
| aiTask: 'AI Tasks', | |||||
| updated: 'Updated', | |||||
| contributors: 'Contributors', | |||||
| searchRepositories: 'Search Repositories', | |||||
| search: 'Search', | |||||
| allFields: 'All Fields', | |||||
| preferred: 'Preferred', | |||||
| openIIncubation: 'OpenI Incubation', | |||||
| hotPapers: 'Hot Papers', | |||||
| watch: 'Watch', | |||||
| star: 'Star', | |||||
| fork: 'Fork', | |||||
| noReposfound: 'No matching repositories found.', | |||||
| }, | |||||
| timeObj: { | |||||
| ago: '{msg} ago', | |||||
| from_now: '{msg} from now', | |||||
| now: 'now', | |||||
| future: 'future', | |||||
| '1s': '1 second', | |||||
| '1m': '1 minute', | |||||
| '1h': '1 hour', | |||||
| '1d': '1 day', | |||||
| '1w': '1 week', | |||||
| '1mon': '1 month', | |||||
| '1y': '1 year', | |||||
| seconds: '{msg} seconds', | |||||
| minutes: '{msg} minutes', | |||||
| hours: '{msg} hours', | |||||
| days: '{msg} days', | |||||
| weeks: '{msg} weeks', | |||||
| months: '{msg} months', | |||||
| years: '{msg} years', | |||||
| raw_seconds: 'seconds', | |||||
| raw_minutes: 'minutes', | |||||
| }, | }, | ||||
| } | } | ||||
| @@ -220,8 +220,24 @@ const zh = { | |||||
| graphicMemory: "显存", | graphicMemory: "显存", | ||||
| memory: "内存", | memory: "内存", | ||||
| sharedMemory: "共享内存", | sharedMemory: "共享内存", | ||||
| tips:'本次新建的调试任务会放在您名下项目openi-notebook中,如果没有该项目系统会自动新建一个。' | |||||
| tips: '本次新建的调试任务会放在您名下项目openi-notebook中,如果没有该项目系统会自动新建一个。' | |||||
| }, | }, | ||||
| tranformImageFailed: '图片脱敏失败', | |||||
| originPicture: '原始图片', | |||||
| desensitizationPicture: '脱敏图片', | |||||
| desensitizationObject: '脱敏对象', | |||||
| example: '示例', | |||||
| startDesensitization: '开始处理', | |||||
| all: '全部', | |||||
| onlyFace: '仅人脸', | |||||
| onlyLicensePlate: '仅车牌', | |||||
| dragThePictureHere: '拖动图片到这里', | |||||
| or: '或', | |||||
| clickUpload: '点击上传', | |||||
| dataDesensitizationModelExperience: '数据脱敏模型体验', | |||||
| dataDesensitizationModelDesc: '利用人工智能AI技术,把图片中的人脸、车牌号码进行脱敏处理。该模型更多信息请访问项目', | |||||
| limitFilesUpload: '只能上传 jpg/jpeg/png 格式的文件', | |||||
| limitSizeUpload: '上传文件大小不能超过 20M !', | |||||
| modelManage: { | modelManage: { | ||||
| modelManage: '模型管理', | modelManage: '模型管理', | ||||
| modelName: '模型名称', | modelName: '模型名称', | ||||
| @@ -282,9 +298,63 @@ const zh = { | |||||
| infoModificationFailed: '信息修改失败', | infoModificationFailed: '信息修改失败', | ||||
| deleteModelFileConfirmTips: '请确认是否删除当前模型文件?', | deleteModelFileConfirmTips: '请确认是否删除当前模型文件?', | ||||
| modelFileDeleteFailed: '模型文件删除失败', | modelFileDeleteFailed: '模型文件删除失败', | ||||
| modelAccess:'模型权限', | |||||
| modelAccessPublic:'公开', | |||||
| modelAccessPrivate:'私有', | |||||
| }, | }, | ||||
| }; | |||||
| repos: { | |||||
| activeOrganization: '活跃组织', | |||||
| activeUsers: '活跃用户', | |||||
| follow: '关注', | |||||
| unFollow: '取消关注', | |||||
| selectedFields: '领域精选', | |||||
| mostPopular: '近期热门', | |||||
| mostActive: '近期活跃', | |||||
| newest: '最近创建', | |||||
| recentlyUpdated: '最近更新', | |||||
| mostStars: '点赞最多', | |||||
| mostForks: '派生最多', | |||||
| mostDatasets: '数据集最多', | |||||
| mostAiTasks: 'AI任务最多', | |||||
| mostModels: '模型最多', | |||||
| dataset: '数据集', | |||||
| model: '模型', | |||||
| aiTask: 'AI任务', | |||||
| updated: '最后更新于', | |||||
| contributors: '贡献者', | |||||
| searchRepositories: '搜项目', | |||||
| search: '搜索', | |||||
| allFields: '全部领域', | |||||
| preferred: '项目优选', | |||||
| openIIncubation: '启智孵化管道', | |||||
| hotPapers: '热门论文项目', | |||||
| watch: '关注', | |||||
| star: '点赞', | |||||
| fork: '派生', | |||||
| noReposfound: '未找到匹配的项目。', | |||||
| }, | |||||
| timeObj: { | |||||
| ago: '{msg}前', | |||||
| from_now: '{msg} 之后', | |||||
| now: '现在', | |||||
| future: '将来', | |||||
| '1s': '1 秒', | |||||
| '1m': '1 分钟', | |||||
| '1h': '1 小时', | |||||
| '1d': '1 天', | |||||
| '1w': '1 周', | |||||
| '1mon': '1 个月', | |||||
| '1y': '1 年', | |||||
| seconds: '{msg} 秒', | |||||
| minutes: '{msg} 分钟', | |||||
| hours: '{msg} 小时', | |||||
| days: '{msg} 天', | |||||
| weeks: '{msg} 周', | |||||
| months: '{msg} 个月', | |||||
| years: '{msg} 年', | |||||
| raw_seconds: '秒', | |||||
| raw_minutes: '分钟', | |||||
| }, | |||||
| } | |||||
| export default zh; | export default zh; | ||||
| @@ -51,6 +51,12 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row"> | |||||
| <div class="tit">{{ $t('modelManage.modelAccess') }}:</div> | |||||
| <div class="val"> | |||||
| <div class="txt-wrap">{{ state.isPrivate }}</div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <div class="area"> | <div class="area"> | ||||
| <div class="row"> | <div class="row"> | ||||
| @@ -176,8 +182,8 @@ | |||||
| <span>{{ scope.row.FileName }}</span> | <span>{{ scope.row.FileName }}</span> | ||||
| </div> | </div> | ||||
| </a> | </a> | ||||
| <a v-else :class="!canOperate ? 'disabled-download' : ''" | |||||
| :href="canOperate ? `${repo}/modelmanage/${state.id}/downloadsingle?parentDir=${filePath.length > 1 ? encodeURIComponent(filePath.map(item => item.path).join('/').slice(1) + '/') : ''}&fileName=${scope.row.FileName}` : 'javascript:;'"> | |||||
| <a v-else :class="!canDownload ? 'disabled-download' : ''" | |||||
| :href="canDownload ? `${repo}/modelmanage/${state.id}/downloadsingle?parentDir=${filePath.length > 1 ? encodeURIComponent(filePath.map(item => item.path).join('/').slice(1) + '/') : ''}&fileName=${scope.row.FileName}` : 'javascript:;'"> | |||||
| <div class="fitted" :title="scope.row.FileName"> | <div class="fitted" :title="scope.row.FileName"> | ||||
| <i class="icon file" width="16" height="16" aria-hidden="true"></i> | <i class="icon file" width="16" height="16" aria-hidden="true"></i> | ||||
| <span>{{ scope.row.FileName }}</span> | <span>{{ scope.row.FileName }}</span> | ||||
| @@ -222,6 +228,7 @@ export default { | |||||
| return { | return { | ||||
| modelType: '0', // 1-本地, 0-线上 | modelType: '0', // 1-本地, 0-线上 | ||||
| canOperate: false, | canOperate: false, | ||||
| canDownload:false, | |||||
| canDelete: false, | canDelete: false, | ||||
| isExpanded: false, | isExpanded: false, | ||||
| loading: false, | loading: false, | ||||
| @@ -285,6 +292,7 @@ export default { | |||||
| const data = this.modelList.filter((model) => model.version == version)[0]; | const data = this.modelList.filter((model) => model.version == version)[0]; | ||||
| this.modelType = data.modelType; | this.modelType = data.modelType; | ||||
| this.canOperate = data.isCanOper; | this.canOperate = data.isCanOper; | ||||
| this.canDownload = data.isCanDownload; | |||||
| this.canDelete = data.isCanDelete; | this.canDelete = data.isCanDelete; | ||||
| this.state.type = data.type; | this.state.type = data.type; | ||||
| this.state.typeStr = data.type == 0 ? 'CPU/GPU' : data.type == 1 ? 'NPU' : ''; | this.state.typeStr = data.type == 0 ? 'CPU/GPU' : data.type == 1 ? 'NPU' : ''; | ||||
| @@ -298,6 +306,7 @@ export default { | |||||
| this.state._label = data.label; | this.state._label = data.label; | ||||
| this.state.description = data.description || '--'; | this.state.description = data.description || '--'; | ||||
| this.state._description = data.description; | this.state._description = data.description; | ||||
| this.state.isPrivate= (data.isPrivate == true ? this.$t('modelManage.modelAccessPrivate'):this.$t('modelManage.modelAccessPublic')); | |||||
| this.state.createTime = formatDate(new Date(data.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss'); | this.state.createTime = formatDate(new Date(data.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss'); | ||||
| const trainTaskInfo = data.trainTaskInfo ? JSON.parse(data.trainTaskInfo) : ''; | const trainTaskInfo = data.trainTaskInfo ? JSON.parse(data.trainTaskInfo) : ''; | ||||
| @@ -85,6 +85,28 @@ | |||||
| :placeholder="$t('modelManage.modelLabelInputTips')" @input="labelInput"></el-input> | :placeholder="$t('modelManage.modelLabelInputTips')" @input="labelInput"></el-input> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row" v-if="repoIsPrivate==false"> | |||||
| <div class="r-title"><label>{{ $t('modelManage.modelAccess') }}</label></div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input id="isPrivate_false" type="radio" name="isPrivate" checked="checked" value="false"> | |||||
| <label>{{ $t('modelManage.modelAccessPublic') }}</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label> </label> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input id="isPrivate_true" type="radio" name="isPrivate" value="true"> | |||||
| <label>{{ $t('modelManage.modelAccessPrivate') }}</label> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="row" style="align-items:flex-start;"> | <div class="row" style="align-items:flex-start;"> | ||||
| <div class="r-title"><label>{{ $t('modelManage.modelDescr') }}</label></div> | <div class="r-title"><label>{{ $t('modelManage.modelDescr') }}</label></div> | ||||
| <div class="r-content"> | <div class="r-content"> | ||||
| @@ -93,6 +115,7 @@ | |||||
| </el-input> | </el-input> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row" style="margin-top:20px"> | <div class="row" style="margin-top:20px"> | ||||
| <div class="r-title"><label></label></div> | <div class="r-title"><label></label></div> | ||||
| <div class="r-content"> | <div class="r-content"> | ||||
| @@ -116,7 +139,7 @@ import { MODEL_ENGINES } from '~/const' | |||||
| const REPO_NAME = location.pathname.split('/')[2]; | const REPO_NAME = location.pathname.split('/')[2]; | ||||
| const MAX_LABEL_COUNT = 5; | const MAX_LABEL_COUNT = 5; | ||||
| const REPOISPRIVATE = window.REPO_IS_PRIVATE; | |||||
| export default { | export default { | ||||
| data() { | data() { | ||||
| return { | return { | ||||
| @@ -129,10 +152,12 @@ export default { | |||||
| engine: '0', | engine: '0', | ||||
| label: '', | label: '', | ||||
| description: '', | description: '', | ||||
| isPrivate : false, | |||||
| }, | }, | ||||
| nameErr: false, | nameErr: false, | ||||
| isShowVersion: false, | isShowVersion: false, | ||||
| engineList: MODEL_ENGINES, | engineList: MODEL_ENGINES, | ||||
| repoIsPrivate: REPOISPRIVATE, | |||||
| }; | }; | ||||
| }, | }, | ||||
| components: {}, | components: {}, | ||||
| @@ -145,6 +170,7 @@ export default { | |||||
| const hasEndSpace = this.state.label[this.state.label.length - 1] == ' '; | const hasEndSpace = this.state.label[this.state.label.length - 1] == ' '; | ||||
| const list = this.state.label.trim().split(' ').filter(label => label != ''); | const list = this.state.label.trim().split(' ').filter(label => label != ''); | ||||
| this.state.label = list.slice(0, MAX_LABEL_COUNT).join(' ') + (hasEndSpace && list.length < MAX_LABEL_COUNT ? ' ' : ''); | this.state.label = list.slice(0, MAX_LABEL_COUNT).join(' ') + (hasEndSpace && list.length < MAX_LABEL_COUNT ? ' ' : ''); | ||||
| }, | }, | ||||
| submit() { | submit() { | ||||
| if (!this.checkName()) { | if (!this.checkName()) { | ||||
| @@ -154,6 +180,16 @@ export default { | |||||
| // }); | // }); | ||||
| return; | return; | ||||
| } | } | ||||
| var radio = document.getElementsByName("isPrivate"); | |||||
| if(radio != null && radio.length > 0){ | |||||
| for (var i=0; i<radio.length; i++) { | |||||
| if (radio[i].checked) { | |||||
| this.state.isPrivate=radio[i].value; | |||||
| } | |||||
| } | |||||
| }else{ | |||||
| this.state.isPrivate = true; | |||||
| } | |||||
| const submintApi = this.type == '1' ? modifyModel : saveLocalModel; | const submintApi = this.type == '1' ? modifyModel : saveLocalModel; | ||||
| submintApi({ | submintApi({ | ||||
| repo: location.pathname.split('/').slice(0, 3).join('/'), | repo: location.pathname.split('/').slice(0, 3).join('/'), | ||||
| @@ -220,6 +256,14 @@ export default { | |||||
| this.state.engine = data.engine.toString(); | this.state.engine = data.engine.toString(); | ||||
| this.state.label = data.label; | this.state.label = data.label; | ||||
| this.state.description = data.description; | this.state.description = data.description; | ||||
| this.state.isPrivate = data.isPrivate; | |||||
| if(data.isPrivate){ | |||||
| $('#isPrivate_true').attr("checked",true); | |||||
| $('#isPrivate_false').attr("checked",false); | |||||
| }else{ | |||||
| $('#isPrivate_true').attr("checked",false); | |||||
| $('#isPrivate_false').attr("checked",true); | |||||
| } | |||||
| } | } | ||||
| }).catch(err => { | }).catch(err => { | ||||
| this.loading = false; | this.loading = false; | ||||
| @@ -0,0 +1,123 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="container"> | |||||
| <div class="title"> | |||||
| <i style="margin-left:10px;margin-right:8px;font-size:20px;" class="ri-blaze-line"></i> | |||||
| <span>{{ $t('repos.activeOrganization') }}</span> | |||||
| </div> | |||||
| <div class="content"> | |||||
| <div class="item" v-for="(item, index) in list" :key="index"> | |||||
| <div class="item-l"> | |||||
| <a class="name" :href="`/${item.Name}`" :title="item.Name"> | |||||
| <img class="avatar" :src="item.RelAvatarLink"> | |||||
| <div class="name-c"><span>{{ item.Name }}</span></div> | |||||
| </a> | |||||
| </div> | |||||
| <div class="item-r"> | |||||
| <i class="ri-user-2-line" style="color:rgb(250, 140, 22);margin-right:4px;"></i> | |||||
| <span>{{ item.NumMembers }}</span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import { getActiveOrgs } from '~/apis/modules/repos'; | |||||
| export default { | |||||
| name: "ActiveOrgs", | |||||
| props: {}, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| list: [], | |||||
| }; | |||||
| }, | |||||
| methods: {}, | |||||
| mounted() { | |||||
| getActiveOrgs().then(res => { | |||||
| res = res.data; | |||||
| if (res.Code == 0) { | |||||
| this.list = res.Data.Orgs || []; | |||||
| } else { | |||||
| this.list = []; | |||||
| } | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| this.list = []; | |||||
| }); | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .title { | |||||
| height: 43px; | |||||
| border-color: rgba(16, 16, 16, 0.05); | |||||
| border-width: 1px 0px; | |||||
| border-style: solid; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| font-size: 18px; | |||||
| color: rgba(47, 9, 69, 0.74); | |||||
| background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(-1.007%2C%200.0010000000000001494%2C%20-0.000018400023883213844%2C%20-1.007%2C%201.003%2C%200.008)%22%3E%3Cstop%20stop-color%3D%22%23eee9da%22%20stop-opacity%3D%220%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23f3e7f7%22%20stop-opacity%3D%220.26%22%20offset%3D%220.29%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23d0e7ff%22%20stop-opacity%3D%220.3%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||||
| } | |||||
| .content { | |||||
| padding: 6px 0; | |||||
| } | |||||
| .item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| height: 48px; | |||||
| padding: 0 8px; | |||||
| font-size: 14px; | |||||
| color: rgba(16, 16, 16, 1); | |||||
| } | |||||
| .item>div { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .item-l { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| a { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| overflow: hidden; | |||||
| } | |||||
| } | |||||
| .item-r { | |||||
| width: 80px; | |||||
| justify-content: flex-end; | |||||
| } | |||||
| .item .avatar { | |||||
| width: 32px; | |||||
| height: 32px; | |||||
| border-radius: 50%; | |||||
| margin-right: 10px; | |||||
| } | |||||
| .item .name-c { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| width: 100%; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| .item .name { | |||||
| color: rgba(16, 16, 16, 1); | |||||
| &:hover { | |||||
| opacity: 0.8; | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,156 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="container"> | |||||
| <div class="title"> | |||||
| <i style="margin-left:10px;margin-right:8px;font-size:20px;" class="ri-account-pin-circle-line"></i> | |||||
| <span>{{ $t('repos.activeUsers') }}</span> | |||||
| </div> | |||||
| <div class="content"> | |||||
| <div class="item" v-for="(item, index) in list" :key="index"> | |||||
| <div class="item-l"> | |||||
| <a class="name" :href="`/${item.User.Name}`" :title="(item.User.FullName || item.User.Name)"> | |||||
| <img class="avatar" :src="item.User.RelAvatarLink"> | |||||
| <div class="name-c"> | |||||
| {{ item.User.FullName || item.User.Name }} | |||||
| </div> | |||||
| </a> | |||||
| </div> | |||||
| <div class="item-r"> | |||||
| <template v-if="item.ShowButton"> | |||||
| <a class="op-btn" v-if="!item.Followed" href="javascript:;" @click="following(item, index, true)"> | |||||
| {{ $t('repos.follow') }}</a> | |||||
| <a class="op-btn" v-if="item.Followed" href="javascript:;" @click="following(item, index, false)"> | |||||
| {{ $t('repos.unFollow') }}</a> | |||||
| </template> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import { getActiveUsers, followingUsers } from '~/apis/modules/repos'; | |||||
| export default { | |||||
| name: "ActiveUsers", | |||||
| props: {}, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| list: [], | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| following(userInfo, index, followingOrNot) { | |||||
| followingUsers(userInfo.User.Name, followingOrNot).then(res => { | |||||
| if (res.status == 204) { // 成功 | |||||
| userInfo.Followed = !userInfo.Followed; | |||||
| } else { | |||||
| console.log(res); | |||||
| } | |||||
| }).catch(err => { | |||||
| if (err.response.status == 401) { // 未登陆 | |||||
| window.location.href = `/user/login?redirect_to=${encodeURIComponent(window.location.href)}`; | |||||
| } else { | |||||
| console.log(err); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }, | |||||
| mounted() { | |||||
| getActiveUsers().then(res => { | |||||
| res = res.data; | |||||
| if (res.Code == 0) { | |||||
| this.list = res.Data.Users || []; | |||||
| } else { | |||||
| this.list = []; | |||||
| } | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| this.list = []; | |||||
| }); | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .title { | |||||
| height: 43px; | |||||
| border-color: rgba(16, 16, 16, 0.05); | |||||
| border-width: 1px 0px; | |||||
| border-style: solid; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| font-size: 18px; | |||||
| color: rgba(47, 9, 69, 0.74); | |||||
| background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(-1.007%2C%200.0010000000000001494%2C%20-0.000018400023883213844%2C%20-1.007%2C%201.003%2C%200.008)%22%3E%3Cstop%20stop-color%3D%22%23eee9da%22%20stop-opacity%3D%220%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23f3e7f7%22%20stop-opacity%3D%220.26%22%20offset%3D%220.29%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23d0e7ff%22%20stop-opacity%3D%220.3%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||||
| } | |||||
| .content { | |||||
| padding: 6px 0; | |||||
| } | |||||
| .item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| height: 48px; | |||||
| padding: 0 8px; | |||||
| font-size: 14px; | |||||
| color: rgba(16, 16, 16, 1); | |||||
| } | |||||
| .item>div { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .item-l { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| a { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| overflow: hidden; | |||||
| } | |||||
| } | |||||
| .item-r { | |||||
| width: 80px; | |||||
| justify-content: flex-end; | |||||
| } | |||||
| .item .avatar { | |||||
| width: 32px; | |||||
| height: 32px; | |||||
| border-radius: 50%; | |||||
| margin-right: 10px; | |||||
| } | |||||
| .item .name-c { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| width: 100%; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| .item .name { | |||||
| color: rgba(16, 16, 16, 1); | |||||
| &:hover { | |||||
| opacity: 0.8; | |||||
| } | |||||
| } | |||||
| .item .op-btn { | |||||
| border-color: rgb(50, 145, 248); | |||||
| border-width: 1px; | |||||
| border-style: solid; | |||||
| color: rgb(50, 145, 248); | |||||
| font-size: 12px; | |||||
| padding: 0px 6px; | |||||
| border-radius: 3px; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,151 @@ | |||||
| <template> | |||||
| <div class="repo-selected-bg"> | |||||
| <div class="ui container _repo_container _repo-selected-container" style="padding-top:3rem;padding-bottom:3rem;"> | |||||
| <div class="_repo_title"><span>{{ $t('repos.selectedFields') }}</span></div> | |||||
| <div class="_repo-selected-list"> | |||||
| <div class="swiper-wrapper" id="_repo-selected"></div> | |||||
| <div class="swiper-pagination _repo-selected-swiper-pagination"></div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import { getHomePageData } from '~/apis/modules/repos'; | |||||
| import LetterAvatar from '~/utils/letteravatar'; | |||||
| export default { | |||||
| name: "RecommendRepos", | |||||
| props: { | |||||
| static: { type: Boolean, default: false }, | |||||
| staticSwiperData: { type: Array, default: () => [] }, | |||||
| }, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| swiperHandler: null, | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| renderRepos(json) { | |||||
| var selectedRepoEl = document.getElementById("_repo-selected"); | |||||
| var html = ""; | |||||
| if (json != null && json.length > 0) { | |||||
| var repoMap = {}; | |||||
| for (var i = 0, iLen = json.length; i < iLen; i++) { | |||||
| var repo = json[i]; | |||||
| var label = repo.Label; | |||||
| if (repoMap[label]) { | |||||
| repoMap[label].push(repo); | |||||
| } else { | |||||
| repoMap[label] = [repo]; | |||||
| } | |||||
| } | |||||
| for (var label in repoMap) { | |||||
| var repos = repoMap[label]; | |||||
| var labelSearch = repos[0].Label; | |||||
| html += `<div class="swiper-slide"><div><a style="color:rgb(50, 145, 248);font-size:16px;font-weight:550;" href="/explore/repos?q=&topic=${labelSearch}&sort=hot"># ${label}</a></div>`; | |||||
| for (var i = 0, iLen = repos.length; i < iLen; i++) { | |||||
| if (i >= 4) break; | |||||
| var repo = repos[i]; | |||||
| html += `<div class="ui fluid card"> | |||||
| <div class="content"> | |||||
| ${repo["Avatar"] ? `<img style="border-radius: 100%;" class="left floated mini ui image" src="${repo["Avatar"]}">` : `<img style="border-radius: 100%;" class="left floated mini ui image" avatar="${repo["OwnerName"]}">`} | |||||
| <span class="header nowrap" style="color:rgb(50, 145, 248);font-size:14px;" href="javascript:;" title="${repo["Alias"]}">${repo["Alias"]}</span> | |||||
| <div class="description nowrap-2" style="rgba(136,136,136,1);;font-size:12px;" title="${repo["Description"]}">${repo["Description"]}</div> | |||||
| </div> | |||||
| <a style="position:absolute;height:100%;width:100%;" href="/${repo["OwnerName"]}/${repo["Name"]}"></a> | |||||
| </div>`; | |||||
| } | |||||
| html += '</div>' | |||||
| } | |||||
| this.swiperHandler = new Swiper("._repo-selected-list", { | |||||
| slidesPerView: 1, | |||||
| spaceBetween: 25, | |||||
| pagination: { | |||||
| el: "._repo-selected-swiper-pagination", | |||||
| clickable: true, | |||||
| }, | |||||
| autoplay: { | |||||
| delay: 4500, | |||||
| disableOnInteraction: false, | |||||
| }, | |||||
| breakpoints: { | |||||
| 768: { | |||||
| slidesPerView: 3, | |||||
| }, | |||||
| 1024: { | |||||
| slidesPerView: 4, | |||||
| }, | |||||
| 1200: { | |||||
| slidesPerView: 4, | |||||
| }, | |||||
| 1600: { | |||||
| slidesPerView: 4, | |||||
| } | |||||
| }, | |||||
| }); | |||||
| selectedRepoEl.innerHTML = html; | |||||
| this.swiperHandler.updateSlides(); | |||||
| this.swiperHandler.updateProgress(); | |||||
| LetterAvatar.transform(); | |||||
| } | |||||
| } | |||||
| }, | |||||
| mounted() { | |||||
| if (this.static) { | |||||
| this.renderRepos(this.staticSwiperData); | |||||
| } else { | |||||
| getHomePageData().then(res => { | |||||
| this.renderRepos(res.data.repo); | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| }); | |||||
| } | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .repo-selected-bg { | |||||
| background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(0.11899999999999993%2C%201.217%2C%20-0.24039506172839506%2C%200.11899999999999993%2C%200.269%2C%20-0.22)%22%3E%3Cstop%20stop-color%3D%22%23ffffff%22%20stop-opacity%3D%220.47%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23e5e7eb%22%20stop-opacity%3D%220.3%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||||
| } | |||||
| ._repo_title { | |||||
| font-size: 18px; | |||||
| color: rgb(16, 16, 16); | |||||
| text-align: center; | |||||
| margin-bottom: 1em; | |||||
| font-weight: bold; | |||||
| } | |||||
| ._repo-selected-list { | |||||
| overflow: hidden; | |||||
| padding: 1em 1em 3em 1em; | |||||
| text-align: left; | |||||
| position: relative; | |||||
| } | |||||
| /deep/._repo-selected-swiper-pagination .swiper-pagination-bullet { | |||||
| width: 8px; | |||||
| height: 8px; | |||||
| border-radius: 100%; | |||||
| background: #76cbed; | |||||
| } | |||||
| /deep/._repo-selected-swiper-pagination .swiper-pagination-bullet-active { | |||||
| width: 40px; | |||||
| border-radius: 4px; | |||||
| } | |||||
| /deep/ ._repo-selected-list .card { | |||||
| border-radius: 6px; | |||||
| background-color: #FFF; | |||||
| box-shadow: 0px 5px 10px 0px rgba(105, 192, 255, .3); | |||||
| border: 1px solid rgba(105, 192, 255, .4); | |||||
| } | |||||
| /deep/ ._repo-selected-list .header { | |||||
| line-height: 40px !important; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,115 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="item" :class="(focusIndex == index) ? 'item-focus' : ''" v-for="(item, index) in list" :key="item.key"> | |||||
| <a href="javascript:;" @click="changeFilters(item, index)">{{ item.label }}</a> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| name: "ReposFilters", | |||||
| props: { | |||||
| defaultsort: { type: String, default: 'mostpopular' }, | |||||
| }, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| focusIndex: 0, | |||||
| list: [{ | |||||
| key: 'mostpopular', | |||||
| label: this.$t('repos.mostPopular'), | |||||
| }, { | |||||
| key: 'mostactive', | |||||
| label: this.$t('repos.mostActive'), | |||||
| }, { | |||||
| key: 'recentupdate', | |||||
| label: this.$t('repos.recentlyUpdated'), | |||||
| }, { | |||||
| key: 'newest', | |||||
| label: this.$t('repos.newest'), | |||||
| }, { | |||||
| key: 'moststars', | |||||
| label: this.$t('repos.mostStars'), | |||||
| }, { | |||||
| key: 'mostforks', | |||||
| label: this.$t('repos.mostForks'), | |||||
| }, { | |||||
| key: 'mostdatasets', | |||||
| label: this.$t('repos.mostDatasets'), | |||||
| }, { | |||||
| key: 'mostaitasks', | |||||
| label: this.$t('repos.mostAiTasks'), | |||||
| }, { | |||||
| key: 'mostmodels', | |||||
| label: this.$t('repos.mostModels'), | |||||
| }] | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| changeFilters(item, index) { | |||||
| this.focusIndex = index; | |||||
| this.$emit('change', this.list[this.focusIndex]); | |||||
| }, | |||||
| setDefaultFilter(sort) { | |||||
| const index = this.list.findIndex((item) => item.key == sort); | |||||
| this.focusIndex = index >= 0 ? index : 0; | |||||
| } | |||||
| }, | |||||
| mounted() { | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .item { | |||||
| height: 40px; | |||||
| border-color: rgba(16, 16, 16, 0.05); | |||||
| border-width: 0px 0px 1px; | |||||
| border-style: solid; | |||||
| color: rgba(16, 16, 16, 0.8); | |||||
| font-size: 14px; | |||||
| padding: 0px; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| position: relative; | |||||
| } | |||||
| .item a { | |||||
| color: inherit; | |||||
| height: 100%; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| &:hover { | |||||
| opacity: 0.8; | |||||
| } | |||||
| } | |||||
| .item-focus { | |||||
| font-weight: bold; | |||||
| border-color: rgba(0, 108, 205, 0.3); | |||||
| color: rgb(50, 145, 248); | |||||
| a { | |||||
| cursor: default; | |||||
| &:hover { | |||||
| opacity: 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| .item-focus:before { | |||||
| content: ""; | |||||
| position: absolute; | |||||
| width: 7px; | |||||
| height: 7px; | |||||
| bottom: -4px; | |||||
| background: rgb(178, 211, 240); | |||||
| left: 0; | |||||
| border-radius: 100%; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,316 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="item"> | |||||
| <div class="item-top"> | |||||
| <img v-if="data.RelAvatarLink" class="avatar" :src="data.RelAvatarLink" /> | |||||
| <img v-else class="avatar" :avatar="data.OwnerName" /> | |||||
| <div class="content"> | |||||
| <div class="title"> | |||||
| <div class="title-l"> | |||||
| <a :href="`/${data.OwnerName}/${data.Name}`" :title="`${data.OwnerName}/${data.Name}`"> | |||||
| <span class="title-1">{{ data.OwnerName }}</span> | |||||
| <span class="title-1"> / </span> | |||||
| <span class="title-2" v-html="data.NameShow"></span> | |||||
| </a> | |||||
| <i v-if="data.IsArchived" class="archive icon archived-icon"></i> | |||||
| <svg v-if="data.IsFork" class="svg octicon-repo-forked" width="15" height="15" aria-hidden="true"> | |||||
| <use xlink:href="#octicon-repo-forked"></use> | |||||
| </svg> | |||||
| <svg v-if="data.IsMirror" class="svg octicon-repo-clone" width="15" height="15" aria-hidden="true"> | |||||
| <use xlink:href="#octicon-repo-clone"></use> | |||||
| </svg> | |||||
| <svg v-if="(data.IsPrivate || data.IsOwnerPrivate)" style="color:#a1882b!important" class="svg octicon-lock" width="15" height="15" | |||||
| aria-hidden="true"> | |||||
| <use xlink:href="#octicon-lock"></use> | |||||
| </svg> | |||||
| </div> | |||||
| <span class="title-r"> | |||||
| <span class="t-item" :title="$t('repos.watch')"> | |||||
| <i class="ri-eye-line"></i> | |||||
| <span>{{ data.NumWatches }}</span> | |||||
| </span> | |||||
| <span class="t-item" :title="$t('repos.star')"> | |||||
| <i class="ri-star-line"></i> | |||||
| <span>{{ data.NumStars }}</span> | |||||
| </span> | |||||
| <span class="t-item" :title="$t('repos.fork')"> | |||||
| <svg class="svg octicon-repo-forked" width="13" height="13" aria-hidden="true"> | |||||
| <use xlink:href="#octicon-repo-forked"></use> | |||||
| </svg> | |||||
| <span>{{ data.NumForks }}</span></span> | |||||
| </span> | |||||
| </div> | |||||
| <div class="descr" v-show="data.DescriptionShow" v-html="data.DescriptionShow"></div> | |||||
| <div class="tags" v-show="data.Topics && data.Topics.length"> | |||||
| <a v-for="(item, index) in data.TopicsShow" :key="index" class="tag" | |||||
| :class="(item.topic.toLocaleLowerCase() == topic.toLocaleLowerCase() ? 'tag-focus' : '')" | |||||
| :href="`/explore/repos?q=&topic=${item.topic}&sort=hot`" v-html="item.topicShow"></a> | |||||
| </div> | |||||
| <div class="repo-datas" v-show="(data.DatasetCnt > 0) || (data.ModelCnt > 0) || (data.AiTaskCnt > 0)"> | |||||
| <span class="repo-datas-item" v-show="(data.DatasetCnt > 0)"> | |||||
| <i class="ri-stack-line"></i> | |||||
| <span class="label">{{ $t('repos.dataset') }}:</span> | |||||
| <span class="value">{{ data.DatasetCnt }}</span> | |||||
| </span> | |||||
| <span class="repo-datas-item" v-show="(data.ModelCnt > 0)"> | |||||
| <i class="ri-send-plane-2-line"></i> | |||||
| <span class="label">{{ $t('repos.model') }}:</span> | |||||
| <span class="value">{{ data.ModelCnt }}</span> | |||||
| </span> | |||||
| <span class="repo-datas-item" v-show="(data.AiTaskCnt > 0)"> | |||||
| <i class="ri-order-play-line"></i> | |||||
| <span class="label">{{ $t('repos.aiTask') }}:</span> | |||||
| <span class="value">{{ data.AiTaskCnt }}</span> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="item-bottom"> | |||||
| <div> | |||||
| <span>{{ $t('repos.updated') }}</span> | |||||
| <el-tooltip effect="dark" :content="dateFormat(data.UpdatedUnix)" placement="top-start"> | |||||
| <span>{{ calcFromNow(data.UpdatedUnix) }}</span> | |||||
| </el-tooltip> | |||||
| <span style="margin-left:8px;" v-if="data.PrimaryLanguage"><i class="color-icon" | |||||
| :style="{ backgroundColor: data.PrimaryLanguage.Color }"></i>{{ data.PrimaryLanguage.Language }}</span> | |||||
| </div> | |||||
| <div class="contributors"> | |||||
| <span class="contributors-count" v-show="data.Contributors && data.Contributors.length"> | |||||
| {{ $t('repos.contributors') }} | |||||
| </span> | |||||
| <span class="contributors-avatar"> | |||||
| <a :href="item.UserName ? `/${item.UserName}` : `mailto:${item.Email}`" class="avatar-c" | |||||
| v-for="(item, index) in data.Contributors" :key="index"> | |||||
| <img class="avatar" v-show="item.UserName" :src="item.RelAvatarLink"> | |||||
| <span class="avatar" v-show="!item.UserName" :style="{ backgroundColor: item.bgColor }"> | |||||
| {{ item.Email[0].toLocaleUpperCase() }}</span> | |||||
| </a> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import relativeTime from 'dayjs/plugin/relativeTime'; | |||||
| import localizedFormat from 'dayjs/plugin/localizedFormat'; | |||||
| import 'dayjs/locale/zh-cn'; | |||||
| import 'dayjs/locale/en'; | |||||
| import dayjs from 'dayjs'; | |||||
| import { lang } from '~/langs'; | |||||
| import { timeSinceUnix } from '~/utils'; | |||||
| dayjs.locale(lang == 'zh-CN' ? 'zh-cn' : 'en'); | |||||
| dayjs.extend(relativeTime); | |||||
| dayjs.extend(localizedFormat); | |||||
| export default { | |||||
| name: "ReposItem", | |||||
| props: { | |||||
| data: { type: Object, default: () => ({}) }, | |||||
| topic: { type: String, default: '' } | |||||
| }, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| contributors: [], | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| calcFromNow(unix) { | |||||
| // return dayjs(unix * 1000).fromNow(); | |||||
| return timeSinceUnix(unix, Date.now() / 1000); | |||||
| }, | |||||
| dateFormat(unix) { | |||||
| return lang == 'zh-CN' ? dayjs(unix * 1000).format('YYYY年MM月DD日 HH时mm分ss秒') : | |||||
| dayjs(unix * 1000).format('ddd, D MMM YYYY HH:mm:ss [CST]'); | |||||
| } | |||||
| }, | |||||
| mounted() { }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .item { | |||||
| width: 100%; | |||||
| border-color: rgba(157, 197, 226, 0.4); | |||||
| border-width: 1px; | |||||
| border-style: solid; | |||||
| box-shadow: rgb(157 197 226 / 20%) 0px 5px 10px 0px; | |||||
| border-radius: 15px; | |||||
| font-size: 14px; | |||||
| padding: 20px 26px 10px 26px; | |||||
| margin-bottom: 40px; | |||||
| } | |||||
| .item-top { | |||||
| display: flex; | |||||
| } | |||||
| .item-top .avatar { | |||||
| width: 38px; | |||||
| height: 38px; | |||||
| margin-right: 10px; | |||||
| border-radius: 100%; | |||||
| } | |||||
| .content { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| } | |||||
| .content .title { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| height: 30px; | |||||
| margin: 4px 0 8px; | |||||
| } | |||||
| .content .title-l { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| width: 100%; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| .content .title-1 { | |||||
| font-size: 18px; | |||||
| color: rgba(16, 16, 16, 0.6); | |||||
| } | |||||
| .content .title-2 { | |||||
| font-size: 18px; | |||||
| color: rgba(16, 16, 16, 1); | |||||
| font-weight: bold; | |||||
| margin-right: 3px; | |||||
| } | |||||
| .content .title-r { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| color: rgba(26, 40, 51, 1); | |||||
| justify-content: flex-end; | |||||
| } | |||||
| .content .t-item { | |||||
| margin-left: 12px; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .content .t-item i { | |||||
| margin-right: 4px; | |||||
| } | |||||
| .content .descr { | |||||
| font-weight: 300; | |||||
| font-size: 14px; | |||||
| color: rgba(16, 16, 16, 0.8); | |||||
| margin-bottom: 16px; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| word-break: break-all; | |||||
| display: -webkit-box; | |||||
| -webkit-box-orient: vertical; | |||||
| -webkit-line-clamp: 6; | |||||
| max-height: 120px; | |||||
| white-space: break-spaces; | |||||
| } | |||||
| .content .tags { | |||||
| margin-bottom: 16px; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| .content .tag { | |||||
| color: rgba(16, 16, 16, 0.8); | |||||
| border-radius: 4px; | |||||
| font-size: 14px; | |||||
| background: rgba(232, 232, 232, 0.6); | |||||
| padding: 2px 6px; | |||||
| margin-right: 8px; | |||||
| &.tag-focus { | |||||
| color: red; | |||||
| } | |||||
| } | |||||
| .content .repo-datas { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-top: 20px; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .content .repo-datas-item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-right: 24px; | |||||
| } | |||||
| .content .repo-datas-item i { | |||||
| color: rgba(2, 107, 251, 0.54); | |||||
| margin-right: 4px; | |||||
| font-size: 16px; | |||||
| } | |||||
| .content .repo-datas-item .label { | |||||
| color: rgba(2, 107, 251, 0.54); | |||||
| margin-right: 4px; | |||||
| } | |||||
| .content .repo-datas-item .value { | |||||
| font-weight: bold; | |||||
| } | |||||
| .item-bottom { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| border-top: 1px solid rgba(157, 197, 226, 0.2); | |||||
| margin-top: 10px; | |||||
| padding-top: 10px; | |||||
| font-size: 12px; | |||||
| color: rgba(16, 16, 16, 0.6); | |||||
| } | |||||
| .item-bottom .contributors { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .item-bottom .contributors-avatar { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-left: 16px; | |||||
| .avatar-c { | |||||
| img[src=""], | |||||
| img:not([src]) { | |||||
| // opacity: 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| .item-bottom .avatar { | |||||
| display: block; | |||||
| width: 25px; | |||||
| height: 25px; | |||||
| margin-left: -6px; | |||||
| border-radius: 100%; | |||||
| border: 1px solid white; | |||||
| font-size: 16px; | |||||
| line-height: 24px; | |||||
| text-align: center; | |||||
| color: white; | |||||
| background-color: white; | |||||
| font-weight: bold; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,161 @@ | |||||
| <template> | |||||
| <div class="list-container"> | |||||
| <div style="min-height:540px;" v-loading="loading"> | |||||
| <div class="repos-item-container" v-for="(item, index) in list" :key="item.ID"> | |||||
| <ReposItem :data="item" :topic="topic"></ReposItem> | |||||
| </div> | |||||
| <div v-show="(!list.length && !loading)" class="repos-no-data">{{ $t('repos.noReposfound') }}</div> | |||||
| </div> | |||||
| <div class="center"> | |||||
| <el-pagination ref="paginationRef" background @current-change="currentChange" @size-change="sizeChange" | |||||
| :current-page.sync="iPage" :page-sizes="iPageSizes" :page-size.sync="iPageSize" | |||||
| layout="total, sizes, prev, pager, next, jumper" :total="total"> | |||||
| </el-pagination> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import ReposItem from '../components/ReposItem.vue'; | |||||
| import { getReposListData } from '~/apis/modules/repos'; | |||||
| import LetterAvatar from '~/utils/letteravatar'; | |||||
| export default { | |||||
| name: "ReposList", | |||||
| props: { | |||||
| q: { type: String, default: '' }, | |||||
| sort: { type: String, default: 'mostpopular' }, | |||||
| topic: { type: String, default: '' }, | |||||
| page: { type: Number, default: 1 }, | |||||
| pageSize: { type: Number, default: 15 }, | |||||
| pageSizes: { type: Array, default: () => [15, 30, 50] } | |||||
| }, | |||||
| components: { ReposItem }, | |||||
| data() { | |||||
| return { | |||||
| loading: false, | |||||
| list: [], | |||||
| iPageSizes: [15, 30, 50], | |||||
| iPageSize: 15, | |||||
| iPage: 1, | |||||
| total: 0, | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| getListData() { | |||||
| this.loading = true; | |||||
| getReposListData({ | |||||
| q: this.q || '', | |||||
| topic: this.topic || '', | |||||
| sort: this.sort || 'mostpopular', | |||||
| pageSize: this.iPageSize || 15, | |||||
| page: this.iPage || 1, | |||||
| }).then(res => { | |||||
| res = res.data; | |||||
| this.loading = false; | |||||
| if (res.Code == 0) { | |||||
| const list = res.Data.Repos || []; | |||||
| this.list = list.map((item) => { | |||||
| item.Contributors = (item.Contributors || []).map((_item) => { | |||||
| return { | |||||
| ..._item, | |||||
| bgColor: this.randomColor(_item.Email[0].toLocaleUpperCase()), | |||||
| } | |||||
| }); | |||||
| const contributors = item.Contributors || []; | |||||
| return { | |||||
| ...item, | |||||
| NameShow: this.handlerSearchStr(item.Alias, this.q), | |||||
| DescriptionShow: this.handlerSearchStr(item.Description, this.q), | |||||
| TopicsShow: (item.Topics || []).map((_item) => { | |||||
| return { | |||||
| topic: _item, | |||||
| topicShow: this.handlerSearchStr(_item, this.q) | |||||
| } | |||||
| }), | |||||
| } | |||||
| }); | |||||
| this.total = res.Data.Total; | |||||
| this.iPage = this.iPage; | |||||
| this.iPageSize = this.iPageSize; | |||||
| this.$nextTick(() => { | |||||
| LetterAvatar.transform(); | |||||
| }); | |||||
| } else { | |||||
| this.list = []; | |||||
| this.total = 0; | |||||
| this.iPage = this.iPage; | |||||
| this.iPageSize = this.iPageSize; | |||||
| } | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| this.loading = false; | |||||
| this.list = []; | |||||
| this.total = 0; | |||||
| this.iPage = this.iPage; | |||||
| this.iPageSize = this.iPageSize; | |||||
| }); | |||||
| }, | |||||
| search() { | |||||
| this.getListData(); | |||||
| }, | |||||
| currentChange(page) { | |||||
| this.iPage = page; | |||||
| this.$emit('current-change', { | |||||
| page: this.iPage, | |||||
| pageSize: this.iPageSize, | |||||
| }); | |||||
| }, | |||||
| sizeChange(pageSize) { | |||||
| this.iPageSize = pageSize; | |||||
| this.$emit('size-change', { | |||||
| page: this.iPage, | |||||
| pageSize: this.iPageSize, | |||||
| }); | |||||
| }, | |||||
| handlerSearchStr(oStr, searchKey) { | |||||
| if (!searchKey) return oStr; | |||||
| return oStr.replace(new RegExp(`(${searchKey})`, 'ig'), `<font color="red">$1</font>`); | |||||
| }, | |||||
| randomColor(t) { | |||||
| const tIndex = t.charCodeAt(0); | |||||
| const colorList = ["#1abc9c", "#2ecc71", "#3498db", "#9b59b6", "#34495e", "#16a085", "#27ae60", "#2980b9", "#8e44ad", | |||||
| "#2c3e50", "#f1c40f", "#e67e22", "#e74c3c", "#00bcd4", "#95a5a6", "#f39c12", "#d35400", "#c0392b", "#bdc3c7", "#7f8c8d"]; | |||||
| return colorList[tIndex % colorList.length]; | |||||
| } | |||||
| }, | |||||
| watch: { | |||||
| page: { | |||||
| handler(val) { | |||||
| this.iPage = val; | |||||
| }, | |||||
| immediate: true, | |||||
| }, | |||||
| pageSize: { | |||||
| handler(val) { | |||||
| this.iPageSize = val; | |||||
| }, | |||||
| immediate: true, | |||||
| } | |||||
| }, | |||||
| mounted() { }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .list-container { | |||||
| margin-left: 12px; | |||||
| margin-right: 12px; | |||||
| } | |||||
| .center { | |||||
| text-align: center; | |||||
| } | |||||
| .repos-no-data { | |||||
| height: 60px; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,255 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="_repo_search"> | |||||
| <div class="_repo_search_input_c"> | |||||
| <div class="_repo_search_input"> | |||||
| <input type="text" v-model="searchInputValue" :placeholder="$t('repos.searchRepositories')" autocomplete="off" | |||||
| @keyup.enter="search" /> | |||||
| </div> | |||||
| <div class="_repo_search_btn" @click="search"> | |||||
| <svg xmlns="http://www.w3.org/2000/svg" | |||||
| class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 kdvdTY svg-icon-path-icon fill" viewBox="0 0 32 32" | |||||
| width="24" height="24"> | |||||
| <defs data-reactroot=""> | |||||
| <linearGradient id="ilac9fwnydq3lcx1,1,rs,1,f0dwf0xj,ezu9f0dw,f000,00lwrsktrs,rs1bhv8urs" x1="0" x2="100%" | |||||
| y1="0" y2="0" | |||||
| gradientTransform="matrix(-0.7069999999999999, -0.707, 0.707, -0.7069999999999999, 16, 38.624)" | |||||
| gradientUnits="userSpaceOnUse"> | |||||
| <stop stop-color="#c9ffbf" stop-opacity="1" offset="0"></stop> | |||||
| <stop stop-color="#0ca451" stop-opacity="1" offset="1"></stop> | |||||
| </linearGradient> | |||||
| </defs> | |||||
| <g> | |||||
| <path fill="url(#ilac9fwnydq3lcx1,1,rs,1,f0dwf0xj,ezu9f0dw,f000,00lwrsktrs,rs1bhv8urs)" | |||||
| d="M14.667 2.667c6.624 0 12 5.376 12 12s-5.376 12-12 12-12-5.376-12-12 5.376-12 12-12zM14.667 24c5.156 0 9.333-4.177 9.333-9.333 0-5.157-4.177-9.333-9.333-9.333-5.157 0-9.333 4.176-9.333 9.333 0 5.156 4.176 9.333 9.333 9.333zM25.98 24.095l3.772 3.771-1.887 1.887-3.771-3.772 1.885-1.885z"> | |||||
| </path> | |||||
| </g> | |||||
| </svg> | |||||
| <span style="margin-left:10px;">{{ $t('repos.search') }}</span> | |||||
| </div> | |||||
| </div> | |||||
| <div class="_repo_search_label_c"> | |||||
| <div class="_repo_search_label"> | |||||
| <a v-if="type == 'square'" :href="`/explore/repos?q=${searchInputValue.trim()}&topic=${item.v}&sort=${sort}`" | |||||
| :style="{ backgroundColor: topicColors[index % topicColors.length] }" v-for="(item, index) in topics" | |||||
| :key="index">{{ item.v }}</a> | |||||
| <a v-if="type == 'search'" href="javascript:;" @click="changeTopic({ k: '', v: '' })" | |||||
| style="font-weight:bold;" | |||||
| :style="{ backgroundColor: selectTopic == '' ? selectedColor : defaultColor, color: selectTopic == '' ? 'white' : '#40485b' }">{{ | |||||
| $t('repos.allFields') | |||||
| }}</a> | |||||
| <a v-if="type == 'search'" href="javascript:;" @click="changeTopic(item)" | |||||
| :style="{ backgroundColor: selectTopic.toLocaleLowerCase() == item.k ? selectedColor : defaultColor, color: selectTopic.toLocaleLowerCase() == item.k ? 'white' : '#40485b' }" | |||||
| v-for="(item, index) in topics" :key="index">{{ item.v }}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import { getPromoteData } from '~/apis/modules/common'; | |||||
| const COLOR_LIST = [ | |||||
| 'rgb(255, 104, 104)', | |||||
| 'rgb(22, 132, 252)', | |||||
| 'rgb(2, 202, 253)', | |||||
| 'rgb(164, 145, 215)', | |||||
| 'rgb(232, 64, 247)', | |||||
| 'rgb(245, 182, 110)', | |||||
| 'rgb(54, 187, 166)', | |||||
| 'rgb(123, 50, 178)' | |||||
| ]; | |||||
| export default { | |||||
| name: "SearchBar", | |||||
| props: { | |||||
| type: { type: String, default: 'square' }, // square|search | |||||
| searchValue: { type: String, default: '' }, | |||||
| topic: { type: String, default: '' }, | |||||
| sort: { type: String, default: '' }, | |||||
| static: { type: Boolean, default: false }, | |||||
| staticTopicsData: { type: String, default: '[]' }, | |||||
| }, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| searchInputValue: '', | |||||
| topicColors: COLOR_LIST, | |||||
| defaultColor: '#F6F6F6', | |||||
| selectedColor: '', | |||||
| selectTopic: '', | |||||
| topicOri: [], | |||||
| topics: [], | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| setDefaultSearch(params) { | |||||
| this.searchInputValue = params.q || ''; | |||||
| this.selectTopic = params.topic || ''; | |||||
| this.selectTopic && this.changeTopic({ | |||||
| k: this.selectTopic.toLocaleLowerCase(), | |||||
| v: this.selectTopic, | |||||
| }, true); | |||||
| }, | |||||
| changeTopic(topicItem, noSearch) { | |||||
| const index_ori = this.topicOri.findIndex((item) => { | |||||
| return item.k == this.selectTopic.toLocaleLowerCase(); | |||||
| }); | |||||
| if (index_ori < 0 && this.selectTopic) { | |||||
| const index = this.topics.findIndex((item) => { | |||||
| return item.k == this.selectTopic.toLocaleLowerCase(); | |||||
| }); | |||||
| if (index > -1) { | |||||
| this.topics.splice(index, 1); | |||||
| } | |||||
| } | |||||
| this.selectTopic = topicItem.v; | |||||
| if (this.selectTopic && this.topics.indexOf(this.selectTopic) < 0) { | |||||
| const index = this.topics.findIndex(item => { | |||||
| return item.k == this.selectTopic.toLocaleLowerCase(); | |||||
| }) | |||||
| if (index < 0) { | |||||
| this.topics.push({ | |||||
| k: this.selectTopic.toLocaleLowerCase(), | |||||
| v: this.selectTopic, | |||||
| }); | |||||
| } | |||||
| } | |||||
| !noSearch && this.search(); | |||||
| }, | |||||
| handlerTopicsData(data) { | |||||
| try { | |||||
| const topicsData = JSON.parse(data); | |||||
| const topics = topicsData.map((item) => { | |||||
| return { | |||||
| k: item.trim().toLocaleLowerCase(), | |||||
| v: item.trim(), | |||||
| } | |||||
| }); | |||||
| this.topicOri = JSON.parse(JSON.stringify(topics)); | |||||
| this.topics = topics; | |||||
| const selectTopic_key = this.selectTopic.toLocaleLowerCase(); | |||||
| if (selectTopic_key) { | |||||
| const index = this.topics.findIndex((item) => { | |||||
| return item.k == selectTopic_key; | |||||
| }); | |||||
| if (index < 0) { | |||||
| this.topics.push({ | |||||
| k: this.selectTopic.toLocaleLowerCase(), | |||||
| v: this.selectTopic, | |||||
| }); | |||||
| } | |||||
| } | |||||
| } catch (err) { | |||||
| console.log(err); | |||||
| } | |||||
| }, | |||||
| search() { | |||||
| this.searchInputValue = this.searchInputValue.trim(); | |||||
| if (this.type == 'square') { | |||||
| window.location.href = `/explore/repos?q=${this.searchInputValue}&sort=${this.sort}&topic=${this.selectTopic}`; | |||||
| } else { | |||||
| this.$emit('change', { | |||||
| q: this.searchInputValue, | |||||
| topic: this.selectTopic, | |||||
| }); | |||||
| } | |||||
| } | |||||
| }, | |||||
| mounted() { | |||||
| if (this.static) { | |||||
| try { | |||||
| this.handlerTopicsData(this.staticTopicsData); | |||||
| } catch (err) { | |||||
| console.log(err); | |||||
| } | |||||
| } else { | |||||
| getPromoteData('/repos/recommend_topics').then(res => { | |||||
| const data = res.data; | |||||
| this.handlerTopicsData(data); | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| this.handlerTopicsData('[]'); | |||||
| }); | |||||
| } | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| ._repo_search { | |||||
| margin: 54px 0; | |||||
| } | |||||
| ._repo_search_input_c { | |||||
| margin: 0 0 35px; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| } | |||||
| ._repo_search_input { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| width: 437px; | |||||
| height: 41px; | |||||
| border-color: rgba(47, 9, 69, 0.64); | |||||
| border-width: 1px; | |||||
| border-style: solid; | |||||
| color: rgba(16, 16, 16, 0.5); | |||||
| border-radius: 20px; | |||||
| font-size: 14px; | |||||
| padding: 20px; | |||||
| text-align: left; | |||||
| line-height: 20px; | |||||
| background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736765e-17%2C%20-0.9999999999999999%2C%200.008802475794500678%2C%206.123233995736765e-17%2C%201%2C%201.003)%22%3E%3Cstop%20stop-color%3D%22%23eeeade%22%20stop-opacity%3D%220.2%22%20offset%3D%220.76%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23ece0e9%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||||
| } | |||||
| ._repo_search_input input { | |||||
| width: 100%; | |||||
| height: 30px; | |||||
| border: none; | |||||
| background: transparent; | |||||
| outline: none; | |||||
| } | |||||
| ._repo_search_btn { | |||||
| margin-left: 10px; | |||||
| width: 110px; | |||||
| height: 40px; | |||||
| border-style: none; | |||||
| border-color: unset; | |||||
| color: rgb(255, 255, 255); | |||||
| border-radius: 21px; | |||||
| font-size: 14px; | |||||
| text-align: center; | |||||
| font-weight: normal; | |||||
| font-style: normal; | |||||
| background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(6.123233995736766e-17%2C%201%2C%20-0.17728531855955676%2C%206.123233995736766e-17%2C%201%2C%200)%22%3E%3Cstop%20stop-color%3D%22%232f0945%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23341a7b%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| cursor: pointer; | |||||
| } | |||||
| ._repo_search_label_c { | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| } | |||||
| ._repo_search_label { | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| flex-wrap: wrap; | |||||
| max-width: 1200px; | |||||
| } | |||||
| ._repo_search_label a { | |||||
| background-color: rgb(2, 202, 253); | |||||
| color: rgb(255, 255, 255); | |||||
| border-radius: 5px; | |||||
| margin: 0 5px 10px 5px; | |||||
| padding: 5px 10px; | |||||
| cursor: pointer; | |||||
| font-size: 12px; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,363 @@ | |||||
| <template> | |||||
| <div class="ui _repo_container_bg"> | |||||
| <div class="ui container _repo_container _content_container"> | |||||
| <div class="_repo_top_left"> | |||||
| <a :href="bannerData[0] ? bannerData[0].url : ''"> | |||||
| <div class="_repo_top_left_img"> | |||||
| <img :src="bannerData[0] ? bannerData[0].src : ''"> | |||||
| </div> | |||||
| </a> | |||||
| </div> | |||||
| <div class="_repo_top_middle"> | |||||
| <div class="_repo_top_middle_header"> | |||||
| <div class="_repo_top_mid_item" :class="(tabIndex == index) ? '_foucs' : ''" v-for="(item, index) in tabs" | |||||
| :key="index" @click="changeTab(item, index)"> | |||||
| <i :class="item.icon"></i> | |||||
| <span>{{ item.label }}</span> | |||||
| </div> | |||||
| </div> | |||||
| <div class="_repo_top_middle_content"> | |||||
| <div class="_repo_top_mid_repo_list"> | |||||
| <div class="swiper-wrapper" id="_repo_top_mid_repo"></div> | |||||
| <div class="swiper-pagination _repo_top-swiper-pagination"></div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="_repo_top_right"> | |||||
| <a :href="bannerData[1] ? bannerData[1].url : ''"> | |||||
| <div class="_repo_top_right_img"> | |||||
| <img :src="bannerData[1] ? bannerData[1].src : ''"> | |||||
| </div> | |||||
| </a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import { getPromoteData } from '~/apis/modules/common'; | |||||
| import { getReposSquareTabData } from '~/apis/modules/repos'; | |||||
| import LetterAvatar from '~/utils/letteravatar'; | |||||
| export default { | |||||
| name: "SquareTop", | |||||
| props: { | |||||
| static: { type: Boolean, default: false }, | |||||
| staticSwiperData: { type: Array, default: () => [] }, | |||||
| staticBannerData: { type: String, default: '[]' }, | |||||
| }, | |||||
| components: {}, | |||||
| data() { | |||||
| return { | |||||
| swiperHandler: null, | |||||
| tabIndex: 0, | |||||
| tabs: [{ | |||||
| key: 'preferred', | |||||
| icon: 'ri-fire-line', | |||||
| label: this.$t('repos.preferred'), | |||||
| }, { | |||||
| key: 'incubation', | |||||
| icon: 'ri-award-line', | |||||
| label: this.$t('repos.openIIncubation'), | |||||
| }, { | |||||
| key: 'hot-paper', | |||||
| icon: 'ri-file-damage-line', | |||||
| label: this.$t('repos.hotPapers'), | |||||
| }], | |||||
| bannerData: [], | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| initSwiper() { | |||||
| this.swiperHandler = new Swiper("._repo_top_mid_repo_list", { | |||||
| slidesPerView: 1, | |||||
| spaceBetween: 20, | |||||
| pagination: { | |||||
| el: "._repo_top-swiper-pagination", | |||||
| clickable: true, | |||||
| }, | |||||
| autoplay: { | |||||
| delay: 4500, | |||||
| disableOnInteraction: false, | |||||
| }, | |||||
| breakpoints: { | |||||
| 768: { | |||||
| slidesPerView: 2, | |||||
| }, | |||||
| 1024: { | |||||
| slidesPerView: 2, | |||||
| }, | |||||
| 1200: { | |||||
| slidesPerView: 3, | |||||
| }, | |||||
| }, | |||||
| }); | |||||
| }, | |||||
| renderSwiper(data) { | |||||
| const swiperEl = document.getElementById("_repo_top_mid_repo"); | |||||
| let html = ''; | |||||
| const width = swiperEl.parentNode.clientWidth; | |||||
| for (let i = 0, iLen = data.length; i < iLen; i++) { | |||||
| html += `<div class="swiper-slide">`; | |||||
| for (let j = i; j < i + 2; j++) { | |||||
| let dataJ = data[j]; | |||||
| if (dataJ === undefined) break; | |||||
| html += `<div class="_repo_sw_card"><div style="display:flex;"> | |||||
| ${dataJ["RelAvatarLink"] ? `<img style="border-radius:100%;width:35px;height:35px;margin-bottom:0.6em;" class="left floated mini ui image" src="${dataJ["RelAvatarLink"]}">` | |||||
| : `<img style="border-radius:100%;width:35px;height:35px;margin-bottom:0.6em;" class="left floated mini ui image" avatar="${dataJ["OwnerName"]}">`} | |||||
| <span class="header nowrap" style="color:rgb(50, 145, 248);font-size:14px;height:35px;line-height:35px;" href="javascript:;" title="${dataJ["Alias"]}">${dataJ["Alias"]}</span> | |||||
| </div><div class="_repo_sw_card_descr _repo_nowrap_line_3" title="${dataJ.Description}">${dataJ.Description}</div> | |||||
| <a href="/${dataJ.OwnerName}/${dataJ.Name}" style="position:absolute;width:100%;height:100%;top:0;left:0;"></a> | |||||
| </div>`; | |||||
| } | |||||
| html += `</div>`; | |||||
| i++; | |||||
| } | |||||
| this.swiperHandler.removeAllSlides(); | |||||
| swiperEl.innerHTML = html; | |||||
| this.swiperHandler.updateSlides(); | |||||
| this.swiperHandler.updateProgress(); | |||||
| LetterAvatar.transform(); | |||||
| }, | |||||
| getBannerData() { | |||||
| getPromoteData('/repos/square_banner').then(res => { | |||||
| const data = res.data; | |||||
| try { | |||||
| const list = JSON.parse(data); | |||||
| this.bannerData = list; | |||||
| } catch (err) { | |||||
| console.log(err); | |||||
| } | |||||
| }).catch(err => { | |||||
| this.bannerData = []; | |||||
| console.log(err); | |||||
| }); | |||||
| }, | |||||
| getTabData() { | |||||
| getReposSquareTabData(this.tabs[this.tabIndex].key).then(res => { | |||||
| res = res.data; | |||||
| if (res.Code == 0) { | |||||
| const data = res.Data.Repos || []; | |||||
| this.renderSwiper(data); | |||||
| } else { | |||||
| this.renderSwiper([]); | |||||
| } | |||||
| }).catch(err => { | |||||
| console.log(err); | |||||
| this.renderSwiper([]); | |||||
| }); | |||||
| }, | |||||
| changeTab(item, index) { | |||||
| this.tabIndex = index; | |||||
| this.getTabData(); | |||||
| }, | |||||
| }, | |||||
| mounted() { | |||||
| this.initSwiper(); | |||||
| if (this.static) { | |||||
| try { | |||||
| this.bannerData = JSON.parse(this.staticBannerData); | |||||
| } catch (err) { | |||||
| console.log(err); | |||||
| } | |||||
| this.renderSwiper(this.staticSwiperData); | |||||
| } else { | |||||
| this.getBannerData(); | |||||
| this.getTabData(); | |||||
| } | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| ._repo_container_bg { | |||||
| width: 100%; | |||||
| height: 450px; | |||||
| background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(0.4999999999999999%2C%20-0.8660000000000001%2C%200.07722000385802469%2C%200.4999999999999999%2C%20-0.183%2C%200.683)%22%3E%3Cstop%20stop-color%3D%22%239aceec%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23eeeeee%22%20stop-opacity%3D%221%22%20offset%3D%220.99%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||||
| position: relative; | |||||
| } | |||||
| ._content_container { | |||||
| display: flex !important; | |||||
| margin: 0 auto !important; | |||||
| height: 100% !important; | |||||
| } | |||||
| ._repo_top_left { | |||||
| width: 243px; | |||||
| height: 100%; | |||||
| position: relative; | |||||
| } | |||||
| ._repo_top_left_img { | |||||
| width: 100%; | |||||
| height: 346px; | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| border-top-left-radius: 10px; | |||||
| overflow: hidden; | |||||
| } | |||||
| ._repo_top_left_img img { | |||||
| height: 100%; | |||||
| width: 100%; | |||||
| } | |||||
| ._content_container img[src=""], | |||||
| img:not([src]) { | |||||
| opacity: 0; | |||||
| } | |||||
| ._repo_top_right { | |||||
| width: 243px; | |||||
| height: 100%; | |||||
| position: relative; | |||||
| } | |||||
| ._repo_top_right_img { | |||||
| width: 100%; | |||||
| height: 346px; | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| border-top-right-radius: 10px; | |||||
| overflow: hidden; | |||||
| } | |||||
| ._repo_top_right_img img { | |||||
| height: 100%; | |||||
| width: 100%; | |||||
| } | |||||
| ._repo_top_middle { | |||||
| flex: 1; | |||||
| height: 100%; | |||||
| position: relative; | |||||
| } | |||||
| ._repo_top_middle_header { | |||||
| width: 100%; | |||||
| height: 42px; | |||||
| position: absolute; | |||||
| bottom: 346px; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| background: raba(0, 0, 255, 0.3); | |||||
| padding: 0 20px; | |||||
| } | |||||
| ._repo_top_mid_item { | |||||
| padding: 0px 16px; | |||||
| font-size: 18px; | |||||
| color: rgba(47, 9, 69, 0.64); | |||||
| height: 100%; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| cursor: pointer; | |||||
| box-sizing: border-box; | |||||
| border-bottom: 3px solid transparent; | |||||
| } | |||||
| ._repo_top_mid_item i { | |||||
| margin-right: 5px; | |||||
| } | |||||
| ._repo_top_mid_item._foucs { | |||||
| background-color: rgba(255, 255, 255, 0.3); | |||||
| color: rgb(16, 16, 16); | |||||
| cursor: default; | |||||
| border-bottom: 3px solid rgba(16, 16, 16, 0.8); | |||||
| } | |||||
| ._repo_top_middle_content { | |||||
| width: 100%; | |||||
| height: 346px; | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| background: rgba(255, 255, 255, 0.3); | |||||
| padding: 20px 20px; | |||||
| overflow: hidden; | |||||
| } | |||||
| ._repo_top_mid_repo_list { | |||||
| overflow: hidden; | |||||
| } | |||||
| /deep/._repo_sw_card { | |||||
| height: 128px; | |||||
| border-color: rgb(255, 255, 255); | |||||
| border-width: 1px; | |||||
| border-style: solid; | |||||
| font-size: 14px; | |||||
| padding: 12px; | |||||
| background: rgba(255, 255, 255, 0.6); | |||||
| margin-bottom: 20px; | |||||
| box-sizing: border-box; | |||||
| position: relative; | |||||
| } | |||||
| /deep/._repo_nowrap { | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| /deep/._repo_nowrap_line_3 { | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| word-break: break-all; | |||||
| font-size: 12px; | |||||
| color: rgb(136, 136, 136); | |||||
| display: -webkit-box; | |||||
| -webkit-box-orient: vertical; | |||||
| -webkit-line-clamp: 3; | |||||
| max-height: 65px; | |||||
| white-space: break-spaces; | |||||
| } | |||||
| /deep/._repo_sw_card a { | |||||
| color: inherit; | |||||
| } | |||||
| /deep/._repo_sw_card_title { | |||||
| font-weight: 700; | |||||
| font-size: 14px; | |||||
| color: rgba(26, 40, 51, 1); | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| /deep/._repo_sw_card_descr { | |||||
| font-size: 12px; | |||||
| color: rgba(80, 85, 89, 1); | |||||
| margin-bottom: 10px; | |||||
| min-height: 42px; | |||||
| } | |||||
| /deep/._repo_sw_card_label { | |||||
| color: rgb(26, 40, 51); | |||||
| font-size: 14px; | |||||
| display: flex; | |||||
| width: 100%; | |||||
| position: relative; | |||||
| } | |||||
| /deep/._repo_sw_card_label span { | |||||
| border-radius: 4px; | |||||
| background: rgba(232, 232, 232, 0.6); | |||||
| padding: 0px 6px 2px; | |||||
| margin-right: 10px; | |||||
| max-width: 50%; | |||||
| } | |||||
| /deep/._repo_top_mid_repo_list .swiper-pagination-bullet { | |||||
| width: 8px; | |||||
| height: 8px; | |||||
| border-radius: 100%; | |||||
| background: #76cbed; | |||||
| } | |||||
| /deep/._repo_top_mid_repo_list .swiper-pagination-bullet-active { | |||||
| width: 40px; | |||||
| border-radius: 4px; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,123 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="ui container"> | |||||
| <SearchBar ref="searchBarRef" type="search" :static="true" :staticTopicsData="staticSquareTopics" | |||||
| :sort="reposListSortType" :searchValue="reposListQurey" :topic="reposListTopic" @change="searchBarChange"> | |||||
| </SearchBar> | |||||
| </div> | |||||
| <div class="ui container"> | |||||
| <div class="ui grid"> | |||||
| <div class="computer only ui two wide computer column"> | |||||
| <ReposFilters ref="reposFiltersRef" @change="filtersChange"></ReposFilters> | |||||
| </div> | |||||
| <div class="ui sixteen wide mobile twelve wide tablet ten wide computer column"> | |||||
| <ReposList ref="reposListRef" :sort="reposListSortType" :q="reposListQurey" :topic="reposListTopic" | |||||
| :page="page" :pageSize="pageSize" :pageSizes="pageSizes" @current-change="currentChange" | |||||
| @size-change="sizeChange"> | |||||
| </ReposList> | |||||
| </div> | |||||
| <div class="computer only ui four wide computer column"> | |||||
| <div> | |||||
| <ActiveUsers></ActiveUsers> | |||||
| </div> | |||||
| <div class="active-org-c"> | |||||
| <ActiveOrgs></ActiveOrgs> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import SearchBar from '../components/SearchBar.vue'; | |||||
| import ReposFilters from '../components/ReposFilters.vue'; | |||||
| import ReposList from '../components/ReposList.vue'; | |||||
| import ActiveUsers from '../components/ActiveUsers.vue'; | |||||
| import ActiveOrgs from '../components/ActiveOrgs.vue'; | |||||
| import { getUrlSearchParams } from '~/utils'; | |||||
| const staticSquareTopics = JSON.stringify(window.staticSquareTopics || []); | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| reposListSortType: 'mostpopular', | |||||
| reposListQurey: '', | |||||
| reposListTopic: '', | |||||
| page: 1, | |||||
| pageSize: 15, | |||||
| pageSizes: [15, 30, 50], | |||||
| staticSquareTopics: staticSquareTopics, | |||||
| }; | |||||
| }, | |||||
| components: { | |||||
| SearchBar, | |||||
| ReposFilters, | |||||
| ReposList, | |||||
| ActiveUsers, | |||||
| ActiveOrgs, | |||||
| }, | |||||
| methods: { | |||||
| filtersChange(condition) { | |||||
| this.page = 1; | |||||
| this.reposListSortType = condition.key; | |||||
| this.search(); | |||||
| }, | |||||
| searchBarChange(params) { | |||||
| this.page = 1; | |||||
| this.reposListQurey = params.q || ''; | |||||
| this.reposListTopic = params.topic || ''; | |||||
| this.search(); | |||||
| }, | |||||
| currentChange({ page, pageSize }) { | |||||
| this.page = page; | |||||
| this.search(); | |||||
| }, | |||||
| sizeChange({ page, pageSize }) { | |||||
| this.page = 1; | |||||
| this.pageSize = pageSize; | |||||
| this.search(); | |||||
| }, | |||||
| search() { | |||||
| window.location.href = `/explore/repos?q=${this.reposListQurey.trim()}&sort=${this.reposListSortType}&topic=${this.reposListTopic.trim()}&page=${this.page}&pageSize=${this.pageSize}`; | |||||
| } | |||||
| }, | |||||
| beforeMount() { | |||||
| const urlParams = getUrlSearchParams(); | |||||
| this.reposListQurey = urlParams.q || ''; | |||||
| this.reposListTopic = urlParams.topic || ''; | |||||
| this.reposListSortType = urlParams.sort || 'mostpopular'; | |||||
| this.page = Number(urlParams.page) || 1; | |||||
| this.pageSize = this.pageSizes.indexOf(Number(urlParams.pageSize)) >= 0 ? Number(urlParams.pageSize) : 15; | |||||
| }, | |||||
| mounted() { | |||||
| this.$nextTick(() => { | |||||
| this.$refs.reposFiltersRef.setDefaultFilter(this.reposListSortType); | |||||
| this.$refs.searchBarRef.setDefaultSearch({ | |||||
| q: this.reposListQurey, | |||||
| topic: this.reposListTopic, | |||||
| }); | |||||
| this.$refs.reposListRef.search(); | |||||
| }); | |||||
| window.addEventListener('pageshow', function (e) { | |||||
| if (e.persisted) { | |||||
| window.location.reload(); | |||||
| } | |||||
| }, false); | |||||
| }, | |||||
| beforeDestroy() { }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .recommend-repos-c { | |||||
| margin: 0 0 54px; | |||||
| } | |||||
| .active-org-c { | |||||
| margin-top: 32px; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,17 @@ | |||||
| import Vue from 'vue'; | |||||
| import ElementUI from 'element-ui'; | |||||
| import 'element-ui/lib/theme-chalk/index.css'; | |||||
| import localeEn from 'element-ui/lib/locale/lang/en'; | |||||
| import localeZh from 'element-ui/lib/locale/lang/zh-CN'; | |||||
| import { i18n, lang } from '~/langs'; | |||||
| import App from './index.vue'; | |||||
| Vue.use(ElementUI, { | |||||
| locale: lang === 'zh-CN' ? localeZh : localeEn, | |||||
| size: 'small', | |||||
| }); | |||||
| new Vue({ | |||||
| i18n, | |||||
| render: (h) => h(App), | |||||
| }).$mount('#__vue-root'); | |||||
| @@ -0,0 +1,146 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div> | |||||
| <SquareTop :static="true" :staticBannerData="staticSquareBanners" :staticSwiperData="staticSquarePreferredRepos"> | |||||
| </SquareTop> | |||||
| </div> | |||||
| <div class="ui container"> | |||||
| <SearchBar :static="true" :staticTopicsData="staticSquareTopics" ref="searchBarRef" type="square" :sort="``" | |||||
| :searchValue="reposListQurey" :topic="``" @change="searchBarChange"></SearchBar> | |||||
| </div> | |||||
| <div class="recommend-repos-c"> | |||||
| <RecommendRepos :static="true" :staticSwiperData="staticSquareRecommendRepos"></RecommendRepos> | |||||
| <a name="search"></a> | |||||
| </div> | |||||
| <div class="ui container"> | |||||
| <div class="ui grid"> | |||||
| <div class="computer only ui two wide computer column"> | |||||
| <ReposFilters ref="reposFiltersRef" @change="filtersChange"></ReposFilters> | |||||
| </div> | |||||
| <div class="ui sixteen wide mobile twelve wide tablet ten wide computer column"> | |||||
| <ReposList ref="reposListRef" :sort="reposListSortType" :q="reposListQurey" :topic="reposListTopic" | |||||
| :page="page" :pageSize="pageSize" :pageSizes="pageSizes" @current-change="currentChange" | |||||
| @size-change="sizeChange"> | |||||
| </ReposList> | |||||
| </div> | |||||
| <div class="computer only ui four wide computer column"> | |||||
| <div> | |||||
| <ActiveUsers></ActiveUsers> | |||||
| </div> | |||||
| <div class="active-org-c"> | |||||
| <ActiveOrgs></ActiveOrgs> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import SquareTop from '../components/SquareTop.vue'; | |||||
| import SearchBar from '../components/SearchBar.vue'; | |||||
| import RecommendRepos from '../components/RecommendRepos.vue'; | |||||
| import ReposFilters from '../components/ReposFilters.vue'; | |||||
| import ReposList from '../components/ReposList.vue'; | |||||
| import ActiveUsers from '../components/ActiveUsers.vue'; | |||||
| import ActiveOrgs from '../components/ActiveOrgs.vue'; | |||||
| import { getUrlSearchParams } from '~/utils'; | |||||
| const staticSquareBanners = JSON.stringify(window.staticSquareBanners || []); | |||||
| const staticSquarePreferredRepos = window.staticSquarePreferredRepos || []; | |||||
| const staticSquareTopics = JSON.stringify(window.staticSquareTopics || []); | |||||
| const staticSquareRecommendRepos = window.staticSquareRecommendRepos || []; | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| reposListSortType: 'mostpopular', | |||||
| reposListQurey: '', | |||||
| reposListTopic: '', | |||||
| page: 1, | |||||
| pageSize: 15, | |||||
| pageSizes: [15, 30, 50], | |||||
| staticSquareBanners: staticSquareBanners, | |||||
| staticSquarePreferredRepos: staticSquarePreferredRepos, | |||||
| staticSquareTopics: staticSquareTopics, | |||||
| staticSquareRecommendRepos: staticSquareRecommendRepos, | |||||
| }; | |||||
| }, | |||||
| components: { | |||||
| SquareTop, | |||||
| SearchBar, | |||||
| RecommendRepos, | |||||
| ReposFilters, | |||||
| ReposList, | |||||
| ActiveUsers, | |||||
| ActiveOrgs, | |||||
| }, | |||||
| methods: { | |||||
| filtersChange(condition) { | |||||
| this.page = 1; | |||||
| this.reposListSortType = condition.key; | |||||
| this.search(); | |||||
| }, | |||||
| searchBarChange(params) { | |||||
| this.page = 1; | |||||
| this.reposListQurey = params.q || ''; | |||||
| this.reposListTopic = params.topic || ''; | |||||
| this.search(); | |||||
| }, | |||||
| currentChange({ page, pageSize }) { | |||||
| this.page = page; | |||||
| this.search(); | |||||
| }, | |||||
| sizeChange({ page, pageSize }) { | |||||
| this.page = 1; | |||||
| this.pageSize = pageSize; | |||||
| this.search(); | |||||
| }, | |||||
| search() { | |||||
| window.location.href = `/explore/repos/square?q=${this.reposListQurey.trim()}&sort=${this.reposListSortType}&topic=${this.reposListTopic.trim()}&page=${this.page}&pageSize=${this.pageSize}`; | |||||
| } | |||||
| }, | |||||
| beforeMount() { | |||||
| const urlParams = getUrlSearchParams(); | |||||
| this.reposListQurey = urlParams.q || ''; | |||||
| this.reposListTopic = urlParams.topic || ''; | |||||
| this.reposListSortType = urlParams.sort || 'mostpopular'; | |||||
| this.page = Number(urlParams.page) || 1; | |||||
| this.pageSize = this.pageSizes.indexOf(Number(urlParams.pageSize)) >= 0 ? Number(urlParams.pageSize) : 15; | |||||
| }, | |||||
| mounted() { | |||||
| this.$nextTick(() => { | |||||
| this.$refs.reposFiltersRef.setDefaultFilter(this.reposListSortType); | |||||
| this.$refs.searchBarRef.setDefaultSearch({ | |||||
| q: this.reposListQurey, | |||||
| topic: this.reposListTopic, | |||||
| }); | |||||
| const urlParams = getUrlSearchParams(); | |||||
| const page = Number(urlParams.page) || 1; | |||||
| const reposListSortType = urlParams.sort; | |||||
| if (page != 1 || reposListSortType) { | |||||
| window.location.href = '#search'; | |||||
| } | |||||
| this.$refs.reposListRef.search(); | |||||
| }); | |||||
| window.addEventListener('pageshow', function (e) { | |||||
| if (e.persisted) { | |||||
| window.location.reload(); | |||||
| } | |||||
| }, false); | |||||
| }, | |||||
| beforeDestroy() { }, | |||||
| }; | |||||
| </script> | |||||
| <style scoped lang="less"> | |||||
| .recommend-repos-c { | |||||
| margin: 0 0 54px; | |||||
| } | |||||
| .active-org-c { | |||||
| margin-top: 32px; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,17 @@ | |||||
| import Vue from 'vue'; | |||||
| import ElementUI from 'element-ui'; | |||||
| import 'element-ui/lib/theme-chalk/index.css'; | |||||
| import localeEn from 'element-ui/lib/locale/lang/en'; | |||||
| import localeZh from 'element-ui/lib/locale/lang/zh-CN'; | |||||
| import { i18n, lang } from '~/langs'; | |||||
| import App from './index.vue'; | |||||
| Vue.use(ElementUI, { | |||||
| locale: lang === 'zh-CN' ? localeZh : localeEn, | |||||
| size: 'small', | |||||
| }); | |||||
| new Vue({ | |||||
| i18n, | |||||
| render: (h) => h(App), | |||||
| }).$mount('#__vue-root'); | |||||
| @@ -27,7 +27,7 @@ export const transFileSize = (srcSize) => { | |||||
| srcSize = parseFloat(srcSize); | srcSize = parseFloat(srcSize); | ||||
| const index = Math.floor(Math.log(srcSize) / Math.log(1024)); | const index = Math.floor(Math.log(srcSize) / Math.log(1024)); | ||||
| const size = (srcSize / Math.pow(1024, index)).toFixed(2); | const size = (srcSize / Math.pow(1024, index)).toFixed(2); | ||||
| return size + ' ' + unitArr[index]; | |||||
| return size + ' ' + unitArr[index]; | |||||
| }; | }; | ||||
| export const renderSpecStr = (spec, showPoint) => { | export const renderSpecStr = (spec, showPoint) => { | ||||
| @@ -39,3 +39,91 @@ export const renderSpecStr = (spec, showPoint) => { | |||||
| var specStr = `${ngpu}, CPU: ${spec.CpuCores}, ${gpuMemStr}${i18n.t('resourcesManagement.mem')}: ${spec.MemGiB}GB${sharedMemStr}${pointStr}`; | var specStr = `${ngpu}, CPU: ${spec.CpuCores}, ${gpuMemStr}${i18n.t('resourcesManagement.mem')}: ${spec.MemGiB}GB${sharedMemStr}${pointStr}`; | ||||
| return specStr; | return specStr; | ||||
| }; | }; | ||||
| const Minute = 60; | |||||
| const Hour = 60 * Minute; | |||||
| const Day = 24 * Hour; | |||||
| const Week = 7 * Day; | |||||
| const Month = 30 * Day; | |||||
| const Year = 12 * Month; | |||||
| const computeTimeDiff = (diff) => { | |||||
| let diffStr = ''; | |||||
| switch (true) { | |||||
| case diff <= 0: | |||||
| diff = 0; | |||||
| diffStr = i18n.t('timeObj.now'); | |||||
| break; | |||||
| case diff < 2: | |||||
| diff = 0; | |||||
| diffStr = i18n.t('timeObj.1s'); | |||||
| break; | |||||
| case diff < 1 * Minute: | |||||
| diffStr = i18n.t('timeObj.seconds', { msg: Math.floor(diff) }); | |||||
| diff = 0; | |||||
| break; | |||||
| case diff < 2 * Minute: | |||||
| diff -= 1 * Minute; | |||||
| diffStr = i18n.t('timeObj.1m'); | |||||
| break; | |||||
| case diff < 1 * Hour: | |||||
| diffStr = i18n.t('timeObj.minutes', { msg: Math.floor(diff / Minute) }); | |||||
| diff -= diff / Minute * Minute; | |||||
| break; | |||||
| case diff < 2 * Hour: | |||||
| diff -= 1 * Hour; | |||||
| diffStr = i18n.t('timeObj.1h'); | |||||
| break; | |||||
| case diff < 1 * Day: | |||||
| diffStr = i18n.t('timeObj.hours', { msg: Math.floor(diff / Hour) }); | |||||
| diff -= diff / Hour * Hour; | |||||
| break; | |||||
| case diff < 2 * Day: | |||||
| diff -= 1 * Day; | |||||
| diffStr = i18n.t('timeObj.1d'); | |||||
| break; | |||||
| case diff < 1 * Week: | |||||
| diffStr = i18n.t('timeObj.days', { msg: Math.floor(diff / Day) }); | |||||
| diff -= diff / Day * Day; | |||||
| break; | |||||
| case diff < 2 * Week: | |||||
| diff -= 1 * Week; | |||||
| diffStr = i18n.t('timeObj.1w'); | |||||
| break; | |||||
| case diff < 1 * Month: | |||||
| diffStr = i18n.t('timeObj.weeks', { msg: Math.floor(diff / Week) }); | |||||
| diff -= diff / Week * Week; | |||||
| break; | |||||
| case diff < 2 * Month: | |||||
| diff -= 1 * Month; | |||||
| diffStr = i18n.t('timeObj.1mon'); | |||||
| break; | |||||
| case diff < 1 * Year: | |||||
| diffStr = i18n.t('timeObj.months', { msg: Math.floor(diff / Month) }); | |||||
| diff -= diff / Month * Month; | |||||
| break; | |||||
| case diff < 2 * Year: | |||||
| diff -= 1 * Year; | |||||
| diffStr = i18n.t('timeObj.1y'); | |||||
| break; | |||||
| default: | |||||
| diffStr = i18n.t('timeObj.years', { msg: Math.floor(diff / Year) }); | |||||
| diff -= (diff / Year) * Year; | |||||
| break; | |||||
| } | |||||
| return { diff, diffStr }; | |||||
| }; | |||||
| export const timeSinceUnix = (then, now) => { | |||||
| let lbl = 'timeObj.ago'; | |||||
| let diff = now - then; | |||||
| if (then > now) { | |||||
| lbl = 'timeObj.from_now'; | |||||
| diff = then - now; | |||||
| } | |||||
| if (diff <= 0) { | |||||
| return i18n.t('timeObj.now'); | |||||
| } | |||||
| const out = computeTimeDiff(diff); | |||||
| return i18n.t(lbl, { msg: out.diffStr }); | |||||
| }; | |||||
| @@ -0,0 +1,75 @@ | |||||
| 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); | |||||
| } | |||||
| let initials1 = initials.toUpperCase(); | |||||
| if (window.devicePixelRatio) { | |||||
| size = size * window.devicePixelRatio; | |||||
| } | |||||
| charIndex = (initials == "?" ? 72 : initials.charCodeAt(0)) - 64; | |||||
| colourIndex = charIndex % 20; | |||||
| canvas = document.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(initials1, size / 2, size / 1.5); | |||||
| dataURI = canvas.toDataURL(); | |||||
| canvas = null; | |||||
| return dataURI; | |||||
| } | |||||
| LetterAvatar.transform = function () { | |||||
| Array.prototype.forEach.call( | |||||
| document.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); | |||||
| } | |||||
| ); | |||||
| }; | |||||
| export default LetterAvatar; | |||||
| @@ -22,8 +22,8 @@ for (const path of glob('web_src/less/themes/*.less')) { | |||||
| const standalone = {}; | const standalone = {}; | ||||
| const stadalonePaths = [ | const stadalonePaths = [ | ||||
| ...glob('web_src/js/standalone/*.js'), | |||||
| ...glob('web_src/less/standalone/*.less'), | |||||
| ...glob('web_src/js/standalone/**/*.js'), | |||||
| ...glob('web_src/less/standalone/**/*.less'), | |||||
| ]; | ]; | ||||
| for (const path of stadalonePaths) { | for (const path of stadalonePaths) { | ||||
| standalone[parse(path).name] = [path]; | standalone[parse(path).name] = [path]; | ||||
| @@ -22,8 +22,8 @@ for (const path of glob('web_src/less/themes/*.less')) { | |||||
| const standalone = {}; | const standalone = {}; | ||||
| const stadalonePaths = [ | const stadalonePaths = [ | ||||
| ...glob('web_src/js/standalone/*.js'), | |||||
| ...glob('web_src/less/standalone/*.less'), | |||||
| ...glob('web_src/js/standalone/**/*.js'), | |||||
| ...glob('web_src/less/standalone/**/*.less'), | |||||
| ]; | ]; | ||||
| for (const path of stadalonePaths) { | for (const path of stadalonePaths) { | ||||
| standalone[parse(path).name] = [path]; | standalone[parse(path).name] = [path]; | ||||