Merge
|
@ -5,7 +5,7 @@
|
||||||
"name": "Iniciar",
|
"name": "Iniciar",
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/app.js",
|
"program": "${workspaceRoot}/services/client/server/server.js",
|
||||||
"stopOnEntry": false,
|
"stopOnEntry": false,
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
|
|
|
@ -7,14 +7,16 @@ def branchName = "${env.BRANCH_NAME}";
|
||||||
def branchNameTest = "preprod";
|
def branchNameTest = "preprod";
|
||||||
def branchNameProd = "master";
|
def branchNameProd = "master";
|
||||||
def prefixDocker = "test";
|
def prefixDocker = "test";
|
||||||
def dockerNginxName = ["nginx", "-p 80:80 --privileged --link test-auth:auth --link test-salix:salix --link test-client:client"]
|
def dockerNginxName = ["nginx", "-p 80:80 --privileged --link test-auth:auth --link test-salix:salix --link test-client:client --link test-mailer:mailer --link test-production:production"]
|
||||||
def dockerAuthName = ["auth", "-p 3000:3000"]
|
def dockerAuthName = ["auth", "-p 3000:3000"]
|
||||||
def dockerSalixName = ["salix", "-p 3001:3001"]
|
def dockerSalixName = ["salix", "-p 3001:3001"]
|
||||||
def dockerClientName = ["client", "-p 3002:3002"]
|
def dockerClientName = ["client", "-p 3002:3002"]
|
||||||
|
def dockerMailerName = ["mailer", "-p 3003:3003"]
|
||||||
|
def dockerProductionName = ["production", "-p 3004:3004"]
|
||||||
|
|
||||||
def buildNumber = "${env.BUILD_NUMBER}";
|
def buildNumber = "${env.BUILD_NUMBER}";
|
||||||
|
|
||||||
def dockers = [dockerAuthName, dockerSalixName, dockerClientName, dockerNginxName]
|
def dockers = [dockerAuthName, dockerSalixName, dockerClientName, dockerMailerName, dockerNginxName, dockerProductionName]
|
||||||
|
|
||||||
node {
|
node {
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"module": "client",
|
"module": "client",
|
||||||
"name": "Clients",
|
"name": "Clients",
|
||||||
"icon": "person",
|
"icon": "person",
|
||||||
|
"validations" : true,
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"url": "/clients",
|
"url": "/clients",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
data="$ctrl.address"
|
data="$ctrl.address"
|
||||||
form="form">
|
form="form">
|
||||||
</vn-watcher>
|
</vn-watcher>
|
||||||
|
<mg-ajax path="/client/api/Addresses/{{edit.params.addressId}}" actions="$ctrl.address=edit.model" options="mgEdit"></mg-ajax>
|
||||||
<form name="form" ng-submit="watcher.submitBack()" pad-medium>
|
<form name="form" ng-submit="watcher.submitBack()" pad-medium>
|
||||||
<vn-card>
|
<vn-card>
|
||||||
<vn-vertical pad-large>
|
<vn-vertical pad-large>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
form="form"
|
form="form"
|
||||||
save="patch">
|
save="patch">
|
||||||
</vn-watcher>
|
</vn-watcher>
|
||||||
<form name="form" ng-submit="$ctrl.checkChanges() && watcher.submit()" pad-medium>
|
<form name="form" ng-submit="$ctrl.submit()" pad-medium>
|
||||||
<vn-card margin-small-bottom>
|
<vn-card margin-small-bottom>
|
||||||
<vn-vertical pad-large>
|
<vn-vertical pad-large>
|
||||||
<vn-title>Información de facturación</vn-title>
|
<vn-title>Información de facturación</vn-title>
|
||||||
|
@ -24,7 +24,10 @@
|
||||||
<vn-textfield vn-one label="Descuento" field="$ctrl.client.discount"></vn-textfield>
|
<vn-textfield vn-one label="Descuento" field="$ctrl.client.discount"></vn-textfield>
|
||||||
<vn-textfield vn-one label="Crédito" field="$ctrl.client.credit"></vn-textfield>
|
<vn-textfield vn-one label="Crédito" field="$ctrl.client.credit"></vn-textfield>
|
||||||
<vn-textfield vn-one label="Crédito asegurado" field="$ctrl.client.creditInsurance"></vn-textfield>
|
<vn-textfield vn-one label="Crédito asegurado" field="$ctrl.client.creditInsurance"></vn-textfield>
|
||||||
<vn-check vn-three label="Recargo de equivalencia" field="$ctrl.client.equalizationTax"></vn-check>
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-check vn-one label="Recargo de equivalencia" field="$ctrl.client.equalizationTax"></vn-check>
|
||||||
|
<vn-check vn-one label="Vies" field="$ctrl.client.vies"></vn-check>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
|
|
|
@ -3,11 +3,11 @@ import ngModule from '../module';
|
||||||
export default class Controller {
|
export default class Controller {
|
||||||
constructor($scope, $http, $timeout, vnApp, $translate) {
|
constructor($scope, $http, $timeout, vnApp, $translate) {
|
||||||
this.$ = $scope;
|
this.$ = $scope;
|
||||||
this.http = $http;
|
this.$http = $http;
|
||||||
this.timeout = $timeout;
|
this.timeout = $timeout;
|
||||||
this.vnApp = vnApp;
|
this.vnApp = vnApp;
|
||||||
this.translate = $translate;
|
this.translate = $translate;
|
||||||
this.payId = null;
|
this.payMethodFk = null;
|
||||||
this.dueDay = null;
|
this.dueDay = null;
|
||||||
this.copyData();
|
this.copyData();
|
||||||
}
|
}
|
||||||
|
@ -16,32 +16,27 @@ export default class Controller {
|
||||||
}
|
}
|
||||||
copyData() {
|
copyData() {
|
||||||
if (this.client) {
|
if (this.client) {
|
||||||
this.payId = this.client.payMethodFk || null;
|
this.payMethodFk = this.client.payMethodFk || null;
|
||||||
this.dueDay = this.client.dueDay ? this.client.dueDay : null;
|
this.dueDay = this.client.dueDay ? this.client.dueDay : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkChanges() {
|
submit() {
|
||||||
let payId = this.client.payMethodFk || null;
|
this.$.watcher.submit().then(
|
||||||
|
() => this.checkPaymentChanges());
|
||||||
|
}
|
||||||
|
checkPaymentChanges() {
|
||||||
|
let payMethodFk = this.client.payMethodFk || null;
|
||||||
let dueDay = this.client.dueDay || null;
|
let dueDay = this.client.dueDay || null;
|
||||||
|
|
||||||
if (this.payId !== payId || this.dueDay !== dueDay) {
|
if (this.payMethodFk !== payMethodFk || this.dueDay !== dueDay)
|
||||||
this.$.sendMail.show();
|
this.$.sendMail.show();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
returnDialog(response) {
|
returnDialog(response) {
|
||||||
if (response === 'ACCEPT') {
|
if (response === 'ACCEPT') {
|
||||||
this.sendMail().then(
|
this.$http.post(`/mailer/manuscript/${this.client.id}/payment-update`).then(
|
||||||
() => this.vnApp.showMessage(this.translate.instant('Notification sent!')),
|
() => this.vnApp.showMessage(this.translate.instant('Notification sent!'))
|
||||||
() => this.vnApp.showMessage(this.translate.instant('Notification error'))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.timeout(() => this.$.watcher.submit());
|
|
||||||
}
|
|
||||||
sendMail() {
|
|
||||||
return this.http.post(`/mailer/manuscript/paymentUpdate`, {user: this.client.id});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Controller.$inject = ['$scope', '$http', '$timeout', 'vnApp', '$translate'];
|
Controller.$inject = ['$scope', '$http', '$timeout', 'vnApp', '$translate'];
|
||||||
|
|
|
@ -3,6 +3,9 @@ import './style.css';
|
||||||
import './item-client';
|
import './item-client';
|
||||||
|
|
||||||
export default class Controller {
|
export default class Controller {
|
||||||
|
constructor() {
|
||||||
|
this.model = {};
|
||||||
|
}
|
||||||
search(index) {
|
search(index) {
|
||||||
index.filter.search = this.model.search;
|
index.filter.search = this.model.search;
|
||||||
index.accept();
|
index.accept();
|
||||||
|
|
|
@ -6,5 +6,15 @@
|
||||||
ng-keyup="$ctrl.onKeyup($event)"
|
ng-keyup="$ctrl.onKeyup($event)"
|
||||||
ng-focus="$ctrl.onFocus($event)"
|
ng-focus="$ctrl.onFocus($event)"
|
||||||
ng-blur="$ctrl.onBlur($event)"/>
|
ng-blur="$ctrl.onBlur($event)"/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="mdl-chip__action ng-hide"
|
||||||
|
tabindex="-1"
|
||||||
|
translate-attr="{title: 'Clear'}"
|
||||||
|
ng-show="$ctrl.value"
|
||||||
|
ng-click="$ctrl.onClear()"
|
||||||
|
>
|
||||||
|
<i class="material-icons">clear</i>
|
||||||
|
</button>
|
||||||
<label class="mdl-textfield__label">{{$ctrl.label | translate}}</label>
|
<label class="mdl-textfield__label">{{$ctrl.label | translate}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,12 +6,14 @@ import './style.scss';
|
||||||
* Combobox like component with search and partial data loading features.
|
* Combobox like component with search and partial data loading features.
|
||||||
*/
|
*/
|
||||||
export default class Autocomplete extends Component {
|
export default class Autocomplete extends Component {
|
||||||
constructor($element, $scope, $http, vnPopover, $transclude) {
|
constructor($element, $scope, $http, vnPopover, $transclude, $timeout) {
|
||||||
super($element);
|
super($element);
|
||||||
this.input = $element[0].querySelector('input');
|
this.input = $element[0].querySelector('input');
|
||||||
this.item = null;
|
this.item = null;
|
||||||
this.data = null;
|
this.$timeout = $timeout;
|
||||||
|
// this.data = null;
|
||||||
this.popover = null;
|
this.popover = null;
|
||||||
|
this.popoverId = null;
|
||||||
this.displayData = null;
|
this.displayData = null;
|
||||||
this.timeoutId = null;
|
this.timeoutId = null;
|
||||||
this.lastSearch = null;
|
this.lastSearch = null;
|
||||||
|
@ -81,10 +83,12 @@ export default class Autocomplete extends Component {
|
||||||
&& !this.moreData
|
&& !this.moreData
|
||||||
&& textFilter.substr(0, lastRequest.length) === lastRequest;
|
&& textFilter.substr(0, lastRequest.length) === lastRequest;
|
||||||
|
|
||||||
if (requestWillSame)
|
if (requestWillSame || !this.url)
|
||||||
this.localFilter(textFilter);
|
this.localFilter(textFilter);
|
||||||
else
|
else if (this.url)
|
||||||
this.requestData(textFilter, false);
|
this.requestData(textFilter, false);
|
||||||
|
else
|
||||||
|
this.setDisplayData(this.data);
|
||||||
}
|
}
|
||||||
getRequestFields() {
|
getRequestFields() {
|
||||||
let fields = {};
|
let fields = {};
|
||||||
|
@ -203,14 +207,14 @@ export default class Autocomplete extends Component {
|
||||||
e => this.onPopoverMousedown(e));
|
e => this.onPopoverMousedown(e));
|
||||||
popover.className = 'vn-autocomplete';
|
popover.className = 'vn-autocomplete';
|
||||||
popover.appendChild(fragment);
|
popover.appendChild(fragment);
|
||||||
this.vnPopover.show(popover, this.input);
|
this.popoverId = this.vnPopover.show(popover, this.input);
|
||||||
this.popover = popover;
|
this.popover = popover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hidePopover() {
|
hidePopover() {
|
||||||
if (!this.popover) return;
|
if (!this.popover) return;
|
||||||
this.activeOption = -1;
|
this.activeOption = -1;
|
||||||
this.vnPopover.hide();
|
this.vnPopover.hide(this.popoverId);
|
||||||
this.destroyScopes();
|
this.destroyScopes();
|
||||||
this.popover = null;
|
this.popover = null;
|
||||||
}
|
}
|
||||||
|
@ -242,6 +246,14 @@ export default class Autocomplete extends Component {
|
||||||
// Prevents input from loosing focus
|
// Prevents input from loosing focus
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
onClear() {
|
||||||
|
this.setValue(null);
|
||||||
|
this.$timeout(
|
||||||
|
() => {
|
||||||
|
this.mdlUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
onClick(event) {
|
onClick(event) {
|
||||||
if (!this.popover)
|
if (!this.popover)
|
||||||
this.showPopover();
|
this.showPopover();
|
||||||
|
@ -387,6 +399,9 @@ export default class Autocomplete extends Component {
|
||||||
|
|
||||||
if (!this.locked)
|
if (!this.locked)
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|
||||||
|
if (this.onChange)
|
||||||
|
this.onChange({item: item});
|
||||||
}
|
}
|
||||||
showItem(item) {
|
showItem(item) {
|
||||||
this.input.value = item ? item[this.showField] : '';
|
this.input.value = item ? item[this.showField] : '';
|
||||||
|
@ -397,16 +412,18 @@ export default class Autocomplete extends Component {
|
||||||
this.destroyScopes();
|
this.destroyScopes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Autocomplete.$inject = ['$element', '$scope', '$http', 'vnPopover', '$transclude'];
|
Autocomplete.$inject = ['$element', '$scope', '$http', 'vnPopover', '$transclude', '$timeout'];
|
||||||
|
|
||||||
module.component('vnAutocomplete', {
|
module.component('vnAutocomplete', {
|
||||||
template: require('./autocomplete.html'),
|
template: require('./autocomplete.html'),
|
||||||
bindings: {
|
bindings: {
|
||||||
url: '@',
|
url: '@?',
|
||||||
showField: '@?',
|
showField: '@?',
|
||||||
valueField: '@?',
|
valueField: '@?',
|
||||||
selectFields: '@?',
|
selectFields: '@?',
|
||||||
initialData: '<?',
|
initialData: '<?',
|
||||||
|
onChange: '&?',
|
||||||
|
data: '<?',
|
||||||
itemAs: '@?',
|
itemAs: '@?',
|
||||||
field: '=',
|
field: '=',
|
||||||
label: '@'
|
label: '@'
|
||||||
|
|
|
@ -22,4 +22,16 @@ ul.vn-autocomplete {
|
||||||
padding: .4em .8em;
|
padding: .4em .8em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
vn-autocomplete {
|
||||||
|
.mdl-chip__action {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: -6px;
|
||||||
|
margin: 22px 0px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="{{$ctrl.className}}" ng-mouseover="$ctrl.mouseIsOver = true" ng-mouseleave="$ctrl.mouseIsOver = false">
|
||||||
|
<vn-horizontal ng-if="$ctrl.text" class="orderly" ng-click="$ctrl.onClick()">
|
||||||
|
<vn-none class="title" translate>
|
||||||
|
{{::$ctrl.text}}
|
||||||
|
</vn-none>
|
||||||
|
<vn-none>
|
||||||
|
<vn-icon icon="keyboard_arrow_down" ng-if="$ctrl.showArrow('DESC')"></vn-icon>
|
||||||
|
<vn-icon icon="keyboard_arrow_up" ng-if="$ctrl.showArrow('ASC')"></vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
</vn-horizontal>
|
||||||
|
<ng-transclude ng-if="!$ctrl.text"></ng-transclude>
|
||||||
|
</div>
|
|
@ -0,0 +1,39 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
|
||||||
|
export default class ColumHeader {
|
||||||
|
constructor() {
|
||||||
|
this.order = undefined;
|
||||||
|
this.mouseIsOver = false;
|
||||||
|
}
|
||||||
|
onClick() {
|
||||||
|
if (this.order === 'ASC') {
|
||||||
|
this.order = 'DESC';
|
||||||
|
} else {
|
||||||
|
this.order = 'ASC';
|
||||||
|
}
|
||||||
|
this.gridHeader.selectColum(this);
|
||||||
|
}
|
||||||
|
showArrow(type) {
|
||||||
|
let showArrow = (this.gridHeader && this.gridHeader.currentColumn && this.gridHeader.currentColumn.field === this.field && this.order === type);
|
||||||
|
let showOther = (this.gridHeader && this.gridHeader.currentColumn && this.gridHeader.currentColumn.field === this.field && this.order !== type);
|
||||||
|
if (type === 'DESC' && this.mouseIsOver && !showOther) {
|
||||||
|
showArrow = true;
|
||||||
|
}
|
||||||
|
return showArrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColumHeader.$inject = [];
|
||||||
|
|
||||||
|
module.component('vnColumHeader', {
|
||||||
|
template: require('./colum-header.html'),
|
||||||
|
bindings: {
|
||||||
|
field: '@?',
|
||||||
|
text: '@?',
|
||||||
|
className: '@?'
|
||||||
|
},
|
||||||
|
require: {
|
||||||
|
gridHeader: '^^vnGridHeader'
|
||||||
|
},
|
||||||
|
controller: ColumHeader,
|
||||||
|
transclude: true
|
||||||
|
});
|
|
@ -14,6 +14,12 @@ import './title/title';
|
||||||
import './subtitle/subtitle';
|
import './subtitle/subtitle';
|
||||||
import './spinner/spinner';
|
import './spinner/spinner';
|
||||||
import './snackbar/snackbar';
|
import './snackbar/snackbar';
|
||||||
|
import './tooltip/tooltip';
|
||||||
|
import './icon-menu/icon-menu';
|
||||||
|
import './drop-down/drop-down';
|
||||||
|
import './colum-header/colum-header';
|
||||||
|
import './grid-header/grid-header';
|
||||||
|
import './multi-check/multi-check';
|
||||||
|
|
||||||
export {NAME as BUTTON, directive as ButtonDirective} from './button/button';
|
export {NAME as BUTTON, directive as ButtonDirective} from './button/button';
|
||||||
export {NAME as BUTTON_MDL, factory as buttonMdl} from './button/button.mdl';
|
export {NAME as BUTTON_MDL, factory as buttonMdl} from './button/button.mdl';
|
||||||
|
@ -26,7 +32,7 @@ export {NAME as TEXTAREA_MDL, factory as textareaMdl} from './textarea/textarea.
|
||||||
export {NAME as LABEL, directive as LabelDirective} from './label/label';
|
export {NAME as LABEL, directive as LabelDirective} from './label/label';
|
||||||
export {NAME as LABEL_MDL, factory as labelMdl} from './label/label.mdl';
|
export {NAME as LABEL_MDL, factory as labelMdl} from './label/label.mdl';
|
||||||
export {NAME as ICON_BUTTON, directive as IconButtonDirective} from './icon-button/icon-button';
|
export {NAME as ICON_BUTTON, directive as IconButtonDirective} from './icon-button/icon-button';
|
||||||
export {NAME as ICON_BUTTON_MDL, factory as iconButtonMdl} from './icon-button/icon-button.mdl';
|
|
||||||
export {NAME as SUBMIT, directive as SubmitDirective} from './submit/submit';
|
export {NAME as SUBMIT, directive as SubmitDirective} from './submit/submit';
|
||||||
export {NAME as SUBMIT_MDL, factory as submitMdl} from './submit/submit.mdl';
|
export {NAME as SUBMIT_MDL, factory as submitMdl} from './submit/submit.mdl';
|
||||||
export {NAME as COMBO, directive as ComboDirective} from './combo/combo';
|
export {NAME as COMBO, directive as ComboDirective} from './combo/combo';
|
||||||
|
|
|
@ -2,12 +2,13 @@ import {module as _module} from '../module';
|
||||||
import * as resolveFactory from '../lib/resolveDefaultComponents';
|
import * as resolveFactory from '../lib/resolveDefaultComponents';
|
||||||
import * as normalizerFactory from '../lib/inputAttrsNormalizer';
|
import * as normalizerFactory from '../lib/inputAttrsNormalizer';
|
||||||
import * as util from '../lib/util';
|
import * as util from '../lib/util';
|
||||||
|
import Flatpickr from 'vendor/src/flatpickr';
|
||||||
|
|
||||||
const _NAME = 'datePicker';
|
const _NAME = 'datePicker';
|
||||||
export const NAME = util.getName(_NAME);
|
export const NAME = util.getName(_NAME);
|
||||||
|
|
||||||
directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME];
|
directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME, '$translate'];
|
||||||
export function directive(resolve, normalizer) {
|
export function directive(resolve, normalizer, $translate) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
template: function(_, attrs) {
|
template: function(_, attrs) {
|
||||||
|
@ -15,12 +16,35 @@ export function directive(resolve, normalizer) {
|
||||||
return resolve.getTemplate(_NAME, attrs);
|
return resolve.getTemplate(_NAME, attrs);
|
||||||
},
|
},
|
||||||
link: function(scope, element, attrs) {
|
link: function(scope, element, attrs) {
|
||||||
|
let input = element[0];
|
||||||
|
let vp;
|
||||||
|
let initOptions = {};
|
||||||
|
|
||||||
|
if (attrs.iniOpts)
|
||||||
|
initOptions = scope.$eval(attrs.iniOpts);
|
||||||
|
|
||||||
|
if (!initOptions.locale)
|
||||||
|
initOptions.locale = $translate.use();
|
||||||
|
|
||||||
|
if (!initOptions.dateFormat && initOptions.locale === 'es')
|
||||||
|
initOptions.dateFormat = 'd-m-Y';
|
||||||
|
|
||||||
|
if (!input.matches('input'))
|
||||||
|
input = input.querySelector('input');
|
||||||
|
|
||||||
|
if (input)
|
||||||
|
vp = new Flatpickr(input, initOptions);
|
||||||
|
|
||||||
scope.$watch(attrs.model, () => {
|
scope.$watch(attrs.model, () => {
|
||||||
let mdlField = element[0].firstChild.MaterialTextfield;
|
let mdlField = element[0].firstChild.MaterialCheckbox;
|
||||||
if (mdlField)
|
if (mdlField)
|
||||||
mdlField.updateClasses_();
|
mdlField.updateClasses_();
|
||||||
});
|
});
|
||||||
componentHandler.upgradeElement(element[0].firstChild);
|
componentHandler.upgradeElement(element[0].firstChild);
|
||||||
|
|
||||||
|
element.on('$destroy', function() {
|
||||||
|
vp.destroy();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ directive.$inject = ['$interpolate', '$compile', '$window'];
|
||||||
export function directive(interpolate, compile, $window) {
|
export function directive(interpolate, compile, $window) {
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
require: ['ngModel', '^^form'],
|
require: ['ngModel', '?^^form'],
|
||||||
link: link
|
link: link
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<vn-vertical class="dropdown-body" ng-show="$ctrl.show">
|
||||||
|
<vn-one ng-show="$ctrl.filter" class="filter">
|
||||||
|
<vn-horizontal>
|
||||||
|
<div ng-if="$ctrl.filterAction">
|
||||||
|
<input vn-one placeholder="{{'Search' | translate}}" type="text" ng-model="$ctrl.search" ng-change="$ctrl.onFilterRest()"/>
|
||||||
|
</div>
|
||||||
|
<div ng-if="!$ctrl.filterAction">
|
||||||
|
<input vn-one placeholder="{{'Search' | translate}}" type="text" ng-model="$ctrl.search" ng-change="$ctrl.filterItems()"/>
|
||||||
|
</div>
|
||||||
|
<vn-icon vn-none icon="clear" ng-click="$ctrl.clearSearch()"></vn-icon>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-one>
|
||||||
|
<vn-one>
|
||||||
|
<ul class="dropdown">
|
||||||
|
<li ng-repeat="item in $ctrl.itemsFiltered" ng-click="$ctrl.selected = item">{{::item.name}}</li>
|
||||||
|
<li ng-if="$ctrl.showLoadMore" class="dropdown__loadMore" ng-click="$ctrl.loadMore()" translate="Load More"></li>
|
||||||
|
</ul>
|
||||||
|
</vn-one>
|
||||||
|
</vn-vertical>
|
|
@ -0,0 +1,58 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
export default class DropDown {
|
||||||
|
constructor($element, $filter) {
|
||||||
|
this.$element = $element;
|
||||||
|
this.$filter = $filter;
|
||||||
|
this.search = '';
|
||||||
|
this.itemsFiltered = [];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
filterItems() {
|
||||||
|
this.itemsFiltered = this.search ? this.$filter('filter')(this.items, this.search) : this.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFilterRest() {
|
||||||
|
this.showLoadMore = false;
|
||||||
|
if (this.filterAction) {
|
||||||
|
this.filterAction({search: this.search});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$onChanges(changesObj) {
|
||||||
|
if (changesObj.show && changesObj.top && changesObj.top.currentValue) {
|
||||||
|
this.$element.css('top', changesObj.top.currentValue + 'px');
|
||||||
|
}
|
||||||
|
if (changesObj.items) {
|
||||||
|
this.filterItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSearch() {
|
||||||
|
this.search = '';
|
||||||
|
this.showLoadMore = this.loadMore != null;
|
||||||
|
if (this.filterAction) {
|
||||||
|
this.filterAction({search: this.search});
|
||||||
|
} else {
|
||||||
|
this.filterItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DropDown.$inject = ['$element', '$filter'];
|
||||||
|
|
||||||
|
module.component('vnDropDown', {
|
||||||
|
template: require('./drop-down.html'),
|
||||||
|
controller: DropDown,
|
||||||
|
bindings: {
|
||||||
|
items: '<',
|
||||||
|
show: '<',
|
||||||
|
filter: '@?',
|
||||||
|
selected: '=',
|
||||||
|
loadMore: '&?',
|
||||||
|
filterAction: '&?',
|
||||||
|
showLoadMore: '<?',
|
||||||
|
top: '<?'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,48 @@
|
||||||
|
vn-drop-down {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9999;
|
||||||
|
padding: 0 15px;
|
||||||
|
margin-left: -15px;
|
||||||
|
background: transparent;
|
||||||
|
.dropdown-body{
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #A7A7A7;
|
||||||
|
.filter{
|
||||||
|
padding: 5px 9px 5px 5px;
|
||||||
|
input{
|
||||||
|
height: 25px;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
vn-icon{
|
||||||
|
font-size: 16px;
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-top: 7px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover{
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ul{
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: white;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
&.dropdown__loadMore{
|
||||||
|
color: rgb(255,171,64);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
li:hover{
|
||||||
|
background-color: #3D3A3B;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
import './phone';
|
import './phone';
|
||||||
|
import './ucwords';
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uppercase the first character of each word in a string
|
||||||
|
*
|
||||||
|
* @return {String} The formated string
|
||||||
|
*/
|
||||||
|
export default function ucwords() {
|
||||||
|
return function(input) {
|
||||||
|
input = input || '';
|
||||||
|
let out = '';
|
||||||
|
let aux = input.split(' ');
|
||||||
|
for (let i = 0; i < aux.length; i++) {
|
||||||
|
out += (aux[i]) ? aux[i].charAt(0).toUpperCase() + aux[i].substr(1).toLowerCase() : '';
|
||||||
|
out += ' ';
|
||||||
|
}
|
||||||
|
return out.trim();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
module.filter('ucwords', ucwords);
|
|
@ -0,0 +1 @@
|
||||||
|
<vn-horizontal class="list" ng-transclude></vn-horizontal>
|
|
@ -0,0 +1,27 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
export default class GridHeader {
|
||||||
|
constructor() {
|
||||||
|
this.currentColumn = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectColum(col) {
|
||||||
|
if (this.currentColumn && this.currentColumn.field != col.field)
|
||||||
|
this.currentColumn.order = undefined;
|
||||||
|
|
||||||
|
this.currentColumn = col;
|
||||||
|
if (this.onOrder)
|
||||||
|
this.onOrder(this.currentColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.component('vnGridHeader', {
|
||||||
|
template: require('./grid-header.html'),
|
||||||
|
transclude: true,
|
||||||
|
bindings: {
|
||||||
|
onOrder: '&?'
|
||||||
|
},
|
||||||
|
controller: GridHeader
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
vn-grid-header {
|
||||||
|
border-bottom: 3px solid #9D9D9D;
|
||||||
|
font-weight: bold;
|
||||||
|
.orderly{
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
vn-none{
|
||||||
|
min-width: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vn-icon{
|
||||||
|
line-height: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: inline;
|
||||||
|
i {
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[min-none]{
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored icon-square {{::$ctrl.className}}" {{$ctrl.enabled}}>
|
||||||
|
<vn-icon icon="{{::$ctrl.icon}}"></vn-icon>{{::$ctrl.label}}
|
||||||
|
</button>
|
|
@ -1,17 +1,12 @@
|
||||||
import {module as _module} from '../module';
|
import {module as _module} from '../module';
|
||||||
import * as resolveFactory from '../lib/resolveDefaultComponents';
|
|
||||||
import * as util from '../lib/util';
|
|
||||||
|
|
||||||
const _NAME = 'iconButton';
|
_module.component('vnIconButton', {
|
||||||
export const NAME = util.getName(_NAME);
|
template: require('./icon-button.html'),
|
||||||
|
bindings: {
|
||||||
|
icon: '@',
|
||||||
|
className: '@?',
|
||||||
|
enabled: '<?',
|
||||||
|
label: '@?'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
directive.$inject = [resolveFactory.NAME];
|
|
||||||
export function directive(resolve) {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
template: function(_, attr) {
|
|
||||||
return resolve.getTemplate(_NAME, attr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_module.directive(NAME, directive);
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored icon-square *[className]*" *[enabled]*>
|
|
||||||
<vn-icon icon="*[icon]*"></vn-icon>*[label]*
|
|
||||||
</button>
|
|
|
@ -1,15 +0,0 @@
|
||||||
import {module} from '../module';
|
|
||||||
import template from './icon-button.mdl.html';
|
|
||||||
|
|
||||||
export const NAME = 'vnIconButtonMdlFactory';
|
|
||||||
export function factory() {
|
|
||||||
return {
|
|
||||||
template: template,
|
|
||||||
default: {
|
|
||||||
enabled: 'enabled',
|
|
||||||
icon: '',
|
|
||||||
label: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
module.factory(NAME, factory);
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="icon-menu">
|
||||||
|
<vn-icon-button icon="{{::$ctrl.icon}}"></vn-icon-button>
|
||||||
|
<div ng-if="!$ctrl.findMore">
|
||||||
|
<vn-drop-down
|
||||||
|
items="$ctrl.items"
|
||||||
|
show="$ctrl.showDropDown"
|
||||||
|
selected="$ctrl.selected"
|
||||||
|
filter="true"
|
||||||
|
></vn-drop-down>
|
||||||
|
</div>
|
||||||
|
<div ng-if="$ctrl.findMore">
|
||||||
|
<vn-drop-down
|
||||||
|
items="$ctrl.items"
|
||||||
|
show="$ctrl.showDropDown"
|
||||||
|
selected="$ctrl.selected"
|
||||||
|
filter="true"
|
||||||
|
load-more="$ctrl.getItems()"
|
||||||
|
show-load-more="$ctrl.maxRow"
|
||||||
|
filter-action="$ctrl.findItems(search)"
|
||||||
|
></vn-drop-down>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,104 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
export default class IconMenu {
|
||||||
|
constructor($element, $http, $timeout) {
|
||||||
|
this.$element = $element;
|
||||||
|
this.$http = $http;
|
||||||
|
this.$timeout = $timeout;
|
||||||
|
this._showDropDown = false;
|
||||||
|
this.finding = false;
|
||||||
|
this.findMore = false;
|
||||||
|
}
|
||||||
|
get showDropDown() {
|
||||||
|
return this._showDropDown;
|
||||||
|
}
|
||||||
|
set showDropDown(value) {
|
||||||
|
this._showDropDown = value;
|
||||||
|
}
|
||||||
|
findItems(search) {
|
||||||
|
if (!this.url)
|
||||||
|
return this.items ? this.items : [];
|
||||||
|
|
||||||
|
if (search && !this.finding) {
|
||||||
|
let filter = {where: {name: {regexp: search}}};
|
||||||
|
let json = JSON.stringify(filter);
|
||||||
|
this.finding = true;
|
||||||
|
this.$http.get(`${this.url}?filter=${json}`).then(
|
||||||
|
json => {
|
||||||
|
this.items = json.data;
|
||||||
|
this.finding = false;
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.finding = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (!search && !this.finding) {
|
||||||
|
this.items = [];
|
||||||
|
this.getItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getItems() {
|
||||||
|
let filter = {};
|
||||||
|
|
||||||
|
if (this.maxRow) {
|
||||||
|
if (this.items) {
|
||||||
|
filter.skip = this.items.length;
|
||||||
|
}
|
||||||
|
filter.limit = this.maxRow;
|
||||||
|
filter.order = 'name ASC';
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = JSON.stringify(filter);
|
||||||
|
|
||||||
|
this.$http.get(`${this.url}?filter=${json}`).then(
|
||||||
|
json => {
|
||||||
|
if (json.data.length)
|
||||||
|
json.data.forEach(
|
||||||
|
el => {
|
||||||
|
this.items.push(el);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
else
|
||||||
|
this.maxRow = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$onInit() {
|
||||||
|
if (!this.items && this.url) {
|
||||||
|
this.items = [];
|
||||||
|
this.getItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.findMore = this.url && this.maxRow;
|
||||||
|
|
||||||
|
this.$element.bind('mouseover', e => {
|
||||||
|
this.$timeout(() => {
|
||||||
|
this.showDropDown = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$element.bind('mouseout', () => {
|
||||||
|
this.$timeout(() => {
|
||||||
|
this.showDropDown = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$onDestroy() {
|
||||||
|
this.$element.unbind('mouseover');
|
||||||
|
this.$element.unbind('mouseout');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IconMenu.$inject = ['$element', '$http', '$timeout'];
|
||||||
|
|
||||||
|
module.component('vnIconMenu', {
|
||||||
|
template: require('./icon-menu.html'),
|
||||||
|
bindings: {
|
||||||
|
url: '@?',
|
||||||
|
items: '<?',
|
||||||
|
icon: '@',
|
||||||
|
maxRow: '@?',
|
||||||
|
selected: '='
|
||||||
|
},
|
||||||
|
controller: IconMenu
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
vn-icon-menu{
|
||||||
|
position: relative;
|
||||||
|
}
|
|
@ -1,19 +1,9 @@
|
||||||
import {module} from '../module';
|
import {module} from '../module';
|
||||||
import './icon.mdl';
|
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import * as resolveFactory from '../lib/resolveDefaultComponents';
|
|
||||||
|
|
||||||
const _NAME = 'icon';
|
module.component('vnIcon', {
|
||||||
export const NAME = 'vnIcon';
|
template: '<i class="material-icons">{{::$ctrl.icon}}</i>',
|
||||||
|
bindings: {
|
||||||
export function directive(resolver) {
|
icon: '@'
|
||||||
return {
|
}
|
||||||
restrict: 'E',
|
});
|
||||||
template: function(_, attrs) {
|
|
||||||
return resolver.getTemplate(_NAME, attrs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
directive.$inject = [resolveFactory.NAME];
|
|
||||||
|
|
||||||
module.directive(NAME, directive);
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<i class="material-icons">*[icon]*</i>
|
|
|
@ -1,12 +0,0 @@
|
||||||
import {module} from '../module';
|
|
||||||
import template from './icon.mdl.html';
|
|
||||||
|
|
||||||
export const NAME = 'vnIconMdlFactory';
|
|
||||||
export function factory() {
|
|
||||||
return {
|
|
||||||
template: template,
|
|
||||||
default: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.factory(NAME, factory);
|
|
|
@ -7,7 +7,7 @@ export function factory($translatePartialLoader, $http, $window, $ocLazyLoad, $q
|
||||||
constructor() {
|
constructor() {
|
||||||
this._loadedModules = {};
|
this._loadedModules = {};
|
||||||
}
|
}
|
||||||
load(moduleName) {
|
load(moduleName, validations) {
|
||||||
if (this._loadedModules[moduleName])
|
if (this._loadedModules[moduleName])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -20,17 +20,18 @@ export function factory($translatePartialLoader, $http, $window, $ocLazyLoad, $q
|
||||||
for (let dep of deps) {
|
for (let dep of deps) {
|
||||||
this._loadedModules[dep] = true;
|
this._loadedModules[dep] = true;
|
||||||
promises.push(modules[dep]());
|
promises.push(modules[dep]());
|
||||||
promises.push(new Promise(resolve => {
|
if (validations)
|
||||||
$http.get(`/${dep}/validations`).then(
|
promises.push(new Promise(resolve => {
|
||||||
json => this.onValidationsReady(json, resolve),
|
$http.get(`/${dep}/validations`).then(
|
||||||
json => resolve()
|
json => this.onValidationsReady(json, resolve),
|
||||||
);
|
json => resolve()
|
||||||
}));
|
);
|
||||||
|
}));
|
||||||
|
|
||||||
$translatePartialLoader.addPart(dep);
|
$translatePartialLoader.addPart(dep);
|
||||||
// FIXME: https://github.com/angular-translate/angular-translate/pull/1674
|
// FIXME: https://github.com/angular-translate/angular-translate/pull/1674
|
||||||
// promises.push($translate.refresh());
|
// promises.push($translate.refresh());
|
||||||
setTimeout (() => $translate.refresh(), 500);
|
setTimeout(() => $translate.refresh(), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ocDeps = deps.map(item => { return { name: item } });
|
let ocDeps = deps.map(item => { return { name: item } });
|
||||||
|
|
|
@ -5,5 +5,6 @@
|
||||||
"Clear": "Borrar",
|
"Clear": "Borrar",
|
||||||
"Save": "Guardar",
|
"Save": "Guardar",
|
||||||
"Add": "Añadir",
|
"Add": "Añadir",
|
||||||
"Search": "Buscar"
|
"Search": "Buscar",
|
||||||
|
"Load More": "Cargar más"
|
||||||
}
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<vn-vertical class="multi-check" vn-none class="multi-check {{$ctrl.className}}" tabindex="-1" ng-blur="$ctrl.showDropDown = false">
|
||||||
|
<vn-one>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-none class="primaryCheckbox" ng-if="$ctrl.checkAll===0">
|
||||||
|
<vn-icon vn-none icon="check_box_outline_blank" ng-click="$ctrl.checkAll = 1"></vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
<vn-none class="primaryCheckbox color" ng-if="$ctrl.checkAll===1">
|
||||||
|
<vn-icon vn-none icon="check_box" ng-click="$ctrl.checkAll = 0"></vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
<vn-none class="primaryCheckbox color" ng-if="$ctrl.checkAll===2">
|
||||||
|
<vn-icon vn-none icon="indeterminate_check_box" ng-click="$ctrl.checkAll = 0"></vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
<vn-icon vn-none class="arrow_down" icon="keyboard_arrow_down" ng-click="$ctrl.showDropDown = true"></vn-icon>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-one>
|
||||||
|
<vn-one>
|
||||||
|
<vn-drop-down vn-none items="$ctrl.options" show="$ctrl.showDropDown" selected="$ctrl.type"></vn-drop-down>
|
||||||
|
</vn-one>
|
||||||
|
</vn-vertical>
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
import './multi-check.scss';
|
||||||
|
/**
|
||||||
|
* Draw checkbox with a drop-down and multi options
|
||||||
|
* @param {Array} options List of options shown in drop-down
|
||||||
|
* @param {Array} models Elements to check / unCheck
|
||||||
|
* @param {String} className Optional css class name
|
||||||
|
*/
|
||||||
|
export default class MultiCheck {
|
||||||
|
constructor() {
|
||||||
|
this._checkAll = 0;
|
||||||
|
this._models = [];
|
||||||
|
this.type = {};
|
||||||
|
this.showDropDown = false;
|
||||||
|
}
|
||||||
|
get models() {
|
||||||
|
return this._models;
|
||||||
|
}
|
||||||
|
set models(value) {
|
||||||
|
this._models = value;
|
||||||
|
}
|
||||||
|
get checkAll() {
|
||||||
|
return this._checkAll;
|
||||||
|
}
|
||||||
|
set checkAll(value) {
|
||||||
|
this._checkAll = value;
|
||||||
|
this.switchChecks();
|
||||||
|
}
|
||||||
|
switchChecks() {
|
||||||
|
if (this.models)
|
||||||
|
this.models.forEach(
|
||||||
|
el => {
|
||||||
|
let checked;
|
||||||
|
if (this.type.id && this.type.id !== 'all' && this.type.id !== 'any') {
|
||||||
|
if (this.type.id.length > 3 && this.type.id.substr(0, 3) === 'no-') {
|
||||||
|
checked = el[this.type.id.replace('no-', '')] == null;
|
||||||
|
} else if (this.type.id.length > 6 && this.type.id.substr(0, 6) === 'equal-') {
|
||||||
|
let label = this.type.id.replace('equal-', '');
|
||||||
|
checked = (el[label] && el[label] === this.type.name);
|
||||||
|
} else {
|
||||||
|
checked = el[this.type.id] != null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
checked = this.checkAll === 1;
|
||||||
|
}
|
||||||
|
el.checked = checked;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$onChanges() {
|
||||||
|
this.type = {};
|
||||||
|
this.checkAll = 0;
|
||||||
|
}
|
||||||
|
$doCheck() {
|
||||||
|
if (this.type && this.type.id) {
|
||||||
|
switch (this.type.id) {
|
||||||
|
case 'all':
|
||||||
|
this.checkAll = 1;
|
||||||
|
break;
|
||||||
|
case 'any':
|
||||||
|
this.checkAll = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.checkAll = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.type = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MultiCheck.$inject = [];
|
||||||
|
|
||||||
|
module.component('vnMultiCheck', {
|
||||||
|
template: require('./multi-check.html'),
|
||||||
|
controller: MultiCheck,
|
||||||
|
bindings: {
|
||||||
|
options: '<',
|
||||||
|
models: '=',
|
||||||
|
className: '@?'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
.multi-check {
|
||||||
|
vn-icon{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&:focus, &:active, &:hover{
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.primaryCheckbox {
|
||||||
|
vn-icon{
|
||||||
|
font-size: 22px;
|
||||||
|
margin-left: -4px;
|
||||||
|
i{
|
||||||
|
color: rgba(0,0,0,.54);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.color {
|
||||||
|
i{
|
||||||
|
color: rgb(255,152,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.arrow_down{
|
||||||
|
i{
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,8 @@ export default class Paging {
|
||||||
$onChanges(changes) {
|
$onChanges(changes) {
|
||||||
if (!this.index) return;
|
if (!this.index) return;
|
||||||
this.numPerPage = this.index.filter.size;
|
this.numPerPage = this.index.filter.size;
|
||||||
if(changes.total)
|
this.currentPage = this.index.filter.page;
|
||||||
|
if (changes.total)
|
||||||
this.numItems = changes.total.currentValue;
|
this.numItems = changes.total.currentValue;
|
||||||
}
|
}
|
||||||
onModelUpdated() {
|
onModelUpdated() {
|
||||||
|
@ -29,7 +30,11 @@ export default class Paging {
|
||||||
}
|
}
|
||||||
onPageChange(page) {
|
onPageChange(page) {
|
||||||
this.index.filter.page = page;
|
this.index.filter.page = page;
|
||||||
this.index.accept();
|
if (typeof this.pageChange === 'undefined') {
|
||||||
|
this.index.accept();
|
||||||
|
} else {
|
||||||
|
this.pageChange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Paging.$inject = ['$http', '$scope'];
|
Paging.$inject = ['$http', '$scope'];
|
||||||
|
@ -39,6 +44,7 @@ export const COMPONENT = {
|
||||||
template: require('./paging.html'),
|
template: require('./paging.html'),
|
||||||
bindings: {
|
bindings: {
|
||||||
index: '<',
|
index: '<',
|
||||||
|
pageChange: '&?',
|
||||||
total: '<'
|
total: '<'
|
||||||
},
|
},
|
||||||
controller: Paging
|
controller: Paging
|
||||||
|
|
|
@ -16,12 +16,38 @@ export function directive(vnPopover) {
|
||||||
module.directive('vnPopover', directive);
|
module.directive('vnPopover', directive);
|
||||||
|
|
||||||
export class Popover {
|
export class Popover {
|
||||||
constructor($document, $compile) {
|
constructor($document, $compile, $transitions) {
|
||||||
this.document = $document[0];
|
this.document = $document[0];
|
||||||
this.$compile = $compile;
|
this.$compile = $compile;
|
||||||
|
this.$transitions = $transitions;
|
||||||
|
this.removeScope = false;
|
||||||
|
this.popOpens = 0;
|
||||||
}
|
}
|
||||||
show(childElement, parent) {
|
_init() {
|
||||||
|
this.docMouseDownHandler = e => this.onDocMouseDown(e);
|
||||||
|
this.document.addEventListener('mousedown', this.docMouseDownHandler);
|
||||||
|
this.docKeyDownHandler = e => this.onDocKeyDown(e);
|
||||||
|
this.document.addEventListener('keydown', this.docKeyDownHandler);
|
||||||
|
this.deregisterCallback = this.$transitions.onStart({},
|
||||||
|
() => this.hideAll());
|
||||||
|
}
|
||||||
|
_destroy() {
|
||||||
|
this.document.removeEventListener('mousedown', this.docMouseDownHandler);
|
||||||
|
this.document.removeEventListener('keydown', this.docKeyDownHandler);
|
||||||
|
this.docMouseDownHandler = null;
|
||||||
|
this.docKeyDownHandler = null;
|
||||||
|
this.deregisterCallback();
|
||||||
|
}
|
||||||
|
show(childElement, parent, popoverId) {
|
||||||
|
this.childElement = childElement;
|
||||||
let popover = this.document.createElement('div');
|
let popover = this.document.createElement('div');
|
||||||
|
this.popOpens++;
|
||||||
|
|
||||||
|
if (!popoverId) {
|
||||||
|
popoverId = 'popover-' + this.popOpens;
|
||||||
|
popover.id = popoverId;
|
||||||
|
}
|
||||||
|
|
||||||
popover.className = 'vn-popover';
|
popover.className = 'vn-popover';
|
||||||
popover.addEventListener('mousedown',
|
popover.addEventListener('mousedown',
|
||||||
e => this.onPopoverMouseDown(e));
|
e => this.onPopoverMouseDown(e));
|
||||||
|
@ -71,38 +97,96 @@ export class Popover {
|
||||||
|
|
||||||
this.document.body.appendChild(popover);
|
this.document.body.appendChild(popover);
|
||||||
|
|
||||||
this.docMouseDownHandler = e => this.onDocMouseDown(e);
|
if (this.popOpens === 1) {
|
||||||
this.document.addEventListener('mousedown', this.docMouseDownHandler);
|
this._init();
|
||||||
|
}
|
||||||
this.docKeyDownHandler = e => this.onDocKeyDown(e);
|
return popoverId;
|
||||||
this.document.addEventListener('keydown', this.docKeyDownHandler);
|
|
||||||
}
|
}
|
||||||
showComponent(childComponent, $scope, parent) {
|
showComponent(childComponent, $scope, parent) {
|
||||||
let childElement = this.document.createElement(childComponent);
|
let childElement = this.document.createElement(childComponent);
|
||||||
this.$compile(childElement)($scope);
|
let id = 'popover-' + this.popOpens;
|
||||||
this.show(childElement, parent);
|
childElement.id = id;
|
||||||
|
this.removeScope = true;
|
||||||
|
this.$compile(childElement)($scope.$new());
|
||||||
|
this.show(childElement, parent, id);
|
||||||
|
return childElement;
|
||||||
}
|
}
|
||||||
hide() {
|
_checkOpens() {
|
||||||
if (!this.popover) return;
|
this.popOpens = this.document.querySelectorAll('*[id^="popover-"]').length;
|
||||||
this.document.removeEventListener('mousedown', this.docMouseDownHandler);
|
if (this.popOpens === 0) {
|
||||||
this.document.removeEventListener('keydown', this.docKeyDownHandler);
|
this._destroy();
|
||||||
this.document.body.removeChild(this.popover);
|
}
|
||||||
this.popover = null;
|
}
|
||||||
this.lastEvent = null;
|
_removeElement(val) {
|
||||||
this.docMouseDownHandler = null;
|
if (!val) return;
|
||||||
this.docKeyDownHandler = null;
|
let element = angular.element(val);
|
||||||
|
let parent = val.parentNode;
|
||||||
|
if (element.scope() && element.scope().$id > 1) {
|
||||||
|
element.scope().$destroy();
|
||||||
|
}
|
||||||
|
element.remove();
|
||||||
|
if (parent.className.indexOf('vn-popover') !== -1)
|
||||||
|
this._removeElement(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide(id) {
|
||||||
|
let popover = this.document.querySelector(`#${id}`);
|
||||||
|
if (popover) {
|
||||||
|
this._removeElement(popover);
|
||||||
|
}
|
||||||
|
this._checkOpens();
|
||||||
|
}
|
||||||
|
hideChilds(id) {
|
||||||
|
let popovers = this.document.querySelectorAll('*[id^="popover-"]');
|
||||||
|
let idNumber = parseInt(id.split('-')[1], 10);
|
||||||
|
popovers.forEach(
|
||||||
|
val => {
|
||||||
|
if (parseInt(val.id.split('-')[1], 10) > idNumber)
|
||||||
|
this._removeElement(val);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this._checkOpens();
|
||||||
|
}
|
||||||
|
hideAll() {
|
||||||
|
let popovers = this.document.querySelectorAll('*[id^="popover-"]');
|
||||||
|
popovers.forEach(
|
||||||
|
val => {
|
||||||
|
this._removeElement(val);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this._checkOpens();
|
||||||
|
}
|
||||||
|
_findPopOver(node) {
|
||||||
|
while (node != null) {
|
||||||
|
if (node.id && node.id.startsWith('popover-')) {
|
||||||
|
return node.id;
|
||||||
|
}
|
||||||
|
node = node.parentNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
onDocMouseDown(event) {
|
onDocMouseDown(event) {
|
||||||
if (event != this.lastEvent)
|
let targetId = this._findPopOver(event.target);
|
||||||
this.hide();
|
if (targetId) {
|
||||||
|
this.hideChilds(targetId);
|
||||||
|
} else {
|
||||||
|
this.hideAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onDocKeyDown(event) {
|
onDocKeyDown(event) {
|
||||||
if (event.keyCode === 27)
|
if (event.keyCode === 27) {
|
||||||
this.hide();
|
let targetId = this._findPopOver(this.lastTarget);
|
||||||
|
if (targetId) {
|
||||||
|
this.hideChilds(targetId);
|
||||||
|
} else {
|
||||||
|
this.hideAll();
|
||||||
|
}
|
||||||
|
this.lastTarget = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onPopoverMouseDown(event) {
|
onPopoverMouseDown(event) {
|
||||||
this.lastEvent = event;
|
this.lastTarget = event.target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Popover.$inject = ['$document', '$compile'];
|
Popover.$inject = ['$document', '$compile', '$transitions'];
|
||||||
module.service('vnPopover', Popover);
|
module.service('vnPopover', Popover);
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
[vn-tooltip]{
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
.tooltip {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 15px;
|
||||||
|
color: #424242;
|
||||||
|
z-index: 999;
|
||||||
|
border: 1px solid #A7A7A7;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-show {
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-arrow {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-text{
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-down .tooltip-arrow {
|
||||||
|
top: -15px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -10px;
|
||||||
|
border-left: 10px solid transparent;
|
||||||
|
border-right: 10px solid transparent;
|
||||||
|
border-bottom: 15px solid #A7A7A7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-up .tooltip-arrow {
|
||||||
|
bottom: -15px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -10px;
|
||||||
|
border-left: 10px solid transparent;
|
||||||
|
border-right: 10px solid transparent;
|
||||||
|
border-top: 15px solid #A7A7A7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-right .tooltip-arrow {
|
||||||
|
left: -15px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -10px;
|
||||||
|
border-top: 10px solid transparent;
|
||||||
|
border-bottom: 10px solid transparent;
|
||||||
|
border-right: 15px solid #A7A7A7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-left .tooltip-arrow {
|
||||||
|
right: -15px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -10px;
|
||||||
|
border-top: 10px solid transparent;
|
||||||
|
border-bottom: 10px solid transparent;
|
||||||
|
border-left: 15px solid #A7A7A7;
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
import {module} from '../module';
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
|
tooltip.$inject = ['$document', '$compile', '$interpolate', '$sce', '$templateCache', '$http', '$q'];
|
||||||
|
function tooltip($document, $compile, $interpolate, $sce, $templateCache, $http, $q) {
|
||||||
|
var promise;
|
||||||
|
|
||||||
|
function _getTemplate(tooltipTemplateUrl) {
|
||||||
|
var template = $templateCache.get(tooltipTemplateUrl);
|
||||||
|
if (typeof template === 'undefined') {
|
||||||
|
template = $http.get(tooltipTemplateUrl).then(function onGetTemplateSuccess(response) {
|
||||||
|
if (promise) {
|
||||||
|
promise.resolve(response.data);
|
||||||
|
}
|
||||||
|
promise = undefined;
|
||||||
|
return response.data;
|
||||||
|
});
|
||||||
|
$templateCache.put(tooltipTemplateUrl, template);
|
||||||
|
}
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTemplate(tooltipTemplateUrl) {
|
||||||
|
var _promise = $q.defer();
|
||||||
|
var template = _getTemplate(tooltipTemplateUrl);
|
||||||
|
if (template) {
|
||||||
|
_promise.resolve(template);
|
||||||
|
} else {
|
||||||
|
promise = _promise;
|
||||||
|
}
|
||||||
|
return _promise.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
priority: -1,
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
var tipHtml = '<div class="mdl-shadow--2dp" ng-class="tipClass"><div class="tooltip-text">{{text}}</div><div ng-if="isHtmlContent" ng-bind-html="htmlContent"></div><div class="tooltip-arrow"></div></div>';
|
||||||
|
var tip;
|
||||||
|
var tipClassName = 'tooltip';
|
||||||
|
var tipActiveClassName = 'tooltip-show';
|
||||||
|
|
||||||
|
scope.tipClass = [tipClassName];
|
||||||
|
scope.text = attrs.vnTooltip || '';
|
||||||
|
|
||||||
|
if (attrs.tooltipHtml) {
|
||||||
|
scope.isHtmlContent = true;
|
||||||
|
scope.htmlContent = $sce.trustAsHtml(attrs.tooltipHtml);
|
||||||
|
_compileTip();
|
||||||
|
} else if (attrs.tooltipTemplate) {
|
||||||
|
getTemplate(attrs.tooltipTemplate).then(template => {
|
||||||
|
scope.isHtmlContent = true;
|
||||||
|
scope.htmlContent = $sce.trustAsHtml($interpolate(template)(scope));
|
||||||
|
_compileTip();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
scope.isHtmlContent = false;
|
||||||
|
scope.htmlContent = null;
|
||||||
|
_compileTip();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.tooltipPosition) {
|
||||||
|
scope.tipClass.push('tooltip-' + attrs.tooltipPosition);
|
||||||
|
} else {
|
||||||
|
scope.tipClass.push('tooltip-down');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _compileTip() {
|
||||||
|
tip = $compile(tipHtml)(scope);
|
||||||
|
$document.find('body').append(tip);
|
||||||
|
_bindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bindEvents() {
|
||||||
|
element.bind('mouseover', function(e) {
|
||||||
|
tip.addClass(tipActiveClassName);
|
||||||
|
|
||||||
|
let pos = e.target.getBoundingClientRect();
|
||||||
|
let tipPos = tip[0].getBoundingClientRect();
|
||||||
|
let offset = {top: 0, left: 0};
|
||||||
|
let tipWidth = tipPos.width || tipPos.right - tipPos.left;
|
||||||
|
let tipHeight = tipPos.height || tipPos.bottom - tipPos.top;
|
||||||
|
let elWidth = pos.width || pos.right - pos.left;
|
||||||
|
let elHeight = pos.height || pos.bottom - pos.top;
|
||||||
|
let tipOffset = 10;
|
||||||
|
|
||||||
|
if (tip.hasClass('tooltip-right')) {
|
||||||
|
offset.top = pos.top - (tipHeight / 2) + (elHeight / 2);
|
||||||
|
offset.left = pos.right + tipOffset;
|
||||||
|
} else if (tip.hasClass('tooltip-left')) {
|
||||||
|
offset.top = pos.top - (tipHeight / 2) + (elHeight / 2);
|
||||||
|
offset.left = pos.left - tipWidth - tipOffset;
|
||||||
|
} else if (tip.hasClass('tooltip-down')) {
|
||||||
|
offset.top = pos.top + elHeight + tipOffset;
|
||||||
|
offset.left = pos.left - (tipWidth / 2) + (elWidth / 2);
|
||||||
|
} else {
|
||||||
|
offset.top = pos.top - tipHeight - tipOffset;
|
||||||
|
offset.left = pos.left - (tipWidth / 2) + (elWidth / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
tip.css('top', offset.top + 'px');
|
||||||
|
tip.css('left', offset.left + 'px');
|
||||||
|
});
|
||||||
|
|
||||||
|
element.on('mouseout', function() {
|
||||||
|
tip.removeClass(tipActiveClassName);
|
||||||
|
});
|
||||||
|
|
||||||
|
tip.on('mouseover', function() {
|
||||||
|
tip.addClass(tipActiveClassName);
|
||||||
|
});
|
||||||
|
|
||||||
|
tip.on('mouseout', function() {
|
||||||
|
tip.removeClass(tipActiveClassName);
|
||||||
|
});
|
||||||
|
|
||||||
|
element.on('$destroy', function() {
|
||||||
|
tip.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive('vnTooltip', tooltip);
|
|
@ -2,6 +2,7 @@
|
||||||
"module": "production",
|
"module": "production",
|
||||||
"name": "Production",
|
"name": "Production",
|
||||||
"icon": "group_work",
|
"icon": "group_work",
|
||||||
|
"validations" : false,
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"url": "/production",
|
"url": "/production",
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
<div pad-large>
|
|
||||||
<form ng-submit="$ctrl.onSearch()">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield vn-one label="ID Ruta" model="$ctrl.filter.ruteId"></vn-textfield>
|
|
||||||
<vn-textfield vn-one label="Fecha" model="$ctrl.filter.date"></vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
initial-value="$ctrl.filter.province"
|
|
||||||
field="$ctrl.filter.provinceFk"
|
|
||||||
url="/client/api/Provinces"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
label="Provincia">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-textfield vn-one label="Hora" model="$ctrl.filter.hour"></vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-check vn-one pad-medium-top label="Ticket con incidencia" field="$ctrl.filter.withIncidence"></vn-check>
|
|
||||||
<vn-textfield vn-one label="Agencia" model="$ctrl.filter.agency"></vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,25 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
|
|
||||||
export default class Controller {
|
|
||||||
constructor($window) {
|
|
||||||
this.$window = $window;
|
|
||||||
}
|
|
||||||
onSearch() {
|
|
||||||
this.setStorageValue();
|
|
||||||
this.onSubmit(this.filter);
|
|
||||||
}
|
|
||||||
$onChanges() {
|
|
||||||
var value = JSON.parse(this.$window.sessionStorage.getItem('production'));
|
|
||||||
if (value !== undefined)
|
|
||||||
this.filter = value;
|
|
||||||
}
|
|
||||||
setStorageValue() {
|
|
||||||
this.$window.sessionStorage.setItem('production', JSON.stringify(this.filter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Controller.$inject = ['$window'];
|
|
||||||
|
|
||||||
ngModule.component('vnProductionFilterPanel', {
|
|
||||||
template: require('./filter-panel.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,36 +1,40 @@
|
||||||
|
<mg-ajax path="/production/api/States/list" options="vnIndex as states" actions="$ctrl.states = states.model;"></mg-ajax>
|
||||||
|
|
||||||
<vn-card margin-large>
|
<vn-card margin-large>
|
||||||
<mg-ajax path="" options="vnIndex"></mg-ajax>
|
<vn-vertical pad-medium>
|
||||||
<vn-vertical pad-medium>
|
<vn-horizontal vn-one margin-large-bottom class="locator-header">
|
||||||
<vn-horizontal vn-one>
|
<vn-title vn-one><span translate>Finder</span></vn-title>
|
||||||
<vn-title vn-one><span translate>Localizador</span></vn-title>
|
<vn-two vn-horizontal class="filterPanel">
|
||||||
<vn-searchbar vn-auto
|
<vn-textfield vn-one label="Filtro" model="$ctrl.filter.q"></vn-textfield>
|
||||||
index="index"
|
<vn-icon
|
||||||
on-search="$ctrl.filter(index)"
|
vn-none
|
||||||
advanced="true"
|
margin-medium-right
|
||||||
search="$ctrl.model.filter"
|
pad-medium-top
|
||||||
popover="vn-production-filter-panel">
|
icon="keyboard_arrow_down"
|
||||||
</vn-searchbar>
|
ng-click="$ctrl.moreFilters($event)">
|
||||||
<vn-one vn-horizontal>
|
</vn-icon>
|
||||||
|
<vn-button vn-none pad-small-top label="Filtrar" ng-click="$ctrl.searchTickets()"></vn-button>
|
||||||
|
</vn-two>
|
||||||
|
<vn-one vn-horizontal>
|
||||||
<vn-one></vn-one>
|
<vn-one></vn-one>
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-two
|
||||||
initial-value="$ctrl.warehouse"
|
initial-value="$ctrl.filter.warehouseFk"
|
||||||
field="$ctrl.warehouseFk"
|
show-field="name"
|
||||||
url="/client/api/ContactChannels"
|
value-field="id"
|
||||||
label="Almacen">
|
field="$ctrl.filter.warehouseFk"
|
||||||
|
url="/production/api/Warehouses/production"
|
||||||
|
on-change = "$ctrl.onChangeWareHouse(item)"
|
||||||
|
label="Store">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-none>
|
<vn-icon-button vn-none pad-ten-top margin-small-left icon="refresh" ng-click="$ctrl.refreshTickets()"></vn-icon-button>
|
||||||
<vn-icon-button icon="refresh"></vn-icon-button>
|
</vn-one>
|
||||||
</vn-none>
|
</vn-horizontal>
|
||||||
</vn-one>
|
<vn-horizontal vn-one margin-large-bottom>
|
||||||
</vn-horizontal>
|
<vn-one>
|
||||||
<vn-horizontal vn-one>
|
<vn-production-actions tickets="$ctrl.tickets" states="$ctrl.states" hour-items="$ctrl.hourItems"></vn-production-actions>
|
||||||
<vn-one>
|
</vn-one>
|
||||||
<vn-horizontal>
|
<vn-two></vn-two>
|
||||||
<vn-button vn-auto label="Impreso"></vn-button>
|
</vn-horizontal>
|
||||||
|
<vn-production-table tickets="$ctrl.tickets" footer="$ctrl.footer"></vn-production-table>
|
||||||
</vn-horizontal>
|
</vn-vertical>
|
||||||
</vn-one>
|
|
||||||
<vn-two></vn-two>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
</vn-card>
|
|
@ -1,11 +1,118 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
export default class ProductionIndex {
|
export default class ProductionIndex {
|
||||||
search(index) {
|
constructor($element, $scope, $http, vnPopover, aclConstant) {
|
||||||
index.filter.search = this.model.search;
|
this.$element = $element;
|
||||||
index.accept();
|
this.$ = $scope;
|
||||||
|
this.$http = $http;
|
||||||
|
this.vnPopover = vnPopover;
|
||||||
|
this.filter = {};
|
||||||
|
this.tickets = [];
|
||||||
|
this.states = [];
|
||||||
|
this.footer = {
|
||||||
|
total: null,
|
||||||
|
lines: null,
|
||||||
|
meters: null
|
||||||
|
};
|
||||||
|
this.hourItems = [];
|
||||||
|
this.child = undefined;
|
||||||
|
this.userProfile = aclConstant.userProfile;
|
||||||
|
this.filter.warehouseFk = this.userProfile.warehouseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions Callbacks
|
||||||
|
_changeState(ids, sateteId, stateName, index) {
|
||||||
|
this.$http.put(`/production/api/TicketStates/${sateteId}/changeState`, {tickets: ids}).then(
|
||||||
|
() => {
|
||||||
|
index.forEach(
|
||||||
|
val => {
|
||||||
|
this.tickets[val].state = stateName;
|
||||||
|
this.tickets[val].stateFk = sateteId;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_sendMessage(tickets) {
|
||||||
|
this.$http.post(`/production/api/FakeProductions/messageSend`, {tickets: tickets}).then(
|
||||||
|
() => {
|
||||||
|
this.vnApp.showMessage(this.$translate.instant('Success: message send!'));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_changeTime(ids, time, index) {
|
||||||
|
this.$http.put(`/production/api/Tickets/${time}/changeTime`, {tickets: ids}).then(
|
||||||
|
() => {
|
||||||
|
index.forEach(
|
||||||
|
val => {
|
||||||
|
this.tickets[val].hour = time;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
moreFilters(event) {
|
||||||
|
this.child = this.vnPopover.showComponent('vn-production-filter-panel', this.$, this.$element[0].querySelector('.filterPanel'));
|
||||||
|
var childCtrl = angular.element(this.child).isolateScope().$ctrl;
|
||||||
|
childCtrl.filter = Object.assign({}, this.filter);
|
||||||
|
childCtrl.data = Object.assign({}, {states: this.states}, {hourItems: this.hourItems});
|
||||||
|
childCtrl.onSubmit = filter => this.onChildSubmit(filter);
|
||||||
|
childCtrl.onCancel = () => this.onChildCancel();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
onChildSubmit(filter) {
|
||||||
|
this.searchTickets(filter);
|
||||||
|
this.onChildCancel();
|
||||||
|
}
|
||||||
|
onChildCancel() {
|
||||||
|
angular.element(this.child).scope().$destroy();
|
||||||
|
angular.element(this.child).remove();
|
||||||
|
delete this.child;
|
||||||
|
}
|
||||||
|
searchTickets(filter) {
|
||||||
|
this.filter = Object.assign({}, filter || {}, this.filter);
|
||||||
|
|
||||||
|
let filters = Object.assign({}, {
|
||||||
|
where: this.filter
|
||||||
|
}, {
|
||||||
|
page: 1,
|
||||||
|
limit: 700
|
||||||
|
});
|
||||||
|
this.$http.get('/production/api/FakeProductions/list?filter=' + JSON.stringify(filters)).then(
|
||||||
|
json => {
|
||||||
|
this.tickets = json.data.tickets;
|
||||||
|
this.footer.lines = json.data.lines;
|
||||||
|
this.footer.meters = json.data.m3;
|
||||||
|
this.footer.total = json.data.total;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
refreshTickets() {
|
||||||
|
this.filter = {};
|
||||||
|
this.filter.warehouseFk = this.userProfile.warehouseId;
|
||||||
|
this.searchTickets();
|
||||||
|
}
|
||||||
|
onChangeWareHouse(item) {
|
||||||
|
if (item && item.id && item.id != this.filter.warehouseFk) {
|
||||||
|
this.filter.warehouseFk = item.id;
|
||||||
|
this.searchTickets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$onInit() {
|
||||||
|
for (let i = 1; i <= 24; i++) {
|
||||||
|
let hour = [i].join('');
|
||||||
|
if (hour.length === 1) {
|
||||||
|
hour = [0, i].join('');
|
||||||
|
}
|
||||||
|
hour += ':00';
|
||||||
|
this.hourItems.push({id: i, name: hour});
|
||||||
|
}
|
||||||
|
this.searchTickets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ProductionIndex.$inject = ['$element', '$scope', '$http', 'vnPopover', 'aclConstant'];
|
||||||
|
|
||||||
ngModule.component('vnProductionIndex', {
|
ngModule.component('vnProductionIndex', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
vn-production-index {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
vn-searchbar {
|
||||||
|
vn-icon{
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
vn-icon-button{
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[pad-ten-top] {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
.icon-square{
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
.locator-header{
|
||||||
|
i{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.moreFilters{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
background-color: white;
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #9D9D9D;
|
||||||
|
margin-top: 60px;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,25 @@
|
||||||
{}
|
{
|
||||||
|
"Finder" : "Localizador",
|
||||||
|
"Error: No tickets selected!" : "Error: ¡No hay tickets seleccionados!",
|
||||||
|
"Error: Action not implemented!" : "Error: ¡Acción no implementada!",
|
||||||
|
"State" : "Estado",
|
||||||
|
"Alarm" : "Alarma",
|
||||||
|
"Agencies": "Agencias",
|
||||||
|
"Agency": "Agencia",
|
||||||
|
"Store" : "Almacén",
|
||||||
|
"Printed": "Impreso",
|
||||||
|
"Commercial": "Comercial",
|
||||||
|
"Hour" : "Hora",
|
||||||
|
"Lines" : "Líneas",
|
||||||
|
"Boxes" : "Cajas",
|
||||||
|
"Comment" : "Comentario",
|
||||||
|
"Message" : "Mensaje",
|
||||||
|
"Send" : "Enviar",
|
||||||
|
"Date" : "Fecha",
|
||||||
|
"Ticket ID" : "ID Ticket",
|
||||||
|
"Route ID": "ID Ruta",
|
||||||
|
"Province" : "Provincia",
|
||||||
|
"Filter" : "Filtrar",
|
||||||
|
"Cancel" : "Cancelar",
|
||||||
|
"Ticket with incidence" : "Ticket con incidencia"
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<vn-horizontal class="actionPanel">
|
||||||
|
<vn-button vn-none margin-medium-right label="Printed" ng-click="$ctrl.doAction('markPrinted')"></vn-button>
|
||||||
|
<vn-none margin-medium-right>
|
||||||
|
<vn-icon-menu icon="assignment" items="$ctrl.states" selected="$ctrl.actionState"></vn-icon-menu>
|
||||||
|
</vn-none>
|
||||||
|
<vn-none margin-medium-right>
|
||||||
|
<vn-icon-button icon="textsms" ng-click="$ctrl.doAction('addComment')"></vn-icon-button>
|
||||||
|
</vn-none>
|
||||||
|
<vn-none margin-medium-right>
|
||||||
|
<vn-icon-menu icon="person" url="/client/api/Clients/employeeList" selected="$ctrl.actionWorker"></vn-icon-menu>
|
||||||
|
</vn-none>
|
||||||
|
<vn-none margin-medium-right>
|
||||||
|
<vn-icon-menu icon="query_builder" items="$ctrl.hourItems" selected="$ctrl.actionHours"></vn-icon-menu>
|
||||||
|
</vn-none>
|
||||||
|
</vn-horizontal>
|
|
@ -0,0 +1,130 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
|
||||||
|
export default class ProductionActions {
|
||||||
|
constructor($http, $translate, vnApp) {
|
||||||
|
this.$http = $http;
|
||||||
|
this.$translate = $translate;
|
||||||
|
this.vnApp = vnApp;
|
||||||
|
|
||||||
|
this._actionState = null;
|
||||||
|
this._actionWorker = null;
|
||||||
|
this._actionHours = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set actionState(value) {
|
||||||
|
this._actionState = value;
|
||||||
|
this.doAction('changeState');
|
||||||
|
}
|
||||||
|
get actionState() {
|
||||||
|
return this._actionState;
|
||||||
|
}
|
||||||
|
|
||||||
|
set actionHours(value) {
|
||||||
|
this._actionHours = value;
|
||||||
|
this.doAction('changeTime');
|
||||||
|
}
|
||||||
|
get actionHours() {
|
||||||
|
return this._actionHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
set actionWorker(value) {
|
||||||
|
this._actionWorker = value;
|
||||||
|
this.doAction('changeWorker');
|
||||||
|
}
|
||||||
|
get actionWorker() {
|
||||||
|
return this._actionWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
_changeState(ids, sateteId, stateName, index) {
|
||||||
|
this.$http.put(`/production/api/TicketStates/${sateteId}/changeState`, {tickets: ids}).then(
|
||||||
|
() => {
|
||||||
|
index.forEach(
|
||||||
|
i => {
|
||||||
|
this.tickets[i].state = stateName;
|
||||||
|
this.tickets[i].stateFk = sateteId;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_sendMessage(tickets) {
|
||||||
|
this.$http.post(`/production/api/FakeProductions/messageSend`, {tickets: tickets}).then(
|
||||||
|
() => {
|
||||||
|
this.vnApp.showMessage(this.$translate.instant('Success: message send!'));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_changeTime(ids, time, index) {
|
||||||
|
this.$http.put(`/production/api/Tickets/${time}/changeTime`, {tickets: ids}).then(
|
||||||
|
() => {
|
||||||
|
index.forEach(
|
||||||
|
i => {
|
||||||
|
this.tickets[i].hour = time;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_changeWorker(ids, workerFk, index) {
|
||||||
|
this.$http.put(`/production/api/Tickets/${workerFk}/changeWorker`, {tickets: ids}).then(
|
||||||
|
() => {
|
||||||
|
index.forEach(
|
||||||
|
i => {
|
||||||
|
this.tickets[i].workerFk = this.actionWorker.id;
|
||||||
|
this.tickets[i].worker = this.actionWorker.name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
doAction(actionName) {
|
||||||
|
let ids = [];
|
||||||
|
let index = [];
|
||||||
|
let tickets = [];
|
||||||
|
this.tickets.forEach(
|
||||||
|
(val, i) => {
|
||||||
|
if (val.checked) {
|
||||||
|
ids.push(val.ticketFk);
|
||||||
|
index.push(i);
|
||||||
|
tickets.push({ticketFk: val.ticketFk, salesPerson: val.salesPerson});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (tickets.length) {
|
||||||
|
switch (actionName) {
|
||||||
|
case 'changeState' :
|
||||||
|
this._changeState(ids, this.actionState.id, this.actionState.name, index);
|
||||||
|
break;
|
||||||
|
case 'addComment':
|
||||||
|
this._sendMessage(tickets);
|
||||||
|
break;
|
||||||
|
case 'markPrinted':
|
||||||
|
this._changeState(ids, 4, 'Impreso', index);
|
||||||
|
break;
|
||||||
|
case 'changeTime':
|
||||||
|
this._changeTime(ids, this.actionHours.name, index);
|
||||||
|
break;
|
||||||
|
case 'changeWorker':
|
||||||
|
this._changeWorker(ids, this.actionWorker.id, index);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.vnApp.showMessage(this.$translate.instant('Error: Action not implemented!'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.vnApp.showMessage(this.$translate.instant('Error: No tickets selected!'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductionActions.$inject = ['$http', '$translate', 'vnApp'];
|
||||||
|
|
||||||
|
ngModule.component('vnProductionActions', {
|
||||||
|
template: require('./production-actions.html'),
|
||||||
|
bindings: {
|
||||||
|
tickets: '<',
|
||||||
|
states: '<',
|
||||||
|
hourItems: '<'
|
||||||
|
},
|
||||||
|
controller: ProductionActions
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
<form ng-submit="$ctrl.onComment($ctrl.ids, $ctrl.comment)" pad-large>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textfield vn-one label="Message" model="$ctrl.comment"></vn-textfield>
|
||||||
|
<vn-submit vn-none pad-small-top label="Send"></vn-submit>
|
||||||
|
</vn-horizontal>
|
||||||
|
</form>
|
|
@ -0,0 +1,5 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
|
||||||
|
ngModule.component('vnProductionComment', {
|
||||||
|
template: require('./production-comment.html')
|
||||||
|
});
|
|
@ -0,0 +1,30 @@
|
||||||
|
<form ng-submit="$ctrl.onSubmit($ctrl.filter)" pad-large>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textfield vn-one label="Route ID" model="$ctrl.filter.routeFk"></vn-textfield>
|
||||||
|
<vn-date-picker vn-one label="Date" model="$ctrl.filter.date"></vn-date-picker>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-autocomplete vn-one
|
||||||
|
field="$ctrl.filter.provinceFk"
|
||||||
|
url="/client/api/Provinces"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id"
|
||||||
|
label="Province">
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete vn-one
|
||||||
|
data="$ctrl.data.hourItems"
|
||||||
|
label="Hour"
|
||||||
|
value-field="name"
|
||||||
|
field="$ctrl.filter.hour"
|
||||||
|
>
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-autocomplete vn-one margin-medium-right field="$ctrl.filter.stateFk" data="$ctrl.data.states" label="State"></vn-autocomplete>
|
||||||
|
<vn-autocomplete vn-one margin-medium-right field="$ctrl.filter.agencyFk" url="/production/api/Agencies" label="Agency"></vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal margin-large-top>
|
||||||
|
<vn-submit vn-one label="Filter"></vn-submit>
|
||||||
|
<vn-button vn-none label="Cancel" ng-click="$ctrl.onCancel()"></vn-button>
|
||||||
|
</vn-horizontal>
|
||||||
|
</form>
|
|
@ -0,0 +1,6 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
ngModule.component('vnProductionFilterPanel', {
|
||||||
|
template: require('./production-filters.html')
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
vn-production-filter-panel{
|
||||||
|
.mdl-button--colored{
|
||||||
|
color: #ffa410 !important;
|
||||||
|
background-color: white !important;
|
||||||
|
}
|
||||||
|
.mdl-button--colored:hover{
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
|
||||||
|
<vn-none min-none></vn-none>
|
||||||
|
<vn-colum-header vn-none min-none>
|
||||||
|
<vn-multi-check models="$ctrl.tickets" options="[{id:'all',name:'Todos'},{id:'any',name:'Ninguno'},{id:'problem',name:'Con incidencia'},{id:'no-problem',name:'Sin incidencia'}]"></vn-multi-check>
|
||||||
|
</vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="ticketFk" text="Ticket ID"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-two pad-medium-h field="agency" text="Agency"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="routeFk" text="Route ID"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-two pad-medium-h field="salesPerson" text="Commercial"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="hour" text="Hour"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="state" text="State"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="lines" text="Lines"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="m3" text="m3"></vn-colum-header>
|
||||||
|
<vn-colum-header vn-one pad-medium-h field="boxes" text="Boxes"></vn-colum-header>
|
||||||
|
<vn-none min-none></vn-none>
|
||||||
|
</vn-grid-header>
|
||||||
|
<vn-one class="list list-content">
|
||||||
|
<vn-horizontal vn-one class="list list-element text-center" ng-repeat="ticket in $ctrl.pageTable.model track by ticket.id" ng-class="{warning: ticket.problem==='RIESGO'}">
|
||||||
|
<vn-none>
|
||||||
|
<vn-icon margin-small-left icon="report_problem" ng-if="ticket.problem" vn-tooltip="{{ticket.problem}}" tooltip-position="right"></vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
<vn-none>
|
||||||
|
<vn-check model="ticket.checked"></vn-check>
|
||||||
|
</vn-none>
|
||||||
|
<vn-one pad-medium-h>{{::ticket.ticketFk}}</vn-one>
|
||||||
|
<vn-two pad-medium-h>{{::ticket.agency}}</vn-two>
|
||||||
|
<vn-one pad-medium-h>{{::ticket.routeFk}}</vn-one>
|
||||||
|
<vn-two pad-medium-h>{{::ticket.salesPerson | ucwords}}</vn-two>
|
||||||
|
<vn-one pad-medium-h>{{ticket.hour}}</vn-one>
|
||||||
|
<vn-one pad-medium-h>{{ticket.state}}</vn-one>
|
||||||
|
<vn-one pad-medium-h>{{::ticket.lines}}</vn-one>
|
||||||
|
<vn-one pad-medium-h>{{::ticket.m3}}</vn-one>
|
||||||
|
<vn-one pad-medium-h>{{::ticket.boxes}}</vn-one>
|
||||||
|
<vn-none>
|
||||||
|
<vn-icon icon="more" vn-tooltip tooltip-template="/static/templates/tooltip.locator.tpl.html" tooltip-position="left"></vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-one>
|
||||||
|
<vn-horizontal vn-one class="list list-footer">
|
||||||
|
<vn-none></vn-none>
|
||||||
|
<vn-none></vn-none>
|
||||||
|
<vn-one pad-medium-h>
|
||||||
|
<span translate="Resultados"></span>:
|
||||||
|
<span>{{$ctrl.footer.total}}</span>
|
||||||
|
</vn-one>
|
||||||
|
<vn-seven pad-medium-h></vn-seven>
|
||||||
|
<vn-one pad-medium-h text-center>{{$ctrl.footer.lines}}</vn-one>
|
||||||
|
<vn-one pad-medium-h text-center>{{$ctrl.footer.meters}}</vn-one>
|
||||||
|
<vn-one></vn-one>
|
||||||
|
<vn-none></vn-none>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-one>
|
||||||
|
<vn-paging page-change="$ctrl.pageTickets()" index="$ctrl.pageTable" total="$ctrl.totalFilter"></vn-paging>
|
||||||
|
</vn-one>
|
||||||
|
</vn-vertical>
|
|
@ -0,0 +1,46 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
|
||||||
|
export class ProductionTable {
|
||||||
|
constructor($filter) {
|
||||||
|
this.$filter = $filter;
|
||||||
|
this._tickets = [];
|
||||||
|
this.itemsDisplayedInList = 14;
|
||||||
|
this.pageTable = {
|
||||||
|
filter: {
|
||||||
|
page: 1,
|
||||||
|
size: this.itemsDisplayedInList
|
||||||
|
},
|
||||||
|
model: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
set tickets(value) {
|
||||||
|
this._tickets = value;
|
||||||
|
this.totalFilter = this._tickets.length;
|
||||||
|
this.pageTable.filter.page = 1;
|
||||||
|
this.pageTickets();
|
||||||
|
}
|
||||||
|
get tickets() {
|
||||||
|
return this._tickets;
|
||||||
|
}
|
||||||
|
onOrder(field, order) {
|
||||||
|
let reverse = order === 'DESC';
|
||||||
|
this.tickets = this.$filter('orderBy')(this.tickets, field, reverse);
|
||||||
|
this.pageTickets();
|
||||||
|
}
|
||||||
|
pageTickets() {
|
||||||
|
let init = (this.pageTable.filter.page - 1) * this.itemsDisplayedInList;
|
||||||
|
let fin = this.pageTable.filter.page * this.itemsDisplayedInList;
|
||||||
|
this.pageTable.model = this.tickets.slice(init, fin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductionTable.$inject = ['$filter'];
|
||||||
|
|
||||||
|
ngModule.component('vnProductionTable', {
|
||||||
|
template: require('./production-table.html'),
|
||||||
|
bindings: {
|
||||||
|
tickets: '=',
|
||||||
|
footer: '<'
|
||||||
|
},
|
||||||
|
controller: ProductionTable
|
||||||
|
});
|
|
@ -3,4 +3,6 @@ export * from './module';
|
||||||
|
|
||||||
// import components
|
// import components
|
||||||
import './index/index';
|
import './index/index';
|
||||||
import './filter-panel/filter-panel';
|
import './production-filters/production-filters';
|
||||||
|
import './production-actions/production-actions';
|
||||||
|
import './production-table/production-table';
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<vn-icon icon="account_circle" translate-attr="{title: 'Profile'}" style="font-size: 35px;"></vn-icon>
|
<vn-icon icon="account_circle" translate-attr="{title: 'Profile'}" style="font-size: 35px;"></vn-icon>
|
||||||
<ul class="mdl-menu mdl-js-menu mdl-menu--bottom-right" pad-medium for="apps">
|
<ul class="mdl-menu mdl-js-menu mdl-menu--bottom-right" pad-medium for="apps">
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<div ng-repeat="mod in $ctrl.modules">
|
<div ng-repeat="mod in $ctrl.modules track by $index" margin-medium-right>
|
||||||
<vn-vertical>
|
<vn-vertical>
|
||||||
<a ui-sref="{{::mod.route.state}}">
|
<a ui-sref="{{::mod.route.state}}">
|
||||||
<button vn-one class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored popover-button">
|
<button vn-one class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored popover-button">
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-textfield vn-one label="Search" model="$ctrl.search"></vn-textfield>
|
<vn-textfield vn-one label="Search" model="$ctrl.search"></vn-textfield>
|
||||||
<vn-icon
|
<vn-icon
|
||||||
|
pad-medium-top
|
||||||
ng-if="$ctrl.advanced"
|
ng-if="$ctrl.advanced"
|
||||||
ng-click="$ctrl.onClick($event)"
|
ng-click="$ctrl.onClick($event)"
|
||||||
icon="keyboard_arrow_down"
|
icon="keyboard_arrow_down"
|
||||||
|
|
|
@ -10,9 +10,7 @@ export default class Controller {
|
||||||
this.$window = $window;
|
this.$window = $window;
|
||||||
}
|
}
|
||||||
onClick(event) {
|
onClick(event) {
|
||||||
var child = this.$document[0].createElement(this.popover);
|
var child = this.vnPopover.showComponent(this.popover, this.$scope, this.element);
|
||||||
this.$compile(child)(this.$scope);
|
|
||||||
this.vnPopover.show(child, this.element);
|
|
||||||
|
|
||||||
// XXX: ¿Existe una forma más adecuada de acceder al controlador de un componente?
|
// XXX: ¿Existe una forma más adecuada de acceder al controlador de un componente?
|
||||||
var childCtrl = angular.element(child).isolateScope().$ctrl;
|
var childCtrl = angular.element(child).isolateScope().$ctrl;
|
||||||
|
|
|
@ -3,10 +3,10 @@ import deps from 'spliting/modules.json';
|
||||||
import ngModule from './module';
|
import ngModule from './module';
|
||||||
import {splitingRegister} from 'core';
|
import {splitingRegister} from 'core';
|
||||||
|
|
||||||
function loader(moduleName) {
|
function loader(moduleName, validations) {
|
||||||
load.$inject = ['vnModuleLoader'];
|
load.$inject = ['vnModuleLoader'];
|
||||||
function load(moduleLoader) {
|
function load(moduleLoader) {
|
||||||
return moduleLoader.load(moduleName);
|
return moduleLoader.load(moduleName, validations);
|
||||||
}
|
}
|
||||||
return load;
|
return load;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ function config($stateProvider, $urlRouterProvider, aclServiceProvider) {
|
||||||
for (let file in routes) {
|
for (let file in routes) {
|
||||||
let fileRoutes = routes[file].routes;
|
let fileRoutes = routes[file].routes;
|
||||||
let moduleName = routes[file].module;
|
let moduleName = routes[file].module;
|
||||||
|
let validations = routes[file].validations || false;
|
||||||
fileRoutes.forEach(function(route) {
|
fileRoutes.forEach(function(route) {
|
||||||
if (aclService.routeHasPermission(route)) {
|
if (aclService.routeHasPermission(route)) {
|
||||||
$stateProvider.state(route.state, {
|
$stateProvider.state(route.state, {
|
||||||
|
@ -47,7 +48,7 @@ function config($stateProvider, $urlRouterProvider, aclServiceProvider) {
|
||||||
abstract: route.abstract || false,
|
abstract: route.abstract || false,
|
||||||
template: `<${route.component} ${getParams(route)}></${route.component}>`,
|
template: `<${route.component} ${getParams(route)}></${route.component}>`,
|
||||||
resolve: {
|
resolve: {
|
||||||
loader: loader(moduleName)
|
loader: loader(moduleName, validations)
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
routes: fileRoutes
|
routes: fileRoutes
|
||||||
|
|
|
@ -4,4 +4,5 @@ $color-orange: rgb(255,171,64);
|
||||||
$color-white: white;
|
$color-white: white;
|
||||||
$color-dark: #3c393b;
|
$color-dark: #3c393b;
|
||||||
$color-dark-grey: #424242;
|
$color-dark-grey: #424242;
|
||||||
$color-light-grey: #e6e6e6;
|
$color-light-grey: #e6e6e6;
|
||||||
|
$color-medium-grey: #9D9D9D;
|
|
@ -1,5 +1,6 @@
|
||||||
@import "padding";
|
@import "padding";
|
||||||
@import "margin";
|
@import "margin";
|
||||||
|
@import "colors";
|
||||||
|
|
||||||
.form {
|
.form {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -29,4 +30,68 @@ vn-button-bar {
|
||||||
}
|
}
|
||||||
html [text-center], .text-center {
|
html [text-center], .text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
html [text-right], .text-right{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
html [text-left], .text-left{
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
html [vn-right], .vn-right{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
html [vn-left], .vn-left{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
html [vn-center], .vn-center{
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list > vn-none{
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-element{
|
||||||
|
padding: 4px 0px;
|
||||||
|
border-bottom: 1px solid $color-medium-grey;
|
||||||
|
i {
|
||||||
|
color: $color-orange;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background-color: $color-light-grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tooltip {
|
||||||
|
.list-header{
|
||||||
|
border-bottom: 3px solid $color-medium-grey;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
.list-element{
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-footer{
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: 3px solid $color-medium-grey;
|
||||||
|
}
|
||||||
|
.list-element.warning{
|
||||||
|
background-color: $color-orange;
|
||||||
|
color:$color-white;
|
||||||
|
font-weight: bold;
|
||||||
|
i {
|
||||||
|
color: $color-white;
|
||||||
|
}
|
||||||
|
.mdl-checkbox.is-checked .mdl-checkbox__box-outline{
|
||||||
|
border-color: $color-white;
|
||||||
|
}
|
||||||
|
.mdl-checkbox.is-checked .mdl-checkbox__tick-outline{
|
||||||
|
background-color: $color-white;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatpickr-month, .flatpickr-weekdays, span.flatpickr-weekday {
|
||||||
|
background-color: $color-orange;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import Flatpickr from 'flatpickr';
|
||||||
|
import 'flatpickr/dist/flatpickr.min.css';
|
||||||
|
import 'flatpickr/dist/themes/material_orange.css';
|
||||||
|
import localeEs from 'flatpickr/dist/l10n/es';
|
||||||
|
Flatpickr.l10ns.es = localeEs.es;
|
||||||
|
export default Flatpickr;
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"loopback-component-explorer": {
|
||||||
|
"mountPath": "/explorer"
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,9 +36,9 @@ gulp.task('client', ['clean'], function() {
|
||||||
|
|
||||||
gulp.task('copy', function() {
|
gulp.task('copy', function() {
|
||||||
var streams = [];
|
var streams = [];
|
||||||
for (i=0; i < services.services.length; i++) {
|
for (i = 0; i < services.services.length; i++) {
|
||||||
var service = services.services[i];
|
var service = services.services[i];
|
||||||
for (j=0; j < services.files.length; j++) {
|
for (j = 0; j < services.files.length; j++) {
|
||||||
var file = services.files[j];
|
var file = services.files[j];
|
||||||
streams.push(gulp.src("./services/service/models/" + file)
|
streams.push(gulp.src("./services/service/models/" + file)
|
||||||
.pipe(gulp.dest(service + "/common/models/")));
|
.pipe(gulp.dest(service + "/common/models/")));
|
||||||
|
@ -52,13 +52,13 @@ gulp.task('services', ['copy'], function() {
|
||||||
require('./services/salix/server/server.js').start();
|
require('./services/salix/server/server.js').start();
|
||||||
require('./services/mailer/server.js').start();
|
require('./services/mailer/server.js').start();
|
||||||
|
|
||||||
for (i=0; i < services.services.length; i++) {
|
for (i = 0; i < services.services.length; i++) {
|
||||||
require(services.services[i] + "/server/server.js").start();
|
require(services.services[i] + "/server/server.js").start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('clean', function() {
|
gulp.task('clean', function() {
|
||||||
return del(`${buildDir}/*`, {force: true});
|
return del([`${buildDir}/*`, `!${buildDir}/templates`], {force: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Spliting
|
// Spliting
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"angular-paging": "^2.2.2",
|
"angular-paging": "^2.2.2",
|
||||||
"angular-translate": "^2.13.1",
|
"angular-translate": "^2.13.1",
|
||||||
"angular-translate-loader-partial": "^2.13.1",
|
"angular-translate-loader-partial": "^2.13.1",
|
||||||
|
"flatpickr": "^2.6.3",
|
||||||
"material-design-lite": "^1.3.0",
|
"material-design-lite": "^1.3.0",
|
||||||
"mg-crud": "^1.1.2",
|
"mg-crud": "^1.1.2",
|
||||||
"oclazyload": "^0.6.3",
|
"oclazyload": "^0.6.3",
|
||||||
|
|
|
@ -41,9 +41,7 @@ module.exports = function(Client){
|
||||||
};
|
};
|
||||||
|
|
||||||
Client.app.models.Address.find(filter, function(err, instances) {
|
Client.app.models.Address.find(filter, function(err, instances) {
|
||||||
if(!err) {
|
(err)? cb(err, null) : cb(null, instances);
|
||||||
cb(null, instances);
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
module.exports = function(Client){
|
||||||
|
Client.remoteMethod('employeeList', {
|
||||||
|
description: 'List employee',
|
||||||
|
accessType: 'READ',
|
||||||
|
returns: {
|
||||||
|
arg: 'data',
|
||||||
|
type: 'Employee',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/employeeList`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Client.employeeList = function(cb) {
|
||||||
|
var include = {include: { relation: 'user'}, where: { userFk: { neq: null }}};
|
||||||
|
Client.app.models.Employee.find(include, function(err, instances) {
|
||||||
|
(err) ? cb(err, null) : cb(null, generateEmployees(instances));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateEmployees(instances){
|
||||||
|
var emps = [];
|
||||||
|
instances.forEach(function(e) {
|
||||||
|
emps.push({id: e.id, name: e.user().name});
|
||||||
|
}, this);
|
||||||
|
return emps;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ module.exports = function(Address) {
|
||||||
function getAddress(ctx, data, next){
|
function getAddress(ctx, data, next){
|
||||||
var address = Address.findOne( {where: { id: data.id}}, function (err, address){
|
var address = Address.findOne( {where: { id: data.id}}, function (err, address){
|
||||||
if(address)
|
if(address)
|
||||||
callbackGetAddress(ctx, data, address, next)
|
callbackGetAddress(ctx, data, address, next);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ module.exports = function(Client) {
|
||||||
require('../methods/client/addresses.js')(Client);
|
require('../methods/client/addresses.js')(Client);
|
||||||
require('../methods/client/filter.js')(Client);
|
require('../methods/client/filter.js')(Client);
|
||||||
require('../methods/client/before-save.js')(Client);
|
require('../methods/client/before-save.js')(Client);
|
||||||
|
require('../methods/client/employee.js')(Client);
|
||||||
|
|
||||||
// Validations
|
// Validations
|
||||||
|
|
||||||
|
@ -28,15 +29,18 @@ module.exports = function(Client) {
|
||||||
Client.validatesFormatOf('postcode', {
|
Client.validatesFormatOf('postcode', {
|
||||||
message: 'El código postal solo debe contener números',
|
message: 'El código postal solo debe contener números',
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
|
allowBlank: true,
|
||||||
with: /^\d+$/
|
with: /^\d+$/
|
||||||
});
|
});
|
||||||
Client.validatesFormatOf('email', {
|
Client.validatesFormatOf('email', {
|
||||||
message: 'Correo electrónico inválido',
|
message: 'Correo electrónico inválido',
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
|
allowBlank: true,
|
||||||
with: /^[\w|\.|\-]+@\w[\w|\.|\-]*\w(,[\w|\.|\-]+@\w[\w|\.|\-]*\w)*$/
|
with: /^[\w|\.|\-]+@\w[\w|\.|\-]*\w(,[\w|\.|\-]+@\w[\w|\.|\-]*\w)*$/
|
||||||
});
|
});
|
||||||
Client.validatesLengthOf('postcode', {
|
Client.validatesLengthOf('postcode', {
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
|
allowBlank: true,
|
||||||
min: 3, max: 10
|
min: 3, max: 10
|
||||||
});
|
});
|
||||||
Client.validatesLengthOf('iban', {
|
Client.validatesLengthOf('iban', {
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
"type": "Number"
|
"type": "Number"
|
||||||
},
|
},
|
||||||
"vies": {
|
"vies": {
|
||||||
"type": "Number"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"isRelevant": {
|
"isRelevant": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
|
|
@ -1,31 +1,126 @@
|
||||||
|
|
||||||
module.exports = function(self) {
|
module.exports = function(self) {
|
||||||
self.setup = function() {
|
self.setup = function() {
|
||||||
self.super_.setup.call(this);
|
self.super_.setup.call(this);
|
||||||
|
|
||||||
let disableMethods = {
|
let disableMethods = {
|
||||||
'create': true,
|
create: true,
|
||||||
'replaceOrCreate': true,
|
replaceOrCreate: true,
|
||||||
'patchOrCreate': true,
|
patchOrCreate: true,
|
||||||
'upsert': true,
|
upsert: true,
|
||||||
'updateOrCreate': true,
|
updateOrCreate: true,
|
||||||
'exists': true,
|
exists: true,
|
||||||
'find': true,
|
find: true,
|
||||||
'findOne': true,
|
findOne: true,
|
||||||
'findById': true,
|
findById: true,
|
||||||
'deleteById': true,
|
deleteById: true,
|
||||||
'replaceById': true,
|
replaceById: true,
|
||||||
'updateAttributes': false,
|
updateAttributes: false,
|
||||||
'createChangeStream': true,
|
createChangeStream: true,
|
||||||
'updateAll': true,
|
updateAll: true,
|
||||||
'upsertWithWhere': true,
|
upsertWithWhere: true,
|
||||||
'count': true
|
count: true
|
||||||
};
|
};
|
||||||
|
for (let method in disableMethods) {
|
||||||
for(let method in disableMethods) {
|
|
||||||
//this.disableRemoteMethod(method, disableMethods[method]);
|
//this.disableRemoteMethod(method, disableMethods[method]);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
self.defineScope = function(serverFilter) {
|
||||||
|
this.remoteMethodCtx('list', {
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'object',
|
||||||
|
description: 'Filter defining where'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: [this.modelName],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
verb: 'get',
|
||||||
|
path: '/list'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.list = function(ctx, clientFilter, cb) {
|
||||||
|
var clientFields = (clientFilter && clientFilter.fields) ? clientFilter.fields : [];
|
||||||
|
var serverFields = (serverFilter && serverFilter.fields) ? serverFilter.fields : [];
|
||||||
|
var fields = clientFields.filter(itemC => {
|
||||||
|
return serverFields.some(itemS => itemS === itemC);
|
||||||
|
});
|
||||||
|
|
||||||
|
var and = [];
|
||||||
|
(clientFilter && clientFilter.where) && and.push(clientFilter.where);
|
||||||
|
(serverFilter && serverFilter.where) && and.push(serverFilter.where);
|
||||||
|
|
||||||
|
var order;
|
||||||
|
var limit;
|
||||||
|
|
||||||
|
if (clientFilter && clientFilter.order)
|
||||||
|
order = clientFilter.order;
|
||||||
|
else if (serverFilter && serverFilter.order)
|
||||||
|
order = serverFilter.order;
|
||||||
|
|
||||||
|
if (serverFilter && serverFilter.limit)
|
||||||
|
limit = serverFilter.limit;
|
||||||
|
else if (clientFilter && clientFilter.limit)
|
||||||
|
limit = clientFilter.limit;
|
||||||
|
|
||||||
|
var filter = {order: order, limit: limit};
|
||||||
|
filter.where = (and.length > 0) && {and: and};
|
||||||
|
filter.fields = fields;
|
||||||
|
|
||||||
|
this.find(filter, function(err, states) {
|
||||||
|
(err) ? cb(err, null) : cb(null, states);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
self.rawSql = function(query, params, cb) {
|
||||||
|
var connector = this.dataSource.connector;
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
connector.execute(query, params, function(error, response) {
|
||||||
|
if (error && !reject)
|
||||||
|
cb(error, null);
|
||||||
|
else if (error && reject)
|
||||||
|
reject(error);
|
||||||
|
else
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.remoteMethodCtx = function(methodName, args) {
|
||||||
|
var ctx = {
|
||||||
|
arg: 'context',
|
||||||
|
type: 'object',
|
||||||
|
http: function(ctx) {
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (args.accepts === undefined)
|
||||||
|
args.accepts = [];
|
||||||
|
else if (!Array.isArray(args.accepts))
|
||||||
|
args.accepts = [args.accepts];
|
||||||
|
args.accepts.unshift(ctx);
|
||||||
|
this.remoteMethod(methodName, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.connectToService = function(ctx, dataSource) {
|
||||||
|
this.app.dataSources[dataSource].connector.remotes.auth = {
|
||||||
|
bearer: new Buffer(ctx.req.accessToken.id).toString('base64'),
|
||||||
|
sendImmediately: true
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
self.disconnectFromService = function(dataSource) {
|
||||||
|
this.app.dataSources[dataSource].connector.remotes.auth = {
|
||||||
|
bearer: new Buffer("").toString('base64'),
|
||||||
|
sendImmediately: true
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
self.installMethod = function(methodName, filterCb) {
|
self.installMethod = function(methodName, filterCb) {
|
||||||
this.remoteMethod(methodName, {
|
this.remoteMethod(methodName, {
|
||||||
|
@ -43,7 +138,7 @@ module.exports = function(self) {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
arg: 'data',
|
arg: 'data',
|
||||||
type: [this.modelName],
|
type: [this.modelName],
|
||||||
root: true
|
root: true
|
||||||
},
|
},
|
||||||
|
@ -55,65 +150,56 @@ module.exports = function(self) {
|
||||||
|
|
||||||
this[methodName] = (params, cb) => {
|
this[methodName] = (params, cb) => {
|
||||||
let filter = removeEmpty(filterCb(params));
|
let filter = removeEmpty(filterCb(params));
|
||||||
var response = {}
|
var response = {};
|
||||||
|
|
||||||
function returnValues(){
|
function returnValues() {
|
||||||
if(response.instances !== undefined && response.count !== undefined)
|
if (response.instances !== undefined && response.count !== undefined)
|
||||||
cb(null, response);
|
cb(null, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
function error(){
|
function error() {
|
||||||
cb(null, response);
|
cb(null, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.find(filter, function(err, instances) {
|
this.find(filter, function(err, instances) {
|
||||||
if(!err){
|
if (err) {
|
||||||
|
error();
|
||||||
|
} else {
|
||||||
response.instances = instances;
|
response.instances = instances;
|
||||||
returnValues();
|
returnValues();
|
||||||
}
|
}
|
||||||
else{
|
});
|
||||||
|
this.count(filter.where, function(err, totalCount) {
|
||||||
|
if (err) {
|
||||||
error();
|
error();
|
||||||
}
|
} else {
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
this.count(filter.where, function(err, totalCount){
|
|
||||||
if(!err){
|
|
||||||
response.count = totalCount;
|
response.count = totalCount;
|
||||||
returnValues();
|
returnValues();
|
||||||
}
|
}
|
||||||
else{
|
});
|
||||||
error();
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
function removeEmpty(o) {
|
function removeEmpty(o) {
|
||||||
if(Array.isArray(o)) {
|
if (Array.isArray(o)) {
|
||||||
let array = [];
|
let array = [];
|
||||||
for(let item of o) {
|
for (let item of o) {
|
||||||
let i = removeEmpty(item);
|
let i = removeEmpty(item);
|
||||||
if(!isEmpty(item))
|
if (!isEmpty(item))
|
||||||
array.push(item);
|
array.push(item);
|
||||||
};
|
|
||||||
if(array.length > 0)
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
else if (typeof o === 'object') {
|
|
||||||
let object = {};
|
|
||||||
for(let key in o) {
|
|
||||||
let i = removeEmpty(o[key]);
|
|
||||||
if(!isEmpty(i))
|
|
||||||
object[key] = i;
|
|
||||||
}
|
}
|
||||||
if(Object.keys(object).length > 0)
|
if (array.length > 0)
|
||||||
|
return array;
|
||||||
|
} else if (typeof o === 'object') {
|
||||||
|
let object = {};
|
||||||
|
for (let key in o) {
|
||||||
|
let i = removeEmpty(o[key]);
|
||||||
|
if (!isEmpty(i))
|
||||||
|
object[key] = i;
|
||||||
|
}
|
||||||
|
if (Object.keys(object).length > 0)
|
||||||
return object;
|
return object;
|
||||||
}
|
} else if (!isEmpty(o))
|
||||||
else if (!isEmpty(o))
|
|
||||||
return o;
|
return o;
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
"id": true,
|
"id": true,
|
||||||
"type": "Number",
|
"type": "Number",
|
||||||
"forceId": false
|
"forceId": false
|
||||||
|
},
|
||||||
|
"username":{
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,6 +25,7 @@ app.start = function() {
|
||||||
app.emit('started');
|
app.emit('started');
|
||||||
var baseUrl = app.get('url').replace(/\/$/, '');
|
var baseUrl = app.get('url').replace(/\/$/, '');
|
||||||
console.log('Web server listening at: %s', baseUrl);
|
console.log('Web server listening at: %s', baseUrl);
|
||||||
|
|
||||||
if (app.get('loopback-component-explorer')) {
|
if (app.get('loopback-component-explorer')) {
|
||||||
var explorerPath = app.get('loopback-component-explorer').mountPath;
|
var explorerPath = app.get('loopback-component-explorer').mountPath;
|
||||||
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
|
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "MailServer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3003,
|
||||||
|
"debug": true,
|
||||||
|
"defaultLanguage": "es",
|
||||||
|
"senderMail": "noreply@localhost",
|
||||||
|
"senderName": ""
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 3306,
|
||||||
|
"user": "reports",
|
||||||
|
"password": "",
|
||||||
|
"database": ""
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 465,
|
||||||
|
"secure": true,
|
||||||
|
"auth": {
|
||||||
|
"user": "noreply",
|
||||||
|
"pass": ""
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"rejectUnauthorized": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var mail = require('../mail.js');
|
||||||
|
var database = require('../database.js');
|
||||||
|
var template = require('../template.js');
|
||||||
|
|
||||||
|
// Escrito de cambios en méto de pago del cliente
|
||||||
|
router.post('/:userId/payment-update', function(request, response, next) {
|
||||||
|
database.pool.query('SELECT `e-mail` AS email, LOWER(p.Codigo) AS countryCode FROM Clientes AS c JOIN Paises AS p ON p.id = c.Id_Pais WHERE Id_Cliente = ?', [request.params.userId], function(error, qryRs) {
|
||||||
|
if (qryRs.length == 0)
|
||||||
|
return response.json({data: {message: 'Client not found'}});
|
||||||
|
|
||||||
|
template.getTemplate('payment-update', qryRs[0].countryCode, {userId: request.params.userId}, function(tplRs, error) {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
mail.send(qryRs[0].email, tplRs.subject, tplRs.body, tplRs.attachments, (mailrs, error) => {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
return response.json({data: {message: 'Mail sent'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,28 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var mail = require('../mail.js');
|
||||||
|
var database = require('../database.js');
|
||||||
|
var template = require('../template.js');
|
||||||
|
|
||||||
|
router.get('/:userId/notice', function(request, response) {
|
||||||
|
database.pool.query('SELECT `e-mail` AS email, LOWER(p.Codigo) AS countryCode FROM Clientes AS c JOIN Paises AS p ON p.id = c.Id_Pais WHERE Id_Cliente = ?', [request.params.userId], function(error, qryRs) {
|
||||||
|
if (qryRs.length == 0)
|
||||||
|
return response.json({data: {message: 'Client not found'}});
|
||||||
|
|
||||||
|
template.getTemplate('notice', qryRs[0].countryCode, {userId: request.params.userId}, function(tplRs, error) {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
mail.send(qryRs[0].email, tplRs.subject, tplRs.body, tplRs.attachments, (mailrs, error) => {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
return response.json({data: {message: 'Mail sent'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
response.send(request.params.userid);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,35 @@
|
||||||
|
let database = require('../database.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el iban
|
||||||
|
* @param {String} addressNumber - Dirección de cuenta bancaria
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
accountAddressIban: function(addressNumber, cb) {
|
||||||
|
database.pool.query('SELECT vn2008.cc_to_iban(?) AS iban', [addressNumber], function(error, result) {
|
||||||
|
cb(result[0].iban);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene el numero de cuenta completo incluyendo iban
|
||||||
|
* @param {String} addressNumber - Dirección de cuenta bancaria
|
||||||
|
* @return {String} Cuenta bancaria formateada
|
||||||
|
*/
|
||||||
|
accountAddress: function(addressNumber) {
|
||||||
|
var formattedAccountAddress = addressNumber.replace(/(.{4})/g, '$1-');
|
||||||
|
return formattedAccountAddress.substring(0, formattedAccountAddress.length - 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el numero de cuenta mostrando únicamente los últimos 4 dígitos.
|
||||||
|
* @param {String} addressNumber - Dirección de cuenta bancaria
|
||||||
|
* @return {String} Cuenta bancaria formateada
|
||||||
|
*/
|
||||||
|
partialAccountAddress: function(addressNumber) {
|
||||||
|
let address = this.accountAddress(addressNumber);
|
||||||
|
return address.substring(0, 19).replace(/[0-9]/g, 'X') + address.substring(19, 24);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Obtiene las variables de entorno
|
||||||
|
* @param {String} env - Nombre de la variable de entorno
|
||||||
|
* @return {String} Valor de la variable de entorno
|
||||||
|
*/
|
||||||
|
getEnv: function(env) {
|
||||||
|
return process.env[env];
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,24 @@
|
||||||
|
var mysql = require('mysql');
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Variable de instancia del pool
|
||||||
|
*/
|
||||||
|
pool: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iniciar pool de conexión con la base de datos
|
||||||
|
*/
|
||||||
|
init: function() {
|
||||||
|
this.pool = mysql.createPool(settings.mysql());
|
||||||
|
|
||||||
|
this.pool.getConnection(function(error, connection) {
|
||||||
|
if (error) {
|
||||||
|
throw new Error('Can\'t connect to database: ' + error.code);
|
||||||
|
} else if (settings.app().debug) {
|
||||||
|
console.log('Database connection stablished');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Devuelve las claves de idioma de una plantilla
|
||||||
|
* @param {String} template - Nombre de la plantilla
|
||||||
|
* @param {String} countryCode - Código de idioma
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
load: function(template, countryCode, cb) {
|
||||||
|
var localeFile = path.join(__dirname, 'template', `${template}`, 'locale', `${countryCode}.json`);
|
||||||
|
var defaultLocaleFile = path.join(__dirname, 'template', `${template}`, 'locale', `${settings.app().defaultLanguage}.json`);
|
||||||
|
|
||||||
|
fs.stat(localeFile, (error, stats) => {
|
||||||
|
if (error)
|
||||||
|
fs.stat(defaultLocaleFile, (error, stats) => {
|
||||||
|
if (error)
|
||||||
|
cb(null, 'Translation not found for template ' + template + '.');
|
||||||
|
return cb(require(defaultLocaleFile));
|
||||||
|
});
|
||||||
|
return cb(require(localeFile));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
var nodemailer = require('nodemailer');
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Módulo para el envío de emails
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
transporter: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Si todavía no está inicializada la configuración,
|
||||||
|
* carga el fichero de configuración.
|
||||||
|
*/
|
||||||
|
init: function() {
|
||||||
|
this.transporter = nodemailer.createTransport(settings.smtp());
|
||||||
|
|
||||||
|
this.transporter.verify(function(error, success) {
|
||||||
|
if (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
} else if (settings.app().debug) {
|
||||||
|
console.log('SMTP connection stablished');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envia un email con los datos recibidos desde un vector.
|
||||||
|
* @param {Object} data - Datos para el envío del email
|
||||||
|
*/
|
||||||
|
send: function(recipient, subject, body, attachments, cb) {
|
||||||
|
let mailOptions = {
|
||||||
|
from: '"' + settings.app().senderName + '" <' + settings.app().senderMail + '>',
|
||||||
|
to: recipient,
|
||||||
|
subject: subject,
|
||||||
|
html: body,
|
||||||
|
attachments
|
||||||
|
};
|
||||||
|
|
||||||
|
this.transporter.sendMail(mailOptions, (error, info) => {
|
||||||
|
if (error) {
|
||||||
|
return cb(null, 'Email not sent: ' + error);
|
||||||
|
} else if (settings.app().debug) {
|
||||||
|
console.log('Mail sent ' + info.messageId + ' [' + info.response + ']');
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var mail = require('../mail.js');
|
||||||
|
var database = require('../database.js');
|
||||||
|
var template = require('../template.js');
|
||||||
|
|
||||||
|
// Escrito de cambios en méto de pago del cliente
|
||||||
|
router.post('/:userId/payment-update', function(request, response, next) {
|
||||||
|
database.pool.query('SELECT `e-mail` AS email, LOWER(p.Codigo) AS countryCode FROM Clientes AS c JOIN Paises AS p ON p.id = c.Id_Pais WHERE Id_Cliente = ?', [request.params.userId], function(error, qryRs) {
|
||||||
|
if (qryRs.length == 0)
|
||||||
|
return response.json({data: {message: 'Client not found'}});
|
||||||
|
|
||||||
|
template.getTemplate('payment-update', qryRs[0].countryCode, {userId: request.params.userId}, function(tplRs, error) {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
mail.send(qryRs[0].email, tplRs.subject, tplRs.body, tplRs.attachments, (mailrs, error) => {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
return response.json({data: {message: 'Mail sent'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,28 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var mail = require('../mail.js');
|
||||||
|
var database = require('../database.js');
|
||||||
|
var template = require('../template.js');
|
||||||
|
|
||||||
|
router.get('/:userId/notice', function(request, response) {
|
||||||
|
database.pool.query('SELECT `e-mail` AS email, LOWER(p.Codigo) AS countryCode FROM Clientes AS c JOIN Paises AS p ON p.id = c.Id_Pais WHERE Id_Cliente = ?', [request.params.userId], function(error, qryRs) {
|
||||||
|
if (qryRs.length == 0)
|
||||||
|
return response.json({data: {message: 'Client not found'}});
|
||||||
|
|
||||||
|
template.getTemplate('notice', qryRs[0].countryCode, {userId: request.params.userId}, function(tplRs, error) {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
mail.send(qryRs[0].email, tplRs.subject, tplRs.body, tplRs.attachments, (mailrs, error) => {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
return response.json({data: {message: 'Mail sent'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
response.send(request.params.userid);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,16 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
|
||||||
|
// Mailer default page
|
||||||
|
router.get('/', function(request, response) {
|
||||||
|
response.send(settings.app().name + ' v' + settings.app().version);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manuscripts
|
||||||
|
router.use('/manuscript', require('./route/manuscript.js'));
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
router.use('/notification', require('./route/notification.js'));
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,45 @@
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Módulo de configuración
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Obtiene la configuración en función del entorno en el que se está
|
||||||
|
* ejecutando la aplicación.
|
||||||
|
* @param {String} name Nombre del fichero
|
||||||
|
* @return {Object} Objeto de configuración
|
||||||
|
*/
|
||||||
|
getConfig: function(name) {
|
||||||
|
let env = process.env.NODE_ENV;
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
env = 'development';
|
||||||
|
|
||||||
|
return require(path.join(__dirname, 'config', `${name}.${env}.json`));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de la aplicación
|
||||||
|
* @return {Object} Objeto de configuración app
|
||||||
|
*/
|
||||||
|
app: function() {
|
||||||
|
return this.getConfig('app');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de smtp
|
||||||
|
* @return {Object} Objeto de configuración smtp
|
||||||
|
*/
|
||||||
|
smtp: function() {
|
||||||
|
return this.getConfig('smtp');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de mysql
|
||||||
|
* @return {Object} Objeto de configuración MySQL
|
||||||
|
*/
|
||||||
|
mysql: function() {
|
||||||
|
return this.getConfig('mysql');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,114 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var mustache = require('mustache');
|
||||||
|
var locale = require('./locale.js');
|
||||||
|
var path = require('path');
|
||||||
|
var inlineCss = require('inline-css');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Obtiene la plantilla.
|
||||||
|
* @param {String} template - Nombre de la plantilla
|
||||||
|
* @param {Object} countryCode - Código del idioma
|
||||||
|
* @param {Object} params - Datos a reemplazar.
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
getTemplate: function(template, countryCode, params, cb) {
|
||||||
|
var templatePath = path.join(__dirname, 'template', `${template}`, `${template}.html`);
|
||||||
|
var classPath = path.join(__dirname, 'template', `${template}`, `${template}.js`);
|
||||||
|
var stylePath = path.join(__dirname, 'template', `${template}`, `${template}.css`);
|
||||||
|
|
||||||
|
fs.stat(templatePath, (error, stat) => {
|
||||||
|
if (error)
|
||||||
|
return cb(null, 'Template ' + template + ' not found');
|
||||||
|
|
||||||
|
let TemplateClass = require(classPath);
|
||||||
|
let instance = new TemplateClass();
|
||||||
|
|
||||||
|
let getRenderedStyles = body => {
|
||||||
|
this.renderStyles(stylePath, body, body => {
|
||||||
|
var titleSubject = body.match(new RegExp('<title>(.*?)</title>', 'i'))[1];
|
||||||
|
this.getAttachments(template, body, attachments => {
|
||||||
|
cb({body: body, subject: titleSubject, attachments: attachments});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let getDataCb = () => {
|
||||||
|
this.render(templatePath, instance, body => getRenderedStyles(body));
|
||||||
|
};
|
||||||
|
|
||||||
|
locale.load(template, countryCode, (translations, error) => {
|
||||||
|
instance._ = translations;
|
||||||
|
instance.getData(params, () => getDataCb());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza las plantillas
|
||||||
|
* @param {String} path - Ruta de la plantilla
|
||||||
|
* @param {Object} data - Listado de parámetros a remplazar
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
render: function(path, data, cb) {
|
||||||
|
fs.readFile(path, 'utf8', function(error, body) {
|
||||||
|
mustache.parse(body);
|
||||||
|
cb(mustache.render(body, data));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza los estilos de las plantillas.
|
||||||
|
* @param {String} path - Ruta de la hoja de estilos
|
||||||
|
* @param {String} body - Html renderizado
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
renderStyles: function(path, html, cb) {
|
||||||
|
fs.stat(path, error => {
|
||||||
|
if (error) return cb(null, 'Template stylesheet not found');
|
||||||
|
fs.readFile(path, 'utf8', (error, css) => {
|
||||||
|
let style = '<style>' + css + '</style>';
|
||||||
|
let body = style + html;
|
||||||
|
let options = {url: ' '};
|
||||||
|
|
||||||
|
inlineCss(body, options)
|
||||||
|
.then(function(body) {
|
||||||
|
cb(body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los ficheros adjuntos de la plantilla
|
||||||
|
* @param {String} template - Nombre de la plantilla
|
||||||
|
* @param {String} body - html de la plantilla
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
getAttachments: function(template, body, cb) {
|
||||||
|
var attachments = [];
|
||||||
|
var tplAttachments = body.match(new RegExp('src="cid:(.*?)"', 'ig'));
|
||||||
|
|
||||||
|
for (var i = 0; i < tplAttachments.length; i++) {
|
||||||
|
var name = tplAttachments[i].replace('src="cid:', '').replace('"', '');
|
||||||
|
var attachmentPath = path.join(__dirname, 'template/image', name);
|
||||||
|
|
||||||
|
attachments.push({filename: name, path: attachmentPath, cid: name});
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachmentsPath = path.join(__dirname, 'template', `${template}`, 'attachment.json');
|
||||||
|
|
||||||
|
fs.stat(attachmentsPath, (error, stats) => {
|
||||||
|
if (error) return cb(null, 'Could not load attachments from template ' + template);
|
||||||
|
|
||||||
|
var attachObj = require(attachmentsPath);
|
||||||
|
|
||||||
|
for (var i = 0; i < attachObj.length; i++) {
|
||||||
|
var attachmentPath = path.join(__dirname, 'template', `${template}`, 'attachment', attachObj[i]);
|
||||||
|
attachments.push({filename: attachObj[i], path: attachmentPath, cid: attachObj[i]});
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(attachments);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |