You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@answer.apache.org by li...@apache.org on 2024/12/09 03:52:40 UTC

(incubator-answer) 15/38: feat: Add key metrics to the dashboard

This is an automated email from the ASF dual-hosted git repository.

linkinstar pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit 98eceff5494a2114cbe0c2846785320acc14addc
Author: sy-records <52...@qq52o.cn>
AuthorDate: Thu Nov 14 17:37:43 2024 +0800

    feat: Add key metrics to the dashboard
---
 i18n/en_US.yaml                                    |  2 ++
 i18n/zh_CN.yaml                                    |  2 ++
 internal/repo/question/question_repo.go            | 23 +++++++++++++++++
 internal/schema/dashboard_schema.go                |  4 +++
 internal/service/dashboard/dashboard_service.go    | 29 +++++++++++++++++++++-
 internal/service/question_common/question.go       |  2 ++
 ui/src/common/interface.ts                         |  4 +++
 .../Dashboard/components/Statistics/index.tsx      | 22 ++++++++++++++++
 8 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 6f3f5215..775d7456 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -1762,6 +1762,8 @@ ui:
       welcome: Welcome to Admin!
       site_statistics: Site statistics
       questions: "Questions:"
+      resolved: "Resolved:"
+      unanswered: "Unanswered:"
       answers: "Answers:"
       comments: "Comments:"
       votes: "Votes:"
diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml
index 85581968..d0feebb9 100644
--- a/i18n/zh_CN.yaml
+++ b/i18n/zh_CN.yaml
@@ -1722,6 +1722,8 @@ ui:
       welcome: 欢迎来到管理后台!
       site_statistics: 站点统计
       questions: "问题:"
+      resolved: "已解决:"
+      unanswered: "未回复:"
       answers: "回答:"
       comments: "评论:"
       votes: "投票:"
diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go
index 16b6085f..1132501e 100644
--- a/internal/repo/question/question_repo.go
+++ b/internal/repo/question/question_repo.go
@@ -284,6 +284,29 @@ func (qr *questionRepo) GetQuestionCount(ctx context.Context) (count int64, err
 	return count, nil
 }
 
