Browse Source

Update statistics service

pull/1619/head
Hironsan 3 years ago
parent
commit
4e36598350
6 changed files with 49 additions and 206 deletions
  1. 87
      frontend/domain/models/statistics/statistics.ts
  2. 7
      frontend/domain/models/statistics/statisticsRepository.ts
  3. 104
      frontend/pages/projects/_id/statistics/index.vue
  4. 20
      frontend/repositories/statistics/apiStatisticsRepository.ts
  5. 17
      frontend/services/application/statistics/statisticsApplicationService.ts
  6. 20
      frontend/services/application/statistics/statisticsData.ts

87
frontend/domain/models/statistics/statistics.ts

@ -1,87 +1,8 @@
export type Label = {[key: string]: number}
export type User = {[key: string]: number}
export type ConfirmedCount = {[key: string]: number}
export class Statistics {
constructor(
public label: Label,
public userLabel: User,
public total: number,
public remaining: number,
public user: User,
public confirmedCount: ConfirmedCount,
) {}
static valueOf(
{ label, user_label, total, remaining, user, confirmed_count }:
{
label: Label,
user_label: User,
total: number,
remaining: number,
user: User,
confirmed_count: ConfirmedCount,
}
): Statistics {
return new Statistics(label, user_label, total, remaining, user, confirmed_count)
}
private makeData(object: Label | User, label: string) {
const labels = object ? Object.keys(object) : []
const counts = object ? Object.values(object) : []
return {
labels,
datasets: [{
label,
backgroundColor: '#00d1b2',
data: counts
}]
}
}
public labelStats(label: string) {
return this.makeData(this.label, label)
}
public userStats(label: string) {
return this.makeData(this.user, label)
}
public progress(labels: string[]) {
const complete = this.total - this.remaining
const incomplete = this.remaining
return {
datasets: [{
data: [complete, incomplete],
backgroundColor: ['#00d1b2', '#ffdd57']
}],
labels
}
}
private makeProgressData(roleName: string, labels: string[]) {
const confirmed = this.confirmedCount[roleName]
const unconfirmed = this.total - confirmed
return {
datasets: [{
data: [confirmed, unconfirmed],
backgroundColor: ['#00d1b2', '#ffdd57']
}],
labels
}
}
public annotatorProgress(labels: string[]) {
return this.makeProgressData('annotator', labels)
}
public approverProgress(labels: string[]) {
return this.makeProgressData('annotation_approver', labels)
}
public adminProgress(labels: string[]) {
return this.makeProgressData('project_admin', labels)
}
export type Distribution = {[user: string]: {[label: string]: number}}
export interface Progress {
total: number
progress: {user: string, done: number}[]
}

7
frontend/domain/models/statistics/statisticsRepository.ts

@ -1,6 +1,7 @@
import { Statistics } from '~/domain/models/statistics/statistics'
import { Distribution, Progress } from '~/domain/models/statistics/statistics'
export interface StatisticsRepository {
fetch(projectId: string): Promise<Statistics>
fetchCategoryDistribution(projectId: string): Promise<Distribution>
fetchSpanDistribution(projectId: string): Promise<Distribution>
fetchMemberProgress(projectId: string): Promise<Progress>
}

104
frontend/pages/projects/_id/statistics/index.vue

@ -1,109 +1,33 @@
<template>
<v-row v-if="!isEmpty">
<v-col
cols="12"
lg="4"
>
<v-card>
<v-card-title>{{ $t('members.roles.annotator') }}</v-card-title>
<v-card-text>
<doughnut-chart
:chart-data="stats.annotatorProgress"
/>
</v-card-text>
</v-card>
<v-row>
<v-col cols="12">
<member-progress />
</v-col>
<v-col
cols="12"
lg="4"
>
<v-card>
<v-card-title>{{ $t('members.roles.annotationApprover') }}</v-card-title>
<v-card-text>
<doughnut-chart
:chart-data="stats.approverProgress"
/>
</v-card-text>
</v-card>
<v-col cols="12">
<category-distribution />
</v-col>
<v-col
cols="12"
lg="4"
>
<v-card>
<v-card-title>{{ $t('members.roles.projectAdmin') }}</v-card-title>
<v-card-text>
<doughnut-chart
:chart-data="stats.adminProgress"
/>
</v-card-text>
</v-card>
</v-col>
<v-col
cols="12"
lg="4"
>
<v-card>
<v-card-title>Label Stats</v-card-title>
<v-card-text>
<bar-chart
:chart-data="stats.label"
/>
</v-card-text>
</v-card>
</v-col>
<v-col
cols="12"
lg="4"
>
<v-card>
<v-card-title>User Stats</v-card-title>
<v-card-text>
<bar-chart
:chart-data="stats.user"
/>
</v-card-text>
</v-card>
<v-col cols="12">
<span-distribution />
</v-col>
</v-row>
</template>
<script>
import _ from 'lodash'
import DoughnutChart from '@/components/statistics/ChartDoughnut'
import BarChart from '@/components/statistics/ChartBar'
import CategoryDistribution from '~/components/statistics/CategoryDistribution'
import SpanDistribution from '~/components/statistics/SpanDistribution'
import MemberProgress from '~/components/statistics/MemberProgress'
export default {
components: {
DoughnutChart,
BarChart
CategoryDistribution,
SpanDistribution,
MemberProgress
},
layout: 'project',
validate({ params }) {
return /^\d+$/.test(params.id)
},
data() {
return {
stats: {}
}
},
computed: {
isEmpty() {
return _.isEmpty(this.stats)
}
},
async created() {
this.stats = await this.$services.statistics.fetchStatistics(
this.$route.params.id,
this.$t('statistics.labelStats'),
this.$t('statistics.userStats'),
this.$t('statistics.progress')
)
}
}
</script>

20
frontend/repositories/statistics/apiStatisticsRepository.ts

@ -1,15 +1,27 @@
import ApiService from '@/services/api.service'
import { StatisticsRepository } from '@/domain/models/statistics/statisticsRepository'
import { Statistics } from '~/domain/models/statistics/statistics'
import { Distribution, Progress } from '~/domain/models/statistics/statistics'
export class APIStatisticsRepository implements StatisticsRepository {
constructor(
private readonly request = ApiService
) {}
async fetch(projectId: string): Promise<Statistics> {
const url = `/projects/${projectId}/statistics`
async fetchCategoryDistribution(projectId: string): Promise<Distribution> {
const url = `/projects/${projectId}/category-distribution`
const response = await this.request.get(url)
return Statistics.valueOf(response.data)
return response.data
}
async fetchSpanDistribution(projectId: string): Promise<Distribution> {
const url = `/projects/${projectId}/span-distribution`
const response = await this.request.get(url)
return response.data
}
async fetchMemberProgress(projectId: string): Promise<Progress> {
const url = `/projects/${projectId}/member-progress`
const response = await this.request.get(url)
return response.data
}
}

17
frontend/services/application/statistics/statisticsApplicationService.ts

@ -1,15 +1,20 @@
import { StatisticsDTO } from './statisticsData'
import { StatisticsRepository } from '~/domain/models/statistics/statisticsRepository'
import { Progress, Distribution } from '~/domain/models/statistics/statistics'
export class StatisticsApplicationService {
constructor(
private readonly repository: StatisticsRepository
) {}
public async fetchStatistics(
projectId: string, labelText: string, userText: string, progressLabels: string[]
): Promise<StatisticsDTO> {
const item = await this.repository.fetch(projectId)
return new StatisticsDTO(item, labelText, userText, progressLabels)
public async fetchMemberProgress(projectId: string): Promise<Progress> {
return await this.repository.fetchMemberProgress(projectId)
}
public async fetchCategoryDistribution(projectId: string): Promise<Distribution> {
return await this.repository.fetchCategoryDistribution(projectId)
}
public async fetchSpanDistribution(projectId: string): Promise<Distribution> {
return await this.repository.fetchSpanDistribution(projectId)
}
}

20
frontend/services/application/statistics/statisticsData.ts

@ -1,20 +0,0 @@
import { Statistics } from '~/domain/models/statistics/statistics'
export class StatisticsDTO {
label: object;
user: object;
progress: object;
annotatorProgress: object;
approverProgress: object;
adminProgress: object;
constructor(item: Statistics, labelText: string, userText: string, progressLabels: string[]) {
this.label = item.labelStats(labelText);
this.user = item.userStats(userText);
this.progress = item.progress(progressLabels);
this.annotatorProgress = item.annotatorProgress(progressLabels);
this.approverProgress = item.approverProgress(progressLabels);
this.adminProgress = item.adminProgress(progressLabels);
}
}
Loading…
Cancel
Save