Skip to content

Backend Sektion

Die Backend Sektion befindet sich innerhalb des Components Ordner´s. Dort befinden sich alle Components und Dateien, die mit dem Backend zu tun haben.

Aufbau und Verbindung

Das Backend ist die Schnittstelle zwischen User (Redakteur) und der Datenbank. Um Veränderungen in die Datenbank einzutragen wird die API-Schnittstelle benötigt. Diese ist abhängig am entsprechenden Kunden. Die Denfinition und Abfragen, welche an die API gehen findest du hier Pinia .

In backend Paket findet man alle Vue Dateien, welche in irgendeiner Art und Weise im views Paket referenziert werden. Dies ist von View zu View unterschiedlich.

Sektionen

Das Backend ist in verschidene Sektionen unterteilt. Folgend wird erklärt was in den einzelnen Sektion zu finden ist und einige technischen Informationen.

Ligen & Turniere

In den Ligen- und Turnier- Ansicht werden alle Daten vom spezifischen Kunden angezeigt.

Details

Der View ist in diesem Fall LeagueView.vue

Die Abfrage der Daten erfolgt so

ts
let retrieveData = (page: number) => {
  // get data via page
  store.getObjectsViaPage("League", 1000, page).then((res) => {
    leagues.value = res.objects;
  });
};
let retrieveData = (page: number) => {
  // get data via page
  store.getObjectsViaPage("League", 1000, page).then((res) => {
    leagues.value = res.objects;
  });
};

Innerhalb des Views befindet sich eine Tabelle, welche die Ligen darstellt. Zu dem können Aktionen an den Ligen vorgenommen werden. Beispielsweise kann eine Liga, über einen Knopf gelöscht werden.

ts
let deleteLeague = (league: League) => {
  if (confirm("Möchtest du die Liga wirklich löschen ?")) {
    store.deleteObject("League", league.id, undefined).then((res: any) => {
      console.log(res);
    });
    const index = leagues.value?.indexOf(league);
    if (index !== undefined && index > -1) {
      leagues.value?.splice(index, 1);
    }
  }
};
let deleteLeague = (league: League) => {
  if (confirm("Möchtest du die Liga wirklich löschen ?")) {
    store.deleteObject("League", league.id, undefined).then((res: any) => {
      console.log(res);
    });
    const index = leagues.value?.indexOf(league);
    if (index !== undefined && index > -1) {
      leagues.value?.splice(index, 1);
    }
  }
};

Liga Detail

So bald man auf eine Liga klickt in der Liste aller Ligen (LeagueView.vue) befindet man sich im Component LeagueDetail.vue. Dieser dient um alle Daten welche dieser Liga wichtig sind anzuzeigen. Wichtig hierbei ist immer den Kontext der Saison zu sehen, sprich sollte sich die Saison-Id in SeasonSelector ändern werden abfragen neu getriggert. Dies geschient in deer LeagueDetail.vue mit dem watch Property.

vue
<script setup lang="ts">
import { watch, computed } from 'vue'

let currentSeasonId = computed(() => {
  if (season_id.value == -1) {
    var x = seasons.find((el: { current: number }) => el.current == 1);
    return x.id;
  } else {
    return season_id.value;
  }
});

watch(
  () => currentSeasonId.value,
  (newVal) => {
    if (league.value && league.value.league_seasons) {
      league_season.value = league.value.league_seasons.find(
        (el: LeagueSeason) => el.fkSeason == newVal,
      );

      if (league_season.value == undefined) {
        showLeagueSeasonEditModal();
      }
    }
  },
);
</script>
<script setup lang="ts">
import { watch, computed } from 'vue'

let currentSeasonId = computed(() => {
  if (season_id.value == -1) {
    var x = seasons.find((el: { current: number }) => el.current == 1);
    return x.id;
  } else {
    return season_id.value;
  }
});

watch(
  () => currentSeasonId.value,
  (newVal) => {
    if (league.value && league.value.league_seasons) {
      league_season.value = league.value.league_seasons.find(
        (el: LeagueSeason) => el.fkSeason == newVal,
      );

      if (league_season.value == undefined) {
        showLeagueSeasonEditModal();
      }
    }
  },
);
</script>

