@christianriedl/media 1.0.173 → 1.0.175
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/BookLine.vue +12 -4
- package/src/views/BooksPage.vue +101 -23
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { ref } from 'vue';
|
|
3
3
|
import { IBook } from '@christianriedl/media';
|
|
4
4
|
|
|
5
|
-
const props = defineProps<{ book: IBook, add?: boolean, allbooks?: IBook[] }>();
|
|
5
|
+
const props = defineProps<{ book: IBook, add?: boolean, readonly?: boolean, ismobile?: boolean, allbooks?: IBook[] }>();
|
|
6
6
|
const book = props.book;
|
|
7
7
|
const emits = defineEmits<{
|
|
8
8
|
(e: 'selectbook', id: number, func: () => void): void,
|
|
@@ -52,7 +52,15 @@
|
|
|
52
52
|
</script>
|
|
53
53
|
|
|
54
54
|
<template>
|
|
55
|
-
<v-row dense align="center" :class="cls" @click="onSelect" >
|
|
55
|
+
<v-row v-if="props.ismobile" dense align="center" :class="cls" @click="onSelect" >
|
|
56
|
+
<v-col cols="9" >
|
|
57
|
+
<v-text-field v-model="book.title" hide-details density="compact" ></v-text-field>
|
|
58
|
+
</v-col>
|
|
59
|
+
<v-col cols="3" >
|
|
60
|
+
<v-text-field v-model="book.year" hide-details density="compact" ></v-text-field>
|
|
61
|
+
</v-col>
|
|
62
|
+
</v-row>
|
|
63
|
+
<v-row v-else dense align="center" :class="cls" @click="onSelect" >
|
|
56
64
|
<v-col v-if="props.add" cols="6" >
|
|
57
65
|
<v-combobox v-model="selected" :items="props.allbooks" item-value="id" item-title="title" hide-details density="compact" single-line @update:modelValue="titleChanged"></v-combobox>
|
|
58
66
|
</v-col>
|
|
@@ -66,8 +74,8 @@
|
|
|
66
74
|
<v-rating hover clearable :length="5" :size="32" :model-value="book.rating" active-color="primary" @update:modelValue="ratingChanged" />
|
|
67
75
|
</v-col>
|
|
68
76
|
<v-col cols="2">
|
|
69
|
-
<v-btn v-if="showDelete" icon="$delete" @click="onDelete"></v-btn>
|
|
70
|
-
<v-btn v-if="showSave" icon="$save" @click="onSave"></v-btn>
|
|
77
|
+
<v-btn v-if="showDelete" icon="$delete" :disabled="props.readonly" @click="onDelete"></v-btn>
|
|
78
|
+
<v-btn v-if="showSave" icon="$save" :disabled="props.readonly" @click="onSave"></v-btn>
|
|
71
79
|
</v-col>
|
|
72
80
|
</v-row>
|
|
73
81
|
</template>
|
package/src/views/BooksPage.vue
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { inject, ref, reactive, onMounted, onUnmounted, computed, StyleValue } from 'vue';
|
|
3
|
-
import { IAppState, appStateSymbol, getOpenAISymbol, IOpenAIService, ICompleteData } from '@christianriedl/utils';
|
|
3
|
+
import { IAppState, appStateSymbol, getOpenAISymbol, IOpenAIService, ICompleteData, EScope, EDevice } from '@christianriedl/utils';
|
|
4
4
|
import { BooksService, getBooksSymbol, IAuthorShort, IAuthor, IBook } from '@christianriedl/media';
|
|
5
5
|
import BookLine from '../components/BookLine.vue';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const appState = inject(appStateSymbol)!;
|
|
8
8
|
const getBooksService = inject(getBooksSymbol)!;
|
|
9
9
|
const booksService = getBooksService() as BooksService;
|
|
10
10
|
const getOpenAI = inject(getOpenAISymbol)!;
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
const showAddBookLine = ref(false);
|
|
22
22
|
const showCurrentBook = ref(false);
|
|
23
23
|
let setBookChanged: () => void;
|
|
24
|
-
|
|
24
|
+
let readonly = !(appState.scopes & EScope.Admin);
|
|
25
|
+
let isMobile = appState.isMobile && (appState.device != EDevice.iPad);
|
|
25
26
|
const heightStyle = computed<StyleValue>(() => { return { height: appState.bodyHeight.value + "px", overflowY: "auto" } });
|
|
27
|
+
|
|
26
28
|
start();
|
|
27
29
|
|
|
28
30
|
async function start() {
|
|
@@ -32,23 +34,35 @@
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
async function addAuthor() {
|
|
37
|
+
if (!checkAuthor(author))
|
|
38
|
+
return;
|
|
35
39
|
const id = await booksService.addAuthor(author);
|
|
36
40
|
if (id > 0) {
|
|
37
41
|
author.id = id;
|
|
38
42
|
mustAddAuthor.value = false;
|
|
39
43
|
}
|
|
44
|
+
else
|
|
45
|
+
alert (`AddAuthor - error ${id}`);
|
|
40
46
|
}
|
|
41
47
|
async function updateAuthor() {
|
|
48
|
+
if (!checkAuthor(author))
|
|
49
|
+
return;
|
|
42
50
|
const rc = await booksService.updateAuthor(author);
|
|
43
51
|
if (rc)
|
|
44
52
|
mustUpdateAuthor.value = false;
|
|
53
|
+
else
|
|
54
|
+
alert ('UpdateAuthor - error');
|
|
45
55
|
}
|
|
46
56
|
async function deleteAuthor() {
|
|
57
|
+
if (!window.confirm(`Willst du ${author.surName} wirklich l�schen ?`))
|
|
58
|
+
return;
|
|
47
59
|
const rc = await booksService.deleteAuthor(author.id);
|
|
48
60
|
if (rc) {
|
|
49
61
|
mustUpdateAuthor.value = false;
|
|
50
62
|
initAuthor ("");
|
|
51
63
|
}
|
|
64
|
+
else
|
|
65
|
+
alert (`DeleteAuthor ${author.id} - error`);
|
|
52
66
|
}
|
|
53
67
|
function initAuthor(surName: string) {
|
|
54
68
|
author.id = 0;
|
|
@@ -59,7 +73,7 @@
|
|
|
59
73
|
author.country = undefined;
|
|
60
74
|
author.books = [];
|
|
61
75
|
}
|
|
62
|
-
async function
|
|
76
|
+
async function getCurrentAuthor (id: number, withBooks: boolean) : Promise<boolean> {
|
|
63
77
|
const authors = await booksService.getAuthors(undefined, undefined, withBooks, id);
|
|
64
78
|
if (authors && authors.length > 0) {
|
|
65
79
|
const a = authors[0];
|
|
@@ -77,13 +91,13 @@
|
|
|
77
91
|
return false;
|
|
78
92
|
}
|
|
79
93
|
}
|
|
80
|
-
async function
|
|
94
|
+
async function authorNameChanged(arg: IAuthorShort | string) {
|
|
81
95
|
showCurrentBook.value = false;
|
|
82
96
|
currentBook.value = { id: 0, authorId: 0, title: ""};
|
|
83
97
|
mustAddAuthor.value = typeof arg == 'string';
|
|
84
98
|
if (!mustAddAuthor.value) {
|
|
85
99
|
const authorShort = arg as IAuthorShort;
|
|
86
|
-
const rc = await
|
|
100
|
+
const rc = await getCurrentAuthor (authorShort.id, true);
|
|
87
101
|
}
|
|
88
102
|
else {
|
|
89
103
|
initAuthor (arg as string);
|
|
@@ -100,7 +114,7 @@
|
|
|
100
114
|
await getAuthorDataFromAI(author.surName, author.givenName);
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
|
-
async function
|
|
117
|
+
async function addNewBook() {
|
|
104
118
|
if (lastAllBooksId.value != author.id) {
|
|
105
119
|
allBooks.value = await getAuthorBooksFromAI (author.surName, author.givenName, author.id);
|
|
106
120
|
lastAllBooksId.value = author.id;
|
|
@@ -108,7 +122,7 @@
|
|
|
108
122
|
newBook = reactive<IBook>({ id: 0, authorId: author.id, title: "", rating: 0 });
|
|
109
123
|
showAddBookLine.value = true;
|
|
110
124
|
}
|
|
111
|
-
function
|
|
125
|
+
function cancelAddNewBook() {
|
|
112
126
|
showAddBookLine.value = false;
|
|
113
127
|
}
|
|
114
128
|
async function selectBook(id: number, func: () => void) {
|
|
@@ -141,8 +155,12 @@
|
|
|
141
155
|
|
|
142
156
|
}
|
|
143
157
|
async function deleteBook(id: number) {
|
|
158
|
+
if (!window.confirm(`Willst du das Buch wirklich l�schen ?`))
|
|
159
|
+
return;
|
|
144
160
|
setBookChanged = () => {};
|
|
145
161
|
const rc = await booksService.deleteBook (id);
|
|
162
|
+
if (!rc)
|
|
163
|
+
alert (`DeleteBook ${id}- error`);
|
|
146
164
|
if (rc && author.books) {
|
|
147
165
|
const idx = author.books.findIndex ((x) => x.id == id);
|
|
148
166
|
if (idx >= 0)
|
|
@@ -150,8 +168,12 @@
|
|
|
150
168
|
}
|
|
151
169
|
}
|
|
152
170
|
async function saveBook(book: IBook) {
|
|
171
|
+
if (!checkBook(book))
|
|
172
|
+
return;
|
|
153
173
|
if (showAddBookLine.value) {
|
|
154
174
|
const id = await booksService.addBook (book);
|
|
175
|
+
if (id < 0)
|
|
176
|
+
alert (`AddBook - error ${id}`);
|
|
155
177
|
if (id > 0 && author.books) {
|
|
156
178
|
book.id = id;
|
|
157
179
|
author.books.splice (0, 0, book);
|
|
@@ -160,7 +182,47 @@
|
|
|
160
182
|
}
|
|
161
183
|
else {
|
|
162
184
|
const rc = await booksService.updateBook (book);
|
|
185
|
+
if (!rc)
|
|
186
|
+
alert ('UpdateBook - error');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function checkAuthor (author: IAuthor): boolean {
|
|
190
|
+
if (!author.surName || !author.givenName) {
|
|
191
|
+
alert("Vor oder Nachname fehlt !");
|
|
192
|
+
return false;
|
|
163
193
|
}
|
|
194
|
+
if (author.surName.length >= 64 || author.givenName.length >= 64) {
|
|
195
|
+
alert("Vor oder Nachname zu lang (>64) !");
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
if (author.country && author.country.length >= 64) {
|
|
199
|
+
alert("Geburtsland zu lang (>64) !");
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
function checkBook (book: IBook): boolean {
|
|
205
|
+
if (!book.title) {
|
|
206
|
+
alert("Titel fehlt !");
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (book.title.length >= 256) {
|
|
210
|
+
alert("Titel zu lang (>256) !");
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
if (!book.authorId) {
|
|
214
|
+
alert("Autor fehlt !");
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
if (book.description && book.description.length >= 4000) {
|
|
218
|
+
alert("Beschreibung zu lang (>4000) !");
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
if (book.comment && book.comment.length >= 1024) {
|
|
222
|
+
alert("Kommentar zu lang (>1024) !");
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
return true;
|
|
164
226
|
}
|
|
165
227
|
async function getAuthorDataFromAI(surName: string, givenName: string) {
|
|
166
228
|
const schema =
|
|
@@ -264,16 +326,28 @@
|
|
|
264
326
|
<template>
|
|
265
327
|
<v-container fluid class="bg-office" :style="heightStyle">
|
|
266
328
|
<v-defaults-provider :defaults="{'VBtn':{'size':'large','variant':'flat','class':'bg-office'}}">
|
|
267
|
-
<v-row dense align="center">
|
|
329
|
+
<v-row v-if="isMobile" dense align="center">
|
|
330
|
+
<v-col cols="6">Name</v-col>
|
|
331
|
+
<v-col cols="6">Vorname</v-col>
|
|
332
|
+
</v-row>
|
|
333
|
+
<v-row v-else dense align="center">
|
|
268
334
|
<v-col cols="2">Name</v-col>
|
|
269
335
|
<v-col cols="2">Vorname</v-col>
|
|
270
336
|
<v-col cols="2">Von</v-col>
|
|
271
337
|
<v-col cols="2">Bis</v-col>
|
|
272
338
|
<v-col cols="2">Land</v-col>
|
|
273
339
|
</v-row>
|
|
274
|
-
<v-row dense align="center">
|
|
340
|
+
<v-row v-if="isMobile" dense align="center">
|
|
341
|
+
<v-col cols="6">
|
|
342
|
+
<v-combobox v-model="selected" :items="authors" item-value="id" item-title="sN" hide-details density="compact" single-line @update:modelValue="authorNameChanged"></v-combobox>
|
|
343
|
+
</v-col>
|
|
344
|
+
<v-col cols="6">
|
|
345
|
+
<v-text-field v-model="author.givenName" hide-details density="compact" @update:modelValue="fieldChanged" @update:focused="givenNameFocused"></v-text-field>
|
|
346
|
+
</v-col>
|
|
347
|
+
</v-row>
|
|
348
|
+
<v-row v-else dense align="center">
|
|
275
349
|
<v-col cols="2">
|
|
276
|
-
<v-combobox v-model="selected" :items="authors" item-value="id" item-title="sN" hide-details density="compact" single-line @update:modelValue="
|
|
350
|
+
<v-combobox v-model="selected" :items="authors" item-value="id" item-title="sN" hide-details density="compact" single-line @update:modelValue="authorNameChanged"></v-combobox>
|
|
277
351
|
</v-col>
|
|
278
352
|
<v-col cols="2">
|
|
279
353
|
<v-text-field v-model="author.givenName" hide-details density="compact" @update:modelValue="fieldChanged" @update:focused="givenNameFocused"></v-text-field>
|
|
@@ -288,26 +362,30 @@
|
|
|
288
362
|
<v-text-field v-model="author.country" hide-details density="compact" @update:modelValue="fieldChanged"></v-text-field>
|
|
289
363
|
</v-col>
|
|
290
364
|
<v-col cols="2">
|
|
291
|
-
<v-btn v-if="mustAddAuthor" @click="addAuthor" append-icon="$plus">AUTHOR</v-btn>
|
|
292
|
-
<v-btn v-if="mustUpdateAuthor" @click="updateAuthor" icon="$save"></v-btn>
|
|
293
|
-
<v-btn v-if="author.id > 0" @click="deleteAuthor" icon="$delete"></v-btn>
|
|
365
|
+
<v-btn v-if="mustAddAuthor" @click="addAuthor" :disabled="readonly" append-icon="$plus">AUTHOR</v-btn>
|
|
366
|
+
<v-btn v-if="mustUpdateAuthor" @click="updateAuthor" :disabled="readonly" icon="$save"></v-btn>
|
|
367
|
+
<v-btn v-if="author.id > 0" @click="deleteAuthor" :disabled="readonly" icon="$delete"></v-btn>
|
|
294
368
|
</v-col>
|
|
295
369
|
</v-row>
|
|
296
370
|
<v-divider></v-divider>
|
|
297
|
-
<v-row dense align="center">
|
|
298
|
-
<v-col cols="
|
|
371
|
+
<v-row v-if="isMobile" dense align="center">
|
|
372
|
+
<v-col cols="7">TITEL</v-col>
|
|
299
373
|
<v-col cols="2">JAHR</v-col>
|
|
300
|
-
<v-col cols="
|
|
374
|
+
<v-col cols="3">RATING</v-col>
|
|
375
|
+
</v-row>
|
|
376
|
+
<v-row v-else dense align="center">
|
|
377
|
+
<v-col cols="9">TITEL</v-col>
|
|
378
|
+
<v-col cols="3">JAHR</v-col>
|
|
301
379
|
<v-col v-if="author.id" cols="2">
|
|
302
|
-
<v-btn v-if="!showAddBookLine" @click="
|
|
303
|
-
<v-btn v-if="showAddBookLine" @click="
|
|
380
|
+
<v-btn v-if="!showAddBookLine" @click="addNewBook" :disabled="readonly" append-icon="$plus">BOOK</v-btn>
|
|
381
|
+
<v-btn v-if="showAddBookLine" @click="cancelAddNewBook" :disabled="readonly" icon="$cancel"></v-btn>
|
|
304
382
|
</v-col>
|
|
305
383
|
</v-row>
|
|
306
|
-
<book-line v-if="showAddBookLine" :book="newBook" :add="true" :allbooks="allBooks" @selectbook="selectBook" @deletebook="deleteBook" @savebook="saveBook"></book-line>
|
|
307
|
-
<book-line v-for="book in author.books" :key="book.id" :book="book" @selectbook="selectBook" @deletebook="deleteBook" @savebook="saveBook"></book-line>
|
|
308
|
-
<v-textarea v-if="showCurrentBook" clearable auto-grow variant="outlined" label="
|
|
384
|
+
<book-line v-if="showAddBookLine" :book="newBook" :add="true" :allbooks="allBooks" :readonly="readonly" :ismobile="isMobile" @selectbook="selectBook" @deletebook="deleteBook" @savebook="saveBook"></book-line>
|
|
385
|
+
<book-line v-for="book in author.books" :key="book.id" :book="book" :readonly="readonly" :ismobile="isMobile" @selectbook="selectBook" @deletebook="deleteBook" @savebook="saveBook"></book-line>
|
|
386
|
+
<v-textarea v-if="showCurrentBook" class="pt-2"clearable auto-grow variant="outlined" label="Beschreibung" v-model="currentBook.description" @update:modelValue="descriptionChanged">
|
|
309
387
|
</v-textarea>
|
|
310
|
-
<v-textarea v-if="showCurrentBook" clearable auto-grow variant="outlined" label="
|
|
388
|
+
<v-textarea v-if="showCurrentBook" clearable auto-grow variant="outlined" label="Kommentar" v-model="currentBook.comment" @update:modelValue="descriptionChanged">
|
|
311
389
|
</v-textarea>
|
|
312
390
|
</v-defaults-provider>
|
|
313
391
|
</v-container>
|