Automatic pagination with vnPagination, improved vnSearchbar
This commit is contained in:
parent
a015b790b5
commit
9fa12d4baf
|
@ -75,20 +75,20 @@
|
|||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
margin-large-right
|
||||
label="Description"
|
||||
model="observation.description"
|
||||
rule="addressObservation.description">
|
||||
</vn-textfield>
|
||||
<vn-auto pad-medium-top>
|
||||
<vn-icon
|
||||
pointer
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
medium-grey
|
||||
margin-medium-v
|
||||
vn-tooltip="Remove note"
|
||||
icon="remove_circle_outline"
|
||||
ng-click="$ctrl.removeObservation($index)">
|
||||
</vn-icon>
|
||||
</vn-one>
|
||||
ng-click="$ctrl.removeObservation($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
<vn-icon-button
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
<mg-ajax path="/client/api/Clients/filter" options="vnIndexNonAuto"></mg-ajax>
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/item/api/Clients"
|
||||
filter="::$ctrl.filter"
|
||||
limit="4"
|
||||
data="clients"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
<div margin-medium>
|
||||
<div class="vn-list">
|
||||
<vn-card>
|
||||
<vn-horizontal>
|
||||
<vn-searchbar vn-one
|
||||
index="index"
|
||||
on-search="$ctrl.search(index)"
|
||||
advanced="true"
|
||||
popover="vn-client-search-panel"
|
||||
ignore-keys = "['page', 'size', 'search']">
|
||||
<vn-card pad-medium-h>
|
||||
<vn-searchbar
|
||||
panel="vn-client-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
</vn-searchbar>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-card margin-medium-top>
|
||||
<vn-card margin-medium-v>
|
||||
<vn-item-client
|
||||
ng-repeat="client in index.model.instances track by client.id"
|
||||
client="client">
|
||||
ng-repeat="client in clients track by client.id"
|
||||
client="::client">
|
||||
</vn-item-client>
|
||||
</vn-card>
|
||||
<vn-paging index="index" total="index.model.count"></vn-paging>
|
||||
<!-- <vn-auto-paging index="index" total="index.model.count" items="$ctrl.clients"></vn-auto-paging> -->
|
||||
<vn-pagination
|
||||
model="model"
|
||||
scroll-selector="ui-view">
|
||||
</vn-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<a ui-sref="client.create" vn-bind="+" fixed-bottom-right>
|
||||
|
|
|
@ -2,23 +2,42 @@ import ngModule from '../module';
|
|||
import './item-client';
|
||||
|
||||
export default class Controller {
|
||||
|
||||
constructor($scope) {
|
||||
this.$scope = $scope;
|
||||
this.$ = $scope;
|
||||
this.clientSelected = null;
|
||||
}
|
||||
|
||||
search(index) {
|
||||
index.accept();
|
||||
/* this.clients = [];
|
||||
index.accept().then(res => {
|
||||
this.clients = res.instances;
|
||||
}); */
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return {
|
||||
or: [
|
||||
{id: value},
|
||||
{name: {regexp: value}}
|
||||
]
|
||||
};
|
||||
case 'phone':
|
||||
return {
|
||||
or: [
|
||||
{phone: value},
|
||||
{mobile: value}
|
||||
]
|
||||
};
|
||||
case 'name':
|
||||
case 'socialName':
|
||||
case 'city':
|
||||
return {[param]: {regexp: value}};
|
||||
case 'id':
|
||||
case 'fi':
|
||||
case 'postcode':
|
||||
case 'email':
|
||||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
openSummary(client) {
|
||||
this.clientSelected = client;
|
||||
this.$scope.dialogSummaryClient.show();
|
||||
this.$.dialogSummaryClient.show();
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$scope'];
|
||||
|
|
|
@ -3,3 +3,4 @@ Phone: Teléfono
|
|||
Town/City: Ciudad
|
||||
Email: Correo electrónico
|
||||
Create client: Crear cliente
|
||||
View client: Ver cliente
|
|
@ -1,22 +1,22 @@
|
|||
<div pad-large style="min-width: 30em">
|
||||
<form ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Client id" model="$ctrl.filter.id" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Tax number" model="$ctrl.filter.fi"></vn-textfield>
|
||||
<vn-textfield vn-one label="Client id" model="filter.id" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Tax number" model="filter.fi"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Name" model="$ctrl.filter.name"></vn-textfield>
|
||||
<vn-textfield vn-one label="Name" model="filter.name"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Social name" model="$ctrl.filter.socialName"></vn-textfield>
|
||||
<vn-textfield vn-one label="Social name" model="filter.socialName"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Town/City" model="$ctrl.filter.city"></vn-textfield>
|
||||
<vn-textfield vn-one label="Postcode" model="$ctrl.filter.postcode"></vn-textfield>
|
||||
<vn-textfield vn-one label="Town/City" model="filter.city"></vn-textfield>
|
||||
<vn-textfield vn-one label="Postcode" model="filter.postcode"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Email" model="$ctrl.filter.email"></vn-textfield>
|
||||
<vn-textfield vn-one label="Phone" model="$ctrl.filter.phone"></vn-textfield>
|
||||
<vn-textfield vn-one label="Email" model="filter.email"></vn-textfield>
|
||||
<vn-textfield vn-one label="Phone" model="filter.phone"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
|
|
|
@ -1,18 +1,7 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor() {
|
||||
// onSubmit() is defined by @vnSearchbar
|
||||
this.onSubmit = () => {};
|
||||
}
|
||||
|
||||
onSearch() {
|
||||
this.onSubmit(this.filter);
|
||||
}
|
||||
}
|
||||
Controller.$inject = [];
|
||||
import SearchPanel from 'core/src/components/searchbar/search-panel';
|
||||
|
||||
ngModule.component('vnClientSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
controller: SearchPanel
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ import './style.scss';
|
|||
|
||||
export default class IconButton {
|
||||
constructor($element) {
|
||||
if ($element[0].getAttribute('tabindex') == null)
|
||||
$element[0].tabIndex = 0;
|
||||
$element.on("keyup", event => this.onKeyDown(event, $element));
|
||||
}
|
||||
|
|
|
@ -2,32 +2,16 @@
|
|||
|
||||
vn-icon-button {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
color: rgba($main-01, 0.7);
|
||||
font-size: 18pt;
|
||||
transition: color 200ms ease-in-out;
|
||||
cursor: pointer;
|
||||
|
||||
&.button {
|
||||
background-color: $main-01;
|
||||
color: white;
|
||||
width: 64px;
|
||||
height: 36px;
|
||||
box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, rgba(0, 0, 0, 0.2) 0px 3px 1px -2px, rgba(0, 0, 0, 0.12) 0px 1px 5px 0px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&.button:focus {
|
||||
will-change: box-shadow;
|
||||
box-shadow: 0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36);
|
||||
transition: box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1);
|
||||
}
|
||||
&.button i {
|
||||
margin-top: 6px;
|
||||
}
|
||||
& > i,
|
||||
& > i.material-icons {
|
||||
& > vn-icon {
|
||||
display: block;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&:not(.button):hover {
|
||||
color: $main-01;
|
||||
|
|
|
@ -3,7 +3,6 @@ import './rest-model/crud-model';
|
|||
import './rest-model/rest-model';
|
||||
import './watcher/watcher';
|
||||
import './textfield/textfield';
|
||||
import './paging/paging';
|
||||
import './icon/icon';
|
||||
import './dialog/dialog';
|
||||
import './confirm/confirm';
|
||||
|
@ -34,4 +33,7 @@ import './switch/switch';
|
|||
import './float-button/float-button';
|
||||
import './step-control/step-control';
|
||||
import './label-value/label-value';
|
||||
import './paging/paging';
|
||||
import './auto-paging/auto-paging';
|
||||
import './pagination/pagination';
|
||||
import './searchbar/searchbar';
|
||||
|
|
|
@ -2,7 +2,7 @@ import ngModule from '../../module';
|
|||
import './style.scss';
|
||||
|
||||
ngModule.component('vnLabelValue', {
|
||||
template: require('../label-value/label-value.html'),
|
||||
template: require('./label-value.html'),
|
||||
replace: true,
|
||||
transclude: true,
|
||||
bindings: {
|
||||
|
|
|
@ -12,13 +12,17 @@ export default class ModelProxy {
|
|||
|
||||
set orgData(value) {
|
||||
this._orgData = value;
|
||||
this._data = [];
|
||||
// this._data.splice(0, this._data.length);
|
||||
|
||||
if (this.Row) {
|
||||
this._data = [];
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
let row = new this.Row(value[i], i);
|
||||
this._data.push(row);
|
||||
}
|
||||
} else
|
||||
this._data = value;
|
||||
|
||||
this.resetChanges();
|
||||
}
|
||||
|
@ -112,6 +116,11 @@ export default class ModelProxy {
|
|||
|
||||
this.resetChanges();
|
||||
}
|
||||
|
||||
dataChanged() {
|
||||
if (this.onDataChange)
|
||||
this.onDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnModelProxy', {
|
||||
|
@ -120,6 +129,7 @@ ngModule.component('vnModelProxy', {
|
|||
orgData: '<?',
|
||||
data: '=?',
|
||||
fields: '<?',
|
||||
link: '<?'
|
||||
link: '<?',
|
||||
onDataChange: '&?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<div
|
||||
ng-if="$ctrl.model.moreRows">
|
||||
<vn-icon-button
|
||||
ng-if="!$ctrl.model.isLoading"
|
||||
icon="more_horiz"
|
||||
vn-tooltip="Load more"
|
||||
ng-click="$ctrl.model.loadMore()">
|
||||
</vn-icon-button>
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.model.isLoading"
|
||||
enable="$ctrl.model.isLoading">
|
||||
</vn-spinner>
|
||||
</div>
|
|
@ -0,0 +1,75 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Pagination component that automatically loads more rows when
|
||||
* the user scrolls down an element.
|
||||
*
|
||||
* @property {CrudModel} model The model used for pagination
|
||||
* @property {String} scrollSelector The the scrollable element selector
|
||||
* @property {HTMLElement} scrollElement The scrollable element
|
||||
* @property {Number} scrollOffset The distance, in pixels, until the end that activates the loading of the next rows
|
||||
*/
|
||||
class Pagination extends Component {
|
||||
constructor($element, $scope) {
|
||||
super($element, $scope);
|
||||
this.scrollOffset = 20;
|
||||
this.scrollHandler = e => this.onScroll(e);
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (!this._scrollElement)
|
||||
this.scrollElement = document.body;
|
||||
}
|
||||
|
||||
set scrollSelector(value) {
|
||||
this._scrollSelector = value;
|
||||
this.scrollElement = document.querySelector(value);
|
||||
}
|
||||
|
||||
get scrollSelector() {
|
||||
return this._scrollSelector;
|
||||
}
|
||||
|
||||
set scrollElement(value) {
|
||||
if (this._scrollElement)
|
||||
this._scrollElement.removeEventListener('scroll', this.scrollHandler);
|
||||
|
||||
this._scrollElement = value;
|
||||
|
||||
if (value)
|
||||
this._scrollElement.addEventListener('scroll', this.scrollHandler);
|
||||
}
|
||||
|
||||
get scrollElement() {
|
||||
return this._scrollElement;
|
||||
}
|
||||
|
||||
onScroll() {
|
||||
let scrollElement = this.scrollElement;
|
||||
let shouldLoad =
|
||||
scrollElement.scrollTop + scrollElement.clientHeight >= (scrollElement.scrollHeight - this.scrollOffset)
|
||||
&& !this.model.isLoading;
|
||||
|
||||
if (shouldLoad) {
|
||||
this.model.loadMore();
|
||||
this.$.$apply();
|
||||
}
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.scrollElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnPagination', {
|
||||
template: require('./pagination.html'),
|
||||
bindings: {
|
||||
model: '<',
|
||||
scrollSelector: '@?',
|
||||
scrollElement: '<?',
|
||||
scrollOffset: '<?'
|
||||
},
|
||||
controller: Pagination
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
vn-pagination {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
||||
& > div > vn-icon-button {
|
||||
font-size: 2em;
|
||||
}
|
||||
}
|
|
@ -10,32 +10,80 @@ export default class CrudModel extends ModelProxy {
|
|||
this.autoLoad = true;
|
||||
}
|
||||
|
||||
get isLoading() {
|
||||
return this.canceler != null;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.autoLoad)
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
refresh(usFilter, usData) {
|
||||
if (!this.url) return;
|
||||
|
||||
let filter = this.filter;
|
||||
|
||||
if (!filter) {
|
||||
let where = Object.assign({}, this.link, this.where);
|
||||
filter = {
|
||||
let myFilter = {
|
||||
fields: this.fields,
|
||||
where: where,
|
||||
where: mergeWhere(this.link, this.where),
|
||||
include: this.include,
|
||||
order: this.order,
|
||||
limit: this.limit
|
||||
limit: this.limit,
|
||||
userData: this.userData
|
||||
};
|
||||
|
||||
let filter = this.filter;
|
||||
filter = mergeFilters(myFilter, filter);
|
||||
filter = mergeFilters(usFilter, filter);
|
||||
return this.sendRequest(filter);
|
||||
}
|
||||
|
||||
let urlFilter = encodeURIComponent(JSON.stringify(filter));
|
||||
cancelRequest() {
|
||||
if (this.canceler) {
|
||||
this.canceler.resolve();
|
||||
this.canceler = null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.$http.get(`${this.url}?filter=${urlFilter}`).then(res => {
|
||||
this.orgData = res.data;
|
||||
});
|
||||
sendRequest(filter, append) {
|
||||
this.cancelRequest();
|
||||
this.canceler = this.$q.defer();
|
||||
let options = {timeout: this.canceler.promise};
|
||||
let json = encodeURIComponent(JSON.stringify(filter));
|
||||
return this.$http.get(`${this.url}?filter=${json}`, options).then(
|
||||
json => this.onRemoteDone(json, filter, append),
|
||||
json => this.onRemoteError(json)
|
||||
);
|
||||
}
|
||||
|
||||
onRemoteDone(json, filter, append) {
|
||||
let data = json.data;
|
||||
|
||||
if (append)
|
||||
this.orgData = this.orgData.concat(data);
|
||||
else
|
||||
this.orgData = data;
|
||||
|
||||
this.currentFilter = filter;
|
||||
this.moreRows = filter.limit && data.length == filter.limit;
|
||||
this.onRequestEnd();
|
||||
this.dataChanged();
|
||||
}
|
||||
|
||||
onRemoteError(err) {
|
||||
this.onRequestEnd();
|
||||
throw err;
|
||||
}
|
||||
|
||||
onRequestEnd() {
|
||||
this.canceler = null;
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
if (this.moreRows) {
|
||||
let filter = Object.assign({}, this.currentFilter);
|
||||
filter.skip = (filter.skip || 0) + filter.limit;
|
||||
this.sendRequest(filter, true);
|
||||
}
|
||||
}
|
||||
|
||||
getChanges() {
|
||||
|
@ -97,7 +145,87 @@ ngModule.component('vnCrudModel', {
|
|||
order: '@?',
|
||||
limit: '<?',
|
||||
filter: '<?',
|
||||
userData: '<?',
|
||||
primaryKey: '@?',
|
||||
autoLoad: '<?'
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Passes a loopback fields filter to an object.
|
||||
*
|
||||
* @param {Object} fields The fields object or array
|
||||
* @return {Object} The fields as object
|
||||
*/
|
||||
function fieldsToObject(fields) {
|
||||
let fieldsObj = {};
|
||||
|
||||
if (Array.isArray(fields))
|
||||
for (let field of fields)
|
||||
fieldsObj[field] = true;
|
||||
else if (typeof fields == 'object')
|
||||
for (let field in fields)
|
||||
if (fields[field])
|
||||
fieldsObj[field] = true;
|
||||
|
||||
return fieldsObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two loopback fields filters.
|
||||
*
|
||||
* @param {Object|Array} src The source fields
|
||||
* @param {Object|Array} dst The destination fields
|
||||
* @return {Array} The merged fields as an array
|
||||
*/
|
||||
function mergeFields(src, dst) {
|
||||
let fields = {};
|
||||
Object.assign(fields,
|
||||
fieldsToObject(src),
|
||||
fieldsToObject(dst)
|
||||
);
|
||||
return Object.keys(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two loopback where filters.
|
||||
*
|
||||
* @param {Object|Array} src The source where
|
||||
* @param {Object|Array} dst The destination where
|
||||
* @return {Array} The merged wheres
|
||||
*/
|
||||
function mergeWhere(src, dst) {
|
||||
let and = [];
|
||||
if (src) and.push(src);
|
||||
if (dst) and.push(dst);
|
||||
return and.length > 1 ? {and} : and[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two loopback filters returning the merged filter.
|
||||
*
|
||||
* @param {Object} src The source filter
|
||||
* @param {Object} dst The destination filter
|
||||
* @return {Object} The result filter
|
||||
*/
|
||||
function mergeFilters(src, dst) {
|
||||
let res = Object.assign({}, dst);
|
||||
|
||||
if (!src)
|
||||
return res;
|
||||
|
||||
if (src.fields)
|
||||
res.fields = mergeFields(src.fields, res.fields);
|
||||
if (src.where)
|
||||
res.where = mergeWhere(res.where, src.where);
|
||||
if (src.include)
|
||||
res.include = src.include;
|
||||
if (src.order)
|
||||
res.order = src.order;
|
||||
if (src.limit)
|
||||
res.limit = src.limit;
|
||||
if (src.userData)
|
||||
res.userData = src.userData;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import Component from '../../lib/component';
|
||||
|
||||
export default class extends Component {
|
||||
set filter(value) {
|
||||
this.$.filter = value;
|
||||
}
|
||||
|
||||
get filter() {
|
||||
return this.$.filter;
|
||||
}
|
||||
|
||||
onSearch() {
|
||||
if (!this.onSubmit)
|
||||
throw new Error('SearchPanel::onSubmit() method not defined');
|
||||
|
||||
this.onSubmit(this.filter);
|
||||
}
|
||||
}
|
|
@ -5,11 +5,11 @@
|
|||
ng-click="$ctrl.clearFilter(); $ctrl.onSubmit()"
|
||||
style="cursor: pointer; padding-top: 23px">
|
||||
</vn-icon-button>
|
||||
<vn-textfield vn-one label="Search" model="$ctrl.stringSearch"></vn-textfield>
|
||||
<vn-textfield vn-one label="Search" model="$ctrl.searchString"></vn-textfield>
|
||||
<vn-icon
|
||||
pad-medium-top
|
||||
ng-if="$ctrl.advanced"
|
||||
ng-click="$ctrl.onpenFilters($event)"
|
||||
ng-if="$ctrl.panel"
|
||||
ng-click="$ctrl.openPanel($event)"
|
||||
icon="keyboard_arrow_down"
|
||||
style="cursor: pointer; color: #aaa">
|
||||
</vn-icon>
|
|
@ -0,0 +1,200 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* An input specialized to perform searches, it allows to use a panel
|
||||
* for advanced searches when the panel property is defined.
|
||||
* When model and exprBuilder properties are used, the model is updated
|
||||
* automatically with an and-filter exprexion in which each operand is built
|
||||
* by calling the exprBuilder function for each non-null parameter.
|
||||
*
|
||||
* @property {Object} filter A key-value object with filter parameters
|
||||
* @property {Function} onSearch Function to call when search is submited
|
||||
* @property {SearchPanel} panel The panel used for advanced searches
|
||||
* @property {CrudModel} model The model used for searching
|
||||
* @property {Function} exprBuilder If defined, is used to build each non-null param expresion
|
||||
*/
|
||||
export default class Controller extends Component {
|
||||
constructor($element, $scope, $compile, $state, $transitions) {
|
||||
super($element, $scope);
|
||||
this.$compile = $compile;
|
||||
this.$state = $state;
|
||||
this.deregisterCallback = $transitions.onStart({},
|
||||
transition => this.changeState(transition));
|
||||
|
||||
this.filter = {};
|
||||
this.searchString = '';
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.$state.params.q)
|
||||
this.filter = JSON.parse(decodeURIComponent(this.$state.params.q));
|
||||
|
||||
this.refreshString();
|
||||
this.doSearch();
|
||||
}
|
||||
|
||||
changeState(transition) {
|
||||
return transition._targetState._identifier.name !== this.$state.current.name;
|
||||
}
|
||||
|
||||
openPanel(event) {
|
||||
if (event.defaultPrevented) return;
|
||||
event.preventDefault();
|
||||
|
||||
this.$panel = this.$compile(`<${this.panel}/>`)(this.$.$new());
|
||||
let panel = this.$panel.isolateScope().$ctrl;
|
||||
panel.filter = this.filter;
|
||||
panel.onSubmit = filter => this.onPanelSubmit(filter);
|
||||
|
||||
this.$.popover.parent = this.element;
|
||||
this.$.popover.child = this.$panel[0];
|
||||
this.$.popover.show();
|
||||
}
|
||||
|
||||
onPopoverClose() {
|
||||
this.$panel.scope().$destroy();
|
||||
this.$panel.remove();
|
||||
this.$panel = null;
|
||||
}
|
||||
|
||||
onPanelSubmit(filter) {
|
||||
this.$.popover.hide();
|
||||
|
||||
for (let param in filter)
|
||||
if (filter[param] == null)
|
||||
delete filter[param];
|
||||
|
||||
this.filter = filter;
|
||||
this.refreshString();
|
||||
this.doSearch();
|
||||
}
|
||||
|
||||
refreshString() {
|
||||
this.searchString = this.getStringFromObject(this.filter);
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.filter = this.getObjectFromString(this.searchString);
|
||||
this.doSearch();
|
||||
}
|
||||
|
||||
doSearch() {
|
||||
this.pushFilterToState(this.filter);
|
||||
|
||||
if (this.onSearch)
|
||||
this.onSearch({filter: this.filter});
|
||||
|
||||
if (this.model) {
|
||||
if (!this.exprBuilder)
|
||||
throw new Error('exprBuilder property should be defined when model is assigned');
|
||||
|
||||
let and = [];
|
||||
|
||||
for (let param in this.filter) {
|
||||
let value = this.filter[param];
|
||||
if (value == null) continue;
|
||||
let expr = this.exprBuilder({param, value});
|
||||
if (expr) and.push(expr);
|
||||
}
|
||||
|
||||
let lbFilter = and.length > 0 ? {where: {and}} : null;
|
||||
this.model.refresh(lbFilter);
|
||||
}
|
||||
}
|
||||
|
||||
pushFilterToState(filter) {
|
||||
let history = window.history || {pushState: () => {
|
||||
console.error('Error in history.pushState(): Browser incompatibility error');
|
||||
}};
|
||||
let aux = window.location.hash.split('?q=');
|
||||
if (Object.keys(filter).length)
|
||||
history.pushState({}, null, `${aux[0]}?q=${encodeURIComponent(JSON.stringify(filter))}`);
|
||||
else
|
||||
history.pushState({}, null, aux[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds pattern key:value or key:(extra value) and passes it to object.
|
||||
*
|
||||
* @param {String} searchString The search string
|
||||
* @return {Object} The parsed object
|
||||
*/
|
||||
getObjectFromString(searchString) {
|
||||
let result = {};
|
||||
if (searchString) {
|
||||
let regex = /((([\w_]+):([\w_]+))|([\w_]+):\(([\w_ ]+)\))/gi;
|
||||
let findPattern = searchString.match(regex);
|
||||
let remnantString = searchString.replace(regex, '').trim();
|
||||
if (findPattern) {
|
||||
for (let i = 0; i < findPattern.length; i++) {
|
||||
let aux = findPattern[i].split(':');
|
||||
let property = aux[0];
|
||||
let value = aux[1].replace(/\(|\)/g, '');
|
||||
result[property] = value.trim();
|
||||
}
|
||||
}
|
||||
if (remnantString)
|
||||
result.search = remnantString;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes an object to pattern key:value or key:(extra value).
|
||||
*
|
||||
* @param {Object} searchObject The search object
|
||||
* @return {String} The passed string
|
||||
*/
|
||||
getStringFromObject(searchObject) {
|
||||
let search = [];
|
||||
|
||||
if (searchObject) {
|
||||
let keys = Object.keys(searchObject);
|
||||
keys.forEach(key => {
|
||||
if (key == 'search') return;
|
||||
|
||||
let value = searchObject[key];
|
||||
let valueString;
|
||||
|
||||
if (typeof value === 'string' && value.indexOf(' ') !== -1)
|
||||
valueString = `(${value})`;
|
||||
else if (value instanceof Date)
|
||||
valueString = value.toJSON();
|
||||
else
|
||||
switch (typeof value) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
valueString = `${value}`;
|
||||
}
|
||||
|
||||
if (valueString)
|
||||
search.push(`${key}:${valueString}`);
|
||||
});
|
||||
|
||||
if (searchObject.search)
|
||||
search.unshift(searchObject.search);
|
||||
}
|
||||
|
||||
return search.length ? search.join(' ') : '';
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.deregisterCallback();
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope', '$compile', '$state', '$transitions'];
|
||||
|
||||
ngModule.component('vnSearchbar', {
|
||||
template: require('./searchbar.html'),
|
||||
bindings: {
|
||||
filter: '<?',
|
||||
onSearch: '&',
|
||||
panel: '@',
|
||||
model: '<?',
|
||||
exprBuilder: '&?'
|
||||
},
|
||||
controller: Controller
|
||||
});
|
|
@ -1,7 +1,6 @@
|
|||
vn-searchbar {
|
||||
padding-top: 6px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
display: block;
|
||||
|
||||
& > form > vn-horizontal > vn-icon-button {
|
||||
color: black;
|
|
@ -11,4 +11,5 @@ Hide: Hide
|
|||
Next: Next
|
||||
Finalize: Finalize
|
||||
Previous: Back
|
||||
Load more: Load more
|
||||
Auto-scroll interrupted, please adjust the search: Auto-scroll interrupted, please adjust the search
|
|
@ -11,4 +11,5 @@ Hide: Ocultar
|
|||
Next: Siguiente
|
||||
Finalize: Finalizar
|
||||
Previous: Anterior
|
||||
Load more: Cargar más
|
||||
Auto-scroll interrupted, please adjust the search: Auto-scroll interrumpido, por favor ajusta la búsqueda
|
|
@ -1,77 +0,0 @@
|
|||
<div pad-large style="min-width: 30em">
|
||||
<form ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Id"
|
||||
model="$ctrl.filter.id"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Name"
|
||||
model="$ctrl.filter.name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Description"
|
||||
model="$ctrl.filter.description">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="/item/api/ItemTypes"
|
||||
label="Type"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.typeFk">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="/item/api/Producers"
|
||||
label="Producer"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.producerFk">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="/item/api/Origins"
|
||||
label="Origin"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.originFk">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="/item/api/Inks"
|
||||
label="Ink"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.inkFk">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Category"
|
||||
model="$ctrl.filter.category">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Size"
|
||||
type="number"
|
||||
model="$ctrl.filter.itemSize">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor() {
|
||||
this.onSubmit = () => {};
|
||||
}
|
||||
|
||||
onSearch() {
|
||||
this.onSubmit(this.filter);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnItemFilterPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,26 +1,30 @@
|
|||
<mg-ajax path="/item/api/Items/filter" options="vnIndexNonAuto"></mg-ajax>
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/item/api/Items"
|
||||
filter="::$ctrl.filter"
|
||||
limit="4"
|
||||
data="items"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
<div margin-medium>
|
||||
<div class="vn-list">
|
||||
<vn-card>
|
||||
<vn-horizontal>
|
||||
<vn-card pad-medium-h>
|
||||
<vn-searchbar
|
||||
vn-one
|
||||
index="index"
|
||||
on-search="$ctrl.search(index)"
|
||||
advanced="true"
|
||||
popover="vn-item-filter-panel"
|
||||
ignore-keys = "['page', 'size', 'search']">
|
||||
panel="vn-item-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
</vn-searchbar>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-card margin-medium-top>
|
||||
<vn-card margin-medium-v>
|
||||
<vn-item-product
|
||||
ng-repeat="item in index.model.instances track by item.id"
|
||||
item="item">
|
||||
ng-repeat="item in items track by item.id"
|
||||
item="::item">
|
||||
</vn-item-product>
|
||||
</vn-card>
|
||||
<vn-paging index="index" total="index.model.count"></vn-paging>
|
||||
<!-- <vn-auto-paging index="index" total="index.model.count" items="$ctrl.items"></vn-auto-paging> -->
|
||||
<vn-pagination
|
||||
model="model"
|
||||
scroll-selector="ui-view">
|
||||
</vn-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<a ui-sref="item.create" vn-bind="+" fixed-bottom-right>
|
||||
|
|
|
@ -3,46 +3,68 @@ import './product';
|
|||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
|
||||
constructor($http, $state, $scope) {
|
||||
this.$http = $http;
|
||||
this.$state = $state;
|
||||
this.$scope = $scope;
|
||||
this.model = {};
|
||||
this.$ = $scope;
|
||||
this.itemSelected = null;
|
||||
this.items = [];
|
||||
|
||||
this.filter = {
|
||||
include: [
|
||||
{relation: 'itemType',
|
||||
scope: {
|
||||
fields: ['name', 'workerFk'],
|
||||
include: {
|
||||
relation: 'worker',
|
||||
fields: ['firstName', 'name']
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
order: 'name ASC'
|
||||
};
|
||||
}
|
||||
|
||||
search(index) {
|
||||
index.accept();
|
||||
/* this.items = [];
|
||||
index.accept().then(res => {
|
||||
this.items = res.instances;
|
||||
}); */
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return {
|
||||
or: [
|
||||
{id: value},
|
||||
{name: {regexp: value}}
|
||||
]
|
||||
};
|
||||
case 'name':
|
||||
case 'description':
|
||||
return {[param]: {regexp: value}};
|
||||
case 'id':
|
||||
case 'typeFk':
|
||||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
cloneItem(item) {
|
||||
this.itemSelected = item;
|
||||
this.$scope.clone.show();
|
||||
this.$.clone.show();
|
||||
}
|
||||
|
||||
onCloneAccept(response) {
|
||||
if (response == 'ACCEPT' && this.itemSelected) {
|
||||
if (!(response == 'ACCEPT' && this.itemSelected))
|
||||
return;
|
||||
|
||||
this.$http.post(`/item/api/Items/${this.itemSelected.id}/clone`).then(res => {
|
||||
if (res && res.data && res.data.id) {
|
||||
if (res && res.data && res.data.id)
|
||||
this.$state.go('item.card.tags', {id: res.data.id});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.itemSelected = null;
|
||||
}
|
||||
|
||||
showItemPreview(item) {
|
||||
this.itemSelected = item;
|
||||
this.$scope.preview.show();
|
||||
this.$.preview.show();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$http', '$state', '$scope'];
|
||||
|
||||
ngModule.component('vnItemIndex', {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import "./colors";
|
||||
|
||||
vn-item-product {
|
||||
display: block;
|
||||
|
|
|
@ -2,7 +2,7 @@ export * from './module';
|
|||
|
||||
import './index';
|
||||
import './filter-item-list';
|
||||
import './filter-panel';
|
||||
import './search-panel';
|
||||
import './create';
|
||||
import './card';
|
||||
import './descriptor';
|
||||
|
|
|
@ -43,3 +43,4 @@ Add barcode: Añadir código de barras
|
|||
Remove barcode: Quitar código de barras
|
||||
Buyer: Comprador
|
||||
No results: Sin resultados
|
||||
Tag: Etiqueta
|
|
@ -0,0 +1,84 @@
|
|||
<mg-ajax path="/item/api/Tags" options="mgIndex as tags"></mg-ajax>
|
||||
<div style="min-width: 30em; max-height: 540px; overflow: auto;">
|
||||
<form pad-large ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Id"
|
||||
model="filter.id"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Name"
|
||||
model="filter.name">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
vn-focus
|
||||
url="/item/api/ItemTypes"
|
||||
label="Type"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="filter.typeFk">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Description"
|
||||
model="filter.description">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<!--
|
||||
<vn-horizontal ng-repeat="itemTag in filter.tags">
|
||||
<vn-autocomplete
|
||||
vn-id="tag"
|
||||
vn-one
|
||||
field="itemTag.tagFk"
|
||||
data="tags.model"
|
||||
show-field="name"
|
||||
label="Tag"
|
||||
on-change="itemTag.value = null">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
ng-show="tag.selection.isFree !== false"
|
||||
vn-id="text"
|
||||
label="Value"
|
||||
model="itemTag.value">
|
||||
</vn-textfield>
|
||||
<vn-autocomplete
|
||||
vn-two
|
||||
ng-show="tag.selection.isFree === false"
|
||||
url="{{$ctrl.getSourceTable(tag.selection)}}"
|
||||
label="Value"
|
||||
field="itemTag.value"
|
||||
show-field="name"
|
||||
value-field="name">
|
||||
</vn-autocomplete>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
medium-grey
|
||||
margin-medium-v
|
||||
vn-tooltip="Remove tag"
|
||||
icon="remove_circle_outline"
|
||||
ng-click="filter.tags.splice($index, 1)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-icon-button
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add tag"
|
||||
icon="add_circle"
|
||||
ng-click="filter.tags.push({})">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
-->
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,32 @@
|
|||
import ngModule from '../module';
|
||||
import SearchPanel from 'core/src/components/searchbar/search-panel';
|
||||
|
||||
class Controller extends SearchPanel {
|
||||
set filter(value) {
|
||||
if (!value.tags)
|
||||
value.tags = [{}];
|
||||
|
||||
this.$.filter = value;
|
||||
}
|
||||
|
||||
get filter() {
|
||||
return this.$.filter;
|
||||
}
|
||||
|
||||
getSourceTable(selection) {
|
||||
if (!selection || selection.isFree === true)
|
||||
return null;
|
||||
|
||||
if (selection.sourceTable)
|
||||
return '/api/'
|
||||
+ selection.sourceTable.charAt(0).toUpperCase()
|
||||
+ selection.sourceTable.substring(1) + 's';
|
||||
else if (selection.sourceTable == null)
|
||||
return `/api/ItemTags/filterItemTags/${selection.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnItemSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -48,14 +48,16 @@
|
|||
rule="itemTag.priority"
|
||||
vn-acl="buyer">
|
||||
</vn-textfield>
|
||||
<vn-icon
|
||||
pad-medium-top
|
||||
pointer
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
medium-grey
|
||||
margin-medium-v
|
||||
vn-tooltip="Remove tag"
|
||||
icon="remove_circle_outline"
|
||||
ng-click="$ctrl.removeTag($index)">
|
||||
</vn-icon>
|
||||
ng-click="$ctrl.removeTag($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
|
|
|
@ -4,4 +4,3 @@ import './main-menu/main-menu';
|
|||
import './left-menu/left-menu';
|
||||
import './left-menu/menu-item';
|
||||
import './topbar/topbar';
|
||||
import './searchbar/searchbar';
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller {
|
||||
constructor($element, $scope, $compile, $timeout, $state, $transitions) {
|
||||
this.element = $element[0];
|
||||
this.$ = $scope;
|
||||
this.$compile = $compile;
|
||||
this.$timeout = $timeout;
|
||||
this.stringSearch = '';
|
||||
this.$state = $state;
|
||||
this.deregisterCallback = $transitions.onStart({},
|
||||
transition => this.changeState(transition));
|
||||
}
|
||||
|
||||
clearFilter() {
|
||||
this.index.filter = {
|
||||
page: 1,
|
||||
size: 20
|
||||
};
|
||||
}
|
||||
|
||||
setFilter(filterObject) {
|
||||
this.clearFilter();
|
||||
Object.assign(this.index.filter, filterObject);
|
||||
}
|
||||
|
||||
getFiltersFromString(stringSearch) {
|
||||
let result = {};
|
||||
if (stringSearch) {
|
||||
// find pattern key:value or key:(extra value) and returns array
|
||||
let findPattern = stringSearch.match(/((([\w_]+):([\w_]+))|([\w_]+):\(([\w_ ]+)\))/gi);
|
||||
let remnantString = (stringSearch.replace(/((([\w_]+):([\w_]+))|([\w_]+):\(([\w_ ]+)\))/gi, '')).trim();
|
||||
if (findPattern) {
|
||||
for (let i = 0; i < findPattern.length; i++) {
|
||||
let aux = findPattern[i].split(':');
|
||||
let property = aux[0];
|
||||
let value = aux[1].replace(/\(|\)/g, '');
|
||||
result[property] = value.trim();
|
||||
}
|
||||
}
|
||||
if (remnantString) {
|
||||
result.search = remnantString;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
createStringFromObject(filterObject) {
|
||||
let search = [];
|
||||
let keys = Object.keys(filterObject);
|
||||
if (keys.length) {
|
||||
keys.forEach(k => {
|
||||
let ignore = (this.ignoreKeys && this.ignoreKeys instanceof Array && this.ignoreKeys.indexOf(k) !== -1);
|
||||
if (!ignore) {
|
||||
let value = filterObject[k];
|
||||
|
||||
if (typeof value === 'string' && value.indexOf(' ') !== -1) {
|
||||
search.push(`${k}:(${value})`);
|
||||
} else if (typeof value !== 'object') {
|
||||
search.push(`${k}:${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (filterObject.search)
|
||||
search.unshift(filterObject.search);
|
||||
}
|
||||
return (search.length) ? search.join(' ') : '';
|
||||
}
|
||||
|
||||
changeState(transition) {
|
||||
return !(transition._targetState._identifier.name === this.$state.current.name);
|
||||
}
|
||||
|
||||
pushFiltersToState(filters) {
|
||||
let history = window.history || {pushState: () => {
|
||||
console.error('Error in history.pushState(): Browser incompatibility error');
|
||||
}};
|
||||
let aux = window.location.hash.split('?q=');
|
||||
if (Object.keys(filters).length)
|
||||
history.pushState({}, null, `${aux[0]}?q=${encodeURIComponent(JSON.stringify(filters))}`);
|
||||
else
|
||||
history.pushState({}, null, aux[0]);
|
||||
}
|
||||
|
||||
onpenFilters(event) {
|
||||
let filter = {};
|
||||
if (this.stringSearch) {
|
||||
filter = this.getFiltersFromString(this.stringSearch);
|
||||
}
|
||||
|
||||
this.$child = this.$compile(`<${this.popover}/>`)(this.$.$new());
|
||||
|
||||
var childCtrl = this.$child.isolateScope().$ctrl;
|
||||
childCtrl.filter = Object.assign({}, filter);
|
||||
childCtrl.onSubmit = filter => this.onChildSubmit(filter);
|
||||
if (this.data)
|
||||
childCtrl.data = Object.assign({}, this.data);
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
this.$.popover.parent = this.element;
|
||||
this.$.popover.child = this.$child[0];
|
||||
this.$.popover.show();
|
||||
}
|
||||
|
||||
onPopoverClose() {
|
||||
this.$child.scope().$destroy();
|
||||
this.$child.remove();
|
||||
this.$child = null;
|
||||
}
|
||||
|
||||
onChildSubmit(filter) {
|
||||
this.$.popover.hide();
|
||||
this.stringSearch = this.createStringFromObject(filter);
|
||||
this.clearFilter();
|
||||
this.$timeout(() => this.onSubmit());
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
let filter = {};
|
||||
if (this.stringSearch) {
|
||||
filter = this.getFiltersFromString(this.stringSearch);
|
||||
}
|
||||
this.setFilter(filter);
|
||||
|
||||
if (this.onSearch)
|
||||
this.onSearch();
|
||||
|
||||
this.pushFiltersToState(filter);
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.clearFilter();
|
||||
this.deregisterCallback();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.$state.params.q) {
|
||||
let filter = JSON.parse(decodeURIComponent(this.$state.params.q));
|
||||
this.stringSearch = this.createStringFromObject(filter);
|
||||
}
|
||||
this.$timeout(() => this.onSubmit());
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope', '$compile', '$timeout', '$state', '$transitions'];
|
||||
|
||||
ngModule.component('vnSearchbar', {
|
||||
template: require('./searchbar.html'),
|
||||
bindings: {
|
||||
index: '<',
|
||||
onSearch: '&',
|
||||
advanced: '=',
|
||||
popover: '@',
|
||||
ignoreKeys: '<?',
|
||||
data: '<?'
|
||||
},
|
||||
controller: Controller
|
||||
});
|
|
@ -64,7 +64,6 @@ html [vn-auto], vn-auto, .vn-auto {
|
|||
flex-basis: auto;
|
||||
}
|
||||
html [vn-none], vn-none, .vn-none {
|
||||
flex: 1;
|
||||
flex: none;
|
||||
}
|
||||
html [vn-one], vn-one, .vn-one {
|
||||
|
|
|
@ -1,55 +1,54 @@
|
|||
<mg-ajax path="/ticket/api/Tickets/filter" options="vnIndexNonAuto"></mg-ajax>
|
||||
<div margin-large>
|
||||
<div>
|
||||
<vn-card pad-medium>
|
||||
<vn-title>TICKETS</vn-title>
|
||||
<vn-horizontal class="vn-list">
|
||||
<vn-searchbar vn-one
|
||||
index="index"
|
||||
on-search="$ctrl.search(index)"
|
||||
ignore-keys = "['page', 'size', 'search']">
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/ticket/api/Tickets"
|
||||
filter="::$ctrl.filter"
|
||||
limit="10"
|
||||
data="tickets"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
<div margin-medium>
|
||||
<div class="vn-list">
|
||||
<vn-card pad-medium-h>
|
||||
<vn-searchbar
|
||||
panel="vn-ticket-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
</vn-searchbar>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
</vn-card>
|
||||
</div>
|
||||
<vn-card margin-medium-v pad-medium>
|
||||
<table class="vn-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th number translate>ID Ticket</th>
|
||||
<th translate>Comercial</th>
|
||||
<th translate number>Id</th>
|
||||
<th translate>Salesperson</th>
|
||||
<th translate>Date</th>
|
||||
<th translate>Hora</th>
|
||||
<th translate>Hour</th>
|
||||
<th translate>Alias</th>
|
||||
<th translate>Provincia</th>
|
||||
<th translate>Estado</th>
|
||||
<th translate>Agencia</th>
|
||||
<th translate>Almacen</th>
|
||||
<th number translate>Factura</th>
|
||||
<th number translate>Ruta</th>
|
||||
<th translate>Province</th>
|
||||
<th translate>State</th>
|
||||
<th translate>Agency</th>
|
||||
<th translate>Warehouse</th>
|
||||
<th translate number>Invoice</th>
|
||||
<th translate number>Route</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="ticket in index.model.instances track by ticket.id"
|
||||
<tr ng-repeat="ticket in tickets"
|
||||
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable"
|
||||
ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
|
||||
<td>
|
||||
<!-- <i pointer
|
||||
class="material-icons"
|
||||
vn-tooltip="delete expedition"
|
||||
ng-click="$ctrl.deleteExpedition(expedition)">warning</i> -->
|
||||
</td>
|
||||
<th number>{{::ticket.id}}</th>
|
||||
<td translate>{{::ticket.client.salesPerson.name | dashIfEmpty}}</td>
|
||||
<td translate>{{::ticket.shipped | date:'dd/MM/yyyy'}}</td>
|
||||
<td translate>{{::ticket.shipped | date:'HH:MM'}}</td>
|
||||
<td translate>{{::ticket.nickname}}</td>
|
||||
<td translate>{{::ticket.address.province.name}}</td>
|
||||
<td translate>{{::ticket.tracking.state.name}}</td>
|
||||
<td translate>{{::ticket.agencyMode.name}}</td>
|
||||
<td translate>{{::ticket.warehouse.name}}</td>
|
||||
<td number translate>{{::ticket.refFk | dashIfEmpty}}</td>
|
||||
<td number translate>{{::ticket.routeFk | dashIfEmpty}}</td>
|
||||
<td >{{::ticket.client.salesPerson.name | dashIfEmpty}}</td>
|
||||
<td >{{::ticket.shipped | date:'dd/MM/yyyy'}}</td>
|
||||
<td >{{::ticket.shipped | date:'HH:MM'}}</td>
|
||||
<td >{{::ticket.nickname}}</td>
|
||||
<td >{{::ticket.address.province.name}}</td>
|
||||
<td >{{::ticket.tracking.state.name}}</td>
|
||||
<td >{{::ticket.agencyMode.name}}</td>
|
||||
<td >{{::ticket.warehouse.name}}</td>
|
||||
<td number >{{::ticket.refFk | dashIfEmpty}}</td>
|
||||
<td number >{{::ticket.routeFk | dashIfEmpty}}</td>
|
||||
<td>
|
||||
<vn-icon-button
|
||||
ng-click="$ctrl.preview($event, ticket)"
|
||||
|
@ -60,11 +59,11 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-paging vn-one index="index" total="index.model.count"></vn-paging>
|
||||
<!-- <vn-auto-paging vn-one index="index" total="index.model.count" items="$ctrl.tickets"></vn-auto-paging> -->
|
||||
</div>
|
||||
<vn-pagination
|
||||
model="model"
|
||||
scroll-selector="ui-view">
|
||||
</vn-pagination>
|
||||
</div>
|
||||
<a ui-sref="ticket.create" vn-bind="+" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
|
|
|
@ -1,11 +1,82 @@
|
|||
import ngModule from '../module';
|
||||
import './ticket-item';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller {
|
||||
constructor($scope) {
|
||||
this.$scope = $scope;
|
||||
this.$ = $scope;
|
||||
this.ticketSelected = null;
|
||||
|
||||
this.filter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'address',
|
||||
scope: {
|
||||
fields: ['provinceFk'],
|
||||
include: {
|
||||
relation: 'province',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'agencyMode',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'tracking',
|
||||
scope: {
|
||||
fields: ['stateFk'],
|
||||
include: {
|
||||
relation: 'state',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['salesPersonFk'],
|
||||
include: {
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
order: 'shipped DESC'
|
||||
};
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return {
|
||||
or: [
|
||||
{id: value},
|
||||
{nickname: {regexp: value}}
|
||||
]
|
||||
};
|
||||
case 'from':
|
||||
return {shipped: {gte: value}};
|
||||
case 'to':
|
||||
return {shipped: {lte: value}};
|
||||
case 'nickname':
|
||||
return {[param]: {regexp: value}};
|
||||
case 'id':
|
||||
case 'clientFk':
|
||||
case 'agencyModeFk':
|
||||
case 'warehouseFk':
|
||||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
compareDate(date) {
|
||||
|
@ -26,17 +97,9 @@ export default class Controller {
|
|||
preview(event, ticket) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.$scope.dialogSummaryTicket.show();
|
||||
this.$.dialogSummaryTicket.show();
|
||||
this.ticketSelected = ticket;
|
||||
}
|
||||
|
||||
search(index) {
|
||||
index.accept();
|
||||
/* this.tickets = [];
|
||||
index.accept().then(res => {
|
||||
this.tickets = res.instances;
|
||||
}); */
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope'];
|
||||
|
|
|
@ -34,14 +34,14 @@ describe('ticket', () => {
|
|||
it('should call preventDefault and stopImmediatePropagation from event and show', () => {
|
||||
let event = jasmine.createSpyObj('event', ['preventDefault', 'stopImmediatePropagation']);
|
||||
|
||||
controller.$scope = {dialogSummaryTicket: {show: () => {}}};
|
||||
spyOn(controller.$scope.dialogSummaryTicket, 'show');
|
||||
controller.$ = {dialogSummaryTicket: {show: () => {}}};
|
||||
spyOn(controller.$.dialogSummaryTicket, 'show');
|
||||
let ticket = {};
|
||||
controller.preview(event, ticket);
|
||||
|
||||
expect(event.preventDefault).toHaveBeenCalledWith();
|
||||
expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
|
||||
expect(controller.$scope.dialogSummaryTicket.show).toHaveBeenCalledWith();
|
||||
expect(controller.$.dialogSummaryTicket.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
vn-ticket-item {
|
||||
display: block;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<a
|
||||
ui-sref="ticket.card.summary({ id: {{::$ctrl.ticket.id}} })"
|
||||
translate-attr="{title: 'View ticket'}"
|
||||
class="vn-list-item">
|
||||
<vn-horizontal ng-click="$ctrl.onClick($event)">
|
||||
<vn-one>
|
||||
<h6>{{::$ctrl.ticket.nickname}}</h6>
|
||||
<vn-label-value label="Id"
|
||||
value="{{::$ctrl.ticket.id}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
<vn-horizontal class="buttons">
|
||||
<vn-icon
|
||||
ng-click="$ctrl.preview($event)"
|
||||
vn-tooltip="Preview"
|
||||
icon="desktop_windows">
|
||||
</vn-icon>
|
||||
</vn-horizontal>
|
||||
</vn-horizontal>
|
||||
</a>
|
|
@ -1,24 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
onClick(event) {
|
||||
if (event.defaultPrevented)
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
preview(event) {
|
||||
event.preventDefault();
|
||||
this.index.openSummary(this.ticket);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnTicketItem', {
|
||||
controller: Controller,
|
||||
template: require('./ticket-item.html'),
|
||||
bindings: {
|
||||
ticket: '<'
|
||||
},
|
||||
require: {
|
||||
index: '^vnTicketIndex'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
<div pad-large style="min-width: 30em">
|
||||
<form ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Nickname"
|
||||
model="filter.nickname"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Ticket id"
|
||||
model="filter.id">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Client id"
|
||||
model="filter.clientFk">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="From"
|
||||
model="filter.from">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="To"
|
||||
model="filter.to">
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Agency"
|
||||
field="filter.agencyModeFk"
|
||||
url="/api/AgencyModes"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
<tpl-item>{{name}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Warehouse"
|
||||
field="filter.warehouseFk"
|
||||
url="/api/Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
import ngModule from '../module';
|
||||
import SearchPanel from 'core/src/components/searchbar/search-panel';
|
||||
|
||||
ngModule.component('vnTicketSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: SearchPanel
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
Ticket id: Id ticket
|
||||
Client id: Id cliente
|
||||
Nickname: Alias
|
||||
From: Desde
|
||||
To: Hasta
|
||||
Agency: Agencia
|
||||
Warehouse: Almacén
|
|
@ -1,5 +1,6 @@
|
|||
export * from './module';
|
||||
|
||||
import './search-panel';
|
||||
import './index';
|
||||
import './create';
|
||||
import './card';
|
||||
|
|
|
@ -192,7 +192,7 @@ export default {
|
|||
itemTags: {
|
||||
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',
|
||||
tagsButton: `vn-menu-item a[ui-sref="item.card.tags"]`,
|
||||
firstRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(2) > vn-icon[icon="remove_circle_outline"]`,
|
||||
firstRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(2) vn-icon-button[icon="remove_circle_outline"]`,
|
||||
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete[field="itemTag.tagFk"] input`,
|
||||
firstTagDisabled: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete > div > div > input`,
|
||||
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
|
@ -218,7 +218,7 @@ export default {
|
|||
fifthTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(5)`,
|
||||
fifthValueInput: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Value"] > div > input`,
|
||||
fifthRelevancyInput: `vn-horizontal:nth-child(6) > vn-textfield[label="Relevancy"] > div > input`,
|
||||
addItemTagButton: `vn-icon[icon="add_circle"]`,
|
||||
addItemTagButton: `vn-icon-button[icon="add_circle"]`,
|
||||
submitItemTagsButton: `${components.vnSubmit}`
|
||||
},
|
||||
itemTax: {
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('Ticket', () => {
|
|||
it('should search for the ticket with id 1', () => {
|
||||
return nightmare
|
||||
.wait(selectors.ticketsIndex.searchTicketInput)
|
||||
.type(selectors.ticketsIndex.searchTicketInput, '1')
|
||||
.type(selectors.ticketsIndex.searchTicketInput, 'id:1')
|
||||
.click(selectors.ticketsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
.countSearchResults(selectors.ticketsIndex.searchResult)
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('Ticket', () => {
|
|||
it('should search for the ticket with id 1', () => {
|
||||
return nightmare
|
||||
.wait(selectors.ticketsIndex.searchTicketInput)
|
||||
.type(selectors.ticketsIndex.searchTicketInput, '1')
|
||||
.type(selectors.ticketsIndex.searchTicketInput, 'id:1')
|
||||
.click(selectors.ticketsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
.countSearchResults(selectors.ticketsIndex.searchResult)
|
||||
|
|
|
@ -25,7 +25,7 @@ describe('Ticket', () => {
|
|||
it('should search for the ticket 1', () => {
|
||||
return nightmare
|
||||
.wait(selectors.ticketsIndex.searchResult)
|
||||
.type(selectors.ticketsIndex.searchTicketInput, 1)
|
||||
.type(selectors.ticketsIndex.searchTicketInput, 'id:1')
|
||||
.click(selectors.ticketsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
.countSearchResults(selectors.ticketsIndex.searchResult)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
// it('should search for the ticket 1', () => {
|
||||
// return nightmare
|
||||
// .wait(selectors.ticketsIndex.searchResult)
|
||||
// .type(selectors.ticketsIndex.searchTicketInput, 1)
|
||||
// .type(selectors.ticketsIndex.searchTicketInput, 'id:1')
|
||||
// .click(selectors.ticketsIndex.searchButton)
|
||||
// .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
// .countSearchResults(selectors.ticketsIndex.searchResult)
|
||||
|
|
|
@ -25,7 +25,7 @@ describe('Ticket', () => {
|
|||
it('should search for the ticket 1', () => {
|
||||
return nightmare
|
||||
.wait(selectors.ticketsIndex.searchResult)
|
||||
.type(selectors.ticketsIndex.searchTicketInput, 1)
|
||||
.type(selectors.ticketsIndex.searchTicketInput, 'id:1')
|
||||
.click(selectors.ticketsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
.countSearchResults(selectors.ticketsIndex.searchResult)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"angular-translate-loader-partial": "^2.18.1",
|
||||
"flatpickr": "^4.4.6",
|
||||
"fs-extra": "^5.0.0",
|
||||
"js-yaml": "^3.10.0",
|
||||
"material-design-lite": "^1.3.0",
|
||||
"mg-crud": "^1.1.2",
|
||||
"npm": "^5.8.0",
|
||||
|
@ -55,7 +56,6 @@
|
|||
"html-loader": "^0.4.4",
|
||||
"jasmine": "^2.9.0",
|
||||
"jasmine-spec-reporter": "^4.2.1",
|
||||
"js-yaml": "^3.10.0",
|
||||
"karma": "^1.7.1",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-firefox-launcher": "^1.1.0",
|
||||
|
|
|
@ -40,6 +40,7 @@ module.exports = function(Self) {
|
|||
street: data.street,
|
||||
city: data.city,
|
||||
provinceFk: data.provinceFk,
|
||||
countryFk: data.countryFk,
|
||||
isEqualizated: data.isEqualizated
|
||||
};
|
||||
newClient = await Self.create(client);
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
module.exports = function(Client) {
|
||||
Client.installMethod('filter', filterClients);
|
||||
|
||||
function filterClients(params) {
|
||||
let filters = {
|
||||
where: {},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size
|
||||
};
|
||||
|
||||
delete params.page;
|
||||
delete params.size;
|
||||
|
||||
if (params.search) {
|
||||
filters.where.and = [
|
||||
{
|
||||
or: [
|
||||
{id: params.search},
|
||||
{name: {regexp: params.search}}
|
||||
]
|
||||
}
|
||||
];
|
||||
delete params.search;
|
||||
}
|
||||
|
||||
if (params.phone) {
|
||||
let phones = [
|
||||
{phone: params.phone},
|
||||
{mobile: params.phone}
|
||||
];
|
||||
if (filters.where.and) {
|
||||
filters.where.and.push(
|
||||
{
|
||||
or: phones
|
||||
}
|
||||
);
|
||||
} else {
|
||||
filters.where.or = phones;
|
||||
}
|
||||
delete params.phone;
|
||||
}
|
||||
|
||||
let properties = Object.keys(params);
|
||||
if (properties.length) {
|
||||
properties.forEach(
|
||||
property => {
|
||||
let propertyToBeEqual = (property === 'postcode' || property === 'fi' || property === 'id');
|
||||
if (filters.where.and) {
|
||||
let filter = {};
|
||||
filter[property] = propertyToBeEqual ? params[property] : {regexp: params[property]};
|
||||
filters.where.and.push(filter);
|
||||
} else {
|
||||
filters.where[property] = propertyToBeEqual ? params[property] : {regexp: params[property]};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
};
|
|
@ -1,62 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.installMethod('filter', filterParams);
|
||||
|
||||
function filterParams(params) {
|
||||
let filter = {
|
||||
where: {},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: params.order || 'name ASC', // name, relevancy DESC
|
||||
include: [
|
||||
{relation: 'itemType',
|
||||
scope: {
|
||||
fields: ['name', 'workerFk'],
|
||||
include: {
|
||||
relation: 'worker',
|
||||
fields: ['firstName', 'name']
|
||||
}
|
||||
}
|
||||
},
|
||||
{relation: 'origin'},
|
||||
{relation: 'ink'},
|
||||
{relation: 'producer'},
|
||||
{relation: 'intrastat'},
|
||||
{relation: 'expence'}
|
||||
]
|
||||
};
|
||||
|
||||
delete params.page;
|
||||
delete params.size;
|
||||
delete params.order;
|
||||
|
||||
if (params.search) {
|
||||
filter.where.and = [
|
||||
{
|
||||
or: [
|
||||
{id: params.search},
|
||||
{name: {regexp: params.search}}
|
||||
]
|
||||
}
|
||||
];
|
||||
delete params.search;
|
||||
}
|
||||
|
||||
if (params.itemSize) {
|
||||
params.size = params.itemSize;
|
||||
delete params.itemSize;
|
||||
}
|
||||
|
||||
Object.keys(params).forEach(
|
||||
key => {
|
||||
if (filter.where.and) {
|
||||
let filter = {};
|
||||
filter[key] = (key === 'description' || key === 'name') ? {regexp: params[key]} : params[key];
|
||||
filter.where.and.push(filter);
|
||||
} else {
|
||||
filter.where[key] = (key === 'description' || key === 'name') ? {regexp: params[key]} : params[key];
|
||||
}
|
||||
}
|
||||
);
|
||||
return filter;
|
||||
}
|
||||
};
|
|
@ -1,87 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.installMethod('filter', filterParams);
|
||||
|
||||
function filterParams(params) {
|
||||
let filters = {
|
||||
where: {},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: params.order || 'created DESC',
|
||||
include: [
|
||||
{
|
||||
relation: 'address',
|
||||
scope: {
|
||||
fields: ['provinceFk'],
|
||||
include: {
|
||||
relation: 'province',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'agencyMode',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'tracking',
|
||||
scope: {
|
||||
fields: ['stateFk'],
|
||||
include: {
|
||||
relation: 'state',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['salesPersonFk'],
|
||||
include: {
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
delete params.page;
|
||||
delete params.size;
|
||||
delete params.order;
|
||||
|
||||
if (params.search) {
|
||||
filters.where.and = [
|
||||
{
|
||||
or: [
|
||||
{id: params.search},
|
||||
{name: {regexp: params.search}}
|
||||
]
|
||||
}
|
||||
];
|
||||
delete params.search;
|
||||
}
|
||||
|
||||
Object.keys(params).forEach(
|
||||
key => {
|
||||
if (filters.where.and) {
|
||||
let filter = {};
|
||||
filter[key] = (key === 'nickname') ? {regexp: params[key]} : params[key];
|
||||
filters.where.and.push(filter);
|
||||
} else {
|
||||
filters.where[key] = (key === 'nickname') ? {regexp: params[key]} : params[key];
|
||||
}
|
||||
}
|
||||
);
|
||||
return filters;
|
||||
}
|
||||
};
|
|
@ -10,7 +10,6 @@ module.exports = Self => {
|
|||
require('../methods/client/card')(Self);
|
||||
require('../methods/client/createWithUser')(Self);
|
||||
require('../methods/client/listWorkers')(Self);
|
||||
require('../methods/client/filter')(Self);
|
||||
require('../methods/client/hasCustomerRole')(Self);
|
||||
require('../methods/client/isValidClient')(Self);
|
||||
require('../methods/client/activeSalesPerson')(Self);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
let UserError = require('../helpers').UserError;
|
||||
|
||||
module.exports = Self => {
|
||||
require('../methods/item/filter')(Self);
|
||||
require('../methods/item/clone')(Self);
|
||||
require('../methods/item/updateTaxes')(Self);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/ticket/changeTime')(Self);
|
||||
require('../methods/ticket/changeWorker')(Self);
|
||||
require('../methods/ticket/filter')(Self);
|
||||
require('../methods/ticket/getVolume')(Self);
|
||||
require('../methods/ticket/getTotalVolume')(Self);
|
||||
require('../methods/ticket/summary')(Self);
|
||||
|
|
Loading…
Reference in New Issue