#2093 fix-1936 fix-1937

Merged
zouap merged 66 commits from fix-1936 into V20220519 1 year ago
  1. +7
    -3
      models/dbsql/repo_foreigntable_for_es.sql
  2. +5
    -0
      models/repo.go
  3. +48
    -0
      models/summary_statistic.go
  4. +151
    -4
      models/user_business_analysis.go
  5. +15
    -6
      models/user_business_struct.go
  6. +24
    -0
      options/locale/locale_en-US.ini
  7. +25
    -0
      options/locale/locale_zh-CN.ini
  8. +12
    -1
      routers/api/v1/api.go
  9. +317
    -0
      routers/api/v1/repo/repo_dashbord.go
  10. +25
    -0
      routers/home.go
  11. +7
    -0
      routers/repo/repo_summary_statistic.go
  12. +175
    -16
      routers/repo/user_data_analysis.go
  13. +7
    -0
      routers/routes/routes.go
  14. +9
    -3
      templates/explore/data_analysis.tmpl
  15. +76
    -105
      web_src/js/components/DataAnalysis.vue
  16. +5
    -0
      web_src/js/components/Overview.vue
  17. +55
    -12
      web_src/js/components/ProAnalysis.vue
  18. +903
    -0
      web_src/js/components/ProTrend.vue
  19. +16
    -13
      web_src/js/components/UserAnalysis.vue
  20. +942
    -0
      web_src/js/components/UserTrend.vue
  21. +2
    -1
      web_src/js/index.js
  22. +64
    -0
      web_src/js/router/index.js

+ 7
- 3
models/dbsql/repo_foreigntable_for_es.sql View File

@@ -523,17 +523,21 @@ DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat;

CREATE OR REPLACE FUNCTION public.udpate_repository_lang() RETURNS trigger AS
$def$
DECLARE
privateValue bigint;
BEGIN
if (TG_OP = 'UPDATE') then
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id;
select into privateValue updated_unix from public.repository where id=NEW.repo_id;
update public.repository_es SET updated_unix=privateValue,lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id;
elsif (TG_OP = 'INSERT') then
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id;
select into privateValue updated_unix from public.repository where id=NEW.repo_id;
update public.repository_es SET updated_unix=privateValue,lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id;
elsif (TG_OP = 'DELETE') then
if exists(select 1 from public.repository where id=OLD.repo_id) then
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=OLD.repo_id) where id=OLD.repo_id;
end if;
end if;
return null;
return NEW;
END;
$def$
LANGUAGE plpgsql;


+ 5
- 0
models/repo.go View File

@@ -1554,6 +1554,11 @@ func GetAllMirrorRepositoriesCount() (int64, error) {
return x.Where("is_mirror = ?", true).Count(repo)
}

func GetAllOrgRepositoriesCount() (int64, error) {
repo := new(Repository)
return x.Table("repository").Join("INNER", []string{"\"user\"", "u"}, "repository.owner_id = u.id and u.type=1").Count(repo)
}

func GetAllForkRepositoriesCount() (int64, error) {
repo := new(Repository)
return x.Where("is_fork = ?", true).Count(repo)


+ 48
- 0
models/summary_statistic.go View File

@@ -2,6 +2,8 @@ package models

import (
"fmt"
"strconv"
"time"

"code.gitea.io/gitea/modules/timeutil"
)
@@ -45,6 +47,7 @@ type SummaryStatistic struct {
NumRepoFork int64 `xorm:"NOT NULL DEFAULT 0"`
NumRepoMirror int64 `xorm:"NOT NULL DEFAULT 0"`
NumRepoSelf int64 `xorm:"NOT NULL DEFAULT 0"`
NumRepoOrg int64 `xorm:"NOT NULL DEFAULT 0"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
@@ -69,6 +72,51 @@ func DeleteSummaryStatisticDaily(date string) error {
return nil
}

func GetLatest2SummaryStatistic() ([]*SummaryStatistic, error) {
summaryStatistics := make([]*SummaryStatistic, 0)
err := xStatistic.Desc("created_unix").Limit(2).Find(&summaryStatistics)
return summaryStatistics, err
}

func GetSummaryStatisticByTimeCount(beginTime time.Time, endTime time.Time) (int64, error) {
summaryStatistics := new(SummaryStatistic)
total, err := xStatistic.Asc("created_unix").Where("created_unix>=" + strconv.FormatInt(beginTime.Unix(), 10) + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)).Count(summaryStatistics)
return total, err
}

func GetSummaryStatisticByDateCount(dates []string) (int64, error) {
summaryStatistics := new(SummaryStatistic)
total, err := xStatistic.Asc("created_unix").In("date", dates).Count(summaryStatistics)
return total, err
}


func GetAllSummaryStatisticByTime(beginTime time.Time, endTime time.Time) ([]*SummaryStatistic, error) {
summaryStatistics := make([]*SummaryStatistic, 0)
err := xStatistic.Asc("created_unix").Where("created_unix>=" + strconv.FormatInt(beginTime.Unix(), 10) + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)).Find(&summaryStatistics)

return summaryStatistics, err
}

func GetSummaryStatisticByTime(beginTime time.Time, endTime time.Time, page int, pageSize int) ([]*SummaryStatistic, error) {
summaryStatistics := make([]*SummaryStatistic, 0)
err := xStatistic.Asc("created_unix").Limit(pageSize+1, (page-1)*pageSize).Where("created_unix>=" + strconv.FormatInt(beginTime.Unix(), 10) + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)).Find(&summaryStatistics)

return summaryStatistics, err
}

func GetAllSummaryStatisticByDates(dates []string) ([]*SummaryStatistic, error) {
summaryStatistics := make([]*SummaryStatistic, 0)
err := xStatistic.Asc("created_unix").In("date", dates).Find(&summaryStatistics)
return summaryStatistics, err
}

func GetSummaryStatisticByDates(dates []string, page int, pageSize int) ([]*SummaryStatistic, error) {
summaryStatistics := make([]*SummaryStatistic, 0)
err := xStatistic.Asc("created_unix").In("date", dates).Limit(pageSize+1, (page-1)*pageSize).Find(&summaryStatistics)
return summaryStatistics, err
}

func InsertSummaryStatistic(summaryStatistic *SummaryStatistic) (int64, error) {
return xStatistic.Insert(summaryStatistic)
}

+ 151
- 4
models/user_business_analysis.go View File

@@ -4,6 +4,7 @@ import (
"fmt"
"sort"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/log"
@@ -227,7 +228,27 @@ func getLastCountDate() int64 {
return pageStartTime.Unix()
}

func QueryMetrics(start int64, end int64) ([]*UserMetrics, int64) {
func QueryMetricsPage(start int64, end int64, page int, pageSize int) ([]*UserMetrics, int64) {

statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
cond := "count_date >" + fmt.Sprint(start) + " and count_date<" + fmt.Sprint(end)
allCount, err := statictisSess.Where(cond).Count(new(UserMetrics))
if err != nil {
log.Info("query error." + err.Error())
return nil, 0
}
userMetricsList := make([]*UserMetrics, 0)
//.Limit(pageSize, page*pageSize)
if err := statictisSess.Table(new(UserMetrics)).Where(cond).OrderBy("count_date desc").
Find(&userMetricsList); err != nil {
return nil, 0
}
postDeal(userMetricsList)
return userMetricsList, allCount
}

func QueryMetrics(start int64, end int64) ([]*UserMetrics, int) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
userMetricsList := make([]*UserMetrics, 0)
@@ -235,7 +256,76 @@ func QueryMetrics(start int64, end int64) ([]*UserMetrics, int64) {
Find(&userMetricsList); err != nil {
return nil, 0
}
return userMetricsList, int64(len(userMetricsList))
postDeal(userMetricsList)
return userMetricsList, len(userMetricsList)
}

func postDeal(userMetricsList []*UserMetrics) {
for _, userMetrics := range userMetricsList {
userMetrics.DisplayDate = userMetrics.DataDate
userMetrics.TotalRegistUser = userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser
userMetrics.TotalNotActivateRegistUser = userMetrics.TotalUser - userMetrics.TotalActivateRegistUser
}
}

func QueryMetricsForAll() []*UserMetrics {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
userMetricsList := make([]*UserMetrics, 0)
if err := statictisSess.Table(new(UserMetrics)).OrderBy("count_date desc").
Find(&userMetricsList); err != nil {
return nil
}
return makeResultForMonth(userMetricsList, len(userMetricsList))
}

func QueryMetricsForYear() []*UserMetrics {
currentTimeNow := time.Now()
currentYearEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
currentYearStartTime := time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
allUserInfo, count := QueryMetrics(currentYearStartTime.Unix(), currentYearEndTime.Unix())

return makeResultForMonth(allUserInfo, count)
}

func makeResultForMonth(allUserInfo []*UserMetrics, count int) []*UserMetrics {
monthMap := make(map[string]*UserMetrics)
if count > 0 {
for _, userMetrics := range allUserInfo {
dateTime := time.Unix(userMetrics.CountDate, 0)
month := fmt.Sprint(dateTime.Year()) + "-" + fmt.Sprint(int(dateTime.Month()))
if _, ok := monthMap[month]; !ok {
monthUserMetrics := &UserMetrics{
DisplayDate: month,
ActivateRegistUser: userMetrics.ActivateRegistUser,
NotActivateRegistUser: userMetrics.NotActivateRegistUser,
TotalUser: userMetrics.TotalUser,
TotalNotActivateRegistUser: userMetrics.TotalUser - userMetrics.TotalActivateRegistUser,
TotalActivateRegistUser: userMetrics.TotalActivateRegistUser,
TotalHasActivityUser: userMetrics.TotalHasActivityUser,
HasActivityUser: userMetrics.HasActivityUser,
DaysForMonth: 1,
TotalRegistUser: userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser,
}
monthMap[month] = monthUserMetrics
} else {
value := monthMap[month]
value.ActivateRegistUser += userMetrics.ActivateRegistUser
value.NotActivateRegistUser += userMetrics.NotActivateRegistUser
value.HasActivityUser += userMetrics.HasActivityUser
value.TotalRegistUser += userMetrics.TotalRegistUser
value.DaysForMonth += 1
}
}
}
result := make([]*UserMetrics, 0)
for _, value := range monthMap {
result = append(result, value)
}
sort.Slice(result, func(i, j int) bool {
return strings.Compare(result[i].DisplayDate, result[j].DisplayDate) > 0
})
return result
}

func QueryRankList(key string, tableName string, limit int) ([]*UserBusinessAnalysisAll, int64) {
@@ -540,6 +630,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
if minUserIndex > dateRecordAll.UserIndexPrimitive {
minUserIndex = dateRecordAll.UserIndexPrimitive
}

dateRecordBatch = append(dateRecordBatch, dateRecordAll)
if len(dateRecordBatch) >= BATCH_INSERT_SIZE {
insertTable(dateRecordBatch, tableName, statictisSess)
@@ -695,7 +786,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
log.Info("query user error. return.")
return err
}
userNewAddActivity := make(map[int64]map[int64]int64)
ParaWeight := getParaWeight()
userMetrics := make(map[string]int)
var indexTotal int64
@@ -767,6 +858,9 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,

dateRecord.UserIndexPrimitive = getUserIndex(dateRecord, ParaWeight)
setUserMetrics(userMetrics, userRecord, start_unix, end_unix, dateRecord)
if getUserActivate(dateRecord) > 0 {
addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID)
}
_, err = statictisSess.Insert(&dateRecord)
if err != nil {
log.Info("insert daterecord failed." + err.Error())
@@ -785,18 +879,71 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
//insert userMetrics table
var useMetrics UserMetrics
useMetrics.CountDate = CountDate.Unix()
useMetrics.DataDate = DataDate
statictisSess.Delete(&useMetrics)

useMetrics.ActivateRegistUser = getMapKeyStringValue("ActivateRegistUser", userMetrics)
useMetrics.HasActivityUser = getMapKeyStringValue("HasActivityUser", userMetrics)
useMetrics.RegistActivityUser = 0
useMetrics.NotActivateRegistUser = getMapKeyStringValue("NotActivateRegistUser", userMetrics)
useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics)
useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics)
statictisSess.Insert(&useMetrics)

count, err = sess.Where("type=0").Count(new(User))
if err != nil {
log.Info("query user error. return.")
}
useMetrics.TotalUser = int(count)
if useMetrics.ActivateRegistUser+useMetrics.NotActivateRegistUser == 0 {
useMetrics.ActivateIndex = 0
} else {
useMetrics.ActivateIndex = float64(useMetrics.ActivateRegistUser) / float64(useMetrics.ActivateRegistUser+useMetrics.NotActivateRegistUser)
}
statictisSess.Insert(&useMetrics)
//update new user activity
updateNewUserAcitivity(userNewAddActivity, statictisSess)
return nil
}

func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, statictisSess *xorm.Session) {
for key, value := range currentUserActivity {
useMetrics := &UserMetrics{CountDate: key}
has, err := statictisSess.Get(useMetrics)
if err == nil && has {
userIdArrays := strings.Split(useMetrics.HasActivityUserJson, ",")
for _, userIdStr := range userIdArrays {
userIdInt, err := strconv.ParseInt(userIdStr, 10, 64)
if err == nil {
value[userIdInt] = userIdInt
}
}
userIdArray := ""
for _, tmpValue := range value {
userIdArray += fmt.Sprint(tmpValue) + ","
}
useMetrics.HasActivityUser = len(value)
if len(userIdArray) > 0 {
useMetrics.HasActivityUserJson = userIdArray[0 : len(userIdArray)-1]
}
updateSql := "update public.user_metrics set has_activity_user_json=" + useMetrics.HasActivityUserJson + ",regist_activity_user=" + fmt.Sprint(useMetrics.HasActivityUser) + " where count_date=" + fmt.Sprint(key)
statictisSess.Exec(updateSql)
}
}
}

func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64) {
CountDateTime := time.Date(registDate.Year(), registDate.AsTime().Month(), registDate.AsTime().Day(), 0, 1, 0, 0, registDate.AsTime().Location())
CountDate := CountDateTime.Unix()
if _, ok := currentUserActivity[CountDate]; !ok {
userIdMap := make(map[int64]int64, 0)
userIdMap[userId] = userId
currentUserActivity[CountDate] = userIdMap
} else {
currentUserActivity[CountDate][userId] = userId
}

}

func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, end_time int64, dateRecord UserBusinessAnalysis) {
//ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
//NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`


+ 15
- 6
models/user_business_struct.go View File

@@ -400,10 +400,19 @@ type UserAnalysisPara struct {
}

type UserMetrics struct {
CountDate int64 `xorm:"pk"`
ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
HasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
TotalHasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
CountDate int64 `xorm:"pk"`
ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
ActivateIndex float64 `xorm:"NOT NULL DEFAULT 0"`
RegistActivityUser int `xorm:"NOT NULL DEFAULT 0"`
HasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
TotalUser int `xorm:"NOT NULL DEFAULT 0"`
TotalRegistUser int `xorm:"-"`
TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
TotalNotActivateRegistUser int `xorm:"-"`
TotalHasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
DisplayDate string `xorm:"-"`
DataDate string `xorm:"NULL"`
DaysForMonth int `xorm:"NOT NULL DEFAULT 0"`
HasActivityUserJson string `xorm:"text NULL"`
}

+ 24
- 0
options/locale/locale_en-US.ini View File

@@ -527,6 +527,19 @@ static.public.user_business_analysis_last30_day=Last_30_day
static.public.user_business_analysis_last_month=Last_Month
static.public.user_business_analysis_yesterday=Yesterday
static.public.user_business_analysis_all=All

metrics.sheetname=User Trend Analysis
metrics.date=Count Date
metrics.newregistuser=New registered user
metrics.newregistandactiveuser=New activated
metrics.hasactivateuser=New contributing activities
metrics.newregistnotactiveuser=New inactive
metrics.averageuser=Average new users
metrics.newuseractiveindex=Activation rate of new users
metrics.totalregistuser=Cumulative registered users
metrics.totalactiveduser=Cumulative activated users
metrics.totalhasactivityuser=Cumulative active users

[settings]
profile = Profile
account = Account
@@ -947,6 +960,15 @@ model_manager = Model
model_noright=No right
model_rename=Duplicate model name, please modify model name.

date=Date
repo_add=Project Increment
repo_total=Project Total
repo_public_add=Public Project Increment
repo_private_add=Private Project Increment
repo_fork_add=Fork Project Increment
repo_mirror_add=Mirror Project Increment
repo_self_add=Custom Project Increment

debug=Debug
debug_again=Restart
stop=Stop
@@ -1011,7 +1033,9 @@ get_repo_stat_error=Can not get the statistics of the repository.
get_repo_info_error=Can not get the information of the repository.
generate_statistic_file_error=Failed to generate file.
repo_stat_inspect=ProjectAnalysis
repo_stat_develop=ProjectGrowthAnalysis
all=All
current_year=Current_Year

computing.all = All
computing.Introduction=Introduction


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

@@ -532,6 +532,19 @@ static.public.user_business_analysis_last30_day=近30天
static.public.user_business_analysis_last_month=上月
static.public.user_business_analysis_yesterday=昨天
static.public.user_business_analysis_all=所有

metrics.sheetname=用户趋势分析
metrics.date=日期
metrics.newregistuser=新增注册用户
metrics.newregistandactiveuser=新增已激活
metrics.hasactivateuser=新增有贡献活动
metrics.newregistnotactiveuser=新增未激活
metrics.averageuser=平均新增用户
metrics.newuseractiveindex=新增用户激活率
metrics.totalregistuser=累计注册用户
metrics.totalactiveduser=累计已激活
metrics.totalhasactivityuser=累计有贡献活动

[settings]
profile=个人信息
account=账号
@@ -948,6 +961,16 @@ model_manager = 模型
model_noright=无权限操作
model_rename=模型名称重复,请修改模型名称


date=日期
repo_add=新增项目
repo_total=累计项目
repo_public_add=新增公开项目
repo_private_add=新增私有项目
repo_fork_add=新增派生项目
repo_mirror_add=新增镜像项目
repo_self_add=新增自建项目

debug=调试
debug_again=再次调试
stop=停止
@@ -1019,7 +1042,9 @@ get_repo_stat_error=查询当前仓库的统计信息失败。
get_repo_info_error=查询当前仓库信息失败。
generate_statistic_file_error=生成文件失败。
repo_stat_inspect=项目分析
repo_stat_develop=项目增长趋势
all=所有
current_year=今年

computing.all=全部
computing.Introduction=简介


+ 12
- 1
routers/api/v1/api.go View File

@@ -535,6 +535,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/restoreFork", repo.RestoreForkNumber)
m.Get("/downloadAll", repo.ServeAllProjectsPeriodStatisticsFile)
m.Get("/downloadAllOpenI", repo.ServeAllProjectsOpenIStatisticsFile)
m.Get("/summary", repo.GetLatestProjectsSummaryData)
m.Get("/summary/period", repo.GetProjectsSummaryData)
m.Get("/summary/download", repo.GetProjectsSummaryDataFile)
m.Group("/project", func() {
m.Get("", repo.GetAllProjectsPeriodStatistics)
m.Get("/numVisit", repo.ProjectNumVisit)
@@ -547,7 +550,15 @@ func RegisterRoutes(m *macaron.Macaron) {
})
}, operationReq)

m.Get("/query_user_metrics", operationReq, repo_ext.QueryMetrics)
m.Get("/query_metrics_current_month", operationReq, repo_ext.QueryUserMetricsCurrentMonth)
m.Get("/query_metrics_current_week", operationReq, repo_ext.QueryUserMetricsCurrentWeek)
m.Get("/query_metrics_current_year", operationReq, repo_ext.QueryUserMetricsCurrentYear)
m.Get("/query_metrics_last30_day", operationReq, repo_ext.QueryUserMetricsLast30Day)
m.Get("/query_metrics_last_month", operationReq, repo_ext.QueryUserMetricsLastMonth)
m.Get("/query_metrics_yesterday", operationReq, repo_ext.QueryUserMetricsYesterday)
m.Get("/query_metrics_all", operationReq, repo_ext.QueryUserMetricsAll)
m.Get("/query_user_metrics_page", operationReq, repo_ext.QueryUserMetricDataPage)

m.Get("/query_user_rank_list", operationReq, repo_ext.QueryRankingList)
m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage)
m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth)


+ 317
- 0
routers/api/v1/repo/repo_dashbord.go View File

@@ -20,8 +20,10 @@ import (

const DEFAULT_PAGE_SIZE = 10
const DATE_FORMAT = "2006-01-02"
const MONTH_FORMAT = "2006-01"
const EXCEL_DATE_FORMAT = "20060102"
const CREATE_TIME_FORMAT = "2006/01/02 15:04:05"
const UPDATE_TIME_FORMAT = "2006-01-02 15:04:05"

type ProjectsPeriodData struct {
RecordBeginTime string `json:"recordBeginTime"`
@@ -60,6 +62,38 @@ type ProjectLatestData struct {
Top10 []UserInfo `json:"top10"`
}

type ProjectSummaryBaseData struct {
NumReposAdd int64 `json:"numReposAdd"`
NumRepoPublicAdd int64 `json:"numRepoPublicAdd"`
NumRepoPrivateAdd int64 `json:"numRepoPrivateAdd"`
NumRepoForkAdd int64 `json:"numRepoForkAdd"`
NumRepoMirrorAdd int64 `json:"numRepoMirrorAdd"`
NumRepoSelfAdd int64 `json:"numRepoSelfAdd"`
NumRepos int64 `json:"numRepos"`
CreatTime string `json:"creatTime"`
}

type ProjectSummaryData struct {
ProjectSummaryBaseData
NumRepoPublic int64 `json:"numRepoPublic"`
NumRepoPrivate int64 `json:"numRepoPrivate"`
NumRepoFork int64 `json:"numRepoFork"`
NumRepoMirror int64 `json:"numRepoMirror"`
NumRepoSelf int64 `json:"numRepoSelf"`

NumRepoOrgAdd int64 `json:"numRepoOrgAdd"`
NumRepoNotOrgAdd int64 `json:"numRepoNotOrgAdd"`

NumRepoOrg int64 `json:"numRepoOrg"`
NumRepoNotOrg int64 `json:"numRepoNotOrg"`
}

type ProjectSummaryPeriodData struct {
RecordBeginTime string `json:"recordBeginTime"`
TotalCount int64 `json:"totalCount"`
PageRecords []*ProjectSummaryBaseData `json:"pageRecords"`
}

func RestoreForkNumber(ctx *context.Context) {
repos, err := models.GetAllRepositories()
if err != nil {
@@ -73,6 +107,146 @@ func RestoreForkNumber(ctx *context.Context) {
ctx.JSON(http.StatusOK, struct{}{})
}

func GetLatestProjectsSummaryData(ctx *context.Context) {
stat, err := models.GetLatest2SummaryStatistic()
data := ProjectSummaryData{}
if err == nil && len(stat) > 0 {
data.NumRepos = stat[0].NumRepos
data.NumRepoOrg = stat[0].NumRepoOrg
data.NumRepoNotOrg = stat[0].NumRepos - stat[0].NumRepoOrg
data.NumRepoFork = stat[0].NumRepoFork
data.NumRepoMirror = stat[0].NumRepoMirror
data.NumRepoSelf = stat[0].NumRepoSelf
data.NumRepoPrivate = stat[0].NumRepoPrivate
data.NumRepoPublic = stat[0].NumRepoPublic
data.CreatTime = stat[0].CreatedUnix.Format(UPDATE_TIME_FORMAT)
if len(stat) == 2 {
data.NumReposAdd = stat[0].NumRepos - stat[1].NumRepos
data.NumRepoOrgAdd = stat[0].NumRepoOrg - stat[1].NumRepoOrg
data.NumRepoNotOrgAdd = (stat[0].NumRepos - stat[0].NumRepoOrg) - (stat[1].NumRepos - stat[1].NumRepoOrg)
data.NumRepoForkAdd = stat[0].NumRepoFork - stat[1].NumRepoFork
data.NumRepoMirrorAdd = stat[0].NumRepoMirror - stat[1].NumRepoMirror
data.NumRepoSelfAdd = stat[0].NumRepoSelf - stat[1].NumRepoSelf
data.NumRepoPrivateAdd = stat[0].NumRepoPrivate - stat[1].NumRepoPrivate
data.NumRepoPublicAdd = stat[0].NumRepoPublic - stat[1].NumRepoPublic
}
}
ctx.JSON(200, data)
}

func GetProjectsSummaryData(ctx *context.Context) {

var datas = make([]*ProjectSummaryBaseData, 0)

recordBeginTime, err := getRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)

beginTime = beginTime.AddDate(0, 0, -1)

queryType := ctx.QueryTrim("type")

var count int64

if queryType == "all" || queryType == "current_year" {
dates := getEndOfMonthDates(beginTime, endTime)
count, _ = models.GetSummaryStatisticByDateCount(dates)
stats, err := models.GetAllSummaryStatisticByDates(dates)
if err != nil {
log.Warn("can not get summary data", err)
} else {

for i, v := range stats {
if i == 0 {
continue
}
data := ProjectSummaryBaseData{}
setStatisticsData(&data, v, stats[i-1])
createTime, _ := time.Parse(DATE_FORMAT, v.Date)
data.CreatTime = createTime.Format(MONTH_FORMAT)
datas = append(datas, &data)
}
}

} else {
count, _ = models.GetSummaryStatisticByTimeCount(beginTime, endTime)
stats, err := models.GetAllSummaryStatisticByTime(beginTime, endTime)
if err != nil {
log.Warn("can not get summary data", err)
} else {

for i, v := range stats {
if i == 0 {
continue
}
data := ProjectSummaryBaseData{}
setStatisticsData(&data, v, stats[i-1])
data.CreatTime = v.Date
datas = append(datas, &data)
}
}

}


projectSummaryPeriodData := ProjectSummaryPeriodData{
TotalCount: count - 1,
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
PageRecords: reverse(datas),
}

ctx.JSON(200, projectSummaryPeriodData)

}

func reverse(datas []*ProjectSummaryBaseData ) []*ProjectSummaryBaseData {
for i := 0; i < len(datas)/2; i++ {
j := len(datas) - i - 1
datas[i], datas[j] = datas[j], datas[i]
}
return datas
}



func setStatisticsData(data *ProjectSummaryBaseData, v *models.SummaryStatistic, stats *models.SummaryStatistic) {
data.NumReposAdd = v.NumRepos - stats.NumRepos
data.NumRepoPublicAdd = v.NumRepoPublic - stats.NumRepoPublic
data.NumRepoPrivateAdd = v.NumRepoPrivate - stats.NumRepoPrivate
data.NumRepoMirrorAdd = v.NumRepoMirror - stats.NumRepoMirror
data.NumRepoForkAdd = v.NumRepoFork - stats.NumRepoFork
data.NumRepoSelfAdd = v.NumRepoSelf - stats.NumRepoSelf

data.NumRepos = v.NumRepos
}

func getEndOfMonthDates(beginTime time.Time, endTime time.Time) []string {
var dates = []string{}
date := endOfMonth(beginTime.AddDate(0, -1, 0))
dates = append(dates, date.Format(DATE_FORMAT))

tempDate := endOfMonth(beginTime)

for {
if tempDate.Before(endTime) {
dates = append(dates, tempDate.Format(DATE_FORMAT))
tempDate = endOfMonth(tempDate.AddDate(0, 0, 1))
} else {
break
}
}

return dates
}

func endOfMonth(date time.Time) time.Time {
return date.AddDate(0, 1, -date.Day())
}

func GetAllProjectsPeriodStatistics(ctx *context.Context) {

recordBeginTime, err := getRecordBeginTime()
@@ -210,6 +384,122 @@ func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) {

}

func GetProjectsSummaryDataFile(ctx *context.Context) {

recordBeginTime, err := getRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
beginTime = beginTime.AddDate(0, 0, -1)
if err != nil {
log.Error("Parameter is wrong", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
return
}

page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := 100

if err != nil {
log.Error("Can not query the last updated time.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
return
}

var projectAnalysis = ctx.Tr("repo.repo_stat_develop")
fileName := getSummaryFileName(ctx, beginTime, endTime, projectAnalysis)

f := excelize.NewFile()

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

for k, v := range allProjectsPeriodSummaryHeader(ctx) {
f.SetCellValue(projectAnalysis, k, v)
}

var total int64
queryType := ctx.QueryTrim("type")

var datas = make([]*ProjectSummaryBaseData, 0)

if queryType == "all" || queryType == "current_year" {
dates := getEndOfMonthDates(beginTime, endTime)
total, _ = models.GetSummaryStatisticByDateCount(dates)
totalPage := getTotalPage(total, pageSize)

for i := 0; i < totalPage; i++ {

stats, err := models.GetSummaryStatisticByDates(dates, i+1, pageSize)
if err != nil {
log.Warn("can not get summary data", err)
} else {
for j, v := range stats {
if j == 0 {
continue
}
data := ProjectSummaryBaseData{}
setStatisticsData(&data, v, stats[j-1])
createTime, _ := time.Parse(DATE_FORMAT, v.Date)
data.CreatTime = createTime.Format(MONTH_FORMAT)

datas = append(datas, &data)

}

}

}

} else {
total, _ = models.GetSummaryStatisticByTimeCount(beginTime, endTime)
totalPage := getTotalPage(total, pageSize)

for i := 0; i < totalPage; i++ {

stats, err := models.GetSummaryStatisticByTime(beginTime, endTime, i+1, pageSize)
if err != nil {
log.Warn("can not get summary data", err)
} else {
for j, v := range stats {
if j == 0 {
continue
}
data := ProjectSummaryBaseData{}
setStatisticsData(&data, v, stats[j-1])
data.CreatTime = v.Date
datas = append(datas, &data)

}

}

}
}
row := 2
datas = reverse(datas)
for _, data := range datas {
for k, v := range allProjectsPeriodSummaryValues(row, data, ctx) {
f.SetCellValue(projectAnalysis, k, v)
}
row++
}

f.SetActiveSheet(index)

ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")

f.WriteTo(ctx.Resp)

}

func ServeAllProjectsOpenIStatisticsFile(ctx *context.Context) {

page := ctx.QueryInt("page")
@@ -290,6 +580,20 @@ func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, p
return frontName
}

func getSummaryFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string {
baseName := projectAnalysis + "_"

if ctx.QueryTrim("type") == "all" {
baseName = baseName + ctx.Tr("repo.all")
} else if ctx.QueryTrim("type") == "current_year" {
baseName = baseName + ctx.Tr("repo.current_year")
} else {
baseName = baseName + beginTime.Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT)
}
frontName := baseName + ".xlsx"
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("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"),
@@ -297,6 +601,19 @@ func allProjectsPeroidHeader(ctx *context.Context) map[string]string {

}

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

return map[string]string{"A1": ctx.Tr("repo.date"), "B1": ctx.Tr("repo.repo_add"), "C1": ctx.Tr("repo.repo_total"), "D1": ctx.Tr("repo.repo_public_add"), "E1": ctx.Tr("repo.repo_private_add"), "F1": ctx.Tr("repo.repo_self_add"), "G1": ctx.Tr("repo.repo_fork_add"), "H1": ctx.Tr("repo.repo_mirror_add")}

}

func allProjectsPeriodSummaryValues(row int, rs *ProjectSummaryBaseData, ctx *context.Context) map[string]string {

return map[string]string{getCellName("A", row): rs.CreatTime, getCellName("B", row): strconv.FormatInt(rs.NumReposAdd, 10), getCellName("C", row): strconv.FormatInt(rs.NumRepos, 10), getCellName("D", row): strconv.FormatInt(rs.NumRepoPublicAdd, 10), getCellName("E", row): strconv.FormatInt(rs.NumRepoPrivateAdd, 10),
getCellName("F", row): strconv.FormatInt(rs.NumRepoSelfAdd, 10), getCellName("G", row): strconv.FormatInt(rs.NumRepoForkAdd, 10), getCellName("H", row): strconv.FormatInt(rs.NumRepoMirrorAdd, 10),
}
}

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): rs.DisplayName(), getCellName("C", row): rs.OwnerName, getCellName("D", row): getBoolDisplay(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),


+ 25
- 0
routers/home.go View File

@@ -605,7 +605,32 @@ func ExploreImages(ctx *context.Context) {
ctx.HTML(200, tplExploreImages)
}

func ExploreDataAnalysisUserTrend(ctx *context.Context) {
ctx.Data["url_params"]="UserTrend"
ctx.HTML(200, tplExploreExploreDataAnalysis)
}
func ExploreDataAnalysisUserAnalysis(ctx *context.Context) {
ctx.Data["url_params"]="UserAnalysis"
ctx.HTML(200, tplExploreExploreDataAnalysis)
}
func ExploreDataAnalysisProTrend(ctx *context.Context) {
ctx.Data["url_params"]="ProTrend"
ctx.HTML(200, tplExploreExploreDataAnalysis)
}
func ExploreDataAnalysisProAnalysis(ctx *context.Context) {
ctx.Data["url_params"]="ProAnalysis"
ctx.HTML(200, tplExploreExploreDataAnalysis)
}
func ExploreDataAnalysisOverview(ctx *context.Context) {
ctx.Data["url_params"]="Overview"
ctx.HTML(200, tplExploreExploreDataAnalysis)
}
func ExploreDataAnalysisBrainAnalysis(ctx *context.Context) {
ctx.Data["url_params"]="BrainAnalysis"
ctx.HTML(200, tplExploreExploreDataAnalysis)
}
func ExploreDataAnalysis(ctx *context.Context) {
ctx.Data["url_params"]=""
ctx.HTML(200, tplExploreExploreDataAnalysis)
}



+ 7
- 0
routers/repo/repo_summary_statistic.go View File

@@ -60,6 +60,12 @@ func SummaryStatisticDaily(date string) {
}
selfRepositoryNumber := repositoryNumer - mirrorRepositoryNumber - forkRepositoryNumber

organizationRepoNumber, err := models.GetAllOrgRepositoriesCount()
if err != nil {
log.Error("can not get org repository number", err)
organizationRepoNumber = 0
}

//repository size
repositorySize, err := models.GetAllRepositoriesSize()
if err != nil {
@@ -99,6 +105,7 @@ func SummaryStatisticDaily(date string) {
NumRepoPrivate: privateRepositoryNumer,
NumRepoPublic: publicRepositoryNumer,
NumRepoSelf: selfRepositoryNumber,
NumRepoOrg: organizationRepoNumber,
NumRepoBigModel: topicsCount[0],
NumRepoAI: topicsCount[1],
NumRepoVision: topicsCount[2],


+ 175
- 16
routers/repo/user_data_analysis.go View File

@@ -19,6 +19,57 @@ const (
PAGE_SIZE = 2000
)

func getUserMetricsExcelHeader(ctx *context.Context) map[string]string {
excelHeader := make([]string, 0)
excelHeader = append(excelHeader, ctx.Tr("user.metrics.date"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newregistuser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newregistandactiveuser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.hasactivateuser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newregistnotactiveuser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.averageuser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newuseractiveindex"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.totalregistuser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.totalactiveduser"))
excelHeader = append(excelHeader, ctx.Tr("user.metrics.totalhasactivityuser"))

excelHeaderMap := make(map[string]string, 0)
var i byte
i = 0
for _, value := range excelHeader {
excelColumn := getColumn(i) + fmt.Sprint(1)
excelHeaderMap[excelColumn] = value
i++
}
return excelHeaderMap
}

func writeUserMetricsExcel(row int, xlsx *excelize.File, sheetName string, userMetrics *models.UserMetrics) {
rows := fmt.Sprint(row)
var tmp byte
tmp = 0
dateTime := time.Unix(userMetrics.CountDate, 0)
//dateTime.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, dateTime.Format("2006-01-02 15:04:05"))
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.ActivateRegistUser+userMetrics.NotActivateRegistUser)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.ActivateRegistUser)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.RegistActivityUser)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.NotActivateRegistUser)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, "")
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, fmt.Sprintf("%.2f", userMetrics.ActivateIndex))
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.TotalUser)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.TotalActivateRegistUser)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.TotalHasActivityUser)
}

func getExcelHeader(ctx *context.Context) map[string]string {
excelHeader := make([]string, 0)
excelHeader = append(excelHeader, ctx.Tr("user.static.id"))
@@ -200,16 +251,61 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac
}
}

func QueryMetrics(ctx *context.Context) {
startDate := ctx.Query("startDate")
endDate := ctx.Query("endDate")
startTime, _ := time.ParseInLocation("2006-01-02", startDate, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02", endDate, time.Local)
result, count := models.QueryMetrics(startTime.Unix(), endTime.Unix())
mapInterface := make(map[string]interface{})
mapInterface["data"] = result
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
func queryMetrics(ctx *context.Context, tableName string, startTime time.Time, endTime time.Time) {

page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
IsReturnFile := ctx.QueryBool("IsReturnFile")

var count int64
result := make([]*models.UserMetrics, 0)
if tableName == "public.user_business_analysis_current_year" {
result = models.QueryMetricsForYear()
count = int64(len(result))
} else if tableName == "public.user_business_analysis_all" {
result = models.QueryMetricsForAll()
count = int64(len(result))
} else {
result, count = models.QueryMetricsPage(startTime.Unix(), endTime.Unix(), page, pageSize)
}
if IsReturnFile {
//writer exec file.
xlsx := excelize.NewFile()
sheetName := ctx.Tr("user.metrics.sheetname")
index := xlsx.NewSheet(sheetName)
xlsx.DeleteSheet("Sheet1")
dataHeader := getUserMetricsExcelHeader(ctx)
for k, v := range dataHeader {
//设置单元格的值
xlsx.SetCellValue(sheetName, k, v)
}
row := 1
log.Info("return count=" + fmt.Sprint(count))
for _, userRecord := range result {
row++
writeUserMetricsExcel(row, xlsx, sheetName, userRecord)
}
//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
if _, err := xlsx.WriteTo(ctx.Resp); err != nil {
log.Info("writer exel error." + err.Error())
}
} else {
mapInterface := make(map[string]interface{})
mapInterface["data"] = result
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}

}

func QueryRankingList(ctx *context.Context) {
@@ -224,34 +320,97 @@ func QueryRankingList(ctx *context.Context) {
ctx.JSON(http.StatusOK, mapInterface)
}

func QueryUserMetricsCurrentMonth(ctx *context.Context) {
currentTimeNow := time.Now()
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_current_month", pageStartTime, pageEndTime)
}
func QueryUserStaticCurrentMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth))
}

func QueryUserMetricsCurrentWeek(ctx *context.Context) {
currentTimeNow := time.Now()
offset := int(time.Monday - currentTimeNow.Weekday())
if offset > 0 {
offset = -6
}
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_current_week", pageStartTime, pageEndTime)
}
func QueryUserStaticCurrentWeek(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_week", new(models.UserBusinessAnalysisCurrentWeek))
}

func QueryUserMetricsCurrentYear(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_current_year", pageStartTime, pageEndTime)
}
func QueryUserStaticCurrentYear(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_year", new(models.UserBusinessAnalysisCurrentYear))
}

func QueryUserMetricsLast30Day(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_last30_day", pageStartTime, pageEndTime)
}
func QueryUserStaticLast30Day(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last30_day", new(models.UserBusinessAnalysisLast30Day))
}

func QueryUserMetricsLastMonth(ctx *context.Context) {
currentTimeNow := time.Now()
thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
pageStartTime := thisMonth.AddDate(0, -1, 0)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
queryMetrics(ctx, "public.user_business_analysis_last_month", pageStartTime, pageEndTime)
}
func QueryUserStaticLastMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth))
}

func QueryUserMetricsYesterday(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_yesterday", pageStartTime, pageEndTime)
}
func QueryUserStaticYesterday(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_yesterday", new(models.UserBusinessAnalysisYesterday))
}

func QueryUserMetricsAll(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(2022, 4, 5, 0, 0, 0, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_all", pageStartTime, pageEndTime)
}
func QueryUserStaticAll(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_all", new(models.UserBusinessAnalysisAll))
}

func QueryUserMetricDataPage(ctx *context.Context) {
startDate := ctx.Query("startDate")
endDate := ctx.Query("endDate")
startTime, _ := time.ParseInLocation("2006-01-02", startDate, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02", endDate, time.Local)

page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
result, count := models.QueryMetricsPage(startTime.Unix(), endTime.Unix(), page, pageSize)

mapInterface := make(map[string]interface{})
mapInterface["data"] = result
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}

func QueryUserStaticDataPage(ctx *context.Context) {
startDate := ctx.Query("startDate")
endDate := ctx.Query("endDate")


+ 7
- 0
routers/routes/routes.go View File

@@ -346,6 +346,13 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/code", routers.ExploreCode)
m.Get("/images", routers.ExploreImages)
m.Get("/data_analysis", routers.ExploreDataAnalysis)
m.Get("/data_analysis/UserTrend", routers.ExploreDataAnalysisUserTrend)
m.Get("/data_analysis/UserAnalysis", routers.ExploreDataAnalysisUserAnalysis)
m.Get("/data_analysis/ProAnalysis", routers.ExploreDataAnalysisProAnalysis)
m.Get("/data_analysis/ProTrend", routers.ExploreDataAnalysisProTrend)
m.Get("/data_analysis/Overview", routers.ExploreDataAnalysisOverview)
m.Get("/data_analysis/BrainAnalysis", routers.ExploreDataAnalysisBrainAnalysis)

}, ignSignIn)
m.Combo("/install", routers.InstallInit).Get(routers.Install).
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)


+ 9
- 3
templates/explore/data_analysis.tmpl View File

@@ -1,15 +1,21 @@
{{template "base/head_fluid" .}}
<input id="url_params" type="hidden" value={{.url_params}}/>
<div id="data_analysis" style="height: 100%;">
</div>

{{template "base/footer_fluid" .}}

<!-- <script>
localStorage.setItem("dataAnalysisURL","{{.url_params}}")
</script> -->
<style>
.full.height {
display: flex;
flex-flow: column wrap;
padding-bottom:0px;
/* flex-grow: 1; */
padding-bottom: 53px;
/* padding-bottom: 53px; */
}

</style>

+ 76
- 105
web_src/js/components/DataAnalysis.vue View File

@@ -1,108 +1,61 @@
<template>
<div style="height:100%">
<el-tabs tab-position="left" v-model="activeName" style="height:100%" @tab-click="handleClick" >
<el-tab-pane label="概览" name="first" >
<span slot="label">
<el-image style="width: 13px; height: 13px" src="/img/overview_rgb.svg">
</el-image>
概览
</span>
<div >暂无内容.......</div>
<el-row style="height:100%;width: 100%; flex:1" >
<el-col :span="3" style="height:100%;padding-right:15px;">
<el-menu
:default-active="this.$router.path"
class="el-menu-vertical-demo"
:router="true" style="height:100%; background-color: #F5F5F6;" >
<el-menu-item index="/Overview" >
<i class="ri-home-4-line"></i>
<span slot="title">概览</span>
</el-menu-item>
<el-submenu index="/">
<template slot="title">
<i class="ri-numbers-line"></i>
<span>项目分析</span>
</template>
<el-menu-item index="/ProTrend">增长趋势分析</el-menu-item>
<el-menu-item index="/ProAnalysis">详细数据</el-menu-item>
</el-submenu>
<el-submenu index="2">
<template slot="title">
<i class="ri-contacts-line"></i>
<span>用户分析</span>
</template>
<el-menu-item index="/UserTrend">增长趋势分析</el-menu-item>
<el-menu-item index="/UserAnalysis">活动分析</el-menu-item>
</el-submenu>
<el-menu-item index="/BrainAnalysis">
<i class="ri-server-fill"></i>
<span slot="title">云脑分析(建设中..)</span>
</el-menu-item>
</el-menu>
</el-col>
<router-view> </router-view>
</el-row>
</template>

</el-tab-pane>
<el-tab-pane label="项目分析" name="second" id="second" >
<ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis>
<span slot="label">
<el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg">
</el-image>
项目分析
</span>
</el-tab-pane>
<el-tab-pane name="third" id='third' >
<span slot='label'>
<el-image style="width: 13px; height: 13px" src="/img/user_rgb.svg">
</el-image>
用户分析
</span>
<UserAnalysis ref='UserAnalysis' v-if="isRouterAlive1" id ="usr"></UserAnalysis>
</el-tab-pane>
<el-tab-pane name="four" id='four' >
<BrainAnalysis ref='BrainAnalysis'id="brain" v-if="isRouterAlive"></BrainAnalysis>
<span slot="label">
<el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg">
</el-image>
云脑分析(建设中..)
</span>
</el-tab-pane>
</el-tabs>
</div>
</template>

<script>
import ProAnalysis from './ProAnalysis.vue'
import UserAnalysis from './UserAnalysis.vue'
import BrainAnalysis from './BrainAnalysis.vue'

export default {

components:{
'ProAnalysis':ProAnalysis,
'UserAnalysis':UserAnalysis,
'BrainAnalysis':BrainAnalysis,
},
data() {
return {
activeName:"second",
loading:true,
loading1:true,
isRouterAlive: true,
isRouterAlive1: true,
isSecond:true,
isThird:false,
}
},
methods:{
handleClick(tab, event){
if(tab.name=="second"){
this.reload()

this.isSecond = true
this.isThird = false
this.$refs.ProAnalysis.getAllProList("all",7)
}
if(tab.name=="third"){

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))
},
reload1 () {
this.isRouterAlive1 = false
this.$nextTick(() => (this.isRouterAlive1 = true))
}

},
}
</script>
<style scoped>
<script>
export default{
data(){
return {
Path_router:'/'
}
},
created(){
var url_params = document.getElementById("url_params").value;
if (url_params!='' && url_params!=undefined && url_params!='/'){
this.$router.path = '/'+url_params.split('/')[0]
}else{
this.$router.path = '/ProAnalysis'
}
},
}
</script>
<style scoped>
/deep/ .is-active{
color: #238BFC ;
background-color: #FFFF ;
color: #238BFC ;
}
/deep/ .ui-container{
background-color: #FFFF;
@@ -137,8 +90,26 @@
/deep/ .el-tabs__item:hover .el-image{
filter:none
}
/deep/ .el-image{
filter:grayscale(100%)

.bk{
background-color: #F5F5F6;
}
.el-menu-item.is-active {
color: #409eff;
background-color: #FFFFFF !important;
}
/deep/ .el-submenu.is-active .el-submenu__title {
color: #409eff
}
/deep/ .el-submenu.is-active .el-submenu__title i{
color: #409eff
}
/deep/ .el-menu, .el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .el-menu--horizontal>.el-submenu .el-submenu__title:hover {
background-color: #F5F5F6;
}
/deep/ .el-pagination {
padding-bottom: 30px;
}

</style>
</style>

+ 5
- 0
web_src/js/components/Overview.vue View File

@@ -0,0 +1,5 @@
<template>
<div>
暂无内容
</div>
</template>

+ 55
- 12
web_src/js/components/ProAnalysis.vue View File

@@ -1,8 +1,8 @@
<template>
<div style="width: 100%;">
<div class="el-col el-col-21" style="padding-right:10px " >
<div id = "pro_main">
<div style="margin-top: 10px;">
<b class="pro_item">项目分析</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}}&nbsp/&nbsp从{{recordBeginTime}}开始统计</span>
<b class="pro_item">详细数据</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}}&nbsp/&nbsp从{{recordBeginTime}}开始统计</span>
</div>
<bar-label :width="'95%'" :height="'500px'"></bar-label>
@@ -29,11 +29,11 @@
</span>
<span style="float:right; margin-right: 20px;">
<div style="display:inline-block;margin-left: 20px; ">
<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>
<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-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>
@@ -59,6 +59,7 @@
>
</el-table-column>
<el-table-column
fixed
label="项目名称中文"
align="left"
prop="name"
@@ -404,8 +405,7 @@
value_time: '',
search:'',
dynamic:7,
download_a:"",
downLoadSrc:'',


//单个项目参数
@@ -652,7 +652,7 @@
getAllProList(type_val,index){
console.log("类型:"+type_val)
// console.log("类型:"+type_val)
this.dynamic = index
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){
this.params.type=''
@@ -665,7 +665,7 @@
this.value_time=[]
}
this.$axios.get('../api/v1/projectboard/project',{
this.$axios.get('../../api/v1/projectboard/project',{
params:this.params
}).then((res)=>{
@@ -720,7 +720,7 @@
},
getOneProData(pro_id){
this.$axios.get('../api/v1/projectboard/project/'+pro_id,{
this.$axios.get('../../api/v1/projectboard/project/'+pro_id,{
}).then((res)=>{
this.tableDataIDTotal = res.data
this.tableDataContTop10=res.data.top10
@@ -731,7 +731,7 @@
},
getOneProList(pro_id,type_val,bool_val,index){
this.dynamic_pro=index
console.log("日期类型:"+type_val)
// console.log("日期类型:"+type_val)
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){
this.paramsID.type=''
this.paramsID.beginTime= this.formatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate())
@@ -743,7 +743,7 @@
this.paramsID.endTime=''
}
this.paramsID.openi=bool_val
this.$axios.get('../api/v1/projectboard/project/'+pro_id+"/period",{
this.$axios.get('../../api/v1/projectboard/project/'+pro_id+"/period",{
params:this.paramsID
}).then((res)=>{
if (bool_val){
@@ -923,12 +923,24 @@
type : 'category',
boundaryGap: false,
data : xdata_openI,
axisLine: {
show: false, //x轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
yAxis : [
{
type : 'value',
axisLine: {
show: false, //x轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
@@ -1011,6 +1023,12 @@
},
legend: {
data:['浏览量','下载量','commit'],
selected:{
// '浏览量':true,
// '下载量':true,
// 'commit':true,
}

// orient: 'vertical',
// top:'top',  
},
@@ -1029,12 +1047,24 @@
{
type : 'category',
data : xdata,
axisLine: {
show: false, //x轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
yAxis : [
{
type : 'value',
type : 'value',
axisLine: {
show: false, //x轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
series : [
@@ -1059,6 +1089,16 @@
]
};
// this.echartsSelectData.resize()
var checkboxs=document.getElementsByName('checkboxchart');
for(var i=0; i<checkboxs.length; i++){
// console.log("selectArr[i]:",this.option.legend.data[i])
if(checkboxs[i].checked){
this.option.legend.selected[this.option.legend.data[i]]=true;
}else{
this.option.legend.selected[this.option.legend.data[i]]=false;
}
}

this.echartsSelectData.setOption(this.option)
// setTimeout(function (){
// window.onresize = function () {
@@ -1299,6 +1339,9 @@
/deep/ .el-range-separator{
width: 20% !important;
}
/deep/ .el-pagination {
padding-bottom: 30px;
}

.colorChange {
background-color: #1684FC;


+ 903
- 0
web_src/js/components/ProTrend.vue View File

@@ -0,0 +1,903 @@
<template>
<div class="el-col el-col-21" style="padding-right:10px ">
<div id='pro_tend' >
<div style="margin-top: 10px;">
<b class="pro_item">增长趋势分析</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}}&nbsp/&nbsp从{{recordBeginTime}}开始统计</span>
</div>
<div style="margin-top:20px">
<el-row>
<el-col :span='1' class ='item_list_first'>
<el-row class="item_title_h">
&nbsp;
</el-row>
<el-row class="item_h">
昨天
</el-row>
<el-row class="item_h">
累计
</el-row>
</el-col>
<el-col span='23' >
<el-col :span='3' class ='item_list'>
<el-row class="item_title_h">
项目
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numReposAdd}}
</el-row>
<el-row class="item_h">
{{ tableDataSummary.numRepos}}
</el-row>
</el-col>
<el-col :span='3' >
<el-row class ='item_list_p item_title_h'>
公开
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoPublicAdd}}
</el-row >
<el-row class="item_h">
{{tableDataSummary.numRepoPublic}}
</el-row>
</el-col>
<el-col :span='3' class ='item_list'>
<el-row class="item_title_h">
私有
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoPrivateAdd}}
</el-row>
<el-row class="item_h">
{{tableDataSummary.numRepoPrivate}}
</el-row>
</el-col>
<el-col :span='3'>
<el-row class ='item_list_p item_title_h'>
自建
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoSelfAdd}}
</el-row >
<el-row class="item_h">
{{tableDataSummary.numRepoSelf}}
</el-row>
</el-col>
<el-col :span='3' >
<el-row class ='item_list_p item_title_h'>
派生
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoForkAdd}}
</el-row >
<el-row class="item_h">
{{tableDataSummary.numRepoFork}}
</el-row>
</el-col>
<el-col :span='3' class ='item_list '>
<el-row class="item_title_h">
镜像
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoMirrorAdd}}
</el-row>
<el-row class="item_h">
{{tableDataSummary.numRepoMirror}}
</el-row>
</el-col>
<el-col :span='3'>
<el-row class ='item_list_p item_title_h'>
组织
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoOrgAdd}}
</el-row>
<el-row class="item_h">
{{tableDataSummary.numRepoOrg}}
</el-row>
</el-col>
<el-col :span='2'>
<el-row class="item_title_h">
个人
</el-row>
<el-row class="item_h num_color">
{{tableDataSummary.numRepoNotOrgAdd}}
</el-row>
<el-row class="item_h">
{{tableDataSummary.numRepoNotOrg}}
</el-row>
</el-col>
</el-col>
</el-row>
</div>
<div style="margin-top: 20px;">
<span class="sta_iterm">统计周期:</span>
<!-- <button type="button" class='btnFirst' id ="yesterday" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getPeriodProList('yesterday',1)">昨天</button> -->
<button type="button" class='btn' id = "current_week" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getPeriodProList('current_week',1)">本周</button>
<button type="button" class='btn' id = "current_month" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getPeriodProList('current_month',2)">本月</button>
<button type="button" class='btn' id = "last_month" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getPeriodProList('last_month',3)">上月</button>
<button type="button" class='btn' id = "monthly" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getPeriodProList('monthly',4)">近30天</button>
<button type="button" class='btn' id = "current_year" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getPeriodProList('current_year',5)">今年</button>
<button type="button" class='btnLast' id = "all" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getPeriodProList('all',6)">所有</button>
<span style="margin-left: 20px;">
<el-date-picker
v-model="value_time"
prefix-icon="el-icon-time"
@change="resetPage(),getPeriodProList('',0)"
type="daterange"
size='small'
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</span>
<span style="float:right; margin-right: 20px;">
<div style="display:inline-block;margin-left: 20px; ">
<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/summary/download?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime">下载报告</a>
<a id = "download_file" v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a>
</span>
</div>
</span>
</div>
<div class="item_echart" id ='linecharts'>
<div style="margin: 15px 10px 30px;">
<label for="label" @change='clickCheckBox'>
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增项目"/> 新增项目
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增公开项目"/>新增公开项目
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增私有项目"/>新增私有项目
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增自建项目"/>新增自建项目
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增派生项目"/>新增派生项目
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增镜像项目"/>新增镜像项目
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="累计项目"/>累计项目
</label>
</div>
<div id ="selectData" style="height: 300px;">

</div>

</div>
<div style="margin-top: 30px;">
<el-table
:data="tableData.slice((page-1)*pageSize,page*pageSize)"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style='cellStyle'>
<el-table-column
label="日期"
align="left"
prop="creatTime"
>
</el-table-column>
<el-table-column
label="新增项目"
align="center"
prop="numReposAdd"
>
</el-table-column>
<el-table-column
label="累计项目"
align="center"
prop="numRepos"
>
</el-table-column>
<el-table-column
prop="numRepoPublicAdd"
label="新增公开项目"
align="center">
</el-table-column>
<el-table-column
prop="numRepoPrivateAdd"
label="新增私有项目"
align="center">
</el-table-column>
<el-table-column
prop="numRepoSelfAdd"
label="新增自建项目"
align="center">
</el-table-column>
<el-table-column
prop="numRepoForkAdd"
label="新增派生项目"
align="center">
</el-table-column>
<el-table-column
prop="numRepoMirrorAdd"
label="新增镜像项目"
align="center">
</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="page"
:page-size="pageSize"
:page-sizes="[5,10,20]"
layout="total, sizes,prev, pager, next,jumper"
:total="tableData.length">
</el-pagination>
</div>
</div>
</div>
</template>

<script>
// import barLabel from './basic/barLabel.vue';
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;

import { export2Excel } from '../excel/util.js'
export default{
name:'ProAnalysis',
components: {
// barLabel,
},
data() {
return {
recordBeginTime:'',
lastUpdatedTime:'',
page:1,
pageSize:10,
params:{type:'monthly',page:1,pagesize:10,beginTime:'',endTime:''},
tableData: [],
tableDataSummary:{},
totalPage:0,
totalNum:0,
pickerOptions: {
},
value_time: '',
dynamic:4,
echartsSelectData:'',
option:'',
};
},
methods: {
// 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()
if (this.tableData!=''){
this.page=1
var saveFileName = this.getFileName()
export2Excel(this.columns,this.tableData,saveFileName)
}else{
alert("数据为空时,不能下载!")
}
},
getFileName(){

var now = new Date(); // 当前日期
var nowDayOfWeek = now.getDay(); // 今天本周的第几天
var nowDay = now.getDate(); // 当前日
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())

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());
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.alias+"_"+startDate+'_'+endDate
}else{
switch(this.paramsID.type){
case "yesterday":{
startDate = this.comparedate(yesterday_tmp,this.recordBeginTime)
endDate = startDate

saveFileName = this.alias+"_"+startDate+'_'+ endDate
break
}
case "current_week":{
var now = new Date(); // 当前日期
var nowDayOfWeek = now.getDay(); // 今天本周的第几天
var day = nowDayOfWeek || 7;
startDate = this.formatDate(now.getFullYear(), nowMonth+1, nowDay + 1 - day);
startDate = this.comparedate(startDate,this.recordBeginTime)

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

endDate = yesterday
saveFileName = this.alias+"_"+startDate+'_'+ endDate
break
}
case "last_month":{

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.alias+"_"+startDate+'_'+ endDate
break
}
case "monthly":{
var temp=new Date(now - 1000 * 60 * 60 * 24 * 30)
startDate = this.formatDate(temp.getFullYear(),temp.getMonth()+1,temp.getDate());
startDate = this.comparedate(startDate,this.recordBeginTime)

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

endDate = yesterday
saveFileName = this.alias+"_"+startDate+'_'+ endDate
break
}
case "all":{
console.log("e:"+today)
startDate = 'all'
endDate = yesterday
saveFileName = this.alias+'_所有'
break
}
}
}
return saveFileName

},
resetPage(){
this.page=1
this.params.page = 1
},
resetCurrentPage(){
this.page=1
},
handleSizeChange(val){
this.pageSize = val
},
handleCurrentChange(val){
this.page = val;
},
saveFormatDate(myyear,mymonth,myweekday) {
// var myyear = this.date.getFullYear();
// var mymonth = this.date.getMonth() + 1;
// var myweekday = this.date.getDate();
if (mymonth < 10) {
mymonth = "0" + mymonth;
}
if (myweekday < 10) {
myweekday = "0" + myweekday;
}
console.log((myyear +''+ mymonth +''+ myweekday))
return (myyear +''+ mymonth +''+ myweekday);
},
formatDate(myyear,mymonth,myweekday) {
// var myyear = this.date.getFullYear();
// var mymonth = this.date.getMonth() + 1;
// var myweekday = this.date.getDate();
if (mymonth < 10) {
mymonth = "0" + mymonth;
}
if (myweekday < 10) {
myweekday = "0" + myweekday;
}
return (myyear +'-'+ mymonth +'-'+ myweekday);
},
//获得某月的天数
getPeriodProList(type_val,index){
// console.log("类型:"+type_val)
this.dynamic = index
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){
this.params.type=''
this.params.beginTime=this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate())
this.params.endTime=this.formatDate(this.value_time[1].getFullYear(),this.value_time[1].getMonth() + 1,this.value_time[1].getDate())
}else{
this.params.type=type_val
this.params.beginTime=''
this.params.endTime=''
this.value_time=[]
}
// console.log("params:",this.params)
this.$axios.get('../../api/v1/projectboard/summary/period',{
params:this.params
}).then((res)=>{
this.recordBeginTime=res.data.recordBeginTime
// this.lastUpdatedTime=res.data.creatTime
this.tableData = res.data.pageRecords
this.totalPage=res.data.totalPage
// this.totalNum = res.data.totalCount//this.totalPage*this.params.pagesize
// console.log("res.data:"+res.data)
this.drawSelectData()

})
},
getSummaryPro(){
this.$axios.get('../../api/v1/projectboard/summary',{
}).then((res)=>{
this.tableDataSummary = res.data
this.lastUpdatedTime = res.data.creatTime
})
},
tableHeaderStyle({row,column,rowIndex,columnIndex}){
if(rowIndex===0){
return 'background:#f5f5f6;color:#606266'
}
},
cellStyle({row,column,rowIndex,columnIndex}){
if(rowIndex%2 === 1){
return 'background:#f5f5f6;color:#606266'
}
},
drawSelectData(){
// $("#selectData").removeAttr("selectData").empty();
var xdata=[]
var ydata_add_pro=[]
var ydata_add_public_pro=[]
var ydata_add_private_pro=[]
var ydata_add_self=[]
var ydata_add_fork=[]
var ydata_add_mirror=[]
var ydata_cumulative_pro=[]
// if ()
for(var i =0;i<this.tableData.length;i++){
xdata.push(this.tableData[this.tableData.length-1-i].creatTime);
ydata_add_pro.push(this.tableData[this.tableData.length-1-i].numReposAdd)
ydata_add_public_pro.push(this.tableData[this.tableData.length-1-i].numRepoPublicAdd)
ydata_add_private_pro.push(this.tableData[this.tableData.length-1-i].numRepoPrivateAdd)
ydata_add_self.push(this.tableData[this.tableData.length-1-i].numRepoSelfAdd)
ydata_add_fork.push(this.tableData[this.tableData.length-1-i].numRepoForkAdd)
ydata_add_mirror.push(this.tableData[this.tableData.length-1-i].numRepoMirrorAdd)
ydata_cumulative_pro.push(this.tableData[this.tableData.length-1-i].numRepos)
}
// console.log("ydata_openI:"+ydata_add_pro)
// console.log(xdata)
this.option = {
title : {
text: '',


textStyle: {
                fontSize: 12,
            },
left:'center',
top:'bottom',

subtext: '',

},
tooltip : {
trigger: 'axis',
backgroundColor:'rgba(255,255,255,0.8)',
color:'black',
borderWidth:'1',
borderColor:'gray',
textStyle:{
color:'black'
},
},
legend: {
data:['新增项目','新增公开项目','新增私有项目','新增自建项目','新增派生项目','新增镜像项目','累计项目'],
selected:{
// '新增项目':true,
// '新增公开项目':true,
// '新增私有项目':true,
//                                 '新增自建项目':false,
//                                 '新增派生项目':false,
//                                 '新增镜像项目':false,
//                                 '累计项目':false
                            }
// orient: 'vertical',
// top:'top',  
},
toolbox: {
show : false,
feature : {
mark : {show: true},
dataView : {show: false, readOnly: false},
magicType : {show: true, type: ['line', 'bar']},
restore : {show: false},
saveAsImage : {show: true}
}
},
calculable : true,
xAxis : [
{
type : 'category',
data : xdata,
axisLine: {
show: false, //x轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
yAxis : [
{
type : 'value',
axisLine: {
show: false, //y轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
series : [
{ name:"新增项目",
data: ydata_add_pro,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#3894FF",
},
color:"#3894FF",
}
},
},
{
name:"新增公开项目",
data: ydata_add_public_pro,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#67B3BB",
},
color:"#67B3BB",
}
},
},
{
name:"新增私有项目",
data: ydata_add_private_pro,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#58A55C",
},
color:"#58A55C",
}
},
},
{
name:"新增自建项目",
data: ydata_add_self,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#F2BD42",
},
color:"#F2BD42",
}
},
},
{
name:"新增派生项目",
data: ydata_add_fork,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#DAA67B",
},
color:"#DAA67B",
}
},
},
{
name:"新增镜像项目",
data: ydata_add_mirror,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#2E4552",
},
color:"#2E4552",
}
},
},
{
name:"累计项目",
data: ydata_cumulative_pro,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#4786B4",
},
color:"#4786B4",
}
},
},

]
};
// this.echartsSelectData.resize()
var checkboxs=document.getElementsByName('checkboxchart');
for(var i=0; i<checkboxs.length; i++){
// console.log("selectArr[i]:",this.option.legend.data[i])
if(checkboxs[i].checked){
this.option.legend.selected[this.option.legend.data[i]]=true;
}else{
this.option.legend.selected[this.option.legend.data[i]]=false;
}
}
this.echartsSelectData.setOption(this.option)
// setTimeout(function (){
// window.onresize = function () {
// this.echartsSelectData.resize;
// }
// },200)

// // 使用刚指定的选择项数据显示图表。
// var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值
// var checkboxs=document.getElementsByName('checkboxchart');
// $(".checkboxchart").click(function(){
// var obj = {};
// for(var i=0; i<checkboxs.length; i++){
// if(checkboxs[i].checked){
// obj[selectArr[i]] = true;
// }else{
// obj[selectArr[i]] = false;
// }
// }
// option.legend.selected = obj;
// this.echartsSelectData.setOption(option);
// });


},
clickCheckBox(){
// 使用刚指定的选择项数据显示图表。
var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值
var checkboxs=document.getElementsByName('checkboxchart');
// $(".checkboxchart").click(function(){
var obj = {};
for(var i=0; i<checkboxs.length; i++){
if(checkboxs[i].checked){
obj[selectArr[i]] = true;
}else{
obj[selectArr[i]] = false;
}
}
this.option.legend.selected = obj;
this.echartsSelectData.setOption(this.option);
// });

},
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:{
},


mounted() {

this.getPeriodProList("monthly",4);
this.getSummaryPro();
document.getElementById('selectData').style.width = document.getElementById('pro_tend').offsetWidth*0.8+'px'
this.echartsSelectData = this.$echarts.init(document.getElementById('selectData'))
},

watch:{
},

created() {
this.getSummaryPro();
this.getPeriodProList("monthly",4);
},
updated(){
if(document.querySelectorAll('img[avatar]').length!==0){
window.LetterAvatar.transform()
}
}
}
</script>

<style scoped>
.item_list_first{
border-right: 1px solid rgba(219,219,219,100);
padding-right: 10px;
}

.item_list{
border-right: 1px solid rgba(219,219,219,100);
padding:0px 10px;
}
.item_list_p{
border-right: 1px solid rgba(219,219,219,100);
padding:0px 10px;
}
.item_h{
line-height: 40px;
text-align: center;
}
.item_title_h{
line-height: 28px;
text-align: center;
}
.num_color{
color: #0366D6;
font-weight: bold;
}

.pro_item{
font-size: 16px;
color: rgba(16, 16, 16, 100);
font-family: SourceHanSansSC-bold;
}
.sta_item{
font-size: 14px;
color: rgb(0 0 0);
font-family: SourceHanSansSC-bold;
}
.update_time{
line-height: 17px;
font-size: 12px;
color:rgba(187, 187, 187, 100);
margin-left: 10px;
}
.btnFirst{
line-height: 1.5;
margin: -3.5px;
border: 1px solid rgba(22, 132, 252, 100);
border-right: none;
background: #FFFF;
color: #1684FC;
width: 60px;
height: 30px;
border-radius:4px 0px 0px 4px;
}
.btn{
line-height: 1.5;
margin: -3.5px;
border: 1px solid rgba(22, 132, 252, 100);
border-right: none;
background: #FFFF;
color: #1684FC;
width: 60px;
height: 30px;
}
.btnLast{
line-height: 1.5;
margin: -3.5px;
border: 1px solid rgba(22, 132, 252, 100);
/* border-right: none; */
background: #FFFF;
color: #1684FC;
width: 60px;
height: 30px;
border-radius:0px 4px 4px 0px;
}
.btnFirst, .btn, .btnLast {
cursor: pointer;
}

/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;
}
/deep/ .el-pagination {
padding-bottom: 30px;
}
.colorChange {
background-color: #1684FC;
color: #FFFF;
cursor: default;
}
.items{
text-align: center;
border-right:1px solid rgba(219, 219, 219, 100);
}
.item_l{
margin-right: 5px;
border:1px solid rgba(219, 219, 219, 100);
height: 370px;
width: 100%;
}
.item_r{
margin-right:5px;
border:1px solid rgba(219, 219, 219, 100);
height: 370px;
overflow:auto
}
.item_echart{
margin-top: 10px;
margin-right: 5px;
border:1px solid rgba(219, 219, 219, 100);
height: 350px;
width: 100%;
}
.item_content{
color:#0366D6;
margin-top: 10px;
font-weight:bold;
}
</style>

+ 16
- 13
web_src/js/components/UserAnalysis.vue View File

@@ -1,7 +1,7 @@
<template>
<div>
<div class="el-col el-col-21" style="padding-right:10px">
<div style="margin-top: 10px;">
<b class="pro_item">用户分析</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{lastUpdatedTime}} &nbsp/&nbsp从{{recordBeginTime}}开始统计</span>
<b class="pro_item">活动分析</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{lastUpdatedTime}} &nbsp/&nbsp从{{recordBeginTime}}开始统计</span>
</div>
<div style="margin-top: 20px;">
<span class="sta_iterm">统计周期:</span>
@@ -54,6 +54,7 @@
>
</el-table-column>
<el-table-column
fixed
label="用户名"
align="left"
prop="Name"
@@ -259,7 +260,7 @@
params:{startDate:'',endDate:'',page:1,pageSize:10,userName:''},
tableData: [],
totalNum:0,
dataUrl:'../api/v1/query_user_static_page',
dataUrl:'../../api/v1/query_user_static_page',
pickerOptions: {
},
value_time: '',
@@ -334,7 +335,7 @@
return days;
},
getUpdateTime(){
this.$axios.get('../api/v1/projectboard/project',{
this.$axios.get('../../api/v1/projectboard/project',{
params:this.params_pro
}).then((res)=>{
this.recordBeginTime=res.data.recordBeginTime
@@ -357,7 +358,7 @@
let lastYear = lastMonthDate.getYear();
let lastMonth = lastMonthDate.getMonth();

this.dataUrl = '../api/v1/query_user_static_page';
this.dataUrl = '../../api/v1/query_user_static_page';

if (typeof type_val=="undefined" || type_val=="null" || type_val==""){
this.params.startDate= this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate());
@@ -366,37 +367,37 @@
switch(type_val){
case "yesterday_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_yesterday';
this.dataUrl = '../../api/v1/query_user_yesterday';
break
}
case "current_week_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_current_week';
this.dataUrl = '../../api/v1/query_user_current_week';
break
}
case "current_month_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_current_month';
this.dataUrl = '../../api/v1/query_user_current_month';
break
}
case "last_month_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_last_month';
this.dataUrl = '../../api/v1/query_user_last_month';
break
}
case "monthly_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_last30_day';
this.dataUrl = '../../api/v1/query_user_last30_day';
break
}
case "current_year_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_current_year';
this.dataUrl = '../../api/v1/query_user_current_year';
break
}
case "all_usr":{
this.value_time=[]
this.dataUrl = '../api/v1/query_user_all';
this.dataUrl = '../../api/v1/query_user_all';
break
}
}
@@ -561,7 +562,9 @@
/deep/ .el-range-separator{
width: 20% !important;
}

/deep/ .el-pagination {
padding-bottom: 30px;
}
.colorChange {
background-color: #1684FC;
color: #FFFF;


+ 942
- 0
web_src/js/components/UserTrend.vue View File

@@ -0,0 +1,942 @@
<template>
<div class="el-col el-col-21" style="padding-right:10px">
<div id='user_tend'>
<div style="margin-top: 10px;">
<b class="pro_item">增长趋势分析</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{lastUpdatedTime}} &nbsp/&nbsp从{{recordBeginTime}}开始统计</span>
</div>
<div id = 'isShow'>
<el-col :span="11">
<el-col id="ys_add_user" class="draw_region">

</el-col>
<el-col :span="8" :style="{ height: '180px'}" v-if="ys_count>0">
<span class="yesterday_blk yesterday_title" >昨日新增注册用户数 </span>
<span class="yesterday_blk yesterday_color1 yesterday_pdrt yesterday_text">未激活:<span class="bold_num">{{ tableDataYesterday.NotActivateRegistUser }}</span> 人 </span>
<span class="yesterday_blk yesterday_color2 yesterday_pdrt yesterday_text">已激活: <span class="bold_num">{{ tableDataYesterday.ActivateRegistUser }} </span>人</span>
<span class="yesterday_blk yesterday_pdrt yesterday_text">有贡献活动: <span class="bold_num">{{ tableDataYesterday.RegistActivityUser }} </span>人</span>
</el-col>
</el-col>
<el-col :span="13">
<el-col id="ys_all_user" class="draw_region">

</el-col>
<el-col :span="8" :style="{ height: '180px'}" v-if="ys_count>0">
<span class="yesterday_blk yesterday_title" >注册用户数 </span>
<span class="yesterday_blk yesterday_color1 yesterday_pdrt yesterday_text">未激活:<span class="bold_num">{{ tableDataYesterday.TotalActivateRegistUser}} </span>人 </span>
<span class="yesterday_blk yesterday_color2 yesterday_pdrt yesterday_text">已激活:<span class="bold_num">{{ tableDataYesterday.TotalNotActivateRegistUser }} </span>人</span>
<span class="yesterday_blk yesterday_pdrt yesterday_text">有贡献活动:<span class="bold_num"> {{ tableDataYesterday.TotalHasActivityUser}} </span>人</span>
</el-col>
</el-col>
</div>

<div style="margin-top: 20px;">
<span class="sta_iterm">统计周期:</span>
<button type="button" class='btn' id = "current_week_usr" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getUserList('current_week_usr',1)">本周</button>
<button type="button" class='btn' id = "current_month_usr" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getUserList('current_month_usr',2)">本月</button>
<button type="button" class='btn' id = "last_month_usr" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getUserList('last_month_usr',3)">上月</button>
<button type="button" class='btn' id = "monthly_usr" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getUserList('monthly_usr',4)">近30天</button>
<button type="button" class='btn' id = "current_year_usr" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getUserList('current_year_usr',5)">今年</button>
<button type="button" class='btnLast' id = "all_usr" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getUserList('all_usr',6)">所有</button>
<span style="margin-left: 20px;">
<el-date-picker
v-model="value_time"
prefix-icon="el-icon-time"
@change="resetPage(),getUserList('',0)"
type="daterange"
size='small'
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</span>
<span style="float:right; margin-right: 20px;" >
<a style="display:inline-block;margin-left: 20px; " id = 'download'>
<a class="el-icon-download" v-if="tableData!=''" :href= "this.dataUrl + '?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true' " ></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= "this.dataUrl + '?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true' " >下载报告</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" @click="searchName() "></i>
</el-input>
</span> -->
</span>
</div>

<div class="item_echart" id ='linecharts'>
<div style="margin: 15px 10px 30px;">
<label for="label" @change='clickCheckBox'>
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增项目"/> 新增注册用户
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增公开项目"/>新增已激活
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增私有项目"/>新增有贡献活动
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增自建项目"/>新增未激活
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增派生项目"/>累计注册用户
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增镜像项目"/>累计已激活
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="累计项目"/>累计有贡献活动
</label>
</div>
<div id ="selectData" style="height: 300px;">

</div>

</div>

<div style="margin-top: 30px;">
<el-table
:data="tableData.slice((page-1)*pageSize,page*pageSize)"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style='cellStyle'>
<el-table-column
label="日期"
prop="DisplayDate"
align="center"
stripe
>
</el-table-column>
<el-table-column
label="新增注册用户"
prop="TotalRegistUser"
align="center">
</el-table-column>
<el-table-column
prop="ActivateRegistUser"
label="新增已激活"
width="120px"
align="center">
</el-table-column>
<el-table-column
prop="RegistActivityUser"
label="新增有贡献活动"
align="center">
</el-table-column>
<el-table-column
prop="NotActivateRegistUser"
label="新增未激活"
align="center">
</el-table-column>
<el-table-column
prop="ActivateIndex"
label="新增用户激活率"
align="center">
</el-table-column>
<el-table-column
prop="TotalUser"
label="累计注册用户"
align="center">
</el-table-column>
<el-table-column
prop="TotalActivateRegistUser"
label="累计已激活"
align="center">
</el-table-column>

<el-table-column
prop="TotalHasActivityUser"
label="累计有贡献活动"
align="center">
</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="page"
:page-size="pageSize"
:page-sizes="[5,10,20]"
layout="total, sizes, prev, pager, next,jumper"
:total="tableData.length">
</el-pagination>
</div>
</div>
</div>
</template>

<script>
import { export2Excel } from '../excel/util.js'
export default{
name:'UserAnalysis',
data() {
return {
type_val:'',
recordBeginTime:'',
lastUpdatedTime:'',
page:1,
pageSize:10,
params:{startDate:'',endDate:''},
tableData: [],
totalNum:0,
dataUrl:'../../api/v1/query_user_metrics_page',
dataYesterdayUrl:'../../api/v1/query_metrics_yesterday',
ys_count:0,
tableDataYesterday: {},
option:'',
optionYesterdayUser:'',
optionYesterdaAllUser:'',
echartsSelectData:'',
echartsYsAddUser:'',
echartsYsAllUser:'',
pickerOptions: {
},
value_time: '',
search:'',
data:'',
// 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:'CloudBrainTaskNum'},{title:'云脑运行时间(小时)',key:'CloudBrainRunTime'},{title:'上传(提交)数据集文件数',key:'CommitDatasetNum'},{title:'提交模型数',key:'CommitModelCount'},{title:'用户指数',key:'UserIndex'},{title:'系统统计时间',key:'CountDate'}],
blob:'',
fileName:'',
dynamic:4,

params_pro:{type:'all',page:1,pagesize:10,beginTime:'',endTime:'',q:'',sort:'openi'},
};
},
methods: {

popMark(){
alert("数据为空时,不能下载!")
},
// exportData(){
// // this.getUserList('all_usr',7)
// var saveFileName = this.getFileName()
// export2Excel(this.columns,this.tableData,saveFileName)
// },
// getFileName(){
// var saveFileName=''
// var Date=(this.params.startDate).split('-')
// var startDate=Date[0]+''+Date[1]+''+Date[2]
// Date=(this.params.endDate).split('-')
// var endDate=Date[0]+Date[1]+Date[2]
// saveFileName = '用户分析_'+this.search+''+startDate+'_'+endDate
// if (this.type_val=='all_usr'){
// saveFileName = '用户分析_'+this.search+'_all'
// }
// return saveFileName

// },
handleCurrentChange(val){
this.page = val
},
handleSizeChange(val){
this.pageSize = val
},
resetPage(){
this.page=1
},
addUser(val1, val2){
return (val1+val2)

},
formatDate(myyear,mymonth,myweekday) {
// var myyear = this.date.getFullYear();
// var mymonth = this.date.getMonth() + 1;
// var myweekday = this.date.getDate();
if (mymonth < 10) {
mymonth = "0" + mymonth;
}
if (myweekday < 10) {
myweekday = "0" + myweekday;
}
return (myyear + "-" + mymonth + "-" + myweekday);
},

// 获得某月的天数
getMonthDays(nowYear,month){
let monthStartDate = new Date(nowYear, month, 1);
let monthEndDate = new Date(nowYear, month + 1, 1);
let days = (monthEndDate - monthStartDate)/(1000 * 60 * 60 * 24);
return days;
},
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;
var now = new Date(); // 当前日期
var nowDayOfWeek = now.getDay(); // 今天本周的第几天
var nowDay = now.getDate(); // 当前日
var nowMonth = now.getMonth(); // 当前月
var nowYear = now.getFullYear(); // 当前年
var today = this.formatDate(nowYear,nowMonth+1,nowDay);

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

this.dataUrl = '../../api/v1/query_user_metrics_page';

if (typeof type_val=="undefined" || type_val=="null" || type_val==""){
this.params.startDate= this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate());
this.params.endDate = this.formatDate(this.value_time[1].getFullYear(),this.value_time[1].getMonth() + 1,this.value_time[1].getDate());
}else{
switch(type_val){
case "yesterday_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_user_yesterday';
break
}
case "current_week_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_metrics_current_week';
break
}
case "current_month_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_metrics_current_month';
break
}
case "last_month_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_metrics_last_month';
break
}
case "monthly_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_metrics_last30_day';
break
}
case "current_year_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_metrics_current_year';
break
}
case "all_usr":{
this.value_time=[]
this.dataUrl = '../../api/v1/query_metrics_all';
break
}
}
};

this.$axios.get(this.dataUrl,{
params:this.params
}).then((res)=>{
this.tableData = res.data.data
// console.log("res.data:"+res.data.data)
this.totalNum = res.data.count
this.drawSelectData()
})

},
getYesterdayUser(){
this.$axios.get(this.dataYesterdayUrl,{
}).then((res)=>{
this.ys_count = res.data.count
this.tableDataYesterday = res.data.data[0]
if(this.ys_count>0){
this.drawYesterdayUser()
this.drawSumUser()
}else{
document.getElementById("isShow").style.display='none'
}
})
},
drawYesterdayUser(){
this.optionYesterdayUser = {
tooltip: {
trigger: 'item',
show:false
},
legend: {
top: '5%',
left: 'center',
show:false
},
// graphic:{
// type:'text',
// left:'center',
// top:'center',
// style:{
// text:this.tableDataYesterday.TotalRegistUser,
// fontSize:18,
// fontWeight:'bold',
// color:'#101010'
// }
// },
color:['#5087Ec','#DBDBDB'],
series: [
{
name: '',
type: 'pie',
radius: ['65%', '70%'],
center:['50%','50%'],
avoidLabelOverlap: false,
label: {
normal:{
show: true,
position: 'center',
formatter:''+this.tableDataYesterday.TotalRegistUser,
fontSize:18,
fontWeight:'bold',
color:'#101010'
}
},
emphasis: {
label: {
show: false,
fontSize: '40',
fontWeight: 'bold'
}
},
labelLine: {
normal:{
show:false
}
},
data: [
{ value: this.tableDataYesterday.ActivateRegistUser, name: '已激活' },
{ value: this.tableDataYesterday.NotActivateRegistUser, name: '未激活'},
],
hoverAnimation:false,
}
]
};
this.echartsYsAddUser.setOption(this.optionYesterdayUser)
},
drawSumUser(){
this.optionYesterdaAllUser = {
tooltip: {
trigger: 'item',
show:false
},
legend: {
top: '5%',
left: 'center',
show:false
},
// graphic:{
// type:'text',
// left:'center',
// top:'center',
// style:{
// text:this.tableDataYesterday.TotalRegistUser,
// fontSize:18,
// fontWeight:'bold',
// color:'#101010'
// }
// },
color:['#5087Ec','#DBDBDB'],
series: [
{
name: '',
type: 'pie',
radius: ['65%', '70%'],
center:['50%','50%'],
avoidLabelOverlap: false,
label: {
normal:{
show: true,
position: 'center',
formatter:''+this.tableDataYesterday.TotalUser,
fontSize:18,
fontWeight:'bold',
color:'#101010'
}
},
emphasis: {
label: {
show: false,
fontSize: '40',
fontWeight: 'bold'
}
},
labelLine: {
normal:{
show:false
}
},
data: [
{ value: this.tableDataYesterday.TotalActivateRegistUser, name: '已激活' },
{ value: this.tableDataYesterday.TotalNotActivateRegistUser, name: '未激活'},
],
hoverAnimation:false,
}
]
};
this.echartsYsAllUser.setOption(this.optionYesterdaAllUser)

},
// searchName(){
// this.params.userName = this.search
// this.params.page = 1
// this.page=1
// this.getUserList(this.type_val, this.dynamic)

