Browse Source

Merge branch 'liuzx_trainjob' of https://git.openi.org.cn/OpenI/aiforge into liuzx_trainjob

pull/896/head^2
zhoupzh 3 years ago
parent
commit
a924822f71
18 changed files with 510 additions and 234 deletions
  1. +40
    -15
      models/user_business_analysis.go
  2. +1
    -1
      modules/git/repo_compare.go
  3. +20
    -1
      modules/modelarts/resty.go
  4. +5
    -2
      modules/setting/setting.go
  5. +11
    -11
      modules/storage/obs.go
  6. +4
    -5
      options/locale/locale_en-US.ini
  7. +1
    -0
      options/locale/locale_zh-CN.ini
  8. +13
    -26
      routers/api/v1/repo/repo_dashbord.go
  9. +5
    -3
      routers/repo/attachment.go
  10. +2
    -0
      routers/repo/modelarts.go
  11. +17
    -7
      routers/repo/repo_statistic.go
  12. +46
    -10
      routers/repo/user_data_analysis.go
  13. +4
    -7
      routers/repo/view.go
  14. +16
    -0
      services/mailer/mail.go
  15. +21
    -18
      web_src/js/components/DataAnalysis.vue
  16. +1
    -0
      web_src/js/components/ObsUploader.vue
  17. +184
    -66
      web_src/js/components/ProAnalysis.vue
  18. +119
    -62
      web_src/js/components/UserAnalysis.vue

+ 40
- 15
models/user_business_analysis.go View File

@@ -82,6 +82,7 @@ type UserBusinessAnalysisQueryOptions struct {
SortType string
StartTime int64
EndTime int64
IsAll bool
}

type UserBusinessAnalysisList []*UserBusinessAnalysis
@@ -142,15 +143,33 @@ func QueryUserStaticData(startTime int64, endTime int64) []*UserBusinessAnalysis
return userBusinessAnalysisReturnList
}

func getLastCountDate() int64 {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
statictisSess.Limit(1, 0)
userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0)
if err := statictisSess.Table("user_business_analysis").OrderBy("count_date desc").Limit(1, 0).
Find(&userBusinessAnalysisList); err == nil {
for _, userRecord := range userBusinessAnalysisList {
return userRecord.CountDate - 10000
}
} else {
log.Info("query error." + err.Error())
}
currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
return pageStartTime.Unix()
}

func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusinessAnalysis, int64) {

log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime))
log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime) + " isAll=" + fmt.Sprint(opts.IsAll))
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()

currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageStartTime := getLastCountDate()
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()).Unix()

var cond = builder.NewCond()
if len(opts.UserName) > 0 {
@@ -159,10 +178,10 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
)
}
cond = cond.And(
builder.Gte{"count_date": pageStartTime.Unix()},
builder.Gte{"count_date": pageStartTime},
)
cond = cond.And(
builder.Lte{"count_date": pageEndTime.Unix()},
builder.Lte{"count_date": pageEndTime},
)

count, err := statictisSess.Where(cond).Count(new(UserBusinessAnalysis))
@@ -190,7 +209,7 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus

resultMap := make(map[int64]*UserBusinessAnalysis)

if opts.Page >= 0 && opts.PageSize > 0 {
if opts.Page >= 0 && opts.PageSize > 0 && len(userBusinessAnalysisList) > 0 {
var newAndCond = builder.NewCond()
var newOrCond = builder.NewCond()
for _, userRecord := range userBusinessAnalysisList {
@@ -201,12 +220,14 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
newAndCond = newAndCond.And(
newOrCond,
)
newAndCond = newAndCond.And(
builder.Gte{"count_date": opts.StartTime},
)
newAndCond = newAndCond.And(
builder.Lte{"count_date": opts.EndTime},
)
if !opts.IsAll {
newAndCond = newAndCond.And(
builder.Gte{"count_date": opts.StartTime},
)
newAndCond = newAndCond.And(
builder.Lte{"count_date": opts.EndTime},
)
}

userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0)
if err := statictisSess.Table("user_business_analysis").Where(newAndCond).
@@ -246,7 +267,7 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
return userBusinessAnalysisReturnList, count
}

func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, endTime time.Time, isReCount bool) {
func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, endTime time.Time, isReCount bool) error {

log.Info("start to count other user info data")
sess := x.NewSession()
@@ -394,9 +415,13 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,

dateRecord.CommitModelCount = 0

statictisSess.Insert(&dateRecord)
_, err = statictisSess.Insert(&dateRecord)
if err != nil {
log.Info("insert daterecord failed." + err.Error())
return err
}
}

return nil
}

