mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 06:47:07 +00:00
Add 4D comparisons list Vue component
This commit is contained in:
396
lib/www/client/source/src/views/GroupList.vue
Normal file
396
lib/www/client/source/src/views/GroupList.vue
Normal file
@@ -0,0 +1,396 @@
|
||||
<template>
|
||||
<v-container fluid>
|
||||
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="displayItems"
|
||||
item-key="group"
|
||||
:options.sync="options"
|
||||
:expanded.sync="expanded"
|
||||
show-expand
|
||||
:loading="loading"
|
||||
>
|
||||
|
||||
<template v-slot:item.group="{item, value}">
|
||||
<v-chip
|
||||
label
|
||||
small
|
||||
:href="`./${value}`"
|
||||
>{{ value }}</v-chip>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.shots_total="{item, value}">
|
||||
<div>{{ item.prime + item.other }}</div>
|
||||
<v-progress-linear
|
||||
background-color="secondary"
|
||||
color="primary"
|
||||
:value="item.prime/(item.prime+item.other)*100"
|
||||
></v-progress-linear>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.prime="{item, value}">
|
||||
{{ value }}
|
||||
({{ (value / (item.prime + item.other) * 100).toFixed(1) }}%)
|
||||
</template>
|
||||
|
||||
<template v-slot:item.other="{item, value}">
|
||||
{{ value }}
|
||||
({{ (value / (item.prime + item.other) * 100).toFixed(1) }}%)
|
||||
</template>
|
||||
|
||||
<template v-slot:item.prod_duration="{item, value}">
|
||||
<span v-if="value.days > 2" :title="`${value.days} d ${value.hours} h ${value.minutes} m ${(value.seconds + value.milliseconds/1000).toFixed(3)} s`">
|
||||
{{ value.days }} d
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ value.days }} d {{ value.hours }} h {{ value.minutes }} m {{ (value.seconds + value.milliseconds/1000).toFixed(1) }} s
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.prod_distance="{item, value}">
|
||||
{{ (value/1000).toFixed(1) }} km
|
||||
</template>
|
||||
|
||||
<template v-slot:item.shooting_rate_mean="{item, value}">
|
||||
{{ (value).toFixed(2) }} s ±{{ (item.shooting_rate_sd).toFixed(3) }} s
|
||||
</template>
|
||||
|
||||
<template v-slot:item.shots_per_point="{item, value}">
|
||||
<div>
|
||||
{{ ((item.prime + item.other)/item.points).toFixed(1) }}
|
||||
({{ ((((item.prime + item.other)/item.points) / item.num_projects)*100).toFixed(2) }}%)
|
||||
</div>
|
||||
<v-progress-linear
|
||||
:value="((((item.prime + item.other)/item.points) / item.num_projects)*100)"
|
||||
></v-progress-linear>
|
||||
</template>
|
||||
|
||||
<template v-slot:expanded-item="{ headers, item }">
|
||||
<td :colspan="headers.length">
|
||||
<v-data-table class="ma-1"
|
||||
:headers="projectHeaders"
|
||||
:items="item.projects"
|
||||
dense
|
||||
hide-default-footer
|
||||
>
|
||||
|
||||
<template v-slot:item.pid="{item, value}">
|
||||
<a :href="`/projects/${value}`" title="Go to project">{{ value }}</a>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.fsp="{item, value}">
|
||||
<span title="First production shot">{{value.tstamp.substr(0, 10)}}</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.lsp="{item, value}">
|
||||
<span title="Last production shot">{{value.tstamp.substr(0, 10)}}</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.prod_duration="{item, value}">
|
||||
<span v-if="value.days > 2" :title="`${value.days} d ${value.hours} h ${value.minutes} m ${(value.seconds + value.milliseconds/1000).toFixed(3)} s`">
|
||||
{{ value.days }} d
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ value.days }} d {{ value.hours }} h {{ value.minutes }} m {{ (value.seconds + value.milliseconds/1000).toFixed(1) }} s
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.prod_distance="{item, value}">
|
||||
{{ (value/1000).toFixed(1) }} km
|
||||
</template>
|
||||
|
||||
</v-data-table>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
</v-data-table>
|
||||
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
td p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import AccessMixin from '@/mixins/access';
|
||||
|
||||
|
||||
// FIXME send to lib/utils or so
|
||||
/*
|
||||
function duration_to_ms(v) {
|
||||
if (v instanceof Object) {
|
||||
return (
|
||||
(v.days || 0) * 86400000 +
|
||||
(v.hours || 0) * 3600000 +
|
||||
(v.minutes || 0) * 60000 +
|
||||
(v.seconds || 0) * 1000 +
|
||||
(v.milliseconds || 0)
|
||||
);
|
||||
} else {
|
||||
return {
|
||||
days: 0,
|
||||
hours: 0,
|
||||
minutes: 0,
|
||||
seconds: 0,
|
||||
milliseconds: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ms_to_duration(v) {
|
||||
const days = Math.floor(v / 86400000);
|
||||
v %= 86400000;
|
||||
const hours = Math.floor(v / 3600000);
|
||||
v %= 3600000;
|
||||
const minutes = Math.floor(v / 60000);
|
||||
v %= 60000;
|
||||
const seconds = Math.floor(v / 1000);
|
||||
const milliseconds = v % 1000;
|
||||
return { days, hours, minutes, seconds, milliseconds };
|
||||
}
|
||||
|
||||
function normalise_duration (v) {
|
||||
return ms_to_duration(duration_to_ms(v));
|
||||
}
|
||||
|
||||
function add_durations(a, b) {
|
||||
return ms_to_duration(duration_to_ms(a) + duration_to_ms(b));
|
||||
}
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: "GroupList",
|
||||
|
||||
components: {
|
||||
},
|
||||
|
||||
mixins: [
|
||||
AccessMixin
|
||||
],
|
||||
|
||||
data () {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
value: "group",
|
||||
text: "Group name"
|
||||
},
|
||||
{
|
||||
value: "num_projects",
|
||||
text: "Number of campaigns"
|
||||
},
|
||||
{
|
||||
value: "lines",
|
||||
text: "Preplot lines"
|
||||
},
|
||||
{
|
||||
value: "points",
|
||||
text: "Preplot points"
|
||||
},
|
||||
{
|
||||
value: "sequences",
|
||||
text: "Total sequences"
|
||||
},
|
||||
{
|
||||
value: "shots_total",
|
||||
text: "Total shots"
|
||||
},
|
||||
{
|
||||
value: "prime",
|
||||
text: "Total prime"
|
||||
},
|
||||
{
|
||||
value: "other",
|
||||
text: "Total reshoot + infill"
|
||||
},
|
||||
/*
|
||||
{
|
||||
value: "ntba",
|
||||
text: "Total NTBA"
|
||||
},
|
||||
*/
|
||||
{
|
||||
value: "prod_duration",
|
||||
text: "Total duration"
|
||||
},
|
||||
{
|
||||
value: "prod_distance",
|
||||
text: "Total distance"
|
||||
},
|
||||
{
|
||||
value: "shooting_rate_mean",
|
||||
text: "Shooting rate (mean)"
|
||||
},
|
||||
{
|
||||
value: "shots_per_point",
|
||||
text: "Shots per point"
|
||||
},
|
||||
],
|
||||
items: [],
|
||||
expanded: [],
|
||||
options: { sortBy: ["group"], sortDesc: [false] },
|
||||
|
||||
projectHeaders: [
|
||||
{
|
||||
value: "pid",
|
||||
text: "ID"
|
||||
},
|
||||
{
|
||||
value: "name",
|
||||
text: "Name"
|
||||
},
|
||||
{
|
||||
value: "fsp",
|
||||
text: "Start"
|
||||
},
|
||||
{
|
||||
value: "lsp",
|
||||
text: "Finish"
|
||||
},
|
||||
{
|
||||
value: "lines",
|
||||
text: "Preplot lines"
|
||||
},
|
||||
{
|
||||
value: "seq_final",
|
||||
text: "Num. of sequences"
|
||||
},
|
||||
{
|
||||
value: "prod_duration",
|
||||
text: "Duration"
|
||||
},
|
||||
{
|
||||
value: "prod_distance",
|
||||
text: "Distance"
|
||||
},
|
||||
],
|
||||
|
||||
// Context menu stuff
|
||||
contextMenuShow: false,
|
||||
contextMenuX: 0,
|
||||
contextMenuY: 0,
|
||||
contextMenuItem: null,
|
||||
|
||||
/*
|
||||
// FIXME Eventually need to move this into Vuex
|
||||
groups: []
|
||||
*/
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
displayItems () {
|
||||
return this.items.filter(i => i.prod_distance);
|
||||
},
|
||||
|
||||
...mapGetters(['loading', 'groups'])
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
/*
|
||||
async prepareGroups () {
|
||||
//const groups = await this.api(["/prospects"]);
|
||||
//console.log("groups", groups);
|
||||
const groups = {};
|
||||
|
||||
for (const project of this.projects) {
|
||||
|
||||
if (!project.prod_distance) {
|
||||
// This project has no production data (either not started yet
|
||||
// or production data has not been imported) so we skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!project.prod_duration.days) {
|
||||
project.prod_duration = normalise_duration(project.prod_duration);
|
||||
}
|
||||
|
||||
for (const name of project.groups) {
|
||||
if (!(name in groups)) {
|
||||
groups[name] = {
|
||||
group: name,
|
||||
num_projects: 0,
|
||||
lines: 0,
|
||||
points: 0,
|
||||
sequences: 0,
|
||||
// Shots:
|
||||
prime: 0,
|
||||
other: 0,
|
||||
ntba: 0,
|
||||
prod_duration: {
|
||||
days: 0,
|
||||
hours: 0,
|
||||
minutes: 0,
|
||||
seconds: 0,
|
||||
milliseconds: 0
|
||||
},
|
||||
prod_distance: 0,
|
||||
shooting_rate: [],
|
||||
projects: []
|
||||
};
|
||||
}
|
||||
const group = groups[name];
|
||||
|
||||
group.num_projects++;
|
||||
group.lines = Math.max(group.lines, project.lines); // In case preplots changed
|
||||
group.points = Math.max(group.points, project.total); // Idem
|
||||
group.sequences += project.seq_final;
|
||||
group.prime += project.prime;
|
||||
group.other += project.other;
|
||||
//group.ntba += project.ntba;
|
||||
group.prod_duration = add_durations(group.prod_duration, project.prod_duration);
|
||||
group.prod_distance += project.prod_distance;
|
||||
group.shooting_rate.push(project.shooting_rate);
|
||||
group.projects.push(project);
|
||||
}
|
||||
}
|
||||
|
||||
this.groups = [];
|
||||
for (const group of Object.values(groups)) {
|
||||
group.shooting_rate_mean = d3a.mean(group.shooting_rate);
|
||||
group.shooting_rate_sd = d3a.deviation(group.shooting_rate);
|
||||
delete group.shooting_rate;
|
||||
|
||||
this.groups.push(group);
|
||||
}
|
||||
|
||||
},
|
||||
*/
|
||||
|
||||
async list () {
|
||||
this.items = [...this.groups];
|
||||
},
|
||||
|
||||
async load () {
|
||||
await this.refreshProjects();
|
||||
//await this.prepareGroups();
|
||||
await this.list();
|
||||
},
|
||||
|
||||
registerNotificationHandlers () {
|
||||
this.$store.dispatch('registerHandler', {
|
||||
table: 'project`',
|
||||
|
||||
handler: (context, message) => {
|
||||
if (message.payload?.table == "public") {
|
||||
this.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
...mapActions(["api", "showSnack", "refreshProjects"])
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.registerNotificationHandlers();
|
||||
this.load();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
Reference in New Issue
Block a user