Merge branch 'dev' of https://git.verdnatura.es/salix into dev

* 'dev' of https://git.verdnatura.es/salix:
  zone model and rest api
  module routes: front dev 80%
  filtro de rutas con paginación
  routes change model and first look
  Login sin url de redirección
This commit is contained in:
Carlos 2017-10-11 12:57:26 +02:00
commit a62285ff9e
29 changed files with 425 additions and 84 deletions

View File

@ -19,6 +19,7 @@ class Autocomplete extends Component {
this.maxRow = 10;
this.showField = this.showField || 'name';
this.valueField = this.valueField || 'id';
this.order = this.order || 'name ASC';
this.items = this.data || [];
this.displayValueMultiCheck = [];
this._multiField = [];
@ -219,38 +220,45 @@ class Autocomplete extends Component {
}
getItems() {
let filter = {};
if (!this.finding) {
this.finding = true;
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.removeLoadMore = false;
this.$http.get(`${this.url}?filter=${json}`).then(
json => {
if (json.data.length) {
json.data.forEach(
el => {
if (this.multiple) {
el.checked = this.field.indexOf(el[this.valueField]) !== -1;
}
this.items.push(el);
}
);
if (filter.skip === 0 && this.maxRow && json.data.length < this.maxRow) {
this.removeLoadMore = true;
}
} else {
this.maxRow = false;
if (this.maxRow) {
if (this.items) {
filter.skip = this.items.length;
}
filter.limit = this.maxRow;
filter.order = this.order;
}
);
let json = JSON.stringify(filter);
this.removeLoadMore = false;
this.$http.get(`${this.url}?filter=${json}`).then(
json => {
if (json.data.length) {
json.data.forEach(
el => {
if (this.multiple) {
el.checked = this.field.indexOf(el[this.valueField]) !== -1;
}
this.items.push(el);
}
);
if (filter.skip === 0 && this.maxRow && json.data.length < this.maxRow) {
this.removeLoadMore = true;
}
} else {
this.maxRow = false;
}
this.finding = false;
},
() => {
this.finding = false;
}
);
}
}
$onInit() {
this.findMore = this.url && this.maxRow;
@ -308,7 +316,8 @@ module.component('vnAutocomplete', {
data: '<?',
field: '=',
label: '@',
multiple: '@?'
multiple: '@?',
order: '@?'
},
transclude: {
tplItem: '?tplItem'

View File

@ -1 +1,3 @@
{}
{
"Production" : "Production"
}

View File

@ -1,13 +1,66 @@
{
"module": "route",
"name": "Route",
"name": "Routes",
"icon" : "local_shipping",
"validations" : false,
"routes": [
{
"url": "/routes",
"state": "routes",
"abstract": true,
"component": "ui-view"
},
{
"url": "/list",
"state": "routes.index",
"component": "vn-route-index"
},
{
"url": "/create",
"state": "routes.create",
"component": "vn-route-create"
},
{
"url": "/:id",
"state": "routes.card",
"abstract": true,
"component": "vn-route-card"
},
{
"url": "/basicData",
"state": "routes.card.basicData",
"component": "vn-route-basic-data",
"params": {
"route": "$ctrl.route"
},
"menu": {
"description": "Datos básicos",
"icon": "person"
}
},
{
"url": "/logisticData",
"state": "routes.card.logisticData",
"component": "vn-route-logistic-data",
"params": {
"route": "$ctrl.route"
},
"menu": {
"description": "Datos logísticos",
"icon": "local_shipping"
}
},
{
"url": "/tickets",
"state": "routes.card.tickets",
"component": "vn-route-tickets",
"params": {
"route": "$ctrl.route"
},
"menu": {
"description": "Tickets asignados",
"icon": "assignment"
}
}
]
}

View File

@ -0,0 +1,27 @@
<vn-horizontal>
<mg-ajax
path="/route/api/Deliveries/{{edit.params.id}}"
actions="$ctrl.route = edit.model"
options="mgEdit">
</mg-ajax>
<vn-empty style="min-width: 18em; padding-left: 1em; padding-bottom: 1em;">
<vn-card>
<vn-vertical class="margin-medium" pad-medium-top pad-medium-bottom>
<vn-horizontal>
<vn-one>
<i class="material-icons descriptor-icon">local_shipping</i>
</vn-one>
<vn-vertical vn-two>
<div class="margin-none"><span translate>Ruta</span> {{::$ctrl.route.id}}</div>
<div class="margin-none">{{$ctrl.route.date | date:'dd/MM/yyyy'}}</div>
</vn-vertical>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-left-menu></vn-left-menu>
</vn-empty>
<vn-auto>
<vn-vertical style="max-width: 70em; margin: 0 auto;" ui-view></vn-vertical>
</vn-auto>
</vn-horizontal>

View File

@ -0,0 +1,12 @@
import ngModule from '../module';
class RouteCard {
constructor() {
this.route = null;
}
}
ngModule.component('vnRouteCard', {
template: require('./card.html'),
controller: RouteCard
});

View File

@ -0,0 +1,29 @@
<mg-ajax path="/route/api/Delivery/createRoute" options="vnPost"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.route"
form="form"
save="post">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium>
<div style="max-width: 70em; margin: 0 auto;">
<vn-card>
<vn-vertical pad-large>
<vn-title>Create Route</vn-title>
<vn-horizontal>
<vn-date-picker vn-one label="Date" field="$ctrl.route.date"></vn-date-picker>
<vn-textfield vn-one label="Agency" field="$ctrl.route.agency"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Driver" field="$ctrl.route.driver"></vn-textfield>
<vn-textfield vn-one label="Vehicle" field="$ctrl.route.vehicle"></vn-textfield>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Create and edit"></vn-submit>
<vn-button label="Create" ng-click="watcher.submitBack()"></vn-button>
</vn-button-bar>
</div>
</form>

View File

@ -0,0 +1,21 @@
import ngModule from '../module';
class RouteCreate {
constructor($scope, $state) {
this.$ = $scope;
this.$state = $state;
this.route = {};
console.log('hi world');
}
onSubmit() {
this.$.watcher.submit().then(
json => this.$state.go('routes.card.basicData', {id: json.data.id})
);
}
}
RouteCreate.$inject = ['$scope', '$state'];
ngModule.component('vnRouteCreate', {
template: require('./create.html'),
controller: RouteCreate
});

View File

@ -1,4 +1,4 @@
<<mg-ajax path="/client/api/Clients/filter" options="mgIndex"></mg-ajax>
<mg-ajax path="/route/api/Deliveries/filter" options="mgIndex"></mg-ajax>
<div margin-medium>
<div style="max-width: 40em; margin: 0 auto;">
<vn-card>
@ -8,16 +8,16 @@
on-search="$ctrl.search(index)"
advanced="true"
search="$ctrl.model.search"
popover="vn-client-search-panel">
popover="vn-route-search-panel">
</vn-searchbar>
</vn-horizontal>
</vn-card>
<vn-card margin-medium-top>
<vn-item-route ng-repeat="route in index.model.instances" title="View Route" client="route"></vn-item-route>
<vn-item-route ng-repeat="route in index.model.instances" title="View Route" route="route"></vn-item-route>
</vn-card>
<vn-paging index="index" total="index.model.count"></vn-paging>
</div>
<a ui-sref="create" fixed-bottom-right>
<a ui-sref="routes.create" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
</div>

View File

@ -0,0 +1,21 @@
<a vn-horizontal ui-sref="routes.card.basicData({id: {{$ctrl.route.id}} })" pad-medium border-solid-bottom>
<vn-one>
<vn-vertical>
<vn-one>
<span translate>ID_RUTA</span>:
<strong>{{$ctrl.route.id}}</strong>
</vn-one>
<vn-one>
<span translate>Fecha</span>:
<strong>{{$ctrl.route.date | date:'dd/MM/yyyy'}}</strong>
</vn-one>
<vn-one>
<span>m<sup>3</sup></span>:
<strong>{{$ctrl.route.m3}}</strong>
</vn-one>
</vn-vertical>
</vn-one>
<vn-none pad-medium-top>
<vn-icon icon="print"></vn-icon>
</vn-none>
</a>

View File

@ -0,0 +1,8 @@
import ngModule from '../module';
ngModule.component('vnItemRoute', {
template: require('./item-route.html'),
bindings: {
route: '<'
}
});

View File

@ -0,0 +1,12 @@
vn-item-route {
display: block;
}
vn-item-route a {
display: block;
text-decoration: none;
color: inherit;
}
vn-item-route a:hover {
color: white;
background-color: #424242;
}

View File

@ -0,0 +1,3 @@
{
"Routes" : "Routes"
}

View File

@ -1,3 +1,3 @@
{
"Routes" : "Rutas"
}

View File

@ -2,3 +2,6 @@ export * from './module';
// import components
import './index/index';
import './search-panel/search-panel';
import './create/create';
import './card/card';

View File

@ -0,0 +1,10 @@
{
"Client id": "Id cliente",
"Tax number": "NIF/CIF",
"Name": "Nombre",
"Social name": "Razon social",
"Town/City": "Ciudad",
"Postcode": "Código postal",
"Email": "Correo electrónico",
"Phone": "Teléfono"
}

View File

@ -0,0 +1,23 @@
<div pad-large style="min-width: 30em">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-date-picker vn-one label="Date" model="$ctrl.filter.date"></vn-date-picker>
<vn-autocomplete
vn-one
label="Zone"
field="$ctrl.filter.zone"
url="/route/api/Zones"
order="printingOrder ASC"
></vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Postcode" model="$ctrl.filter.postcode"></vn-textfield>
<vn-textfield vn-one label="Route_Id" model="$ctrl.filter.id"></vn-textfield>
</vn-horizontal>
<vn-horizontal margin-large-top>
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,27 @@
import ngModule from '../module';
export default class Controller {
constructor($window) {
this.$window = $window;
// onSubmit() is defined by @vnSearchbar
this.onSubmit = () => {};
}
onSearch() {
this.setStorageValue();
this.onSubmit(this.filter);
}
$onChanges() {
var value = JSON.parse(this.$window.sessionStorage.getItem('filter'));
if (value !== undefined)
this.filter = value;
}
setStorageValue() {
this.$window.sessionStorage.setItem('filter', JSON.stringify(this.filter));
}
}
Controller.$inject = ['$window'];
ngModule.component('vnRouteSearchPanel', {
template: require('./search-panel.html'),
controller: Controller
});

View File

@ -45,8 +45,9 @@ vn-home {
}
i{
font-size: 50px !important;
font-size: 75px !important;
margin: 0 auto;
padding-top: 15px;
}
&:hover{
opacity: 0.7;

View File

@ -6,6 +6,7 @@
<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-small for="apps">
<li class="mdl-menu__item" ng-repeat="mod in $ctrl.modules track by $index" ui-sref="{{::mod.route.state}}">
<vn-icon ng-if="mod.icon && !mod.icon.startsWith('/')" icon="{{::mod.icon}}"></vn-icon>
<img ng-if="mod.icon && mod.icon.startsWith('/')" ng-src="{{::mod.icon}}" />
<span translate="{{::mod.name}}"></span>
</li>

View File

@ -8,6 +8,11 @@ vn-main-menu {
vertical-align: middle;
margin-top: -3px;
}
i{
float: left;
padding-top: 13px;
margin-right: 3px;
}
}
li.mdl-menu__item:hover{
background-color: #FF9300;

View File

@ -9,5 +9,7 @@
"Can't contact with server": "No se pudo contactar con el servidor",
"Push on applications menu": "Para abrir un módulo pulsa en el menú de aplicaciones",
"Clients": "Clientes",
"Routes" : "Rutas",
"Production" : "Producción",
"Modules access" : "Acceso a módulos"
}

View File

@ -10,10 +10,11 @@ module.exports = function(app) {
});
app.post('/login', function(req, res) {
let user = req.body.user ? req.body.user : "";
let password = req.body.password;
let body = req.body;
let user = body.user;
let password = body.password;
let syncOnFail = true;
let usesEmail = user.indexOf('@') !== -1;
let usesEmail = user && user.indexOf('@') !== -1;
login();
@ -38,26 +39,23 @@ module.exports = function(app) {
return;
}
let parsedLocation;
let loginUrl;
let shouldContinue = false;
let continueUrl;
if (req.body.location)
parsedLocation = url.parse(req.body.location, true);
if (parsedLocation && parsedLocation.query) {
loginUrl = applications[parsedLocation.query.apiKey];
shouldContinue = parsedLocation.query.continue;
}
try {
let query = url.parse(req.body.location, true).query;
loginUrl = applications[query.apiKey];
continueUrl = query.continue;
} catch (e) {}
if (!loginUrl)
loginUrl = applications.default;
res.json({
res.send(JSON.stringify({
token: token.id,
continue: shouldContinue,
continue: continueUrl,
loginUrl: loginUrl
});
}));
}
function findCb(err, instance) {
if (!instance || instance.password !== md5(password)) {
@ -78,9 +76,9 @@ module.exports = function(app) {
}
function badLogin() {
res.status(401);
res.json({
res.send(JSON.stringify({
message: 'Login failed'
});
}));
}
});

View File

@ -0,0 +1,48 @@
module.exports = function(Delivery) {
Delivery.installMethod('filter', filterRoutes);
function filterRoutes(params) {
if (params.search)
return searchWhere(params);
return andWhere(params);
}
function searchWhere(params) {
return {
where: {
or: [
{id: params.search},
{name: {regexp: params.search}}
]
},
skip: (params.page - 1) * params.size,
limit: params.size
};
}
function andWhere(params) {
let filters = {
where: {},
skip: (params.page - 1) * params.size,
limit: params.size
};
delete params.page;
delete params.size;
if (params.phone) {
filters.where.or = [
{phone: params.phone},
{mobile: params.phone}
];
delete params.phone;
}
Object.keys(params).forEach(
key => {
filters.where[key] = {regexp: params[key]};
}
);
return filters;
}
};

View File

@ -0,0 +1,3 @@
module.exports = function(Delivery) {
require('../methods/filter.js')(Delivery);
};

View File

@ -1,15 +1,21 @@
{
"name": "Route",
"name": "Delivery",
"base": "MyModel",
"validateUpsert": true,
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
"type": "Number",
"forceId": false
},
"date": {
"type": "date"
"type": "Date"
},
"m3":{
"type": "Number"
},
"warehouseFk":{
"type": "Number"
}
},
"acls": [
@ -25,7 +31,5 @@
"principalId": "root",
"permission": "ALLOW"
}
],
"validations": [],
"methods": {}
}
]
}

View File

@ -0,0 +1,33 @@
{
"name": "Zone",
"base": "MyModel",
"validateUpsert": true,
"properties": {
"id": {
"id": true,
"type": "Number",
"forceId": false
},
"name": {
"type": "String"
},
"printingOrder":{
"type": "Number"
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "root",
"permission": "ALLOW"
}
]
}

View File

@ -27,15 +27,5 @@
"password": "",
"connectTimeout": 20000,
"acquireTimeout": 20000
},
"client": {
"name": "client",
"connector": "remote",
"url": "http://localhost:3002/api"
},
"route": {
"name": "route",
"connector": "remote",
"url": "http://localhost:3004/api"
}
}

View File

@ -27,10 +27,5 @@
"password": "",
"connectTimeout": 20000,
"acquireTimeout": 20000
},
"client": {
"name": "client",
"connector": "remote",
"url": "http://localhost:3002/api"
}
}

View File

@ -42,9 +42,10 @@
"Account": {
"dataSource": "auth"
},
"Route": {
"dataSource": "route",
"public": true
"Delivery": {
"dataSource": "vn"
},
"Zone": {
"dataSource": "vn"
}
}