Add statistics table

This commit is contained in:
Anton Vakhrushev 2020-02-27 22:16:39 +03:00
parent 76bae89331
commit a2d8855f28
6 changed files with 122 additions and 5 deletions

View File

@ -18,6 +18,16 @@
</span> </span>
</section> </section>
<p class="profile-info">Профиль: {{ profileId }}</p> <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> </div>
</template> </template>
@ -31,11 +41,14 @@ export default {
started: false, started: false,
total_time: null, total_time: null,
today_time: null, today_time: null,
show_stat: false,
statistics: [],
}; };
}, },
created() { created() {
this.profileId = h.extract_profile_id(); this.profileId = h.extract_profile_id();
this.get_status(); this.get_status();
this.get_statistics();
setInterval(() => this.get_status(), 60 * 1000); setInterval(() => this.get_status(), 60 * 1000);
}, },
methods: { methods: {
@ -46,6 +59,11 @@ export default {
this.today_time = TimeSpan.fromObject(data.today.time); this.today_time = TimeSpan.fromObject(data.today.time);
}); });
}, },
get_statistics() {
h.get_statistics(this.profileId).then(data => {
this.statistics = data;
});
},
start() { start() {
h.start(this.profileId).then(() => this.get_status()); h.start(this.profileId).then(() => this.get_status());
}, },
@ -85,4 +103,8 @@ export default {
.profile-info { .profile-info {
margin-top: 2em; margin-top: 2em;
} }
.stat-table {
display: inline-table;
}
</style> </style>

View File

@ -32,4 +32,19 @@ async function finish(profileId) {
}); });
} }
export default { extract_profile_id, check_profile, get_status, start, finish }; async function get_statistics(profileId) {
const response = await fetch('/api/statistics?profile_id=' + profileId, {
method: 'GET',
});
const data = await response.json();
return data;
}
export default {
extract_profile_id,
check_profile,
get_status,
start,
finish,
get_statistics,
};

View File

@ -77,5 +77,11 @@ module Dayoff::Test
span = prof.date_status t(1, 15) span = prof.date_status t(1, 15)
span.total_hours.should eq 3 span.total_hours.should eq 3
end end
it "can get statistics" do
prof = create_profile
stat = prof.statistics t(3, 12)
stat.size.should eq 3
end
end end
end end

View File

@ -19,9 +19,10 @@ end
def serialize_span(span : Time::Span) def serialize_span(span : Time::Span)
{ {
status: span < Time::Span.zero ? STATUS_OVERTIME : STATUS_UPTIME, status: span < Time::Span.zero ? STATUS_OVERTIME : STATUS_UPTIME,
hours: span.abs.total_hours.to_i32, hours: span.abs.total_hours.to_i32,
minutes: span.abs.minutes.to_i32, minutes: span.abs.minutes.to_i32,
total_minutes: span.abs.total_minutes.to_i32,
} }
end end
@ -55,6 +56,19 @@ get "/api/status" do |env|
data.to_json data.to_json
end end
get "/api/statistics" do |env|
profile = app.profile Dayoff::ProfileId.new(env.get("profile_id").to_s)
data = profile.statistics now
mapped = data.map do |v|
{
date: v.date.to_s("%Y-%m-%d"),
planned: serialize_span(v.planned),
worked: serialize_span(v.worked),
}
end
mapped.to_json
end
get "/" do get "/" do
render "public/index.ecr" render "public/index.ecr"
end end

View File

@ -23,9 +23,13 @@ module Dayoff
def initialize(@date : Time, @hours : Int32) def initialize(@date : Time, @hours : Int32)
end end
def hours_as_span : Time::Span
Time::Span.new(hours: @hours, minutes: 0, seconds: 0)
end
def in_range(from_time : Time, to_time : Time) : Time::Span def in_range(from_time : Time, to_time : Time) : Time::Span
if @date >= from_time && @date < to_time if @date >= from_time && @date < to_time
Time::Span.new(hours: @hours, minutes: 0, seconds: 0) hours_as_span
else else
Time::Span.zero Time::Span.zero
end end
@ -61,6 +65,10 @@ module Dayoff
!@finish.nil? !@finish.nil?
end end
def get_span(to_time : Time) : Time::Span
in_range @start, to_time
end
def in_range(from_time : Time, to_time : Time) : Time::Span def in_range(from_time : Time, to_time : Time) : Time::Span
if finished? if finished?
in_range_finished from_time, to_time in_range_finished from_time, to_time

View File

@ -12,6 +12,23 @@ module Dayoff
end end
end end
class DayStatRecord
getter date
getter planned
getter worked
def initialize(@date : Time, @planned : Time::Span, @worked : Time::Span)
end
def add_planned(v : Time::Span)
@planned += v
end
def add_worked(v : Time::Span)
@worked += v
end
end
class Profile class Profile
@pdates = [] of PlannedDate @pdates = [] of PlannedDate
@wrecords = [] of WorkRecord @wrecords = [] of WorkRecord
@ -75,5 +92,40 @@ module Dayoff
worked = get_worked on_time.at_beginning_of_day, on_time worked = get_worked on_time.at_beginning_of_day, on_time
planned - worked planned - worked
end end
def statistics(on_time : Time) : Array(DayStatRecord)
dates = {} of String => DayStatRecord
@pdates.each do |pd|
key = pd.date.to_s("%Y-%m-%d")
dates[key] = DayStatRecord.new(
pd.date,
pd.hours_as_span,
Time::Span.zero
)
end
@wrecords.each do |wr|
key = wr.start.to_s("%Y-%m-%d")
if dates.has_key? key
dates[key].add_worked wr.in_range(Helpers.zero_time, on_time)
else
dates[key] = DayStatRecord.new(
wr.start,
Time::Span.zero,
wr.in_range(Helpers.zero_time, on_time)
)
end
end
date_keys = dates.keys.sort!.reverse!
result = [] of DayStatRecord
date_keys.each do |k|
result.push dates[k]
end
result
end
end end
end end