Browse Source

Implement statistics page

pull/341/head
Hironsan 5 years ago
parent
commit
3be5979a3a
9 changed files with 242 additions and 2 deletions
  1. 13
      frontend/api/db/stats.json
  2. 2
      frontend/api/index.js
  3. 11
      frontend/api/routes/stats.js
  4. 43
      frontend/components/molecules/BarChart.vue
  5. 28
      frontend/components/molecules/DoughnutChart.vue
  6. 2
      frontend/package.json
  7. 94
      frontend/pages/projects/_id/statistics/index.vue
  8. 13
      frontend/services/statistics.service.js
  9. 38
      frontend/yarn.lock

13
frontend/api/db/stats.json

@ -0,0 +1,13 @@
{
"label": {
"LOC": 1838,
"MISC": 922,
"ORG": 1340,
"PER": 1842
},
"user": {
"hironsan": 5942
},
"total": 3250,
"remaining": 645
}

2
frontend/api/index.js

@ -6,9 +6,11 @@ const labels = require('./routes/labels')
const projects = require('./routes/projects')
const members = require('./routes/members')
const users = require('./routes/users')
const stats = require('./routes/stats')
app.use('/users', users)
app.use('/projects', projects)
app.use('/projects/:project_id/statistics', stats)
app.use('/projects/:project_id/docs', docs)
app.use('/projects/:project_id/labels', labels)
app.use('/projects/:project_id/users', members)

11
frontend/api/routes/stats.js

@ -0,0 +1,11 @@
const fs = require('fs')
const express = require('express')
const router = express.Router()
let db = JSON.parse(fs.readFileSync('./api/db/stats.json', 'utf8'))
// Get statistics.
router.get('/', (req, res) => {
res.json(db)
})
module.exports = router

43
frontend/components/molecules/BarChart.vue

@ -0,0 +1,43 @@
<script>
import { HorizontalBar, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: HorizontalBar,
mixins: [reactiveProp],
props: {
chartData: {
type: Object,
default: () => {},
required: true
}
},
data() {
return {
options: {
scales: {
yAxes: [
{
barPercentage: 0.3
}
],
xAxes: [
{
ticks: {
beginAtZero: true,
min: 0
}
}
]
},
maintainAspectRatio: false
}
}
},
mounted() {
this.renderChart(this.chartData, this.options)
}
}
</script>

28
frontend/components/molecules/DoughnutChart.vue

@ -0,0 +1,28 @@
<script>
import { Doughnut, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Doughnut,
mixins: [reactiveProp],
props: {
chartData: {
type: Object,
default: () => {},
required: true
}
},
data() {
return {
options: {
maintainAspectRatio: false
}
}
},
mounted() {
this.renderChart(this.chartData, this.options)
}
}
</script>

2
frontend/package.json

@ -17,10 +17,12 @@
"@nuxtjs/axios": "^5.3.6",
"@nuxtjs/vuetify": "^1.0.2",
"@toast-ui/vue-editor": "^1.1.1",
"chart.js": "^2.8.0",
"codemirror": "^5.48.2",
"nuxt": "^2.0.0",
"papaparse": "^5.0.2",
"tui-editor": "^1.4.5",
"vue-chartjs": "^3.4.2",
"vuetify": "^2.0.2"
},
"devDependencies": {

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

@ -1,9 +1,99 @@
<template>
<div />
<v-container fluid>
<v-row>
<v-col
cols="12"
lg="4"
>
<v-card>
<doughnut-chart
:chart-data="progressStat"
/>
</v-card>
</v-col>
<v-col
cols="12"
lg="4"
>
<v-card>
<bar-chart
:chart-data="labelStat"
/>
</v-card>
</v-col>
<v-col
cols="12"
lg="4"
>
<v-card>
<bar-chart
:chart-data="userStat"
/>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
import DoughnutChart from '@/components/molecules/DoughnutChart'
import BarChart from '@/components/molecules/BarChart'
import StatisticsService from '@/services/statistics.service'
export default {
layout: 'project'
layout: 'project',
components: {
DoughnutChart,
BarChart
},
data() {
return {
progressStat: {},
userStat: {},
labelStat: {}
}
},
created() {
StatisticsService.getStatistics().then((response) => {
this.labelStat = this.makeData(response.label, 'Label stats')
this.userStat = this.makeData(response.user, 'User stats')
const complete = response.total - response.remaining
const incomplete = response.remaining
this.progressStat = {
datasets: [{
data: [complete, incomplete],
backgroundColor: ['#00d1b2', '#ffdd57']
}],
labels: [
'Completed',
'Incomplete'
]
}
})
},
methods: {
makeData(object, label) {
const labels = Object.keys(object)
const counts = Object.values(object)
const res = {
labels: labels,
datasets: [{
label: label,
backgroundColor: '#00d1b2',
data: counts
}]
}
return res
}
},
validate({ params }) {
return /^\d+$/.test(params.id)
}
}
</script>

13
frontend/services/statistics.service.js

@ -0,0 +1,13 @@
import ApiService from '@/services/api.service'
class StatisticsService {
constructor() {
this.request = new ApiService()
}
getStatistics(projectId) {
return this.request.get(`/projects/${projectId}/statistics`)
}
}
export default new StatisticsService()

38
frontend/yarn.lock

@ -2464,6 +2464,29 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chart.js@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.8.0.tgz#b703b10d0f4ec5079eaefdcd6ca32dc8f826e0e9"
integrity sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"
chartjs-color-string@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71"
integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
dependencies:
color-name "^1.0.0"
chartjs-color@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.3.0.tgz#0e7e1e8dba37eae8415fd3db38bf572007dd958f"
integrity sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==
dependencies:
chartjs-color-string "^0.6.0"
color-convert "^0.5.3"
check-types@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
@ -2627,6 +2650,11 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -6344,6 +6372,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@
dependencies:
minimist "0.0.8"
moment@^2.10.2:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@ -9717,6 +9750,11 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
vue-chartjs@^3.4.2:
version "3.4.2"
resolved "https://registry.yarnpkg.com/vue-chartjs/-/vue-chartjs-3.4.2.tgz#0323e6a99a10a68f38d426899c3994f48596fd23"
integrity sha512-EhoXUJ17+9isMLhJpOliS++xE5z5FM8iAVytIqnKofByVMr8AISRL/SCy3zvWbvzhjgQPStd9y6adMF5bnWQdg==
vue-eslint-parser@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1"

Loading…
Cancel
Save