Browse Source

Merge pull request #1235 from doccano/enhancement/statistics

[Enhancement] statistics
pull/1240/head
Hiroki Nakayama 3 years ago
committed by GitHub
parent
commit
1ef6ad4175
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 135 additions and 25 deletions
  1. 59
      frontend/models/statistics.ts
  2. 43
      frontend/pages/projects/_id/statistics/index.vue
  3. 10
      frontend/plugins/services.ts
  4. 15
      frontend/repositories/statistics/api.ts
  5. 6
      frontend/repositories/statistics/interface.ts
  6. 27
      frontend/services/application/statistics.service.ts

59
frontend/models/statistics.ts

@ -0,0 +1,59 @@
export type Label = {[key: string]: number}
export type User = {[key: string]: number}
export class Statistics {
constructor(
public label: Label,
public userLabel: User,
public total: number,
public remaining: number,
public user: User
) {}
static valueOf(
{ label, user_label, total, remaining, user }:
{
label: Label,
user_label: User,
total: number,
remaining: number,
user: User
}
): Statistics {
return new Statistics(label, user_label, total, remaining, user)
}
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
}
}
}

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

@ -1,12 +1,12 @@
<template> <template>
<v-row v-if="stats">
<v-row v-if="!isEmpty">
<v-col <v-col
cols="12" cols="12"
lg="4" lg="4"
> >
<v-card> <v-card>
<doughnut-chart <doughnut-chart
:chart-data="progressLocale()"
:chart-data="stats.progress"
/> />
</v-card> </v-card>
</v-col> </v-col>
@ -16,7 +16,7 @@
> >
<v-card> <v-card>
<bar-chart <bar-chart
:chart-data="labelStatsLocale()"
:chart-data="stats.label"
/> />
</v-card> </v-card>
</v-col> </v-col>
@ -26,7 +26,7 @@
> >
<v-card> <v-card>
<bar-chart <bar-chart
:chart-data="userStatsLocale()"
:chart-data="stats.user"
/> />
</v-card> </v-card>
</v-col> </v-col>
@ -34,7 +34,7 @@
</template> </template>
<script> <script>
import { mapActions, mapGetters, mapState } from 'vuex'
import _ from 'lodash'
import DoughnutChart from '@/components/molecules/DoughnutChart' import DoughnutChart from '@/components/molecules/DoughnutChart'
import BarChart from '@/components/molecules/BarChart' import BarChart from '@/components/molecules/BarChart'
@ -46,28 +46,25 @@ export default {
BarChart BarChart
}, },
computed: {
...mapGetters('statistics', ['userStats', 'labelStats', 'progress']),
...mapState('statistics', ['stats'])
data() {
return {
stats: {}
}
}, },
async created() {
await this.fetchStatistics({
projectId: this.$route.params.id
})
computed: {
isEmpty() {
return _.isEmpty(this.stats)
}
}, },
methods: {
...mapActions('statistics', ['fetchStatistics']),
progressLocale() {
return this.progress(this.$t('statistics.progress'))
},
labelStatsLocale() {
return this.labelStats(this.$t('statistics.labelStats'))
},
userStatsLocale() {
return this.userStats(this.$t('statistics.userStats'))
}
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')
)
}, },
validate({ params }) { validate({ params }) {

10
frontend/plugins/services.ts

@ -5,12 +5,14 @@ import { FromApiUserItemListRepository } from '@/repositories/user/api'
import { FromApiRoleItemListRepository } from '@/repositories/role/api' import { FromApiRoleItemListRepository } from '@/repositories/role/api'
import { FromApiProjectItemListRepository } from '@/repositories/project/api' import { FromApiProjectItemListRepository } from '@/repositories/project/api'
import { FromApiCommentItemListRepository } from '@/repositories/comment/api' import { FromApiCommentItemListRepository } from '@/repositories/comment/api'
import { FromApiStatisticsRepository } from '@/repositories/statistics/api'
import { LabelApplicationService } from '@/services/application/label.service' import { LabelApplicationService } from '@/services/application/label.service'
import { MemberApplicationService } from '@/services/application/member.service' import { MemberApplicationService } from '@/services/application/member.service'
import { UserApplicationService } from '@/services/application/user.service' import { UserApplicationService } from '@/services/application/user.service'
import { RoleApplicationService } from '@/services/application/role.service' import { RoleApplicationService } from '@/services/application/role.service'
import { ProjectApplicationService } from '@/services/application/project.service' import { ProjectApplicationService } from '@/services/application/project.service'
import { CommentApplicationService } from '@/services/application/comment.service' import { CommentApplicationService } from '@/services/application/comment.service'
import { StatisticsApplicationService } from '@/services/application/statistics.service'
export interface Services { export interface Services {
label: LabelApplicationService, label: LabelApplicationService,
@ -18,7 +20,8 @@ export interface Services {
user: UserApplicationService, user: UserApplicationService,
role: RoleApplicationService, role: RoleApplicationService,
project: ProjectApplicationService, project: ProjectApplicationService,
comment: CommentApplicationService
comment: CommentApplicationService,
statistics: StatisticsApplicationService
} }
declare module 'vue/types/vue' { declare module 'vue/types/vue' {
@ -40,13 +43,16 @@ const plugin: Plugin = (context, inject) => {
const project = new ProjectApplicationService(projectRepository) const project = new ProjectApplicationService(projectRepository)
const commentRepository = new FromApiCommentItemListRepository() const commentRepository = new FromApiCommentItemListRepository()
const comment = new CommentApplicationService(commentRepository) const comment = new CommentApplicationService(commentRepository)
const statisticsRepository = new FromApiStatisticsRepository()
const statistics = new StatisticsApplicationService(statisticsRepository)
const services: Services = { const services: Services = {
label, label,
member, member,
user, user,
role, role,
project, project,
comment
comment,
statistics
} }
inject('services', services) inject('services', services)
} }

15
frontend/repositories/statistics/api.ts

@ -0,0 +1,15 @@
import ApiService from '@/services/api.service'
import { Statistics } from '@/models/statistics'
import { StatisticsRepository } from './interface'
export class FromApiStatisticsRepository implements StatisticsRepository {
constructor(
private readonly request = ApiService
) {}
async fetch(projectId: string): Promise<Statistics> {
const url = `/projects/${projectId}/statistics`
const response = await this.request.get(url)
return Statistics.valueOf(response.data)
}
}

6
frontend/repositories/statistics/interface.ts

@ -0,0 +1,6 @@
import { Statistics } from '@/models/statistics'
export interface StatisticsRepository {
fetch(projectId: string): Promise<Statistics>
}

27
frontend/services/application/statistics.service.ts

@ -0,0 +1,27 @@
import { Statistics } from '@/models/statistics'
import { StatisticsRepository } from '@/repositories/statistics/interface'
export class StatisticsDTO {
label: object
user: object
progress: 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)
}
}
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)
}
}
Loading…
Cancel
Save