mergepull/1425/head
@@ -364,11 +364,12 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { | |||||
return actions, nil | return actions, nil | ||||
} | } | ||||
func GetLast20PublicFeeds() ([]*Action, error) { | |||||
func GetLast20PublicFeeds(opTypes []int) ([]*Action, error) { | |||||
cond := builder.NewCond() | cond := builder.NewCond() | ||||
cond = cond.And(builder.Eq{"is_private": false}) | cond = cond.And(builder.Eq{"is_private": false}) | ||||
cond = cond.And(builder.Eq{"is_deleted": false}) | cond = cond.And(builder.Eq{"is_deleted": false}) | ||||
cond = cond.And(builder.Expr("user_id=act_user_id")) | |||||
cond = cond.And(builder.In("op_type", opTypes)) | |||||
actions := make([]*Action, 0, 20) | actions := make([]*Action, 0, 20) | ||||
@@ -387,7 +387,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[s | |||||
OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix) | OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix) | ||||
DataDate := currentTimeNow.Format("2006-01-02") | |||||
DataDate := currentTimeNow.Format("2006-01-02") + " 00:01" | |||||
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)) | ||||
@@ -222,42 +222,42 @@ issues.in_your_repos = In your repositories | |||||
contributors = Contributors | contributors = Contributors | ||||
page_title=Explore Better AI | page_title=Explore Better AI | ||||
page_small_title=OpenI AI development cooperation platform | |||||
page_small_title=OpenI AI Development Cooperation Platform | |||||
page_description=The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation | page_description=The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation | ||||
page_use=Use Now | page_use=Use Now | ||||
page_only_dynamic=Show only open source project dynamics | |||||
page_recommend_org=Recommended organization | |||||
page_recommend_org_desc=These excellent organizations are using Qizhi AI to develop collaboration platforms; Your organization also wants to show here, | |||||
page_recommend_org_commit=Click here to submit | |||||
page_recommend_org_more=More organizations | |||||
page_recommend_repo=Recommended projects | |||||
page_recommend_repo_desc=Excellent AI project recommendation; Your project also wants to show here, | |||||
page_recommend_repo_commit=Click here to submit | |||||
page_recommend_repo_go=. Click here | |||||
page_recommend_repo_more=Project Square | |||||
page_dev_env=Collaborative development environment | |||||
page_dev_env_desc=The biggest difference between Qizhi AI collaborative development platform and traditional git platform is that it provides a collaborative development environment for AI development | |||||
page_dev_env_desc_title=Unified management of development elements | |||||
page_dev_env_desc_desc=The platform provides four elements of AI development: unified management of model code, data set, model and execution environment | |||||
page_dev_env_desc1_title=Data collaboration and sharing | |||||
page_dev_env_desc1_desc=By uploading data sets in the project, many project members cooperate to complete data preprocessing; You can also establish a better model with community developers by setting the data as a public dataset | |||||
page_dev_env_desc2_title=Model management and sharing | |||||
page_dev_env_desc2_desc=Associate the model with the code version, adjust the model in different ways based on the code history version, and save the results; The trained model can be open and shared, so that more people can use the model to test and give feedback | |||||
page_dev_env_desc3_title=One configuration, multiple use | |||||
page_dev_env_desc3_desc=Provide execution environment sharing, one-time configuration and multiple use, reduce the threshold of model development, and avoid spending repeated time configuring complex environments | |||||
page_dev_yunlao=PengCheng Cloudbrain open source collaboration | |||||
page_dev_yunlao_desc1=The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks | |||||
page_dev_yunlao_desc2=Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and shengteng processors | |||||
page_dev_yunlao_desc3=Developers can freely choose the corresponding computing resources according to the use requirements, and can test the adaptability, performance and stability of the model in different hardware environments | |||||
page_dev_yunlao_desc4=If your model needs more computing resources, you can also apply separately | |||||
page_dev_yunlao_apply=Separate apply | |||||
page_only_dynamic=Only show the dynamics of open source projects | |||||
page_recommend_org=Recommended Organization | |||||
page_recommend_org_desc=These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here, | |||||
page_recommend_org_commit=Click here to submit. | |||||
page_recommend_org_more=More Organizations | |||||
page_recommend_repo=Recommended Projects | |||||
page_recommend_repo_desc=Excellent AI projects recommendation. To show your project here, | |||||
page_recommend_repo_commit=Click here to submit. | |||||
page_recommend_repo_go=Click here to | |||||
page_recommend_repo_more=explore more projects. | |||||
page_dev_env=Collaborative Development Environment | |||||
page_dev_env_desc=Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms. | |||||
page_dev_env_desc_title=Unified Management of Development Elements | |||||
page_dev_env_desc_desc=The platform provides four elements of AI development: unified management of model code, data set, model and execution environment. | |||||
page_dev_env_desc1_title=Data Collaboration and Sharing | |||||
page_dev_env_desc1_desc=By uploading data sets in the project, many project members cooperate to complete data preprocessing. You can also establish a better model with community developers by setting the data as a public dataset. | |||||
page_dev_env_desc2_title=Model Management and Sharing | |||||
page_dev_env_desc2_desc=Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback. | |||||
page_dev_env_desc3_title=Once Configuration, Multiple Reuse | |||||
page_dev_env_desc3_desc=Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments. | |||||
page_dev_yunlao=PengCheng Cloudbrain Open Source Collaboration | |||||
page_dev_yunlao_desc1=The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks. | |||||
page_dev_yunlao_desc2=Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors. | |||||
page_dev_yunlao_desc3=Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments. | |||||
page_dev_yunlao_desc4=If your model requires more computing resources, you can also apply for it separately. | |||||
page_dev_yunlao_apply=Apply Separately | |||||
[explore] | [explore] | ||||
repos = Repositories | repos = Repositories | ||||
select_repos = Select the project | select_repos = Select the project | ||||
users = Users | users = Users | ||||
organizations = Organizations | organizations = Organizations | ||||
images = CloudImages | |||||
images = Cloudbrain Mirror | |||||
search = Search | search = Search | ||||
code = Code | code = Code | ||||
repo_no_results = No matching repositories found. | repo_no_results = No matching repositories found. | ||||
@@ -348,6 +348,8 @@ modify = Update | |||||
[form] | [form] | ||||
UserName = Username | UserName = Username | ||||
Alias = Repository name | Alias = Repository name | ||||
courseAlias = Course Name | |||||
courseAdress = Course Path | |||||
RepoPath = Repository path | RepoPath = Repository path | ||||
RepoAdress = Repository Adress | RepoAdress = Repository Adress | ||||
Email = Email address | Email = Email address | ||||
@@ -2703,6 +2705,7 @@ error.unit_not_allowed = You are not allowed to access this repository section. | |||||
head.community = Community | head.community = Community | ||||
head.project = Repositories | head.project = Repositories | ||||
head.openi = OpenI | head.openi = OpenI | ||||
head.openi.repo = OpenI Projects | |||||
head.dataset = Datasets | head.dataset = Datasets | ||||
foot.council = Council | foot.council = Council | ||||
foot.technical_committee = Technical Committee | foot.technical_committee = Technical Committee | ||||
@@ -353,6 +353,8 @@ modify=更新 | |||||
UserName=用户名 | UserName=用户名 | ||||
RepoName=项目路径 | RepoName=项目路径 | ||||
Alias=项目名称 | Alias=项目名称 | ||||
courseAlias=课程名称 | |||||
courseAdress=课程地址 | |||||
RepoPath=项目路径 | RepoPath=项目路径 | ||||
RepoAdress=项目地址 | RepoAdress=项目地址 | ||||
Email=邮箱地址 | Email=邮箱地址 | ||||
@@ -802,6 +804,7 @@ generate_from=生成自 | |||||
repo_desc=项目描述 | repo_desc=项目描述 | ||||
repo_lang=项目语言 | repo_lang=项目语言 | ||||
repo_gitignore_helper=选择 .gitignore 模板。 | repo_gitignore_helper=选择 .gitignore 模板。 | ||||
repo_label_helpe=输入完成后回车键完成标签确定。 | |||||
issue_labels=任务标签 | issue_labels=任务标签 | ||||
issue_labels_helper=选择一个任务标签集 | issue_labels_helper=选择一个任务标签集 | ||||
license=授权许可 | license=授权许可 | ||||
@@ -2050,6 +2053,7 @@ team_access_desc=项目权限 | |||||
team_permission_desc=权限 | team_permission_desc=权限 | ||||
team_unit_desc=允许访问项目单元 | team_unit_desc=允许访问项目单元 | ||||
team_unit_disabled=(已禁用) | team_unit_disabled=(已禁用) | ||||
selected_couse=精选课程 | |||||
form.name_reserved=组织名称 '%s' 是被保留的。 | form.name_reserved=组织名称 '%s' 是被保留的。 | ||||
form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。 | form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。 | ||||
@@ -2136,6 +2140,9 @@ teams.all_repositories_read_permission_desc=此团队授予<strong>读取</stron | |||||
teams.all_repositories_write_permission_desc=此团队授予<strong>修改</strong><strong>所有项目</strong>的访问权限: 成员可以查看和推送至项目。 | teams.all_repositories_write_permission_desc=此团队授予<strong>修改</strong><strong>所有项目</strong>的访问权限: 成员可以查看和推送至项目。 | ||||
teams.all_repositories_admin_permission_desc=该团队拥有 <strong>管理</strong> <strong>所有项目</strong>的权限:团队成员可以读取、克隆、推送以及添加其它项目协作者。 | teams.all_repositories_admin_permission_desc=该团队拥有 <strong>管理</strong> <strong>所有项目</strong>的权限:团队成员可以读取、克隆、推送以及添加其它项目协作者。 | ||||
teams.join_teams=加入该组织 | |||||
[admin] | [admin] | ||||
dashboard=管理面板 | dashboard=管理面板 | ||||
users=帐户管理 | users=帐户管理 | ||||
@@ -42,10 +42,10 @@ if(document.location.host == "git.openi.org.cn" || document.URL.startsWith("http | |||||
var socket = new WebSocket(url); | var socket = new WebSocket(url); | ||||
socket.onopen = function () { | socket.onopen = function () { | ||||
messageQueue = []; | |||||
console.log("message has connected."); | console.log("message has connected."); | ||||
}; | }; | ||||
var messageQueue = []; | |||||
var maxSize = 20; | var maxSize = 20; | ||||
var html =document.documentElement; | var html =document.documentElement; | ||||
var lang = html.attributes["lang"] | var lang = html.attributes["lang"] | ||||
@@ -165,12 +165,12 @@ function getTime(UpdatedUnix,currentTime){ | |||||
var seconds= leave3; | var seconds= leave3; | ||||
if(hours == 0 && minutes == 0){ | if(hours == 0 && minutes == 0){ | ||||
return seconds + getRepoOrOrg(6,isZh); | |||||
return seconds + getRepoOrOrg(6,isZh,seconds); | |||||
}else{ | }else{ | ||||
if(hours > 0){ | if(hours > 0){ | ||||
return hours + getRepoOrOrg(4,isZh); | |||||
return hours + getRepoOrOrg(4,isZh,hours); | |||||
}else{ | }else{ | ||||
return minutes + getRepoOrOrg(5,isZh); | |||||
return minutes + getRepoOrOrg(5,isZh,minutes); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -239,7 +239,7 @@ var actionNameZH={ | |||||
"5":"推送了 {branch} 分支的代码到", | "5":"推送了 {branch} 分支的代码到", | ||||
"6":"创建了任务", | "6":"创建了任务", | ||||
"7":"创建了合并请求", | "7":"创建了合并请求", | ||||
"9":"推送了 {branch} 分支的代码到", | |||||
"9":"推送了标签 {branch} 到", | |||||
"10":"评论了任务", | "10":"评论了任务", | ||||
"11":"合并了合并请求", | "11":"合并了合并请求", | ||||
"12":"关闭了任务", | "12":"关闭了任务", | ||||
@@ -257,7 +257,7 @@ var actionNameEN={ | |||||
"5":" pushed to {branch} at", | "5":" pushed to {branch} at", | ||||
"6":" opened issue", | "6":" opened issue", | ||||
"7":" created pull request", | "7":" created pull request", | ||||
"9":" pushed to {branch} at", | |||||
"9":" pushed tag {branch} to ", | |||||
"10":" commented on issue", | "10":" commented on issue", | ||||
"11":" merged pull request", | "11":" merged pull request", | ||||
"12":" closed issue", | "12":" closed issue", | ||||
@@ -273,18 +273,30 @@ var repoAndOrgZH={ | |||||
"1":"项目", | "1":"项目", | ||||
"2":"成员", | "2":"成员", | ||||
"3":"团队", | "3":"团队", | ||||
"11":"项目", | |||||
"21":"成员", | |||||
"31":"团队", | |||||
"4":"小时前", | "4":"小时前", | ||||
"5":"分钟前", | "5":"分钟前", | ||||
"6":"秒前" | |||||
"6":"秒前", | |||||
"41":"小时前", | |||||
"51":"分钟前", | |||||
"61":"秒前" | |||||
}; | }; | ||||
var repoAndOrgEN={ | var repoAndOrgEN={ | ||||
"1":"repository", | |||||
"2":"Members ", | |||||
"3":"Teams", | |||||
"4":" hours ago", | |||||
"5":" minutes ago", | |||||
"6":" seconds ago" | |||||
"1":"Repository", | |||||
"2":"Member ", | |||||
"3":"Team", | |||||
"11":"Repositorys", | |||||
"22":"Members ", | |||||
"31":"Teams", | |||||
"4":" hour ago", | |||||
"5":" minute ago", | |||||
"6":" second ago", | |||||
"41":" hours ago", | |||||
"51":" minutes ago", | |||||
"61":" seconds ago" | |||||
}; | }; | ||||
@@ -415,7 +427,10 @@ function displayRepo(json){ | |||||
//var repoAndOrgEN = new Map([['1', "Repository"], ['2', "Members"], ['3', "Teams"]]); | //var repoAndOrgEN = new Map([['1', "Repository"], ['2', "Members"], ['3', "Teams"]]); | ||||
function getRepoOrOrg(key,isZhLang){ | |||||
function getRepoOrOrg(key,isZhLang,numbers=1){ | |||||
if(numbers > 1){ | |||||
key+="1"; | |||||
} | |||||
if(isZhLang){ | if(isZhLang){ | ||||
return repoAndOrgZH[key]; | return repoAndOrgZH[key]; | ||||
}else{ | }else{ | ||||
@@ -436,7 +451,7 @@ function displayOrg(json){ | |||||
html += " <img class=\"ui image\" src=\"" + record["Avatar"] + "\">"; | html += " <img class=\"ui image\" src=\"" + record["Avatar"] + "\">"; | ||||
html += " <div class=\"content nowrap\">"; | html += " <div class=\"content nowrap\">"; | ||||
html += " <span class=\"ui blue\">" + record["Name"] + "</span> " + record["FullName"]; | html += " <span class=\"ui blue\">" + record["Name"] + "</span> " + record["FullName"]; | ||||
html += " <div class=\"sub header\">" + record["NumRepos"] +" " + getRepoOrOrg(1,isZh) + " ・ " + record["NumMembers"] +" " + getRepoOrOrg(2,isZh) + " ・ " + record["NumTeams"] + " " + getRepoOrOrg(3,isZh) + "</div>"; | |||||
html += " <div class=\"sub header\">" + record["NumRepos"] +" " + getRepoOrOrg(1,isZh,record["NumRepos"]) + " ・ " + record["NumMembers"] +" " + getRepoOrOrg(2,isZh,record["NumMembers"]) + " ・ " + record["NumTeams"] + " " + getRepoOrOrg(3,isZh,record["NumTeams"]) + "</div>"; | |||||
html += " </div>"; | html += " </div>"; | ||||
html += " </div>"; | html += " </div>"; | ||||
html += " </div>"; | html += " </div>"; | ||||
@@ -51,12 +51,14 @@ func RepoStatisticDaily(date string) { | |||||
isInitMinMaxRadar := false | isInitMinMaxRadar := false | ||||
var error_projects = make([]string, 0) | |||||
for _, repo := range repos { | for _, repo := range repos { | ||||
log.Info("start statistic: %s", getDistinctProjectName(repo)) | |||||
projectName := getDistinctProjectName(repo) | |||||
log.Info("start statistic: %s", projectName) | |||||
var numDevMonths, numWikiViews, numContributor, numKeyContributor, numCommitsGrowth, numCommitLinesGrowth, numContributorsGrowth, numCommits int64 | var numDevMonths, numWikiViews, numContributor, numKeyContributor, numCommitsGrowth, numCommitLinesGrowth, numContributorsGrowth, numCommits int64 | ||||
repoGitStat, err := models.GetRepoKPIStats(repo) | repoGitStat, err := models.GetRepoKPIStats(repo) | ||||
if err != nil { | if err != nil { | ||||
log.Error("GetRepoKPIStats failed: %s", getDistinctProjectName(repo)) | |||||
log.Error("GetRepoKPIStats failed: %s", projectName) | |||||
} else { | } else { | ||||
numDevMonths = repoGitStat.DevelopAge | numDevMonths = repoGitStat.DevelopAge | ||||
numKeyContributor = repoGitStat.KeyContributors | numKeyContributor = repoGitStat.KeyContributors | ||||
@@ -79,26 +81,26 @@ func RepoStatisticDaily(date string) { | |||||
var numVersions int64 | var numVersions int64 | ||||
numVersions, err = models.GetReleaseCountByRepoID(repo.ID, models.FindReleasesOptions{}) | numVersions, err = models.GetReleaseCountByRepoID(repo.ID, models.FindReleasesOptions{}) | ||||
if err != nil { | if err != nil { | ||||
log.Error("GetReleaseCountByRepoID failed(%s): %v", getDistinctProjectName(repo), err) | |||||
log.Error("GetReleaseCountByRepoID failed(%s): %v", projectName, err) | |||||
} | } | ||||
var datasetSize int64 | var datasetSize int64 | ||||
datasetSize, err = getDatasetSize(repo) | datasetSize, err = getDatasetSize(repo) | ||||
if err != nil { | if err != nil { | ||||
log.Error("getDatasetSize failed(%s): %v", getDistinctProjectName(repo), err) | |||||
log.Error("getDatasetSize failed(%s): %v", projectName, err) | |||||
} | } | ||||
var numComments int64 | var numComments int64 | ||||
numComments, err = models.GetCommentCountByRepoID(repo.ID) | numComments, err = models.GetCommentCountByRepoID(repo.ID) | ||||
if err != nil { | if err != nil { | ||||
log.Error("GetCommentCountByRepoID failed(%s): %v", getDistinctProjectName(repo), err) | |||||
log.Error("GetCommentCountByRepoID failed(%s): %v", projectName, err) | |||||
} | } | ||||
beginTime, endTime := getStatTime(date) | beginTime, endTime := getStatTime(date) | ||||
var numVisits int | var numVisits int | ||||
numVisits, err = repository.AppointProjectView(repo.OwnerName, repo.Name, beginTime, endTime) | numVisits, err = repository.AppointProjectView(repo.OwnerName, repo.Name, beginTime, endTime) | ||||
if err != nil { | if err != nil { | ||||
log.Error("AppointProjectView failed(%s): %v", getDistinctProjectName(repo), err) | |||||
log.Error("AppointProjectView failed(%s): %v", projectName, err) | |||||
} | } | ||||
repoStat := models.RepoStatistic{ | repoStat := models.RepoStatistic{ | ||||
@@ -162,9 +164,10 @@ func RepoStatisticDaily(date string) { | |||||
} | } | ||||
if _, err = models.InsertRepoStat(&repoStat); err != nil { | if _, err = models.InsertRepoStat(&repoStat); err != nil { | ||||
log.Error("InsertRepoStat failed(%s): %v", getDistinctProjectName(repo), err) | |||||
log.Error("failed statistic: %s", getDistinctProjectName(repo)) | |||||
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage) | |||||
log.Error("InsertRepoStat failed(%s): %v", projectName, err) | |||||
log.Error("failed statistic: %s", projectName) | |||||
error_projects = append(error_projects, projectName) | |||||
continue | continue | ||||
} | } | ||||
@@ -247,6 +250,10 @@ func RepoStatisticDaily(date string) { | |||||
log.Info("finish statistic: %s", getDistinctProjectName(repo)) | log.Info("finish statistic: %s", getDistinctProjectName(repo)) | ||||
} | } | ||||
if len(error_projects) > 0 { | |||||
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage) | |||||
} | |||||
//radar map | //radar map | ||||
log.Info("begin statistic radar") | log.Info("begin statistic radar") | ||||
for _, radarInit := range reposRadar { | for _, radarInit := range reposRadar { | ||||
@@ -88,7 +88,7 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac | |||||
xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) | xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) | ||||
formatTime = userRecord.DataDate | formatTime = userRecord.DataDate | ||||
xlsx.SetCellValue(sheetName, "Q"+rows, formatTime+" 00:01") | |||||
xlsx.SetCellValue(sheetName, "Q"+rows, formatTime) | |||||
} | } | ||||
//设置默认打开的表单 | //设置默认打开的表单 | ||||
@@ -10,6 +10,8 @@ import ( | |||||
"github.com/elliotchance/orderedmap" | "github.com/elliotchance/orderedmap" | ||||
) | ) | ||||
var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23} | |||||
type ClientsManager struct { | type ClientsManager struct { | ||||
Clients *orderedmap.OrderedMap | Clients *orderedmap.OrderedMap | ||||
Register chan *Client | Register chan *Client | ||||
@@ -47,13 +49,15 @@ func (h *ClientsManager) Run() { | |||||
close(client.Send) | close(client.Send) | ||||
} | } | ||||
case message := <-models.ActionChan: | case message := <-models.ActionChan: | ||||
LastActionsQueue.Push(message) | |||||
for _, client := range h.Clients.Keys() { | |||||
select { | |||||
case client.(*Client).Send <- message: | |||||
default: | |||||
close(client.(*Client).Send) | |||||
h.Clients.Delete(client) | |||||
if isInOpTypes(opTypes, message.OpType) { | |||||
LastActionsQueue.Push(message) | |||||
for _, client := range h.Clients.Keys() { | |||||
select { | |||||
case client.(*Client).Send <- message: | |||||
default: | |||||
close(client.(*Client).Send) | |||||
h.Clients.Delete(client) | |||||
} | |||||
} | } | ||||
} | } | ||||
case s := <-sig: | case s := <-sig: | ||||
@@ -71,8 +75,19 @@ func (h *ClientsManager) Run() { | |||||
} | } | ||||
} | } | ||||
func isInOpTypes(types []int, opType models.ActionType) bool { | |||||
isFound := false | |||||
for _, value := range types { | |||||
if value == int(opType) { | |||||
isFound = true | |||||
break | |||||
} | |||||
} | |||||
return isFound | |||||
} | |||||
func initActionQueue() { | func initActionQueue() { | ||||
actions, err := models.GetLast20PublicFeeds() | |||||
actions, err := models.GetLast20PublicFeeds(opTypes) | |||||
if err == nil { | if err == nil { | ||||
for i := len(actions) - 1; i >= 0; i-- { | for i := len(actions) - 1; i >= 0; i-- { | ||||
@@ -43,7 +43,7 @@ | |||||
{{if .IsOperator}} | {{if .IsOperator}} | ||||
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
{{end}} | {{end}} | ||||
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
{{else if .IsLandingPageHome}} | {{else if .IsLandingPageHome}} | ||||
@@ -57,7 +57,7 @@ | |||||
<div class="leftline02-2"></div> | <div class="leftline02-2"></div> | ||||
<div class="ui center homepro-tit am-mb-20"> | <div class="ui center homepro-tit am-mb-20"> | ||||
<h2>{{.page_recommend_repo}}</h2> | <h2>{{.page_recommend_repo}}</h2> | ||||
<p><span class="ui text grey">{{.page_recommend_repo_desc}}</span><a href="{{.RecommendURL}}">{{.page_recommend_repo_commit}}</a>{{.page_recommend_repo_go}}<a href="{{AppSubUrl}}/explore/">{{.page_recommend_repo_more}}</a></p> | |||||
<p><span class="ui text grey">{{.page_recommend_repo_desc}}</span><a href="{{.RecommendURL}}">{{.page_recommend_repo_commit}}</a>{{.page_recommend_repo_go}} <a href="{{AppSubUrl}}/explore/">{{.page_recommend_repo_more}}</a></p> | |||||
</div> | </div> | ||||
<div class="homepro-list"> | <div class="homepro-list"> | ||||
@@ -0,0 +1,334 @@ | |||||
<style> | |||||
.text-right{ | |||||
float:right !important; | |||||
} | |||||
.header{ | |||||
font-weight:bold; | |||||
font-size: 18px; | |||||
font-family: SourceHanSansSC-medium; | |||||
} | |||||
.cor{ | |||||
color:#0366D6 !important; | |||||
} | |||||
.header_card{ | |||||
/* color:#003A8C !important; */ | |||||
color:#101010 !important; | |||||
margin: 10px 0 0px 0; | |||||
height: 25px; | |||||
font-size: 18px; | |||||
} | |||||
.marg{ | |||||
margin: 0 5px !important; | |||||
} | |||||
.content_list{ | |||||
max-height: 130px; | |||||
overflow: auto; | |||||
} | |||||
.Relist{ | |||||
color:#0366D6 !important; | |||||
} | |||||
.descript_height{ | |||||
color: #101010 !important; | |||||
margin: 10px 0; | |||||
height: 40px !important; | |||||
word-break:break-all; | |||||
line-height: 20px; | |||||
overflow: hidden; | |||||
/* overflow: hidden!important; | |||||
word-wrap:break-word!important; */ | |||||
} | |||||
.tags_height{ | |||||
height: 30px !important; | |||||
} | |||||
.full_height{ | |||||
height: 100%; | |||||
} | |||||
.omit{ | |||||
overflow: hidden; white-space: nowrap; text-overflow: ellipsis; | |||||
} | |||||
/deep/ ui.checkbox input[type=checkbox]::after{ | |||||
border: 1px solid #0366D6 !important; | |||||
} | |||||
.nowrap-2 { | |||||
/* height: 2.837em; */ | |||||
/* line-height: 1.4285em; */ | |||||
overflow: hidden; | |||||
overflow: hidden; | |||||
display: -webkit-box; | |||||
-webkit-line-clamp: 2; | |||||
-webkit-box-orient: vertical; | |||||
} | |||||
.ui.label{ | |||||
color:#0366D6 !important; | |||||
background-color: #B3DBDB !important; | |||||
font-weight:normal !important | |||||
} | |||||
</style> | |||||
<div class="ui stackable grid"> | |||||
<!-- <div style="width: 100%;margin:15px 0;"> | |||||
{{if .tags}} | |||||
<span class="header"> | |||||
精选项目 | |||||
</span> | |||||
{{if .IsOrganizationOwner}} | |||||
<a class="text-right" id="model" onclick="showcreate()" >{{svg "octicon-gear" 16}}自定义</a> | |||||
{{end}} | |||||
{{end}} | |||||
</div> --> | |||||
<div style="width: 100%;"> | |||||
<div class="ui three cards" style="margin-bottom: 10px;"> | |||||
{{range .Repos}} | |||||
<div class="card" > | |||||
<div class="extra full_height cor" > | |||||
<div class="content " > | |||||
{{if .Topics }} | |||||
<div class=" tags " style="position: relative;"> | |||||
{{range .Topics}} | |||||
{{if ne . "" }}<a style="max-width:100%;margin: 5px 0;display:inline-flex;" href="{{AppSubUrl}}/explore/repos?q={{.}}&topic={{$.Topic}}" ><span class="ui small label topic omit" >{{.}}</span></a>{{end}} | |||||
{{end}} | |||||
</div> | |||||
{{end}} | |||||
</div> | |||||
<div class=" header header_card omit" > | |||||
<a class="header_card image poping up " href="{{.Link}}" data-content="{{.Alias}}" data-position="top left" data-variation="tiny inverted"> {{.Alias}}</a> | |||||
</div> | |||||
<div class='content descript_height nowrap-2'> | |||||
{{.Description}} | |||||
<!-- <p class="time"> | |||||
{{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}} | |||||
{{if .PrimaryLanguage }} | |||||
<span class="text grey"><i class="color-icon" style="background-color: {{.PrimaryLanguage.Color}}"></i>{{ .PrimaryLanguage.Language }}</span> | |||||
{{end}} | |||||
</p> --> | |||||
</div> | |||||
</div> | |||||
<div class=" extra " style="color:#888888;border-top: none !important"> | |||||
<p class="time"> | |||||
{{$.i18n.Tr "org.repo_updated"}}{{.CreatedUnix.FormatShort}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}} | |||||
<!-- {{if .PrimaryLanguage }} | |||||
<span class="text grey"><i class="color-icon" style="background-color: {{.PrimaryLanguage.Color}}"></i>{{ .PrimaryLanguage.Language }}</span> | |||||
{{end}} --> | |||||
</p> | |||||
<!-- <div class="ui mini right compact marg" > | |||||
<a class="item marg "> | |||||
{{svg "octicon-eye" 16}} {{.NumWatches}} | |||||
</a> | |||||
<a class="item marg"> | |||||
{{svg "octicon-star" 16}} {{.NumStars}} | |||||
</a> | |||||
<a class="item marg"> | |||||
{{svg "octicon-git-branch" 16}} {{.NumForks}} | |||||
</a> | |||||
</div> --> | |||||
</div> | |||||
</div> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- <div class="ui modal"> | |||||
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | |||||
<h4 id="model_header">自定义精选课程</h4> | |||||
</div> | |||||
<div class="content content-padding" style="color: black;"> | |||||
<p>最多可选9个公开项目</p> | |||||
<div class="ui search" > | |||||
<div class="ui input" style="width: 100%;"> | |||||
<input type="text" id = 'search_selectPro' placeholder="Search ..." value = '' oninput="search()"> | |||||
</div> | |||||
</div> | |||||
<div style="margin: 10px ;"> | |||||
<div id ='org_list' style="margin-bottom: 20px;"class="content_list" > | |||||
</div> | |||||
</div> | |||||
<p id='recommend'></p> | |||||
<div class="inline field" style="margin-left: 37%;"> | |||||
<div class="actions"> | |||||
<button id="submitId" type="button" class="ui create_train_job green deny button" onclick="saveSeletedPro(1)"> | |||||
{{.i18n.Tr "explore.save"}} | |||||
</button> | |||||
<button class="ui button cancel" >{{.i18n.Tr "explore.cancel"}}</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> --> | |||||
<script> | |||||
var data; | |||||
var filterData=[]; | |||||
var num=0; | |||||
function showcreate(obj){ | |||||
document.getElementById("search_selectPro").value='' | |||||
$('.ui.modal') | |||||
.modal({ | |||||
centered: false, | |||||
onShow:function(){ | |||||
$("#org_list").empty() | |||||
getPro(1) | |||||
}, | |||||
onHide:function(){ | |||||
} | |||||
}) | |||||
.modal('show') | |||||
} | |||||
function getPro(typeTag){ | |||||
$.ajax({ | |||||
type:"GET", | |||||
url:"/org/{{.Org.Name}}/org_tag/repo_list?tagId="+typeTag, | |||||
dataType:"json", | |||||
async:false, | |||||
success:function(json){ | |||||
data = json.data; | |||||
var n_length = data.length | |||||
pro_html = getHTML(data) | |||||
$("#org_list").append(pro_html) | |||||
// console.log('原始',data) | |||||
checkedNum(0) | |||||
} | |||||
}); | |||||
} | |||||
function getHTML(data){ | |||||
let pro_html='' | |||||
for (let i=0;i<data.length;i++){ | |||||
if (data[i].Selected==true){ | |||||
console.log("data[i]:",data[i]) | |||||
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = " ${i}" checked="" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected=${data[i].Selected} > <label class='omit image poping up' data-content=${data[i].RepoName} data-position="top left " data-variation="mini"> ${data[i].RepoName}</label></div>` | |||||
pro_html += '</div>' | |||||
} | |||||
else{ | |||||
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = "${i}" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected= ${data[i].Selected}> <label class='omit image poping up' data-content=${data[i].RepoName} data-position="top left " data-variation="mini"> ${data[i].RepoName} </label></div>` | |||||
pro_html += '</div>' | |||||
} | |||||
} | |||||
return pro_html | |||||
} | |||||
function saveSeletedPro(typeTag){ | |||||
var saveData=[]; | |||||
$('input[name="select_pro_name"]:checked').each(function(){ | |||||
console.log('值',this.dataset.repoid) | |||||
saveData.push(parseInt(this.dataset.repoid)); | |||||
}) | |||||
if(saveData.length>9){ | |||||
alert("最多可选9个,保存失败") | |||||
return | |||||
} | |||||
// saveData = getSelecteDataID(); | |||||
// console.log("数据:",saveData) | |||||
$.ajax({ | |||||
type:"POST", | |||||
url:"/org/{{.Org.Name}}/org_tag/repo_submit?tagId="+typeTag, | |||||
contentType:'application/json', | |||||
dataType:"json", | |||||
async:false, | |||||
data:JSON.stringify({'repoList':saveData | |||||
}), | |||||
success:function(res){ | |||||
console.log('保存成功'); | |||||
location.reload() | |||||
} | |||||
}); | |||||
} | |||||
function getSelecteData(){ | |||||
var selectedData=[]; | |||||
$('input[name="select_pro_name"]:checked').each(function(){ | |||||
// console.log(this) | |||||
// console.log('值',this.dataset.selected) | |||||
selectedData.push({"RepoID":parseInt(this.dataset.repoid),"RepoName":this.dataset.reponame,"Selected":JSON.parse(this.dataset.selected)}); | |||||
}) | |||||
return selectedData | |||||
} | |||||
function search(){ | |||||
var selectedData = getSelecteData(); | |||||
var searchValue = document.getElementById("search_selectPro").value; | |||||
filterData=[]; | |||||
console.log("searchValue:",searchValue) | |||||
for (let i=0;i<data.length;i++){ | |||||
var isInclude=false; | |||||
if(data[i].RepoName.toLowerCase().includes(searchValue.toLowerCase())){ | |||||
filterData.push(data[i]) | |||||
} | |||||
} | |||||
console.log("选中的值:",selectedData) | |||||
console.log("筛选包括选中的值:",filterData) | |||||
var showData=[]; | |||||
for(i=0;i<selectedData.length;i++){ | |||||
filterData =filterData.filter((item)=>{ | |||||
return item.RepoID!=selectedData[i].RepoID | |||||
}); | |||||
} | |||||
console.log("筛选后不包括选中的值:",filterData) | |||||
$("#org_list").empty() | |||||
if(searchValue!=""){ | |||||
if (filterData.length!=0){ | |||||
var pro_html = getHTML(selectedData); | |||||
console.log("selectedData_pro_html:",pro_html) | |||||
$("#org_list").append(pro_html) | |||||
pro_html= getHTML(filterData); | |||||
$("#org_list").append(pro_html) | |||||
}else{ | |||||
var pro_html = getHTML(selectedData); | |||||
$("#org_list").append(pro_html) | |||||
} | |||||
}else{ | |||||
var pro_html = getHTML(data); | |||||
$("#org_list").append(pro_html) | |||||
} | |||||
} | |||||
function checkedNum(id){ | |||||
num=0; | |||||
var inputs = document.getElementsByName("select_pro_name") | |||||
for (var i=0;i<inputs.length;i++){ | |||||
if(inputs[i].checked){ | |||||
num++ | |||||
if(num>9){ | |||||
document.getElementById(id).checked=false | |||||
alert("选择超过9个,请重新选择!") | |||||
return | |||||
} | |||||
} | |||||
} | |||||
var show_num = 9-num; | |||||
document.getElementById("recommend").innerHTML="还能推荐"+show_num+"个" | |||||
} | |||||
</script> |
@@ -0,0 +1,479 @@ | |||||
<style> | |||||
.organization-info_1000{ | |||||
background: #F5F5F6 !important; | |||||
} | |||||
.organization-info >.container { | |||||
overflow: auto; | |||||
background: #f5f5f6 !important; | |||||
padding-top: 30px; | |||||
padding-bottom: 20px; | |||||
background-size: cover; | |||||
border-radius: 5px; | |||||
border: none !important | |||||
} | |||||
.organization.profile #org-avatar { | |||||
border:none !important | |||||
} | |||||
.desc { | |||||
font-size: 14px; | |||||
margin-bottom: 10px !important; | |||||
} | |||||
.item { | |||||
display: inline-block; | |||||
margin-right: 10px; | |||||
} | |||||
.item .icon { | |||||
margin-right: 5px; | |||||
} | |||||
.organization-info >.container { | |||||
padding-bottom:0px !important; | |||||
} | |||||
.tag_bg{ | |||||
background-color: #0366D6 !important; | |||||
color:#FFFFFF !important; | |||||
} | |||||
.course{ | |||||
padding: 10px 15px !important; | |||||
} | |||||
.course_color{ | |||||
color: #FA8C16; | |||||
} | |||||
.tag_lable{ | |||||
border: 1px solid rgba(232, 232, 232, 100) ; | |||||
border-radius: 4px; | |||||
color: rgba(65, 80, 88, 100); | |||||
font-family: Microsoft Yahei; | |||||
font-size: 14px; | |||||
padding: 0.3em 0.5em; | |||||
height: 30px; | |||||
text-align: center; | |||||
margin: 0.2em; | |||||
} | |||||
.tag_lable_first{ | |||||
border: 1px solid rgba(232, 232, 232, 100) ; | |||||
border-radius: 4px; | |||||
color: rgba(65, 80, 88, 100); | |||||
font-family: Microsoft Yahei; | |||||
font-size: 14px; | |||||
padding: 0.3em 0.5em; | |||||
height: 30px; | |||||
text-align: center; | |||||
margin: 0.2em; | |||||
margin-left: none; | |||||
} | |||||
</style> | |||||
{{template "base/head" .}} | |||||
<div class="organization profile"> | |||||
{{/* overflow: auto is the clearfix - this avoids the image going beyond | |||||
the container where it is supposed to stay inside. */}} | |||||
<!-- <div class="organization-info"> | |||||
<div class="ui center aligned container " style="overflow: auto"> | |||||
<img class="ui circular image" id="org-avatar" src="{{.Org.SizedRelAvatarLink 140}}"/> | |||||
<div id="org-info"> | |||||
<div class="ui header"> | |||||
{{.Org.DisplayName}} | |||||
{{if .IsOrganizationOwner}}<a class="middle text grey" href="{{.OrgLink}}/settings">{{svg "octicon-gear" 16}}</a>{{end}} | |||||
</div> | |||||
{{if .Org.Description}}<p class="text grey desc">{{.Org.Description}}</p>{{end}} | |||||
<div class="meta"> | |||||
{{if .Org.Location}}<div class="item">{{svg "octicon-location" 16}} <span>{{.Org.Location}}</span></div>{{end}} | |||||
{{if .Org.Website}}<div class="item">{{svg "octicon-link" 16}} <a target="_blank" rel="noopener noreferrer" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> --> | |||||
<div class="organization-info organization-info_1000"> | |||||
<div class="ui center aligned container " style="overflow: auto"> | |||||
<img class="ui left image" id="org-avatar" src="{{.Org.SizedRelAvatarLink 140}}"/> | |||||
<div class="content" style="text-align: left;margin-left:100px" > | |||||
<div class="ui header" > | |||||
{{.Org.DisplayName}} | |||||
<!-- {{if .IsOrganizationOwner}}<a class="middle text grey" href="{{.OrgLink}}/settings">{{svg "octicon-gear" 16}}</a>{{end}} --> | |||||
</div> | |||||
<div class="description" > | |||||
{{if .Org.Description}}<p class="text grey desc">{{.Org.Description}}</p>{{end}} | |||||
</div> | |||||
<div class="meta" style="display: inline-flex;"> | |||||
{{if .Org.Location}}<div class="item">{{svg "octicon-location" 16}} <span>{{.Org.Location}}</span></div>{{end}} | |||||
{{if .Org.Website}}<div class="item">{{svg "octicon-link" 16}} <a target="_blank" rel="noopener noreferrer" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui tabs container"> | |||||
<div class="ui tabular stackable menu navbar"> | |||||
{{with .Org}} | |||||
<a class="{{if $.PageIsOrgHome}}active{{end}} item " href="{{.HomeLink}}"> | |||||
{{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | |||||
</a> | |||||
{{end}} | |||||
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||||
{{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||||
</a> | |||||
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | |||||
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | |||||
{{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | |||||
</a> | |||||
{{end}} | |||||
{{if .IsOrganizationOwner}}<a class="right text grey item" href="{{.OrgLink}}/settings">{{svg "octicon-gear" 16}} 组织设置</a>{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- <div class="ui container " style="overflow: auto"> | |||||
<img class="ui left image" id="org-avatar" src="{{.Org.SizedRelAvatarLink 140}}"/> | |||||
<p id="org-info"> | |||||
<div class="ui header"> | |||||
{{.Org.DisplayName}} | |||||
{{if .IsOrganizationOwner}}<a class="middle text grey" href="{{.OrgLink}}/settings">{{svg "octicon-gear" 16}}</a>{{end}} | |||||
</div> | |||||
{{if .Org.Description}}<p class="text grey desc">{{.Org.Description}}</p>{{end}} | |||||
<div class="meta"> | |||||
{{if .Org.Location}}<div class="item">{{svg "octicon-location" 16}} <span>{{.Org.Location}}</span></div>{{end}} | |||||
{{if .Org.Website}}<div class="item">{{svg "octicon-link" 16}} <a target="_blank" rel="noopener noreferrer" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}} | |||||
</div> | |||||
</p> | |||||
</div> --> | |||||
<div class="ui container"> | |||||
<!-- 新增 --> | |||||
<div class="ui stackable grid"> | |||||
<div class="ui sixteen wide computer column"> | |||||
<div class="ui mobile reversed stackable grid"> | |||||
<div class="ui ten wide tablet eleven wide computer column" id='tag'> | |||||
<a class="ui small lable tag_lable topic tag_bg" style="margin-left: 0px;" >全部关键字</a> | |||||
{{range .CoursesKeywords}} | |||||
<a class="ui small lable tag_lable topic" >{{.}}</a> | |||||
{{end}} | |||||
</div> | |||||
<div class="ui sixteen wide mobile six wide tablet five wide computer column"> | |||||
<!-- {{if .CanCreateOrgRepo}} --> | |||||
<div class="text center" style="margin-left: 10px;"> | |||||
<a class="ui green button" href="{{AppSubUrl}}/repo/create?org={{.Org.ID}}"><i class="ri-folder-add-line" style="vertical-align: middle;"></i> 发布课程{{.i18n.Tr "new_repo"}} </a> | |||||
</div> | |||||
<!-- {{end}} --> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- 全部 --> | |||||
<div class="ui stackable grid"> | |||||
<div class="ui sixteen wide computer column"> | |||||
<div class="ui mobile reversed stackable grid"> | |||||
<div class="ui ten wide tablet eleven wide computer column"> | |||||
<!-- {{if .CanCreateOrgRepo}} | |||||
<div class="text right"> | |||||
<a class="ui green button" href="{{AppSubUrl}}/repo/create?org={{.Org.ID}}">{{.i18n.Tr "new_repo"}}</a> | |||||
</div> | |||||
{{end}} --> | |||||
{{template "org/course_list" .}} | |||||
{{template "base/paginate" .}} | |||||
</div> | |||||
<div class="ui sixteen wide mobile six wide tablet five wide computer column"> | |||||
<h4 class="ui top attached header"> | |||||
<strong>{{.i18n.Tr "org.selected_couse"}}</strong> | |||||
<div class="ui right"> | |||||
<a class="text grey" id="model" onclick="showcreate()">{{svg "octicon-gear" 16}}</a> | |||||
</div> | |||||
<!-- {{if .IsOrganizationMember}} --> | |||||
<!-- {{end}} --> | |||||
</h4> | |||||
<div class="ui attached table segment course items"> | |||||
{{range $i, $v := .RecommendCourses}} | |||||
{{if gt $i 0}} | |||||
<div class="ui divider" style="margin-bottom:10px;"></div> | |||||
{{end}} | |||||
<div class="item"> | |||||
<i class="ri-bookmark-3-line course_color" ></i> | |||||
<div class="content" style="margin-left: 10px;"> | |||||
<a href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong class="team-name">{{.Alias}}</strong></a> | |||||
<p class="text grey"> | |||||
贡献者:{{.Creator.Name}} | |||||
</p> | |||||
</div> | |||||
</div> | |||||
<!-- <div class="ui divider"></div> --> | |||||
{{end}} | |||||
</div> | |||||
<h4 class="ui top attached header"> | |||||
<strong>{{.i18n.Tr "org.people"}}</strong> | |||||
<div class="ui right"> | |||||
<a class="text grey" href="{{.OrgLink}}/members">{{.MembersTotal}} {{svg "octicon-chevron-right" 16}}</a> | |||||
</div> | |||||
<!-- {{if .IsOrganizationMember}} --> | |||||
<!-- {{end}} --> | |||||
</h4> | |||||
<div class="ui attached segment members"> | |||||
{{$isMember := .IsOrganizationMember}} | |||||
{{range .Members}} | |||||
{{if or $isMember (.IsPublicMember $.Org.ID)}} | |||||
<a href="{{.HomeLink}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}"><img class="ui avatar" src="{{.RelAvatarLink}}"></a> | |||||
{{end}} | |||||
{{end}} | |||||
<div style="text-align: center;margin-top: 5px;"> | |||||
<a class="ui blue basic button" href="{{.OrgLink}}/teams/new"> <i class="ri-user-add-line"></i> {{.i18n.Tr "org.teams.join_teams"}}</a> | |||||
</div> | |||||
</div> | |||||
{{if .IsOrganizationMember}} | |||||
<div class="ui top attached header"> | |||||
<strong>{{.i18n.Tr "org.teams"}}</strong> | |||||
<div class="ui right"> | |||||
<a class="text grey" href="{{.OrgLink}}/teams"><span>{{.Org.NumTeams}}</span> {{svg "octicon-chevron-right" 16}}</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui attached table segment teams"> | |||||
{{range .Teams}} | |||||
<div class="item"> | |||||
<a href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong class="team-name">{{.Name}}</strong></a> | |||||
<p class="text grey"> | |||||
<a href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> · | |||||
<a href="{{$.OrgLink}}/teams/{{.LowerName}}/repositories"><strong>{{.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a> | |||||
</p> | |||||
</div> | |||||
{{end}} | |||||
</div> | |||||
{{if .IsOrganizationOwner}} | |||||
<div class="ui bottom attached segment"> | |||||
<a class="ui blue small button" href="{{.OrgLink}}/teams/new">{{.i18n.Tr "org.create_new_team"}}</a> | |||||
</div> | |||||
{{end}} | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui modal"> | |||||
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | |||||
<h4 id="model_header">自定义精选课程</h4> | |||||
</div> | |||||
<div class="content content-padding" style="color: black;"> | |||||
<p>最多可选9个公开项目</p> | |||||
<div class="ui search" > | |||||
<div class="ui input" style="width: 100%;"> | |||||
<input type="text" id = 'search_selectPro' placeholder="Search ..." value = '' oninput="search()"> | |||||
</div> | |||||
</div> | |||||
<div style="margin: 10px ;"> | |||||
<div id ='org_list' style="margin-bottom: 20px;"class="content_list" > | |||||
</div> | |||||
</div> | |||||
<p id='recommend'></p> | |||||
<div class="inline field" style="margin-left: 37%;"> | |||||
<div class="actions"> | |||||
<button id="submitId" type="button" class="ui create_train_job green deny button" onclick="saveSeletedPro(1)"> | |||||
{{.i18n.Tr "explore.save"}} | |||||
</button> | |||||
<button class="ui button cancel" >{{.i18n.Tr "explore.cancel"}}</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{template "base/footer" .}} | |||||
<script> | |||||
// var div = document.getElementsByClassName("ui ten wide tablet eleven wide computer column").getElementsByTagName("a"); | |||||
// function changeBgcolor(){ | |||||
// document.getElementsByClassName("ui small lable tag_lable topic tag_bg").className= "ui small lable tag_lable topic"; | |||||
// // this.classList.add("tag_bg") | |||||
// } | |||||
window.onload = function () | |||||
{ | |||||
var atag =document.getElementById("tag").getElementsByTagName("a"); | |||||
var i = 0; | |||||
for (i = 0; i < atag.length; i++) | |||||
{ | |||||
atag[i].onclick = function () | |||||
{ | |||||
for (i = 0; i < atag.length; i++) | |||||
atag[i].className = "ui small lable tag_lable topic"; | |||||
this.className = "ui small lable tag_lable topic tag_bg"; | |||||
}; | |||||
} | |||||
}; | |||||
var data; | |||||
var filterData=[]; | |||||
var num=0; | |||||
function showcreate(obj){ | |||||
document.getElementById("search_selectPro").value='' | |||||
$('.ui.modal') | |||||
.modal({ | |||||
centered: false, | |||||
onShow:function(){ | |||||
$("#org_list").empty() | |||||
getPro(1) | |||||
}, | |||||
onHide:function(){ | |||||
} | |||||
}) | |||||
.modal('show') | |||||
} | |||||
function getPro(typeTag){ | |||||
$.ajax({ | |||||
type:"GET", | |||||
url:"/org/{{.Org.Name}}/org_tag/repo_list?tagId="+typeTag, | |||||
dataType:"json", | |||||
async:false, | |||||
success:function(json){ | |||||
data = json.data; | |||||
var n_length = data.length | |||||
pro_html = getHTML(data) | |||||
$("#org_list").append(pro_html) | |||||
// console.log('原始',data) | |||||
checkedNum(0) | |||||
} | |||||
}); | |||||
} | |||||
function getHTML(data){ | |||||
let pro_html='' | |||||
for (let i=0;i<data.length;i++){ | |||||
if (data[i].Selected==true){ | |||||
console.log("data[i]:",data[i]) | |||||
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = " ${i}" checked="" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected=${data[i].Selected} > <label class='omit image poping up' data-content=${data[i].RepoName} data-position="top left " data-variation="mini"> ${data[i].RepoName}</label></div>` | |||||
pro_html += '</div>' | |||||
} | |||||
else{ | |||||
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = "${i}" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected= ${data[i].Selected}> <label class='omit image poping up' data-content=${data[i].RepoName} data-position="top left " data-variation="mini"> ${data[i].RepoName} </label></div>` | |||||
pro_html += '</div>' | |||||
} | |||||
} | |||||
return pro_html | |||||
} | |||||
function saveSeletedPro(typeTag){ | |||||
var saveData=[]; | |||||
$('input[name="select_pro_name"]:checked').each(function(){ | |||||
console.log('值',this.dataset.repoid) | |||||
saveData.push(parseInt(this.dataset.repoid)); | |||||
}) | |||||
if(saveData.length>9){ | |||||
alert("最多可选9个,保存失败") | |||||
return | |||||
} | |||||
// saveData = getSelecteDataID(); | |||||
// console.log("数据:",saveData) | |||||
$.ajax({ | |||||
type:"POST", | |||||
url:"/org/{{.Org.Name}}/org_tag/repo_submit?tagId="+typeTag, | |||||
contentType:'application/json', | |||||
dataType:"json", | |||||
async:false, | |||||
data:JSON.stringify({'repoList':saveData | |||||
}), | |||||
success:function(res){ | |||||
console.log('保存成功'); | |||||
location.reload() | |||||
} | |||||
}); | |||||
} | |||||
function getSelecteData(){ | |||||
var selectedData=[]; | |||||
$('input[name="select_pro_name"]:checked').each(function(){ | |||||
// console.log(this) | |||||
// console.log('值',this.dataset.selected) | |||||
selectedData.push({"RepoID":parseInt(this.dataset.repoid),"RepoName":this.dataset.reponame,"Selected":JSON.parse(this.dataset.selected)}); | |||||
}) | |||||
return selectedData | |||||
} | |||||
function search(){ | |||||
var selectedData = getSelecteData(); | |||||
var searchValue = document.getElementById("search_selectPro").value; | |||||
filterData=[]; | |||||
console.log("searchValue:",searchValue) | |||||
for (let i=0;i<data.length;i++){ | |||||
var isInclude=false; | |||||
if(data[i].RepoName.toLowerCase().includes(searchValue.toLowerCase())){ | |||||
filterData.push(data[i]) | |||||
} | |||||
} | |||||
console.log("选中的值:",selectedData) | |||||
console.log("筛选包括选中的值:",filterData) | |||||
var showData=[]; | |||||
for(i=0;i<selectedData.length;i++){ | |||||
filterData =filterData.filter((item)=>{ | |||||
return item.RepoID!=selectedData[i].RepoID | |||||
}); | |||||
} | |||||
console.log("筛选后不包括选中的值:",filterData) | |||||
$("#org_list").empty() | |||||
if(searchValue!=""){ | |||||
if (filterData.length!=0){ | |||||
var pro_html = getHTML(selectedData); | |||||
console.log("selectedData_pro_html:",pro_html) | |||||
$("#org_list").append(pro_html) | |||||
pro_html= getHTML(filterData); | |||||
$("#org_list").append(pro_html) | |||||
}else{ | |||||
var pro_html = getHTML(selectedData); | |||||
$("#org_list").append(pro_html) | |||||
} | |||||
}else{ | |||||
var pro_html = getHTML(data); | |||||
$("#org_list").append(pro_html) | |||||
} | |||||
} | |||||
function checkedNum(id){ | |||||
num=0; | |||||
var inputs = document.getElementsByName("select_pro_name") | |||||
for (var i=0;i<inputs.length;i++){ | |||||
if(inputs[i].checked){ | |||||
num++ | |||||
if(num>9){ | |||||
document.getElementById(id).checked=false | |||||
alert("选择超过9个,请重新选择!") | |||||
return | |||||
} | |||||
} | |||||
} | |||||
var show_num = 9-num; | |||||
document.getElementById("recommend").innerHTML="还能推荐"+show_num+"个" | |||||
} | |||||
</script> |
@@ -0,0 +1,98 @@ | |||||
{{template "base/head" .}} | |||||
<div class="repository new repo" style="margin-top: 40px;"> | |||||
<div class="ui middle very relaxed page grid"> | |||||
<div class="column"> | |||||
<form class="ui form" action="{{.Link}}" method="post" id="create_repo_form"> | |||||
{{.CsrfTokenHtml}} | |||||
<h3 class="ui top attached header"> | |||||
{{.i18n.Tr "new_course"}} | |||||
</h3> | |||||
<div class="ui attached segment"> | |||||
{{template "base/alert" .}} | |||||
<div class="inline required field" > | |||||
<label for="Alias">{{.i18n.Tr "form.courseAlias"}}</label> | |||||
<input id="alias" name="Alias" value="" autofocus required> | |||||
<span class="help">{{.i18n.Tr "form.reponame_dash_dot_error"}}</span> | |||||
</div> | |||||
<div class="inline required fields" style="margin-bottom: 0;"> | |||||
<label style="text-align: right;width: 250px!important;word-wrap: break-word;">{{.i18n.Tr "form.courseAdress"}}</label> | |||||
<div class="required field {{if .Err_Owner}}error{{end}}" style="padding: 0;"> | |||||
<div class="ui selection owner dropdown" id="ownerDropdown"> | |||||
<input type="hidden" id="uid" name="uid" value="{{.Owner.Name}}" required> | |||||
<div class="text" title="{{.Owner.Name}}"> | |||||
<img class="ui mini image" src="{{.Owner.RelAvatarLink}}"> | |||||
{{$.Owner.Name}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui interval" style="width: 0.6em;font-size: 2rem;line-height: 0px;text-align: center;">/</div> | |||||
<div class="required field {{if .Err_RepoName}}error{{end}}"> | |||||
<input style="width: 100% !important;" id="repo_name" name="RepoName" value="{{.repo_name}}" autofocus required> | |||||
</div> | |||||
</div> | |||||
<span style="display: block;margin-bottom: 1em;" class="help">{{.i18n.Tr "form.repoadd_dash_dot_error"}}</span> | |||||
<div class="inline field" id="repoAdress" style="display: none;word-break: break-all;"> | |||||
<label for="">{{.i18n.Tr "form.RepoAdress"}}:</label> | |||||
<span></span> | |||||
</div> | |||||
<div class="inline required field"> | |||||
<label>{{.i18n.Tr "repo.model.manage.label"}}</label> | |||||
<div class="ui multiple search selection dropdown"> | |||||
<input type="hidden" name="Topics" value=""> | |||||
<div class="default text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||||
<div class="menu" id="course_label_item"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="inline field {{if .Err_Description}}error{{end}}"> | |||||
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> | |||||
<textarea id="description" name="Description" maxlength="254">{{.description}}</textarea> | |||||
</div> | |||||
<div class="inline field"> | |||||
<label></label> | |||||
<button class="ui green button" id="submit_reponame"> | |||||
{{.i18n.Tr "new_course"}} | |||||
</button> | |||||
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{template "base/footer" .}} | |||||
<script> | |||||
$(document).ready(function(){ | |||||
$('.ui.multiple.search.selection.dropdown') | |||||
.dropdown({ | |||||
allowAdditions: true, | |||||
onChange: function(value, text, $selectedItem) { | |||||
$('#course_label_item').empty() | |||||
} | |||||
}) | |||||
$('input.search').bind('input propertychange', function (event) { | |||||
const query = $('input.search').val() | |||||
if(!query){ | |||||
$('#course_label_item').empty() | |||||
}else{ | |||||
$.get(`/api/v1/topics/search?q=${query}`,(data)=>{ | |||||
console.log(data) | |||||
if(data.topics.length!==0){ | |||||
let html='' | |||||
$('#course_label_item').empty() | |||||
data.topics.forEach(element => { | |||||
html += `<div class="item" data-value="${element.topic_name}">${element.topic_name}</div>` | |||||
}); | |||||
$('#course_label_item').append(html) | |||||
} | |||||
}) | |||||
} | |||||
}); | |||||
}) | |||||
</script> |
@@ -135,13 +135,10 @@ | |||||
</template> | </template> | ||||
</el-table-column> | </el-table-column> | ||||
<el-table-column | <el-table-column | ||||
prop="CountDate" | |||||
prop="DataDate" | |||||
label="系统统计时间" | label="系统统计时间" | ||||
width="120px" | width="120px" | ||||
align="center"> | align="center"> | ||||
<template slot-scope="scope"> | |||||
{{scope.row.CountDate | transformTimestamp}} | |||||
</template> | |||||
</el-table-column> | </el-table-column> | ||||
</el-table> | </el-table> | ||||
</div> | </div> | ||||