Address, Config, Orders
This commit is contained in:
parent
03a7734cf3
commit
73a8d045a6
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"name": "Account",
|
||||||
|
"base": "PersistedModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "account.user"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"roleFk": {
|
||||||
|
"type": "number",
|
||||||
|
"mysql": {
|
||||||
|
"columnName": "role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nickname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"lang": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"updated": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "Country",
|
||||||
|
"description": "Worldwide countries",
|
||||||
|
"base": "PersistedModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "country"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "Number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -13,6 +13,10 @@ module.exports = Self => {
|
||||||
arg: 'typeFk',
|
arg: 'typeFk',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The item type id'
|
description: 'The item type id'
|
||||||
|
}, {
|
||||||
|
arg: 'categoryFk',
|
||||||
|
type: 'Number',
|
||||||
|
description: 'The item category id'
|
||||||
}, {
|
}, {
|
||||||
arg: 'search',
|
arg: 'search',
|
||||||
type: 'String',
|
type: 'String',
|
||||||
|
@ -42,7 +46,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.catalog = async (dated, typeFk, search, order, limit, tagFilter) => {
|
Self.catalog = async (dated, typeFk, categoryFk, search, order, limit, tagFilter) => {
|
||||||
let $ = Self.app.models;
|
let $ = Self.app.models;
|
||||||
let itemIds;
|
let itemIds;
|
||||||
|
|
||||||
|
@ -63,11 +67,27 @@ module.exports = Self => {
|
||||||
if (/^[0-9]+$/.test(search)) {
|
if (/^[0-9]+$/.test(search)) {
|
||||||
itemIds = [parseInt(search)];
|
itemIds = [parseInt(search)];
|
||||||
} else {
|
} else {
|
||||||
if (typeFk || search) {
|
let inbounds = await $.Inbound.find({
|
||||||
let where = {};
|
fields: ['itemFk'],
|
||||||
|
where: inboundWhere
|
||||||
|
});
|
||||||
|
itemIds = toValues(inbounds, 'itemFk');
|
||||||
|
|
||||||
if (typeFk)
|
if (categoryFk || typeFk || search) {
|
||||||
|
let where = {
|
||||||
|
id: {inq: itemIds}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeFk) {
|
||||||
where.typeFk = typeFk;
|
where.typeFk = typeFk;
|
||||||
|
} else if (categoryFk) {
|
||||||
|
let types = await $.ItemType.find({
|
||||||
|
fields: ['id'],
|
||||||
|
where: {categoryFk}
|
||||||
|
});
|
||||||
|
where.typeFk = {inq: toValues(types, 'id')};
|
||||||
|
}
|
||||||
|
|
||||||
if (search)
|
if (search)
|
||||||
where.longName = {like: `%${search}%`};
|
where.longName = {like: `%${search}%`};
|
||||||
|
|
||||||
|
@ -79,15 +99,6 @@ module.exports = Self => {
|
||||||
let items = await Self.find(filter);
|
let items = await Self.find(filter);
|
||||||
itemIds = items.map(i => i.id);
|
itemIds = items.map(i => i.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let where = Object.assign({}, inboundWhere);
|
|
||||||
if (itemIds) where.itemFk = {inq: itemIds};
|
|
||||||
|
|
||||||
let inbounds = await $.Inbound.find({
|
|
||||||
fields: ['itemFk'],
|
|
||||||
where
|
|
||||||
});
|
|
||||||
itemIds = toValues(inbounds, 'itemFk');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies tag filters
|
// Applies tag filters
|
||||||
|
@ -129,6 +140,9 @@ module.exports = Self => {
|
||||||
|
|
||||||
// Obtains distinct tags and it's distinct values
|
// Obtains distinct tags and it's distinct values
|
||||||
|
|
||||||
|
let tags = [];
|
||||||
|
|
||||||
|
if (typeFk || search) {
|
||||||
let tagValues = await $.ItemTag.find({
|
let tagValues = await $.ItemTag.find({
|
||||||
fields: ['tagFk', 'value', 'intValue', 'priority'],
|
fields: ['tagFk', 'value', 'intValue', 'priority'],
|
||||||
where: {
|
where: {
|
||||||
|
@ -162,7 +176,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tagIds = [...tagValueMap.keys()];
|
let tagIds = [...tagValueMap.keys()];
|
||||||
let tags = await $.Tag.find({
|
tags = await $.Tag.find({
|
||||||
fields: ['id', 'name', 'isQuantitative', 'unit'],
|
fields: ['id', 'name', 'isQuantitative', 'unit'],
|
||||||
where: {
|
where: {
|
||||||
id: {inq: tagIds}
|
id: {inq: tagIds}
|
||||||
|
@ -206,12 +220,15 @@ module.exports = Self => {
|
||||||
filter
|
filter
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Obtains items data
|
// Obtains items data
|
||||||
|
|
||||||
let items = await Self.find({
|
let items = await Self.find({
|
||||||
fields: ['id', 'longName', 'subname', 'image'],
|
fields: ['id', 'longName', 'subName', 'image'],
|
||||||
where: {id: {inq: itemIds}},
|
where: {id: {inq: itemIds}},
|
||||||
|
limit: limit,
|
||||||
|
order: order,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
relation: 'tags',
|
relation: 'tags',
|
||||||
|
@ -236,13 +253,14 @@ module.exports = Self => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
limit: limit,
|
|
||||||
order: order
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let item of items)
|
for (let item of items) {
|
||||||
|
item.inbound = item.inbounds()[0];
|
||||||
|
item.buy = item.inbound && item.inbound.buy();
|
||||||
item.available = sum(item.inbounds(), 'available');
|
item.available = sum(item.inbounds(), 'available');
|
||||||
|
}
|
||||||
|
|
||||||
return {items, tags};
|
return {items, tags};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "Language",
|
||||||
|
"base": "PersistedModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "hedera.language"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"orgName": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"isActive": {
|
||||||
|
"type": "boolean",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "UserPassword",
|
||||||
|
"description": "User password requirements",
|
||||||
|
"base": "PersistedModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "account.userPassword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "Number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"length": {
|
||||||
|
"type": "Number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"nAlpha": {
|
||||||
|
"type": "Number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"nUpper": {
|
||||||
|
"type": "Number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"nDigits": {
|
||||||
|
"type": "Number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"nPunct": {
|
||||||
|
"type": "Number",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Account": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Address": {
|
"Address": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
@ -68,6 +71,9 @@
|
||||||
"Client": {
|
"Client": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Country": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"DeliveryMethod": {
|
"DeliveryMethod": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
@ -86,6 +92,9 @@
|
||||||
"ItemType": {
|
"ItemType": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Language": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"New": {
|
"New": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
@ -119,6 +128,9 @@
|
||||||
"TicketTracking": {
|
"TicketTracking": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"UserPassword": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Warehouse": {
|
"Warehouse": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,42 +27,51 @@ module.exports = function (ctx) {
|
||||||
framework: {
|
framework: {
|
||||||
components: [
|
components: [
|
||||||
'QBadge',
|
'QBadge',
|
||||||
'QLayout',
|
|
||||||
'QHeader',
|
|
||||||
'QDate',
|
|
||||||
'QDrawer',
|
|
||||||
'QPageContainer',
|
|
||||||
'QPage',
|
|
||||||
'QToolbar',
|
|
||||||
'QToolbarTitle',
|
|
||||||
'QBtn',
|
'QBtn',
|
||||||
'QIcon',
|
|
||||||
'QList',
|
|
||||||
'QInfiniteScroll',
|
|
||||||
'QItem',
|
|
||||||
'QItemSection',
|
|
||||||
'QItemLabel',
|
|
||||||
'QCarousel',
|
'QCarousel',
|
||||||
'QCarouselControl',
|
'QCarouselControl',
|
||||||
'QCarouselSlide',
|
'QCarouselSlide',
|
||||||
'QCard',
|
'QCard',
|
||||||
'QCardSection',
|
'QCardSection',
|
||||||
'QCardActions',
|
'QCardActions',
|
||||||
'QRating',
|
|
||||||
'QCheckbox',
|
'QCheckbox',
|
||||||
|
'QDate',
|
||||||
|
'QDialog',
|
||||||
|
'QDrawer',
|
||||||
|
'QExpansionItem',
|
||||||
|
'QHeader',
|
||||||
|
'QIcon',
|
||||||
|
'QImg',
|
||||||
|
'QInfiniteScroll',
|
||||||
'QInput',
|
'QInput',
|
||||||
|
'QItem',
|
||||||
|
'QItemSection',
|
||||||
|
'QItemLabel',
|
||||||
|
'QList',
|
||||||
|
'QLayout',
|
||||||
|
'QPageContainer',
|
||||||
|
'QPage',
|
||||||
|
'QPageSticky',
|
||||||
|
'QPopupProxy',
|
||||||
|
'QRadio',
|
||||||
|
'QRating',
|
||||||
'QRange',
|
'QRange',
|
||||||
'QSelect',
|
'QSelect',
|
||||||
'QSeparator',
|
'QSeparator',
|
||||||
'QSpinner',
|
'QSpinner',
|
||||||
'QTooltip',
|
'QTab',
|
||||||
'QImg',
|
'QTabs',
|
||||||
'QPageSticky',
|
'QTabPanel',
|
||||||
'QPopupProxy'
|
'QTabPanels',
|
||||||
|
'QRouteTab',
|
||||||
|
'QToolbar',
|
||||||
|
'QToolbarTitle',
|
||||||
|
'QTooltip'
|
||||||
],
|
],
|
||||||
|
|
||||||
directives: [
|
directives: [
|
||||||
'Ripple'
|
'Ripple',
|
||||||
|
'ClosePopup'
|
||||||
],
|
],
|
||||||
|
|
||||||
// Quasar plugins
|
// Quasar plugins
|
||||||
|
|
|
@ -7,7 +7,8 @@ export default async ({ app, Vue }) => {
|
||||||
userName: null,
|
userName: null,
|
||||||
title: null,
|
title: null,
|
||||||
subtitle: null,
|
subtitle: null,
|
||||||
search: null
|
search: null,
|
||||||
|
rightDrawerOpen: true
|
||||||
})
|
})
|
||||||
Vue.prototype.$state = state
|
Vue.prototype.$state = state
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,10 @@
|
||||||
// app global css
|
// app global css
|
||||||
|
|
||||||
|
.vn-w-md
|
||||||
|
width 30em
|
||||||
|
.vn-pp
|
||||||
|
padding 1em
|
||||||
|
|
||||||
|
@media (max-width: 960px)
|
||||||
|
.vn-pp
|
||||||
|
padding 1em 0
|
||||||
|
|
|
@ -5,6 +5,16 @@ export default {
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
remember: 'Don not close session',
|
remember: 'Don not close session',
|
||||||
search: 'Search',
|
search: 'Search',
|
||||||
|
accept: 'Accept',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
save: 'Save',
|
||||||
|
delete: 'Delete',
|
||||||
|
add: 'Add',
|
||||||
|
create: 'create',
|
||||||
|
dataSaved: 'Data saved!',
|
||||||
|
noDataFound: 'No data found',
|
||||||
|
areYouSureDelete: 'Are you sure you want to delete?',
|
||||||
|
fieldIsRequired: 'Field is required',
|
||||||
date: {
|
date: {
|
||||||
days: [
|
days: [
|
||||||
'Sunday',
|
'Sunday',
|
||||||
|
@ -64,9 +74,14 @@ export default {
|
||||||
orders: 'Orders',
|
orders: 'Orders',
|
||||||
conditions: 'Conditions',
|
conditions: 'Conditions',
|
||||||
about: 'About us',
|
about: 'About us',
|
||||||
|
config: 'Configuration',
|
||||||
|
user: 'User',
|
||||||
|
addresses: 'Addresses',
|
||||||
|
addressEdit: 'Edit address',
|
||||||
register: 'Register',
|
register: 'Register',
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
|
recentNews: 'Recent news',
|
||||||
startOrder: 'Start order',
|
startOrder: 'Start order',
|
||||||
|
|
||||||
weThinkForYou: 'We think for you',
|
weThinkForYou: 'We think for you',
|
||||||
|
@ -86,6 +101,8 @@ export default {
|
||||||
|
|
||||||
// Catalog
|
// Catalog
|
||||||
more: 'More',
|
more: 'More',
|
||||||
|
noItemsFound: 'No items found',
|
||||||
|
pleaseSetFilter: 'Please, set a filter using the right menu',
|
||||||
buy: 'Buy',
|
buy: 'Buy',
|
||||||
deleteFilter: 'Delete filter',
|
deleteFilter: 'Delete filter',
|
||||||
viewMore: 'View more',
|
viewMore: 'View more',
|
||||||
|
@ -101,6 +118,7 @@ export default {
|
||||||
relevancy: 'Relevancy',
|
relevancy: 'Relevancy',
|
||||||
priceAsc: 'Acending price',
|
priceAsc: 'Acending price',
|
||||||
priceDesc: 'Descending price',
|
priceDesc: 'Descending price',
|
||||||
|
novelty: 'Novelty',
|
||||||
available: 'Available',
|
available: 'Available',
|
||||||
siceAsc: 'Ascending size',
|
siceAsc: 'Ascending size',
|
||||||
sizeDesc: 'Descencing size',
|
sizeDesc: 'Descencing size',
|
||||||
|
@ -109,6 +127,7 @@ export default {
|
||||||
ordersMadeAt: 'Orders made at',
|
ordersMadeAt: 'Orders made at',
|
||||||
pendingConfirmtion: 'Pending confirmation',
|
pendingConfirmtion: 'Pending confirmation',
|
||||||
noOrdersFound: 'No orders found',
|
noOrdersFound: 'No orders found',
|
||||||
|
pending: 'Pending',
|
||||||
confirmed: 'Confirmed',
|
confirmed: 'Confirmed',
|
||||||
packages: '{n} packages',
|
packages: '{n} packages',
|
||||||
|
|
||||||
|
@ -118,10 +137,45 @@ export default {
|
||||||
// About
|
// About
|
||||||
aboutDesc: 'Verdnatura offers all services for your florist.',
|
aboutDesc: 'Verdnatura offers all services for your florist.',
|
||||||
|
|
||||||
|
// Config
|
||||||
|
userName: 'Username',
|
||||||
|
nickname: 'Nickname',
|
||||||
|
language: 'Language',
|
||||||
|
receiveInvoiceByEmail: 'Receive invoices by email',
|
||||||
|
passwordRequirements: 'Password requirements',
|
||||||
|
charsLong: '{0} characters long',
|
||||||
|
alphabeticChars: '{0} alphabetic chars',
|
||||||
|
upperLetters: '{0} uppercase letters',
|
||||||
|
digits: '{0} digits',
|
||||||
|
simbols: '{0} symbols. Ex: $%&.',
|
||||||
|
oldPassword: 'Old password',
|
||||||
|
newPassword: 'New password',
|
||||||
|
repeatPassword: 'Repeat password',
|
||||||
|
changePassword: 'Change password',
|
||||||
|
passwordCannotBeEmpty: 'Password cannot be empty',
|
||||||
|
passwordsDontMatch: 'Passwords do not match',
|
||||||
|
passwordChanged: 'Password changed successfully!',
|
||||||
|
|
||||||
|
// Addresses
|
||||||
|
setAsDefault: 'Set as default',
|
||||||
|
addressSetAsDefault: 'Address set as default',
|
||||||
|
addressRemoved: 'Address removed',
|
||||||
|
areYouSureDeleteAddress: 'Are you sure you want to delete the address?',
|
||||||
|
addressCreated: 'Address created successfully!',
|
||||||
|
|
||||||
|
// Address
|
||||||
|
consignatary: 'Consignatary',
|
||||||
|
street: 'Street',
|
||||||
|
city: 'City',
|
||||||
|
postalCode: 'Postal code',
|
||||||
|
province: 'Province',
|
||||||
|
country: 'Country',
|
||||||
|
phone: 'Phone',
|
||||||
|
mobile: 'Mobile',
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
registerAsNew: 'Registrarse como nuevo usuario',
|
registerAsNew: 'Registrarse como nuevo usuario',
|
||||||
notYetUser: 'You are not yet a user, register now and start enjoying everything that Verdnatura offers you.',
|
notYetUser: 'You are not yet a user, register now and start enjoying everything that Verdnatura offers you.',
|
||||||
repeatPassword: 'Repeat password',
|
|
||||||
receiveOffers: 'Receive offers and promotions by e-mail',
|
receiveOffers: 'Receive offers and promotions by e-mail',
|
||||||
userRegistered: 'User registered successfully'
|
userRegistered: 'User registered successfully'
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,16 @@ export default {
|
||||||
password: 'Contraseña',
|
password: 'Contraseña',
|
||||||
remember: 'No cerrar sesión',
|
remember: 'No cerrar sesión',
|
||||||
search: 'Buscar',
|
search: 'Buscar',
|
||||||
|
accept: 'Aceptar',
|
||||||
|
cancel: 'Cancelar',
|
||||||
|
save: 'Guardar',
|
||||||
|
delete: 'Borrar',
|
||||||
|
add: 'Añadir',
|
||||||
|
create: 'Crear',
|
||||||
|
dataSaved: '¡Datos guardados!',
|
||||||
|
noDataFound: 'No se han encontrado datos',
|
||||||
|
areYouSureDelete: '¿Seguro que quieres eliminar?',
|
||||||
|
fieldIsRequired: 'Campo requerido',
|
||||||
date: {
|
date: {
|
||||||
days: [
|
days: [
|
||||||
'Domingo',
|
'Domingo',
|
||||||
|
@ -65,9 +75,14 @@ export default {
|
||||||
orders: 'Pedidos',
|
orders: 'Pedidos',
|
||||||
conditions: 'Condiciones',
|
conditions: 'Condiciones',
|
||||||
about: 'Sobre nosotros',
|
about: 'Sobre nosotros',
|
||||||
|
config: 'Configuración',
|
||||||
|
user: 'Usuario',
|
||||||
|
addresses: 'Direcciones',
|
||||||
|
addressEdit: 'Editar dirección',
|
||||||
register: 'Registrarse',
|
register: 'Registrarse',
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
|
recentNews: 'Noticias recientes',
|
||||||
startOrder: 'Empezar pedido',
|
startOrder: 'Empezar pedido',
|
||||||
|
|
||||||
weThinkForYou: 'Pensamos para tí',
|
weThinkForYou: 'Pensamos para tí',
|
||||||
|
@ -87,6 +102,8 @@ export default {
|
||||||
|
|
||||||
// Catalog
|
// Catalog
|
||||||
more: 'Más',
|
more: 'Más',
|
||||||
|
noItemsFound: 'No se han encontrado artículos',
|
||||||
|
pleaseSetFilter: 'Por favor, establece un filtro usando el menú de la derecha',
|
||||||
buy: 'Comprar',
|
buy: 'Comprar',
|
||||||
deleteFilter: 'Eliminar filtro',
|
deleteFilter: 'Eliminar filtro',
|
||||||
viewMore: 'Ver más',
|
viewMore: 'Ver más',
|
||||||
|
@ -102,6 +119,7 @@ export default {
|
||||||
relevancy: 'Relevancia',
|
relevancy: 'Relevancia',
|
||||||
priceAsc: 'Precio ascendente',
|
priceAsc: 'Precio ascendente',
|
||||||
priceDesc: 'Precio descendente',
|
priceDesc: 'Precio descendente',
|
||||||
|
novelty: 'Novedad',
|
||||||
available: 'Disponible',
|
available: 'Disponible',
|
||||||
siceAsc: 'Medida ascendente',
|
siceAsc: 'Medida ascendente',
|
||||||
sizeDesc: 'Medida descendente',
|
sizeDesc: 'Medida descendente',
|
||||||
|
@ -110,6 +128,7 @@ export default {
|
||||||
ordersMadeAt: 'Pedidos realizados en',
|
ordersMadeAt: 'Pedidos realizados en',
|
||||||
pendingConfirmtion: 'Pendientes de confirmar',
|
pendingConfirmtion: 'Pendientes de confirmar',
|
||||||
noOrdersFound: 'No se han encontrado pedidos',
|
noOrdersFound: 'No se han encontrado pedidos',
|
||||||
|
pending: 'Pendientes',
|
||||||
confirmed: 'Confirmados',
|
confirmed: 'Confirmados',
|
||||||
packages: '{n} bultos',
|
packages: '{n} bultos',
|
||||||
|
|
||||||
|
@ -119,10 +138,45 @@ export default {
|
||||||
// About
|
// About
|
||||||
aboutDesc: 'Verdnatura te ofrece todos los servicios que necesita tu floristería.',
|
aboutDesc: 'Verdnatura te ofrece todos los servicios que necesita tu floristería.',
|
||||||
|
|
||||||
|
// Config
|
||||||
|
userName: 'Nombre de usuario',
|
||||||
|
nickname: 'Nombre a mostrar',
|
||||||
|
language: 'Idioma',
|
||||||
|
receiveInvoiceByEmail: 'Recibir facturas por correo eletrónico',
|
||||||
|
passwordRequirements: 'Requisitos de contraseña',
|
||||||
|
charsLong: '{0} carácteres de longitud',
|
||||||
|
alphabeticChars: '{0} carácteres alfabéticos',
|
||||||
|
upperLetters: '{0} letras mayúsculas',
|
||||||
|
digits: '{0} dígitos',
|
||||||
|
simbols: '{0} símbolos. Ej: $%&.',
|
||||||
|
oldPassword: 'Antigua contraseña',
|
||||||
|
newPassword: 'Nueva contraseña',
|
||||||
|
repeatPassword: 'Repetir contraseña',
|
||||||
|
changePassword: 'Cambiar contraseña',
|
||||||
|
passwordCannotBeEmpty: 'La contraseña no puede estar vacía',
|
||||||
|
passwordsDontMatch: 'Las contraseñas no coinciden',
|
||||||
|
passwordChanged: '¡Contraseña modificada correctamente!',
|
||||||
|
|
||||||
|
// Addresses
|
||||||
|
setAsDefault: 'Establecer como predeterminada',
|
||||||
|
addressSetAsDefault: 'Dirección establecida como predeterminada',
|
||||||
|
addressRemoved: 'Dirección eliminada',
|
||||||
|
areYouSureDeleteAddress: '¿Seguro que quieres eliminar la dirección?',
|
||||||
|
addressCreated: '¡Dirección creada correctamente!',
|
||||||
|
|
||||||
|
// Address
|
||||||
|
consignatary: 'Consignatario',
|
||||||
|
street: 'Dirección',
|
||||||
|
city: 'City',
|
||||||
|
postalCode: 'Código postal',
|
||||||
|
province: 'Provincia',
|
||||||
|
country: 'País',
|
||||||
|
phone: 'Teléfono',
|
||||||
|
mobile: 'Móvil',
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
registerAsNew: 'Registrarse como nuevo usuario',
|
registerAsNew: 'Registrarse como nuevo usuario',
|
||||||
notYetUser: '¿Todavía no eres usuari@?, registrate y empieza a disfrutar de todo lo que Verdnatura puede ofrecerte.',
|
notYetUser: '¿Todavía no eres usuari@?, registrate y empieza a disfrutar de todo lo que Verdnatura puede ofrecerte.',
|
||||||
repeatPassword: 'Repetir contraseña',
|
|
||||||
receiveOffers: 'Recibir ofertas y promociones por correo electrónico',
|
receiveOffers: 'Recibir ofertas y promociones por correo electrónico',
|
||||||
userRegistered: 'Usuario registrado correctamente'
|
userRegistered: 'Usuario registrado correctamente'
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
<q-checkbox v-model="remember" :label="$t('remember')" />
|
<q-checkbox v-model="remember" :label="$t('remember')" />
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions class="justify-center">
|
<q-card-actions class="justify-center">
|
||||||
|
<q-btn flat :label="$t('register')" to="/register" />
|
||||||
<q-btn flat :label="$t('enter')" @click="login()" />
|
<q-btn flat :label="$t('enter')" @click="login()" />
|
||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
|
@ -19,36 +19,50 @@
|
||||||
{{$state.subtitle}}
|
{{$state.subtitle}}
|
||||||
</div>
|
</div>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
<q-input
|
|
||||||
v-if="$router.currentRoute.name == 'catalog'"
|
|
||||||
dark
|
|
||||||
dense
|
|
||||||
standout
|
|
||||||
v-model="$state.search">
|
|
||||||
<template v-slot:append>
|
|
||||||
<q-icon v-if="$state.search === ''" name="search" />
|
|
||||||
<q-icon v-else name="clear" class="cursor-pointer" @click="$state.search = ''" />
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
<q-btn flat
|
|
||||||
v-if="$router.currentRoute.name == 'catalog'"
|
|
||||||
class="q-ml-md"
|
|
||||||
:label="$t('configureOrder')"
|
|
||||||
:to="{name: 'orders'}"
|
|
||||||
/>
|
|
||||||
<q-btn flat
|
<q-btn flat
|
||||||
v-if="!$state.userId"
|
v-if="!$state.userId"
|
||||||
class="q-ml-md"
|
class="q-ml-md"
|
||||||
:label="$t('login')"
|
:label="$t('login')"
|
||||||
:to="{name: 'login'}"
|
to="/login"
|
||||||
/>
|
/>
|
||||||
|
<q-input
|
||||||
|
v-if="$router.currentRoute.name == 'catalog'"
|
||||||
|
v-model="$state.search"
|
||||||
|
debounce="500"
|
||||||
|
class="q-mr-sm"
|
||||||
|
dark
|
||||||
|
dense
|
||||||
|
standout>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon
|
||||||
|
v-if="$state.search === ''"
|
||||||
|
name="search"
|
||||||
|
/>
|
||||||
|
<q-icon
|
||||||
|
v-else
|
||||||
|
name="clear"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="$state.search = ''"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-btn
|
||||||
|
v-if="$router.currentRoute.name == 'catalog'"
|
||||||
|
@click="$state.rightDrawerOpen = !$state.rightDrawerOpen"
|
||||||
|
aria-label="Menu"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
round>
|
||||||
|
<q-icon name="menu" />
|
||||||
|
</q-btn>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="leftDrawerOpen"
|
v-model="leftDrawerOpen"
|
||||||
content-class="bg-grey-2"
|
content-class="bg-grey-2"
|
||||||
|
behavior="mobile"
|
||||||
elevated
|
elevated
|
||||||
>
|
overlay>
|
||||||
<div class="q-pa-md shadow-1 q-mb-md bg-grey-10" style="color: white;">
|
<div class="q-pa-md shadow-1 q-mb-md bg-grey-10" style="color: white;">
|
||||||
<img src="statics/logo-dark.svg" alt="Verdnatura" class="logo q-mb-md"/>
|
<img src="statics/logo-dark.svg" alt="Verdnatura" class="logo q-mb-md"/>
|
||||||
<div class="row items-center full-width justify-between">
|
<div class="row items-center full-width justify-between">
|
||||||
|
@ -82,11 +96,21 @@
|
||||||
<q-item-label>{{$t('about')}}</q-item-label>
|
<q-item-label>{{$t('about')}}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable :to="{name: 'register'}">
|
<q-expansion-item
|
||||||
|
expand-icon-toggle
|
||||||
|
expand-separator
|
||||||
|
:label="$t('config')">
|
||||||
|
<q-item clickable :to="{name: 'config'}">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{$t('register')}}</q-item-label>
|
<q-item-label>{{$t('user')}}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
<q-item clickable :to="{name: 'addresses'}">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{$t('addresses')}}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-expansion-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
|
@ -123,7 +147,7 @@ export default {
|
||||||
openURL,
|
openURL,
|
||||||
logout () {
|
logout () {
|
||||||
localStorage.removeItem('token')
|
localStorage.removeItem('token')
|
||||||
this.$router.push('login')
|
this.$router.push('/login')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
<template>
|
||||||
|
<div class="vn-pp row justify-center">
|
||||||
|
<q-card class="vn-w-md">
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="address.nickname" :label="$t('consignatary')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="address.street" :label="$t('street')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="address.city" :label="$t('city')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="address.postalCode" :label="$t('postalCode')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-select
|
||||||
|
v-model="country"
|
||||||
|
:label="$t('country')"
|
||||||
|
:options="countries"
|
||||||
|
option-value="id"
|
||||||
|
option-label="country"/>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-select
|
||||||
|
v-model="province"
|
||||||
|
:label="$t('province')"
|
||||||
|
:options="provinces"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"/>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="address.phone" :label="$t('phone')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions class="justify-center">
|
||||||
|
<q-btn
|
||||||
|
:label="$t('cancel')"
|
||||||
|
to="/addresses"
|
||||||
|
flat/>
|
||||||
|
<q-btn
|
||||||
|
v-if="addressId"
|
||||||
|
:label="$t('save')"
|
||||||
|
@click="onSave"
|
||||||
|
flat/>
|
||||||
|
<q-btn
|
||||||
|
v-if="!addressId"
|
||||||
|
:label="$t('create')"
|
||||||
|
@click="onSave"
|
||||||
|
flat/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Address',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
address: {},
|
||||||
|
addressId: null,
|
||||||
|
provinces: null,
|
||||||
|
countries: null,
|
||||||
|
province: null,
|
||||||
|
country: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
let filter = {
|
||||||
|
fields: ['id', 'country']
|
||||||
|
}
|
||||||
|
this.$axios.get('Countries', { params: { filter } })
|
||||||
|
.then(res => (this.countries = res.data))
|
||||||
|
|
||||||
|
this.loadAddress()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
address () {
|
||||||
|
this.updateCountry()
|
||||||
|
},
|
||||||
|
countries () {
|
||||||
|
this.updateCountry()
|
||||||
|
},
|
||||||
|
provinces () {
|
||||||
|
this.updateProvince()
|
||||||
|
},
|
||||||
|
country () {
|
||||||
|
this.loadProvinces()
|
||||||
|
},
|
||||||
|
province (value) {
|
||||||
|
if (!this.address.provinceFk) return
|
||||||
|
this.address.provinceFk = value && value.id
|
||||||
|
},
|
||||||
|
'this.$route.params.address': function () {
|
||||||
|
this.loadAddress()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadAddress () {
|
||||||
|
this.addressId = this.$route.params.address
|
||||||
|
this.address = {}
|
||||||
|
|
||||||
|
if (this.addressId) {
|
||||||
|
let filter = {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'nickname',
|
||||||
|
'street',
|
||||||
|
'city',
|
||||||
|
'postalCode',
|
||||||
|
'provinceFk',
|
||||||
|
'phone'
|
||||||
|
],
|
||||||
|
include: {
|
||||||
|
relation: 'province',
|
||||||
|
scope: {
|
||||||
|
fields: ['countryFk']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$axios.get(`Addresses/${this.addressId}`, { params: { filter } })
|
||||||
|
.then(res => (this.address = res.data))
|
||||||
|
} else {
|
||||||
|
this.address = {
|
||||||
|
clientFk: this.$state.userId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadProvinces () {
|
||||||
|
this.provinces = null
|
||||||
|
if (!this.country) return
|
||||||
|
|
||||||
|
let filter = {
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
where: { countryFk: this.country.id }
|
||||||
|
}
|
||||||
|
this.$axios.get('Provinces', { params: { filter } })
|
||||||
|
.then(res => (this.provinces = res.data))
|
||||||
|
},
|
||||||
|
updateCountry () {
|
||||||
|
if (!this.countries || !this.address.province) return
|
||||||
|
this.country = this.countries.find(
|
||||||
|
i => i.id === this.address.province.countryFk)
|
||||||
|
},
|
||||||
|
updateProvince () {
|
||||||
|
if (!this.provinces) return
|
||||||
|
let province = this.provinces.find(
|
||||||
|
i => i.id === this.address.provinceFk)
|
||||||
|
if (province) this.province = province
|
||||||
|
},
|
||||||
|
onSave () {
|
||||||
|
if (this.addressId) {
|
||||||
|
this.$axios.patch(`Addresses/${this.addressId}`, this.address)
|
||||||
|
.then(res => {
|
||||||
|
this.$q.notify(this.$t('dataSaved'))
|
||||||
|
this.$router.push('/addresses')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$axios.post(`Addresses`, this.address)
|
||||||
|
.then(res => {
|
||||||
|
this.$q.notify(this.$t('addressCreated'))
|
||||||
|
this.$router.push('/addresses')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,141 @@
|
||||||
|
<template>
|
||||||
|
<div class="vn-pp row justify-center">
|
||||||
|
<q-card class="vn-w-md">
|
||||||
|
<q-list bordered separator>
|
||||||
|
<q-item v-if="addresses && !addresses.length">
|
||||||
|
{{$t('noDataFound')}}
|
||||||
|
</q-item>
|
||||||
|
<q-item
|
||||||
|
v-for="(address, index) in addresses"
|
||||||
|
:key="address.id"
|
||||||
|
:to="`/address/${address.id}`"
|
||||||
|
clickable
|
||||||
|
v-ripple>
|
||||||
|
<q-item-section side top>
|
||||||
|
<q-radio
|
||||||
|
v-model="defaultAddress"
|
||||||
|
:val="address.id"
|
||||||
|
:title="$t('setAsDefault')"/>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label class="ellipsis">
|
||||||
|
{{address.nickname}}
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label class="ellipsis" caption>
|
||||||
|
{{address.street}}
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label class="ellipsis" caption>
|
||||||
|
{{address.postalCode}} {{address.city}}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side top>
|
||||||
|
<q-btn
|
||||||
|
icon="delete"
|
||||||
|
@click="deleteAddress(index, $event)"
|
||||||
|
:title="$t('delete')"
|
||||||
|
size="12px"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
round/>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card>
|
||||||
|
<q-dialog v-model="confirm" persistent>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
{{$t('areYouSureDeleteAddress')}}
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn
|
||||||
|
:label="$t('cancel')"
|
||||||
|
v-close-popup
|
||||||
|
flat
|
||||||
|
color="primary"/>
|
||||||
|
<q-btn
|
||||||
|
:label="$t('accept')"
|
||||||
|
@click="confirmDeletion(deleteIndex)"
|
||||||
|
v-close-popup
|
||||||
|
flat
|
||||||
|
color="primary"/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
||||||
|
<q-btn
|
||||||
|
fab
|
||||||
|
icon="add"
|
||||||
|
color="accent"
|
||||||
|
to="/address"
|
||||||
|
:title="$t('add')"
|
||||||
|
/>
|
||||||
|
</q-page-sticky>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Addresses',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
addresses: null,
|
||||||
|
defaultAddress: null,
|
||||||
|
confirm: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
let filter = {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'nickname',
|
||||||
|
'street',
|
||||||
|
'city',
|
||||||
|
'postalCode'
|
||||||
|
],
|
||||||
|
where: {
|
||||||
|
clientFk: this.$state.userId,
|
||||||
|
isActive: true
|
||||||
|
},
|
||||||
|
order: 'nickname'
|
||||||
|
}
|
||||||
|
this.$axios.get('Addresses', { params: { filter } })
|
||||||
|
.then(res => (this.addresses = res.data))
|
||||||
|
|
||||||
|
filter = {
|
||||||
|
fields: ['defaultAddressFk']
|
||||||
|
}
|
||||||
|
this.$axios.get(`Clients/${this.$state.userId}`, { params: { filter } })
|
||||||
|
.then(res => (this.defaultAddress = res.data.defaultAddressFk))
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
defaultAddress (value, oldValue) {
|
||||||
|
if (!oldValue) return
|
||||||
|
let data = { defaultAddressFk: value }
|
||||||
|
this.$axios.patch(`Clients/${this.$state.userId}`, data)
|
||||||
|
.then(res => {
|
||||||
|
this.$q.notify(this.$t('addressSetAsDefault'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
deleteAddress (index, event) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
this.confirm = true
|
||||||
|
this.deleteIndex = index
|
||||||
|
},
|
||||||
|
confirmDeletion (index) {
|
||||||
|
let address = this.addresses[index]
|
||||||
|
let data = { isActive: false }
|
||||||
|
this.$axios.patch(`Addresses/${address.id}`, data)
|
||||||
|
.then(res => {
|
||||||
|
this.addresses.splice(index, 1)
|
||||||
|
this.$q.notify(this.$t('addressRemoved'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="padding-bottom: 5em;">
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="rightDrawerOpen"
|
v-model="$state.rightDrawerOpen"
|
||||||
content-class="bg-grey-2"
|
content-class="bg-grey-2"
|
||||||
side="right"
|
side="right"
|
||||||
elevated>
|
elevated>
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
name="cancel"
|
name="cancel"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
:title="$t('deleteFilter')"
|
:title="$t('deleteFilter')"
|
||||||
:to="{params: {category: null}}"
|
@click="$router.push({params: {category: null}})"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
:class="{active: category == cat.id}"
|
:class="{active: category == cat.id}"
|
||||||
:key="cat.id"
|
:key="cat.id"
|
||||||
:title="cat.name"
|
:title="cat.name"
|
||||||
:to="{params: {category: cat.id}}">
|
:to="{params: {category: cat.id, type: null}}">
|
||||||
<img
|
<img
|
||||||
class="category-img"
|
class="category-img"
|
||||||
:src="`statics/category/${cat.id}.svg`">
|
:src="`statics/category/${cat.id}.svg`">
|
||||||
|
@ -40,6 +40,7 @@
|
||||||
clearable
|
clearable
|
||||||
:label="$t('family')"
|
:label="$t('family')"
|
||||||
@filter="filterType"
|
@filter="filterType"
|
||||||
|
@input="$router.push({params: {type: type && type.id}})"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
|
@ -66,14 +67,14 @@
|
||||||
</div>
|
</div>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<div class="q-pa-md"
|
<div class="q-pa-md"
|
||||||
v-if="type || search">
|
v-if="typeId || search">
|
||||||
<div class="q-mb-md"
|
<div class="q-mb-md"
|
||||||
v-for="tag in tags"
|
v-for="tag in tags"
|
||||||
:key="tag.uid">
|
:key="tag.uid">
|
||||||
<div class="q-mb-xs text-caption text-grey-7">
|
<div class="q-mb-xs text-caption text-grey-7">
|
||||||
{{tag.name}}
|
{{tag.name}}
|
||||||
<q-icon
|
<q-icon
|
||||||
v-if="tag.filter.length || tag.filter.min || tag.filter.max"
|
v-if="tag.hasFilter"
|
||||||
style="font-size: 1.3em;"
|
style="font-size: 1.3em;"
|
||||||
name="cancel"
|
name="cancel"
|
||||||
:title="$t('deleteFilter')"
|
:title="$t('deleteFilter')"
|
||||||
|
@ -90,7 +91,7 @@
|
||||||
:dense="true"
|
:dense="true"
|
||||||
:val="value"
|
:val="value"
|
||||||
:label="value"
|
:label="value"
|
||||||
@input="loadItems"
|
@input="onCheck(tag)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="tag.values.length > tag.showCount">
|
<div v-if="tag.values.length > tag.showCount">
|
||||||
|
@ -118,8 +119,9 @@
|
||||||
:min="tag.min"
|
:min="tag.min"
|
||||||
:max="tag.max"
|
:max="tag.max"
|
||||||
:step="tag.step"
|
:step="tag.step"
|
||||||
@input="loadItemsDelayed"
|
:color="tag.hasFilter ? 'primary' : 'grey-6'"
|
||||||
@change="loadItems"
|
@input="onRangeChange(tag, true)"
|
||||||
|
@change="onRangeChange(tag)"
|
||||||
label-always
|
label-always
|
||||||
markers
|
markers
|
||||||
snap
|
snap
|
||||||
|
@ -139,29 +141,45 @@
|
||||||
color="primary"
|
color="primary"
|
||||||
size="50px">
|
size="50px">
|
||||||
</q-spinner>
|
</q-spinner>
|
||||||
|
<div
|
||||||
|
v-if="items && !items.length"
|
||||||
|
class="text-subtitle1 text-grey-7 q-pa-md">
|
||||||
|
{{$t('noItemsFound')}}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!items && !isLoading"
|
||||||
|
class="text-subtitle1 text-grey-7 q-pa-md">
|
||||||
|
{{$t('pleaseSetFilter')}}
|
||||||
|
</div>
|
||||||
<q-card
|
<q-card
|
||||||
class="my-card"
|
class="my-card"
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
:key="item.id">
|
:key="item.id">
|
||||||
<img :src="`${$imageBase}/catalog/200x200/${item.image}`" />
|
<img :src="`${$imageBase}/catalog/200x200/${item.image}`" />
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="name text-subtitle1">{{item.longName}}</div>
|
<div class="name text-subtitle1">
|
||||||
<div class="text-uppercase text-subtitle1 text-grey-7">
|
{{item.longName}}
|
||||||
|
</div>
|
||||||
|
<div class="sub-name text-uppercase text-subtitle1 text-grey-7 ellipsize q-pt-xs">
|
||||||
{{item.subName}}
|
{{item.subName}}
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
<div class="tags q-pt-xs">
|
||||||
<q-card-section class="tags">
|
|
||||||
<div v-for="tag in item.tags" :key="tag.tagFk">
|
<div v-for="tag in item.tags" :key="tag.tagFk">
|
||||||
<span class="text-grey-7">{{tag.tag.name}}</span> {{tag.value}}
|
<span class="text-grey-7">{{tag.tag.name}}</span> {{tag.value}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions class="actions justify-between">
|
<q-card-actions class="actions justify-between">
|
||||||
<div class="q-pl-sm">
|
<div class="q-pl-sm">
|
||||||
<span class="available bg-green text-white">{{item.available}}</span>
|
<span class="available bg-green text-white">{{item.available}}</span>
|
||||||
{{$t('from')}}
|
{{$t('from')}}
|
||||||
<span class="price">{{item.inbounds[0].buy && item.inbounds[0].buy.price3 | currency}}</span>
|
<span class="price">{{item.buy && item.buy.price3 | currency}}</span>
|
||||||
</div>
|
</div>
|
||||||
<q-btn flat>{{$t('buy')}}</q-btn>
|
<q-btn
|
||||||
|
icon="add_shopping_cart"
|
||||||
|
:title="$t('buy')"
|
||||||
|
flat>
|
||||||
|
</q-btn>
|
||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
|
@ -171,16 +189,27 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</q-infinite-scroll>
|
</q-infinite-scroll>
|
||||||
|
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
||||||
|
<q-btn
|
||||||
|
fab
|
||||||
|
icon="shopping_basket"
|
||||||
|
color="accent"
|
||||||
|
:to="{name: 'orders'}"
|
||||||
|
:title="$t('orders')"
|
||||||
|
/>
|
||||||
|
</q-page-sticky>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.my-card
|
.my-card
|
||||||
width 100%
|
width 100%
|
||||||
max-width 21em
|
max-width 17.5em
|
||||||
height 38em
|
height 32.5em
|
||||||
overflow hidden
|
overflow hidden
|
||||||
.name
|
.name, .sub-name
|
||||||
|
line-height 1.3em
|
||||||
|
.ellipsize
|
||||||
white-space nowrap
|
white-space nowrap
|
||||||
overflow hidden
|
overflow hidden
|
||||||
text-overflow ellipsis
|
text-overflow ellipsis
|
||||||
|
@ -194,7 +223,7 @@
|
||||||
.category-img
|
.category-img
|
||||||
height 3.5em
|
height 3.5em
|
||||||
.tags
|
.tags
|
||||||
max-height 6.2em
|
max-height 4.6em
|
||||||
overflow hidden
|
overflow hidden
|
||||||
.available
|
.available
|
||||||
padding .15em
|
padding .15em
|
||||||
|
@ -223,26 +252,35 @@ export default {
|
||||||
date: date.formatDate(new Date(), 'YYYY/MM/DD'),
|
date: date.formatDate(new Date(), 'YYYY/MM/DD'),
|
||||||
category: null,
|
category: null,
|
||||||
categories: [],
|
categories: [],
|
||||||
tags: [],
|
|
||||||
type: null,
|
type: null,
|
||||||
|
typeId: null,
|
||||||
types: [],
|
types: [],
|
||||||
orgTypes: [],
|
orgTypes: [],
|
||||||
|
tags: [],
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
items: null,
|
items: null,
|
||||||
rightDrawerOpen: this.$q.platform.is.desktop,
|
|
||||||
pageSize: 24,
|
|
||||||
limit: null,
|
limit: null,
|
||||||
|
pageSize: 30,
|
||||||
maxTags: 5,
|
maxTags: 5,
|
||||||
disableScroll: true,
|
disableScroll: true,
|
||||||
order: {
|
order: {
|
||||||
label: this.$t('name'),
|
label: this.$t('relevancy'),
|
||||||
value: 'name'
|
value: 'relevancy DESC, longName'
|
||||||
},
|
},
|
||||||
orderOptions: [
|
orderOptions: [
|
||||||
{
|
{
|
||||||
|
label: this.$t('relevancy'),
|
||||||
|
value: 'relevancy DESC, longName'
|
||||||
|
}, {
|
||||||
label: this.$t('name'),
|
label: this.$t('name'),
|
||||||
value: 'longName'
|
value: 'longName'
|
||||||
}, /* {
|
}, {
|
||||||
|
label: this.$t('siceAsc'),
|
||||||
|
value: 'size ASC'
|
||||||
|
}, {
|
||||||
|
label: this.$t('sizeDesc'),
|
||||||
|
value: 'size DESC'
|
||||||
|
} /* {
|
||||||
label: this.$t('priceAsc'),
|
label: this.$t('priceAsc'),
|
||||||
value: 'price ASC'
|
value: 'price ASC'
|
||||||
}, {
|
}, {
|
||||||
|
@ -251,71 +289,92 @@ export default {
|
||||||
}, {
|
}, {
|
||||||
label: this.$t('available'),
|
label: this.$t('available'),
|
||||||
value: 'available'
|
value: 'available'
|
||||||
}, */ {
|
|
||||||
label: this.$t('siceAsc'),
|
|
||||||
value: 'size ASC'
|
|
||||||
}, {
|
}, {
|
||||||
label: this.$t('sizeDesc'),
|
label: this.$t('novelty'),
|
||||||
value: 'size DESC'
|
value: 'dated DESC'
|
||||||
}
|
} */
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$axios.get('ItemCategories')
|
this.$axios.get('ItemCategories')
|
||||||
.then(res => (this.categories = res.data))
|
.then(res => (this.categories = res.data))
|
||||||
|
this.onRouteChange(this.$route)
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.clearTimeoutAndRequest()
|
this.clearTimeoutAndRequest()
|
||||||
},
|
},
|
||||||
|
beforeRouteUpdate (to, from, next) {
|
||||||
|
this.onRouteChange(to)
|
||||||
|
next()
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
categories () {
|
||||||
|
this.refreshTitle()
|
||||||
|
},
|
||||||
|
orgTypes () {
|
||||||
|
this.refreshTitle()
|
||||||
|
},
|
||||||
order () {
|
order () {
|
||||||
this.loadItems()
|
this.loadItems()
|
||||||
},
|
},
|
||||||
date () {
|
date () {
|
||||||
this.loadItems()
|
this.loadItems()
|
||||||
},
|
},
|
||||||
type (type) {
|
category (value) {
|
||||||
this.$router.push({
|
this.orgTypes = []
|
||||||
params: {
|
|
||||||
category: this.category,
|
if (value) {
|
||||||
type: type && type.id
|
let filter = {
|
||||||
|
where: { categoryFk: value },
|
||||||
|
order: 'order DESC, name'
|
||||||
|
}
|
||||||
|
this.$axios.get('ItemTypes', { params: { filter } })
|
||||||
|
.then(res => (this.orgTypes = res.data))
|
||||||
}
|
}
|
||||||
})
|
|
||||||
this.$state.subtitle = type && type.name
|
|
||||||
this.$state.search = ''
|
|
||||||
this.loadItems()
|
|
||||||
},
|
},
|
||||||
'$state.search': function (value) {
|
'$state.search': function (value) {
|
||||||
if (!value) this.loadItems()
|
let location = { params: this.$route.params }
|
||||||
else this.loadItemsDelayed()
|
if (value) location.query = { search: value }
|
||||||
},
|
this.$router.push(location)
|
||||||
'$route.params.category': function (categoryId) {
|
|
||||||
let category = this.categories.find(i => i.id === categoryId)
|
|
||||||
|
|
||||||
if (category) {
|
|
||||||
this.$state.title = category.name
|
|
||||||
this.$state.titleColor = `#${category.color}`
|
|
||||||
} else {
|
|
||||||
this.$state.title = this.$t(this.$router.currentRoute.name)
|
|
||||||
this.$state.titleColor = null
|
|
||||||
}
|
|
||||||
|
|
||||||
this.category = categoryId
|
|
||||||
this.type = null
|
|
||||||
|
|
||||||
let params = { filter: { where: { categoryFk: categoryId } } }
|
|
||||||
this.$axios.get('ItemTypes', { params })
|
|
||||||
.then(res => (this.orgTypes = res.data))
|
|
||||||
},
|
|
||||||
'$route.params.type': function (type) {
|
|
||||||
if (!this.type) this.type = { id: type }
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadItemsDelayed () {
|
onRouteChange (route) {
|
||||||
this.clearTimeoutAndRequest()
|
let { category, type } = route.params
|
||||||
this.timeout = setTimeout(() => this.loadItems(), 500)
|
|
||||||
|
category = parseInt(category) || null
|
||||||
|
type = parseInt(type) || null
|
||||||
|
|
||||||
|
this.category = category
|
||||||
|
this.typeId = category ? type : null
|
||||||
|
this.search = route.query.search || ''
|
||||||
|
this.$state.search = this.search
|
||||||
|
this.tags = []
|
||||||
|
|
||||||
|
this.refreshTitle()
|
||||||
|
this.loadItems()
|
||||||
|
},
|
||||||
|
refreshTitle () {
|
||||||
|
let title = this.$t(this.$router.currentRoute.name)
|
||||||
|
let titleColor
|
||||||
|
let subtitle
|
||||||
|
|
||||||
|
if (this.category) {
|
||||||
|
let category = this.categories.find(i => i.id === this.category) || {}
|
||||||
|
title = category.name
|
||||||
|
titleColor = `#${category.color}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.typeId) {
|
||||||
|
this.type = this.orgTypes.find(i => i.id === this.typeId)
|
||||||
|
subtitle = title
|
||||||
|
title = this.type && this.type.name
|
||||||
|
} else {
|
||||||
|
this.type = null
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this.$state, { title, titleColor, subtitle })
|
||||||
},
|
},
|
||||||
clearTimeoutAndRequest () {
|
clearTimeoutAndRequest () {
|
||||||
if (this.timeout) {
|
if (this.timeout) {
|
||||||
|
@ -327,34 +386,36 @@ export default {
|
||||||
this.source = null
|
this.source = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
loadItemsDelayed () {
|
||||||
|
this.clearTimeoutAndRequest()
|
||||||
|
this.timeout = setTimeout(() => this.loadItems(), 500)
|
||||||
|
},
|
||||||
loadItems () {
|
loadItems () {
|
||||||
this.items = []
|
this.items = null
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
this.limit = this.pageSize
|
this.limit = this.pageSize
|
||||||
this.disableScroll = false
|
this.disableScroll = false
|
||||||
this.loadItemsBase()
|
this.loadItemsBase()
|
||||||
.finally(() => {
|
.finally(() => (this.isLoading = false))
|
||||||
this.isLoading = false
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
onLoad (index, done) {
|
onLoad (index, done) {
|
||||||
if (this.isLoading) return done()
|
if (this.isLoading) return done()
|
||||||
this.limit += this.pageSize
|
this.limit += this.pageSize
|
||||||
this.loadItemsBase()
|
this.loadItemsBase()
|
||||||
.finally(() => done())
|
.finally(done)
|
||||||
},
|
},
|
||||||
loadItemsBase () {
|
loadItemsBase () {
|
||||||
this.clearTimeoutAndRequest()
|
this.clearTimeoutAndRequest()
|
||||||
|
|
||||||
if (!this.type) {
|
if (!(this.category || this.typeId || this.search)) {
|
||||||
|
this.tags = []
|
||||||
return Promise.resolve(true)
|
return Promise.resolve(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
let typeFk
|
|
||||||
let tagFilter = []
|
let tagFilter = []
|
||||||
|
|
||||||
for (let tag of this.tags) {
|
for (let tag of this.tags) {
|
||||||
if (this.hasFilters(tag)) {
|
if (tag.hasFilter) {
|
||||||
tagFilter.push({
|
tagFilter.push({
|
||||||
tagFk: tag.id,
|
tagFk: tag.id,
|
||||||
values: tag.filter
|
values: tag.filter
|
||||||
|
@ -362,19 +423,16 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.type) {
|
|
||||||
typeFk = this.type.id
|
|
||||||
}
|
|
||||||
|
|
||||||
this.source = CancelToken.source()
|
this.source = CancelToken.source()
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
dated: this.date,
|
dated: this.date,
|
||||||
typeFk: typeFk,
|
typeFk: this.typeId,
|
||||||
search: this.$state.search,
|
categoryFk: this.category,
|
||||||
|
search: this.search,
|
||||||
order: this.order.value,
|
order: this.order.value,
|
||||||
tagFilter: tagFilter,
|
limit: this.limit,
|
||||||
limit: this.limit
|
tagFilter
|
||||||
}
|
}
|
||||||
let config = {
|
let config = {
|
||||||
params,
|
params,
|
||||||
|
@ -382,14 +440,20 @@ export default {
|
||||||
}
|
}
|
||||||
return this.$axios.get('Items/catalog', config)
|
return this.$axios.get('Items/catalog', config)
|
||||||
.then(res => this.onItemsGet(res))
|
.then(res => this.onItemsGet(res))
|
||||||
.catch(err => { if (!err.__CANCEL__) throw err })
|
.catch(err => this.onItemsError(err))
|
||||||
.finally(() => (this.cancel = null))
|
.finally(() => (this.cancel = null))
|
||||||
},
|
},
|
||||||
|
onItemsError (err) {
|
||||||
|
if (err.__CANCEL__) return
|
||||||
|
this.disableScroll = true
|
||||||
|
throw err
|
||||||
|
},
|
||||||
onItemsGet (res) {
|
onItemsGet (res) {
|
||||||
for (let tag of res.data.tags) {
|
for (let tag of res.data.tags) {
|
||||||
tag.uid = this.uid++
|
tag.uid = this.uid++
|
||||||
|
|
||||||
if (tag.filter) {
|
if (tag.filter) {
|
||||||
|
tag.hasFilter = true
|
||||||
tag.useRange =
|
tag.useRange =
|
||||||
tag.filter.max ||
|
tag.filter.max ||
|
||||||
tag.filter.min
|
tag.filter.min
|
||||||
|
@ -412,11 +476,23 @@ export default {
|
||||||
this.tags = res.data.tags
|
this.tags = res.data.tags
|
||||||
this.disableScroll = this.items.length < this.limit
|
this.disableScroll = this.items.length < this.limit
|
||||||
},
|
},
|
||||||
|
onRangeChange (tag, delay) {
|
||||||
|
tag.hasFilter = true
|
||||||
|
|
||||||
|
if (!delay) this.loadItems()
|
||||||
|
else this.loadItemsDelayed()
|
||||||
|
},
|
||||||
|
onCheck (tag) {
|
||||||
|
tag.hasFilter = tag.filter.length > 0
|
||||||
|
this.loadItems()
|
||||||
|
},
|
||||||
resetTagFilter (tag) {
|
resetTagFilter (tag) {
|
||||||
|
tag.hasFilter = false
|
||||||
|
|
||||||
if (tag.useRange) {
|
if (tag.useRange) {
|
||||||
tag.filter = {
|
tag.filter = {
|
||||||
min: null,
|
min: tag.min,
|
||||||
max: null
|
max: tag.max
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tag.filter = []
|
tag.filter = []
|
||||||
|
@ -426,10 +502,6 @@ export default {
|
||||||
this.resetTagFilter(tag)
|
this.resetTagFilter(tag)
|
||||||
this.loadItems()
|
this.loadItems()
|
||||||
},
|
},
|
||||||
hasFilters (tag) {
|
|
||||||
let filter = tag.filter
|
|
||||||
return filter.length || filter.min || filter.max
|
|
||||||
},
|
|
||||||
filterType (val, update) {
|
filterType (val, update) {
|
||||||
if (val === '') {
|
if (val === '') {
|
||||||
update(() => { this.types = this.orgTypes })
|
update(() => { this.types = this.orgTypes })
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
<template>
|
||||||
|
<div class="vn-pp row justify-center">
|
||||||
|
<q-card class="vn-w-md">
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input
|
||||||
|
v-model="user.name"
|
||||||
|
:label="$t('userName')"
|
||||||
|
readonly/>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="user.email" :label="$t('email')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input v-model="user.nickname" :label="$t('nickname')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-select
|
||||||
|
v-model="user.lang"
|
||||||
|
:label="$t('language')"
|
||||||
|
:options="languages"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-checkbox v-model="receiveInvoices" :label="$t('receiveInvoiceByEmail')" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions class="justify-center">
|
||||||
|
<q-btn flat :label="$t('changePassword')" :to="{ query: { changePassword: true } }"/>
|
||||||
|
<q-btn flat :label="$t('save')" @click="onSave"/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
<q-dialog v-model="changePassword" persistent>
|
||||||
|
<q-card style="width: 25em;">
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
v-model="oldPassword"
|
||||||
|
:label="$t('oldPassword')"
|
||||||
|
type="password"
|
||||||
|
:rules="[val => !!val || $t('fieldIsRequired')]"
|
||||||
|
autofocus
|
||||||
|
dense/>
|
||||||
|
<q-input
|
||||||
|
v-model="newPassword"
|
||||||
|
:label="$t('newPassword')"
|
||||||
|
type="password"
|
||||||
|
:rules="[val => !!val || $t('passwordCannotBeEmpty')]"
|
||||||
|
dense>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="warning">
|
||||||
|
<q-tooltip>
|
||||||
|
<div>
|
||||||
|
{{$t('passwordRequirements')}}
|
||||||
|
</div>
|
||||||
|
<ul class="q-pl-md">
|
||||||
|
<li>{{$t('charsLong', [requirements.length])}}</li>
|
||||||
|
<li>{{$t('alphabeticChars', [requirements.nAlpha])}}</li>
|
||||||
|
<li>{{$t('upperLetters', [requirements.nUpper])}}</li>
|
||||||
|
<li>{{$t('digits', [requirements.nDigits])}}</li>
|
||||||
|
<li>{{$t('simbols', [requirements.nPunct])}}</li>
|
||||||
|
</ul>
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-input
|
||||||
|
v-model="repeatPassword"
|
||||||
|
:label="$t('repeatPassword')"
|
||||||
|
type="password"
|
||||||
|
:rules="[val => val === newPassword || $t('passwordsDontMatch')]"
|
||||||
|
dense/>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn
|
||||||
|
:label="$t('cancel')"
|
||||||
|
to="/config"
|
||||||
|
flat
|
||||||
|
color="primary"/>
|
||||||
|
<q-btn
|
||||||
|
:label="$t('accept')"
|
||||||
|
@click="onChangePassword()"
|
||||||
|
flat
|
||||||
|
color="primary"/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Config',
|
||||||
|
props: {
|
||||||
|
changePassword: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
user: {},
|
||||||
|
receiveInvoices: false,
|
||||||
|
languages: null,
|
||||||
|
requirements: {},
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
repeatPassword: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
let filter = {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'nickname',
|
||||||
|
'lang',
|
||||||
|
'email'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.$axios.get(`Accounts/${this.$state.userId}`, { params: { filter } })
|
||||||
|
.then(res => (this.user = res.data))
|
||||||
|
|
||||||
|
filter = {
|
||||||
|
fields: [
|
||||||
|
'code',
|
||||||
|
'name',
|
||||||
|
'orgName'
|
||||||
|
],
|
||||||
|
where: { isActive: true }
|
||||||
|
}
|
||||||
|
this.$axios.get(`Languages`, { params: { filter } })
|
||||||
|
.then(res => (this.languages = res.data))
|
||||||
|
|
||||||
|
filter = {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'length',
|
||||||
|
'nAlpha',
|
||||||
|
'nUpper',
|
||||||
|
'nDigits',
|
||||||
|
'nPunct'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.$axios.get(`UserPasswords`, { params: { filter } })
|
||||||
|
.then(res => (this.requirements = res.data[0]))
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChangePassword: function () {
|
||||||
|
this.$q.notify(this.$t('passwordChanged'))
|
||||||
|
this.$router.push('/config')
|
||||||
|
|
||||||
|
this.oldPassword = ''
|
||||||
|
this.newPassword = ''
|
||||||
|
this.repeatPassword = ''
|
||||||
|
},
|
||||||
|
onSave () {
|
||||||
|
this.$axios.patch(`Accounts/${this.$state.userId}`, this.user)
|
||||||
|
.then(res => (this.$q.notify(this.$t('dataSaved'))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<div class="my-list q-pa-md">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<q-select v-model="yearFilter" :options="years" :label="$t('ordersMadeAt')" />
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
<q-card class="q-mt-md">
|
||||||
|
<q-list bordered separator>
|
||||||
|
<q-item v-if="!tickets.length">
|
||||||
|
{{$t('noOrdersFound')}}
|
||||||
|
</q-item>
|
||||||
|
<q-item
|
||||||
|
v-for="ticket in tickets"
|
||||||
|
:key="ticket.id"
|
||||||
|
clickable
|
||||||
|
v-ripple>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{formatDate(ticket.landed)}}</q-item-label>
|
||||||
|
<q-item-label caption>#{{ticket.id}}</q-item-label>
|
||||||
|
<q-item-label caption>{{ticket.address.nickname}}</q-item-label>
|
||||||
|
<q-item-label caption>{{ticket.address.city}}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side top>
|
||||||
|
<q-item-label>
|
||||||
|
485.50€
|
||||||
|
</q-item-label>
|
||||||
|
<q-badge
|
||||||
|
v-if="ticket.state"
|
||||||
|
color="teal"
|
||||||
|
:label="ticket.state.state.name"/>
|
||||||
|
<q-item-label v-if="ticket.packages" caption>
|
||||||
|
{{$t('packages', {n: ticket.packages})}}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.my-list
|
||||||
|
max-width 30em
|
||||||
|
margin auto
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { date } from 'quasar'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Orders',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
yearFilter: null,
|
||||||
|
years: [],
|
||||||
|
tickets: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
let now = new Date()
|
||||||
|
let curYear = now.getFullYear()
|
||||||
|
|
||||||
|
for (let i = 0; i <= 5; i++) {
|
||||||
|
this.years.push(curYear - i)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.yearFilter = curYear
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
yearFilter (year) {
|
||||||
|
let start = new Date(year, 0)
|
||||||
|
let end = new Date(year + 1, 0)
|
||||||
|
|
||||||
|
let params = { filter: {
|
||||||
|
where: {
|
||||||
|
clientFk: this.$state.userId,
|
||||||
|
landed: { between: [start, end] }
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
'address',
|
||||||
|
{ state: 'state' }
|
||||||
|
],
|
||||||
|
order: 'landed DESC'
|
||||||
|
} }
|
||||||
|
this.$axios.get('Tickets', { params })
|
||||||
|
.then(res => (this.tickets = res.data))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatDate (value) {
|
||||||
|
return date.formatDate(value, 'ddd, MMMM Do', this.$t('date'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -29,6 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
</q-carousel-slide>
|
</q-carousel-slide>
|
||||||
</q-carousel>
|
</q-carousel>
|
||||||
|
<h2 class="text-center text-grey-7">{{$t('recentNews')}}</h2>
|
||||||
<div class="q-pa-sm row items-start">
|
<div class="q-pa-sm row items-start">
|
||||||
<div
|
<div
|
||||||
class="new-card q-pa-sm"
|
class="new-card q-pa-sm"
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
||||||
<q-btn
|
<q-btn
|
||||||
fab
|
fab
|
||||||
icon="shopping_basket"
|
icon="add_shopping_cart"
|
||||||
color="accent"
|
color="accent"
|
||||||
:to="{name: 'catalog'}"
|
:to="{name: 'catalog'}"
|
||||||
:title="$t('startOrder')"
|
:title="$t('startOrder')"
|
||||||
|
@ -113,7 +114,6 @@ export default {
|
||||||
name: 'PageIndex',
|
name: 'PageIndex',
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
slideIndex: 0,
|
|
||||||
slide: null,
|
slide: null,
|
||||||
slides: [
|
slides: [
|
||||||
{
|
{
|
||||||
|
@ -154,13 +154,14 @@ export default {
|
||||||
this.$axios.get('News', { params })
|
this.$axios.get('News', { params })
|
||||||
.then(res => (this.news = res.data))
|
.then(res => (this.news = res.data))
|
||||||
|
|
||||||
this.slide = this.slides[this.slideIndex].image
|
this.slide = this.slides[0].image
|
||||||
this.interval = setInterval(() => {
|
this.interval = setInterval(() => {
|
||||||
this.slideIndex = (this.slideIndex + 1) % this.slides.length
|
let index = this.slides.findIndex(i => i.image === this.slide)
|
||||||
this.slide = this.slides[this.slideIndex].image
|
let nextIndex = (index + 1) % this.slides.length
|
||||||
|
this.slide = this.slides[nextIndex].image
|
||||||
}, 8000)
|
}, 8000)
|
||||||
},
|
},
|
||||||
destroyed () {
|
beforeDestroy () {
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,69 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="my-list q-pa-md">
|
<div>
|
||||||
<q-card>
|
<q-tabs
|
||||||
<q-list bordered separator>
|
inline-label
|
||||||
<q-item-label header>{{$t('pendingConfirmtion')}}</q-item-label>
|
class="bg-secondary text-white shadow-2">
|
||||||
<q-item v-if="!orders.length">
|
<q-route-tab to="/orders/pending" icon="av_timer" :label="$t('pending')" />
|
||||||
{{$t('noOrdersFound')}}
|
<q-route-tab to="/orders/confirmed" icon="check" :label="$t('confirmed')" />
|
||||||
</q-item>
|
</q-tabs>
|
||||||
<q-item
|
<router-view></router-view>
|
||||||
v-for="order in orders"
|
|
||||||
:key="order.id"
|
|
||||||
clickable
|
|
||||||
v-ripple>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label>{{formatDate(order.landed)}}</q-item-label>
|
|
||||||
<q-item-label caption>#{{order.id}}</q-item-label>
|
|
||||||
<q-item-label caption>{{order.address.nickname}}</q-item-label>
|
|
||||||
<q-item-label caption>{{order.address.city}}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section side top>
|
|
||||||
485.50€
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-card>
|
|
||||||
<q-card class="q-mt-md">
|
|
||||||
<q-card-section>
|
|
||||||
<q-select v-model="yearFilter" :options="years" :label="$t('ordersMadeAt')" />
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
<q-card class="q-mt-md">
|
|
||||||
<q-list bordered separator>
|
|
||||||
<q-item-label header>{{$t('confirmed')}}</q-item-label>
|
|
||||||
<q-item v-if="!tickets.length">
|
|
||||||
{{$t('noOrdersFound')}}
|
|
||||||
</q-item>
|
|
||||||
<q-item
|
|
||||||
v-for="ticket in tickets"
|
|
||||||
:key="ticket.id"
|
|
||||||
clickable
|
|
||||||
v-ripple>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label>{{formatDate(ticket.landed)}}</q-item-label>
|
|
||||||
<q-item-label caption>#{{ticket.id}}</q-item-label>
|
|
||||||
<q-item-label caption>{{ticket.address.nickname}}</q-item-label>
|
|
||||||
<q-item-label caption>{{ticket.address.city}}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section side top>
|
|
||||||
<q-item-label>
|
|
||||||
485.50€
|
|
||||||
</q-item-label>
|
|
||||||
<q-badge
|
|
||||||
v-if="ticket.state"
|
|
||||||
color="teal"
|
|
||||||
:label="ticket.state.state.name"/>
|
|
||||||
<q-item-label v-if="ticket.packages" caption>
|
|
||||||
{{$t('packages', {n: ticket.packages})}}
|
|
||||||
</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-card>
|
|
||||||
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
||||||
<q-btn
|
<q-btn
|
||||||
fab
|
fab
|
||||||
icon="shopping_basket"
|
icon="add_shopping_cart"
|
||||||
color="accent"
|
color="accent"
|
||||||
:to="{name: 'catalog'}"
|
:to="{name: 'catalog'}"
|
||||||
:title="$t('startOrder')"
|
:title="$t('startOrder')"
|
||||||
|
@ -72,72 +19,12 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.my-list
|
|
||||||
max-width 30em
|
|
||||||
margin auto
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { date } from 'quasar'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Orders',
|
name: 'Orders',
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
yearFilter: null,
|
|
||||||
years: [],
|
|
||||||
orders: [],
|
|
||||||
tickets: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
mounted () {
|
||||||
let params = { filter: {
|
this.$router.replace('/orders/pending')
|
||||||
where: {
|
|
||||||
clientFk: this.$state.userId,
|
|
||||||
isConfirmed: false
|
|
||||||
},
|
|
||||||
include: 'address',
|
|
||||||
order: 'created DESC',
|
|
||||||
limit: 20
|
|
||||||
} }
|
|
||||||
this.$axios.get('Orders', { params })
|
|
||||||
.then(res => (this.orders = res.data))
|
|
||||||
|
|
||||||
let now = new Date()
|
|
||||||
let curYear = now.getFullYear()
|
|
||||||
|
|
||||||
for (let i = 0; i <= 5; i++) {
|
|
||||||
this.years.push(curYear - i)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.yearFilter = curYear
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
yearFilter (year) {
|
|
||||||
let start = new Date(year, 0)
|
|
||||||
let end = new Date(year + 1, 0)
|
|
||||||
|
|
||||||
let params = { filter: {
|
|
||||||
where: {
|
|
||||||
clientFk: this.userId,
|
|
||||||
landed: { between: [start, end] }
|
|
||||||
},
|
|
||||||
include: [
|
|
||||||
'address',
|
|
||||||
{ state: 'state' }
|
|
||||||
],
|
|
||||||
order: 'landed DESC'
|
|
||||||
} }
|
|
||||||
this.$axios.get('Tickets', { params })
|
|
||||||
.then(res => (this.tickets = res.data))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
formatDate (value) {
|
|
||||||
return date.formatDate(value, 'ddd, MMMM Do', this.$t('date'))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<div class="my-list q-pa-md">
|
||||||
|
<q-card>
|
||||||
|
<q-list bordered separator>
|
||||||
|
<q-item v-if="!orders.length">
|
||||||
|
{{$t('noOrdersFound')}}
|
||||||
|
</q-item>
|
||||||
|
<q-item
|
||||||
|
v-for="order in orders"
|
||||||
|
:key="order.id"
|
||||||
|
clickable
|
||||||
|
v-ripple>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{formatDate(order.landed)}}</q-item-label>
|
||||||
|
<q-item-label caption>#{{order.id}}</q-item-label>
|
||||||
|
<q-item-label caption>{{order.address.nickname}}</q-item-label>
|
||||||
|
<q-item-label caption>{{order.address.city}}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side top>
|
||||||
|
485.50€
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.my-list
|
||||||
|
max-width 30em
|
||||||
|
margin auto
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { date } from 'quasar'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Orders',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
orders: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
let params = { filter: {
|
||||||
|
where: {
|
||||||
|
clientFk: this.$state.userId,
|
||||||
|
isConfirmed: false
|
||||||
|
},
|
||||||
|
include: 'address',
|
||||||
|
order: 'created DESC',
|
||||||
|
limit: 20
|
||||||
|
} }
|
||||||
|
this.$axios.get('Orders', { params })
|
||||||
|
.then(res => (this.orders = res.data))
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatDate (value) {
|
||||||
|
return date.formatDate(value, 'ddd, MMMM Do', this.$t('date'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -23,14 +23,13 @@ export default function (/* { store, ssrContext } */) {
|
||||||
})
|
})
|
||||||
|
|
||||||
Router.afterEach((to, from) => {
|
Router.afterEach((to, from) => {
|
||||||
|
if (from.name === to.name) return
|
||||||
let app = Router.app
|
let app = Router.app
|
||||||
let $state = app.$state
|
Object.assign(app.$state, {
|
||||||
|
title: app.$t(to.name),
|
||||||
if (from.name !== to.name) {
|
titleColor: null,
|
||||||
$state.title = app.$t(to.name)
|
subtitle: null
|
||||||
$state.titleColor = null
|
})
|
||||||
$state.subtitle = null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return Router
|
return Router
|
||||||
|
|
|
@ -19,7 +19,16 @@ const routes = [
|
||||||
}, {
|
}, {
|
||||||
name: 'orders',
|
name: 'orders',
|
||||||
path: '/orders',
|
path: '/orders',
|
||||||
component: () => import('pages/Orders.vue')
|
component: () => import('pages/Orders.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'pending',
|
||||||
|
component: () => import('pages/Pending.vue')
|
||||||
|
}, {
|
||||||
|
path: 'confirmed',
|
||||||
|
component: () => import('pages/Confirmed.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
}, {
|
}, {
|
||||||
name: 'conditions',
|
name: 'conditions',
|
||||||
path: '/conditions',
|
path: '/conditions',
|
||||||
|
@ -32,6 +41,21 @@ const routes = [
|
||||||
name: 'register',
|
name: 'register',
|
||||||
path: '/register',
|
path: '/register',
|
||||||
component: () => import('pages/Register.vue')
|
component: () => import('pages/Register.vue')
|
||||||
|
}, {
|
||||||
|
name: 'config',
|
||||||
|
path: '/config',
|
||||||
|
component: () => import('pages/Config.vue'),
|
||||||
|
props: route => ({
|
||||||
|
changePassword: String(route.query.changePassword) === 'true'
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
name: 'addresses',
|
||||||
|
path: '/addresses',
|
||||||
|
component: () => import('pages/Addresses.vue')
|
||||||
|
}, {
|
||||||
|
name: 'addressEdit',
|
||||||
|
path: '/address/:address?',
|
||||||
|
component: () => import('pages/Address.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
|
|
Loading…
Reference in New Issue