mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-02 07:40:28 +00:00
Add total price indicator to labels and locations
This commit is contained in:
parent
8cc0f30291
commit
58cf7e816b
3 changed files with 78 additions and 5 deletions
|
@ -193,6 +193,7 @@ export interface LabelOut {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
updatedAt: Date | string;
|
updatedAt: Date | string;
|
||||||
|
totalPrice: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LabelSummary {
|
export interface LabelSummary {
|
||||||
|
@ -217,6 +218,7 @@ export interface LocationOut {
|
||||||
name: string;
|
name: string;
|
||||||
parent: LocationSummary;
|
parent: LocationSummary;
|
||||||
updatedAt: Date | string;
|
updatedAt: Date | string;
|
||||||
|
totalPrice: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LocationOutCount {
|
export interface LocationOutCount {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import Currency from "~~/components/global/Currency.vue";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
});
|
});
|
||||||
|
@ -84,6 +86,8 @@
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label.value.totalPrice = resp.data.items.map(item => Number(item.purchasePrice)).reduce((a, b) => a + b, 0);
|
||||||
|
|
||||||
return resp.data.items;
|
return resp.data.items;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -111,8 +115,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-2xl pb-1">
|
<h1 class="text-2xl pb-1 flex items-center gap-3">
|
||||||
{{ label ? label.name : "" }}
|
{{ label ? label.name : "" }}
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="label && label.totalPrice"
|
||||||
|
class="text-xs bg-secondary text-secondary-content rounded-full px-2 py-1"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Currency :amount="label.totalPrice" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="flex gap-1 flex-wrap text-xs">
|
<div class="flex gap-1 flex-wrap text-xs">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { LocationSummary, LocationUpdate } from "~~/lib/api/types/data-contracts";
|
import { LocationSummary, LocationUpdate, TreeItem } from "~~/lib/api/types/data-contracts";
|
||||||
import { useLocationStore } from "~~/stores/locations";
|
import { useLocationStore } from "~~/stores/locations";
|
||||||
|
import Currency from "~~/components/global/Currency.vue";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
|
@ -89,8 +90,47 @@
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const locationTreeResp = await api.locations.getTree();
|
||||||
|
|
||||||
|
if (locationTreeResp.error) {
|
||||||
|
toast.error("Failed to load items");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullLocationTree: TreeItem[] = locationTreeResp.data;
|
||||||
|
|
||||||
|
function flattenLocation(location: TreeItem): string[] {
|
||||||
|
return location.children.reduce((acc, child) => [...acc, ...flattenLocation(child)], [location.id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findObjectById(locations: TreeItem[], targetId: string): TreeItem | undefined {
|
||||||
|
if (!locations || !Array.isArray(locations)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = locations.find(location => location.id === targetId);
|
||||||
|
if (target) return target;
|
||||||
|
|
||||||
|
for (let i = 0; i < locations.length; i++) {
|
||||||
|
const result = findObjectById(locations[i].children, targetId);
|
||||||
|
if (result) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const locationTree: TreeItem | undefined = findObjectById(fullLocationTree, location.value.id);
|
||||||
|
|
||||||
|
if (!locationTree) {
|
||||||
|
toast.error("Failed to get tree for current location");
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const allChildLocations = flattenLocation(locationTree);
|
||||||
|
|
||||||
const resp = await api.items.getAll({
|
const resp = await api.items.getAll({
|
||||||
locations: [location.value.id],
|
locations: allChildLocations,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (resp.error) {
|
if (resp.error) {
|
||||||
|
@ -98,7 +138,16 @@
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.data.items;
|
const locationItems = resp.data.items.filter(item => {
|
||||||
|
if (item.location && location.value) return item?.location.id === location?.value.id;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalPrice = resp.data.items.map(item => Number(item.purchasePrice)).reduce((a, b) => a + b, 0);
|
||||||
|
|
||||||
|
location.value.totalPrice = totalPrice;
|
||||||
|
|
||||||
|
return locationItems;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -135,8 +184,17 @@
|
||||||
<li>{{ location.name }}</li>
|
<li>{{ location.name }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-2xl pb-1">
|
<h1 class="text-2xl pb-1 flex items-center gap-3">
|
||||||
{{ location ? location.name : "" }}
|
{{ location ? location.name : "" }}
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="location && location.totalPrice"
|
||||||
|
class="text-xs bg-secondary text-secondary-content rounded-full px-2 py-1"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Currency :amount="location.totalPrice" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="flex gap-1 flex-wrap text-xs">
|
<div class="flex gap-1 flex-wrap text-xs">
|
||||||
<div>
|
<div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue