Refactor backend CORS settings to include default origins and improve error handling in chat services: Introduce dynamic CORS origin handling, enhance RabbitMQ message sending with fallback mechanisms, and update WebSocket service to manage pending messages. Update UI components for better accessibility and responsiveness, including adjustments to dialog and navigation elements. Enhance styling for improved user experience across various components.
This commit is contained in:
@@ -2,7 +2,14 @@
|
||||
<div class="contenthidden">
|
||||
<StatusBar ref="statusBar" />
|
||||
<div class="contentscroll">
|
||||
<h2>{{ $t('falukant.branch.title') }}</h2>
|
||||
<div class="falukant-branch">
|
||||
<section class="branch-hero surface-card">
|
||||
<div>
|
||||
<span class="branch-kicker">Niederlassung</span>
|
||||
<h2>{{ $t('falukant.branch.title') }}</h2>
|
||||
<p>Produktion, Lager, Verkauf und Transport in einer spielweltbezogenen Steuerflaeche.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<BranchSelection
|
||||
:branches="branches"
|
||||
@@ -308,6 +315,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1110,8 +1118,49 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
h2 {
|
||||
padding-top: 20px;
|
||||
.falukant-branch {
|
||||
max-width: var(--content-max-width);
|
||||
margin: 0 auto;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.branch-hero {
|
||||
padding: 24px 26px;
|
||||
margin-bottom: 16px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(248, 162, 43, 0.16), transparent 28%),
|
||||
linear-gradient(180deg, rgba(255, 250, 243, 0.98) 0%, rgba(247, 238, 224, 0.98) 100%);
|
||||
}
|
||||
|
||||
.branch-kicker {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(248, 162, 43, 0.14);
|
||||
color: #8a5411;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.branch-hero p {
|
||||
margin: 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.branch-tab-content {
|
||||
margin-top: 16px;
|
||||
padding: 18px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: rgba(255, 252, 247, 0.86);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.branch-tab-pane {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.send-all-vehicles {
|
||||
@@ -1161,11 +1210,12 @@ h2 {
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
background: rgba(255,255,255,0.98);
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
border-radius: var(--radius-lg);
|
||||
min-width: 400px;
|
||||
max-width: 600px;
|
||||
box-shadow: var(--shadow-medium);
|
||||
}
|
||||
|
||||
.send-vehicle-form {
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
<StatusBar />
|
||||
<div class="contentscroll family-layout">
|
||||
<div class="family-content">
|
||||
<h2>{{ $t('falukant.family.title') }}</h2>
|
||||
<section class="family-hero surface-card">
|
||||
<div>
|
||||
<span class="family-kicker">Familie</span>
|
||||
<h2>{{ $t('falukant.family.title') }}</h2>
|
||||
<p>Beziehungen, Kinder und familiäre Entwicklung in einer eigenen Spielweltansicht.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="spouse-section">
|
||||
<h3>{{ $t('falukant.family.spouse.title') }}</h3>
|
||||
@@ -36,7 +42,7 @@
|
||||
<td>
|
||||
<div class="progress">
|
||||
<div class="progress-inner" :style="{
|
||||
width: relationships[0].progress + '%',
|
||||
width: normalizeWooingProgress(relationships[0].progress) + '%',
|
||||
backgroundColor: progressColor(relationships[0].progress)
|
||||
}"></div>
|
||||
</div>
|
||||
@@ -200,6 +206,8 @@ import Character3D from '@/components/Character3D.vue'
|
||||
import apiClient from '@/utils/axios.js'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
const WOOING_PROGRESS_TARGET = 70
|
||||
|
||||
export default {
|
||||
name: 'FamilyView',
|
||||
components: {
|
||||
@@ -342,6 +350,8 @@ export default {
|
||||
},
|
||||
|
||||
async cancelWooing() {
|
||||
const confirmed = window.confirm(this.$t('falukant.family.spouse.wooing.cancelConfirm'));
|
||||
if (!confirmed) return;
|
||||
try {
|
||||
await apiClient.post('/api/falukant/family/cancel-wooing');
|
||||
await this.loadFamilyData();
|
||||
@@ -409,11 +419,16 @@ export default {
|
||||
},
|
||||
|
||||
progressColor(p) {
|
||||
const pct = Math.max(0, Math.min(100, p)) / 100;
|
||||
const pct = this.normalizeWooingProgress(p) / 100;
|
||||
const red = Math.round(255 * (1 - pct));
|
||||
const green = Math.round(255 * pct);
|
||||
return `rgb(${red}, ${green}, 0)`;
|
||||
},
|
||||
normalizeWooingProgress(p) {
|
||||
const raw = Number(p) || 0
|
||||
const normalized = (raw / WOOING_PROGRESS_TARGET) * 100
|
||||
return Math.max(0, Math.min(100, normalized))
|
||||
},
|
||||
|
||||
jumpToPartyForm() {
|
||||
this.$router.push({
|
||||
@@ -469,7 +484,33 @@ export default {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
padding-top: 24px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.family-hero {
|
||||
padding: 24px 26px;
|
||||
margin-bottom: 16px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(248, 162, 43, 0.16), transparent 28%),
|
||||
linear-gradient(180deg, rgba(255, 250, 243, 0.98) 0%, rgba(247, 238, 224, 0.98) 100%);
|
||||
}
|
||||
|
||||
.family-kicker {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(248, 162, 43, 0.14);
|
||||
color: #8a5411;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.family-hero p {
|
||||
margin: 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.self-character-3d {
|
||||
@@ -483,15 +524,20 @@ export default {
|
||||
|
||||
.family-content {
|
||||
flex: 1;
|
||||
max-width: var(--content-max-width);
|
||||
margin: 0 auto;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.spouse-section,
|
||||
.children-section,
|
||||
.lovers-section {
|
||||
border: 1px solid #ccc;
|
||||
margin: 10px 0;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--color-border);
|
||||
margin: 12px 0;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 16px;
|
||||
background: rgba(255, 252, 247, 0.86);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.relationship-container {
|
||||
@@ -513,8 +559,8 @@ export default {
|
||||
.partner-character-3d {
|
||||
width: 200px;
|
||||
height: 280px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background-color: #fdf1db;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -537,8 +583,8 @@ export default {
|
||||
.child-character-3d {
|
||||
width: 200px;
|
||||
height: 280px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background-color: #fdf1db;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -597,10 +643,6 @@ export default {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.relationship>table,
|
||||
.relationship>ul {
|
||||
display: inline-block;
|
||||
@@ -648,4 +690,11 @@ h2 {
|
||||
.set-heir-button:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
</style>
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.relationship-row,
|
||||
.children-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="falukant-overview">
|
||||
<StatusBar />
|
||||
<h2>{{ $t('falukant.overview.title') }}</h2>
|
||||
<section class="falukant-hero surface-card">
|
||||
<div>
|
||||
<span class="falukant-kicker">Falukant</span>
|
||||
<h2>{{ $t('falukant.overview.title') }}</h2>
|
||||
<p>Dein Stand in Wirtschaft, Familie und Besitz in einer verdichteten Uebersicht.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="falukantUser?.character" class="falukant-summary-grid">
|
||||
<article class="summary-card surface-card">
|
||||
<span class="summary-card__label">Niederlassungen</span>
|
||||
<strong>{{ branchCount }}</strong>
|
||||
<p>Direkter Zugriff auf deine wichtigsten Geschaeftsstandorte.</p>
|
||||
</article>
|
||||
<article class="summary-card surface-card">
|
||||
<span class="summary-card__label">Produktionen aktiv</span>
|
||||
<strong>{{ productionCount }}</strong>
|
||||
<p>Laufende Produktionen, die zeitnah Abschluss oder Kontrolle brauchen.</p>
|
||||
</article>
|
||||
<article class="summary-card surface-card">
|
||||
<span class="summary-card__label">Lagerpositionen</span>
|
||||
<strong>{{ stockEntryCount }}</strong>
|
||||
<p>Verdichteter Blick auf Warenbestand ueber alle Regionen.</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section v-if="falukantUser?.character" class="falukant-routine-grid">
|
||||
<article
|
||||
v-for="action in routineActions"
|
||||
:key="action.title"
|
||||
class="routine-card surface-card"
|
||||
>
|
||||
<span class="routine-card__eyebrow">{{ action.kicker }}</span>
|
||||
<h3>{{ action.title }}</h3>
|
||||
<p>{{ action.description }}</p>
|
||||
<button type="button" :class="action.secondary ? 'button-secondary' : ''" @click="openRoute(action.route)">
|
||||
{{ action.cta }}
|
||||
</button>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- Erben-Auswahl wenn kein Charakter vorhanden -->
|
||||
<div v-if="!falukantUser?.character" class="heir-selection-container">
|
||||
@@ -136,6 +175,7 @@
|
||||
import StatusBar from '@/components/falukant/StatusBar.vue';
|
||||
import Character3D from '@/components/Character3D.vue';
|
||||
import apiClient from '@/utils/axios.js';
|
||||
import { showError, showSuccess } from '@/utils/feedback.js';
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
const AVATAR_POSITIONS = {
|
||||
@@ -233,6 +273,50 @@ export default {
|
||||
const m = this.falukantUser?.money;
|
||||
return typeof m === 'string' ? parseFloat(m) : m;
|
||||
},
|
||||
branchCount() {
|
||||
return this.falukantUser?.branches?.length || 0;
|
||||
},
|
||||
productionCount() {
|
||||
return this.productions.length;
|
||||
},
|
||||
stockEntryCount() {
|
||||
return this.allStock.length;
|
||||
},
|
||||
routineActions() {
|
||||
return [
|
||||
{
|
||||
kicker: 'Routine',
|
||||
title: 'Niederlassung oeffnen',
|
||||
description: 'Die schnellste Route zu Produktion, Lager, Verkauf und Transport.',
|
||||
cta: 'Zu den Betrieben',
|
||||
route: 'BranchView',
|
||||
},
|
||||
{
|
||||
kicker: 'Ueberblick',
|
||||
title: 'Finanzen pruefen',
|
||||
description: 'Kontostand, Verlauf und wirtschaftliche Entwicklung ohne lange Suche.',
|
||||
cta: 'Geldhistorie',
|
||||
route: 'MoneyHistoryView',
|
||||
secondary: true,
|
||||
},
|
||||
{
|
||||
kicker: 'Charakter',
|
||||
title: 'Familie und Nachfolge',
|
||||
description: 'Wichtige persoenliche Entscheidungen und Haushaltsstatus gesammelt.',
|
||||
cta: 'Familie oeffnen',
|
||||
route: 'FalukantFamily',
|
||||
secondary: true,
|
||||
},
|
||||
{
|
||||
kicker: 'Besitz',
|
||||
title: 'Haus und Umfeld',
|
||||
description: 'Wohnsitz und alltaeglicher Status als eigener Arbeitsbereich.',
|
||||
cta: 'Zum Haus',
|
||||
route: 'HouseView',
|
||||
secondary: true,
|
||||
},
|
||||
];
|
||||
},
|
||||
locale() {
|
||||
return window.navigator.language || 'en-US';
|
||||
},
|
||||
@@ -369,6 +453,16 @@ export default {
|
||||
openBranch(branchId) {
|
||||
this.$router.push({ name: 'BranchView', params: { branchId } });
|
||||
},
|
||||
openRoute(routeName) {
|
||||
if (routeName === 'BranchView') {
|
||||
const firstBranch = this.falukantUser?.branches?.[0];
|
||||
if (firstBranch?.id) {
|
||||
this.openBranch(firstBranch.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.$router.push({ name: routeName });
|
||||
},
|
||||
async fetchProductions() {
|
||||
try {
|
||||
const response = await apiClient.get('/api/falukant/productions');
|
||||
@@ -399,15 +493,15 @@ export default {
|
||||
async selectHeir(heirId) {
|
||||
try {
|
||||
await apiClient.post('/api/falukant/heirs/select', { heirId });
|
||||
// Lade User-Daten neu
|
||||
await this.fetchFalukantUser();
|
||||
if (this.falukantUser?.character) {
|
||||
await this.fetchAllStock();
|
||||
await this.fetchProductions();
|
||||
}
|
||||
showSuccess(this, 'Erbe wurde uebernommen.');
|
||||
} catch (error) {
|
||||
console.error('Error selecting heir:', error);
|
||||
alert(this.$t('falukant.overview.heirSelection.error'));
|
||||
showError(this, this.$t('falukant.overview.heirSelection.error'));
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -415,16 +509,99 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.falukant-overview {
|
||||
max-width: var(--content-max-width);
|
||||
margin: 0 auto;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.falukant-hero {
|
||||
padding: 24px 26px;
|
||||
margin-bottom: 16px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(248, 162, 43, 0.16), transparent 28%),
|
||||
linear-gradient(180deg, rgba(255, 250, 243, 0.98) 0%, rgba(247, 238, 224, 0.98) 100%);
|
||||
}
|
||||
|
||||
.falukant-kicker {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(248, 162, 43, 0.14);
|
||||
color: #8a5411;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.falukant-hero p {
|
||||
margin: 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.falukant-summary-grid,
|
||||
.falukant-routine-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.falukant-routine-grid {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.summary-card,
|
||||
.routine-card {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.summary-card strong {
|
||||
display: block;
|
||||
margin: 6px 0 8px;
|
||||
font-size: 1.8rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.summary-card p,
|
||||
.routine-card p {
|
||||
margin: 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.summary-card__label,
|
||||
.routine-card__eyebrow {
|
||||
display: inline-flex;
|
||||
margin-bottom: 4px;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.76rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.routine-card h3 {
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
.routine-card button {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.overviewcontainer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
grid-gap: 5px;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.overviewcontainer>div {
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
padding: 16px;
|
||||
border-radius: var(--radius-lg);
|
||||
background: rgba(255, 253, 249, 0.82);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.imagecontainer {
|
||||
@@ -438,10 +615,12 @@ export default {
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background-color: rgba(255,255,255,0.72);
|
||||
background-repeat: no-repeat;
|
||||
image-rendering: crisp-edges;
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.house-with-character {
|
||||
@@ -453,8 +632,8 @@ export default {
|
||||
.house {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background-repeat: no-repeat;
|
||||
image-rendering: crisp-edges;
|
||||
z-index: 1;
|
||||
@@ -470,16 +649,13 @@ export default {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.heir-selection-container {
|
||||
border: 2px solid #dc3545;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(177, 59, 53, 0.18);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
background-color: #fff3cd;
|
||||
background-color: rgba(255, 243, 205, 0.92);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.heir-selection-container h3 {
|
||||
@@ -495,10 +671,10 @@ h2 {
|
||||
}
|
||||
|
||||
.heir-card {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 15px;
|
||||
background-color: white;
|
||||
background-color: rgba(255,255,255,0.86);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
@@ -518,6 +694,20 @@ h2 {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.falukant-routine-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.falukant-summary-grid,
|
||||
.falukant-routine-grid,
|
||||
.overviewcontainer {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.select-heir-button {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
@@ -535,6 +725,16 @@ h2 {
|
||||
.loading, .no-heirs {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.overviewcontainer {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.imagecontainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user