소스 검색

Работа над проектом

Book Pauk 2 년 전
부모
커밋
b4c8f5ad72
3개의 변경된 파일141개의 추가작업 그리고 40개의 파일을 삭제
  1. 64 4
      client/components/Search/BookView/BookView.vue
  2. 75 33
      client/components/Search/Search.vue
  3. 2 3
      client/components/share/NumInput.vue

+ 64 - 4
client/components/Search/BookView/BookView.vue

@@ -1,9 +1,27 @@
 <template>
-    <div>
-        <div class="q-my-sm" @click="selectTitle(book.title)">
-            {{ book.title }}
-            <br>{{ book.src }}
+    <div class="row items-center">
+        <div class="q-my-sm clickable2" @click="selectTitle">
+            {{ book.serno ? `${book.serno}. ` : '' }}
+            <span class="text-blue-10">{{ book.title }}</span>
         </div>
+
+        <div class="q-ml-sm">
+            {{ bookSize }}, {{ book.ext }}
+        </div>
+
+        <div class="q-ml-sm clickable" @click="download">
+            (скачать)
+        </div>
+
+        <div class="q-ml-sm clickable" @click="copyLink">
+            <q-icon name="la la-copy" size="20px" />
+        </div>
+
+        <div class="q-ml-sm">
+            {{ bookGenre }}
+        </div>
+
+        {{ book.src1 }}
     </div>
 </template>
 
@@ -21,11 +39,44 @@ class BookView {
     _options = componentOptions;
     _props = {
         book: Object,
+        genreTree: Array,
     };
 
     created() {
     }
 
+    get bookSize() {
+        let size = this.book.size/1024;
+        let unit = 'KB';
+        if (size > 1024) {
+            size = size/1024;
+            unit = 'MB';
+        }
+        return `${size.toFixed(0)}${unit}`;
+    }
+
+    get bookGenre() {
+        let result = [];
+        const genre = new Set(this.book.genre.split(','));
+
+        for (const section of this.genreTree) {
+            for (const g of section.value)
+                if (genre.has(g.value))
+                    result.push(g.name);
+        }
+
+        return `(${result.join(', ')})`;
+    }
+
+    selectTitle() {
+        this.$emit('bookEvent', {action: 'titleClick', book: this.book});
+    }
+
+    download() {
+    }
+
+    copyLink() {
+    }
 }
 
 export default vueComponent(BookView);
@@ -33,4 +84,13 @@ export default vueComponent(BookView);
 </script>
 
 <style scoped>
+.clickable {
+    color: blue;
+    cursor: pointer;
+}
+
+.clickable2 {
+    cursor: pointer;
+}
+
 </style>

+ 75 - 33
client/components/Search/Search.vue

@@ -131,7 +131,7 @@
                         </div>
                     </div>
 
-                    <div class="clickable q-ml-xs q-py-sm" style="font-weight: bold" @click="selectAuthor(item.author)">
+                    <div class="clickable2 q-ml-xs q-py-sm text-green-10 text-bold" @click="selectAuthor(item.author)">
                         {{ item.name }}                            
                     </div>
 
@@ -140,10 +140,15 @@
                     </div>                    
                 </div>
 
+                <div v-if="item.bookLoading" class="book-row">
+                    Загрузка
+                    <q-icon class="la la-spinner icon-rotate text-blue-8" size="28px" />
+                </div>
+
                 <div v-if="isExpanded(item) && item.books">
                     <div v-for="book in item.books" :key="book.key" class="book-row column">
                         <div v-if="book.type == 'series'" class="column">
-                            <div class="row items-center q-mr-xs no-wrap">
+                            <div class="row items-center q-mr-xs no-wrap text-grey-9">
                                 <div class="row items-center clickable2 q-py-xs no-wrap" @click="expandSeries(book)">
                                     <div style="min-width: 30px">
                                         <div v-if="!isExpandedSeries(book)">
@@ -161,12 +166,10 @@
                             </div>
 
                             <div v-if="isExpandedSeries(book) && book.books" class="book-row column">
-                                <BookView v-for="subbook in book.books" :key="subbook.key" :book="subbook" @book-event="bookEvent" />
+                                <BookView v-for="subbook in book.books" :key="subbook.key" :book="subbook" :genre-tree="genreTree" @book-event="bookEvent" />
                             </div>
                         </div>
-                        <div v-else>
-                            <BookView :book="book" @book-event="bookEvent" />
-                        </div>
+                        <BookView v-else :book="book" :genre-tree="genreTree" @book-event="bookEvent" />
                     </div>
                 </div>
             </div>
@@ -179,6 +182,7 @@
             <div class="row justify-center">
                 <PageScroller v-show="pageCount > 1" v-model="search.page" :page-count="pageCount" />
             </div>
+            <div v-show="pageCount <= 1" class="q-mt-lg" />
         </div>
 
         <Dialog v-model="settingsDialogVisible">
@@ -237,6 +241,8 @@ import diffUtils from '../../share/diffUtils';
 
 import _ from 'lodash';
 
+const maxItemCount = 500;//выше этого значения показываем "Загрузка"
+
 const componentOptions = {
     components: {
         PageScroller,
@@ -487,7 +493,7 @@ class Search {
     }
 
     get hiddenResultsMessage() {
-        return `+${this.hiddenCount} результат${utils.wordEnding(this.hiddenCount)} скрыты`;
+        return `+${this.hiddenCount} результат${utils.wordEnding(this.hiddenCount)} скрыт${utils.wordEnding(this.hiddenCount, 2)}`;
     }
 
     updatePageCount() {
@@ -506,13 +512,37 @@ class Search {
         }
     }
 
+    getBookCount(item) {
+        let result = '';
+        if (!this.showCounts || item.count === undefined)
+            return result;
+
+        if (item.books) {
+            let count = 0;
+            for (const book of item.books) {
+                if (book.type == 'series')
+                    count += book.books.length;
+                else
+                    count++;
+            }
+
+            result = `${count}/${item.count}`;
+        } else 
+            result = `#/${item.count}`;
+
+        return `(${result})`;
+    }
+
     selectAuthor(author) {
         this.search.author = `=${author}`;
+        this.search.series = '';
+        this.search.title = '';
         this.scrollToTop();
     }
 
     selectSeries(series) {
         this.search.series = `=${series}`;
+        this.search.title = '';
     }
 
     bookEvent(event) {
@@ -535,14 +565,14 @@ class Search {
         this.commit('setSettings', {[name]: _.cloneDeep(newValue)});
     }
 
-    expandAuthor(item) {
+    async expandAuthor(item) {
         const expanded = _.cloneDeep(this.expanded);
         const key = item.author;
 
         if (!this.isExpanded(item)) {
             expanded.push(key);
 
-            this.getBooks(item);
+            await this.getBooks(item);
 
             if (expanded.length > 100) {
                 expanded.shift();
@@ -581,19 +611,6 @@ class Search {
         }
     }
 
-    getBookCount(item) {
-        let result = '';
-        if (!this.showCounts || item.count === undefined)
-            return result;
-
-        if (item.books)
-            result = `${item.books.length}/${item.count}`;
-        else 
-            result = `#/${item.count}`;
-
-        return `(${result})`;
-    }
-
     async loadBooks(authorId) {
         try {
             let result;
@@ -709,13 +726,20 @@ class Search {
     }
 
     async getBooks(item) {
-        if (item.books)
+        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++;
+        item.bookLoading = true;
 
         try {
             if (this.getBooksFlag == 1) {
@@ -736,6 +760,12 @@ class Search {
                     type: 'book',
                     title: book.title,
                     series: book.series,
+                    serno: book.serno,
+                    genre: book.genre,
+                    size: book.size,
+                    ext: book.ext,
+
+                    src: book,
                 }
             };
 
@@ -751,6 +781,7 @@ class Search {
                             key: `${item.author}-${book.series}`,
                             type: 'series',
                             series: book.series,
+
                             books: [],
                         });
 
@@ -766,22 +797,32 @@ class Search {
             //сортировка
             books.sort((a, b) => {
                 if (a.type == 'series') {
-                    if (b.type == 'series')
-                        return a.key.localeCompare(b.key);
-                    else
-                        return -1;
+                    return (b.type == 'series' ? a.key.localeCompare(b.key) : -1);
                 } else {
-                    if (b.type == 'book')
-                        return a.title.localeCompare(b.title);
-                    else
-                        return 1;
+                    return (b.type == 'book' ? a.title.localeCompare(b.title) : 1);
                 }
             });
 
             //сортировка внутри серий
+            for (const book of books) {
+                if (book.type == 'series') {
+                    book.books.sort((a, b) => {
+                        const dserno = (a.serno || Number.MAX_VALUE) - (b.serno || Number.MAX_VALUE);
+                        const dtitle = a.title.localeCompare(b.title);
+                        const dext = a.ext.localeCompare(b.ext);
+                        return (dserno ? dserno : (dtitle ? dtitle : dext));
+                    });
+                }
+            }
+
+            if (books.length == 1 && books[0].type == 'series' && !this.isExpandedSeries(books[0])) {
+                this.expandSeries(books[0]);
+            }
 
             item.books = books;
+            await this.$nextTick();
         } finally {
+            item.bookLoading = false;
             this.getBooksFlag--;
             if (this.getBooksFlag == 0)
                 this.loadingMessage2 = '';
@@ -842,11 +883,12 @@ class Search {
                 name: rec.author.replace(/,/g, ', '),
                 count,
                 book: false,
+                bookLoading: false,
             });
             num++;
 
             if (expandedSet.has(item.author)) {
-                if (authors.length > 1)
+                if (authors.length > 1 || item.count > maxItemCount)
                     this.getBooks(item);//no await
                 else 
                     await this.getBooks(item);
@@ -857,7 +899,7 @@ class Search {
 
         if (result.length == 1 && !this.isExpanded(result[0])) {
             this.expandAuthor(result[0]);
-        }        
+        }
 
         this.tableData = result;
     }

+ 2 - 3
client/components/share/NumInput.vue

@@ -11,8 +11,8 @@
         <template #prepend>
             <q-icon
                 v-show="mmButtons"
-                style="font-size: 100%"
                 v-ripple="modelValue != min" 
+                style="font-size: 100%"
                 :class="(modelValue != min ? '' : 'disable')" 
                 name="la la-angle-double-left" 
                 class="button" 
@@ -50,14 +50,13 @@
 
             <q-icon
                 v-show="mmButtons"
-                style="font-size: 100%"
                 v-ripple="modelValue != max" 
+                style="font-size: 100%"
                 :class="(modelValue != max ? '' : 'disable')" 
                 name="la la-angle-double-right" 
                 class="button" 
                 @click="toMax"
             />
-
         </template>
     </q-input>
 </template>