// },
tableHeaderStyle({row,column,rowIndex,columnIndex}){
if(rowIndex===0){
return 'background:#f5f5f6;color:#606266'
}
},
cellStyle({row,column,rowIndex,columnIndex}){
if(rowIndex%2 === 1){
return 'background:#f5f5f6;color:#606266'
}
},
drawSelectData(){
// $("#selectData").removeAttr("selectData").empty();
var xdata=[]
var ydata_TotalRegistUser=[]
var ydata_ActivateRegistUser=[]
var ydata_NotActivateRegistUser=[]
var ydata_RegistActivityUser=[]
var ydata_TotalUser=[]
var ydata_TotalActivateRegistUser=[]
var ydata_TotalHasActivityUser=[]
// if ()
for(var i =0;i<this.tableData.length;i++){
xdata.push(this.tableData[this.tableData.length-1-i].DisplayDate);
ydata_TotalRegistUser.push(this.tableData[this.tableData.length-1-i].TotalRegistUser)
ydata_ActivateRegistUser.push(this.tableData[this.tableData.length-1-i].ActivateRegistUser)
ydata_RegistActivityUser.push(this.tableData[this.tableData.length-1-i].RegistActivityUser)
ydata_NotActivateRegistUser.push(this.tableData[this.tableData.length-1-i].NotActivateRegistUser)
ydata_TotalUser.push(this.tableData[this.tableData.length-1-i].TotalUser)
ydata_TotalActivateRegistUser.push(this.tableData[this.tableData.length-1-i].TotalActivateRegistUser)
ydata_TotalHasActivityUser.push(this.tableData[this.tableData.length-1-i].TotalHasActivityUser)
}

this.option = {
title : {
text: '',


textStyle: {
                fontSize: 12,
            },
left:'center',
top:'bottom',

subtext: '',

},
tooltip : {
trigger: 'axis',
backgroundColor:'rgba(255,255,255,0.8)',
color:'black',
borderWidth:'1',
borderColor:'gray',
textStyle:{
color:'black'
},
},
legend: {
data:['新增注册用户','新增已激活','新增有贡献活动','新增未激活','累计注册用户','累计已激活','累计有贡献活动'],
selected:{
// '新增注册用户':true,
// '新增已激活':true,
// '新增有贡献活动':true,
// '新增未激活':false,
// '累计注册用户':false,
// '累计已激活':false,
// '累计有贡献活动':false
}
// orient: 'vertical',
// top:'top',  
},
toolbox: {
show : false,
feature : {
mark : {show: true},
dataView : {show: false, readOnly: false},
magicType : {show: true, type: ['line', 'bar']},
restore : {show: false},
saveAsImage : {show: true}
}
},
calculable : true,
xAxis : [
{
type : 'category',
data : xdata,
axisLine: {
show: false, //x轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
yAxis : [
{
type : 'value',
axisLine: {
show: false, //y轴线消失
},
axisTick:{
show:false//刻度隐藏
}
}
],
series : [
{ name:"新增注册用户",
data: ydata_TotalRegistUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#3894FF ",
},
color:"#3894FF ",
}
},
},
{
name:"新增已激活",
data: ydata_ActivateRegistUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#67B3BB",
},
color:"#67B3BB",
}
},
},
{
name:"新增有贡献活动",
data: ydata_RegistActivityUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#58A55C",
},
color:"#58A55C",
}
},
},
{
name:"新增未激活",
data: ydata_NotActivateRegistUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#F2BD42",
},
color:"#F2BD42",
}
},
},
{
name:"累计注册用户",
data: ydata_TotalUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#2E4552",
},
color:"#2E4552",
}
},
},
{
name:"累计已激活",
data: ydata_TotalActivateRegistUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#4786B4",
},
color:"#4786B4",
}
},
},
{
name:"累计有贡献活动",
data: ydata_TotalHasActivityUser,
type: 'line',
areaStyle: {},
itemStyle:{
normal:{
lineStyle:{
color:"#4E9C8F",
},
color:"#4E9C8F",
}
},
},

]
};
// this.echartsSelectData.resize()
var checkboxs=document.getElementsByName('checkboxchart');
// $(".checkboxchart").click(function(){
for(var i=0; i<checkboxs.length; i++){
// console.log("selectArr[i]:",this.option.legend.data[i])
if(checkboxs[i].checked){
this.option.legend.selected[this.option.legend.data[i]]=true;
}else{
this.option.legend.selected[this.option.legend.data[i]]=false;
}
}
this.echartsSelectData.setOption(this.option)
// this.clickCheckBox()
// setTimeout(function (){
// window.onresize = function () {
// this.echartsSelectData.resize;
// }
// },200)

// // 使用刚指定的选择项数据显示图表。
// var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值
// var checkboxs=document.getElementsByName('checkboxchart');
// $(".checkboxchart").click(function(){
// var obj = {};
// for(var i=0; i<checkboxs.length; i++){
// if(checkboxs[i].checked){
// obj[selectArr[i]] = true;
// }else{
// obj[selectArr[i]] = false;
// }
// }
// option.legend.selected = obj;
// this.echartsSelectData.setOption(option);
// });


},
clickCheckBox(){
// 使用刚指定的选择项数据显示图表。
var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值
var checkboxs=document.getElementsByName('checkboxchart');
// $(".checkboxchart").click(function(){
var obj = {};
for(var i=0; i<checkboxs.length; i++){
if(checkboxs[i].checked){
obj[selectArr[i]] = true;
}else{
obj[selectArr[i]] = false;
}
}
// console.log("obj:",obj)
this.option.legend.selected = obj;
this.echartsSelectData.setOption(this.option);
// });

},

},
filters:{
rounding (value) {
return Number(value).toFixed(2)
},
roundingToHour (value) {
return (Number(value)/3600).toFixed(2)
},
transformTimestamp(timestamp){
let a = new Date(timestamp*1000);
const date = new Date(a);
const Y = date.getFullYear() + '/';
const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/';
const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' ';
const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':';
const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes());// + ':' ;
// const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒
const dateString = Y + M + D + h + m ;//+ s;
return dateString;
},
addUser(val1,val2){
return val1+val2
}
},
mounted() {
// document.getElementById("all_usr").style.outline="none"
// document.getElementById("all_usr").focus()
this.getUpdateTime()
this.getUserList("monthly_usr",4)
this.getYesterdayUser()

document.getElementById('selectData').style.width = document.getElementById('user_tend').offsetWidth*0.8+'px'
this.echartsSelectData = this.$echarts.init(document.getElementById('selectData'))
this.echartsYsAddUser = this.$echarts.init(document.getElementById('ys_add_user'))
this.echartsYsAllUser = this.$echarts.init(document.getElementById('ys_all_user'))
},
created() {
this.getUserList("monthly_usr",4)
this.getYesterdayUser()
},
watch:{
// search(val){
// if(!val){
// this.params.userName = this.search
// this.params.page = 1
// this.page=1
// this.getUserList(this.type_val, this.dynamic)
// }
// }
},
}
</script>

<style scoped>
.pro_item{
font-size: 16px;
color: rgba(16, 16, 16, 100);
font-family: SourceHanSansSC-bold;
}
.sta_item{
font-size: 14px;
color: rgb(0 0 0);
font-family: SourceHanSansSC-bold;
}
.update_time{
line-height: 17px;
font-size: 12px;
color:rgba(187, 187, 187, 100);
margin-left: 10px;
}
/* .btn{
line-height: 1.5;
margin: -3px;
border: 1px solid #409effd6;
background: #FFFF;
color: #409eff;
width: 60px;
height: 30px;
border-radius:4px ;
} */
.btnFirst{
line-height: 1.5;
margin: -3.5px;
border: 1px solid rgba(22, 132, 252, 100);
border-right: none;
background: #FFFF;
color: #1684FC;
width: 60px;
height: 30px;
border-radius:4px 0px 0px 4px;
}
.btn{
line-height: 1.5;
margin: -3.5px;
border: 1px solid rgba(22, 132, 252, 100);
border-right: none;
background: #FFFF;
color: #1684FC;
width: 60px;
height: 30px;
}
.btnLast{
line-height: 1.5;
margin: -3.5px;
border: 1px solid rgba(22, 132, 252, 100);
/* border-right: none; */
background: #FFFF;
color: #1684FC;
width: 60px;
height: 30px;
border-radius:0px 4px 4px 0px;
}
.btnFirst,.btn,.btnLast {
cursor: pointer;
}


/* .btn:focus,
.btn:active{
background-color:#409effd6 ;
} */
/* /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;
}
/deep/ .el-pagination {
padding-bottom: 30px;
}
.colorChange {
background-color: #1684FC;
color: #FFFF;
cursor: default;
}
.item_echart{
margin-top: 10px;
margin-right: 5px;
border:1px solid rgba(219, 219, 219, 100);
height: 350px;
width: 100%;
}
.yesterday_blk{
display: block;
margin-top:40px
}
.yesterday_pdrt{
padding-left: 10px;
}
.yesterday_color1{
border-left: 3px solid #DBDBDB;
}
.yesterday_color2{
border-left: 3px solid #5087Ec;
}
.yesterday_title{
font-size: 14px;
font-weight: bold;
}
.yesterday_text{
font-size: 12px;
line-height: 12px;
color: #888888;
margin-top: 10px;
}
.bold_num{
font-weight: bold;
}
.draw_region{
width: 180px;
height: 180px;
}
</style>

+ 2
- 1
web_src/js/index.js View File

@@ -45,6 +45,7 @@ import WxAutorize from './components/WxAutorize.vue'
import initCloudrain from './features/cloudrbanin.js'
import initImage from './features/images.js'
// import $ from 'jquery.js'
import router from './router/index.js'

Vue.use(ElementUI);
Vue.prototype.$axios = axios;
@@ -4474,7 +4475,7 @@ function initVueDataAnalysis() {

new Vue({
el: '#data_analysis',
router,
render: h => h(DataAnalysis)
});
}


+ 64
- 0
web_src/js/router/index.js View File

@@ -0,0 +1,64 @@
import Vue from 'vue'
import Router from 'vue-router'
import DataAnalysis from '../components/DataAnalysis.vue'
import ProAnalysis from '../components/ProAnalysis.vue'
import ProTrend from '../components/ProTrend.vue'
import UserTrend from '../components/UserTrend.vue'
import UserAnalysis from '../components/UserAnalysis.vue'
import BrainAnalysis from '../components/BrainAnalysis.vue'
import Overview from '../components/Overview.vue'

const originalPush = Router.prototype.push

Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
Vue.use(Router)

export default new Router({
mode: 'history',
base: '/explore/data_analysis/', //添加根目录
scrollBehavior: () => ({ y: 0 }),
routes:[
{
path:'/',redirect:'/ProAnalysis',
name:'ProAnalysis',
component:ProAnalysis,
},

{
path:'/Overview',
name:'Overview',
component:Overview,
},
{
path:'/ProTrend',
name:'ProTrend',
component:ProTrend,
},
{
path:'/ProAnalysis',
name:'ProAnalysis',
component:ProAnalysis,
},
{
path:'/UserAnalysis',
name:'UserAnalysis',
component:UserAnalysis,
},
{
path:'/UserTrend',
name:'UserTrend',
component:UserTrend,
},

{
path:'/BrainAnalysis',
name:'BrainAnalysis',
component:BrainAnalysis,
},

],


})

Loading…
Cancel
Save