Compare commits
2 Commits
b20ba213e7
...
579dfc10ff
| Author | SHA1 | Date | |
|---|---|---|---|
| 579dfc10ff | |||
| c6fd026ba2 |
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -31,7 +31,6 @@ declare module 'vue' {
|
|||||||
BookShops: typeof import('./src/components/bookdetail/BookShops.vue')['default']
|
BookShops: typeof import('./src/components/bookdetail/BookShops.vue')['default']
|
||||||
BookStats: typeof import('./src/components/bookdetail/BookStats.vue')['default']
|
BookStats: typeof import('./src/components/bookdetail/BookStats.vue')['default']
|
||||||
Buchkarten: typeof import('./src/components/Buchkarten.vue')['default']
|
Buchkarten: typeof import('./src/components/Buchkarten.vue')['default']
|
||||||
Buecherdatenbank: typeof import('./src/pages/buecherdatenbank.vue')['default']
|
|
||||||
BuyNow: typeof import('./src/@core/components/BuyNow.vue')['default']
|
BuyNow: typeof import('./src/@core/components/BuyNow.vue')['default']
|
||||||
CardAddEditDialog: typeof import('./src/components/dialogs/CardAddEditDialog.vue')['default']
|
CardAddEditDialog: typeof import('./src/components/dialogs/CardAddEditDialog.vue')['default']
|
||||||
CardStatisticsHorizontal: typeof import('./src/@core/components/cards/CardStatisticsHorizontal.vue')['default']
|
CardStatisticsHorizontal: typeof import('./src/@core/components/cards/CardStatisticsHorizontal.vue')['default']
|
||||||
|
|||||||
223
package-lock.json
generated
223
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -67,9 +67,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Reset Button -->
|
<!-- Reset Button -->
|
||||||
<div v-if="!isStatic" class="reset-container">
|
<!-- <div v-if="!isStatic" class="reset-container">
|
||||||
<button @click="resetSliders">Fieberkurve zurücksetzen</button>
|
<button @click="resetSliders">Fieberkurve zurücksetzen</button>
|
||||||
</div>
|
</div>-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -179,6 +180,10 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item1{
|
||||||
|
width: 105px;
|
||||||
|
}
|
||||||
|
|
||||||
.item1,
|
.item1,
|
||||||
.item3 {
|
.item3 {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
<VCardTitle>Deine Aktionen</VCardTitle>
|
<VCardTitle>Deine Aktionen</VCardTitle>
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<div class="d-flex flex-column gap-2">
|
<div class="d-flex flex-column gap-2">
|
||||||
|
|
||||||
<VBtn :color="liked ? 'primary' : 'grey'" @click="toggleLike" variant="outlined">
|
<VBtn :color="liked ? 'primary' : 'grey'" @click="toggleLike" variant="outlined">
|
||||||
<VIcon
|
<VIcon
|
||||||
start
|
start
|
||||||
|
|||||||
@ -1,82 +1,105 @@
|
|||||||
// VERSION 1:
|
// BookService.js
|
||||||
/*import axios from 'axios'
|
|
||||||
|
|
||||||
const baseUrl = 'http://localhost:8001/api/v1/book/registration/search/isbn/' // Passe die URL an
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getBookByIsbn(isbn) {
|
|
||||||
return axios.get(`${baseUrl}${isbn}`, {
|
|
||||||
headers: {
|
|
||||||
'accept': 'application/json',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
// Detailliertere Fehlerbehandlung
|
|
||||||
console.error('Fehler beim Abrufen des Buches:', error)
|
|
||||||
|
|
||||||
// Zeige dem Benutzer eine informative Fehlermeldung an
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// ********************************
|
|
||||||
// VERSION 2:
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
const baseUrl = 'http://localhost:8001/api/v1/book/registration/search/isbn/'
|
// const baseUrl = 'http://localhost:8001/api/v1/book/suggestion'
|
||||||
|
// const baseUrl = 'http://h2983688.stratoserver.net:8001/api/v1/book/suggestion'
|
||||||
|
// const baseUrl= 'https://skoutz-backend.it-tomaschko.de/api/v1/book/suggestion'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const suggestionBase = 'http://localhost:8001/api/v1/book/suggestion'
|
||||||
|
const registrationBase = 'http://localhost:8001/api/v1/book/registration'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async getBookByIsbn(isbn) {
|
async getBookByIsbn(isbn) {
|
||||||
|
const { data } = await axios.get(`${suggestionBase}/search/isbn/${encodeURIComponent(isbn)}`, {
|
||||||
|
timeout: 5000, headers: { Accept: 'application/json' },
|
||||||
|
})
|
||||||
|
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
|
||||||
|
async getBookByTitle(title) {
|
||||||
|
const { data } = await axios.get(`${suggestionBase}/search/title`, {
|
||||||
|
params: { title }, timeout: 5000, headers: { Accept: 'application/json' },
|
||||||
|
})
|
||||||
|
|
||||||
|
return data // Array von Vorschlägen
|
||||||
|
},
|
||||||
|
|
||||||
|
async registerBook(payload) {
|
||||||
|
// 1) Versuch: JSON-Body (das ist in modernen Spring-Stacks Standard)
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${baseUrl}${isbn}`, {
|
const { data } = await axios.post(
|
||||||
timeout: 5000, // Adjust timeout as needed
|
`${registrationBase}`,
|
||||||
})
|
payload, // <-- reines JSON, kein Wrapper
|
||||||
|
{
|
||||||
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
||||||
|
timeout: 8000,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return response.data
|
return data
|
||||||
} catch (error) {
|
} catch (errJson) {
|
||||||
console.error('Fehler beim Abrufen des Buches:', error)
|
// Heuristiken, wann wir auf die 'book=' Variante zurückfallen sollten
|
||||||
console.error('Antwort vom Server:', error.response)
|
const msg = (errJson?.response?.data && JSON.stringify(errJson.response.data)) || `${errJson}`
|
||||||
|
|
||||||
// Detailliertere Fehlerbehandlung basierend auf dem Fehlertyp
|
const shouldRetryAsForm =
|
||||||
if (error.response && error.response.status === 404) {
|
/Required request parameter 'book'|MissingServletRequestParameter/i.test(msg) ||
|
||||||
console.error('Buch nicht gefunden')
|
/Failed to read request|HTTP message not readable/i.test(msg) ||
|
||||||
} else if (error.code === 'ECONNABORTED') {
|
|
||||||
console.error('Verbindungsabbruch')
|
// manche Backends antworten schlicht 500, wenn sie query-param erwarten
|
||||||
} else if (error.response && error.response.status === 500) {
|
(/Failed to convert value of type 'java\.lang\.String' to required type 'de\.skoutz\.backend\.book\.Book'/i.test(msg))
|
||||||
console.error('Interner Serverfehler')
|
|
||||||
} else {
|
if (!shouldRetryAsForm) {
|
||||||
console.error('Unbekannter Fehler')
|
throw errJson
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zeige dem Benutzer eine benutzerfreundliche Fehlermeldung an
|
// 2) Fallback: form-url-encoded mit 'book=<json>'
|
||||||
throw new Error('Ein Fehler ist beim Abrufen des Buchs aufgetreten.')
|
try {
|
||||||
|
const body = new URLSearchParams()
|
||||||
|
|
||||||
|
body.set('book', JSON.stringify(payload))
|
||||||
|
|
||||||
|
const { data } = await axios.post(
|
||||||
|
`${registrationBase}`,
|
||||||
|
body,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
timeout: 8000,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return data
|
||||||
|
} catch (errForm) {
|
||||||
|
// schöner Fehlertext
|
||||||
|
const status = errForm?.response?.status
|
||||||
|
const backendMsg = errForm?.response?.data?.message || errForm?.response?.data?.error
|
||||||
|
|
||||||
|
const msg2 =
|
||||||
|
backendMsg ? `${status ?? ''} ${backendMsg}`.trim() :
|
||||||
|
status === 400 ? 'Ungültige Daten (400).' :
|
||||||
|
status === 409 ? 'ISBN bereits registriert (409).' :
|
||||||
|
status === 500 ? 'Serverfehler (500).' :
|
||||||
|
'Unbekannter Fehler beim Registrieren.'
|
||||||
|
|
||||||
|
const e = new Error(msg2)
|
||||||
|
|
||||||
|
e.response = errForm?.response; throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
async isIsbnRegistered(isbn) {
|
||||||
|
const { data } = await axios.get(`${registrationBase}/isIsbnRegistered/${encodeURIComponent(isbn)}`, {
|
||||||
|
timeout: 5000, headers: { Accept: 'application/json' },
|
||||||
|
})
|
||||||
|
|
||||||
// ********************************
|
return data === true || data === 'true'
|
||||||
// VERSION 3:
|
|
||||||
/*const axios = require('axios')
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getBookByIsbn(isbn) {
|
|
||||||
// Make a request for a user with a given ID
|
|
||||||
console.log(isbn)
|
|
||||||
axios.get('http://localhost:8001/api/v1/book/registration/search/isbn/9783898798822')
|
|
||||||
.then(function (response) {
|
|
||||||
// handle success
|
|
||||||
console.log("hi", response)
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
// handle error
|
|
||||||
console.log(error)
|
|
||||||
console.log("hi")
|
|
||||||
})
|
|
||||||
.finally(function () {
|
|
||||||
// always executed
|
|
||||||
console.log("hi")
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
}*/
|
}
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
<VRow>
|
<VRow>
|
||||||
<!-- Linke Spalte -->
|
<!-- Linke Spalte -->
|
||||||
<VCol cols="12" md="3">
|
<VCol cols="12" md="3">
|
||||||
<div class="mb-4" style="aspect-ratio: 2/3; overflow: hidden;">
|
<div
|
||||||
|
class="mb-4 cover-wrapper"
|
||||||
|
>
|
||||||
<VImg :src="book.image" height="100%" width="100%" cover class="elevation-1" />
|
<VImg :src="book.image" height="100%" width="100%" cover class="elevation-1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -164,3 +166,17 @@ const genreIcon = genre => {
|
|||||||
return icons[genre] || 'tabler-book'
|
return icons[genre] || 'tabler-book'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cover-wrapper {
|
||||||
|
aspect-ratio: 2 / 3;
|
||||||
|
overflow: hidden;
|
||||||
|
//transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
/*.cover-wrapper:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15);
|
||||||
|
}*/
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -14,10 +14,14 @@
|
|||||||
@update:values="updateFieberkurveValues"
|
@update:values="updateFieberkurveValues"
|
||||||
@filter-by-row="filterByRow"
|
@filter-by-row="filterByRow"
|
||||||
/>
|
/>
|
||||||
|
<div class="d-flex justify-start my-2">
|
||||||
|
<VBtn variant="text" color="primary" @click="fieberkurveRef?.resetSliders()">
|
||||||
|
<VIcon icon="tabler-refresh" class="mr-1" /> Fieberkurve zurücksetzen
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
||||||
<!-- Genres -->
|
<!-- Genres -->
|
||||||
<div class="genre-section-main">
|
<div class="genre-section-main">
|
||||||
<div
|
<div
|
||||||
@ -37,14 +41,14 @@
|
|||||||
</VTooltip>
|
</VTooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="d-flex justify-start my-2">
|
||||||
<!-- Button zum Zurücksetzen der Genres -->
|
<VBtn variant="text" color="primary" @click="clearGenres">
|
||||||
<VBtn class="my-3 mx-auto d-block" color="primary" @click="clearGenres">
|
<VIcon icon="tabler-refresh" class="mr-1" /> Genres zurücksetzen
|
||||||
Alle Genres Zurücksetzen
|
</VBtn>
|
||||||
</VBtn>
|
</div>
|
||||||
|
|
||||||
<!-- Text Suchfeld -->
|
<!-- Text Suchfeld -->
|
||||||
<div style="padding: 0 5rem;">
|
<div style="padding: 0 15rem;">
|
||||||
<AppTextField
|
<AppTextField
|
||||||
v-model="message"
|
v-model="message"
|
||||||
clearable
|
clearable
|
||||||
@ -61,26 +65,22 @@
|
|||||||
</template>
|
</template>
|
||||||
</AppTextField>
|
</AppTextField>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="d-flex justify-start my-2">
|
||||||
|
<VBtn variant="text" color="error" @click="resetAllSettings">
|
||||||
|
<VIcon icon="tabler-trash" class="mr-1" /> Alles zurücksetzen
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Button zum Zurücksetzen der Einstellungen -->
|
<br>
|
||||||
<VBtn
|
|
||||||
class="my-3 mx-auto d-block"
|
|
||||||
:color="resetFeedback ? 'success' : 'error'"
|
|
||||||
@click="resetAllSettings"
|
|
||||||
>
|
|
||||||
{{ resetFeedback ? 'Zurückgesetzt!' : 'Alle Einstellungen zurücksetzen' }}
|
|
||||||
</VBtn>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
</VCard>
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
|
||||||
<!-- Trefferanzahl -->
|
<!-- Trefferanzahl -->
|
||||||
<!-- <VDivider class="my-2" />-->
|
|
||||||
<VCardTitle class="text-h5 px-6 pt-4 pb-2">
|
<VCardTitle class="text-h5 px-6 pt-4 pb-2">
|
||||||
{{ filteredBooks.length }} {{ filteredBooks.length === 1 ? 'Buch' : 'Bücher' }} gefunden
|
{{ filteredBooks.length }} {{ filteredBooks.length === 1 ? 'Buch' : 'Bücher' }} gefunden
|
||||||
</VCardTitle>
|
</VCardTitle>
|
||||||
<!-- <VDivider class="my-2" />-->
|
|
||||||
<!-- Gefundene Bücher -->
|
<!-- Gefundene Bücher -->
|
||||||
<VRow>
|
<VRow>
|
||||||
<Buchkarten :books="filteredBooks" />
|
<Buchkarten :books="filteredBooks" />
|
||||||
@ -88,90 +88,64 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue"
|
||||||
import Fieberkurve from "@/components/Fieberkurve.vue";
|
import Fieberkurve from "@/components/Fieberkurve.vue"
|
||||||
import Buchkarten from '@/components/Buchkarten.vue';
|
import Buchkarten from '@/components/Buchkarten.vue'
|
||||||
import { books } from "@/components/buecherdatenbank";
|
import { books } from "@/components/buecherdatenbank"
|
||||||
import { genres } from "@/components/genredatenbank";
|
import { genres } from "@/components/genredatenbank"
|
||||||
|
|
||||||
const message = ref("");
|
const message = ref("")
|
||||||
const loading = ref(false);
|
const selectedCheckbox = ref([])
|
||||||
const selectedCheckbox = ref([]);
|
const fieberkurveValues = ref([4, 4, 4, 4, 4])
|
||||||
const fieberkurveValues = ref([4, 4, 4, 4, 4]);
|
const fieberkurveRowFilter = ref([])
|
||||||
const fieberkurveRowFilter = ref([]);
|
const fieberkurveRef = ref(null)
|
||||||
|
|
||||||
const resultCount = computed(() => filteredBooks.value.length)
|
|
||||||
|
|
||||||
const filteredBooks = computed(() => {
|
const filteredBooks = computed(() => {
|
||||||
return books.filter((book) => {
|
return books.filter(book => {
|
||||||
const matchesGenres =
|
const matchesGenres =
|
||||||
selectedCheckbox.value.length === 0 ||
|
selectedCheckbox.value.length === 0 ||
|
||||||
selectedCheckbox.value.some((genre) => book.genres.includes(genre));
|
selectedCheckbox.value.some(genre => book.genres.includes(genre))
|
||||||
|
|
||||||
const matchesText =
|
const matchesText =
|
||||||
!message.value ||
|
!message.value ||
|
||||||
book.title.toLowerCase().includes(message.value.toLowerCase()) ||
|
book.title.toLowerCase().includes(message.value.toLowerCase()) ||
|
||||||
book.authors?.some((author) =>
|
book.authors?.some(author =>
|
||||||
author.name.toLowerCase().includes(message.value.toLowerCase())
|
author.name.toLowerCase().includes(message.value.toLowerCase()),
|
||||||
) ||
|
) ||
|
||||||
book.isbn?.includes(message.value);
|
book.isbn?.includes(message.value)
|
||||||
|
|
||||||
const hasRowFilters = fieberkurveRowFilter.value.length > 0;
|
const hasRowFilters = fieberkurveRowFilter.value.length > 0
|
||||||
|
|
||||||
const matchesFieberkurve = !hasRowFilters && fieberkurveValues.value.every((value, index) => {
|
const matchesFieberkurve =
|
||||||
const bookValue = book.fieberkurve[index]?.value || 4;
|
!hasRowFilters &&
|
||||||
return value === 4 || value === bookValue;
|
fieberkurveValues.value.every((value, index) => {
|
||||||
});
|
const bookValue = book.fieberkurve[index]?.value || 4
|
||||||
|
|
||||||
const matchesFieberkurveRowFilters = hasRowFilters && fieberkurveRowFilter.value.every(({ rowIndex, value }) => {
|
return value === 4 || value === bookValue
|
||||||
return book.fieberkurve[rowIndex]?.value === value;
|
})
|
||||||
});
|
|
||||||
|
|
||||||
return matchesGenres && matchesText && (matchesFieberkurve || matchesFieberkurveRowFilters);
|
const matchesFieberkurveRowFilters =
|
||||||
});
|
hasRowFilters &&
|
||||||
});
|
fieberkurveRowFilter.value.every(({ rowIndex, value }) => {
|
||||||
|
return book.fieberkurve[rowIndex]?.value === value
|
||||||
|
})
|
||||||
|
|
||||||
const searchBooks = () => {
|
return matchesGenres && matchesText && (matchesFieberkurve || matchesFieberkurveRowFilters)
|
||||||
console.log("Suche gestartet mit Text:", message.value);
|
})
|
||||||
};
|
})
|
||||||
|
|
||||||
const toggleGenre = (genre) => {
|
|
||||||
if (selectedCheckbox.value.includes(genre)) {
|
|
||||||
selectedCheckbox.value = selectedCheckbox.value.filter((g) => g !== genre);
|
|
||||||
} else {
|
|
||||||
selectedCheckbox.value.push(genre);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearGenres = () => {
|
|
||||||
selectedCheckbox.value = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const fieberkurveRef = ref(null);
|
|
||||||
const resetFeedback = ref(false);
|
|
||||||
|
|
||||||
|
const searchBooks = () => { console.log("Suche gestartet mit Text:", message.value) }
|
||||||
|
const toggleGenre = genre => selectedCheckbox.value.includes(genre) ? selectedCheckbox.value = selectedCheckbox.value.filter(g => g !== genre) : selectedCheckbox.value.push(genre)
|
||||||
|
const clearGenres = () => { selectedCheckbox.value = [] }
|
||||||
const resetAllSettings = () => {
|
const resetAllSettings = () => {
|
||||||
selectedCheckbox.value = [];
|
clearGenres(); fieberkurveRef.value?.resetSliders(); message.value = ""; fieberkurveRowFilter.value = [];
|
||||||
fieberkurveRef.value?.resetSliders();
|
}
|
||||||
message.value = "";
|
const updateFieberkurveValues = values => { fieberkurveValues.value = values }
|
||||||
fieberkurveRowFilter.value = [];
|
const filterByRow = activeFilters => { fieberkurveRowFilter.value = activeFilters }
|
||||||
resetFeedback.value = true;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
resetFeedback.value = false;
|
|
||||||
}, 1500);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateFieberkurveValues = (values) => {
|
|
||||||
fieberkurveValues.value = values;
|
|
||||||
};
|
|
||||||
|
|
||||||
const filterByRow = (activeFilters) => {
|
|
||||||
fieberkurveRowFilter.value = activeFilters;
|
|
||||||
console.log("Aktive Fieberkurvenfilter:", activeFilters);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.genre-section-main {
|
.genre-section-main {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user