Merge branch '132-frontend-improvements' into 'master'

Resolve "Frontend improvements"

Closes #132

See merge request marcel.schwarz/2020ss-qbc-geofence-timetracking!114
This commit is contained in:
Simon Kellner 2020-06-14 14:28:53 +00:00
commit ad833f3831
12 changed files with 575 additions and 730 deletions

View File

@ -1,5 +1,5 @@
{ {
"name": "geotime", "name": "Geo_Timetracking",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
@ -5167,554 +5167,14 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
}, },
"fsevents": { "fsevents": {
"version": "1.2.12", "version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
"bindings": "^1.5.0", "bindings": "^1.5.0",
"nan": "^2.12.1", "nan": "^2.12.1"
"node-pre-gyp": "*"
},
"dependencies": {
"abbrev": {
"version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
"bundled": true,
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"chownr": {
"version": "1.1.4",
"bundled": true,
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
},
"debug": {
"version": "3.2.6",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ms": "^2.1.1"
}
},
"deep-extend": {
"version": "0.6.0",
"bundled": true,
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"bundled": true,
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.7",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.6.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"glob": {
"version": "7.1.6",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has-unicode": {
"version": "2.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore-walk": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimatch": "^3.0.4"
}
},
"inflight": {
"version": "1.0.6",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"bundled": true,
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
"bundled": true,
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
"bundled": true,
"dev": true,
"optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.3.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.9.0"
}
},
"mkdirp": {
"version": "0.5.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "^1.2.5"
}
},
"ms": {
"version": "2.1.2",
"bundled": true,
"dev": true,
"optional": true
},
"needle": {
"version": "2.3.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
}
},
"node-pre-gyp": {
"version": "0.14.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4.4.2"
}
},
"nopt": {
"version": "4.0.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
},
"npm-bundled": {
"version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"npm-normalize-package-bin": "^1.0.1"
}
},
"npm-normalize-package-bin": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.4.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1",
"npm-normalize-package-bin": "^1.0.1"
}
},
"npmlog": {
"version": "4.1.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
"bundled": true,
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
}
},
"readable-stream": {
"version": "2.3.7",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"rimraf": {
"version": "2.7.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"bundled": true,
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"bundled": true,
"dev": true,
"optional": true
},
"semver": {
"version": "5.7.1",
"bundled": true,
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"string_decoder": {
"version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"bundled": true,
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.13",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
}
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"string-width": "^1.0.2 || 2"
}
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"dev": true,
"optional": true
}
} }
}, },
"fstream": { "fstream": {

View File

@ -1,5 +1,5 @@
{ {
"name": "geotime", "name": "Geo_Timetracking",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -18,58 +18,91 @@ const routes = [
{ {
path: "/", path: "/",
name: "Home", name: "Home",
component: Home component: Home,
meta: {
title: "Geo Timetracking - Home",
}
}, },
{ {
path: "/timerecords", path: "/timerecords",
name: "TimeRecords", name: "TimeRecords",
component: TimeRecords component: TimeRecords,
meta: {
title: 'Geo Timetracking - Time Records',
}
}, },
{ {
path: "/about", path: "/about",
name: "About", name: "About",
component: About component: About,
meta: {
title: 'Geo Timetracking - About',
}
}, },
{ {
path: "/statistics", path: "/statistics",
name: "Statistics", name: "Statistics",
component: StatisticOverview component: StatisticOverview,
meta: {
title: 'Geo Timetracking - Statistics',
}
}, },
{ {
path: "/users", path: "/users",
name: "Users", name: "Users",
component: Users component: Users,
meta: {
title: 'Geo Timetracking - Users',
}
}, },
{ {
path: "/edituser", path: "/edituser",
name: "EditUser", name: "EditUser",
component: EditUser component: EditUser,
meta: {
title: 'Geo Timetracking - Edit User',
}
}, },
{ {
path: "/timetrackaccounts", path: "/timetrackaccounts",
name: "TimeTrack Accounts", name: "TimeTrack Accounts",
component: TimeTrackAccounts component: TimeTrackAccounts,
meta: {
title: 'Geo Timetracking - TimeTrack Accounts',
}
}, },
{ {
path: "/edittimetrackaccount", path: "/edittimetrackaccount",
name: "Edit TimeTrack Account", name: "Edit TimeTrack Account",
component: EditTimeTrackAccount component: EditTimeTrackAccount,
meta: {
title: 'Geo Timetracking - Edit TimeTrack Account',
}
}, },
{ {
path: "/createtimetrackaccount", path: "/createtimetrackaccount",
name: "Create TimeTrack Account", name: "Create TimeTrack Account",
component: CreateTimeTrackAccount component: CreateTimeTrackAccount,
meta: {
title: 'Geo Timetracking - Create TimeTrack Accounts',
}
}, },
{ {
path: "/edittimerecord", path: "/edittimerecord",
name: "EditTimerecord", name: "EditTimerecord",
component: EditTimerecord component: EditTimerecord,
meta: {
title: 'Geo Timetracking - Edit Time Record',
}
}, },
{ {
path: "/createtimerecord", path: "/createtimerecord",
name: "CreateTimerecord", name: "CreateTimerecord",
component: CreateTimerecord component: CreateTimerecord,
meta: {
title: 'Geo Timetracking - Create Time Record',
}
}, },
{ {
path: '*', path: '*',

View File

@ -1,26 +1,47 @@
<template> <template>
<v-container fluid> <v-container fluid>
<v-row class="ma-5">
<v-col cols="3" ></v-col>
<v-col cols="6">
<v-card> <v-card>
<p class="text-center logowhite--text" style="font-size:20pt">This is a ubiquitos computing project.</p> <p
<p class="text-center logowhite--text" style="font-size:20pt">It was created by the team TacocaT.</p> class="text-center logowhite--text"
style="font-size:20pt"
>This is a ubiquitous computing project.</p>
<p
class="text-center logowhite--text"
style="font-size:20pt"
>It was created by the team TacocaT.</p>
</v-card> </v-card>
</v-col>
<v-col cols="3"></v-col>
<v-col cols="3"></v-col>
<v-col cols="6">
<v-card> <v-card>
<p class="text-center logowhite--text" style="font-size:30pt">Team TacocaT</p> <p class="text-center logowhite--text" style="font-size:30pt">Team TacocaT</p>
<br> <br />
<p class="text-center logowhite--text" style="font-size:20pt">Backend Developer: Marcel Schwarz</p> <p
<p class="text-center logowhite--text" style="font-size:20pt">Android Developer: Tobias Wieck</p> class="text-center logowhite--text"
<p class="text-center logowhite--text" style="font-size:20pt">Frontend Developer: Simon Kellner, Tim Zieger</p> style="font-size:20pt"
>Backend Developer: Marcel Schwarz</p>
<p
class="text-center logowhite--text"
style="font-size:20pt"
>Android Developer: Tobias Wieck</p>
<p
class="text-center logowhite--text"
style="font-size:20pt"
>Frontend Developer: Simon Kellner, Tim Zieger</p>
</v-card> </v-card>
</v-col>
</v-row>
</v-container> </v-container>
</template> </template>
<script> <script>
// @ is an alias to /src // @ is an alias to /src
export default { export default {
name: "About", name: "About"
}; };
</script> </script>

View File

@ -66,7 +66,7 @@
</v-row> </v-row>
<v-card v-if="loggedIn == 'false'" class="pa-3"> <v-card v-if="loggedIn == 'false'" class="pa-3">
<p style="font-size:20pt">Welcome to geotime</p> <p style="font-size:20pt">Welcome to Geo Timetracking</p>
</v-card> </v-card>
</v-container> </v-container>
</template> </template>

View File

@ -1,22 +1,26 @@
<template> <template>
<v-row class="ma-5"> <v-row class="ma-5">
<v-col cols="3"> <v-col cols="4">
<WorkPausePie /> <WorkPausePie />
</v-col> </v-col>
<v-col cols="9"> <v-col cols="4">
<WeekSummary /> <account-pie />
</v-col> </v-col>
<v-col cols="9"> <v-col cols="4">
<revenue-pie/>
</v-col>
<v-col cols="12">
<MonthSummary /> <MonthSummary />
</v-col> </v-col>
<v-col cols="3"> <v-col cols="12">
<account-pie/> <WeekSummary />
</v-col> </v-col>
</v-row> </v-row>
</template> </template>
<script> <script>
import RevenuePie from "./charts/RevenuePie.vue"
import WeekSummary from "./charts/WeekSummary.vue"; import WeekSummary from "./charts/WeekSummary.vue";
import MonthSummary from "./charts/MonthSummary.vue"; import MonthSummary from "./charts/MonthSummary.vue";
import WorkPausePie from "./charts/WorkPausePie.vue"; import WorkPausePie from "./charts/WorkPausePie.vue";
@ -25,6 +29,7 @@ import AccountPie from "./charts/AccountPie.vue";
export default { export default {
name: "StatisticOverview", name: "StatisticOverview",
components: { components: {
RevenuePie,
WeekSummary, WeekSummary,
MonthSummary, MonthSummary,
WorkPausePie, WorkPausePie,

View File

@ -20,7 +20,8 @@ export default {
}, },
computed: { computed: {
chartOptions: function() { chartOptions: function() {
return{labels: ["Working hours", "Pause hours"], return {
labels: ["Working hours", "Pause hours"],
chart: { chart: {
type: "donut", type: "donut",
background: "#202020", background: "#202020",
@ -49,14 +50,14 @@ export default {
show: false show: false
}, },
y: { y: {
formatter: (value) => { formatter: value => {
var revenueTMP = 0; var revenueTMP = 0;
for (let index = 0; index < this.series.length; index++) { for (let index = 0; index < this.series.length; index++) {
if (value == this.series[index]) { if (value == this.series[index]) {
revenueTMP = this.revenue[index]; revenueTMP = this.revenue[index];
} }
} }
revenueTMP = revenueTMP / 60 * value * 1.00; revenueTMP = (revenueTMP / 60) * value * 1.0;
revenueTMP = Math.round(revenueTMP * 100) / 100; revenueTMP = Math.round(revenueTMP * 100) / 100;
var decimalTimeString = value; var decimalTimeString = value;
var decimalTime = parseFloat(decimalTimeString); var decimalTime = parseFloat(decimalTimeString);
@ -78,11 +79,27 @@ export default {
if (seconds < 10) { if (seconds < 10) {
seconds = "0" + seconds; seconds = "0" + seconds;
} }
return hours + ":" + minutes + ":" + seconds + " with " + revenueTMP + "$ revenue."; return (
hours +
":" +
minutes +
":" +
seconds +
" with " +
revenueTMP +
"$ revenue."
);
} }
} }
}, },
colors: ["#0096ff", "#e21d1f", "#03ac13", "#800080", "#f9d71c", "ff1694"], colors: [
"#0096ff",
"#e21d1f",
"#03ac13",
"#800080",
"#f9d71c",
"ff1694"
],
theme: { theme: {
mode: "dark" mode: "dark"
}, },
@ -105,11 +122,12 @@ export default {
} }
} }
] ]
}} };
}
}, },
data: () => ({ data: () => ({
series: [0, 0], series: [0, 0],
revenue: [0, 0], revenue: [0, 0]
}), }),
created() { created() {
// Get all Timetrack accounts for the current user // Get all Timetrack accounts for the current user
@ -153,12 +171,21 @@ export default {
// Get and sort all Records to the accounts // Get and sort all Records to the accounts
var xhttp = new XMLHttpRequest(); var xhttp = new XMLHttpRequest();
var records; var records = new Array(0);
var hasNext = true;
var page = 0;
while (hasNext) {
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { if (this.readyState == 4 && this.status == 200) {
var recordsDB = JSON.parse(xhttp.responseText); var recordsDB = JSON.parse(xhttp.responseText);
recordsDB._embedded.records.forEach(tmpRecord => {
records = recordsDB._embedded.records; records.push(tmpRecord);
});
page++;
if (recordsDB.page.number == recordsDB.page.totalPages - 1) {
hasNext = false;
}
} }
}; };
xhttp.open( xhttp.open(
@ -167,18 +194,28 @@ export default {
"/records/search/allForUser?username=" + "/records/search/allForUser?username=" +
sessionStorage.getItem("username") + sessionStorage.getItem("username") +
"&projection=overview" + "&projection=overview" +
"&size=200", "&page=" +
page +
"&size=50",
false false
); );
xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt")); xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt"));
xhttp.send(null); xhttp.send(null);
}
for (let index = 0; index < records.length; index++) { for (let index = 0; index < records.length; index++) {
var record = records[index]; var record = records[index];
for (let indexAccs = 0; indexAccs < this.chartOptions.labels.length; indexAccs++) { for (
if (record.account == this.chartOptions.labels[indexAccs] && record.type == "PAID") { let indexAccs = 0;
indexAccs < this.chartOptions.labels.length;
indexAccs++
) {
if (
record.account == this.chartOptions.labels[indexAccs] &&
record.type == "PAID"
) {
this.series[indexAccs] += record.duration; this.series[indexAccs] += record.duration;
} }
} }

View File

@ -112,6 +112,30 @@ export default {
type: "datetime", type: "datetime",
categories: [] categories: []
}, },
yaxis: {
labels: {
formatter: function(value) {
var decimalTimeString = value;
var decimalTime = parseFloat(decimalTimeString);
decimalTime = decimalTime * 60;
var hours = Math.floor(decimalTime / (60 * 60));
decimalTime = decimalTime - hours * 60 * 60;
var minutes = Math.floor(decimalTime / 60);
decimalTime = decimalTime - minutes * 60;
var seconds = Math.round(decimalTime);
if (hours < 10) {
hours = "0" + hours;
}
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
return hours + ":" + minutes + ":" + seconds;
}
}
},
legend: { legend: {
show: false, show: false,
position: "left", position: "left",
@ -126,7 +150,10 @@ export default {
created() { created() {
var daysToDisplay = 31; var daysToDisplay = 31;
var xhttp = new XMLHttpRequest(); var xhttp = new XMLHttpRequest();
var records; var records = new Array(0);
var hasNext = true;
var page = 0;
this.chartOptions.xaxis.categories = new Array(daysToDisplay); this.chartOptions.xaxis.categories = new Array(daysToDisplay);
this.series[0].data = new Array(daysToDisplay); this.series[0].data = new Array(daysToDisplay);
this.series[1].data = new Array(daysToDisplay); this.series[1].data = new Array(daysToDisplay);
@ -150,13 +177,20 @@ export default {
} }
today = yyyy + "-" + mm + "-" + dd; today = yyyy + "-" + mm + "-" + dd;
while (hasNext) {
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { if (this.readyState == 4 && this.status == 200) {
var recordsDB = JSON.parse(xhttp.responseText); var recordsDB = JSON.parse(xhttp.responseText);
recordsDB._embedded.records.forEach(tmpRecord => {
records = recordsDB._embedded.records; records.push(tmpRecord);
});
page++;
if (recordsDB.page.number == recordsDB.page.totalPages - 1) {
hasNext = false;
}
} }
}; };
xhttp.open( xhttp.open(
"GET", "GET",
baseUri + baseUri +
@ -165,22 +199,28 @@ export default {
"T00:00:01" + "T00:00:01" +
"&end=" + "&end=" +
today + today +
"T00:00:01" + "T23:59:59" +
"&username=" + "&username=" +
sessionStorage.getItem("username") + sessionStorage.getItem("username") +
"&size=150", "&page=" +
page +
"&size=50",
false false
); );
xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt")); xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt"));
xhttp.send(null); xhttp.send(null);
}
for (let index = 0; index < records.length; index++) { for (let index = 0; index < records.length; index++) {
var record = records[index]; var record = records[index];
for (let indexA = 0; indexA < daysToDisplay; indexA++) { for (let indexA = 0; indexA < daysToDisplay; indexA++) {
if (record.startdate.split("T")[0] == this.chartOptions.xaxis.categories[indexA]) { if (
record.startdate.split("T")[0] ==
this.chartOptions.xaxis.categories[indexA]
) {
if (record.type == "PAID") { if (record.type == "PAID") {
this.series[0].data[indexA] += record.duration; this.series[0].data[indexA] += record.duration;
} else { } else {

View File

@ -0,0 +1,199 @@
<template>
<v-card color="main_accent" outlined>
<div>
<p></p>
<h3 align="center">Revenue by TimeTrack Account</h3>
<div id="chart">
<apexchart class="ma-5" type="donut" width="100%" :options="chartOptions" :series="series"></apexchart>
</div>
</div>
</v-card>
</template>
<script>
import VueApexCharts from "vue-apexcharts";
import { baseUri } from "../../variables.js";
export default {
components: {
apexchart: VueApexCharts
},
computed: {
chartOptions: function() {
return {
labels: ["Working hours", "Pause hours"],
chart: {
type: "donut",
background: "#202020",
toolbar: {
show: true,
offsetX: 0,
offsetY: 0,
tools: {
download: true,
selection: true,
zoom: false,
zoomin: false,
zoomout: false,
pan: false,
reset: false,
customIcons: []
},
autoSelected: "zoom"
}
},
tooltip: {
enabled: true,
followCursor: true,
fillSeriesColor: false,
x: {
show: false
},
y: {
formatter: value => {
return Math.round(value * 100) / 100 + "$"
}
}
},
colors: [
"#0096ff",
"#e21d1f",
"#03ac13",
"#800080",
"#f9d71c",
"ff1694"
],
theme: {
mode: "dark"
},
legend: {
show: false,
position: "left",
offsetY: 40
},
responsive: [
{
breakpoint: 480,
options: {
chart: {
width: 300
},
legend: {
position: "bottom"
}
}
}
]
};
}
},
data: () => ({
series: [0, 0],
revenue: [0, 0]
}),
created() {
// Get all Timetrack accounts for the current user
var accounts;
var timeTrackAccountsTMP;
var accountxhttp = new XMLHttpRequest();
accountxhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
accounts = JSON.parse(accountxhttp.responseText);
timeTrackAccountsTMP = accounts._embedded.accounts;
}
};
accountxhttp.open(
"GET",
baseUri +
"/accounts/search/findByUsername?username=" +
sessionStorage.getItem("username"),
false
);
accountxhttp.setRequestHeader(
"Authorization",
sessionStorage.getItem("jwt")
);
accountxhttp.send(null);
this.chartOptions.labels = new Array(timeTrackAccountsTMP.length);
this.series = new Array(timeTrackAccountsTMP.length);
this.revenue = new Array(timeTrackAccountsTMP.length);
for (let index = 0; index < this.series.length; index++) {
this.series[index] = 0;
this.revenue[index] = 0;
}
for (let index = 0; index < timeTrackAccountsTMP.length; index++) {
this.chartOptions.labels[index] = timeTrackAccountsTMP[index].name;
this.revenue[index] = timeTrackAccountsTMP[index].revenue;
}
// Get and sort all Records to the accounts
var xhttp = new XMLHttpRequest();
var records = new Array(0);
var hasNext = true;
var page = 0;
while (hasNext) {
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var recordsDB = JSON.parse(xhttp.responseText);
recordsDB._embedded.records.forEach(tmpRecord => {
records.push(tmpRecord);
});
page++;
if (recordsDB.page.number == recordsDB.page.totalPages - 1) {
hasNext = false;
}
}
};
xhttp.open(
"GET",
baseUri +
"/records/search/allForUser?username=" +
sessionStorage.getItem("username") +
"&projection=overview" +
"&page=" +
page +
"&size=50",
false
);
xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt"));
xhttp.send(null);
}
for (let index = 0; index < records.length; index++) {
var record = records[index];
for (
let indexAccs = 0;
indexAccs < this.chartOptions.labels.length;
indexAccs++
) {
if (
record.account == this.chartOptions.labels[indexAccs] &&
record.type == "PAID"
) {
this.series[indexAccs] += record.duration;
}
}
}
for (let index = 0; index < this.series.length; index++) {
this.series[index] = this.series[index] * this.revenue[index] /60;
}
}
};
</script>
<style scoped>
.v-card {
border-radius: 20px !important;
}
</style>

View File

@ -112,6 +112,30 @@ export default {
type: "datetime", type: "datetime",
categories: [] categories: []
}, },
yaxis: {
labels: {
formatter: function(value) {
var decimalTimeString = value;
var decimalTime = parseFloat(decimalTimeString);
decimalTime = decimalTime * 60;
var hours = Math.floor(decimalTime / (60 * 60));
decimalTime = decimalTime - hours * 60 * 60;
var minutes = Math.floor(decimalTime / 60);
decimalTime = decimalTime - minutes * 60;
var seconds = Math.round(decimalTime);
if (hours < 10) {
hours = "0" + hours;
}
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
return hours + ":" + minutes + ":" + seconds;
}
}
},
legend: { legend: {
show: false, show: false,
position: "left", position: "left",
@ -126,7 +150,10 @@ export default {
created() { created() {
var daysToDisplay = 8; var daysToDisplay = 8;
var xhttp = new XMLHttpRequest(); var xhttp = new XMLHttpRequest();
var records; var records = new Array(0);
var hasNext = true;
var page = 0;
this.chartOptions.xaxis.categories = new Array(daysToDisplay); this.chartOptions.xaxis.categories = new Array(daysToDisplay);
this.series[0].data = new Array(daysToDisplay); this.series[0].data = new Array(daysToDisplay);
this.series[1].data = new Array(daysToDisplay); this.series[1].data = new Array(daysToDisplay);
@ -150,11 +177,18 @@ export default {
} }
today = yyyy + "-" + mm + "-" + dd; today = yyyy + "-" + mm + "-" + dd;
while (hasNext) {
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { if (this.readyState == 4 && this.status == 200) {
var recordsDB = JSON.parse(xhttp.responseText); var recordsDB = JSON.parse(xhttp.responseText);
recordsDB._embedded.records.forEach(tmpRecord => {
records = recordsDB._embedded.records; records.push(tmpRecord);
});
page++;
if (recordsDB.page.number == recordsDB.page.totalPages - 1) {
hasNext = false;
}
} }
}; };
xhttp.open( xhttp.open(
@ -168,6 +202,8 @@ export default {
"T00:00:01" + "T00:00:01" +
"&username=" + "&username=" +
sessionStorage.getItem("username") + sessionStorage.getItem("username") +
"&page=" +
page +
"&size=50", "&size=50",
false false
); );
@ -175,6 +211,8 @@ export default {
xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt")); xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt"));
xhttp.send(null); xhttp.send(null);
}
for (let index = 0; index < records.length; index++) { for (let index = 0; index < records.length; index++) {
var record = records[index]; var record = records[index];

View File

@ -102,12 +102,21 @@ export default {
}), }),
created() { created() {
var xhttp = new XMLHttpRequest(); var xhttp = new XMLHttpRequest();
var records; var records = new Array(0);
var hasNext = true;
var page = 0;
while (hasNext) {
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { if (this.readyState == 4 && this.status == 200) {
var recordsDB = JSON.parse(xhttp.responseText); var recordsDB = JSON.parse(xhttp.responseText);
recordsDB._embedded.records.forEach(tmpRecord => {
records = recordsDB._embedded.records; records.push(tmpRecord)
});
page++;
if (recordsDB.page.number == recordsDB.page.totalPages - 1) {
hasNext = false;
}
} }
}; };
xhttp.open( xhttp.open(
@ -115,13 +124,17 @@ export default {
baseUri + baseUri +
"/records/search/allForUser?username=" + "/records/search/allForUser?username=" +
sessionStorage.getItem("username") + sessionStorage.getItem("username") +
"&projection=overview", "&page=" +
page +
"&projection=overview" +
"&size=50",
false false
); );
xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt")); xhttp.setRequestHeader("Authorization", sessionStorage.getItem("jwt"));
xhttp.send(null); xhttp.send(null);
}
var paidTime = 0; var paidTime = 0;
var breakTime = 0; var breakTime = 0;
@ -130,7 +143,6 @@ export default {
var record = records[index]; var record = records[index];
var type = record.type + ""; var type = record.type + "";
if (type == "PAID") { if (type == "PAID") {
paidTime += record.duration; paidTime += record.duration;
} else { } else {