Работа над TitleList
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<LoadingMessage :message="loadingMessage2" z-index="1" />
|
<LoadingMessage :message="loadingMessage2" z-index="1" />
|
||||||
|
|
||||||
<!-- Формирование списка ------------------------------------------------------------------------>
|
<!-- Формирование списка ------------------------------------------------------------------------>
|
||||||
<div v-for="item in tableData" :key="item.key" class="column" :class="{'odd-author': item.num % 2}" style="font-size: 120%">
|
<div v-for="item in tableData" :key="item.key" class="column" :class="{'odd-item': item.num % 2}" style="font-size: 120%">
|
||||||
<div class="row items-center q-ml-md q-mr-xs no-wrap">
|
<div class="row items-center q-ml-md q-mr-xs no-wrap">
|
||||||
<div class="row items-center clickable2 q-py-xs no-wrap" @click="expandAuthor(item)">
|
<div class="row items-center clickable2 q-py-xs no-wrap" @click="expandAuthor(item)">
|
||||||
<div style="min-width: 30px">
|
<div style="min-width: 30px">
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
|
|
||||||
<div v-if="isExpandedAuthor(item) && item.books && !item.books.length" class="book-row row items-center">
|
<div v-if="isExpandedAuthor(item) && item.books && !item.books.length" class="book-row row items-center">
|
||||||
<q-icon class="la la-meh q-mr-xs" size="24px" />
|
<q-icon class="la la-meh q-mr-xs" size="24px" />
|
||||||
По каждому из заданных критериев у этого автора были найдены разные книги, но нет полного совпадения
|
По каждому из заданных критериев у этого автора были найдены разные книги, но нет полного совпадения
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -456,7 +456,7 @@ export default vueComponent(AuthorList);
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.odd-author {
|
.odd-item {
|
||||||
background-color: #e8e8e8;
|
background-color: #e8e8e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -198,6 +198,9 @@ export default class BaseList {
|
|||||||
case 'authorClick':
|
case 'authorClick':
|
||||||
this.selectAuthor(event.book.author);
|
this.selectAuthor(event.book.author);
|
||||||
break;
|
break;
|
||||||
|
case 'seriesClick':
|
||||||
|
this.selectSeries(event.book.series);
|
||||||
|
break;
|
||||||
case 'titleClick':
|
case 'titleClick':
|
||||||
this.selectTitle(event.book.title);
|
this.selectTitle(event.book.title);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="q-ml-sm row items-center">
|
<div v-if="!titleList" class="q-ml-sm row items-center">
|
||||||
{{ book.serno ? `${book.serno}. ` : '' }}
|
{{ book.serno ? `${book.serno}. ` : '' }}
|
||||||
<div v-if="showAuthor && book.author">
|
<div v-if="showAuthor && book.author">
|
||||||
<span class="clickable2 text-green-10" @click="selectAuthor">{{ bookAuthor }}</span>
|
<span class="clickable2 text-green-10" @click="selectAuthor">{{ bookAuthor }}</span>
|
||||||
@@ -40,6 +40,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<span v-else class="clickable2" :class="titleColor" @click="selectTitle">{{ book.title }}</span>
|
<span v-else class="clickable2" :class="titleColor" @click="selectTitle">{{ book.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="q-ml-sm row items-center">
|
||||||
|
<span class="clickable2" :class="titleColor" @click="selectTitle">{{ book.title }}</span>
|
||||||
|
|
||||||
|
<div v-if="book.author || bookSeries" class="row">
|
||||||
|
-
|
||||||
|
<div v-if="book.author">
|
||||||
|
<span class="clickable2 text-green-10" @click="selectAuthor">{{ bookAuthor }}</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div v-if="bookSeries">
|
||||||
|
<span class="clickable2" @click="selectSeries">{{ bookSeries }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="q-ml-sm">
|
<div class="q-ml-sm">
|
||||||
@@ -88,6 +102,7 @@ class BookView {
|
|||||||
genreMap: Object,
|
genreMap: Object,
|
||||||
showAuthor: Boolean,
|
showAuthor: Boolean,
|
||||||
showReadLink: Boolean,
|
showReadLink: Boolean,
|
||||||
|
titleList: Boolean,
|
||||||
titleColor: { type: String, default: 'text-blue-10'},
|
titleColor: { type: String, default: 'text-blue-10'},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,7 +127,7 @@ class BookView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get bookAuthor() {
|
get bookAuthor() {
|
||||||
if (this.showAuthor && this.book.author) {
|
if ((this.showAuthor || this.titleList) && this.book.author) {
|
||||||
let a = this.book.author.split(',');
|
let a = this.book.author.split(',');
|
||||||
return a.slice(0, 2).join(', ') + (a.length > 2 ? ' и др.' : '');
|
return a.slice(0, 2).join(', ') + (a.length > 2 ? ' и др.' : '');
|
||||||
}
|
}
|
||||||
@@ -120,6 +135,14 @@ class BookView {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get bookSeries() {
|
||||||
|
if (this.book.series) {
|
||||||
|
return `(${this.book.series})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
get bookSize() {
|
get bookSize() {
|
||||||
let size = this.book.size/1024;
|
let size = this.book.size/1024;
|
||||||
let unit = 'KB';
|
let unit = 'KB';
|
||||||
@@ -155,6 +178,10 @@ class BookView {
|
|||||||
this.$emit('bookEvent', {action: 'authorClick', book: this.book});
|
this.$emit('bookEvent', {action: 'authorClick', book: this.book});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectSeries() {
|
||||||
|
this.$emit('bookEvent', {action: 'seriesClick', book: this.book});
|
||||||
|
}
|
||||||
|
|
||||||
selectTitle() {
|
selectTitle() {
|
||||||
this.$emit('bookEvent', {action: 'titleClick', book: this.book});
|
this.$emit('bookEvent', {action: 'titleClick', book: this.book});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-show="message" class="fit row justify-center items-center" :style="`position: absolute; top: 0; left: 0; background-color: rgba(0, 0, 0, 0.2); z-index: ${zIndex}`">
|
<div v-show="message" class="fit row justify-center items-center" :style="`position: fixed; top: 0; left: 0; background-color: rgba(0, 0, 0, 0.2); z-index: ${zIndex}`">
|
||||||
<div class="bg-white row justify-center items-center q-px-lg" style="min-width: 180px; height: 50px; border-radius: 10px; box-shadow: 2px 2px 10px #333333">
|
<div class="bg-white row justify-center items-center q-px-lg" style="min-width: 180px; height: 50px; border-radius: 10px; box-shadow: 2px 2px 10px #333333">
|
||||||
<q-icon class="la la-spinner icon-rotate text-blue-8" size="28px" />
|
<q-icon class="la la-spinner icon-rotate text-blue-8" size="28px" />
|
||||||
<div class="q-ml-sm">
|
<div class="q-ml-sm">
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ import vueComponent from '../vueComponent.js';
|
|||||||
|
|
||||||
import AuthorList from './AuthorList/AuthorList.vue';
|
import AuthorList from './AuthorList/AuthorList.vue';
|
||||||
import SeriesList from './SeriesList/SeriesList.vue';
|
import SeriesList from './SeriesList/SeriesList.vue';
|
||||||
|
import TitleList from './TitleList/TitleList.vue';
|
||||||
|
|
||||||
import PageScroller from './PageScroller/PageScroller.vue';
|
import PageScroller from './PageScroller/PageScroller.vue';
|
||||||
import SelectGenreDialog from './SelectGenreDialog/SelectGenreDialog.vue';
|
import SelectGenreDialog from './SelectGenreDialog/SelectGenreDialog.vue';
|
||||||
@@ -186,13 +187,14 @@ import _ from 'lodash';
|
|||||||
const route2component = {
|
const route2component = {
|
||||||
'author': {component: 'AuthorList', label: 'Авторы'},
|
'author': {component: 'AuthorList', label: 'Авторы'},
|
||||||
'series': {component: 'SeriesList', label: 'Серии'},
|
'series': {component: 'SeriesList', label: 'Серии'},
|
||||||
'book': {component: 'AuthorList', label: 'Книги'},
|
'book': {component: 'TitleList', label: 'Книги'},
|
||||||
};
|
};
|
||||||
|
|
||||||
const componentOptions = {
|
const componentOptions = {
|
||||||
components: {
|
components: {
|
||||||
AuthorList,
|
AuthorList,
|
||||||
SeriesList,
|
SeriesList,
|
||||||
|
TitleList,
|
||||||
PageScroller,
|
PageScroller,
|
||||||
SelectGenreDialog,
|
SelectGenreDialog,
|
||||||
SelectLangDialog,
|
SelectLangDialog,
|
||||||
@@ -263,6 +265,7 @@ const componentOptions = {
|
|||||||
selectedList(newValue) {
|
selectedList(newValue) {
|
||||||
this.selectedListComponent = (route2component[newValue] ? route2component[newValue].component : null);
|
this.selectedListComponent = (route2component[newValue] ? route2component[newValue].component : null);
|
||||||
this.pageCount = 1;
|
this.pageCount = 1;
|
||||||
|
this.foundCountMessage = '';
|
||||||
|
|
||||||
if (this.getListRoute() != newValue) {
|
if (this.getListRoute() != newValue) {
|
||||||
this.updateRouteQueryFromSearch();
|
this.updateRouteQueryFromSearch();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<LoadingMessage :message="loadingMessage2" z-index="1" />
|
<LoadingMessage :message="loadingMessage2" z-index="1" />
|
||||||
|
|
||||||
<!-- Формирование списка ------------------------------------------------------------------------>
|
<!-- Формирование списка ------------------------------------------------------------------------>
|
||||||
<div v-for="item in tableData" :key="item.key" class="column" :class="{'odd-author': item.num % 2}" style="font-size: 120%">
|
<div v-for="item in tableData" :key="item.key" class="column" :class="{'odd-item': item.num % 2}" style="font-size: 120%">
|
||||||
<div class="row items-center q-ml-md q-mr-xs no-wrap">
|
<div class="row items-center q-ml-md q-mr-xs no-wrap">
|
||||||
<div class="row items-center clickable2 q-py-xs no-wrap" @click="expandSeries(item)">
|
<div class="row items-center clickable2 q-py-xs no-wrap" @click="expandSeries(item)">
|
||||||
<div style="min-width: 30px">
|
<div style="min-width: 30px">
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
<div v-if="!item.showAllBooks && isExpandedSeries(item) && item.books && !item.books.length" class="book-row row items-center">
|
<div v-if="!item.showAllBooks && isExpandedSeries(item) && item.books && !item.books.length" class="book-row row items-center">
|
||||||
<q-icon class="la la-meh q-mr-xs" size="24px" />
|
<q-icon class="la la-meh q-mr-xs" size="24px" />
|
||||||
По каждому из заданных критериев у этой серии были найдены разные книги, но нет полного совпадения
|
Возможно у этой серии были найдены книги, помеченные как удаленные, но подходящие по критериям
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -288,7 +288,7 @@ export default vueComponent(SeriesList);
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.odd-author {
|
.odd-item {
|
||||||
background-color: #e8e8e8;
|
background-color: #e8e8e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
158
client/components/Search/TitleList/TitleList.vue
Normal file
158
client/components/Search/TitleList/TitleList.vue
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a ref="download" style="display: none;"></a>
|
||||||
|
|
||||||
|
<LoadingMessage :message="loadingMessage" z-index="2" />
|
||||||
|
<LoadingMessage :message="loadingMessage2" z-index="1" />
|
||||||
|
|
||||||
|
<!-- Формирование списка ------------------------------------------------------------------------>
|
||||||
|
<div v-for="item in tableData" :key="item.key" class="column" :class="{'odd-item': item.num % 2}" style="font-size: 120%">
|
||||||
|
<BookView
|
||||||
|
class="book-row"
|
||||||
|
title-list
|
||||||
|
:book="item.book" :genre-map="genreMap" :show-read-link="showReadLink" @book-event="bookEvent"
|
||||||
|
/>
|
||||||
|
<BookView
|
||||||
|
v-for="book in item.books" :key="book.id"
|
||||||
|
:book="book" :genre-map="genreMap"
|
||||||
|
class="book-row"
|
||||||
|
title-list
|
||||||
|
:show-read-link="showReadLink"
|
||||||
|
@book-event="bookEvent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- Формирование списка конец ------------------------------------------------------------------>
|
||||||
|
|
||||||
|
<div v-if="!refreshing && !tableData.length" class="row items-center q-ml-md" style="font-size: 120%">
|
||||||
|
<q-icon class="la la-meh q-mr-xs" size="28px" />
|
||||||
|
Поиск не дал результатов
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
import vueComponent from '../../vueComponent.js';
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
import BaseList from '../BaseList';
|
||||||
|
|
||||||
|
import * as utils from '../../../share/utils';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
class TitleList extends BaseList {
|
||||||
|
get foundCountMessage() {
|
||||||
|
return `Найден${utils.wordEnding(this.list.totalFound, 4)} ${this.list.totalFound} уникальн${utils.wordEnding(this.list.totalFound, 6)} назван${utils.wordEnding(this.list.totalFound, 3)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTableData() {
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
const title = this.searchResult.title;
|
||||||
|
if (!title)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let num = 0;
|
||||||
|
for (const rec of title) {
|
||||||
|
const item = reactive({
|
||||||
|
key: rec.id,
|
||||||
|
title: rec.title,
|
||||||
|
num,
|
||||||
|
|
||||||
|
book: false,
|
||||||
|
books: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (rec.books) {
|
||||||
|
const filtered = this.filterBooks(rec.books);
|
||||||
|
|
||||||
|
for (let i = 0; i < filtered.length; i++) {
|
||||||
|
if (i === 0)
|
||||||
|
item.book = filtered[i];
|
||||||
|
else
|
||||||
|
item.books.push(filtered[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtered.length) {
|
||||||
|
num++;
|
||||||
|
result.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tableData = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async refresh() {
|
||||||
|
//параметры запроса
|
||||||
|
let newQuery = _.cloneDeep(this.search);
|
||||||
|
newQuery = newQuery.setDefaults(newQuery);
|
||||||
|
delete newQuery.setDefaults;
|
||||||
|
newQuery.offset = (newQuery.page - 1)*newQuery.limit;
|
||||||
|
|
||||||
|
if (_.isEqual(newQuery, this.prevQuery))
|
||||||
|
return;
|
||||||
|
this.prevQuery = newQuery;
|
||||||
|
|
||||||
|
this.queryExecute = newQuery;
|
||||||
|
|
||||||
|
if (this.refreshing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.refreshing = true;
|
||||||
|
|
||||||
|
(async() => {
|
||||||
|
await utils.sleep(500);
|
||||||
|
if (this.refreshing)
|
||||||
|
this.loadingMessage = 'Поиск книг...';
|
||||||
|
})();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (this.queryExecute) {
|
||||||
|
const query = this.queryExecute;
|
||||||
|
this.queryExecute = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.api.titleSearch(query);
|
||||||
|
|
||||||
|
this.list.queryFound = result.title.length;
|
||||||
|
this.list.totalFound = result.totalFound;
|
||||||
|
this.list.inpxHash = result.inpxHash;
|
||||||
|
|
||||||
|
this.searchResult = result;
|
||||||
|
|
||||||
|
await utils.sleep(1);
|
||||||
|
if (!this.queryExecute) {
|
||||||
|
await this.updateTableData();
|
||||||
|
this.scrollToTop();
|
||||||
|
this.highlightPageScroller(query);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.$root.stdDialog.alert(e.message, 'Ошибка');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.refreshing = false;
|
||||||
|
this.loadingMessage = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default vueComponent(TitleList);
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.clickable2 {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odd-item {
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.book-row {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -40,6 +40,8 @@ export function wordEnding(num, type = 0) {
|
|||||||
['о', '', 'о', 'о', 'о', 'о', 'о', 'о', 'о', 'о'],
|
['о', '', 'о', 'о', 'о', 'о', 'о', 'о', 'о', 'о'],
|
||||||
['ий', 'ие', 'ия', 'ия', 'ия', 'ий', 'ий', 'ий', 'ий', 'ий'],
|
['ий', 'ие', 'ия', 'ия', 'ия', 'ий', 'ий', 'ий', 'ий', 'ий'],
|
||||||
['о', 'а', 'о', 'о', 'о', 'о', 'о', 'о', 'о', 'о'],
|
['о', 'а', 'о', 'о', 'о', 'о', 'о', 'о', 'о', 'о'],
|
||||||
|
['ок', 'ка', 'ки', 'ки', 'ки', 'ок', 'ок', 'ок', 'ок', 'ок'],
|
||||||
|
['ых', 'ое', 'ых', 'ых', 'ых', 'ых', 'ых', 'ых', 'ых', 'ых'],
|
||||||
];
|
];
|
||||||
const deci = num % 100;
|
const deci = num % 100;
|
||||||
if (deci > 10 && deci < 20) {
|
if (deci > 10 && deci < 20) {
|
||||||
|
|||||||
Reference in New Issue
Block a user