Добавил роутинг

И всякие косметические правки
This commit is contained in:
Anton Vakhrushev 2020-03-02 22:26:02 +03:00
parent a031c12a48
commit a002d130e0
8 changed files with 213 additions and 100 deletions

View File

@ -1,6 +1,6 @@
root = true
[*.cr]
[*.{cr,vue,js}]
charset = utf-8
end_of_line = lf
insert_final_newline = true

View File

@ -1,110 +1,37 @@
<template>
<div id="app">
<section
v-if="today_time"
class="timer"
v-bind:class="{ overtime: today_time.isOvertime() }"
>
{{ today_time.toStr() }}
</section>
<section class="actions">
<a v-if="started" v-on:click.prevent="finish" href="#">Закончить</a>
<a v-else v-on:click.prevent="start" href="#">Начать</a>
</section>
<section v-if="total_time" class="total">
Всего
<span v-bind:class="{ overtime: total_time.isOvertime() }">
{{ total_time.toStr() }}
</span>
</section>
<p class="profile-info">Профиль: {{ profileId }}</p>
<a href="#" v-on:click.prevent="show_stat = !show_stat">Статистика</a>
<div v-if="show_stat">
<table class="stat-table">
<tr v-for="item in statistics">
<td>{{ item.date }}</td>
<td>{{ item.planned.total_minutes }}</td>
<td>{{ item.worked.total_minutes }}</td>
</tr>
</table>
</div>
</div>
<main id="app">
<nav id="nav">
<router-link class="nav-link" :to="{ name: 'timer' }">Таймер</router-link>
<router-link class="nav-link" :to="{ name: 'statistics' }"
>Статистика</router-link
>
</nav>
<router-view></router-view>
</main>
</template>
<script>
import TimeSpan from './TimeSpan';
import h from './helpers';
export default {
data() {
return {
profileId: null,
started: false,
total_time: null,
today_time: null,
show_stat: false,
statistics: [],
};
},
created() {
this.profileId = h.extract_profile_id();
this.get_status();
this.get_statistics();
setInterval(() => this.get_status(), 60 * 1000);
},
methods: {
get_status() {
h.get_status(this.profileId).then(data => {
this.started = data.started;
this.total_time = TimeSpan.fromObject(data.total.time);
this.today_time = TimeSpan.fromObject(data.today.time);
});
},
get_statistics() {
h.get_statistics(this.profileId).then(data => {
this.statistics = data;
});
},
start() {
h.start(this.profileId).then(() => this.get_status());
},
finish() {
h.finish(this.profileId).then(() => this.get_status());
},
},
};
</script>
<script></script>
<style lang="scss" scoped>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
max-width: 400px;
display: block;
margin: 2em auto;
}
#nav {
text-align: center;
margin-top: 3em;
margin: 2em auto;
}
.timer {
font-size: 600%;
.nav-link {
display: inline-block;
}
.overtime {
color: green;
}
.actions {
font-size: 240%;
}
.total {
margin-top: 1em;
font-size: 200%;
}
.profile-info {
margin-top: 2em;
}
.stat-table {
display: inline-table;
.nav-link + .nav-link {
margin-left: 0.6em;
}
</style>

75
assets/StatisticsPage.vue Normal file
View File

@ -0,0 +1,75 @@
<template>
<table class="stat-table">
<tr>
<th>Дата</th>
<th>План</th>
<th>Работа</th>
<th></th>
</tr>
<tr v-for="item in statistics">
<td class="date">{{ item.date }}</td>
<td class="planned">{{ item.planned.total_minutes | tt }}</td>
<td class="worked">{{ item.worked.total_minutes | tt }}</td>
<td class="worked">
{{ (item.worked.total_minutes - item.planned.total_minutes) | td }}
</td>
</tr>
</table>
</template>
<script>
import h from './helpers';
export default {
data() {
return {
statistics: [],
};
},
created() {
this.profileId = h.extract_profile_id();
this.get_statistics();
},
methods: {
get_statistics() {
h.get_statistics(this.profileId).then(data => {
this.statistics = data;
});
},
},
filters: {
tt(v) {
const h = Math.round(v / 60);
const m = v % 60;
return (h ? h : '00') + ':' + String(m).padStart(2, '0');
},
td(v) {
const o = v > 0;
const a = Math.abs(v);
const h = Math.round(a / 60);
const m = a % 60;
const t = (h ? h : '00') + ':' + String(m).padStart(2, '0');
return (o ? '+' : '-') + t;
},
},
};
</script>
<style lang="scss" scoped>
.stat-table {
margin: 1em auto;
border-collapse: collapse;
width: 100%;
th,
td {
border: 1px solid #ddd;
padding: 10px 6px;
}
.date,
.planned,
.worked {
text-align: center;
}
}
</style>

90
assets/TimerPage.vue Normal file
View File

@ -0,0 +1,90 @@
<template>
<div class="timer-page">
<section
v-if="today_time"
class="timer"
v-bind:class="{ overtime: today_time.isOvertime() }"
>
{{ today_time.toStr() }}
</section>
<section class="actions">
<a v-if="started" v-on:click.prevent="finish" href="#">Закончить</a>
<a v-else v-on:click.prevent="start" href="#">Начать</a>
</section>
<section v-if="total_time" class="total">
{{
total_time.isOvertime()
? 'Переработка на начало дня'
: 'Долг на начало дня'
}}
<span v-bind:class="{ overtime: total_time.isOvertime() }">
{{ total_time.toStr() }}
</span>
</section>
<p class="profile-info">Профиль: {{ profileId }}</p>
</div>
</template>
<script>
import TimeSpan from './TimeSpan';
import h from './helpers';
export default {
data() {
return {
profileId: null,
started: false,
total_time: null,
today_time: null,
};
},
created() {
this.profileId = h.extract_profile_id();
this.get_status();
setInterval(() => this.get_status(), 60 * 1000);
},
methods: {
get_status() {
h.get_status(this.profileId).then(data => {
this.started = data.started;
this.total_time = TimeSpan.fromObject(data.total.time);
this.today_time = TimeSpan.fromObject(data.today.time);
});
},
start() {
h.start(this.profileId).then(() => this.get_status());
},
finish() {
h.finish(this.profileId).then(() => this.get_status());
},
},
};
</script>
<style lang="scss" scoped>
.timer-page {
text-align: center;
}
.timer {
font-size: 600%;
margin: 0.25em auto;
}
.overtime {
color: green;
}
.actions {
font-size: 240%;
}
.total {
margin-top: 3em;
margin-bottom: 3em;
font-size: 140%;
}
.profile-info {
margin-top: 2em;
}
</style>

View File

@ -1,10 +1,24 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
Vue.config.productionTip = false;
import TimerPage from './TimerPage.vue';
import StatisticsPage from './StatisticsPage.vue';
Vue.use(VueRouter);
const routes = [
{ path: '/', name: 'timer', component: TimerPage },
{ path: '/statistics', name: 'statistics', component: StatisticsPage },
];
const router = new VueRouter({
routes,
});
new Vue({
// router,
el: '#app',
router,
// store,
render: h => h(App),
}).$mount('#app');
});

8
package-lock.json generated
View File

@ -1,5 +1,5 @@
{
"name": "homepage",
"name": "dayoff",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
@ -6783,6 +6783,12 @@
"vue-style-loader": "^4.1.0"
}
},
"vue-router": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.6.tgz",
"integrity": "sha512-GYhn2ynaZlysZMkFE5oCHRUTqE8BWs/a9YbKpNLi0i7xD6KG1EzDqpHQmv1F5gXjr8kL5iIVS8EOtRaVUEXTqA==",
"dev": true
},
"vue-style-loader": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",

View File

@ -24,6 +24,7 @@
"underscore": "^1.9.2",
"vue": "^2.6.11",
"vue-loader": "^15.9.0",
"vue-router": "^3.1.6",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.41.6",

View File

@ -40,7 +40,7 @@ end
get "/api/status" do |env|
profile = app.profile Dayoff::ProfileId.new(env.get("profile_id").to_s)
total_span = profile.total_status now
total_span = profile.total_status now.at_beginning_of_day
today_span = profile.date_status now
data = {
started: profile.started?,