statsssss

This commit is contained in:
mcbloch 2023-12-07 04:52:52 +01:00
parent 51af80d6ba
commit 9af648f305
2 changed files with 285 additions and 52 deletions

View file

@ -4,6 +4,9 @@ import vweb
import db.sqlite import db.sqlite
import time import time
import net.http import net.http
import arrays
import maps
import math.stats
const http_port = 8080 const http_port = 8080
@ -24,15 +27,16 @@ pub fn (s Status) str() string {
} }
struct Person { struct Person {
id int @[primary; sql: serial] id int @[primary; sql: serial]
status int status int
name string name string
remark string remark string
order_time time.Time order_time time.Time
delivery_time time.Time
} }
pub fn (p Person) str() string { pub fn (p Person) str() string {
return 'Person[id:${p.id}, status:${p.status}]' return 'Person[id:${p.id}, name: ${p.name}, status:${p.status}, time:${p.order_time}, end:${p.delivery_time}]'
} }
pub fn (p Person) order_time_humanized() string { pub fn (p Person) order_time_humanized() string {
@ -69,6 +73,83 @@ fn get_people() ![]Person {
return people return people
} }
fn get_finished_count() !int {
mut db := create_db_connection()!
people := sql db {
select from Person where status == 3
}!
return people.len
}
struct PerHour {
t time.Time
label string
amount int
percentage int
color string
}
fn get_all() ![]Person {
mut db := create_db_connection()!
return sql db {
select from Person order by id desc
}!
}
fn get_last_delivered() ![]Person {
mut db := create_db_connection()!
return sql db {
select from Person order by delivery_time desc limit 1
}!
}
fn get_finished_per_hour() ![]PerHour {
mut db := create_db_connection()!
people := sql db {
select from Person where status == 3
}!
grouped := arrays.group_by(people, fn (p Person) string {
return '${p.order_time.hour}:${int(p.order_time.minute / 30) * 30} ${p.order_time.day}/${p.order_time.month}'
})
max_per_hour := arrays.max(grouped.values().map(it.len)) or { 1 } + 10
mut grouped_arr := maps.to_array(grouped, fn [max_per_hour] (k string, v []Person) PerHour {
return PerHour{
t: v[0].order_time
label: k
amount: v.len
percentage: int(v.len * 100 / max_per_hour)
color: (if v[0].order_time.hour % 2 == 0 { 'green' } else { 'red' })
}
})
grouped_arr.sort(a.t < b.t)
return grouped_arr
}
fn get_ppu() !f64 {
mut db := create_db_connection()!
mut people := sql db {
select from Person where status == 3
}!
people.sort(a.order_time < b.order_time)
time_range := people.last().order_time - people.first().order_time
return people.len / time_range.hours()
}
fn get_mean_time_between_pannenkoeken() !time.Duration {
mut db := create_db_connection()!
time_zero := time.Time{
unix: 0
}
mut people := sql db {
select from Person where (status == 3 && delivery_time > time_zero) order by delivery_time desc limit 10
}!
return stats.mean(arrays.window(people, size: 2).map(it[0].delivery_time - it[1].delivery_time))
}
fn status_update(user_id int) !Person { fn status_update(user_id int) !Person {
mut db := create_db_connection()! mut db := create_db_connection()!
people := sql db { people := sql db {
@ -78,6 +159,11 @@ fn status_update(user_id int) !Person {
sql db { sql db {
update Person set status = person.status + 1 where id == person.id update Person set status = person.status + 1 where id == person.id
}! }!
if person.status == 2 {
sql db {
update Person set delivery_time = time.now() where id == person.id
}!
}
return person return person
} }
@ -111,7 +197,7 @@ pub fn (app App) before_request() {
} }
fn main() { fn main() {
println('Start pannenkoeken webserver') println('Start 🥞 webserver')
mut db := create_db_connection() or { panic(err) } mut db := create_db_connection() or { panic(err) }
sql db { sql db {
@ -129,6 +215,40 @@ pub fn (mut app App) home() vweb.Result {
app.set_status(400, '') app.set_status(400, '')
return app.text('${err}') return app.text('${err}')
} }
person_finished_count := get_finished_count() or {
app.set_status(400, '')
return app.text('${err}')
}
finished_per_hour := get_finished_per_hour() or {
app.set_status(400, '')
return app.text('${err}')
}
// pannenkoek per uur
ppu := get_ppu() or {
app.set_status(400, '')
return app.text('${err}')
}
all_people := get_all() or {
app.set_status(400, '')
return app.text('${err}')
}
mean_time := get_mean_time_between_pannenkoeken() or {
app.set_status(400, '')
return app.text('${err}')
}
mut last_delivered := get_last_delivered() or {
app.set_status(400, '')
return app.text('${err}')
}
if last_delivered.len == 0 {
last_delivered << Person{
delivery_time: time.now()
}
}
// Time to pannenkoek
time_since_last := (time.now() - last_delivered.first().delivery_time)
ttp := time.unix(i64(mean_time.seconds() - time_since_last.seconds())) - time.unix(0)
return $vweb.html() return $vweb.html()
} }

View file

@ -1,10 +1,11 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.5"> <meta name="viewport" content="width=device-width, initial-scale=1.5">
<title>Pannenkoekenwachtrij</title> <title>🥞wachtrij</title>
<link href="https://cdn.jsdelivr.net/npm/tuicss@@2.1.1/dist/tuicss.min.css" rel="stylesheet"/> <link href="https://cdn.jsdelivr.net/npm/tuicss@@2.1.1/dist/tuicss.min.css" rel="stylesheet" />
<style> <style>
.tui-window { .tui-window {
width: 100%; width: 100%;
@ -18,7 +19,8 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
td, th { td,
th {
text-align: center; text-align: center;
} }
@ -27,14 +29,64 @@
} }
</style> </style>
</head> </head>
<body class="tui-bg-green-black"> <body class="tui-bg-green-black">
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 80%"> <div style="margin: auto; width: 60%; margin-top: 40px;">
<div class="container" style="width: 100%"> <div class="container" style="width: 100%">
<div class="row"> <div class="row">
<div class="col m12"> <div class="col m6">
<div class="tui-window red-168"> <div class="tui-window red-168">
<fieldset class="tui-fieldset"> <fieldset class="tui-fieldset">
Welkom bij de pannenkoekenwachtrij Welkom bij de 🥞wachtrij
</fieldset>
</div>
</div>
<div class="col m6">
<div class="tui-window red-168">
<fieldset class="tui-fieldset">
Er zijn al @person_finished_count 🥞 afgeleverd!
<br />
Dat is @{ppu:.2} 🥞/uur
<br />
Gemiddelde tijd tussen 🥞: @{mean_time.str()}
<br/>
<span id="ttp">
TTP:
@if ttp < 0
Soon™
@else
@ttp
@end
</span>
<script>
function time_left_string(time_left) {
let minutes = Math.floor(time_left / 60000);
let seconds = Math.floor((time_left - minutes * 60000) / 1000);
if (seconds < 10) {
seconds = "0" + seconds;
}
return minutes + ":" + seconds + ".000";
}
let ttp = new Date(@ttp.milliseconds())
console.log(ttp)
if (ttp.getTime() > 0){
const ttp_span = document.getElementById('ttp')
console.log('sd')
setInterval(function(){
console.log(ttp.getTime())
ttp.setTime(ttp.getTime() - 1000)
console.log(ttp.getTime())
console.log('----')
if (ttp.getTime() <= 0) {
ttp_span.innerText = "TTP: Soon™"
} else {
ttp_span.innerText = "TTP: " + time_left_string(ttp)
}
}, 1000)
}
</script>
</fieldset> </fieldset>
</div> </div>
</div> </div>
@ -47,18 +99,21 @@
<div class="row"> <div class="row">
<div class="col m12" style="display: inline-flex"> <div class="col m12" style="display: inline-flex">
Naam van de volgende: Naam van de volgende:
<input class="tui-input" type="text" id="name" name="name" style="margin-left: 10px; flex: 1"> <input class="tui-input" type="text" id="name" name="name"
style="margin-left: 10px; flex: 1">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col m12" style="display: inline-flex"> <div class="col m12" style="display: inline-flex">
Specifieke opmerkingen: Specifieke opmerkingen:
<input class="tui-input" type="text" id="remark" name="remark" style="margin-left: 10px; flex: 1"> <input class="tui-input" type="text" id="remark" name="remark"
style="margin-left: 10px; flex: 1">
</div> </div>
</div> </div>
<div class="row" style="margin-bottom: 10px"> <div class="row" style="margin-bottom: 10px">
<div class="col m12" style="display: inline-flex"> <div class="col m12" style="display: inline-flex">
<input class="tui-button green-168" type="submit" value="Persoon toevoegen" style="flex: 1; margin-bottom: 0px;"> <input class="tui-button green-168" type="submit" value="Persoon toevoegen"
style="flex: 1; margin-bottom: 0px;">
</div> </div>
</div> </div>
</form> </form>
@ -73,7 +128,8 @@
<fieldset class="tui-fieldset"> <fieldset class="tui-fieldset">
<form action="/status_update" method="POST"> <form action="/status_update" method="POST">
<input type="hidden" name="id" value="@{people[0].id}"> <input type="hidden" name="id" value="@{people[0].id}">
<input class="tui-button green-168" type="submit" value="Update First Person" style="width: 100%"> <input class="tui-button green-168" type="submit" value="Update First Person"
style="width: 100%">
</form> </form>
</fieldset> </fieldset>
</div> </div>
@ -84,44 +140,47 @@
<div class="col m12"> <div class="col m12">
<div class="tui-window red-168"> <div class="tui-window red-168">
<fieldset class="tui-fieldset"> <fieldset class="tui-fieldset">
<h2>Zie hieronder de lijst van personen die een pannenkoek willen</h2> <h2>Zie hieronder de lijst van personen die een 🥞 willen</h2>
<table class="tui-table" style="width: 100%"> <table class="tui-table" style="width: 100%">
<tbody> <tbody>
<tr> <tr>
<td colspan="4" style="text-align:center; vertical-align:middle; padding-top: 20px">Volgende persoon</td> <td colspan="4"
style="text-align:center; vertical-align:middle; padding-top: 20px">Volgende
persoon</td>
</tr> </tr>
@if people.len > 0 @if people.len > 0
@for person in people[..1] @for person in people[..1]
<tr> <tr>
<td>@person.name @person.remark()</td> <td>@person.name @person.remark()</td>
<td>@person.status_str()</td> <td>@person.status_str()</td>
<td>@person.order_time_humanized()</td> <td>@person.order_time_humanized()</td>
<td> <td>
<form action="/status_update" method="POST"> <form action="/status_update" method="POST">
<input type="hidden" name="id" value="@person.id"> <input type="hidden" name="id" value="@person.id">
<input class="tui-button green-168" type="submit" value="Update"> <input class="tui-button green-168" type="submit" value="Update">
</form> </form>
</td> </td>
</tr> </tr>
@end @end
@end @end
<tr> <tr>
<td colspan="4" style='text-align:center; vertical-align:middle'>Andere personen</td> <td colspan="4" style='text-align:center; vertical-align:middle'>Andere personen
</td>
</tr> </tr>
@if people.len > 1 @if people.len > 1
@for person in people[1..] @for person in people[1..]
<tr> <tr>
<td>@person.name @person.remark()</td> <td>@person.name @person.remark()</td>
<td>@person.status_str()</td> <td>@person.status_str()</td>
<td>@person.order_time_humanized()</td> <td>@person.order_time_humanized()</td>
<td> <td>
<form action="/status_update" method="POST"> <form action="/status_update" method="POST">
<input type="hidden" name="id" value="@person.id"> <input type="hidden" name="id" value="@person.id">
<input class="tui-button green-168" type="submit" value="Update"> <input class="tui-button green-168" type="submit" value="Update">
</form> </form>
</td> </td>
</tr> </tr>
@end @end
@end @end
</tbody> </tbody>
</table> </table>
@ -129,7 +188,61 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row">
<div class="col m12">
<div class="tui-window red-168">
<fieldset class="tui-fieldset">
<h2>Aantal bestelde 🥞</h2>
<div class="tui-chart-vertical" style="width: 100%; height: 200px;">
<div class="tui-chart-display">
@for ph in finished_per_hour
<div class="tui-chart-value @ph.color-168" style="height: @{ph.percentage}%;">
@ph.amount</div>
@end
</div>
<!-- <div class="tui-chart-y-axis">
<div class="tui-chart-legend">100%</div>
<div class="tui-chart-legend">75%</div>
<div class="tui-chart-legend">50%</div>
<div class="tui-chart-legend">25%</div>
</div> -->
<div class="tui-chart-x-axis">
@for ph in finished_per_hour
<div class="tui-chart-legend">@ph.label</div>
@end
</div>
</div>
</fieldset>
</div>
</div>
</div>
</div> </div>
<!-- <table class="container tui-window">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>remark</th>
<th>status</th>
<th>order time</th>
<th>delivery time</th>
</tr>
</thead>
<tbody>
@for p in all_people
<tr>
<td>@p.id</td>
<td>@p.name</td>
<td>@p.remark</td>
<td>@p.status</td>
<td>@p.order_time</td>
<td>@p.delivery_time</td>
</tr>
@end
</tbody>
</table> -->
</div> </div>
</body> </body>
</html> </html>