diff --git a/client/components/Api/Api.vue b/client/components/Api/Api.vue index 551dec6..cd50da3 100644 --- a/client/components/Api/Api.vue +++ b/client/components/Api/Api.vue @@ -212,8 +212,8 @@ class Api { return response; } - async getBookList(authorId) { - const response = await this.request({action: 'get-book-list', authorId}); + async getAuthorBookList(authorId) { + const response = await this.request({action: 'get-author-book-list', authorId}); if (response.error) { throw new Error(response.error); diff --git a/client/components/Search/AuthorList/AuthorList.vue b/client/components/Search/AuthorList/AuthorList.vue index a5a5e2d..739cf50 100644 --- a/client/components/Search/AuthorList/AuthorList.vue +++ b/client/components/Search/AuthorList/AuthorList.vue @@ -191,6 +191,135 @@ class AuthorList extends BaseList { return seriesItem.booksSet.has(seriesBook.id); } + async expandAuthor(item) { + const expanded = _.cloneDeep(this.expandedAuthor); + const key = item.author; + + if (!this.isExpandedAuthor(item)) { + expanded.push(key); + + await this.getAuthorBooks(item); + + if (expanded.length > 10) { + expanded.shift(); + } + + //this.$emit('listEvent', {action: 'ignoreScroll'}); + this.setSetting('expandedAuthor', expanded); + } else { + const i = expanded.indexOf(key); + if (i >= 0) { + expanded.splice(i, 1); + this.setSetting('expandedAuthor', expanded); + } + } + } + + async getAuthorBooks(item) { + if (item.books) { + if (item.count > this.maxItemCount) { + item.bookLoading = true; + await utils.sleep(1);//для перерисовки списка + item.bookLoading = false; + } + return; + } + + if (!this.getBooksFlag) + this.getBooksFlag = 0; + + this.getBooksFlag++; + if (item.count > this.maxItemCount) + item.bookLoading = true; + + try { + if (this.getBooksFlag == 1) { + (async() => { + await utils.sleep(500); + if (this.getBooksFlag > 0) + this.loadingMessage2 = 'Загрузка списка книг...'; + })(); + } + + const booksToFilter = await this.loadAuthorBooks(item.key); + const filtered = this.filterBooks(booksToFilter); + + const prepareBook = (book) => { + return Object.assign( + { + key: book.id, + type: 'book', + }, + book + ); + }; + + //объединение по сериям + const books = []; + const seriesIndex = {}; + for (const book of filtered) { + if (book.series) { + let index = seriesIndex[book.series]; + if (index === undefined) { + index = books.length; + books.push(reactive({ + key: `${item.author}-${book.series}`, + type: 'series', + series: book.series, + allBooksLoaded: null, + allBooks: null, + showAllBooks: false, + showMore: false, + + seriesBooks: [], + })); + + seriesIndex[book.series] = index; + } + + books[index].seriesBooks.push(prepareBook(book)); + } else { + books.push(prepareBook(book)); + } + } + + //сортировка + books.sort((a, b) => { + if (a.type == 'series') { + return (b.type == 'series' ? a.key.localeCompare(b.key) : -1); + } else { + return (b.type == 'book' ? a.title.localeCompare(b.title) : 1); + } + }); + + //сортировка внутри серий + for (const book of books) { + if (book.type == 'series') { + this.sortSeriesBooks(book.seriesBooks); + + //асинхронно подгрузим все книги серии, если она раскрыта + if (this.isExpandedSeries(book)) { + this.getSeriesBooks(book);//no await + } + } + } + + if (books.length == 1 && books[0].type == 'series' && !this.isExpandedSeries(books[0])) { + this.expandSeries(books[0]); + } + + item.booksLoaded = books; + this.showMore(item); + + await this.$nextTick(); + } finally { + item.bookLoading = false; + this.getBooksFlag--; + if (this.getBooksFlag == 0) + this.loadingMessage2 = ''; + } + } + async updateTableData() { let result = []; @@ -225,9 +354,9 @@ class AuthorList extends BaseList { if (expandedSet.has(item.author)) { if (authors.length > 1 || item.count > this.maxItemCount) - this.getBooks(item);//no await + this.getAuthorBooks(item);//no await else - await this.getBooks(item); + await this.getAuthorBooks(item); } result.push(item); diff --git a/client/components/Search/BaseList.js b/client/components/Search/BaseList.js index d85a513..2f1537e 100644 --- a/client/components/Search/BaseList.js +++ b/client/components/Search/BaseList.js @@ -1,4 +1,3 @@ -import { reactive } from 'vue'; import _ from 'lodash'; import authorBooksStorage from './authorBooksStorage'; @@ -226,30 +225,6 @@ export default class BaseList { this.$emit('listEvent', {action: 'highlightPageScroller', query}); } - async expandAuthor(item) { - const expanded = _.cloneDeep(this.expandedAuthor); - const key = item.author; - - if (!this.isExpandedAuthor(item)) { - expanded.push(key); - - await this.getBooks(item); - - if (expanded.length > 10) { - expanded.shift(); - } - - //this.$emit('listEvent', {action: 'ignoreScroll'}); - this.setSetting('expandedAuthor', expanded); - } else { - const i = expanded.indexOf(key); - if (i >= 0) { - expanded.splice(i, 1); - this.setSetting('expandedAuthor', expanded); - } - } - } - async expandSeries(seriesItem) { const expandedSeries = _.cloneDeep(this.expandedSeries); const key = seriesItem.key; @@ -274,7 +249,7 @@ export default class BaseList { } } - async loadBooks(authorId) { + async loadAuthorBooks(authorId) { try { let result; @@ -284,11 +259,11 @@ export default class BaseList { if (data) { result = JSON.parse(data); } else { - result = await this.api.getBookList(authorId); + result = await this.api.getAuthorBookList(authorId); await authorBooksStorage.setData(key, JSON.stringify(result)); } } else { - result = await this.api.getBookList(authorId); + result = await this.api.getAuthorBookList(authorId); } return (result.books ? JSON.parse(result.books) : []); @@ -472,108 +447,4 @@ export default class BaseList { }); } - async getBooks(item) { - if (item.books) { - if (item.count > maxItemCount) { - item.bookLoading = true; - await utils.sleep(1);//для перерисовки списка - item.bookLoading = false; - } - return; - } - - if (!this.getBooksFlag) - this.getBooksFlag = 0; - - this.getBooksFlag++; - if (item.count > maxItemCount) - item.bookLoading = true; - - try { - if (this.getBooksFlag == 1) { - (async() => { - await utils.sleep(500); - if (this.getBooksFlag > 0) - this.loadingMessage2 = 'Загрузка списка книг...'; - })(); - } - - const booksToFilter = await this.loadBooks(item.key); - const filtered = this.filterBooks(booksToFilter); - - const prepareBook = (book) => { - return Object.assign( - { - key: book.id, - type: 'book', - }, - book - ); - }; - - //объединение по сериям - const books = []; - const seriesIndex = {}; - for (const book of filtered) { - if (book.series) { - let index = seriesIndex[book.series]; - if (index === undefined) { - index = books.length; - books.push(reactive({ - key: `${item.author}-${book.series}`, - type: 'series', - series: book.series, - allBooksLoaded: null, - allBooks: null, - showAllBooks: false, - showMore: false, - - seriesBooks: [], - })); - - seriesIndex[book.series] = index; - } - - books[index].seriesBooks.push(prepareBook(book)); - } else { - books.push(prepareBook(book)); - } - } - - //сортировка - books.sort((a, b) => { - if (a.type == 'series') { - return (b.type == 'series' ? a.key.localeCompare(b.key) : -1); - } else { - return (b.type == 'book' ? a.title.localeCompare(b.title) : 1); - } - }); - - //сортировка внутри серий - for (const book of books) { - if (book.type == 'series') { - this.sortSeriesBooks(book.seriesBooks); - - //асинхронно подгрузим все книги серии, если она раскрыта - if (this.isExpandedSeries(book)) { - this.getSeriesBooks(book);//no await - } - } - } - - if (books.length == 1 && books[0].type == 'series' && !this.isExpandedSeries(books[0])) { - this.expandSeries(books[0]); - } - - item.booksLoaded = books; - this.showMore(item); - - await this.$nextTick(); - } finally { - item.bookLoading = false; - this.getBooksFlag--; - if (this.getBooksFlag == 0) - this.loadingMessage2 = ''; - } - } } \ No newline at end of file diff --git a/server/controllers/WebSocketController.js b/server/controllers/WebSocketController.js index 903dfb5..e2b4dc4 100644 --- a/server/controllers/WebSocketController.js +++ b/server/controllers/WebSocketController.js @@ -76,8 +76,8 @@ class WebSocketController { await this.getWorkerState(req, ws); break; case 'author-search': await this.authorSearch(req, ws); break; - case 'get-book-list': - await this.getBookList(req, ws); break; + case 'get-author-book-list': + await this.getAuthorBookList(req, ws); break; case 'get-series-book-list': await this.getSeriesBookList(req, ws); break; case 'get-genre-tree': @@ -142,20 +142,14 @@ class WebSocketController { this.send(result, req, ws); } - async getBookList(req, ws) { - if (!utils.hasProp(req, 'authorId')) - throw new Error(`authorId is empty`); - - const result = await this.webWorker.getBookList(req.authorId); + async getAuthorBookList(req, ws) { + const result = await this.webWorker.getAuthorBookList(req.authorId); this.send(result, req, ws); } async getSeriesBookList(req, ws) { - if (!utils.hasProp(req, 'series')) - throw new Error(`series is empty`); - - const result = await this.webWorker.getSeriesBookList(req.series); + const result = await this.webWorker.getSeriesBookList(req.series, req.seriesId); this.send(result, req, ws); } diff --git a/server/core/DbSearcher.js b/server/core/DbSearcher.js index a35bb55..846930f 100644 --- a/server/core/DbSearcher.js +++ b/server/core/DbSearcher.js @@ -382,10 +382,13 @@ class DbSearcher { } } - async getBookList(authorId) { + async getAuthorBookList(authorId) { if (this.closed) throw new Error('DbSearcher closed'); + if (!authorId) + return {author: '', books: ''}; + this.searchFlag++; try { @@ -411,10 +414,13 @@ class DbSearcher { } } - async getSeriesBookList(series) { + async getSeriesBookList(series, seriesId) { if (this.closed) throw new Error('DbSearcher closed'); + if (!series && !seriesId) + return {books: ''}; + this.searchFlag++; try { diff --git a/server/core/WebWorker.js b/server/core/WebWorker.js index 0349dad..cf6f5b3 100644 --- a/server/core/WebWorker.js +++ b/server/core/WebWorker.js @@ -258,16 +258,16 @@ class WebWorker { }; } - async getBookList(authorId) { + async getAuthorBookList(authorId) { this.checkMyState(); - return await this.dbSearcher.getBookList(authorId); + return await this.dbSearcher.getAuthorBookList(authorId); } - async getSeriesBookList(seriesId) { + async getSeriesBookList(series, seriesId) { this.checkMyState(); - return await this.dbSearcher.getSeriesBookList(seriesId); + return await this.dbSearcher.getSeriesBookList(series, seriesId); } async getGenreTree() {