Dann gibt es die Tabs in der Detail Ansicht -> Übersicht, Mannschaften und Spielplan In dem Übersichts-Tab findet man alle Information aus der Datenbank zum LeagueSeason Eintrag. Hier kann man Einstellen ob ein Spielplan gespiegelt werden soll oder wie viele Auf- und Absteiger es geben soll. Sollte noch kein Eintrag zur Saison bestehen öffnet sich das Modal zum Erstellen.

Der zweite Tab "Mannschaften" beinhaltet alle LeagueTeamMap Einträge aus der Datenbank in einer Tabelle (Saisonbezogen). Als Component wird hierfür LeagueTeamList.vue verwendet. Die Teams in der Liste werden mit dem TeamEditModal.vue editiert. In diesem Modal können beispielsweise auch Punkteanpassungen LeagueAdjustment vorgenommen werden.

Der dritte Tab "Spielplan" beinhaltet alle Spiele aufgeteilt nach Spieltag einer Liga. Der Component ist MatchPlan.vue und dieser ist wohl aktuell der größte Component mit den meisten Funktionen. Diese sind Spieltag löschen, tauschen und übertragen.

Löschen

ts
let deleteAllMatchesFromMatchDay = () => {
  if (confirm("Sollen alle Spiele vom Spieltag gelöscht werden?")) {
    is_loading.value = true;
    if (matches.value && matches.value.length > 0) {
      matches.value.forEach((element: any) => {
        if (element.id && element.matchDay == match_day.value) {
          store.deleteMatch(element.id).then(() => {
            setTimeout(() => {
              retrieveMatchData(false);
              is_loading.value = false;
            }, 1500);
          });
        }
      });
    }
  }
};
let deleteAllMatchesFromMatchDay = () => {
  if (confirm("Sollen alle Spiele vom Spieltag gelöscht werden?")) {
    is_loading.value = true;
    if (matches.value && matches.value.length > 0) {
      matches.value.forEach((element: any) => {
        if (element.id && element.matchDay == match_day.value) {
          store.deleteMatch(element.id).then(() => {
            setTimeout(() => {
              retrieveMatchData(false);
              is_loading.value = false;
            }, 1500);
          });
        }
      });
    }
  }
};

Tauschen hier öffnet sich ein Modal mit dem Input mit welchem Spieltag getauscht werden soll. Dann werden die Spiele angezeigt. Sollten man aufspeichern klicken passiert folgendes.

ts
let saveSwitchMatchDay = () => {
  if (modal_match_day.value) {
    is_loading.value = true;
    let temp_matches = [];
    matches.value.forEach((element: any) => {
      element.matchDay = modal_match_day.value;
      temp_matches.push(element);
    });
    modal_matches.value.forEach((element: any) => {
      element.matchDay = match_day.value;
      temp_matches.push(element);
    });
    temp_matches.forEach((element: any) => {
      store.editObject("Match", element);
    });
    showInfoContainer();
  }
  closeModal(true);
};
let saveSwitchMatchDay = () => {
  if (modal_match_day.value) {
    is_loading.value = true;
    let temp_matches = [];
    matches.value.forEach((element: any) => {
      element.matchDay = modal_match_day.value;
      temp_matches.push(element);
    });
    modal_matches.value.forEach((element: any) => {
      element.matchDay = match_day.value;
      temp_matches.push(element);
    });
    temp_matches.forEach((element: any) => {
      store.editObject("Match", element);
    });
    showInfoContainer();
  }
  closeModal(true);
};

Übertragen eines Spieltags werden alle Teams Heim und Auswärts getauscht und man muss beim Speichern mit geben was der Spieltag sein soll (number)

ts
let saveDuplicateMatchDay = () => {
  if (modal_matches.value) {
    is_loading.value = true;
    modal_matches.value.forEach((element: any) => {
      delete element.team_home;
      delete element.team_away;
      element.matchDay = modal_match_day.value;
      store.createObject("Match", element);
    });
    showInfoContainer();
  }
  closeModal(true);
};
let saveDuplicateMatchDay = () => {
  if (modal_matches.value) {
    is_loading.value = true;
    modal_matches.value.forEach((element: any) => {
      delete element.team_home;
      delete element.team_away;
      element.matchDay = modal_match_day.value;
      store.createObject("Match", element);
    });
    showInfoContainer();
  }
  closeModal(true);
};

