Ver Fonte

Начало добавления группировки в RecentBooksPage

Book Pauk há 3 anos atrás
pai
commit
7caa0c2112
2 ficheiros alterados com 178 adições e 47 exclusões
  1. 175 47
      client/components/Reader/RecentBooksPage/RecentBooksPage.vue
  2. 3 0
      client/quasar.js

+ 175 - 47
client/components/Reader/RecentBooksPage/RecentBooksPage.vue

@@ -9,7 +9,62 @@
 
         <a ref="download" style="display: none;" target="_blank"></a>
 
-        <q-table
+        <div id="vs-container" ref="vsContainer" class="recent-books-scroll col">
+            <div ref="header" class="scroll-header bg-blue-2">
+                <q-input 
+                    ref="input" v-model="search"
+                    outlined rounded dense
+                    style="position: relative; top: 5px; left: 200px; width: 350px" bg-color="white"
+                    placeholder="Найти"
+                    @click.stop
+                >
+                    <template #append>
+                        <q-icon v-if="search !== ''" name="la la-times" class="cursor-pointer" @click.stop="resetSearch" />
+                    </template>
+                </q-input>
+            </div>
+
+            <q-virtual-scroll
+                v-slot="{ item, index }"
+                :items="tableData"
+                scroll-target="#vs-container"
+                virtual-scroll-item-size="80"
+                @virtual-scroll="onScroll"
+            >
+                <div class="table-row row" :class="{even: index % 2 > 0, 'active-book': item.active}">
+                    <div class="row-part row justify-center items-center" style="width: 80px">
+                        {{ index }}
+                    </div>
+
+                    <div class="row-part column items-stretch break-word clickable" style="width: 350px; font-size: 80%" @click="loadBook(item)">
+                        <div class="column col">
+                            <div style="color: green">
+                                {{ item.desc.author }}
+                            </div>
+                            <div>{{ item.desc.title }}</div>
+                        </div>
+                        <div class="read-bar" :style="`width: ${340*item.readPart}px`"></div>
+                    </div>
+
+                    <div class="row-part column justify-center" style="width: 80px; font-size: 80%">
+                        <a v-show="isUrl(item.url)" :href="item.url" target="_blank">Оригинал</a><br>
+                        <a :href="item.path" @click.prevent="downloadBook(item.path, item.fullTitle)">Скачать FB2</a>
+                    </div>
+
+                    <div class="row-part column justify-center">
+                        <q-btn
+                            dense
+                            style="width: 30px; height: 30px; padding: 7px 0 7px 0; margin-left: 4px"
+                            @click="handleDel(item.key)"
+                        >
+                            <q-icon class="la la-times" size="14px" />
+                        </q-btn>
+                    </div>
+                </div>
+            </q-virtual-scroll>
+        </div>
+
+        <!--q-table
             class="recent-books-table col"
             :rows="tableData"
             row-key="key"
@@ -91,7 +146,7 @@
                     </q-td>
                 </q-tr>
             </template>
-        </q-table>
+        </q-table-->
     </Window>
 </template>
 
@@ -103,6 +158,7 @@ import path from 'path-browserify';
 //import _ from 'lodash';
 
 import * as utils from '../../../share/utils';
+import LockQueue from '../../../share/LockQueue';
 import Window from '../../share/Window.vue';
 import bookManager from '../share/bookManager';
 import readerApi from '../../../api/reader';
@@ -127,10 +183,14 @@ class RecentBooksPage {
     pagination = {};
 
     created() {
-        this.firstInit = true;
-        this.pagination = {rowsPerPage: 0};
+        this.lastScrollTop1 = 0;
+        this.lastScrollTop2 = 0;
+
+        this.lock = new LockQueue(100);
 
-        this.columns = [
+        //this.pagination = {rowsPerPage: 0};
+
+        /*this.columns = [
             {
                 name: 'num',
                 label: '#',
@@ -168,7 +228,7 @@ class RecentBooksPage {
                 label: '',
                 align: 'left',
             },
-        ];
+        ];*/
     }
 
     init() {
@@ -177,28 +237,84 @@ class RecentBooksPage {
         this.$nextTick(() => {
             //this.$refs.input.focus();//плохо на планшетах
         });
-        (async() => {//подгрузка списка
-            if (this.initing)
-                return;
-            this.initing = true;
-
-            if (this.firstInit) {//для отзывчивости
-                await this.updateTableData(20);
-                this.firstInit = false;
+
+        this.updateTableData();//no await
+    }
+
+    async updateTableData() {
+        await this.lock.get();
+        try {
+            let result = [];
+
+            const sorted = bookManager.getSortedRecent();
+            const activeBook = bookManager.mostRecentBook();
+
+            let num = 0;
+            for (const book of sorted) {
+                if (book.deleted)
+                    continue;
+
+                num++;
+
+                let d = new Date();
+                d.setTime(book.touchTime);
+                const touchTime = utils.formatDate(d);
+
+                let readPart = 0;
+                let perc = '';
+                let textLen = '';
+                const p = (book.bookPosSeen ? book.bookPosSeen : (book.bookPos ? book.bookPos : 0));
+                if (book.textLength) {
+                    readPart = p/book.textLength;
+                    perc = ` [${(readPart*100).toFixed(2)}%]`;
+                    textLen = ` ${Math.round(book.textLength/1000)}k`;
+                }
+
+                const bt = utils.getBookTitle(book.fb2);
+
+                let title = bt.bookTitle;
+                title = (title ? `"${title}"`: '');
+                const author = (bt.author ? bt.author : (bt.bookTitle ? bt.bookTitle : (book.uploadFileName ? book.uploadFileName : book.url)));
+
+                result.push({
+                    num,
+                    touchTime,
+                    desc: {
+                        author,
+                        title: `${title}${perc}${textLen}`,
+                    },
+                    readPart,
+                    url: book.url,
+                    path: book.path,
+                    fullTitle: bt.fullTitle,
+                    key: book.key,
+                    active: (activeBook.key == book.key),
+
+                    //для сортировки
+                    touchTimeRaw: book.touchTime,
+                    descString: `${author}${title}${perc}${textLen}`,
+                });
             }
-            await utils.sleep(50);
-            await this.updateTableData();
 
-            this.initing = false;
-        })();
+            const search = this.search;
+            result = result.filter(item => {
+                return !search ||
+                    item.touchTime.includes(search) ||
+                    item.desc.title.toLowerCase().includes(search.toLowerCase()) ||
+                    item.desc.author.toLowerCase().includes(search.toLowerCase())
+            });
+
+            this.tableData = result;
+        } finally {
+            this.lock.ret();
+        }
     }
 
-    async updateTableData(limit) {
+    /*async updateTableData(limit) {
         while (this.updating) await utils.sleep(100);
         this.updating = true;
         let result = [];
 
-        this.loading = !!limit;
         const sorted = bookManager.getSortedRecent();
 
         let num = 0;
@@ -260,7 +376,7 @@ class RecentBooksPage {
 
         this.tableData = result;
         this.updating = false;
-    }
+    }*/
 
     resetSearch() {
         this.search = '';
@@ -324,6 +440,24 @@ class RecentBooksPage {
             return false;
     }
 
+    onScroll() {
+        const curScrollTop = this.$refs.vsContainer.scrollTop;
+
+        if (curScrollTop - this.lastScrollTop1 > 150) {
+            this.$refs.header.style.top = `-${this.$refs.header.offsetHeight}px`;
+            this.$refs.header.style.transition = 'top 0.2s ease 0s';
+
+            this.lastScrollTop1 = curScrollTop;
+        } else if (curScrollTop - this.lastScrollTop2 < 0) {
+            this.$refs.header.style.position = 'sticky';
+            this.$refs.header.style.top = 0;
+
+            this.lastScrollTop1 = curScrollTop;
+        }
+
+        this.lastScrollTop2 = curScrollTop;
+    }
+
     close() {
         this.$emit('recent-books-close');
     }
@@ -341,31 +475,34 @@ export default vueComponent(RecentBooksPage);
 </script>
 
 <style scoped>
-.recent-books-table {
+.recent-books-scroll {
     width: 573px;
     overflow-y: auto;
     overflow-x: hidden;
 }
 
-.clickable {
-    cursor: pointer;
+.scroll-header {
+    height: 50px;
+    position: sticky;
+    z-index: 1;
+    top: 0;
+}
+
+.table-row {
+    min-height: 80px;
+    border-bottom: 1px solid #cccccc;
 }
 
-.td-mp {
-    margin: 0 !important;
-    padding: 4px 4px 4px 4px !important;
-    border-bottom: 1px solid #ddd;
+.row-part {
+    padding: 4px 4px 4px 4px;
 }
 
-.no-mp {
-    margin: 0 !important;
-    padding: 0 !important;
-    border: 0;
-    border-left: 1px solid #ddd !important;
+.clickable {
+    cursor: pointer;
 }
 
 .break-word {
-    line-height: 180%;
+    line-height: 150%;
     overflow-wrap: break-word;
     word-wrap: break-word;
     white-space: normal;
@@ -375,21 +512,12 @@ export default vueComponent(RecentBooksPage);
     height: 3px;
     background-color: #aaaaaa;
 }
-</style>
 
-<style>
-.recent-books-table .q-table__middle {
-    height: 100%;
-    overflow-x: hidden;
+.even {
+    background-color: #f0f0f0;
 }
 
-.recent-books-table thead tr:first-child th {
-    position: sticky;
-    z-index: 1;
-    top: 0;
-    background-color: #c1f4cd;
-}
-.recent-books-table tr:nth-child(even) {
-    background-color: #f8f8f8;
+.active-book {
+    background-color: #b0f0b0 !important;
 }
 </style>

+ 3 - 0
client/quasar.js

@@ -32,6 +32,8 @@ import {QPopupProxy} from 'quasar/src/components/popup-proxy';
 import {QDialog} from 'quasar/src/components/dialog';
 import {QChip} from 'quasar/src/components/chip';
 import {QTree} from 'quasar/src/components/tree';
+import {QVirtualScroll} from 'quasar/src/components/virtual-scroll';
+
 //import {QExpansionItem} from 'quasar/src/components/expansion-item';
 
 const components = {
@@ -62,6 +64,7 @@ const components = {
     QChip,
     QTree,
     //QExpansionItem,
+    QVirtualScroll,
 };
 
 //directives