Работа над проектом
This commit is contained in:
@@ -29,7 +29,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DivBtn class="q-mx-md text-white bg-secondary" :size="30" :icon-size="24" :imt="1" icon="la la-cog" round @click="settingsDialogVisible = true" />
|
<DivBtn class="q-mx-md text-white bg-secondary" :size="30" :icon-size="24" :imt="1" icon="la la-cog" round @click="settingsDialogVisible = true">
|
||||||
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||||
|
Настройки
|
||||||
|
</q-tooltip>
|
||||||
|
</DivBtn>
|
||||||
|
|
||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
<div class="q-px-sm q-py-xs bg-green-12" style="border: 1px solid #aaaaaa; border-radius: 6px">
|
<div class="q-px-sm q-py-xs bg-green-12" style="border: 1px solid #aaaaaa; border-radius: 6px">
|
||||||
@@ -57,7 +61,7 @@
|
|||||||
class="bg-white q-mt-xs" input-style="cursor: pointer" style="width: 200px;" label="Жанр" stack-label outlined dense clearable readonly
|
class="bg-white q-mt-xs" input-style="cursor: pointer" style="width: 200px;" label="Жанр" stack-label outlined dense clearable readonly
|
||||||
@click="selectGenre"
|
@click="selectGenre"
|
||||||
>
|
>
|
||||||
<q-tooltip v-if="genreNames" :delay="500" anchor="bottom right" content-style="font-size: 80%" max-width="400px">
|
<q-tooltip v-if="genreNames" :delay="500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||||
{{ genreNames }}
|
{{ genreNames }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-input>
|
</q-input>
|
||||||
@@ -66,10 +70,24 @@
|
|||||||
v-model="lang" :maxlength="inputMaxLength" :debounce="inputDebounce"
|
v-model="lang" :maxlength="inputMaxLength" :debounce="inputDebounce"
|
||||||
class="bg-white q-mt-xs" input-style="cursor: pointer" style="width: 80px;" label="Язык" stack-label outlined dense clearable readonly
|
class="bg-white q-mt-xs" input-style="cursor: pointer" style="width: 80px;" label="Язык" stack-label outlined dense clearable readonly
|
||||||
@click="selectLang"
|
@click="selectLang"
|
||||||
/>
|
>
|
||||||
<div class="q-mx-xs" />
|
<q-tooltip v-if="lang" :delay="500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||||
|
{{ lang }}
|
||||||
|
</q-tooltip>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
<DivBtn class="text-white bg-grey-13" :size="30" :icon-size="24" icon="la la-question" round @click="showSearchHelp" />
|
<div class="q-mx-xs" />
|
||||||
|
<DivBtn class="text-white bg-grey-13" :size="30" :icon-size="24" icon="la la-broom" round @click="setDefaults">
|
||||||
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||||
|
Сбросить поиск
|
||||||
|
</q-tooltip>
|
||||||
|
</DivBtn>
|
||||||
|
<div class="q-mx-xs" />
|
||||||
|
<DivBtn class="text-white bg-grey-13" :size="30" :icon-size="24" icon="la la-question" round @click="showSearchHelp">
|
||||||
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%" max-width="400px">
|
||||||
|
Подсказка
|
||||||
|
</q-tooltip>
|
||||||
|
</DivBtn>
|
||||||
|
|
||||||
<div class="q-mx-xs" />
|
<div class="q-mx-xs" />
|
||||||
<div class="row items-center q-mt-xs">
|
<div class="row items-center q-mt-xs">
|
||||||
@@ -93,7 +111,7 @@
|
|||||||
<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 style="min-width: 35px">
|
<!--div style="min-width: 35px">
|
||||||
<DivBtn v-if="tableData.length > 1" :icon-size="24" icon="la la-check-circle" @click="selectAuthor(item.author)">
|
<DivBtn v-if="tableData.length > 1" :icon-size="24" icon="la la-check-circle" @click="selectAuthor(item.author)">
|
||||||
<q-tooltip :delay="1500" anchor="bottom right" content-style="font-size: 80%">
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
||||||
Только этот автор
|
Только этот автор
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</DivBtn>
|
</DivBtn>
|
||||||
@@ -171,6 +189,7 @@
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<SelectGenreDialog v-model="selectGenreDialogVisible" v-model:genre="genre" :genre-tree="genreTree" />
|
<SelectGenreDialog v-model="selectGenreDialogVisible" v-model:genre="genre" :genre-tree="genreTree" />
|
||||||
|
<SelectLangDialog v-model="selectLangDialogVisible" v-model:lang="lang" :lang-list="langList" :lang-default="langDefault" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -181,6 +200,8 @@ import { reactive } from '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';
|
||||||
|
import SelectLangDialog from './SelectLangDialog/SelectLangDialog.vue';
|
||||||
|
|
||||||
import authorBooksStorage from './authorBooksStorage';
|
import authorBooksStorage from './authorBooksStorage';
|
||||||
import DivBtn from '../share/DivBtn.vue';
|
import DivBtn from '../share/DivBtn.vue';
|
||||||
import Dialog from '../share/Dialog.vue';
|
import Dialog from '../share/Dialog.vue';
|
||||||
@@ -193,6 +214,7 @@ const componentOptions = {
|
|||||||
components: {
|
components: {
|
||||||
PageScroller,
|
PageScroller,
|
||||||
SelectGenreDialog,
|
SelectGenreDialog,
|
||||||
|
SelectLangDialog,
|
||||||
Dialog,
|
Dialog,
|
||||||
DivBtn
|
DivBtn
|
||||||
},
|
},
|
||||||
@@ -250,6 +272,7 @@ class Search {
|
|||||||
loadingMessage2 = '';
|
loadingMessage2 = '';
|
||||||
settingsDialogVisible = false;
|
settingsDialogVisible = false;
|
||||||
selectGenreDialogVisible = false;
|
selectGenreDialogVisible = false;
|
||||||
|
selectLangDialogVisible = false;
|
||||||
|
|
||||||
page = 1;
|
page = 1;
|
||||||
pageCount = 1;
|
pageCount = 1;
|
||||||
@@ -271,6 +294,7 @@ class Search {
|
|||||||
showCounts = true;
|
showCounts = true;
|
||||||
showDeleted = false;
|
showDeleted = false;
|
||||||
abCacheEnabled = true;
|
abCacheEnabled = true;
|
||||||
|
langDefault = '';
|
||||||
|
|
||||||
//stuff
|
//stuff
|
||||||
queryFound = -1;
|
queryFound = -1;
|
||||||
@@ -278,6 +302,7 @@ class Search {
|
|||||||
bookRowsOnPage = 100;
|
bookRowsOnPage = 100;
|
||||||
inpxHash = '';
|
inpxHash = '';
|
||||||
genreTree = [];
|
genreTree = [];
|
||||||
|
langList = [];
|
||||||
genreTreeInpxHash = '';
|
genreTreeInpxHash = '';
|
||||||
|
|
||||||
limitOptions = [
|
limitOptions = [
|
||||||
@@ -308,6 +333,10 @@ class Search {
|
|||||||
if (!this.$root.isMobileDevice)
|
if (!this.$root.isMobileDevice)
|
||||||
this.$refs.authorInput.focus();
|
this.$refs.authorInput.focus();
|
||||||
|
|
||||||
|
this.setDefaults();
|
||||||
|
|
||||||
|
//query from url parse
|
||||||
|
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
this.refresh();//no await
|
this.refresh();//no await
|
||||||
})();
|
})();
|
||||||
@@ -321,6 +350,7 @@ class Search {
|
|||||||
this.showCounts = settings.showCounts;
|
this.showCounts = settings.showCounts;
|
||||||
this.showDeleted = settings.showDeleted;
|
this.showDeleted = settings.showDeleted;
|
||||||
this.abCacheEnabled = settings.abCacheEnabled;
|
this.abCacheEnabled = settings.abCacheEnabled;
|
||||||
|
this.langDefault = settings.langDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
get config() {
|
||||||
@@ -373,7 +403,7 @@ class Search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectLang() {
|
selectLang() {
|
||||||
this.$root.stdDialog.alert('Выбор языка');
|
this.selectLangDialogVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
@@ -434,9 +464,7 @@ class Search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSetting(name, newValue) {
|
setSetting(name, newValue) {
|
||||||
const newSettings = _.cloneDeep(this.settings);
|
this.commit('setSettings', {[name]: _.cloneDeep(newValue)});
|
||||||
newSettings[name] = _.cloneDeep(newValue);
|
|
||||||
this.commit('setSettings', newSettings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expandAuthor(item) {
|
expandAuthor(item) {
|
||||||
@@ -566,6 +594,7 @@ class Search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.genreTree = result.genreTree;
|
this.genreTree = result.genreTree;
|
||||||
|
this.langList = result.langList;
|
||||||
this.genreTreeInpxHash = result.inpxHash;
|
this.genreTreeInpxHash = result.inpxHash;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -606,6 +635,14 @@ class Search {
|
|||||||
this.tableData = result;
|
this.tableData = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDefaults() {
|
||||||
|
this.author = '';
|
||||||
|
this.series = '';
|
||||||
|
this.title = '';
|
||||||
|
this.genre = '';
|
||||||
|
this.lang = this.langDefault;
|
||||||
|
}
|
||||||
|
|
||||||
async refresh() {
|
async refresh() {
|
||||||
if (!this.ready)
|
if (!this.ready)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div ref="box" class="column q-mt-xs overflow-auto no-wrap" style="width: 350px; padding: 0px 10px 10px 10px;">
|
<div ref="box" class="column q-mt-xs overflow-auto no-wrap" style="width: 370px; padding: 0px 10px 10px 10px;">
|
||||||
<div class="row items-center top-panel bg-grey-3">
|
<div class="row items-center top-panel bg-grey-3">
|
||||||
<q-input ref="search" v-model="search" class="col" outlined dense bg-color="white" placeholder="Найти" clearable />
|
<q-input ref="search" v-model="search" class="col" outlined dense bg-color="white" placeholder="Найти" clearable />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
190
client/components/Search/SelectLangDialog/SelectLangDialog.vue
Normal file
190
client/components/Search/SelectLangDialog/SelectLangDialog.vue
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog ref="dialog" v-model="dialogVisible">
|
||||||
|
<template #header>
|
||||||
|
<div class="row items-center">
|
||||||
|
<div style="font-size: 130%">
|
||||||
|
Выбрать язык
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div ref="box" class="column q-mt-xs overflow-auto no-wrap" style="width: 370px; padding: 0px 10px 10px 10px;">
|
||||||
|
<div v-show="langList.length" class="checkbox-tick-all">
|
||||||
|
<div class="row items-center">
|
||||||
|
<q-option-group
|
||||||
|
v-model="ticked"
|
||||||
|
:options="optionsPre"
|
||||||
|
type="checkbox"
|
||||||
|
inline
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="col" />
|
||||||
|
<div v-show="lang != langDefault" class="clickable" @click="setAsDefaults">
|
||||||
|
Установить по умолчанию
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-checkbox v-model="tickAll" label="Выбрать/снять все" toggle-order="ft" @update:model-value="makeTickAll" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-option-group
|
||||||
|
v-model="ticked"
|
||||||
|
:options="options"
|
||||||
|
type="checkbox"
|
||||||
|
inline
|
||||||
|
>
|
||||||
|
<template #label="opt">
|
||||||
|
<div class="row items-center" style="width: 35px">
|
||||||
|
<span>{{ opt.label }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-option-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<q-btn class="q-px-md q-ml-sm" color="primary" dense no-caps @click="okClick">
|
||||||
|
OK
|
||||||
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
import vueComponent from '../../vueComponent.js';
|
||||||
|
|
||||||
|
import Dialog from '../../share/Dialog.vue';
|
||||||
|
|
||||||
|
const componentOptions = {
|
||||||
|
components: {
|
||||||
|
Dialog
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(newValue) {
|
||||||
|
this.dialogVisible = newValue;
|
||||||
|
if (newValue)
|
||||||
|
this.init();//no await
|
||||||
|
},
|
||||||
|
dialogVisible(newValue) {
|
||||||
|
this.$emit('update:modelValue', newValue);
|
||||||
|
},
|
||||||
|
lang() {
|
||||||
|
this.updateTicked();
|
||||||
|
},
|
||||||
|
ticked() {
|
||||||
|
this.checkAllTicked();
|
||||||
|
this.updateLang();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class SelectLangDialog {
|
||||||
|
_options = componentOptions;
|
||||||
|
_props = {
|
||||||
|
modelValue: Boolean,
|
||||||
|
lang: {type: String, value: ''},
|
||||||
|
langDefault: {type: String, value: ''},
|
||||||
|
langList: Array,
|
||||||
|
};
|
||||||
|
|
||||||
|
dialogVisible = false;
|
||||||
|
|
||||||
|
ticked = [];
|
||||||
|
tickAll = false;
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.commit = this.$store.commit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
//await this.$refs.dialog.waitShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
get options() {
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (const lang of this.langList) {
|
||||||
|
result.push({label: lang, value: lang});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
get optionsPre() {
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (const lang of this.langList) {
|
||||||
|
if (['ru', 'en'].includes(lang)) {
|
||||||
|
result.push({label: lang, value: lang});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
makeTickAll() {
|
||||||
|
if (this.tickAll) {
|
||||||
|
const newTicked = [];
|
||||||
|
for (const lang of this.langList) {
|
||||||
|
newTicked.push(lang);
|
||||||
|
}
|
||||||
|
this.ticked = newTicked;
|
||||||
|
} else {
|
||||||
|
this.ticked = [];
|
||||||
|
this.tickAll = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAllTicked() {
|
||||||
|
const ticked = new Set(this.ticked);
|
||||||
|
|
||||||
|
let newTickAll = !!(this.langList.length);
|
||||||
|
for (const lang of this.langList) {
|
||||||
|
if (!ticked.has(lang)) {
|
||||||
|
newTickAll = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ticked.length && !newTickAll) {
|
||||||
|
this.tickAll = undefined;
|
||||||
|
} else {
|
||||||
|
this.tickAll = newTickAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTicked() {
|
||||||
|
this.ticked = this.lang.split(',').filter(s => s);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLang() {
|
||||||
|
this.$emit('update:lang', this.ticked.join(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
setAsDefaults() {
|
||||||
|
this.commit('setSettings', {langDefault: this.lang});
|
||||||
|
}
|
||||||
|
|
||||||
|
okClick() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default vueComponent(SelectLangDialog);
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.checkbox-tick-all {
|
||||||
|
border-bottom: 1px solid #bbbbbb;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
padding: 5px 5px 2px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable {
|
||||||
|
color: blue;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -33,8 +33,9 @@ import {QDialog} from 'quasar/src/components/dialog';
|
|||||||
//import {QChip} from 'quasar/src/components/chip';
|
//import {QChip} from 'quasar/src/components/chip';
|
||||||
import {QTree} from 'quasar/src/components/tree';
|
import {QTree} from 'quasar/src/components/tree';
|
||||||
//import {QVirtualScroll} from 'quasar/src/components/virtual-scroll';
|
//import {QVirtualScroll} from 'quasar/src/components/virtual-scroll';
|
||||||
|
|
||||||
//import {QExpansionItem} from 'quasar/src/components/expansion-item';
|
//import {QExpansionItem} from 'quasar/src/components/expansion-item';
|
||||||
|
import {QOptionGroup} from 'quasar/src/components/option-group';
|
||||||
|
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
//QLayout,
|
//QLayout,
|
||||||
@@ -66,6 +67,7 @@ const components = {
|
|||||||
QTree,
|
QTree,
|
||||||
//QExpansionItem,
|
//QExpansionItem,
|
||||||
//QVirtualScroll,
|
//QVirtualScroll,
|
||||||
|
QOptionGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
//directives
|
//directives
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const state = {
|
|||||||
showCounts: true,
|
showCounts: true,
|
||||||
showDeleted: false,
|
showDeleted: false,
|
||||||
abCacheEnabled: true,
|
abCacheEnabled: true,
|
||||||
|
langDefault: '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ const mutations = {
|
|||||||
state.config = value;
|
state.config = value;
|
||||||
},
|
},
|
||||||
setSettings(state, value) {
|
setSettings(state, value) {
|
||||||
state.settings = value;
|
state.settings = Object.assign({}, state.settings, value);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ class WebWorker {
|
|||||||
|
|
||||||
//добавим к жанрам те, что нашлись при парсинге
|
//добавим к жанрам те, что нашлись при парсинге
|
||||||
const genreParsed = new Set();
|
const genreParsed = new Set();
|
||||||
const rows = await db.select({table: 'genre', map: `(r) => ({value: r.value})`});
|
let rows = await db.select({table: 'genre', map: `(r) => ({value: r.value})`});
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
genreParsed.add(row.value);
|
genreParsed.add(row.value);
|
||||||
|
|
||||||
@@ -245,8 +245,13 @@ class WebWorker {
|
|||||||
genres.splice(j--, 1);
|
genres.splice(j--, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// langs
|
||||||
|
rows = await db.select({table: 'lang', map: `(r) => ({value: r.value})`});
|
||||||
|
const langs = rows.map(r => r.value);
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
genreTree: genres,
|
genreTree: genres,
|
||||||
|
langList: langs,
|
||||||
inpxHash: (config.inpxHash ? config.inpxHash : ''),
|
inpxHash: (config.inpxHash ? config.inpxHash : ''),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user