+func (qr *questionRepo) GetUnansweredQuestionCount(ctx context.Context) (count int64, err error) {
+	session := qr.data.DB.Context(ctx)
+	session.Where(builder.Lt{"status": entity.QuestionStatusDeleted}).
+		And(builder.Eq{"answer_count": 0})
+	count, err = session.Count(&entity.Question{Show: entity.QuestionShow})
+	if err != nil {
+		return 0, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+	}
+	return count, nil
+}
+
+func (qr *questionRepo) GetResolvedQuestionCount(ctx context.Context) (count int64, err error) {
+	session := qr.data.DB.Context(ctx)
+	session.Where(builder.Lt{"status": entity.QuestionStatusDeleted}).
+		And(builder.Neq{"answer_count": 0}).
+		And(builder.Neq{"accepted_answer_id": 0})
+	count, err = session.Count(&entity.Question{Show: entity.QuestionShow})
+	if err != nil {
+		return 0, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+	}
+	return count, nil
+}
+
 func (qr *questionRepo) GetUserQuestionCount(ctx context.Context, userID string, show int) (count int64, err error) {
 	session := qr.data.DB.Context(ctx)
 	session.Where(builder.Lt{"status": entity.QuestionStatusDeleted})
diff --git a/internal/schema/dashboard_schema.go b/internal/schema/dashboard_schema.go
index 2d780b8c..c2c7677d 100644
--- a/internal/schema/dashboard_schema.go
+++ b/internal/schema/dashboard_schema.go
@@ -30,6 +30,10 @@ const (
 
 type DashboardInfo struct {
 	QuestionCount         int64                `json:"question_count"`
+	ResolvedCount         int64                `json:"resolved_count"`
+	ResolvedRate          string               `json:"resolved_rate"`
+	UnansweredCount       int64                `json:"unanswered_count"`
+	UnansweredRate        string               `json:"unanswered_rate"`
 	AnswerCount           int64                `json:"answer_count"`
 	CommentCount          int64                `json:"comment_count"`
 	VoteCount             int64                `json:"vote_count"`
diff --git a/internal/service/dashboard/dashboard_service.go b/internal/service/dashboard/dashboard_service.go
index 67abc2a7..ebc9a79d 100644
--- a/internal/service/dashboard/dashboard_service.go
+++ b/internal/service/dashboard/dashboard_service.go
@@ -103,7 +103,6 @@ func (ds *dashboardService) Statistical(ctx context.Context) (*schema.DashboardI
 	dashboardInfo := ds.getFromCache(ctx)
 	if dashboardInfo == nil {
 		dashboardInfo = &schema.DashboardInfo{}
-		dashboardInfo.QuestionCount = ds.questionCount(ctx)
 		dashboardInfo.AnswerCount = ds.answerCount(ctx)
 		dashboardInfo.CommentCount = ds.commentCount(ctx)
 		dashboardInfo.UserCount = ds.userCount(ctx)
@@ -121,6 +120,18 @@ func (ds *dashboardService) Statistical(ctx context.Context) (*schema.DashboardI
 		dashboardInfo.DatabaseSize = ds.GetDatabaseSize()
 	}
 
+	dashboardInfo.QuestionCount = ds.questionCount(ctx)
+	dashboardInfo.UnansweredCount = ds.unansweredQuestionCount(ctx)
+	dashboardInfo.ResolvedCount = ds.resolvedQuestionCount(ctx)
+
+	if dashboardInfo.QuestionCount == 0 {
+		dashboardInfo.ResolvedRate = "0.00"
+		dashboardInfo.UnansweredRate = "0.00"
+	} else {
+		dashboardInfo.ResolvedRate = fmt.Sprintf("%.2f", float64(dashboardInfo.ResolvedCount)/float64(dashboardInfo.QuestionCount)*100)
+		dashboardInfo.UnansweredRate = fmt.Sprintf("%.2f", float64(dashboardInfo.UnansweredCount)/float64(dashboardInfo.QuestionCount)*100)
+	}
+
 	dashboardInfo.ReportCount = ds.reportCount(ctx)
 	dashboardInfo.SMTP = ds.smtpStatus(ctx)
 	dashboardInfo.HTTPS = ds.httpsStatus(ctx)
@@ -170,6 +181,22 @@ func (ds *dashboardService) questionCount(ctx context.Context) int64 {
 	return questionCount
 }
 
+func (ds *dashboardService) unansweredQuestionCount(ctx context.Context) int64 {
+	unansweredQuestionCount, err := ds.questionRepo.GetUnansweredQuestionCount(ctx)
+	if err != nil {
+		log.Errorf("get unanswered question count failed: %s", err)
+	}
+	return unansweredQuestionCount
+}
+
+func (ds *dashboardService) resolvedQuestionCount(ctx context.Context) int64 {
+	resolvedQuestionCount, err := ds.questionRepo.GetResolvedQuestionCount(ctx)
+	if err != nil {
+		log.Errorf("get resolved question count failed: %s", err)
+	}
+	return resolvedQuestionCount
+}
+
 func (ds *dashboardService) answerCount(ctx context.Context) int64 {
 	answerCount, err := ds.answerRepo.GetAnswerCount(ctx)
 	if err != nil {
diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go
index 13df3389..08c74f29 100644
--- a/internal/service/question_common/question.go
+++ b/internal/service/question_common/question.go
@@ -74,6 +74,8 @@ type QuestionRepo interface {
 	FindByID(ctx context.Context, id []string) (questionList []*entity.Question, err error)
 	AdminQuestionPage(ctx context.Context, search *schema.AdminQuestionPageReq) ([]*entity.Question, int64, error)
 	GetQuestionCount(ctx context.Context) (count int64, err error)
+	GetUnansweredQuestionCount(ctx context.Context) (count int64, err error)
+	GetResolvedQuestionCount(ctx context.Context) (count int64, err error)
 	GetUserQuestionCount(ctx context.Context, userID string, show int) (count int64, err error)
 	SitemapQuestions(ctx context.Context, page, pageSize int) (questionIDList []*schema.SiteMapQuestionInfo, err error)
 	RemoveAllUserQuestion(ctx context.Context, userID string) (err error)
diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts
index 8a933471..903c5c28 100644
--- a/ui/src/common/interface.ts
+++ b/ui/src/common/interface.ts
@@ -524,6 +524,10 @@ export interface SearchRes extends ListResult<SearchResItem> {
 export interface AdminDashboard {
   info: {
     question_count: number;
+    resolved_count: number;
+    resolved_rate: string;
+    unanswered_count: number;
+    unanswered_rate: string;
     answer_count: number;
     comment_count: number;
     vote_count: number;
diff --git a/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx b/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx
index c95eaba7..a3077ba4 100644
--- a/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx
+++ b/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx
@@ -39,6 +39,28 @@ const Statistics: FC<IProps> = ({ data }) => {
             <span className="text-secondary me-1">{t('questions')}</span>
             <strong>{data.question_count}</strong>
           </Col>
+          <Col xs={6} className="mb-1">
+            <span className="text-secondary me-1">{t('resolved')}</span>
+            <strong>{data.resolved_count}</strong>
+            {data.resolved_count > 0 ? (
+              <span className="text-secondary m-1">
+                ({data.resolved_rate}%)
+              </span>
+            ) : (
+              ''
+            )}
+          </Col>
+          <Col xs={6} className="mb-1">
+            <span className="text-secondary me-1">{t('unanswered')}</span>
+            <strong>{data.unanswered_count}</strong>
+            {data.unanswered_count > 0 ? (
+              <span className="text-secondary m-1">
+                ({data.unanswered_rate}%)
+              </span>
+            ) : (
+              ''
+            )}
+          </Col>
           <Col xs={6} className="mb-1">
             <span className="text-secondary me-1">{t('answers')}</span>
             <strong>{data.answer_count}</strong>