func CounDataByDate(wikiCountMap map[string]int, startTime time.Time, endTime time.Time) {


+ 1
- 1
modules/git/repo_compare.go View File

@@ -32,7 +32,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin
if tmpRemote != "origin" {
tmpBaseName := "refs/remotes/" + tmpRemote + "/tmp_" + base
// Fetch commit into a temporary branch in order to be able to handle commits and tags
_, err := NewCommand("fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path)
_, err := NewCommand("fetch", tmpRemote, base+":"+tmpBaseName,"--no-tags").RunInDir(repo.Path)
if err == nil {
base = tmpBaseName
}


+ 20
- 1
modules/modelarts/resty.go View File

@@ -366,6 +366,16 @@ sendjob:
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {
log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}

@@ -411,7 +421,16 @@ sendjob:
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
BootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {
log.Error("启动文件错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
log.Error("数据集错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}



+ 5
- 2
modules/setting/setting.go View File

@@ -547,8 +547,9 @@ var (
GrowthCommit float64
GrowthComments float64
RecordBeginTime string
Path string
}{}
Warn_Notify_Mails []string
)

// DateLang transforms standard language locale name to corresponding value in datetime plugin.
@@ -1292,6 +1293,9 @@ func NewContext() {
ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time")

SetRadarMapConfig()

sec = Cfg.Section("warn_mail")
Warn_Notify_Mails = strings.Split(sec.Key("mails").MustString(""), ",")
}

func SetRadarMapConfig() {
@@ -1329,7 +1333,6 @@ func SetRadarMapConfig() {
RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2)
RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2)
RadarMap.RecordBeginTime = sec.Key("record_beigin_time").MustString("2021-11-05")
RadarMap.Path = sec.Key("PATH").MustString("data/projectborad")

}



+ 11
- 11
modules/storage/obs.go View File

@@ -29,20 +29,20 @@ type FileInfo struct {
}

//check if has the object
//todo:修改查询方式
func ObsHasObject(path string) (bool, error) {
hasObject := false
output, err := ObsCli.ListObjects(&obs.ListObjectsInput{Bucket: setting.Bucket})
if err != nil {
log.Error("ListObjects failed:%v", err)
return hasObject, err
}

for _, obj := range output.Contents {
//obj.Key:attachment/0/1/019fd24e-4ef7-41cc-9f85-4a7b8504d958
if path == obj.Key {
hasObject = true
break
input := &obs.GetObjectMetadataInput{}
input.Bucket = setting.Bucket
input.Key = path
_, err := ObsCli.GetObjectMetadata(input)
if err == nil {
hasObject = true
} else {
if obsError, ok := err.(obs.ObsError); ok {
log.Error("GetObjectMetadata failed(%d): %s", obsError.StatusCode, obsError.Message)
} else {
log.Error("%v", err.Error())
}
}



+ 4
- 5
options/locale/locale_en-US.ini View File

@@ -420,7 +420,7 @@ static.createrepocount=Create Repo Count
static.openiindex=OpenI Index
static.registdate=Regist Date
static.countdate=Count Date
static.all=All

[settings]
profile = Profile
@@ -813,10 +813,9 @@ total_count_get_error=Can not get the total page.
last_update_time_error=Can not get the last updated time.
get_repo_stat_error=Can not get the statistics of the repository.
get_repo_info_error=Can not get the information of the repository.
modelarts.status=Status
modelarts.createtime=CreateTime
modelarts.version_nums = Version Nums
modelarts.computing_resources=compute Resources
generate_statistic_file_error=Fail to generate file.
repo_stat_inspect=ProjectAnalysis
all=All
modelarts.notebook=Debug Task
modelarts.train_job=Train Task
modelarts.train_job.new_debug= New Debug Task


+ 1
- 0
options/locale/locale_zh-CN.ini View File

@@ -423,6 +423,7 @@ static.createrepocount=创建项目数
static.openiindex=OpenI指数
static.registdate=用户注册时间
static.countdate=系统统计时间
static.all=所有
[settings]
profile=个人信息
account=账号


+ 13
- 26
routers/api/v1/repo/repo_dashbord.go View File

@@ -4,8 +4,6 @@ import (
"fmt"
"net/http"
"net/url"
"os"
"path"
"strconv"
"time"

@@ -175,15 +173,12 @@ func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) {
var projectAnalysis = ctx.Tr("repo.repo_stat_inspect")
fileName := getFileName(ctx, beginTime, endTime, projectAnalysis)

if err := os.MkdirAll(setting.RadarMap.Path, os.ModePerm); err != nil {
ctx.Error(http.StatusBadRequest, fmt.Errorf("Failed to create dir %s: %v", setting.AvatarUploadPath, err).Error())
}

totalPage := getTotalPage(total, pageSize)

f := excelize.NewFile()

index := f.NewSheet(projectAnalysis)
f.DeleteSheet("Sheet1")

for k, v := range allProjectsPeroidHeader(ctx) {
f.SetCellValue(projectAnalysis, k, v)
@@ -204,7 +199,6 @@ func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) {

}
f.SetActiveSheet(index)
f.DeleteSheet("Sheet1")

ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
@@ -214,7 +208,7 @@ func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) {
}

func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string {
baseName := setting.RadarMap.Path + "/" + projectAnalysis + "_"
baseName := projectAnalysis + "_"

if ctx.QueryTrim("q") != "" {
baseName = baseName + ctx.QueryTrim("q") + "_"
@@ -225,21 +219,21 @@ func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, p
baseName = baseName + beginTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT)
}
frontName := baseName + ".xlsx"
return path.Base(frontName)
return frontName
}

func allProjectsPeroidHeader(ctx *context.Context) map[string]string {

return map[string]string{"A1": ctx.Tr("admin.repos.id"), "B1": ctx.Tr("admin.repos.projectName"), "C1": ctx.Tr("admin.repos.isPrivate"), "D1": ctx.Tr("admin.repos.openi"), "E1": ctx.Tr("admin.repos.visit"), "F1": ctx.Tr("admin.repos.download"), "G1": ctx.Tr("admin.repos.pr"), "H1": ctx.Tr("admin.repos.commit"),
"I1": ctx.Tr("admin.repos.watches"), "J1": ctx.Tr("admin.repos.stars"), "K1": ctx.Tr("admin.repos.forks"), "L1": ctx.Tr("admin.repos.issues"), "M1": ctx.Tr("admin.repos.closedIssues"), "N1": ctx.Tr("admin.repos.contributor")}
return map[string]string{"A1": ctx.Tr("admin.repos.id"), "B1": ctx.Tr("admin.repos.projectName"), "C1": ctx.Tr("repo.owner"), "D1": ctx.Tr("admin.repos.isPrivate"), "E1": ctx.Tr("admin.repos.openi"), "F1": ctx.Tr("admin.repos.visit"), "G1": ctx.Tr("admin.repos.download"), "H1": ctx.Tr("admin.repos.pr"), "I1": ctx.Tr("admin.repos.commit"),
"J1": ctx.Tr("admin.repos.watches"), "K1": ctx.Tr("admin.repos.stars"), "L1": ctx.Tr("admin.repos.forks"), "M1": ctx.Tr("admin.repos.issues"), "N1": ctx.Tr("admin.repos.closedIssues"), "O1": ctx.Tr("admin.repos.contributor")}

}

func allProjectsPeroidValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string {
return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): constructDistinctName(rs), getCellName("C", row): getIsPrivateDisplay(rs.IsPrivate, ctx), getCellName("D", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64),
getCellName("E", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("F", row): strconv.FormatInt(rs.NumDownloads, 10), getCellName("G", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("H", row): strconv.FormatInt(rs.NumCommits, 10),
getCellName("I", row): strconv.FormatInt(rs.NumWatches, 10), getCellName("J", row): strconv.FormatInt(rs.NumStars, 10), getCellName("K", row): strconv.FormatInt(rs.NumForks, 10), getCellName("L", row): strconv.FormatInt(rs.NumIssues, 10),
getCellName("M", row): strconv.FormatInt(rs.NumClosedIssues, 10), getCellName("N", row): strconv.FormatInt(rs.NumContributor, 10),
return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): rs.Name, getCellName("C", row): rs.OwnerName, getCellName("D", row): getIsPrivateDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64),
getCellName("F", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("G", row): strconv.FormatInt(rs.NumDownloads, 10), getCellName("H", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("I", row): strconv.FormatInt(rs.NumCommits, 10),
getCellName("J", row): strconv.FormatInt(rs.NumWatches, 10), getCellName("K", row): strconv.FormatInt(rs.NumStars, 10), getCellName("L", row): strconv.FormatInt(rs.NumForks, 10), getCellName("M", row): strconv.FormatInt(rs.NumIssues, 10),
getCellName("N", row): strconv.FormatInt(rs.NumClosedIssues, 10), getCellName("O", row): strconv.FormatInt(rs.NumContributor, 10),
}
}

@@ -247,13 +241,6 @@ func getCellName(col string, row int) string {
return col + strconv.Itoa(row)
}

func constructDistinctName(rs *models.RepoStatistic) string {
if rs.OwnerName == "" {
return rs.Name
}
return rs.OwnerName + "/" + rs.Name
}

func getIsPrivateDisplay(private bool, ctx *context.Context) string {
if private {
return ctx.Tr("admin.repos.yes")
@@ -327,6 +314,7 @@ func GetProjectLatestStatistics(ctx *context.Context) {
Mode: mode,
PR: pr,
RelAvatarLink: contributor.RelAvatarLink,
Email: contributor.Email,
}
users = append(users, userInfo)

@@ -508,12 +496,12 @@ func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time,

} else {

beginTime, err = time.Parse("2006-01-02", beginTimeStr)
beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
if err != nil {
return now, now, err
}

endTime, err = time.Parse("2006-01-02", endTimeStr)
endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
if err != nil {
return now, now, err
}
@@ -533,8 +521,7 @@ func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time,
}

func getRecordBeginTime() (time.Time, error) {

return time.Parse(DATE_FORMAT, setting.RadarMap.RecordBeginTime)
return time.ParseInLocation(DATE_FORMAT, setting.RadarMap.RecordBeginTime, time.Local)
}

func getTotalPage(total int64, pageSize int) int {


+ 5
- 3
routers/repo/attachment.go View File

@@ -360,6 +360,7 @@ func GetPresignedPutObjectURL(ctx *context.Context) {
// AddAttachment response for add attachment record
func AddAttachment(ctx *context.Context) {
typeCloudBrain := ctx.QueryInt("type")
fileName := ctx.Query("file_name")
err := checkTypeCloudBrain(typeCloudBrain)
if err != nil {
ctx.ServerError("checkTypeCloudBrain failed", err)
@@ -375,7 +376,7 @@ func AddAttachment(ctx *context.Context) {
return
}
} else {
has, err = storage.ObsHasObject(setting.BasePath + models.AttachmentRelativePath(uuid) + "/" + uuid)
has, err = storage.ObsHasObject(setting.BasePath + models.AttachmentRelativePath(uuid) + "/" + fileName)
if err != nil {
ctx.ServerError("ObsHasObject", err)
return
@@ -391,7 +392,7 @@ func AddAttachment(ctx *context.Context) {
UUID: uuid,
UploaderID: ctx.User.ID,
IsPrivate: true,
Name: ctx.Query("file_name"),
Name: fileName,
Size: ctx.QueryInt64("size"),
DatasetID: ctx.QueryInt64("dataset_id"),
Type: typeCloudBrain,
@@ -479,6 +480,7 @@ func UpdateAttachmentDecompressState(ctx *context.Context) {
func GetSuccessChunks(ctx *context.Context) {
fileMD5 := ctx.Query("md5")
typeCloudBrain := ctx.QueryInt("type")
fileName := ctx.Query("file_name")
var chunks string

err := checkTypeCloudBrain(typeCloudBrain)
@@ -510,7 +512,7 @@ func GetSuccessChunks(ctx *context.Context) {
return
}
} else {
isExist, err = storage.ObsHasObject(setting.BasePath + models.AttachmentRelativePath(fileChunk.UUID) + "/" + fileChunk.UUID)
isExist, err = storage.ObsHasObject(setting.BasePath + models.AttachmentRelativePath(fileChunk.UUID) + "/" + fileName)
if err != nil {
ctx.ServerError("ObsHasObject failed", err)
return


+ 2
- 0
routers/repo/modelarts.go View File

@@ -1006,6 +1006,8 @@ func TrainJobShow(ctx *context.Context) {
paramTemp = paramTemp + param
}
VersionListTasks[i].Parameters = paramTemp[:len(paramTemp)-2]
} else {
VersionListTasks[i].Parameters = ""
}
}



+ 17
- 7
routers/repo/repo_statistic.go View File

@@ -3,6 +3,8 @@ package repo
import (
"time"

"code.gitea.io/gitea/services/mailer"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/normalization"
@@ -26,14 +28,17 @@ func RepoStatisticDaily(date string) {
log.Info("%s", date)
log.Info("begin Repo Statistic")
t, _ := time.Parse("2006-01-02", date)
warnEmailMessage := "项目统计信息入库失败,请尽快定位。"
if err := models.DeleteRepoStatDaily(date); err != nil {
log.Error("DeleteRepoStatDaily failed: %v", err.Error())
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage)
return
}

repos, err := models.GetAllRepositories()
if err != nil {
log.Error("GetAllRepositories failed: %v", err.Error())
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage)
return
}

@@ -47,7 +52,7 @@ func RepoStatisticDaily(date string) {
var numDevMonths, numWikiViews, numContributor, numKeyContributor, numCommitsGrowth, numCommitLinesGrowth, numContributorsGrowth int64
repoGitStat, err := models.GetRepoKPIStats(repo)
if err != nil {
log.Error("GetRepoKPIStats failed: %s", repo.Name)
log.Error("GetRepoKPIStats failed: %s", getDistinctProjectName(repo))
} else {
numDevMonths = repoGitStat.DevelopAge
numKeyContributor = repoGitStat.KeyContributors
@@ -68,26 +73,26 @@ func RepoStatisticDaily(date string) {
var numVersions int64
numVersions, err = models.GetReleaseCountByRepoID(repo.ID, models.FindReleasesOptions{})
if err != nil {
log.Error("GetReleaseCountByRepoID failed(%s): %v", repo.Name, err)
log.Error("GetReleaseCountByRepoID failed(%s): %v", getDistinctProjectName(repo), err)
}

var datasetSize int64
datasetSize, err = getDatasetSize(repo)
if err != nil {
log.Error("getDatasetSize failed(%s): %v", repo.Name, err)
log.Error("getDatasetSize failed(%s): %v", getDistinctProjectName(repo), err)
}

var numComments int64
numComments, err = models.GetCommentCountByRepoID(repo.ID)
if err != nil {
log.Error("GetCommentCountByRepoID failed(%s): %v", repo.Name, err)
log.Error("GetCommentCountByRepoID failed(%s): %v", getDistinctProjectName(repo), err)
}

beginTime, endTime := getStatTime(date)
var numVisits int
numVisits, err = repository.AppointProjectView(repo.OwnerName, repo.Name, beginTime, endTime)
if err != nil {
log.Error("AppointProjectView failed(%s): %v", repo.Name, err)
log.Error("AppointProjectView failed(%s): %v", getDistinctProjectName(repo), err)
}

repoStat := models.RepoStatistic{
@@ -151,8 +156,9 @@ func RepoStatisticDaily(date string) {
}

if _, err = models.InsertRepoStat(&repoStat); err != nil {
log.Error("InsertRepoStat failed(%s): %v", repo.Name, err)
log.Error("failed statistic: %s", repo.Name)
log.Error("InsertRepoStat failed(%s): %v", getDistinctProjectName(repo), err)
log.Error("failed statistic: %s", getDistinctProjectName(repo))
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage)
continue
}

@@ -244,6 +250,10 @@ func RepoStatisticDaily(date string) {

}

func getDistinctProjectName(repo *models.Repository) string {
return repo.OwnerName + "/" + repo.Name
}

func getDatasetSize(repo *models.Repository) (int64, error) {
dataset, err := models.GetDatasetByRepo(repo)
if err != nil {


+ 46
- 10
routers/repo/user_data_analysis.go View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/mailer"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

@@ -39,12 +40,26 @@ func QueryUserStaticDataPage(ctx *context.Context) {
}
userName := ctx.Query("userName")
IsReturnFile := ctx.QueryBool("IsReturnFile")

log.Info("startDate=" + startDate + " endDate=" + endDate + " userName=" + userName + " page=" + fmt.Sprint(page))
startTime, _ := time.Parse("2006-01-02", startDate)
endTime, _ := time.Parse("2006-01-02", endDate)
endTime = endTime.AddDate(0, 0, 1)
log.Info("startTime=" + fmt.Sprint(startTime.Unix()) + " endDate=" + fmt.Sprint(endTime.Unix()))
var startTime time.Time
var endTime time.Time
var isAll bool
if startDate == "all" {
isAll = true
startTime = time.Now()
endTime = time.Now()
} else {
startTime, _ = time.Parse("2006-01-02", startDate)
settingStartTime, _ := time.Parse("2006-01-02", setting.RadarMap.RecordBeginTime)
if startTime.Unix() < settingStartTime.Unix() {
startTime = settingStartTime
startDate = settingStartTime.Format("2006-01-02")
}
endTime, _ = time.Parse("2006-01-02", endDate)
endTime = endTime.AddDate(0, 0, 1)
isAll = false
log.Info("startTime=" + fmt.Sprint(startTime.Unix()) + " endDate=" + fmt.Sprint(endTime.Unix()))
}

if IsReturnFile {
page = -1
@@ -59,6 +74,7 @@ func QueryUserStaticDataPage(ctx *context.Context) {
UserName: userName,
StartTime: startTime.Unix(),
EndTime: endTime.Unix(),
IsAll: isAll,
}
mapInterface := make(map[string]interface{})
re, count := models.QueryUserStaticDataPage(pageOpts)
@@ -67,8 +83,10 @@ func QueryUserStaticDataPage(ctx *context.Context) {
if IsReturnFile {
//writer exec file.
xlsx := excelize.NewFile()
xlsx.DeleteSheet("Sheet1")
sheetName := ctx.Tr("user.static.sheetname")
index := xlsx.NewSheet(sheetName)

dataHeader := map[string]string{
"A1": ctx.Tr("user.static.id"),
"B1": ctx.Tr("user.static.name"),
@@ -110,14 +128,27 @@ func QueryUserStaticDataPage(ctx *context.Context) {
xlsx.SetCellValue(sheetName, "L"+rows, userRecord.SolveIssueCount)
xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount)
xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount)
xlsx.SetCellValue(sheetName, "O"+rows, userRecord.OpenIIndex)
xlsx.SetCellValue(sheetName, "O"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex))
xlsx.SetCellValue(sheetName, "P"+rows, userRecord.RegistDate.Format("2006-01-02"))
xlsx.SetCellValue(sheetName, "Q"+rows, time.Unix(userRecord.CountDate, 0).Format("2006-01-02"))
}

//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + "_" + strings.ReplaceAll(startDate, "-", "") + "_" + strings.ReplaceAll(endDate, "-", "") + ".xlsx"
var filename string

nowTime := time.Now()
nowZeroTime := time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day(), 0, 0, 0, 0, nowTime.Location())
if endTime.Unix() >= nowZeroTime.Unix() {
endDate = nowZeroTime.AddDate(0, 0, -1).Format("2006-01-02")
}

if isAll {
filename = sheetName + "_" + ctx.Tr("user.static.all") + ".xlsx"
} else {
filename = sheetName + "_" + strings.ReplaceAll(startDate, "-", "") + "_" + strings.ReplaceAll(endDate, "-", "") + ".xlsx"
}

if len(userName) > 0 {
filename = sheetName + "_" + userName + "_" + strings.ReplaceAll(startDate, "-", "") + "_" + strings.ReplaceAll(endDate, "-", "") + ".xlsx"
}
@@ -142,10 +173,11 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) {
//query wiki data
log.Info("start to time count data")
wikiMap := make(map[string]int)
warnEmailMessage := "用户统计信息入库失败,请尽快定位。"
repoList, err := models.GetAllRepositories()
if err != nil {
log.Error("query repo error.")
log.Error("query repo error." + err.Error())
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage)
return
}
log.Info("start to query wiki data")
@@ -180,7 +212,11 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) {
}
}
//other user info data
models.CounDataByDateAndReCount(wikiMap, startTime, endTime, isReCount)
err = models.CounDataByDateAndReCount(wikiMap, startTime, endTime, isReCount)
if err != nil {
log.Error("count user info error." + err.Error())
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage)
}
}

func TimingCountDataByDate(date string) {


+ 4
- 7
routers/repo/view.go View File

@@ -824,24 +824,21 @@ func renderCode(ctx *context.Context) {
*/
baseGitRepo, err := git.OpenRepository(ctx.Repo.Repository.BaseRepo.RepoPath())
defer baseGitRepo.Close()
var compareInfo *git.CompareInfo
if err != nil {
log.Error("error open baseRepo:%s", ctx.Repo.Repository.BaseRepo.RepoPath())
ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error
} else {
if _, error := baseGitRepo.GetBranch(ctx.Repo.BranchName); error == nil {
//base repo has the same branch, then compare between current repo branch and base repo's branch
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.BranchName
ctx.SetParams("*", compareUrl)
compareInfo, err = baseGitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName, ctx.Repo.BranchName)
ctx.Data["UpstreamSameBranchName"] = true
} else {
//else, compare between current repo branch and base repo's default branch
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.Repository.BaseRepo.DefaultBranch
ctx.SetParams("*", compareUrl)
compareInfo, err = baseGitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName, ctx.Repo.Repository.BaseRepo.DefaultBranch)
ctx.Data["UpstreamSameBranchName"] = false
}
_, _, headGitRepo, compareInfo, _, _ := ParseCompareInfo(ctx)
defer headGitRepo.Close()
if compareInfo != nil {
if err==nil && compareInfo != nil {
if compareInfo.Commits != nil {
log.Info("compareInfoCommits数量:%d", compareInfo.Commits.Len())
ctx.Data["FetchUpstreamCnt"] = compareInfo.Commits.Len()


+ 16
- 0
services/mailer/mail.go View File

@@ -115,6 +115,22 @@ func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAdd
SendAsync(msg)
}

func SendWarnNotifyMail(emails []string, message string) {
if setting.MailService == nil {
log.Warn("SendWarnNotifyMail is being invoked but mail service hasn't been initialized")
return
}
if len(emails) == 0 {
log.Warn("SendWarnNotifyMail is being invoked but do not have email to send")
return
}
msg := NewMessage(emails, message, message)
msg.Info = fmt.Sprintf(message)

SendAsync(msg)

}

// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
func SendRegisterNotifyMail(locale Locale, u *models.User) {
if setting.MailService == nil {


+ 21
- 18
web_src/js/components/DataAnalysis.vue View File

@@ -7,10 +7,8 @@
</el-image>
概览
</span>
<div >概览.......</div>
<div >概览.......</div>
<div >概览.......</div><div >概览.......</div>
<div >概览.......</div>
<div >暂无内容.......</div>

</el-tab-pane>
<el-tab-pane label="项目分析" name="second" id="second" >
<ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis>
@@ -20,13 +18,13 @@
项目分析
</span>
</el-tab-pane>
<el-tab-pane name="third" >
<el-tab-pane name="third" id='third' >
<span slot='label'>
<el-image style="width: 13px; height: 13px" src="/img/name.png">
</el-image>
用户分析
</span>
<UserAnalysis ref='UserAnalysis' id ="usr"></UserAnalysis>
<UserAnalysis ref='UserAnalysis' v-if="isRouterAlive1" id ="usr"></UserAnalysis>
</el-tab-pane>
</el-tabs>
</div>
@@ -48,6 +46,7 @@
loading:true,
loading1:true,
isRouterAlive: true,
isRouterAlive1: true,
isSecond:true,
isThird:false,
@@ -57,30 +56,34 @@
handleClick(tab, event){
if(tab.name=="second"){
this.reload()
//document.getElementById('usr').style.display="none"
//document.getElementById("pro").style.display='block'
//this.$refs.ProAnalysis.getAllProList("all",7)

this.isSecond = true
this.isThird = false
this.$refs.ProAnalysis.getAllProList("all",7)
}
if(tab.name=="third"){
// document.getElementById('usr').style.display="block"
// document.getElementById("pro").style.display='none'
this.$refs.UserAnalysis.getUserList("all_usr",7)

this.reload1()
this.isSecond = false
this.isThird = true

this.$refs.UserAnalysis.getUpdateTime()
this.$refs.UserAnalysis.getUserList("all_usr",7)

}

},
},
reload () {
this.isRouterAlive = false
this.$nextTick(() => (this.isRouterAlive = true))
}
reload () {
this.isRouterAlive = false
this.$nextTick(() => (this.isRouterAlive = true))
},
reload1 () {
this.isRouterAlive1 = false
this.$nextTick(() => (this.isRouterAlive1 = true))
}

},
}


+ 1
- 0
web_src/js/components/ObsUploader.vue View File

@@ -262,6 +262,7 @@ export default {
params: {
md5: file.uniqueIdentifier,
type: CloudBrainType,
file_name: file.name,
_csrf: csrf
}
};


+ 184
- 66
web_src/js/components/ProAnalysis.vue View File

@@ -29,8 +29,13 @@
</span>
<span style="float:right; margin-right: 20px;">
<div style="display:inline-block;margin-left: 20px; ">
<i class="el-icon-download"></i>
<span ><a id = "download_file" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" >下载报告</a> </span>
<a class="el-icon-download" v-if="tableData!=''" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" ></a>
<i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i>
<!-- <span ><a id = "download_file" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" >下载报告</a> </span> -->
<span >
<a id = "download_file" v-if="tableData!=''" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'">下载报告</a>
<a id = "download_file" v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a>
</span>
</div>


@@ -53,16 +58,6 @@
stripe
>
</el-table-column>

<el-table-column
label="拥有者"
align="center"
prop="ownerName"
stripe
v-if='0'
>
</el-table-column>

<el-table-column
label="项目名称"
width="125px"
@@ -74,6 +69,13 @@
<a @click=goToDetailPage(scope.row.repo_id,scope.row.name,scope.row.ownerName)>{{scope.row.name}} </a>
</template>
</el-table-column>
<el-table-column
label="拥有者"
align="center"
prop="ownerName"
stripe
>
</el-table-column>
<el-table-column
prop="isPrivate"
label="私有"
@@ -145,10 +147,12 @@
<div style="margin-top:50px;text-align:center">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page"
:page-size="pageSize"
layout="prev, pager, next"
:page-sizes="[5,10,20]"
layout="total, sizes,prev, pager, next,jumper"
:total="totalNum">
</el-pagination>
</div>
@@ -156,7 +160,7 @@
</div>
<div id ="pro_detail" style="display:none;width: 100%;">
<div style="margin-top: 10px;">
<b class="pro_item">{{this.ownerName}}/{{this.pro_name}}</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{tableDataIDTotal.lastUpdatedTime}}/{{tableDataIDTotal.recordBeginTime}}</span>
<b class="pro_item">{{this.ownerName}}&nbsp/&nbsp{{this.pro_name}}</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{tableDataIDTotal.lastUpdatedTime}}&nbsp/&nbsp从{{tableDataIDTotal.recordBeginTime}}开始统计</span>
</div>
<div style="margin-top: 10px;">
项目描述:{{tableDataIDTotal.description | discriptionFun}}
@@ -185,7 +189,7 @@
</el-col>
<el-col :span='4' style="text-align: center;">
<el-row>任务完成比例</el-row>
<el-row class="item_content">{{tableDataIDTotal.issueClosedRatio * 100}}%</el-row>
<el-row class="item_content">{{Math.round(tableDataIDTotal.issueClosedRatio * 100) }}%</el-row>
</el-col>
</el-row>
</div>
@@ -248,18 +252,18 @@
</div>
<div style="margin-top: 20px;">
<span class="sta_iterm">统计周期:</span>
<button type="button" class='btn' id ="yesterday_pro" v-bind:class="{colorChange:1==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'yesterday',true,1),getOneProList(pro_id,'yesterday',false,1)">昨天</button>
<button type="button" class='btn' id = "current_week_pro" v-bind:class="{colorChange:2==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_week',true,2),getOneProList(pro_id,'current_week',false,2)">本周</button>
<button type="button" class='btn' id = "current_month_pro" v-bind:class="{colorChange:3==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_month',true,3),getOneProList(pro_id,'current_month',false,3)">本月</button>
<button type="button" class='btn' id = "last_month_pro" v-bind:class="{colorChange:4==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'last_month',true,4),getOneProList(pro_id,'last_month',false,4)">上月</button>
<button type="button" class='btn' id = "monthly_pro" v-bind:class="{colorChange:5==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'monthly',true,5),getOneProList(pro_id,'monthly',false,5)">近30天</button>
<button type="button" class='btn' id = "current_year_pro" v-bind:class="{colorChange:6==dynamic}" @click="resetCurrentPage(),getOneProList(pro_id,'current_year',true,6),getOneProList(pro_id,'current_year',false,6)">今年</button>
<button type="button" class='btn' id = "all_pro" v-bind:class="{colorChange:7==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'all',true,7),getOneProList(pro_id,'all',false,7)">所有</button>
<button type="button" class='btn' id ="yesterday_pro" v-bind:class="{colorChange:1==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'yesterday',false,1)">昨天</button>
<button type="button" class='btn' id = "current_week_pro" v-bind:class="{colorChange:2==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_week',false,2)">本周</button>
<button type="button" class='btn' id = "current_month_pro" v-bind:class="{colorChange:3==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_month',false,3)">本月</button>
<button type="button" class='btn' id = "last_month_pro" v-bind:class="{colorChange:4==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'last_month',false,4)">上月</button>
<button type="button" class='btn' id = "monthly_pro" v-bind:class="{colorChange:5==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'monthly',false,5)">近30天</button>
<button type="button" class='btn' id = "current_year_pro" v-bind:class="{colorChange:6==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'current_year',false,6)">今年</button>
<button type="button" class='btn' id = "all_pro" v-bind:class="{colorChange:7==dynamic_pro}" @click="resetCurrentPage(),getOneProList(pro_id,'all',false,7)">所有</button>
<span style="margin-left: 20px;">
<el-date-picker
v-model="create_time_pro"
prefix-icon="el-icon-time"
@change="resetCurrentPage(),getOneProList(pro_id,'',true,0),getOneProList(pro_id,'',false,0),clickCheckBox"
@change="resetCurrentPage(),getOneProList(pro_id,'',false,0),clickCheckBox"
type="daterange"
size='small'
range-separator="至"
@@ -269,8 +273,12 @@
</span>
<span style="float:right; margin-right: 20px;">
<div style="display:inline-block;margin-left: 20px;">
<i class="el-icon-download"></i>
<span ><a @click="exportData()">下载报告</a> </span>
<a v-if="tableDataID!=''" @click="exportData()" class="el-icon-download"></a>
<a v-else="tableDataID=''" @click="exportData()" style="color:rgba(187, 187, 187, 100);" class="el-icon-download"></a>
<span >
<a v-if="tableDataID!=''" @click="exportData()">下载报告</a>
<a v-else="tableDataID=''" @click="exportData()" style="color:rgba(187, 187, 187, 100);">下载报告</a>
</span>
</div>
</span>
</div>
@@ -289,7 +297,7 @@
</div>
<div style="margin-top: 30px;">
<el-table
:data="tableDataID.slice((currentPage-1)*pageSize,currentPage*pageSize)"
:data="tableDataID.slice((currentPage-1)*pageSize1,currentPage*pageSize1)"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style='cellStyle'>
@@ -321,10 +329,12 @@
<div style="margin-top:50px;text-align:center">
<el-pagination
background
@size-change="handleSizeChangeID"
@current-change="handleCurrentChangeID"
:current-page="currentPage"
:page-size="pageSize1"
layout="prev, pager, next"
:page-sizes="[5,10,20]"
layout="total, sizes,prev, pager, next,jumper"
:total="tableDataID.length">
</el-pagination>
</div>
@@ -360,6 +370,7 @@
search:'',
dynamic:7,
download_a:"",
downLoadSrc:'',

//单个项目参数
@@ -388,14 +399,22 @@
// download_file(){
// this.params.type='all'
// },
popMark(){
alert("数据为空时,不能下载!")
},
exportData(){
// this.getOneProList(this.pro_id,'all',true,7)
// this.getOneProList(this.pro_id,'all',false,7)
// this.fileName()
this.currentPage=1
var saveFileName = this.getFileName()
export2Excel(this.columns,this.tableDataID,saveFileName)
if (this.tableDataID!=''){
this.currentPage=1
var saveFileName = this.getFileName()
export2Excel(this.columns,this.tableDataID,saveFileName)
}else{
alert("数据为空时,不能下载!")
}
},
getFileName(){

@@ -405,27 +424,32 @@
var nowMonth = now.getMonth(); // 当前月
var nowYear = now.getFullYear(); // 当前年
var today = this.saveFormatDate(nowYear,nowMonth+1,nowDay);
var tmp = new Date(now.setTime(now.getTime()-24*60*60*1000));
var yesterday = this.saveFormatDate(tmp.getFullYear(),tmp.getMonth()+1,tmp.getDate());
var yesterday_tmp = this.formatDate(tmp.getFullYear(),tmp.getMonth()+1,tmp.getDate())

let lastMonthDate = new Date(); // 上月日期
lastMonthDate.setDate(1);
lastMonthDate.setMonth(lastMonthDate.getMonth()-1);
let lastYear = lastMonthDate.getYear();
let lastMonth = lastMonthDate.getMonth();
var startDate=''
var endDate=''
var saveFileName = ''
if (typeof this.paramsID.type=="undefined" || this.paramsID.type=="null" || this.paramsID.type==""){
startDate= this.saveFormatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate());
// startDate= this.saveFormatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate());
endDate = this.saveFormatDate(this.create_time_pro[1].getFullYear(),this.create_time_pro[1].getMonth() + 1,this.create_time_pro[1].getDate());
var tmp = this.formatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate())
startDate = this.comparedate(tmp,this.recordBeginTime)

console.log("comparedate:"+startDate)
saveFileName = this.pro_name+"_"+startDate+'_'+endDate
}else{
switch(this.paramsID.type){
case "yesterday":{
var now = new Date();
var tmp = new Date(now.setTime(now.getTime()-24*60*60*1000));
startDate = this.saveFormatDate(tmp.getFullYear(),tmp.getMonth()+1,tmp.getDate());
endDate = today
startDate = this.comparedate(yesterday_tmp,this.recordBeginTime)
endDate = startDate
saveFileName = this.pro_name+"_"+startDate+'_'+ endDate
break
}
@@ -433,43 +457,66 @@
var now = new Date(); // 当前日期
var nowDayOfWeek = now.getDay(); // 今天本周的第几天
var day = nowDayOfWeek || 7;
startDate = this.saveFormatDate(now.getFullYear(), nowMonth+1, nowDay + 1 - day);
endDate = today
startDate = this.formatDate(now.getFullYear(), nowMonth+1, nowDay + 1 - day);
startDate = this.comparedate(startDate,this.recordBeginTime)

endDate = yesterday
saveFileName = this.pro_name+"_"+startDate+'_'+ endDate
break
}
case "current_month":{
startDate = this.saveFormatDate(nowYear,nowMonth+1,1);
endDate = today
startDate = this.formatDate(nowYear,nowMonth+1,1);
startDate = this.comparedate(startDate,this.recordBeginTime)

endDate = yesterday
saveFileName = this.pro_name+"_"+startDate+'_'+ endDate
break
}
case "last_month":{
startDate=this.saveFormatDate(nowYear, lastMonth+1, 1);
endDate=this.saveFormatDate(nowYear, lastMonth+1, this.saveFormatDate(nowYear,lastMonth));
endDate = today

let lastMonthDate = new Date(); // 上月日期
lastMonthDate.setDate(1);
lastMonthDate.setMonth(lastMonthDate.getMonth()-1);
let lastYear = lastMonthDate.getFullYear();
let lastMonth = lastMonthDate.getMonth();

startDate=this.formatDate(lastYear, lastMonth+1, 1);
startDate = this.comparedate(startDate,this.recordBeginTime)


var monthStartDate = new Date(lastYear, lastMonth, 1);
var monthEndDate = new Date(lastYear, lastMonth+1, 1);
var days = (monthEndDate - monthStartDate) / (1000 * 60 * 60 * 24)

endDate=this.saveFormatDate(lastYear, lastMonth+1, days); //月份从0开始,所以+1保存月份
saveFileName = this.pro_name+"_"+startDate+'_'+ endDate
break

}
case "monthly":{
var temp=new Date(now - 1000 * 60 * 60 * 24 * 30)
startDate = this.saveFormatDate(temp.getFullYear(),temp.getMonth()+1,temp.getDate());
endDate = today
startDate = this.formatDate(temp.getFullYear(),temp.getMonth()+1,temp.getDate());
startDate = this.comparedate(startDate,this.recordBeginTime)

endDate = yesterday
saveFileName = this.pro_name+"_"+startDate+'_'+ endDate
break
}
case "current_year":{
startDate = this.saveFormatDate(now.getFullYear(), 1, 1);
endDate = today
startDate = this.formatDate(now.getFullYear(), 1, 1);
startDate = this.comparedate(startDate,this.recordBeginTime)

endDate = yesterday
saveFileName = this.pro_name+"_"+startDate+'_'+ endDate
break
}
case "all":{
console.log("e:"+today)
startDate = 'all'
endDate = today
saveFileName = this.pro_name+'_all'
endDate = yesterday
saveFileName = this.pro_name+'_所有'
break
}
}
@@ -484,6 +531,11 @@
resetCurrentPage(){
this.currentPage=1
},
handleSizeChange(val){
this.params.pagesize = val
this.resetPage()
this.getAllProList(this.params.type, this.dynamic)
},
handleCurrentChange(val){
console.log(val)
this.params.page = val
@@ -559,6 +611,9 @@
}
return (myyear +'-'+ mymonth +'-'+ myweekday);
},
//获得某月的天数
getAllProList(type_val,index){
console.log("类型:"+type_val)
@@ -604,7 +659,7 @@
this.pro_id=pro_id;
this.ownerName=ownerName
this.getOneProData(pro_id);
this.getOneProList(pro_id,"monthly",true,5);
this.getOneProList(pro_id,"current_year",true,0);
this.getOneProList(pro_id,"monthly",false,5);
},
tableHeaderStyle({row,column,rowIndex,columnIndex}){
@@ -619,10 +674,14 @@
return 'background:#f5f5f6;color:#606266'
}
},
handleSizeChangeID(val){
this.pageSize1=val
},

handleCurrentChangeID(currentPage){
this.currentPage = currentPage;
},
getOneProData(pro_id){
this.$axios.get('../api/v1/projectboard/project/'+pro_id,{
}).then((res)=>{
@@ -665,7 +724,7 @@
},
drawRadarOpenI(){
var ydata = [this.roundingF(this.tableDataIDTotal.impact),this.roundingF(this.tableDataIDTotal.completeness),this.roundingF(this.tableDataIDTotal.liveness),this.tableDataIDTotal.projectHealth,this.roundingF(this.tableDataIDTotal.teamHealth),this.roundingF(this.tableDataIDTotal.growth)]
var ydata = [this.roundingF(this.tableDataIDTotal.impact),this.roundingF(this.tableDataIDTotal.completeness),this.roundingF(this.tableDataIDTotal.liveness),this.roundingF(this.tableDataIDTotal.projectHealth),this.roundingF(this.tableDataIDTotal.teamHealth),this.roundingF(this.tableDataIDTotal.growth)]
console.log("ydata:",ydata)
var i = -1;
var option = {
@@ -681,7 +740,39 @@
textStyle:{
color:'black'
},
position: 'right'
position: 'right',



// formatter: function (params) {
// console.log('params:',params)
// console.log('params.data:',params[0])
// let str = params.data.name + "<br />";
// params.data.forEach((item) => {
// str +=
// '<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:'+params.color+'"></span>' + item.seriesName + " : " + '<span style="float:right">'+item.data[1] +'</span>'+ "<br />";
// });
// return str;
// },
// formatter: function (params, ticket, callback) {
// console.log(params);
// var showHtm="";
// var data = params.data.value
// for(var i=0;i<data.length;i++){
// //x轴名称
// var name = data[i];
// //值
// var value = params[i][2];
// showHtm+= text+ '--' + name + ' :' + value+'<br>'
// }
// return showHtm;
// }






},//提示层
legend: {
@@ -775,7 +866,7 @@
backgroundColor:'rgba(255,255,255,0.8)',
color:'black',
borderWidth:'1',
borderColor:'gray',
borderColor:'#DCE7FB',
textStyle:{
color:'black'
},
@@ -840,9 +931,9 @@
// if ()
for(var i =0;i<this.tableDataID.length;i++){
xdata.push(this.tableDataID[this.tableDataID.length-1-i].date);
ydata_view.push(this.roundingF(this.tableDataID[this.tableDataID.length-1-i].view))
ydata_download.push(this.roundingF(this.tableDataID[this.tableDataID.length-1-i].download))
ydata_commit.push(this.roundingF(this.tableDataID[this.tableDataID.length-1-i].commit))
ydata_view.push(this.tableDataID[this.tableDataID.length-1-i].view)
ydata_download.push(this.tableDataID[this.tableDataID.length-1-i].download)
ydata_commit.push(this.tableDataID[this.tableDataID.length-1-i].commit)
}
console.log("ydata_openI:"+ydata_download)
console.log(xdata)
@@ -961,14 +1052,29 @@
this.echartsSelectData.setOption(this.option);
// });

}
},
comparedate(date1,date2){
console.log("date1:"+date1)
console.log("date1:"+date2)
var oDate1 = new Date(date1);
var oDate2 = new Date(date2);
if(oDate1.getTime() < oDate2.getTime()){
var data = date2.split('-')
return data[0]+''+data[1]+''+data[2]
} else {
var data = date1.split('-')
return data[0]+''+data[1]+''+data[2]
}
},

},
filters:{

rounding (value) {
return Number(value).toFixed(2)
},
changeType(value){
if(value=='false'){
if(value==false){
return "否"
}else{
return "是"
@@ -1074,9 +1180,21 @@
.btn:active{
background-color:#409effd6 ;
} */
/deep/ .el-date-picker {
width: 200px;
/* /deep/ .el-date-picker {
width: 250px;
} */
/deep/ .el-table tbody tr:hover>td {
background-color:#D3D3D3!important;
opacity:1
}
/deep/ .el-table {
font-size: 12px;
}
/deep/ .el-range-separator{
width: 20% !important;
}

.colorChange {
background-color: #409effd6;
color: #FFFF;


+ 119
- 62
web_src/js/components/UserAnalysis.vue View File

@@ -5,18 +5,18 @@
</div>
<div style="margin-top: 20px;">
<span class="sta_iterm">统计周期:</span>
<button type="button" class='btn' id ="yesterday_usr" v-bind:class="{colorChange:1==dynamic}" @click="getUserList('yesterday_usr',1)">昨天</button>
<button type="button" class='btn' id = "current_week_usr" v-bind:class="{colorChange:2==dynamic}" @click="getUserList('current_week_usr',2)">本周</button>
<button type="button" class='btn' id = "current_month_usr" v-bind:class="{colorChange:3==dynamic}" @click="getUserList('current_month_usr',3)">本月</button>
<button type="button" class='btn' id = "last_month_usr" v-bind:class="{colorChange:4==dynamic}" @click="getUserList('last_month_usr',4)">上月</button>
<button type="button" class='btn' id = "monthly_usr" v-bind:class="{colorChange:5==dynamic}" @click="getUserList('monthly_usr',5)">近30天</button>
<button type="button" class='btn' id = "current_year_usr" v-bind:class="{colorChange:6==dynamic}" @click="getUserList('current_year_usr',6)">今年</button>
<button type="button" class='btn' id = "all_usr" v-bind:class="{colorChange:7==dynamic}" @click="getUserList('all_usr',7)">所有</button>
<button type="button" class='btn' id ="yesterday_usr" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getUserList('yesterday_usr',1)">昨天</button>
<button type="button" class='btn' id = "current_week_usr" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getUserList('current_week_usr',2)">本周</button>
<button type="button" class='btn' id = "current_month_usr" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getUserList('current_month_usr',3)">本月</button>
<button type="button" class='btn' id = "last_month_usr" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getUserList('last_month_usr',4)">上月</button>
<button type="button" class='btn' id = "monthly_usr" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getUserList('monthly_usr',5)">近30天</button>
<button type="button" class='btn' id = "current_year_usr" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getUserList('current_year_usr',6)">今年</button>
<button type="button" class='btn' id = "all_usr" v-bind:class="{colorChange:7==dynamic}" @click="resetPage(),getUserList('all_usr',7)">所有</button>
<span style="margin-left: 20px;">
<el-date-picker
v-model="value_time"
prefix-icon="el-icon-time"
@change="getUserList('',0)"
@change="resetPage(),getUserList('',0)"
type="daterange"
size='small'
unlink-panels
@@ -27,18 +27,22 @@
</span>
<span style="float:right; margin-right: 20px;" >
<a style="display:inline-block;margin-left: 20px; " id = 'download'>
<i class="el-icon-download"></i>
<span ><a @click="exportData()">下载报告</a> </span>
<a class="el-icon-download" v-if="tableData!=''" :href= "'../tool/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" ></a>
<i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i>
<span >
<a v-if="tableData!=''" :href= "'../tool/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" >下载报告</a>
<a v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a>
</span>
</a>
<span style="display:inline-block;margin-left: 20px; ">
<el-input size="small" placeholder="输入用户名搜索" v-model="search" class="input-with-select" @keyup.enter.native="searchName() "><i slot="suffix" class="el-input__icon el-icon-search"></i>
<el-input size="small" placeholder="输入用户名搜索" v-model="search" class="input-with-select" @keyup.enter.native="searchName() "><i slot="suffix" class="el-input__icon el-icon-search" @click="searchName() "></i>
</el-input>
</span>
</span>
</div>
<div style="margin-top: 30px;">
<el-table
:data="tableData.slice((currentPage-1)*pageSize,currentPage*pageSize)"
:data="tableData"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style='cellStyle'>
@@ -123,29 +127,31 @@
label="用户注册时间"
width="120px"
align="center">
<!-- <template slot-scope="scope">
<template slot-scope="scope">
{{scope.row.RegistDate | transformTimestamp}}
</template> -->
</template>
</el-table-column>
<el-table-column
prop="CountDate"
label="系统统计时间"
width="120px"
align="center">
<!-- <template slot-scope="scope">
<template slot-scope="scope">
{{scope.row.CountDate | transformTimestamp}}
</template> -->
</template>
</el-table-column>
</el-table>
</div>
<div style="margin-top:50px;text-align:center">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:current-page="page"
:page-size="pageSize"
layout="prev, pager, next"
:total="tableData.length">
:page-sizes="[2,5,10,20]"
layout="total, sizes, prev, pager, next,jumper"
:total="totalNum">
</el-pagination>
</div>
@@ -161,17 +167,17 @@
type_val:'',
recordBeginTime:'',
lastUpdatedTime:'',
currentPage:1,
page:1,
pageSize:10,
params:{startDate:'',endDate:''},
params:{startDate:'',endDate:'',page:1,pageSize:10,userName:''},
tableData: [],
totalNum:0,
pickerOptions: {
},
value_time: '',
search:'',
data:'',
columns: [{title: 'ID',key: 'ID'},{title: '用户名',key: 'Name'},{title: 'PR数',key: 'CodeMergeCount'},{title: 'cimmit数',key:'CommitCount'},{title: '提出任务数',key: 'IssueCount'},{title: '评论数',key: 'CommentCount'},{title: '关注项目数',key: 'FocusRepoCount'},{title: '点赞项目数',key: 'StarRepoCount'},{title: '登录次数',key: 'LoginCount'},{title:'关注者数',key:'WatchedCount'},{title:'commit代码行数',key:'CommitCodeSize'},{title:'已解决任务数',key:'SolveIssueCount'},{title:'百科页面贡献次数',key:'EncyclopediasCount'},{title:'创建项目',key:'CreateRepoCount'},{title:'用户注册时间',key:'RegistDate'},{title:'系统统计时间',key:'CountDate'}],
columns: [{title: 'ID',key: 'ID'},{title: '用户名',key: 'Name'},{title: 'PR数',key: 'CodeMergeCount'},{title: 'commit数',key:'CommitCount'},{title: '提出任务数',key: 'IssueCount'},{title: '评论数',key: 'CommentCount'},{title: '关注项目数',key: 'FocusRepoCount'},{title: '点赞项目数',key: 'StarRepoCount'},{title: '登录次数',key: 'LoginCount'},{title:'关注者数',key:'WatchedCount'},{title:'commit代码行数',key:'CommitCodeSize'},{title:'已解决任务数',key:'SolveIssueCount'},{title:'百科页面贡献次数',key:'EncyclopediasCount'},{title:'创建项目',key:'CreateRepoCount'},{title:'用户注册时间',key:'RegistDate'},{title:'系统统计时间',key:'CountDate'}],
blob:'',
fileName:'',
dynamic:7,
@@ -181,6 +187,9 @@
},
methods: {

popMark(){
alert("数据为空时,不能下载!")
},
exportData(){
// this.getUserList('all_usr',7)
var saveFileName = this.getFileName()
@@ -200,9 +209,22 @@
return saveFileName

},
handleCurrentChange(currentPage){
this.currentPage = currentPage;
handleCurrentChange(val){
this.params.page = val
this.page = val
this.getUserList(this.type_val,this.dynamic)

},
handleSizeChange(val){
this.params.pageSize = val
this.resetPage()
this.getUserList(this.type_val,this.dynamic)
},
resetPage(){
this.page=1
this.params.page = 1
},

formatDate(myyear,mymonth,myweekday) {
// var myyear = this.date.getFullYear();
// var mymonth = this.date.getMonth() + 1;
@@ -224,7 +246,14 @@
let days = (monthEndDate - monthStartDate)/(1000 * 60 * 60 * 24);
return days;
},

getUpdateTime(){
this.$axios.get('../api/v1/projectboard/project',{
params:this.params_pro
}).then((res)=>{
this.recordBeginTime=res.data.recordBeginTime
this.lastUpdatedTime=res.data.lastUpdatedTime
})
},
getUserList(type_val,index){
this.type_val = type_val
this.dynamic = index;
@@ -295,50 +324,63 @@
}
case "all_usr":{
console.log("e:"+today)
this.params.startDate = this.recordBeginTime//this.formatDate(2000, 1, 1); //
this.params.startDate = 'all'//this.formatDate(2000, 1, 1); //this.recordBeginTime//
this.params.endDate = today
this.value_time=[]
break
}
}
};
this.$axios.get('../tool/query_user_static',{
this.$axios.get('../tool/query_user_static_page',{
params:this.params
}).then((res)=>{
this.currentPage = 1
this.tableData = res.data
console.log(" this.tableData:", this.tableData.length)
for(var i=0;i<this.tableData.length;i++){
this.tableData[i].RegistDate = this.transformTimestamp(this.tableData[i].RegistDate)
this.tableData[i].CountDate = this.transformTimestamp(this.tableData[i].CountDate)
console.log(" this.tableData:", this.tableData[i].RegistDate)
}
})
this.$axios.get('../api/v1/projectboard/project',{
params:this.params_pro
}).then((res)=>{
this.recordBeginTime=res.data.recordBeginTime
this.lastUpdatedTime=res.data.lastUpdatedTime
this.tableData = res.data.data
// console.log("res.data:"+res.data.data)
this.totalNum = res.data.count
console.log("res.count:"+res.data.count)
})

// this.$axios.get('../tool/query_user_static',{
// params:this.params
// }).then((res)=>{
// this.currentPage = 1
// this.tableData = res.data
// console.log(" this.tableData:", this.tableData.length)
// for(var i=0;i<this.tableData.length;i++){
// this.tableData[i].RegistDate = this.transformTimestamp(this.tableData[i].RegistDate)
// this.tableData[i].CountDate = this.transformTimestamp(this.tableData[i].CountDate)
// console.log(" this.tableData:", this.tableData[i].RegistDate)
// }
// })




},
searchName(){
// this.params.q = this.search
// this.params.page = 1
// this.getUserList("all_usr")
var search = this.search;
this.getUserList("all_usr",7)
this.tableData = this.tableData.filter(data => !search || data.Name.toLowerCase().includes(search.toLowerCase()))
// var search = this.search;
// this.getUserList("all_usr",7)
// this.tableData = this.tableData.filter(data => !search || data.Name.toLowerCase().includes(search.toLowerCase()))

},
goToDetailPage(pro_id,pro_name){
sessionStorage.setItem("pro_id",pro_id);
sessionStorage.setItem("pro_name",pro_name);
document.getElementById("pro_main").style.display="none";
document.getElementById("pro_detail").style.display="block";
this.params.userName = this.search
this.params.page = 1
this.page=1
this.getUserList(this.type_val, this.dynamic)

},
// goToDetailPage(pro_id,pro_name){
// sessionStorage.setItem("pro_id",pro_id);
// sessionStorage.setItem("pro_name",pro_name);
// document.getElementById("pro_main").style.display="none";
// document.getElementById("pro_detail").style.display="block";

// },
tableHeaderStyle({row,column,rowIndex,columnIndex}){
if(rowIndex===0){
@@ -351,6 +393,11 @@
return 'background:#f5f5f6;color:#606266'
}
},

},
filters:{

transformTimestamp(timestamp){
console.log("timestamp",timestamp)
let a = new Date(timestamp*1000);
@@ -365,9 +412,6 @@
console.log('dateString', dateString); // > dateString 2021-07-06 14:23
return dateString;
},
},
filters:{

// transformTimestamp(timestamp){
// var dateString= new Date(timestamp);
@@ -377,8 +421,8 @@
},
mounted() {
document.getElementById("all_usr").style.outline="none"
document.getElementById("all_usr").focus()
// document.getElementById("all_usr").style.outline="none"
// document.getElementById("all_usr").focus()
this.getUserList("all_usr",7)
},
created() {
@@ -386,9 +430,15 @@
},
watch:{
search(val){
// if(!val){
// this.getUserList("all_usr",7)
// }
if(!val){
this.getUserList("all_usr",7)
}
this.params.userName = this.search
this.params.page = 1
this.page=1
this.getUserList(this.type_val, this.dynamic)
}
}
},
}
@@ -426,12 +476,19 @@
.btn:active{
background-color:#409effd6 ;
} */
/deep/ .el-date-picker {
width: 200px;
}
/* /deep/ .el-date-picker {
width: 220px;
} */
/deep/ .el-table {
font-size: 12px;
}
/deep/ .el-table tbody tr:hover>td {
background-color:#D3D3D3!important;
opacity:1
}
/deep/ .el-range-separator{
width: 20% !important;
}

.colorChange {
background-color: #409effd6;


Loading…
Cancel
Save