Änderung: - Der Daemon WebSocket wurde aufgrund von CORS- und Protokollproblemen deaktiviert. - Alle WebSocket-Interaktionen wurden auf Socket.io umgestellt, um die Funktionalität weiterhin zu gewährleisten. - Entsprechende Protokollausgaben wurden hinzugefügt, um den Status der Deaktivierung zu dokumentieren. Diese Anpassung verbessert die Stabilität der Anwendung und sorgt für eine konsistente Handhabung von WebSocket-Events.
190 lines
6.8 KiB
Vue
190 lines
6.8 KiB
Vue
<template>
|
|
<div class="statusbar">
|
|
<div class="status-item messages" @click="openMessages" :title="$t('falukant.messages.tooltip')">
|
|
<span class="badge" v-if="unreadCount > 0">{{ unreadCount }}</span>
|
|
<img src="/images/icons/falukant/messages24.png" class="menu-icon" />
|
|
</div>
|
|
<template v-for="item in statusItems" :key="item.key">
|
|
<div class="status-item" v-if="item.value !== null && item.image == null" :title="$t(`falukant.statusbar.${item.key}`)">
|
|
<span class="status-icon">
|
|
<template v-if="item.iconImage">
|
|
<img :src="'/images/icons/' + item.iconImage" class="inline-icon" width="16" height="16" />:
|
|
</template>
|
|
<template v-else>
|
|
{{ item.icon }}:
|
|
</template>
|
|
{{ item.value }}
|
|
</span>
|
|
</div>
|
|
<div class="status-item" v-else-if="item.image !== null" :title="$t(`falukant.statusbar.${item.key}`)">
|
|
<span class="status-icon">{{ item.icon }}:</span> <img :src="'/images/icons/falukant/relationship-' + item.image + '.png'" class="relationship-icon" />
|
|
</div>
|
|
</template>
|
|
<span v-if="statusItems.length > 0">
|
|
<template v-for="(menuItem, key) in menu.falukant.children" :key="menuItem.id" >
|
|
<img :src="'/images/icons/falukant/shortmap/' + key + '.png'" class="menu-icon" @click="openPage(menuItem)" :title="$t(`navigation.m-falukant.${key}`)" />
|
|
</template>
|
|
</span>
|
|
<MessagesDialog ref="msgs" />
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapState, mapGetters } from "vuex";
|
|
import apiClient from "@/utils/axios.js";
|
|
import MessagesDialog from './MessagesDialog.vue';
|
|
|
|
export default {
|
|
name: "StatusBar",
|
|
components: { MessagesDialog },
|
|
data() {
|
|
return {
|
|
statusItems: [
|
|
{ key: "age", icon: null, iconImage: 'falukant/age.png', value: 0 },
|
|
{ key: "relationship", icon: "💑", image: null },
|
|
{ key: "wealth", icon: "💰", value: 0 },
|
|
{ key: "health", icon: "❤️", value: "Good" },
|
|
{ key: "events", icon: "📰", value: null, image: null },
|
|
{ key: "children", icon: "👶", value: null },
|
|
],
|
|
unreadCount: 0,
|
|
};
|
|
},
|
|
computed: {
|
|
...mapState(["socket", "daemonSocket"]),
|
|
...mapGetters(['menu']),
|
|
},
|
|
async mounted() {
|
|
await this.fetchStatus();
|
|
if (this.socket) {
|
|
this.socket.on("falukantUpdateStatus", this.fetchStatus);
|
|
}
|
|
if (this.daemonSocket) {
|
|
this.daemonSocket.addEventListener("message", this.handleDaemonSocketMessage);
|
|
}
|
|
},
|
|
beforeUnmount() {
|
|
if (this.socket) {
|
|
this.socket.off("falukantUpdateStatus", this.fetchStatus);
|
|
}
|
|
if (this.daemonSocket) {
|
|
this.daemonSocket.removeEventListener("message", this.handleDaemonSocketMessage);
|
|
}
|
|
},
|
|
methods: {
|
|
async fetchStatus() {
|
|
try {
|
|
const response = await apiClient.get("/api/falukant/info");
|
|
const { money, character, events } = response.data;
|
|
const { age, health } = character;
|
|
const relationship = response.data.character.relationshipsAsCharacter1[0]?.relationshipType?.tr
|
|
|| response.data.character.relationshipsAsCharacter2[0]?.relationshipType?.tr
|
|
|| null;
|
|
// Children counts and unread notifications are now part of /info
|
|
const childCount = Number(response.data.childrenCount) || 0;
|
|
const unbaptisedCount = Number(response.data.unbaptisedChildrenCount) || 0;
|
|
this.unreadCount = Number(response.data.unreadNotifications) || 0;
|
|
const childrenDisplay = `${childCount}${unbaptisedCount > 0 ? `(${unbaptisedCount})` : ''}`;
|
|
let healthStatus = '';
|
|
if (health > 90) {
|
|
healthStatus = this.$t("falukant.health.amazing");
|
|
} else if (health > 75) {
|
|
healthStatus = this.$t("falukant.health.good");
|
|
} else if (health > 50) {
|
|
healthStatus = this.$t("falukant.health.normal");
|
|
} else if (health > 25) {
|
|
healthStatus = this.$t("falukant.health.bad");
|
|
} else {
|
|
healthStatus = this.$t("falukant.health.very_bad");
|
|
}
|
|
this.statusItems = [
|
|
{ key: "age", icon: null, iconImage: 'falukant/age.png', value: age },
|
|
{ key: "relationship", icon: "💑", image: relationship },
|
|
{ key: "wealth", icon: "💰", value: Intl.NumberFormat(navigator.language, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(money) },
|
|
{ key: "health", icon: "❤️", value: healthStatus },
|
|
{ key: "events", icon: "📰", value: events || null, image: null },
|
|
{ key: "children", icon: "👶", value: childrenDisplay },
|
|
];
|
|
} catch (error) {
|
|
console.error("Error fetching status:", error);
|
|
}
|
|
},
|
|
// Daemon WebSocket deaktiviert - verwende Socket.io Events
|
|
// Diese Methode wird nicht mehr verwendet
|
|
openPage(url, hasSubmenu = false) {
|
|
if (hasSubmenu) {
|
|
return;
|
|
}
|
|
if (url) {
|
|
this.$router.push(url);
|
|
}
|
|
},
|
|
openMessages() {
|
|
this.$refs.msgs.open();
|
|
// After opening, refresh unread count after a short delay (server marks them shown)
|
|
setTimeout(() => this.fetchStatus(), 500);
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.statusbar {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
background-color: #f4f4f4;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
width: calc(100% + 40px);
|
|
gap: 1.2em;
|
|
margin: -21px -20px 1.5em -20px;
|
|
position: fixed;
|
|
}
|
|
|
|
.status-item {
|
|
text-align: center;
|
|
cursor: pointer;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.status-icon {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.menu-icon {
|
|
width: 30px;
|
|
height: 30px;
|
|
cursor: pointer;
|
|
padding: 4px 2px 0 0;
|
|
}
|
|
|
|
.relationship-icon {
|
|
max-width: 24px;
|
|
max-height: 24px;
|
|
}
|
|
|
|
.messages { position: relative; }
|
|
.badge {
|
|
position: absolute;
|
|
top: -6px;
|
|
right: -2px;
|
|
background: #e53935;
|
|
color: #fff;
|
|
border-radius: 10px;
|
|
padding: 0 6px;
|
|
font-size: 12px;
|
|
line-height: 18px;
|
|
min-width: 18px;
|
|
text-align: center;
|
|
}
|
|
|
|
.inline-icon {
|
|
width: 16px;
|
|
height: 16px;
|
|
vertical-align: middle;
|
|
margin-right: 4px;
|
|
}
|
|
</style>
|