mirror of https://github.com/doccano/doccano.git
6 changed files with 49 additions and 206 deletions
Unified View
Diff Options
-
87frontend/domain/models/statistics/statistics.ts
-
7frontend/domain/models/statistics/statisticsRepository.ts
-
104frontend/pages/projects/_id/statistics/index.vue
-
20frontend/repositories/statistics/apiStatisticsRepository.ts
-
17frontend/services/application/statistics/statisticsApplicationService.ts
-
20frontend/services/application/statistics/statisticsData.ts
@ -1,87 +1,8 @@ |
|||||
export type Label = {[key: string]: number} |
export type Label = {[key: string]: number} |
||||
|
|
||||
export type User = {[key: string]: number} |
export type User = {[key: string]: number} |
||||
|
|
||||
export type ConfirmedCount = {[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}[] |
||||
} |
} |
@ -1,6 +1,7 @@ |
|||||
import { Statistics } from '~/domain/models/statistics/statistics' |
|
||||
|
import { Distribution, Progress } from '~/domain/models/statistics/statistics' |
||||
|
|
||||
export interface StatisticsRepository { |
export interface StatisticsRepository { |
||||
|
|
||||
fetch(projectId: string): Promise<Statistics> |
|
||||
|
fetchCategoryDistribution(projectId: string): Promise<Distribution> |
||||
|
fetchSpanDistribution(projectId: string): Promise<Distribution> |
||||
|
fetchMemberProgress(projectId: string): Promise<Progress> |
||||
} |
} |
@ -1,109 +1,33 @@ |
|||||
<template> |
<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> |
||||
<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> |
||||
<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-col> |
||||
</v-row> |
</v-row> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<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 { |
export default { |
||||
|
|
||||
components: { |
components: { |
||||
DoughnutChart, |
|
||||
BarChart |
|
||||
|
CategoryDistribution, |
||||
|
SpanDistribution, |
||||
|
MemberProgress |
||||
}, |
}, |
||||
|
|
||||
layout: 'project', |
layout: 'project', |
||||
|
|
||||
validate({ params }) { |
validate({ params }) { |
||||
return /^\d+$/.test(params.id) |
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> |
</script> |
@ -1,15 +1,27 @@ |
|||||
import ApiService from '@/services/api.service' |
import ApiService from '@/services/api.service' |
||||
import { StatisticsRepository } from '@/domain/models/statistics/statisticsRepository' |
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 { |
export class APIStatisticsRepository implements StatisticsRepository { |
||||
constructor( |
constructor( |
||||
private readonly request = ApiService |
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) |
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 |
||||
} |
} |
||||
} |
} |
@ -1,15 +1,20 @@ |
|||||
import { StatisticsDTO } from './statisticsData' |
|
||||
import { StatisticsRepository } from '~/domain/models/statistics/statisticsRepository' |
import { StatisticsRepository } from '~/domain/models/statistics/statisticsRepository' |
||||
|
import { Progress, Distribution } from '~/domain/models/statistics/statistics' |
||||
|
|
||||
export class StatisticsApplicationService { |
export class StatisticsApplicationService { |
||||
constructor( |
constructor( |
||||
private readonly repository: StatisticsRepository |
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) |
||||
} |
} |
||||
} |
} |
@ -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); |
|
||||
} |
|
||||
} |
|
Write
Preview
Loading…
Cancel
Save