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

This commit is contained in:
Book Pauk
2022-08-20 02:16:27 +07:00
parent d9a03a7e0d
commit 40d6b9c807
4 changed files with 316 additions and 83 deletions

View File

@@ -1,31 +1,40 @@
<template>
<div class="root column fit">
<div class="col fit" style="position: relative">
<div v-show="loadingVisible" class="fit row justify-center items-center" style="position: absolute; background-color: rgba(0, 0, 0, 0.2); z-index: 1">
<div class="root column fit" style="position: relative">
<div v-show="loadingMessage" class="fit row justify-center items-center" style="position: absolute; background-color: rgba(0, 0, 0, 0.2); z-index: 1">
<div class="bg-white row justify-center items-center" style="width: 180px; height: 50px; border-radius: 10px; box-shadow: 2px 2px 10px #333333">
<q-spinner color="primary" size="2em" />
<div class="q-ml-sm">
Поиск авторов...
{{ loadingMessage }}
</div>
</div>
</div>
<div ref="scroller" class="col fit column no-wrap" style="overflow: auto; position: relative" @scroll="onScroll">
<div ref="toolPanel" class="tool-panel column bg-green-11" style="position: sticky; top: 0;">
<div class="header q-mx-md q-mt-sm row justify-between items-center">
<div class="row items-center">
<div class="q-mr-xs">
<div ref="toolPanel" class="tool-panel column bg-green-11" style="position: sticky; top: 0; z-index: 10;">
<div class="header q-mx-md q-mt-xs row items-center justify-between">
<div class="row items-center q-mr-xs" style="font-size: 150%;">
<div class="q-py-xs q-px-sm bg-green-12" style="border: 1px solid #aaaaaa; border-radius: 6px">
{{ projectName }}
</div>
<div class="q-ml-md q-mr-xs">
Коллекция
</div>
<div class="clickable" @click="showCollectionInfo">
{{ collection }}
</div>
</div>
<div class="q-ml-md">
{{ projectName }}
<div class="row items-center" style="font-size: 120%;">
<div class="q-mr-xs">
На странице
</div>
<q-select
v-model="limit" :options="limitOptions" class="bg-white"
dropdown-icon="la la-angle-down la-sm"
outlined dense emit-value map-options
/>
</div>
</div>
<div class="row q-mx-md q-my-sm items-center">
<div class="row q-mx-md q-mb-sm items-center">
<q-input
ref="authorInput" v-model="author" :maxlength="5000" :debounce="inputDebounce"
class="bg-white q-mt-xs" style="width: 300px;" label="Автор" stack-label outlined dense clearable
@@ -64,16 +73,19 @@
Ничего не найдено
</div>
</div>
<div class="q-mx-xs" />
<div class="col row justify-end q-mt-xs">
<q-select
v-model="limit" :options="limitOptions" class="bg-white"
dropdown-icon="la la-angle-down la-sm"
outlined dense emit-value map-options
/>
</div>
</div>
<div v-show="totalPages > 1" class="row justify-center items-center q-ml-md q-my-xs" style="font-size: 120%">
<div class="q-mr-xs">
Страница
</div>
<div class="bg-white">
<NumInput v-model="page" :min="1" :max="totalPages" style="width: 150px" />
</div>
<div class="q-ml-xs">
из {{ totalPages }}
</div>
</div>
<div v-for="item in tableData" :key="item.key" style="border-bottom: 1px solid #aaaaaa">
@@ -81,6 +93,17 @@
{{ item.value }}
</div>
</div>
<div v-show="totalPages > 1" class="row justify-center items-center q-ml-md q-my-xs" style="font-size: 120%">
<div class="q-mr-xs">
Страница
</div>
<div class="bg-white">
<NumInput v-model="page" :min="1" :max="totalPages" style="width: 150px" />
</div>
<div class="q-ml-xs">
из {{ totalPages }}
</div>
</div>
</div>
</div>
@@ -90,11 +113,14 @@
//-----------------------------------------------------------------------------
import vueComponent from '../vueComponent.js';
import NumInput from '../share/NumInput.vue';
import * as utils from '../../share/utils';
//import _ from 'lodash';
const componentOptions = {
components: {
NumInput,
},
watch: {
config() {
@@ -115,9 +141,16 @@ const componentOptions = {
lang() {
this.refresh();
},
limit() {
page() {
this.refresh();
},
limit() {
this.updatePageCount();
this.refresh();
},
totalFound() {
this.updatePageCount();
}
},
};
class Search {
@@ -125,7 +158,9 @@ class Search {
collection = '';
projectName = '';
loadingVisible = false;
loadingMessage = '';
page = 1;
totalPages = 1;
//input field consts
inputMaxLength = 1000;
@@ -220,6 +255,13 @@ class Search {
this.lastScrollTop = curScrollTop;
}
updatePageCount() {
this.totalPages = Math.floor(this.totalFound/this.limit);
this.totalPages = (this.totalPages < 1 ? 1 : this.totalPages);
if (this.page > this.totalPages)
this.page = 1;
}
async updateTableData() {
let result = [];
@@ -231,6 +273,8 @@ class Search {
}
async refresh() {
const offset = (this.page - 1)*this.limit;
const newQuery = {
author: this.author,
series: this.series,
@@ -238,6 +282,7 @@ class Search {
genre: this.genre,
lang: this.lang,
limit: this.limit,
offset,
};
this.queryExecute = newQuery;
@@ -255,7 +300,7 @@ class Search {
(async() => {
await utils.sleep(500);
if (inSearch)
this.loadingVisible = true;
this.loadingMessage = 'Поиск авторов...';
})();
try {
@@ -271,7 +316,7 @@ class Search {
return;
} finally {
inSearch = false;
this.loadingVisible = false;
this.loadingMessage = '';
}
}
} finally {
@@ -293,7 +338,6 @@ export default vueComponent(Search);
}
.header {
font-size: 150%;
min-height: 30px;
}

View File

@@ -0,0 +1,188 @@
<template>
<q-input
v-model="filteredValue"
outlined dense
input-style="text-align: center"
class="no-mp"
:class="(error ? 'error' : '')"
:disable="disable"
>
<slot></slot>
<template #prepend>
<q-icon
v-ripple="validate(modelValue - step)"
:class="(validate(modelValue - step) ? '' : 'disable')"
name="la la-minus-circle"
class="button"
@click="minus"
@mousedown.prevent.stop="onMouseDown($event, 'minus')"
@mouseup.prevent.stop="onMouseUp"
@mouseout.prevent.stop="onMouseUp"
@touchstart.stop="onTouchStart($event, 'minus')"
@touchend.stop="onTouchEnd"
@touchcancel.prevent.stop="onTouchEnd"
/>
</template>
<template #append>
<q-icon
v-ripple="validate(modelValue + step)"
:class="(validate(modelValue + step) ? '' : 'disable')"
name="la la-plus-circle"
class="button"
@click="plus"
@mousedown.prevent.stop="onMouseDown($event, 'plus')"
@mouseup.prevent.stop="onMouseUp"
@mouseout.prevent.stop="onMouseUp"
@touchstart.stop="onTouchStart($event, 'plus')"
@touchend.stop="onTouchEnd"
@touchcancel.prevent.stop="onTouchEnd"
/>
</template>
</q-input>
</template>
<script>
//-----------------------------------------------------------------------------
import vueComponent from '../vueComponent.js';
import * as utils from '../../share/utils';
const componentOptions = {
watch: {
filteredValue: function(newValue) {
if (this.validate(newValue)) {
this.error = false;
this.$emit('update:modelValue', this.string2number(newValue));
} else {
this.error = true;
}
},
modelValue: function(newValue) {
this.filteredValue = newValue;
},
}
};
class NumInput {
_options = componentOptions;
_props = {
modelValue: Number,
min: { type: Number, default: -Number.MAX_VALUE },
max: { type: Number, default: Number.MAX_VALUE },
step: { type: Number, default: 1 },
digits: { type: Number, default: 0 },
disable: Boolean
};
filteredValue = 0;
error = false;
created() {
this.filteredValue = this.modelValue;
}
string2number(value) {
return Number.parseFloat(Number.parseFloat(value).toFixed(this.digits));
}
validate(value) {
let n = this.string2number(value);
if (isNaN(n))
return false;
if (n < this.min)
return false;
if (n > this.max)
return false;
return true;
}
plus() {
const newValue = this.modelValue + this.step;
if (this.validate(newValue))
this.filteredValue = newValue;
}
minus() {
const newValue = this.modelValue - this.step;
if (this.validate(newValue))
this.filteredValue = newValue;
}
onMouseDown(event, way) {
this.startClickRepeat = true;
this.clickRepeat = false;
if (event.button == 0) {
(async() => {
await utils.sleep(300);
if (this.startClickRepeat) {
this.clickRepeat = true;
while (this.clickRepeat) {
if (way == 'plus') {
this.plus();
} else {
this.minus();
}
await utils.sleep(50);
}
}
})();
}
}
onMouseUp() {
if (this.inTouch)
return;
this.startClickRepeat = false;
this.clickRepeat = false;
}
onTouchStart(event, way) {
if (!this.$root.isMobileDevice)
return;
if (event.touches.length == 1) {
this.inTouch = true;
this.onMouseDown({button: 0}, way);
}
}
onTouchEnd() {
if (!this.$root.isMobileDevice)
return;
this.inTouch = false;
this.onMouseUp();
}
}
export default vueComponent(NumInput);
//-----------------------------------------------------------------------------
</script>
<style scoped>
.no-mp {
margin: 0;
padding: 0;
}
.button {
font-size: 130%;
border-radius: 20px;
color: #bbb;
cursor: pointer;
}
.button:hover {
color: #616161;
background-color: #efebe9;
}
.error {
background-color: #ffabab;
border-radius: 3px;
}
.disable, .disable:hover {
cursor: not-allowed;
color: #bbb;
background-color: white;
}
</style>

View File

@@ -67,10 +67,10 @@ const components = {
};
//directives
//import Ripple from 'quasar/src/directives/Ripple';
import Ripple from 'quasar/src/directives/Ripple';
import ClosePopup from 'quasar/src/directives/ClosePopup';
const directives = {/*Ripple, */ClosePopup};
const directives = {Ripple, ClosePopup};
//plugins
//import AppFullscreen from 'quasar/src/plugins/AppFullscreen';

View File

@@ -240,12 +240,13 @@ class DbSearcher {
const totalFound = authorIds.length;
const limit = (query.limit ? query.limit : 1000);
const offset = (query.offset ? query.offset : 0);
//выборка найденных авторов
let result = await db.select({
table: 'author',
map: `(r) => ({id: r.id, author: r.author})`,
where: `@@id(${db.esc(authorIds.slice(0, limit))})`
where: `@@id(${db.esc(authorIds.slice(offset, offset + limit))})`
});
return {result, totalFound};