Compare commits
No commits in common. "579dfc10ffc95ed686f8fb8cdb7efe83fefb12b7" and "b20ba213e7aa52214a1d16049fa4c43ff868e9d2" have entirely different histories.
579dfc10ff
...
b20ba213e7
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -31,6 +31,7 @@ declare module 'vue' {
|
||||
BookShops: typeof import('./src/components/bookdetail/BookShops.vue')['default']
|
||||
BookStats: typeof import('./src/components/bookdetail/BookStats.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']
|
||||
CardAddEditDialog: typeof import('./src/components/dialogs/CardAddEditDialog.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,10 +67,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Reset Button -->
|
||||
<!-- <div v-if="!isStatic" class="reset-container">
|
||||
<div v-if="!isStatic" class="reset-container">
|
||||
<button @click="resetSliders">Fieberkurve zurücksetzen</button>
|
||||
</div>-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -180,10 +179,6 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item1{
|
||||
width: 105px;
|
||||
}
|
||||
|
||||
.item1,
|
||||
.item3 {
|
||||
background: transparent;
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
<VCardTitle>Deine Aktionen</VCardTitle>
|
||||
<VCardText>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
|
||||
<VBtn :color="liked ? 'primary' : 'grey'" @click="toggleLike" variant="outlined">
|
||||
<VIcon
|
||||
start
|
||||
|
||||
@ -1,105 +1,82 @@
|
||||
// BookService.js
|
||||
// VERSION 1:
|
||||
/*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'
|
||||
|
||||
// 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'
|
||||
const baseUrl = 'http://localhost:8001/api/v1/book/registration/search/isbn/'
|
||||
|
||||
export default {
|
||||
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 {
|
||||
const { data } = await axios.post(
|
||||
`${registrationBase}`,
|
||||
payload, // <-- reines JSON, kein Wrapper
|
||||
{
|
||||
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
||||
timeout: 8000,
|
||||
},
|
||||
)
|
||||
const response = await axios.get(`${baseUrl}${isbn}`, {
|
||||
timeout: 5000, // Adjust timeout as needed
|
||||
})
|
||||
|
||||
return data
|
||||
} catch (errJson) {
|
||||
// Heuristiken, wann wir auf die 'book=' Variante zurückfallen sollten
|
||||
const msg = (errJson?.response?.data && JSON.stringify(errJson.response.data)) || `${errJson}`
|
||||
return response.data
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen des Buches:', error)
|
||||
console.error('Antwort vom Server:', error.response)
|
||||
|
||||
const shouldRetryAsForm =
|
||||
/Required request parameter 'book'|MissingServletRequestParameter/i.test(msg) ||
|
||||
/Failed to read request|HTTP message not readable/i.test(msg) ||
|
||||
|
||||
// manche Backends antworten schlicht 500, wenn sie query-param erwarten
|
||||
(/Failed to convert value of type 'java\.lang\.String' to required type 'de\.skoutz\.backend\.book\.Book'/i.test(msg))
|
||||
|
||||
if (!shouldRetryAsForm) {
|
||||
throw errJson
|
||||
// Detailliertere Fehlerbehandlung basierend auf dem Fehlertyp
|
||||
if (error.response && error.response.status === 404) {
|
||||
console.error('Buch nicht gefunden')
|
||||
} else if (error.code === 'ECONNABORTED') {
|
||||
console.error('Verbindungsabbruch')
|
||||
} else if (error.response && error.response.status === 500) {
|
||||
console.error('Interner Serverfehler')
|
||||
} else {
|
||||
console.error('Unbekannter Fehler')
|
||||
}
|
||||
|
||||
// 2) Fallback: form-url-encoded mit 'book=<json>'
|
||||
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
|
||||
}
|
||||
// Zeige dem Benutzer eine benutzerfreundliche Fehlermeldung an
|
||||
throw new Error('Ein Fehler ist beim Abrufen des Buchs aufgetreten.')
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
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,9 +4,7 @@
|
||||
<VRow>
|
||||
<!-- Linke Spalte -->
|
||||
<VCol cols="12" md="3">
|
||||
<div
|
||||
class="mb-4 cover-wrapper"
|
||||
>
|
||||
<div class="mb-4" style="aspect-ratio: 2/3; overflow: hidden;">
|
||||
<VImg :src="book.image" height="100%" width="100%" cover class="elevation-1" />
|
||||
</div>
|
||||
|
||||
@ -166,17 +164,3 @@ const genreIcon = genre => {
|
||||
return icons[genre] || 'tabler-book'
|
||||
}
|
||||
</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,14 +14,10 @@
|
||||
@update:values="updateFieberkurveValues"
|
||||
@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>
|
||||
|
||||
|
||||
<!-- Genres -->
|
||||
<div class="genre-section-main">
|
||||
<div
|
||||
@ -41,14 +37,14 @@
|
||||
</VTooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-start my-2">
|
||||
<VBtn variant="text" color="primary" @click="clearGenres">
|
||||
<VIcon icon="tabler-refresh" class="mr-1" /> Genres zurücksetzen
|
||||
</VBtn>
|
||||
</div>
|
||||
|
||||
<!-- Button zum Zurücksetzen der Genres -->
|
||||
<VBtn class="my-3 mx-auto d-block" color="primary" @click="clearGenres">
|
||||
Alle Genres Zurücksetzen
|
||||
</VBtn>
|
||||
|
||||
<!-- Text Suchfeld -->
|
||||
<div style="padding: 0 15rem;">
|
||||
<div style="padding: 0 5rem;">
|
||||
<AppTextField
|
||||
v-model="message"
|
||||
clearable
|
||||
@ -65,22 +61,26 @@
|
||||
</template>
|
||||
</AppTextField>
|
||||
</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>
|
||||
|
||||
<br>
|
||||
<!-- Button zum Zurücksetzen der Einstellungen -->
|
||||
<VBtn
|
||||
class="my-3 mx-auto d-block"
|
||||
:color="resetFeedback ? 'success' : 'error'"
|
||||
@click="resetAllSettings"
|
||||
>
|
||||
{{ resetFeedback ? 'Zurückgesetzt!' : 'Alle Einstellungen zurücksetzen' }}
|
||||
</VBtn>
|
||||
|
||||
<br />
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
<!-- Trefferanzahl -->
|
||||
<!-- <VDivider class="my-2" />-->
|
||||
<VCardTitle class="text-h5 px-6 pt-4 pb-2">
|
||||
{{ filteredBooks.length }} {{ filteredBooks.length === 1 ? 'Buch' : 'Bücher' }} gefunden
|
||||
</VCardTitle>
|
||||
|
||||
<!-- <VDivider class="my-2" />-->
|
||||
<!-- Gefundene Bücher -->
|
||||
<VRow>
|
||||
<Buchkarten :books="filteredBooks" />
|
||||
@ -88,64 +88,90 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue"
|
||||
import Fieberkurve from "@/components/Fieberkurve.vue"
|
||||
import Buchkarten from '@/components/Buchkarten.vue'
|
||||
import { books } from "@/components/buecherdatenbank"
|
||||
import { genres } from "@/components/genredatenbank"
|
||||
import { ref, computed } from "vue";
|
||||
import Fieberkurve from "@/components/Fieberkurve.vue";
|
||||
import Buchkarten from '@/components/Buchkarten.vue';
|
||||
import { books } from "@/components/buecherdatenbank";
|
||||
import { genres } from "@/components/genredatenbank";
|
||||
|
||||
const message = ref("")
|
||||
const selectedCheckbox = ref([])
|
||||
const fieberkurveValues = ref([4, 4, 4, 4, 4])
|
||||
const fieberkurveRowFilter = ref([])
|
||||
const fieberkurveRef = ref(null)
|
||||
const message = ref("");
|
||||
const loading = ref(false);
|
||||
const selectedCheckbox = ref([]);
|
||||
const fieberkurveValues = ref([4, 4, 4, 4, 4]);
|
||||
const fieberkurveRowFilter = ref([]);
|
||||
|
||||
const resultCount = computed(() => filteredBooks.value.length)
|
||||
|
||||
const filteredBooks = computed(() => {
|
||||
return books.filter(book => {
|
||||
return books.filter((book) => {
|
||||
const matchesGenres =
|
||||
selectedCheckbox.value.length === 0 ||
|
||||
selectedCheckbox.value.some(genre => book.genres.includes(genre))
|
||||
selectedCheckbox.value.some((genre) => book.genres.includes(genre));
|
||||
|
||||
const matchesText =
|
||||
!message.value ||
|
||||
book.title.toLowerCase().includes(message.value.toLowerCase()) ||
|
||||
book.authors?.some(author =>
|
||||
author.name.toLowerCase().includes(message.value.toLowerCase()),
|
||||
book.authors?.some((author) =>
|
||||
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 bookValue = book.fieberkurve[index]?.value || 4
|
||||
const matchesFieberkurve = !hasRowFilters && fieberkurveValues.value.every((value, index) => {
|
||||
const bookValue = book.fieberkurve[index]?.value || 4;
|
||||
return value === 4 || value === bookValue;
|
||||
});
|
||||
|
||||
return value === 4 || value === bookValue
|
||||
})
|
||||
const matchesFieberkurveRowFilters = hasRowFilters && fieberkurveRowFilter.value.every(({ rowIndex, value }) => {
|
||||
return book.fieberkurve[rowIndex]?.value === value;
|
||||
});
|
||||
|
||||
const matchesFieberkurveRowFilters =
|
||||
hasRowFilters &&
|
||||
fieberkurveRowFilter.value.every(({ rowIndex, value }) => {
|
||||
return book.fieberkurve[rowIndex]?.value === value
|
||||
})
|
||||
return matchesGenres && matchesText && (matchesFieberkurve || matchesFieberkurveRowFilters);
|
||||
});
|
||||
});
|
||||
|
||||
return matchesGenres && matchesText && (matchesFieberkurve || matchesFieberkurveRowFilters)
|
||||
})
|
||||
})
|
||||
const searchBooks = () => {
|
||||
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 = () => {
|
||||
clearGenres(); fieberkurveRef.value?.resetSliders(); message.value = ""; fieberkurveRowFilter.value = [];
|
||||
}
|
||||
const updateFieberkurveValues = values => { fieberkurveValues.value = values }
|
||||
const filterByRow = activeFilters => { fieberkurveRowFilter.value = activeFilters }
|
||||
selectedCheckbox.value = [];
|
||||
fieberkurveRef.value?.resetSliders();
|
||||
message.value = "";
|
||||
fieberkurveRowFilter.value = [];
|
||||
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>
|
||||
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.genre-section-main {
|
||||
display: flex;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user