|
|
@ -1,5 +1,6 @@ |
|
|
|
<script lang="ts"> |
|
|
|
import type Item from "../models/item"; |
|
|
|
import type { LogResult } from "../models/log"; |
|
|
|
import type { ProjectResult } from "../models/project"; |
|
|
|
import Icon from "./Icon.svelte"; |
|
|
|
|
|
|
@ -8,95 +9,150 @@ |
|
|
|
amount: number |
|
|
|
target: number |
|
|
|
extras: number |
|
|
|
noTarget?: boolean |
|
|
|
} |
|
|
|
|
|
|
|
export let project: ProjectResult; |
|
|
|
export let project: ProjectResult = null; |
|
|
|
export let logs: LogResult[] = []; |
|
|
|
export let centered = false; |
|
|
|
export let vertical = false; |
|
|
|
|
|
|
|
let list: ListEntry[] = []; |
|
|
|
|
|
|
|
$: { |
|
|
|
list = []; |
|
|
|
for (const task of project.tasks) { |
|
|
|
let entry = list.find(e => e.item.id === task.item.id); |
|
|
|
if (entry == null) { |
|
|
|
entry = {item: task.item, amount: 0, target: 0, extras: 0}; |
|
|
|
list.push(entry); |
|
|
|
} |
|
|
|
|
|
|
|
if (task.completedAmount > task.itemAmount) { |
|
|
|
entry.extras += task.completedAmount - task.itemAmount; |
|
|
|
entry.amount += task.itemAmount; |
|
|
|
} else { |
|
|
|
entry.amount += task.completedAmount; |
|
|
|
} |
|
|
|
if (project != null) { |
|
|
|
for (const task of project.tasks) { |
|
|
|
let entry = list.find(e => e.item.id === task.item.id); |
|
|
|
if (entry == null) { |
|
|
|
entry = {item: task.item, amount: 0, target: 0, extras: 0}; |
|
|
|
list.push(entry); |
|
|
|
} |
|
|
|
|
|
|
|
if (["completed", "failed", "declined"].includes(task.statusTag)) { |
|
|
|
entry.target += task.itemAmount - Math.max(0, task.itemAmount - task.completedAmount); |
|
|
|
} else { |
|
|
|
entry.target += task.itemAmount; |
|
|
|
if (task.completedAmount > task.itemAmount) { |
|
|
|
entry.extras += task.completedAmount - task.itemAmount; |
|
|
|
entry.amount += task.itemAmount; |
|
|
|
} else { |
|
|
|
entry.amount += task.completedAmount; |
|
|
|
} |
|
|
|
|
|
|
|
if (["completed", "failed", "declined"].includes(task.statusTag)) { |
|
|
|
entry.target += task.itemAmount - Math.max(0, task.itemAmount - task.completedAmount); |
|
|
|
} else { |
|
|
|
entry.target += task.itemAmount; |
|
|
|
} |
|
|
|
|
|
|
|
for (const log of task.logs) { |
|
|
|
if (log.secondaryItem != null) { |
|
|
|
let entry = list.find(e => e.item.id === log.secondaryItemId); |
|
|
|
if (entry == null) { |
|
|
|
entry = {item: log.secondaryItem, amount: 0, target: 0, extras: 0}; |
|
|
|
list.push(entry); |
|
|
|
} |
|
|
|
|
|
|
|
entry.extras += log.secondaryItemAmount; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (const log of logs) { |
|
|
|
const items: [Item, number][] = [ |
|
|
|
[log.item, log.itemAmount], |
|
|
|
[log.secondaryItem, log.secondaryItemAmount] |
|
|
|
]; |
|
|
|
|
|
|
|
for (const log of task.logs) { |
|
|
|
if (log.secondaryItem != null) { |
|
|
|
let entry = list.find(e => e.item.id === log.secondaryItemId); |
|
|
|
for (const [item, count] of items) { |
|
|
|
if (item != null) { |
|
|
|
let entry = list.find(e => e.item.id === item.id); |
|
|
|
if (entry == null) { |
|
|
|
entry = {item: log.secondaryItem, amount: 0, target: 0, extras: 0}; |
|
|
|
entry = {item, amount: 0, target: 0, extras: 0, noTarget: true}; |
|
|
|
list.push(entry); |
|
|
|
} |
|
|
|
|
|
|
|
entry.extras += log.secondaryItemAmount; |
|
|
|
entry.amount += count; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
list = list.sort((a,b) => { |
|
|
|
if (a.noTarget && b.noTarget) { |
|
|
|
return a.amount - b.amount; |
|
|
|
} |
|
|
|
|
|
|
|
if (a.target === b.target) { |
|
|
|
return a.item.name.localeCompare(b.item.name); |
|
|
|
} else { |
|
|
|
return b.target - a.target; |
|
|
|
} |
|
|
|
}).filter(l => l.extras > 0 || l.target > 0); |
|
|
|
}).filter(l => l.extras > 0 || (l.target > 0 || l.noTarget)); |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<div class="ItemProgress"> |
|
|
|
{#each list as entry (entry.item.id)} |
|
|
|
<div class="entry"> |
|
|
|
<div class="icon"> |
|
|
|
<Icon name={entry.item.icon} /> |
|
|
|
</div> |
|
|
|
<div class="name"> |
|
|
|
{entry.item.name} |
|
|
|
</div> |
|
|
|
{#if entry.target !== 0} |
|
|
|
<div class="amount"> |
|
|
|
<span>{entry.amount}</span> |
|
|
|
<span> / </span> |
|
|
|
<span>{entry.target}</span> |
|
|
|
{#if entry.extras > 0} |
|
|
|
<span class="extras">+ {entry.extras}</span> |
|
|
|
{/if} |
|
|
|
</div> |
|
|
|
|
|
|
|
{:else} |
|
|
|
<div class="extras"> |
|
|
|
×{entry.extras} |
|
|
|
<div class="wrapper" class:centered class:vertical={vertical || list.length > 3}> |
|
|
|
{#each list as entry (entry.item.id)} |
|
|
|
<div class="entry"> |
|
|
|
{#if entry.noTarget} |
|
|
|
<div class="amount"> |
|
|
|
<span>{entry.amount}× </span> |
|
|
|
</div> |
|
|
|
{:else} |
|
|
|
<div class="icon"> |
|
|
|
<Icon name={entry.item.icon} /> |
|
|
|
</div> |
|
|
|
{/if} |
|
|
|
<div class="name"> |
|
|
|
{entry.item.name} |
|
|
|
</div> |
|
|
|
{/if} |
|
|
|
</div> |
|
|
|
{/each} |
|
|
|
{#if entry.target !== 0} |
|
|
|
<div class="amount"> |
|
|
|
<span>{entry.amount}</span> |
|
|
|
<span> / </span> |
|
|
|
<span>{entry.target}</span> |
|
|
|
{#if entry.extras > 0} |
|
|
|
<span class="extras">+ {entry.extras}</span> |
|
|
|
{/if} |
|
|
|
</div> |
|
|
|
{:else if !entry.noTarget} |
|
|
|
<div class="extras"> |
|
|
|
×{entry.extras} |
|
|
|
</div> |
|
|
|
{/if} |
|
|
|
</div> |
|
|
|
{/each} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<style> |
|
|
|
div.ItemProgress { |
|
|
|
display: inline-block; |
|
|
|
display: flex; |
|
|
|
flex-direction: row; |
|
|
|
} |
|
|
|
|
|
|
|
div.ItemProgress div.wrapper { |
|
|
|
display: flex; |
|
|
|
flex-direction: row; |
|
|
|
flex-wrap: wrap; |
|
|
|
padding: 0.25em; |
|
|
|
font-size: 0.8em; |
|
|
|
} |
|
|
|
div.ItemProgress div.wrapper.centered { |
|
|
|
margin: 0 auto; |
|
|
|
} |
|
|
|
div.ItemProgress div.wrapper.vertical { |
|
|
|
flex-direction: column; |
|
|
|
} |
|
|
|
|
|
|
|
div.ItemProgress div.entry { |
|
|
|
display: flex; |
|
|
|
flex-direction: row; |
|
|
|
color: #777; |
|
|
|
padding-right: 1ch; |
|
|
|
} |
|
|
|
div.ItemProgress div.wrapper.vertical div.entry { |
|
|
|
padding-right: 0; |
|
|
|
} |
|
|
|
div.ItemProgress div.entry div { |
|
|
|
padding: 0.1em 0.25em; |
|
|
@ -105,7 +161,7 @@ |
|
|
|
color: #555; |
|
|
|
} |
|
|
|
div.ItemProgress div.entry .icon { |
|
|
|
padding: 0.20em; |
|
|
|
padding: 0.20em 0.5ch; |
|
|
|
} |
|
|
|
div.ItemProgress div.entry .extras { |
|
|
|
color: #484; |
|
|
|