Teams

Hier finden Sie alle Teams zu einem Publisher Pageniert in einer Tabelle.

Spielkalender

Hier finden Sie eine Zusammenfassung aller Spiele, die zum Publisher gehören. Die Tabs sind unterteilt in Spielkalender, Fehlende Ergebnisse und Sonderwertungen. Im Tab "Spielkalender" haben Sie die Möglichkeit, ein Datum auszuwählen, und die Ansicht zeigt die entsprechenden Ergebnisse an. Darüber hinaus besteht die Möglichkeit, mit dem Button "Zeitraum" einen Zeitraum auszuwählen, um Spiele zu selektieren.

Die Anischt "Fehlende Ergebnisse" zeigt in einem Zeitraum von -7 Tagen alle Spiele ohne Ergebniss an und in der Ansicht "Sonderwertung" finden Sie alle Spiele mit einer Sonderwertung.

Match Objekt -> goalsHome oder goalsAway == nullMatch Objekt -> resultCode

In der Ansicht werden Basis-Funktionen wie CRUD an den einzelnen Spiele ermöglicht.

Die Darstellungen der Spiele findet rein technisch mit dem component MatchList.vue statt. Als props muss das Array mit dem dict´s übergeben werden und ob resultCodes mit angezeigt werden sollen props.matches (array "any" ) und props.is_result_codes (bool). MatchList.vue hat drei emits -> saveMatches, reload und deleteMatch.

Bei saveMatches wird eine Array mit allen geänderten Spielen aus der Liste von props.matches zurück an den Vater-Component übergeben um dort dann via Pinia Store es an die API weiterzugeben und zu speichern.

Bei deleteMatch wird die Id eines Spiels an den Vater-Component übergeben um dort dann mit dem Pinia Store das Spiel zu löschen und mit reload wird beim Vater-Component getriggert das alle Spiele nochmal von der API geholt werden und props.matches ersetzt wird.

Einbindung der MatchList.vue in einen anderen Component, MatchList kann immer importiert werden sollte die Matches die in geparsed werden im richtigen Format sein.

vue
<template>
  <MatchList
    :matches="matches_calendar"
    :is_result_codes="false"
    @save-matches="saveMatchCalendar"
    @delete-match="deleteMatchFromMatchCalendar"
    @reload="retrieveMatchCalendar"
  />
</template>
<script lang="ts" setup>
import MatchList from "@/match/MatchList.vue";
import { ref } from 'vue';
import { store as useStore } from "@/stores";

const store = useStore();

let matches_calendar = ref([]);
// methods
let saveMatchesCalendar = (changed_matches: array<any>) => {
  if (changed_matches.length > 0) {
    changed_matches.forEach((match) => {
      if (typeof match.goalsHome == "string" && match.goalsHome == "") {
        match.goalsHome = null;
      }

      if (typeof match.goalsAway == "string" && match.goalsAway == "") {
        match.goalsAway = null;
      }
      store.editObject("Match", match);
    });

    setTimeout(() => {
      matches_calendar.value = [];
      retrieveMatchCalendar();
    }, 1000);
  }
}

... other methods
</script>
<template>
  <MatchList
    :matches="matches_calendar"
    :is_result_codes="false"
    @save-matches="saveMatchCalendar"
    @delete-match="deleteMatchFromMatchCalendar"
    @reload="retrieveMatchCalendar"
  />
</template>
<script lang="ts" setup>
import MatchList from "@/match/MatchList.vue";
import { ref } from 'vue';
import { store as useStore } from "@/stores";

const store = useStore();

let matches_calendar = ref([]);
// methods
let saveMatchesCalendar = (changed_matches: array<any>) => {
  if (changed_matches.length > 0) {
    changed_matches.forEach((match) => {
      if (typeof match.goalsHome == "string" && match.goalsHome == "") {
        match.goalsHome = null;
      }

      if (typeof match.goalsAway == "string" && match.goalsAway == "") {
        match.goalsAway = null;
      }
      store.editObject("Match", match);
    });

    setTimeout(() => {
      matches_calendar.value = [];
      retrieveMatchCalendar();
    }, 1000);
  }
}

... other methods
</script>

Freundschaftsspiele

Diese Sektion beinhaltet eine Liste aller Freundschaftsspiele eines Kunden. In der Liste tauchen die Spiele auf, welche mit einem EditModal editiert werden können. FriendlyMatchView. Die Suche ist in diesem eine Funktion wo nach Matches mit der fkLeague 88 und der entsprechenden Team-Id gefunden werden. Die Mehthode im Store heißt retrieveFriendlyMatchesFromTeam, für die Übersichtsseite werden die Daten mit dieser Methode abgerufen retrieveFriendlyMatchesFromPublisher

User Verwaltung

Hier in dieser Ansicht können User angelegt und gelöscht werden. Dies geschient mit dem Modal UserModal und dem Modal UserTickerAccess. Das UserModal wird verwendet um einen bestehenden User zu editieren. Das UserTickerAcess Modal wird für die neu Erstellung verwendet. Die Übersicht´s Seite ist im views Ordner mit dem Titel UserView.vue.

Suche und VueMultiSelect

In einigen Modals oder auch normalen Übersichtsseiten gibt es die Möglichkeit und Funktionen nach etwas zu suchen. In diesem Beispiel nehme ich die Suche nach einem Team in FriendlyMatchCreateModal.vue es gibt dort einmal das VueMultiSelect Paket eine externe Library zum Darstellen einer Liste als Input Feld.

vue
<template>
  <VueMultiselect
      v-if="match"
      v-model="selected_team_home"
      :options="home_teams"
      @search-change="retrieveHomeTeamsViaSearch"
      placeholder="Heimteam suchen..."
      :no-result="'Keine Ergebnisse gefunden'"
      :custom-label="customLabel"
      track-by="code"
    />
</template>

<script setup lang="ts">
import VueMultiselect from "vue-multiselect";
</script>
<template>
  <VueMultiselect
      v-if="match"
      v-model="selected_team_home"
      :options="home_teams"
      @search-change="retrieveHomeTeamsViaSearch"
      placeholder="Heimteam suchen..."
      :no-result="'Keine Ergebnisse gefunden'"
      :custom-label="customLabel"
      track-by="code"
    />
</template>

<script setup lang="ts">
import VueMultiselect from "vue-multiselect";
</script>

Hierbei ist home_teams die Liste aus der Suche welches über die Methode retrieveHomeTeamsViaSearch geschient, diese gibt eine Liste an Ergebnissen zurück.

ts
let retrieveHomeTeamsViaSearch = (search: string) => {
  if (search) {
    store.retrieveDataFromSearch(search).then((res) => {
      home_teams.value = res;
    });
  }
};
let retrieveHomeTeamsViaSearch = (search: string) => {
  if (search) {
    store.retrieveDataFromSearch(search).then((res) => {
      home_teams.value = res;
    });
  }
};

Das ausgewählte Team hierbei ist dann selected_team_home als Variablen.

ts
let selected_team_home = ref();
let selected_team_home = ref();

und in diesem Fall wird dann match.fkTeam_home gleich selected_team_home gesetzt.

ts
watch(selected_team_home, (newValue) => {
  if (newValue) {
    match.value.fkTeam_home = newValue.id;
  }
});
watch(selected_team_home, (newValue) => {
  if (newValue) {
    match.value.fkTeam_home = newValue.id;
  }
});

Das Ausgeben der Werte aus retrieveHomeTeamsViaSearch wird in diesem Fall auch nochmal mit einer Methode gemacht.

ts
let customLabel = (option: any) => {
  return `${option.name} (${option.sportsType} | ${option.teamType})`;
};
let customLabel = (option: any) => {
  return `${option.name} (${option.sportsType} | ${option.teamType})`;
};

Konfiguration / Einstellungen

In diesem Abschnitt sind allgemeine Einstellungen enthalten, die in der Datenbank vorgenommen werden können, um Wettbewerbe darzustellen. SettingView Hier gibt es drei Registerkarten: Saisons, Sportarten und Team-Arten. Alle diese drei Datentypen sind erforderlich, um Wettbewerbe oder Wettkämpfer (Teams) erstellen zu können. Die Listenansichten sind ähnlich aufgebaut wie die Ansichten für Ligen und Turniere.