diff --git a/.vscode/launch.json b/.vscode/launch.json index 244fe2b498..825c36d56f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Iniciar", "type": "node", "request": "launch", - "program": "${workspaceRoot}/app.js", + "program": "${workspaceRoot}/services/client/server/server.js", "stopOnEntry": false, "args": [], "cwd": "${workspaceRoot}", diff --git a/Jenkinsfile b/Jenkinsfile index 3d33de37b8..db8dcd4bc6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,14 +7,16 @@ def branchName = "${env.BRANCH_NAME}"; def branchNameTest = "preprod"; def branchNameProd = "master"; 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 dockerSalixName = ["salix", "-p 3001:3001"] def dockerClientName = ["client", "-p 3002:3002"] +def dockerMailerName = ["mailer", "-p 3003:3003"] +def dockerProductionName = ["production", "-p 3004:3004"] def buildNumber = "${env.BUILD_NUMBER}"; -def dockers = [dockerAuthName, dockerSalixName, dockerClientName, dockerNginxName] +def dockers = [dockerAuthName, dockerSalixName, dockerClientName, dockerMailerName, dockerNginxName, dockerProductionName] node { diff --git a/client/client/routes.json b/client/client/routes.json index ecfdc4ea78..488c6c1048 100644 --- a/client/client/routes.json +++ b/client/client/routes.json @@ -2,6 +2,7 @@ "module": "client", "name": "Clients", "icon": "person", + "validations" : true, "routes": [ { "url": "/clients", diff --git a/client/client/src/address-edit/address-edit.html b/client/client/src/address-edit/address-edit.html index 7b6a5d5e80..034f3ba344 100644 --- a/client/client/src/address-edit/address-edit.html +++ b/client/client/src/address-edit/address-edit.html @@ -6,6 +6,7 @@ data="$ctrl.address" form="form"> +
diff --git a/client/client/src/billing-data/billing-data.html b/client/client/src/billing-data/billing-data.html index f43f41e767..a4c2f0b61d 100644 --- a/client/client/src/billing-data/billing-data.html +++ b/client/client/src/billing-data/billing-data.html @@ -5,7 +5,7 @@ form="form" save="patch"> - + Información de facturación @@ -24,7 +24,10 @@ - + + + + diff --git a/client/client/src/billing-data/billing-data.js b/client/client/src/billing-data/billing-data.js index 9537b5590f..f45f22c1c4 100644 --- a/client/client/src/billing-data/billing-data.js +++ b/client/client/src/billing-data/billing-data.js @@ -3,11 +3,11 @@ import ngModule from '../module'; export default class Controller { constructor($scope, $http, $timeout, vnApp, $translate) { this.$ = $scope; - this.http = $http; + this.$http = $http; this.timeout = $timeout; this.vnApp = vnApp; this.translate = $translate; - this.payId = null; + this.payMethodFk = null; this.dueDay = null; this.copyData(); } @@ -16,32 +16,27 @@ export default class Controller { } copyData() { if (this.client) { - this.payId = this.client.payMethodFk || null; + this.payMethodFk = this.client.payMethodFk || null; this.dueDay = this.client.dueDay ? this.client.dueDay : null; } } - checkChanges() { - let payId = this.client.payMethodFk || null; + submit() { + this.$.watcher.submit().then( + () => this.checkPaymentChanges()); + } + checkPaymentChanges() { + let payMethodFk = this.client.payMethodFk || null; let dueDay = this.client.dueDay || null; - if (this.payId !== payId || this.dueDay !== dueDay) { + if (this.payMethodFk !== payMethodFk || this.dueDay !== dueDay) this.$.sendMail.show(); - return false; - } - - return true; } returnDialog(response) { if (response === 'ACCEPT') { - this.sendMail().then( - () => this.vnApp.showMessage(this.translate.instant('Notification sent!')), - () => this.vnApp.showMessage(this.translate.instant('Notification error')) + this.$http.post(`/mailer/manuscript/${this.client.id}/payment-update`).then( + () => this.vnApp.showMessage(this.translate.instant('Notification sent!')) ); } - this.timeout(() => this.$.watcher.submit()); - } - sendMail() { - return this.http.post(`/mailer/manuscript/paymentUpdate`, {user: this.client.id}); } } Controller.$inject = ['$scope', '$http', '$timeout', 'vnApp', '$translate']; diff --git a/client/client/src/index/index.js b/client/client/src/index/index.js index 85c7a34001..38d9996ca2 100644 --- a/client/client/src/index/index.js +++ b/client/client/src/index/index.js @@ -3,6 +3,9 @@ import './style.css'; import './item-client'; export default class Controller { + constructor() { + this.model = {}; + } search(index) { index.filter.search = this.model.search; index.accept(); diff --git a/client/core/src/autocomplete/autocomplete.html b/client/core/src/autocomplete/autocomplete.html index 4d25b25c10..b08702f520 100644 --- a/client/core/src/autocomplete/autocomplete.html +++ b/client/core/src/autocomplete/autocomplete.html @@ -6,5 +6,15 @@ ng-keyup="$ctrl.onKeyup($event)" ng-focus="$ctrl.onFocus($event)" ng-blur="$ctrl.onBlur($event)"/> + diff --git a/client/core/src/autocomplete/autocomplete.js b/client/core/src/autocomplete/autocomplete.js index c46fcebf76..d4d17a54c0 100644 --- a/client/core/src/autocomplete/autocomplete.js +++ b/client/core/src/autocomplete/autocomplete.js @@ -6,12 +6,14 @@ import './style.scss'; * Combobox like component with search and partial data loading features. */ export default class Autocomplete extends Component { - constructor($element, $scope, $http, vnPopover, $transclude) { + constructor($element, $scope, $http, vnPopover, $transclude, $timeout) { super($element); this.input = $element[0].querySelector('input'); this.item = null; - this.data = null; + this.$timeout = $timeout; + // this.data = null; this.popover = null; + this.popoverId = null; this.displayData = null; this.timeoutId = null; this.lastSearch = null; @@ -81,10 +83,12 @@ export default class Autocomplete extends Component { && !this.moreData && textFilter.substr(0, lastRequest.length) === lastRequest; - if (requestWillSame) + if (requestWillSame || !this.url) this.localFilter(textFilter); - else + else if (this.url) this.requestData(textFilter, false); + else + this.setDisplayData(this.data); } getRequestFields() { let fields = {}; @@ -203,14 +207,14 @@ export default class Autocomplete extends Component { e => this.onPopoverMousedown(e)); popover.className = 'vn-autocomplete'; popover.appendChild(fragment); - this.vnPopover.show(popover, this.input); + this.popoverId = this.vnPopover.show(popover, this.input); this.popover = popover; } } hidePopover() { if (!this.popover) return; this.activeOption = -1; - this.vnPopover.hide(); + this.vnPopover.hide(this.popoverId); this.destroyScopes(); this.popover = null; } @@ -242,6 +246,14 @@ export default class Autocomplete extends Component { // Prevents input from loosing focus event.preventDefault(); } + onClear() { + this.setValue(null); + this.$timeout( + () => { + this.mdlUpdate(); + } + ); + } onClick(event) { if (!this.popover) this.showPopover(); @@ -387,6 +399,9 @@ export default class Autocomplete extends Component { if (!this.locked) this.value = value; + + if (this.onChange) + this.onChange({item: item}); } showItem(item) { this.input.value = item ? item[this.showField] : ''; @@ -397,16 +412,18 @@ export default class Autocomplete extends Component { this.destroyScopes(); } } -Autocomplete.$inject = ['$element', '$scope', '$http', 'vnPopover', '$transclude']; +Autocomplete.$inject = ['$element', '$scope', '$http', 'vnPopover', '$transclude', '$timeout']; module.component('vnAutocomplete', { template: require('./autocomplete.html'), bindings: { - url: '@', + url: '@?', showField: '@?', valueField: '@?', selectFields: '@?', initialData: ' + + + {{::$ctrl.text}} + + + + + + + + \ No newline at end of file diff --git a/client/core/src/colum-header/colum-header.js b/client/core/src/colum-header/colum-header.js new file mode 100644 index 0000000000..ad9c57aad6 --- /dev/null +++ b/client/core/src/colum-header/colum-header.js @@ -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 +}); diff --git a/client/core/src/components.js b/client/core/src/components.js index 2c8a096300..9e7b27edec 100644 --- a/client/core/src/components.js +++ b/client/core/src/components.js @@ -14,6 +14,12 @@ import './title/title'; import './subtitle/subtitle'; import './spinner/spinner'; 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_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_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_MDL, factory as iconButtonMdl} from './icon-button/icon-button.mdl'; + 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 COMBO, directive as ComboDirective} from './combo/combo'; diff --git a/client/core/src/date-picker/date-picker.js b/client/core/src/date-picker/date-picker.js index 8b02d12365..f0a829df44 100644 --- a/client/core/src/date-picker/date-picker.js +++ b/client/core/src/date-picker/date-picker.js @@ -2,12 +2,13 @@ import {module as _module} from '../module'; import * as resolveFactory from '../lib/resolveDefaultComponents'; import * as normalizerFactory from '../lib/inputAttrsNormalizer'; import * as util from '../lib/util'; +import Flatpickr from 'vendor/src/flatpickr'; const _NAME = 'datePicker'; export const NAME = util.getName(_NAME); -directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME]; -export function directive(resolve, normalizer) { +directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME, '$translate']; +export function directive(resolve, normalizer, $translate) { return { restrict: 'E', template: function(_, attrs) { @@ -15,12 +16,35 @@ export function directive(resolve, normalizer) { return resolve.getTemplate(_NAME, 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, () => { - let mdlField = element[0].firstChild.MaterialTextfield; + let mdlField = element[0].firstChild.MaterialCheckbox; if (mdlField) mdlField.updateClasses_(); }); componentHandler.upgradeElement(element[0].firstChild); + + element.on('$destroy', function() { + vp.destroy(); + }); } }; } diff --git a/client/core/src/directives/validation.js b/client/core/src/directives/validation.js index 0b0939318a..8159017b69 100644 --- a/client/core/src/directives/validation.js +++ b/client/core/src/directives/validation.js @@ -6,7 +6,7 @@ directive.$inject = ['$interpolate', '$compile', '$window']; export function directive(interpolate, compile, $window) { return { restrict: 'A', - require: ['ngModel', '^^form'], + require: ['ngModel', '?^^form'], link: link }; diff --git a/client/core/src/drop-down/drop-down.html b/client/core/src/drop-down/drop-down.html new file mode 100644 index 0000000000..dad08a84fe --- /dev/null +++ b/client/core/src/drop-down/drop-down.html @@ -0,0 +1,19 @@ + + + +
+ +
+
+ +
+ +
+
+ + + +
\ No newline at end of file diff --git a/client/core/src/drop-down/drop-down.js b/client/core/src/drop-down/drop-down.js new file mode 100644 index 0000000000..ece781507d --- /dev/null +++ b/client/core/src/drop-down/drop-down.js @@ -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: ' \ No newline at end of file diff --git a/client/core/src/grid-header/grid-header.js b/client/core/src/grid-header/grid-header.js new file mode 100644 index 0000000000..3f8bd7292d --- /dev/null +++ b/client/core/src/grid-header/grid-header.js @@ -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 +}); diff --git a/client/core/src/grid-header/style.scss b/client/core/src/grid-header/style.scss new file mode 100644 index 0000000000..742c8e7d51 --- /dev/null +++ b/client/core/src/grid-header/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/client/core/src/icon-button/icon-button.html b/client/core/src/icon-button/icon-button.html new file mode 100644 index 0000000000..4bd12c6204 --- /dev/null +++ b/client/core/src/icon-button/icon-button.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/client/core/src/icon-button/icon-button.js b/client/core/src/icon-button/icon-button.js index 62ce9a2a4d..4201a37a89 100644 --- a/client/core/src/icon-button/icon-button.js +++ b/client/core/src/icon-button/icon-button.js @@ -1,17 +1,12 @@ import {module as _module} from '../module'; -import * as resolveFactory from '../lib/resolveDefaultComponents'; -import * as util from '../lib/util'; -const _NAME = 'iconButton'; -export const NAME = util.getName(_NAME); +_module.component('vnIconButton', { + template: require('./icon-button.html'), + bindings: { + icon: '@', + className: '@?', + enabled: ' - *[label]* - \ No newline at end of file diff --git a/client/core/src/icon-button/icon-button.mdl.js b/client/core/src/icon-button/icon-button.mdl.js deleted file mode 100644 index 14c9fa2a3b..0000000000 --- a/client/core/src/icon-button/icon-button.mdl.js +++ /dev/null @@ -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); diff --git a/client/core/src/icon-menu/icon-menu.html b/client/core/src/icon-menu/icon-menu.html new file mode 100644 index 0000000000..f09652178b --- /dev/null +++ b/client/core/src/icon-menu/icon-menu.html @@ -0,0 +1,22 @@ +
+ +
+ +
+
+ +
+
\ No newline at end of file diff --git a/client/core/src/icon-menu/icon-menu.js b/client/core/src/icon-menu/icon-menu.js new file mode 100644 index 0000000000..a81d3f512a --- /dev/null +++ b/client/core/src/icon-menu/icon-menu.js @@ -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: '{{::$ctrl.icon}}', + bindings: { + icon: '@' + } +}); diff --git a/client/core/src/icon/icon.mdl.html b/client/core/src/icon/icon.mdl.html deleted file mode 100644 index 865296d9bc..0000000000 --- a/client/core/src/icon/icon.mdl.html +++ /dev/null @@ -1 +0,0 @@ -*[icon]* diff --git a/client/core/src/icon/icon.mdl.js b/client/core/src/icon/icon.mdl.js deleted file mode 100644 index ce3f82856d..0000000000 --- a/client/core/src/icon/icon.mdl.js +++ /dev/null @@ -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); diff --git a/client/core/src/lib/moduleLoader.js b/client/core/src/lib/moduleLoader.js index 2adfa20ad3..10c2cc903b 100644 --- a/client/core/src/lib/moduleLoader.js +++ b/client/core/src/lib/moduleLoader.js @@ -7,7 +7,7 @@ export function factory($translatePartialLoader, $http, $window, $ocLazyLoad, $q constructor() { this._loadedModules = {}; } - load(moduleName) { + load(moduleName, validations) { if (this._loadedModules[moduleName]) return; @@ -20,17 +20,18 @@ export function factory($translatePartialLoader, $http, $window, $ocLazyLoad, $q for (let dep of deps) { this._loadedModules[dep] = true; promises.push(modules[dep]()); - promises.push(new Promise(resolve => { - $http.get(`/${dep}/validations`).then( - json => this.onValidationsReady(json, resolve), - json => resolve() - ); - })); + if (validations) + promises.push(new Promise(resolve => { + $http.get(`/${dep}/validations`).then( + json => this.onValidationsReady(json, resolve), + json => resolve() + ); + })); $translatePartialLoader.addPart(dep); // FIXME: https://github.com/angular-translate/angular-translate/pull/1674 // promises.push($translate.refresh()); - setTimeout (() => $translate.refresh(), 500); + setTimeout(() => $translate.refresh(), 500); } let ocDeps = deps.map(item => { return { name: item } }); diff --git a/client/core/src/locale/es.json b/client/core/src/locale/es.json index ea3e195fac..3ce07bc509 100644 --- a/client/core/src/locale/es.json +++ b/client/core/src/locale/es.json @@ -5,5 +5,6 @@ "Clear": "Borrar", "Save": "Guardar", "Add": "Añadir", - "Search": "Buscar" + "Search": "Buscar", + "Load More": "Cargar más" } \ No newline at end of file diff --git a/client/core/src/multi-check/multi-check.html b/client/core/src/multi-check/multi-check.html new file mode 100644 index 0000000000..3ddd0e0a3b --- /dev/null +++ b/client/core/src/multi-check/multi-check.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/core/src/multi-check/multi-check.js b/client/core/src/multi-check/multi-check.js new file mode 100644 index 0000000000..14e14760e9 --- /dev/null +++ b/client/core/src/multi-check/multi-check.js @@ -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: '@?' + } +}); + diff --git a/client/core/src/multi-check/multi-check.scss b/client/core/src/multi-check/multi-check.scss new file mode 100644 index 0000000000..596a2e6f57 --- /dev/null +++ b/client/core/src/multi-check/multi-check.scss @@ -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; + } + } +} \ No newline at end of file diff --git a/client/core/src/paging/paging.js b/client/core/src/paging/paging.js index 8e0b86aa17..e04f9ee5ea 100644 --- a/client/core/src/paging/paging.js +++ b/client/core/src/paging/paging.js @@ -16,7 +16,8 @@ export default class Paging { $onChanges(changes) { if (!this.index) return; this.numPerPage = this.index.filter.size; - if(changes.total) + this.currentPage = this.index.filter.page; + if (changes.total) this.numItems = changes.total.currentValue; } onModelUpdated() { @@ -29,7 +30,11 @@ export default class Paging { } onPageChange(page) { this.index.filter.page = page; - this.index.accept(); + if (typeof this.pageChange === 'undefined') { + this.index.accept(); + } else { + this.pageChange(); + } } } Paging.$inject = ['$http', '$scope']; @@ -39,6 +44,7 @@ export const COMPONENT = { template: require('./paging.html'), bindings: { index: '<', + pageChange: '&?', total: '<' }, controller: Paging diff --git a/client/core/src/popover/popover.js b/client/core/src/popover/popover.js index f04cb3d090..a1cac7112b 100644 --- a/client/core/src/popover/popover.js +++ b/client/core/src/popover/popover.js @@ -16,12 +16,38 @@ export function directive(vnPopover) { module.directive('vnPopover', directive); export class Popover { - constructor($document, $compile) { + constructor($document, $compile, $transitions) { this.document = $document[0]; 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'); + this.popOpens++; + + if (!popoverId) { + popoverId = 'popover-' + this.popOpens; + popover.id = popoverId; + } + popover.className = 'vn-popover'; popover.addEventListener('mousedown', e => this.onPopoverMouseDown(e)); @@ -71,38 +97,96 @@ export class Popover { this.document.body.appendChild(popover); - this.docMouseDownHandler = e => this.onDocMouseDown(e); - this.document.addEventListener('mousedown', this.docMouseDownHandler); - - this.docKeyDownHandler = e => this.onDocKeyDown(e); - this.document.addEventListener('keydown', this.docKeyDownHandler); + if (this.popOpens === 1) { + this._init(); + } + return popoverId; } showComponent(childComponent, $scope, parent) { let childElement = this.document.createElement(childComponent); - this.$compile(childElement)($scope); - this.show(childElement, parent); + let id = 'popover-' + this.popOpens; + childElement.id = id; + this.removeScope = true; + this.$compile(childElement)($scope.$new()); + this.show(childElement, parent, id); + return childElement; } - hide() { - if (!this.popover) return; - this.document.removeEventListener('mousedown', this.docMouseDownHandler); - this.document.removeEventListener('keydown', this.docKeyDownHandler); - this.document.body.removeChild(this.popover); - this.popover = null; - this.lastEvent = null; - this.docMouseDownHandler = null; - this.docKeyDownHandler = null; + _checkOpens() { + this.popOpens = this.document.querySelectorAll('*[id^="popover-"]').length; + if (this.popOpens === 0) { + this._destroy(); + } + } + _removeElement(val) { + if (!val) return; + 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) { - if (event != this.lastEvent) - this.hide(); + let targetId = this._findPopOver(event.target); + if (targetId) { + this.hideChilds(targetId); + } else { + this.hideAll(); + } } onDocKeyDown(event) { - if (event.keyCode === 27) - this.hide(); + if (event.keyCode === 27) { + let targetId = this._findPopOver(this.lastTarget); + if (targetId) { + this.hideChilds(targetId); + } else { + this.hideAll(); + } + this.lastTarget = null; + } } onPopoverMouseDown(event) { - this.lastEvent = event; + this.lastTarget = event.target; } } -Popover.$inject = ['$document', '$compile']; +Popover.$inject = ['$document', '$compile', '$transitions']; module.service('vnPopover', Popover); diff --git a/client/core/src/tooltip/style.css b/client/core/src/tooltip/style.css new file mode 100644 index 0000000000..9d27976c04 --- /dev/null +++ b/client/core/src/tooltip/style.css @@ -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; +} \ No newline at end of file diff --git a/client/core/src/tooltip/tooltip.js b/client/core/src/tooltip/tooltip.js new file mode 100644 index 0000000000..4842979770 --- /dev/null +++ b/client/core/src/tooltip/tooltip.js @@ -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 = '
{{text}}
'; + 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); diff --git a/client/production/routes.json b/client/production/routes.json index 38ab36dc01..a99b910a37 100644 --- a/client/production/routes.json +++ b/client/production/routes.json @@ -2,6 +2,7 @@ "module": "production", "name": "Production", "icon": "group_work", + "validations" : false, "routes": [ { "url": "/production", diff --git a/client/production/src/filter-panel/filter-panel.html b/client/production/src/filter-panel/filter-panel.html deleted file mode 100644 index 2bb03ead06..0000000000 --- a/client/production/src/filter-panel/filter-panel.html +++ /dev/null @@ -1,23 +0,0 @@ -
- - - - - - - - - - - - - - - -
\ No newline at end of file diff --git a/client/production/src/filter-panel/filter-panel.js b/client/production/src/filter-panel/filter-panel.js deleted file mode 100644 index c432b3b08f..0000000000 --- a/client/production/src/filter-panel/filter-panel.js +++ /dev/null @@ -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 -}); diff --git a/client/production/src/index/index.html b/client/production/src/index/index.html index 4cf14099c8..b4e95608fc 100644 --- a/client/production/src/index/index.html +++ b/client/production/src/index/index.html @@ -1,36 +1,40 @@ + + - - - - Localizador - - - + + + Finder + + + + + + + - + - - - - - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/client/production/src/index/index.js b/client/production/src/index/index.js index 3c0e9cfafb..95eb8e6508 100644 --- a/client/production/src/index/index.js +++ b/client/production/src/index/index.js @@ -1,11 +1,118 @@ import ngModule from '../module'; +import './style.scss'; export default class ProductionIndex { - search(index) { - index.filter.search = this.model.search; - index.accept(); + constructor($element, $scope, $http, vnPopover, aclConstant) { + this.$element = $element; + 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', { template: require('./index.html'), diff --git a/client/production/src/index/style.scss b/client/production/src/index/style.scss new file mode 100644 index 0000000000..eea97e50e1 --- /dev/null +++ b/client/production/src/index/style.scss @@ -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; + } + } +} \ No newline at end of file diff --git a/client/production/src/locale/es.json b/client/production/src/locale/es.json index 9e26dfeeb6..32bd658972 100644 --- a/client/production/src/locale/es.json +++ b/client/production/src/locale/es.json @@ -1 +1,25 @@ -{} \ No newline at end of file +{ + "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" +} \ No newline at end of file diff --git a/client/production/src/production-actions/production-actions.html b/client/production/src/production-actions/production-actions.html new file mode 100644 index 0000000000..4786d9136b --- /dev/null +++ b/client/production/src/production-actions/production-actions.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/production/src/production-actions/production-actions.js b/client/production/src/production-actions/production-actions.js new file mode 100644 index 0000000000..0e5482f30c --- /dev/null +++ b/client/production/src/production-actions/production-actions.js @@ -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 +}); diff --git a/client/production/src/production-comment/production-comment.html b/client/production/src/production-comment/production-comment.html new file mode 100644 index 0000000000..e094d47b85 --- /dev/null +++ b/client/production/src/production-comment/production-comment.html @@ -0,0 +1,6 @@ +
+ + + + +
\ No newline at end of file diff --git a/client/production/src/production-comment/production-comment.js b/client/production/src/production-comment/production-comment.js new file mode 100644 index 0000000000..390de47c2c --- /dev/null +++ b/client/production/src/production-comment/production-comment.js @@ -0,0 +1,5 @@ +import ngModule from '../module'; + +ngModule.component('vnProductionComment', { + template: require('./production-comment.html') +}); diff --git a/client/production/src/production-filters/production-filters.html b/client/production/src/production-filters/production-filters.html new file mode 100644 index 0000000000..037d6c8855 --- /dev/null +++ b/client/production/src/production-filters/production-filters.html @@ -0,0 +1,30 @@ +
+ + + + + + + + + + + + + + + + + + +
diff --git a/client/production/src/production-filters/production-filters.js b/client/production/src/production-filters/production-filters.js new file mode 100644 index 0000000000..eb6a95ea48 --- /dev/null +++ b/client/production/src/production-filters/production-filters.js @@ -0,0 +1,6 @@ +import ngModule from '../module'; +import './style.scss'; + +ngModule.component('vnProductionFilterPanel', { + template: require('./production-filters.html') +}); diff --git a/client/production/src/production-filters/style.scss b/client/production/src/production-filters/style.scss new file mode 100644 index 0000000000..17e5fc417b --- /dev/null +++ b/client/production/src/production-filters/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/client/production/src/production-table/production-table.html b/client/production/src/production-table/production-table.html new file mode 100644 index 0000000000..d559bb16cb --- /dev/null +++ b/client/production/src/production-table/production-table.html @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + {{::ticket.ticketFk}} + {{::ticket.agency}} + {{::ticket.routeFk}} + {{::ticket.salesPerson | ucwords}} + {{ticket.hour}} + {{ticket.state}} + {{::ticket.lines}} + {{::ticket.m3}} + {{::ticket.boxes}} + + + + + + + + + + : + {{$ctrl.footer.total}} + + + {{$ctrl.footer.lines}} + {{$ctrl.footer.meters}} + + + + + + + \ No newline at end of file diff --git a/client/production/src/production-table/production-table.js b/client/production/src/production-table/production-table.js new file mode 100644 index 0000000000..a8dc794fc0 --- /dev/null +++ b/client/production/src/production-table/production-table.js @@ -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 +}); diff --git a/client/production/src/production.js b/client/production/src/production.js index f36e961565..0a6b7c51d2 100644 --- a/client/production/src/production.js +++ b/client/production/src/production.js @@ -3,4 +3,6 @@ export * from './module'; // import components import './index/index'; -import './filter-panel/filter-panel'; +import './production-filters/production-filters'; +import './production-actions/production-actions'; +import './production-table/production-table'; diff --git a/client/salix/src/components/main-menu/main-menu.html b/client/salix/src/components/main-menu/main-menu.html index 7902c4b72b..075b91ef79 100644 --- a/client/salix/src/components/main-menu/main-menu.html +++ b/client/salix/src/components/main-menu/main-menu.html @@ -6,7 +6,7 @@