This is an automated email from the ASF dual-hosted git repository.
linkinstar pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
The following commit(s) were added to refs/heads/dev by this push:
new 6049b5e8 feat: Add key metrics to the dashboard
6049b5e8 is described below
commit 6049b5e8835268a9778d763665b616492d4049e1
Author: sy-records <[email protected]>
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 6427a346..cc30f6ea 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>