1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-10 12:01:57 +08:00

REfactory from Panjian changes, update gRPC library and components (#526)

This commit is contained in:
Yamel Senih 2020-08-08 16:41:20 -04:00 committed by GitHub
parent 5bbe07532b
commit 40cc40a9ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
132 changed files with 3999 additions and 1545 deletions

View File

@ -3,12 +3,3 @@ ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
# It only does one thing by converting all import() to require().
# This configuration can significantly increase the speed of hot updates,
# when you have a large number of pages.
# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
VUE_CLI_BABEL_TRANSPILE_MODULES = true

View File

@ -19,8 +19,10 @@ Asking questions about use
#### Steps to reproduce
1. [xxx]
<!--
2. [xxx]
3. [xxxx]
-->
#### Screenshot or Gif
@ -33,6 +35,7 @@ Please only use Codepen, JSFiddle, CodeSandbox or a github repo
#### Other relevant information
- Your OS:
- Web Browser:
- Node.js version:
- vue-element-admin version:

View File

@ -74,7 +74,7 @@ Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace d
```
- Iniciar / Cerrar Sesión
- Permisos de Authentication
- Permisos de Autenticación
- Permisos basado en ADempiere
- Página de Permisos
- Directivas de permisos
@ -82,18 +82,21 @@ Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace d
- Autenticación por dos pasos
- Construcción Multi-entorno
- dev sit stage producción
- Desarrollo (dev)
- sit
- Escenario de pruebas (stage),
- Producción (prod)
- Características Globales
- I18n
- Temas dinámicos
- Dynamic sidebar (soporte a rutas multi-nivel)
- Menu lateral dinámico (soporte a rutas multi-nivel)
- Barra de rutas dinámica
- Tags-view (Tab page Support right-click operation)
- Tags-view (Pestañas de página, Soporta operación de clic derecho)
- Svg Sprite
- Datos de simulación con Mock
- Pantalla completa
- Responsive Sidebar
- Menu lateral responsivo
- Editor
- Editor de Texto Enriquecido
@ -104,7 +107,7 @@ Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace d
- Exportación a Excel
- Carga de Excel
- Visualización de Excel
- Exportación como zip
- Exportación como ZIP
- Tabla
- Tabla Dinámica
@ -139,7 +142,7 @@ Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace d
- Página de Guías
- ECharts (Gráficos)
- Portapapeles
- Convertidor de Markdown a html
- Convertidor de Markdown a HTML
```
## Iniciando
@ -210,7 +213,7 @@ Navegadores modernos e Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| últimas 2 versiones| últimas 2 versiones| últimas 2 versiones
| IE10, IE11, Edge | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones |
## Licencia

View File

@ -56,7 +56,7 @@ Understanding and learning this knowledge in advance will greatly help the use o
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p>
@ -83,7 +83,10 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Permission configuration page
- Multi-environment build
- dev sit stage prod
- Develop (dev)
- sit
- Stage Test (stage)
- Production (prod)
- Global Features
- I18n
@ -209,7 +212,7 @@ Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
| IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License

View File

@ -1,5 +1,14 @@
module.exports = {
presets: [
'@vue/app'
]
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
'@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
'plugins': ['dynamic-import-node']
}
}
}

View File

@ -1,4 +1,4 @@
import Mock from 'mockjs'
const Mock = require('mockjs')
const List = []
const count = 100
@ -27,7 +27,7 @@ for (let i = 0; i < count; i++) {
}))
}
export default [
module.exports = [
{
url: '/vue-element-admin/article/list',
type: 'get',

View File

@ -1,10 +1,10 @@
import Mock from 'mockjs'
import { param2Obj } from '../src/utils'
const Mock = require('mockjs')
const { param2Obj } = require('./utils')
import user from './user'
import role from './role'
import article from './article'
import search from './remote-search'
const user = require('./user')
const role = require('./role')
const article = require('./article')
const search = require('./remote-search')
const mocks = [
...user,
@ -16,7 +16,7 @@ const mocks = [
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
export function mockXHR() {
function mockXHR() {
// mock patch
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
@ -54,4 +54,7 @@ export function mockXHR() {
}
}
export default mocks
module.exports = {
mocks,
mockXHR
}

View File

@ -8,7 +8,7 @@ const mockDir = path.join(process.cwd(), 'mock')
function registerRoutes(app) {
let mockLastIndex
const { default: mocks } = require('./index.js')
const { mocks } = require('./index.js')
const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})
@ -44,9 +44,6 @@ const responseFake = (url, type, respond) => {
}
module.exports = app => {
// es6 polyfill
require('@babel/register')
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())

View File

@ -1,4 +1,4 @@
import Mock from 'mockjs'
const Mock = require('mockjs')
const NameList = []
const count = 100
@ -10,7 +10,7 @@ for (let i = 0; i < count; i++) {
}
NameList.push({ name: 'mock-Pan' })
export default [
module.exports = [
// username search
{
url: '/vue-element-admin/search/user',

View File

@ -1,6 +1,6 @@
import Mock from 'mockjs'
import { deepClone } from '../../src/utils/index.js'
import { asyncRoutes, constantRoutes } from './routes.js'
const Mock = require('mockjs')
const { deepClone } = require('../utils')
const { asyncRoutes, constantRoutes } = require('./routes.js')
const routes = deepClone([...constantRoutes, ...asyncRoutes])
@ -35,7 +35,7 @@ const roles = [
}
]
export default [
module.exports = [
// mock get all routes form server
{
url: '/vue-element-admin/routes',

View File

@ -1,6 +1,6 @@
// Just a mock data
export const constantRoutes = [
const constantRoutes = [
{
path: '/redirect',
component: 'layout/Layout',
@ -72,7 +72,7 @@ export const constantRoutes = [
}
]
export const asyncRoutes = [
const asyncRoutes = [
{
path: '/permission',
component: 'layout/Layout',
@ -523,3 +523,8 @@ export const asyncRoutes = [
{ path: '*', redirect: '/404', hidden: true }
]
module.exports = {
constantRoutes,
asyncRoutes
}

View File

@ -23,7 +23,7 @@ const users = {
}
}
export default [
module.exports = [
// user login
{
url: '/vue-element-admin/user/login',

48
mock/utils.js Normal file
View File

@ -0,0 +1,48 @@
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
module.exports = {
param2Obj,
deepClone
}

View File

@ -1,6 +1,6 @@
{
"name": "adempiere-vue",
"version": "4.2.1",
"version": "4.3.1",
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>",
"contributors": [
@ -9,29 +9,101 @@
"url": "https://github.com/EdwinBetanc0urt/"
}
],
"license": "GPL-3.0-or-later",
"scripts": {
"start": "vue-cli-service serve",
"dev": "vue-cli-service serve",
"lint": "eslint --ext .js,.vue src",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"new": "plop",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"new": "plop"
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
"dependencies": {
"@adempiere/grpc-access-client": "^1.2.3",
"@adempiere/grpc-core-client": "^1.2.3",
"@adempiere/grpc-data-client": "^2.4.9",
"@adempiere/grpc-dictionary-client": "^1.4.5",
"@adempiere/grpc-enrollment-client": "^1.1.2",
"@adempiere/grpc-pos-client": "^1.4.1",
"axios": "0.19.2",
"clipboard": "2.0.6",
"codemirror": "5.56.0",
"core-js": "3.6.5",
"driver.js": "0.9.8",
"dropzone": "5.7.2",
"echarts": "4.8.0",
"element-ui": "2.13.2",
"file-saver": "2.0.2",
"fuse.js": "3.4.4",
"js-cookie": "2.2.1",
"jsonlint": "1.6.3",
"jszip": "3.5.0",
"moment": "^2.27.0",
"normalize.css": "8.0.1",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"pinyin": "2.9.1",
"screenfull": "5.0.2",
"script-loader": "0.7.2",
"sortablejs": "1.10.2",
"tui-editor": "1.4.10",
"v-markdown": "^1.0.2",
"vue": "2.6.11",
"vue-content-loading": "^1.6.0",
"vue-count-to": "1.0.13",
"vue-i18n": "8.19.0",
"vue-multipane": "^0.9.5",
"vue-resize": "^0.5.0",
"vue-router": "3.3.4",
"vue-shortkey": "^3.1.7",
"vue-split-panel": "^1.0.4",
"vue-splitpane": "1.0.6",
"vuedraggable": "^2.24.0",
"vuex": "3.5.1",
"xlsx": "0.16.4"
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-plugin-unit-jest": "4.4.6",
"@vue/cli-service": "4.4.6",
"@vue/test-utils": "1.0.3",
"autoprefixer": "9.8.5",
"babel-eslint": "10.1.0",
"babel-jest": "26.1.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "4.1.0",
"chokidar": "3.4.1",
"connect": "3.7.0",
"eslint": "7.5.0",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "4.3.0",
"husky": "4.2.5",
"lint-staged": "10.2.11",
"mockjs": "1.1.0",
"plop": "2.7.3",
"runjs": "4.4.2",
"sass": "1.26.10",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.4",
"serve-static": "1.14.1",
"svg-sprite-loader": "5.0.0",
"svgo": "1.3.2",
"vue-template-compiler": "2.6.11"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"keywords": [
"vue",
@ -42,95 +114,20 @@
"admin-template",
"management-system"
],
"license": "GPL-3.0-or-later",
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
},
"bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
},
"dependencies": {
"@adempiere/grpc-access-client": "^1.2.2",
"@adempiere/grpc-core-client": "^1.1.8",
"@adempiere/grpc-data-client": "^2.4.6",
"@adempiere/grpc-dictionary-client": "^1.4.4",
"@adempiere/grpc-enrollment-client": "^1.1.1",
"@adempiere/grpc-pos-client": "^1.3.4",
"axios": "0.19.2",
"clipboard": "2.0.6",
"codemirror": "5.53.2",
"core-js": "^3.6.5",
"driver.js": "0.9.8",
"dropzone": "5.7.0",
"echarts": "4.7.0",
"element-ui": "2.13.2",
"file-saver": "2.0.2",
"fuse.js": "3.4.4",
"js-cookie": "2.2.1",
"jsonlint": "1.6.3",
"jszip": "3.4.0",
"mime-type": "^3.0.7",
"moment": "^2.24.0",
"normalize.css": "8.0.1",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"pinyin": "2.9.0",
"screenfull": "5.0.2",
"script-loader": "0.7.2",
"showdown": "1.9.1",
"sortablejs": "1.10.2",
"tui-editor": "1.4.10",
"v-markdown": "^1.0.2",
"vue": "2.6.11",
"vue-count-to": "1.0.13",
"vue-i18n": "8.17.4",
"vue-multipane": "^0.9.5",
"vue-resize": "^0.5.0",
"vue-router": "3.3.2",
"vue-shortkey": "^3.1.7",
"vue-split-panel": "^1.0.4",
"vue-splitpane": "1.0.6",
"vuedraggable": "^2.23.2",
"vuex": "3.4.0",
"xlsx": "0.15.6"
},
"devDependencies": {
"@babel/core": "7.9.0",
"@babel/register": "7.9.0",
"@vue/cli-plugin-babel": "4.3.1",
"@vue/cli-plugin-eslint": "4.3.1",
"@vue/cli-plugin-unit-jest": "^4.3.1",
"@vue/cli-service": "4.3.1",
"@vue/test-utils": "1.0.0-beta.33",
"autoprefixer": "^9.7.6",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^25.5.1",
"chalk": "4.0.0",
"chokidar": "3.4.0",
"connect": "3.7.0",
"eslint": "^6.8.0",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "4.2.1",
"husky": "^4.2.5",
"lint-staged": "10.2.0",
"mockjs": "1.1.0",
"node-sass": "^4.14.0",
"plop": "2.6.0",
"runjs": "^4.4.2",
"sass-loader": "^8.0.2",
"script-ext-html-webpack-plugin": "2.1.4",
"serve-static": "^1.14.1",
"svg-sprite-loader": "4.2.7",
"svgo": "1.3.2",
"vue-template-compiler": "2.6.11"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
}

View File

@ -1,9 +1,2 @@
exports.notEmpty = name => {
return v => {
if (!v || v.trim === '') {
return `${name} is required`
} else {
return true
}
}
}
exports.notEmpty = name => v =>
!v || v.trim() === '' ? `${name} is required` : true

View File

@ -0,0 +1,57 @@
const tableName = 'C_Location'
/**
* Create a location and return the created entity
* @param {array} attributes
*/
export function requestCreateLocationAddress({
attributes
}) {
const { createEntity } = require('@/api/ADempiere/persistence.js')
return createEntity({
tableName,
attributes,
formatReturn: 'object'
})
}
/**
* Get location entity by identifier
* @param {number} id as C_Location_ID
* @param {string} uuid
*/
export function requestGetLocationAddress({
id,
uuid
}) {
const { getEntity } = require('@/api/ADempiere/persistence.js')
return getEntity({
tableName,
recordId: id,
recordUuid: uuid
})
}
/**
* Update an existing location by id or uuid
* @param {number} id as C_Location_ID
* @param {string} uuid
* @param {array} attributes, all attributes (including empty values)
*/
export function requestUpdateLocationAddress({
id,
uuid,
attributes
}) {
const { updateEntity } = require('@/api/ADempiere/persistence.js')
return updateEntity({
tableName,
recordId: id,
recordUuid: uuid,
attributes,
formatReturn: 'object'
})
}

View File

@ -0,0 +1,261 @@
import { POSInstance as Instance } from '@/api/ADempiere/instances.js'
import Criteria from '@/utils/ADempiere/criteria.js'
/**
* method in price-checking.js as getProductPrice
*/
export { getProductPrice as findProduct } from '@/api/ADempiere/form/price-checking.js'
// List Point of sales
export function requestlistPointOfSales({
userUuid,
pageSize,
pageToken
}) {
return Instance.call(this).listPointOfSales({
userUuid,
pageSize,
pageToken
})
}
// Create order from POS
export function createOrder({
posUuid,
customerUuid,
documentTypeUuid
}) {
return Instance.call(this).createOrder({
posUuid,
customerUuid,
documentTypeUuid
})
}
// Update order from POS
export function updateOrder({
orderUuid,
posUuid,
customerUuid,
description
}) {
return Instance.call(this).updateOrder({
orderUuid,
posUuid,
customerUuid,
description
})
}
// Create order line from order uuid and product
export function createOrderLine({
orderUuid,
warehouseUuid,
productUuid,
chargeUuid,
description,
quantity,
price,
discountRate
}) {
return Instance.call(this).createOrderLine({
orderUuid,
warehouseUuid,
productUuid,
chargeUuid,
description,
quantity,
price,
discountRate
})
}
// Create order line from order uuid and product
export function getOrder(orderUuid) {
return Instance.call(this).getOrder({ orderUuid })
}
// List orders from pos uuid
export function requestListOrders({
posUuid,
documentNo,
businessPartnerUuid,
grandTotal,
openAmount,
isPaid,
isProcessed,
isAisleSeller,
isInvoiced,
dateOrderedFrom,
dateOrderedTo,
salesRepresentativeUuid,
pageSize,
pageToken
}) {
const criteria = new Criteria({ tableName: 'C_Order' })
/*
criteria.addCondition({
columnName: 'DocumentNo',
value: documentNo
}).addCondition({
columnName: 'C_BPartner_ID_UUID',
value: businessPartnerUuid
}).addCondition({
columnName: 'GrandTotal',
value: grandTotal
}).addCondition({
columnName: 'OpenAmt',
value: openAmount
}).addCondition({
columnName: 'IsPaid',
value: isPaid
}).addCondition({
columnName: 'Processed',
value: isProcessed
}).addCondition({
columnName: 'IsAisleSeller',
value: isAisleSeller
}).addCondition({
columnName: 'IsInvoiced',
value: isInvoiced
}).addCondition({
columnName: 'DateOrderedFrom',
value: dateOrderedFrom
}).addCondition({
columnName: 'DateOrderedTo',
value: dateOrderedTo
}).addCondition({
columnName: 'SalesRep_ID_UUID',
value: salesRepresentativeId
})
*/
return Instance.call(this).listOrders({
posUuid,
documentNo,
businessPartnerUuid,
grandTotal,
openAmount,
isPaid,
isProcessed,
isAisleSeller,
isInvoiced,
dateOrderedFrom,
dateOrderedTo,
salesRepresentativeUuid,
criteria: criteria.getCriteria(),
pageSize,
pageToken
})
}
// updateOrderLine orders from pos uuid
export function updateOrderLine({
orderLineUuid,
description,
quantity,
price,
discountRate
}) {
return Instance.call(this).updateOrderLine({
orderLineUuid,
description,
quantity,
price,
discountRate
})
}
// delete Order Line
export function deleteOrderLine({
orderLineUuid
}) {
return Instance.call(this).deleteOrderLine({
orderLineUuid
})
}
export function listOrderLines({
orderUuid
}) {
return Instance.call(this).listOrderLines({
orderUuid
})
}
export function getKeyLayout({ keyLayoutUuid }) {
return Instance.call(this).getKeyLayout({
keyLayoutUuid
})
}
// ListProductPrice
export function requestListProductPrice({
searchValue,
priceListUuid,
businessPartnerUuid,
warehouseUuid,
validFrom,
// Query
criteria,
pageSize,
pageToken
}) {
return Instance.call(this).requestListProductPrice({
searchValue,
priceListUuid,
businessPartnerUuid,
warehouseUuid,
validFrom,
// Query
criteria,
pageSize,
pageToken
})
}
export function requestPrintOrder({
orderUuid
}) {
console.info(`Print order ${orderUuid}`)
}
export function requestGenerateImmediateInvoice({
posId,
posUuid
}) {
console.info(`Generate imediate invoice with POS id ${posId}, and uuid ${posUuid}`)
}
export function requestCompletePreparedOrder({
orderUuid
}) {
console.info(`Complete prepared order ${orderUuid}`)
}
export function requestReverseSalesTransaction({
orderUuid
}) {
console.info(`Reverse sales transaction ${orderUuid}`)
}
export function requestCreateWithdrawal({
posId,
posUuid
}) {
console.info(`Withdrall cash with POS id ${posId}, and uuid ${posUuid}`)
}
export function requestCreateNewCustomerReturnOrder({
orderUuid
}) {
console.info(`New Customer Return Order ${orderUuid}`)
}
export function requestCashClosing({
posId,
posUuid
}) {
console.info(`Cash closing with POS id ${posId}, and uuid ${posUuid}`)
}

View File

@ -6,10 +6,15 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js'
* @param {string} tableName
* @param {array} attributesList
*/
export function createEntity({ tableName, attributes }) {
export function createEntity({
tableName,
attributes,
formatReturn = 'array'
}) {
return Instance.call(this).requestCreateEntity({
tableName,
attributesList: attributes
attributesList: attributes,
formatToConvert: formatReturn
})
}
@ -20,12 +25,19 @@ export function createEntity({ tableName, attributes }) {
* @param {string} recordUuid
* @param {array} attributesList
*/
export function updateEntity({ tableName, recordId, recordUuid, attributes }) {
export function updateEntity({
tableName,
recordId,
recordUuid,
attributes,
formatReturn = 'array'
}) {
return Instance.call(this).requestUpdateEntity({
tableName,
recordId,
recordUuid,
attributesList: attributes
attributesList: attributes,
formatToConvert: formatReturn
})
}
@ -104,7 +116,7 @@ export function getEntitiesList({
* @param {string} tableName
* @param {string} language
* @param {string} recordUuid
* @param {integer} recordId
* @param {number} recordId
*/
export function requestTranslations({ tableName, language, recordUuid, recordId, pageToken, pageSize }) {
return Instance.call(this).requestListTranslations({
@ -116,3 +128,20 @@ export function requestTranslations({ tableName, language, recordUuid, recordId,
pageSize
})
}
// Download a resource from file name
export function getResource({ resourceUuid }, callBack = {
onData: () => {},
onStatus: () => {},
onEnd: () => {}
}) {
const stream = Instance.call(this).getResource({
resourceUuid
})
stream.on('data', (response) => callBack.onData(response))
stream.on('status', (status) => callBack.onStatus(status))
stream.on('end', (end) => callBack.onEnd(end))
return stream
}

View File

@ -43,11 +43,15 @@ export function getWarehousesList({
})
}
// Get Country definition from server using id or uuid for record
export function getCountryDefinition({ countryUuid, countryId }) {
/**
* Get Country definition from server using id or uuid for record
* @param {string} uuid
* @param {number} id
*/
export function getCountryDefinition({ uuid, id }) {
return SystemCoreInstance.call(this).requestGetCountry({
countryUuid,
countryId
uuid,
id
})
}
@ -55,3 +59,91 @@ export function getCountryDefinition({ countryUuid, countryId }) {
export function listLanguages({ pageToken, pageSize }) {
return Instance.call(this).requestListLanguages({ pageToken, pageSize })
}
export function requestCreateBusinessPartner({
value,
taxId,
duns,
naics,
name,
lastName,
description,
contactName,
eMail,
phone,
businessPartnerGroupUuid,
// Location
address1,
address2,
address3,
address4,
cityUuid,
cityName,
postalCode,
regionUuid,
regionName,
countryUuid,
posUuid
}) {
return SystemCoreInstance.call(this).requestCreateBusinessPartner({
value,
taxId,
duns,
naics,
name,
lastName,
description,
contactName,
eMail,
phone,
businessPartnerGroupUuid,
// Location
address1,
address2,
address3,
address4,
cityUuid,
cityName,
postalCode,
regionUuid,
regionName,
countryUuid,
posUuid
})
}
export function requestGetBusinessPartner({
searchValue
}) {
return SystemCoreInstance.call(this).requestGetBusinessPartner({
searchValue
})
}
export function requestListBusinessPartner({
searchValue,
value,
name,
contactName,
eMail,
postalCode,
phone,
// Query
criteria,
pageSize,
pageToken
}) {
return SystemCoreInstance.call(this).requestListBusinessPartner({
searchValue,
value,
name,
contactName,
eMail,
postalCode,
phone,
// Query
criteria,
pageSize,
pageToken
})
}

View File

@ -13,12 +13,11 @@ export function login({
userPass,
role
})
} else {
return Instance.call(this).requestLoginDefault({
userName,
userPass
})
}
return Instance.call(this).requestLoginDefault({
userName,
userPass
})
}
// Get User Info from session Uuid or token
@ -39,11 +38,6 @@ export function logout(sessionUuid) {
return Instance.call(this).requestLogOut(sessionUuid)
}
// Get User menu from server
export function getMenu(sessionUuid) {
return Instance.call(this).requestUserMenuFromSession(sessionUuid)
}
/**
*
* @param {string} attributes.sessionUuid
@ -51,6 +45,10 @@ export function getMenu(sessionUuid) {
* @param {string} attributes.organizationUuid
* @param {string} attributes.warehouseUuid
*/
// Get User menu from server
export function getMenu(sessionUuid) {
return Instance.call(this).requestUserMenuFromSession(sessionUuid)
}
export function changeRole(attributes) {
return Instance.call(this).requestChangeRole(attributes)
}

View File

@ -44,6 +44,7 @@
</el-popover>
</el-badge>
</template>
<script>
export default {
name: 'Badge',
@ -82,10 +83,14 @@ export default {
instanceUuid: getRecordNotification.instanceUuid,
fileName: getRecordNotification.download
}
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
} else {
this.$router.push({
name: 'ProcessActivity'
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
}
}

View File

@ -36,9 +36,11 @@
</el-card>
</div>
</template>
<script>
import { MixinInfo } from '@/components/ADempiere/ContainerInfo/mixinInfo'
import MixinInfo from './mixinInfo.js'
import chatTextLong from '@/components/ADempiere/Field/chatTextLong'
export default {
name: 'ChatEntries',
components: {

View File

@ -1,4 +1,5 @@
export const MixinInfo = {
export default {
name: 'MixinContainerInfo',
data() {
return {
currentKey: 100,
@ -50,7 +51,7 @@ export const MixinInfo = {
},
methods: {
sendComment() {
var chatTextLong = this.$store.getters.getChatTextLong
const chatTextLong = this.$store.getters.getChatTextLong
if (!this.isEmptyValue(chatTextLong)) {
this.$store.dispatch('createChatEntry', {
tableName: this.$route.params.tableName,

View File

@ -33,8 +33,10 @@
</el-card>
</div>
</template>
<script>
import { MixinInfo } from '@/components/ADempiere/ContainerInfo/mixinInfo'
import MixinInfo from './mixinInfo.js'
export default {
name: 'RecordLogs',
mixins: [MixinInfo],

View File

@ -64,8 +64,10 @@
</el-card>
</div>
</template>
<script>
import { MixinInfo } from '@/components/ADempiere/ContainerInfo/mixinInfo'
import MixinInfo from './mixinInfo.js'
export default {
name: 'WorkflowLogs',
mixins: [MixinInfo]

View File

@ -0,0 +1,26 @@
<script>
import VueContentLoading from 'vue-content-loading'
export default {
name: 'ContentLoader',
components: {
VueContentLoading
},
props: {
width: {
type: Number,
default: 300
},
height: {
type: Number,
default: 300
}
}
}
</script>
<template>
<vue-content-loading :width="width" :height="height">
<rect cx="50" cy="20" :width="width" :height="height" />
</vue-content-loading>
</template>

View File

@ -2,7 +2,7 @@
<div class="container-submenu container-context-menu">
<el-menu
ref="contextMenu"
v-shortkey="{ f2: ['f2'], f3: ['f3'], f5: ['f5'], f3:['ctrl', 'd'] }"
v-shortkey="shorcutKey"
:default-active="activeMenu"
:router="false"
class="el-menu-demo"
@ -23,7 +23,7 @@
{{ $t('components.contextMenuRelations') }}
</el-menu-item>
<el-submenu v-if="actions !== undefined && actions.length" class="el-menu-item" index="actions" @click.native="runAction(actions[0])">
<el-submenu v-if="!isEmptyValue(actions)" class="el-menu-item" index="actions" @click.native="runAction(actions[0])">
<template slot="title">
{{ $t('components.contextMenuActions') }}
</template>
@ -112,7 +112,7 @@
</template>
<script>
import { contextMixin } from '@/components/ADempiere/ContextMenu/contextMenuMixin'
import contextMixin from './contextMenuMixin.js'
export default {
name: 'ContextMenuDesktop',

View File

@ -1,10 +1,11 @@
import { showNotification, showMessage } from '@/utils/ADempiere/notification'
import { showNotification } from '@/utils/ADempiere/notification.js'
import Item from './items'
import { convertFieldListToShareLink, recursiveTreeSearch } from '@/utils/ADempiere/valueUtils'
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil'
import { convertFieldListToShareLink, recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil.js'
import ROUTES from '@/utils/ADempiere/zoomWindow'
export const contextMixin = {
export default {
name: 'MixinContextMenu',
components: {
Item
},
@ -192,6 +193,14 @@ export const contextMixin = {
},
isManageDataRecords() {
return ['browser', 'window'].includes(this.panelType)
},
shorcutKey() {
return {
defaultValues: ['f2'],
deleteRecord: ['f3'],
deleteRecord2: ['ctrl', 'd'],
refreshData: ['f5']
}
}
},
watch: {
@ -229,11 +238,10 @@ export const contextMixin = {
this.getReferences()
},
methods: {
showMessage,
showNotification,
actionContextMenu(event) {
switch (event.srcKey) {
case 'f2':
case 'defaultValues':
this.$store.dispatch('setDefaultValues', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
@ -242,14 +250,15 @@ export const contextMixin = {
isNewRecord: true
})
break
case 'f3':
case 'deleteRecord':
case 'deleteRecord2':
this.$store.dispatch('deleteEntity', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
recordUuid: this.recordUuid
})
break
case 'f5':
case 'refreshData':
this.refreshData()
break
}
@ -271,7 +280,7 @@ export const contextMixin = {
fieldsList: this.getterFieldList
})
if (fieldsEmpty.length) {
this.showMessage({
this.$message({
message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty,
type: 'info'
})
@ -328,7 +337,11 @@ export const contextMixin = {
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
return jsonData.map(row => {
return filterVal.map(column => {
return row[column]
})
})
},
generateContextMenu() {
this.metadataMenu = this.getterContextMenu
@ -392,7 +405,7 @@ export const contextMixin = {
},
showModal(action) {
// TODO: Refactor and remove redundant dispatchs
if (action.type === 'process') {
if (['process'].includes(action.type)) {
// Add context from view open in process to opening
if (action.parentUuidAssociated || action.containerUuidAssociated) {
const attributes = this.$store.getters.getValuesView({
@ -431,6 +444,8 @@ export const contextMixin = {
query: {
...this.getOldRouteOfWindow.query
}
}).catch(error => {
console.info(`Context Menu Mixin: ${error.name}, ${error.message}`)
})
} else {
this.$store.dispatch(action.action, {
@ -575,9 +590,11 @@ export const contextMixin = {
// windowUuid: this.parentUuid,
tabParent: 0
}
}).catch(error => {
console.info(`Context Menu Mixin: ${error.name}, ${error.message}`)
})
} else {
this.showMessage({
this.$message({
type: 'error',
message: this.$t('notifications.noRoleAccess')
})
@ -639,6 +656,7 @@ export const contextMixin = {
this.$message({
message: message,
type: 'success',
showClose: true,
duration: 1500
})
},
@ -649,45 +667,33 @@ export const contextMixin = {
action: this.getReportDefinition.output.printFormatUuid,
tabParent: ROUTES.PRINT_FORMAT_SETUP_WINDOW.tabParent
}
}).catch(error => {
console.info(`Context Menu Mixin: ${error.name}, ${error.message}`)
})
},
validatePrivateAccess({ isLocked, tableName, recordId }) {
if (this.isPersonalLock) {
let isHiddenLock = false
if (isLocked) {
this.actions = this.actions.map(actionItem => {
if (actionItem.action === 'unlockRecord') {
return {
...actionItem,
hidden: false,
tableName,
recordId
}
} else if (actionItem.action === 'lockRecord') {
return {
...actionItem,
hidden: true
}
}
return actionItem
})
} else {
this.actions = this.actions.map(actionItem => {
if (actionItem.action === 'lockRecord') {
return {
...actionItem,
hidden: false,
tableName,
recordId
}
} else if (actionItem.action === 'unlockRecord') {
return {
...actionItem,
hidden: true
}
}
return actionItem
})
isHiddenLock = true
}
this.actions = this.actions.map(actionItem => {
if (actionItem.action === 'lockRecord') {
return {
...actionItem,
hidden: isHiddenLock,
tableName,
recordId
}
} else if (actionItem.action === 'unlockRecord') {
return {
...actionItem,
hidden: !isHiddenLock
}
}
return actionItem
})
}
}
}

View File

@ -4,7 +4,7 @@
<right-menu>
<el-menu
ref="contextMenu"
v-shortkey="{ f2: ['f2'], f3: ['f3'], f5: ['f5'], f3:['ctrl', 'd'] }"
v-shortkey="shorcutKey"
:default-active="activeMenu"
:router="false"
class="el-menu-demo"
@ -119,7 +119,7 @@
</template>
<script>
import { contextMixin } from '@/components/ADempiere/ContextMenu/contextMenuMixin'
import contextMixin from './contextMenuMixin.js'
import RightMenu from '@/components/RightPanel/menu'
export default {
@ -130,13 +130,13 @@ export default {
mixins: [contextMixin],
computed: {
isPanelTypeMobile() {
if (this.$route.meta.type === 'process' || this.$route.meta.type === 'report') {
if (['process', 'report'].includes(this.$route.meta.type)) {
return true
}
return false
},
iconDefault() {
if (this.$route.meta.type === 'process') {
if (this.isPanelTypeMobile) {
return 'component'
}
return 'skill'
@ -144,6 +144,7 @@ export default {
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;

View File

@ -13,7 +13,9 @@
size="mini"
:metadata="scope"
:placeholder="$t('table.dataTable.search')"
/>
>
<svg-icon slot="prefix" icon-class="search" />
</el-input>
</template>
<template slot-scope="{row}">
<span>{{ row.name }}</span>
@ -26,36 +28,22 @@
<script>
import { getPendingDocumentsFromServer } from '@/api/ADempiere/dashboard/dashboard'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import mixinDashboard from '@/components/ADempiere/Dashboard/mixinDashboard.js'
export default {
name: 'PendingDocuments',
props: {
metadata: {
type: Object,
required: true
}
},
mixins: [mixinDashboard],
data() {
return {
documents: [],
unsubscribe: () => {},
search: ''
documents: []
}
},
computed: {
cachedViews() {
return this.$store.getters.cachedViews
},
dataResult() {
if (this.search.length) {
return this.filterResult(this.search)
}
return this.documents
},
permissionRoutes() {
return this.$store.getters.permission_routes
}
},
mounted() {
@ -67,7 +55,6 @@ export default {
this.unsubscribe()
},
methods: {
showMessage,
getPendingDocuments() {
const userUuid = this.$store.getters['user/getUserUuid']
const roleUuid = this.$store.getters.getRoleUuid
@ -97,37 +84,39 @@ export default {
})
},
handleClick(row) {
const viewSearch = recursiveTreeSearch({
const viewSearch = this.recursiveTreeSearch({
treeData: this.permissionRoutes,
attributeValue: row.windowUuid,
attributeName: 'meta',
secondAttribute: 'uuid',
attributeChilds: 'children'
})
if (viewSearch) {
let tabParent
if (row.action === 'window') {
tabParent = 0
}
this.$router.push({
name: viewSearch.name,
params: {
...row.criteria
},
query: {
action: 'criteria'
action: 'criteria',
tabParent
}
}).catch(error => {
console.info(`Dashboard/docstatus Component: ${error.name}, ${error.message}`)
})
} else {
this.showMessage({
this.$message({
type: 'error',
message: this.$t('notifications.noRoleAccess')
})
}
// conditions for the registration amount (operador: row.criteria.whereClause)
},
filterResult(search) {
return this.documents.filter(item => this.ignoreAccent(item.name).toLowerCase().includes(this.ignoreAccent(search.toLowerCase())))
},
ignoreAccent(s) {
if (!s) { return '' }
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
}
}
}

View File

@ -0,0 +1,75 @@
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
export default {
name: 'MixinDashboard',
props: {
metadata: {
type: Object,
required: true
}
},
data() {
return {
search: '',
unsubscribe: () => {}
}
},
computed: {
permissionRoutes() {
return this.$store.getters.permission_routes
}
},
methods: {
recursiveTreeSearch,
handleClick(row) {
const viewSearch = this.recursiveTreeSearch({
treeData: this.permissionRoutes,
attributeValue: row.windowUuid,
attributeName: 'meta',
secondAttribute: 'uuid',
attributeChilds: 'children'
})
if (viewSearch) {
let recordUuid
if (!this.isEmptyValue(row.uuidRecord)) {
recordUuid = row.uuidRecord
}
let tabParent
if (row.action === 'window') {
tabParent = 0
}
this.$router.push({
name: viewSearch.name,
query: {
action: recordUuid,
tabParent
}
}).catch(error => {
console.info(`Dashboard ${this.name}: ${error.name}, ${error.message}`)
})
} else {
this.$message({
type: 'error',
message: this.$t('notifications.noRoleAccess')
})
}
// conditions for the registration amount (operador: row.criteria.whereClause)
},
filterResult(search) {
const searchFilter = this.ignoreAccent(search.toLowerCase())
return this.documents.filter(item => {
return this.ignoreAccent(item.name)
.toLowerCase()
.includes(searchFilter)
})
},
ignoreAccent(s) {
if (!s) {
return ''
}
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
}
}
}

View File

@ -14,7 +14,9 @@
size="mini"
:metadata="scope"
:placeholder="$t('table.dataTable.search')"
/>
>
<svg-icon slot="prefix" icon-class="search" />
</el-input>
</template>
<template slot-scope="{row}">
<span>{{ row.displayName }}</span>
@ -35,45 +37,27 @@
<script>
import { getRecentItems as getRecentItemsFromServer } from '@/api/ADempiere/dashboard/dashboard'
import { convertAction } from '@/utils/ADempiere/dictionaryUtils'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import mixinDashboard from '@/components/ADempiere/Dashboard/mixinDashboard.js'
export default {
name: 'RecentItems',
props: {
metadata: {
type: Object,
required: true
}
},
mixins: [mixinDashboard],
data() {
return {
recentItems: [],
unsubscribe: () => {},
isLoaded: true,
search: '',
accentRegexp: /[\u0300-\u036f]/g
isLoaded: true
}
},
computed: {
getterRecentItems() {
return this.$store.getters.getRecentItems
},
cachedViews() {
return this.$store.getters.cachedViews
},
dataResult() {
if (this.search.length) {
return this.filterResult(this.search)
}
return this.recentItems
},
permissionRoutes() {
return this.$store.getters.permission_routes
}
},
mounted() {
this.getRecentItems({ pageToken: undefined, pageSize: undefined })
this.getRecentItems({})
this.unsubscribe = this.subscribeChanges()
},
@ -81,10 +65,6 @@ export default {
this.unsubscribe()
},
methods: {
showMessage,
checkOpened(uuid) {
return this.cachedViews.includes(uuid)
},
getRecentItems({ pageToken, pageSize }) {
return new Promise(resolve => {
getRecentItemsFromServer({ pageToken, pageSize })
@ -111,39 +91,6 @@ export default {
})
})
},
handleClick(row) {
const viewSearch = recursiveTreeSearch({
treeData: this.permissionRoutes,
attributeValue: row.referenceUuid,
attributeName: 'meta',
secondAttribute: 'uuid',
attributeChilds: 'children'
})
if (viewSearch) {
let recordUuid
if (!this.isEmptyValue(row.uuidRecord)) {
recordUuid = row.uuidRecord
}
let tabParent
if (row.action === 'window') {
tabParent = 0
}
this.$router.push({
name: viewSearch.name,
query: {
action: recordUuid,
tabParent
}
})
} else {
this.showMessage({
type: 'error',
message: this.$t('notifications.noRoleAccess')
})
}
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'notifyDashboardRefresh') {
@ -151,13 +98,6 @@ export default {
}
})
},
filterResult(search) {
return this.recentItems.filter(item => this.ignoreAccent(item.displayName).toLowerCase().includes(this.ignoreAccent(search.toLowerCase())))
},
ignoreAccent(s) {
if (!s) { return '' }
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
},
translateDate(value) {
return this.$d(new Date(value), 'long', this.language)
}

View File

@ -14,7 +14,9 @@
size="mini"
:metadata="scope"
:placeholder="$t('table.dataTable.search')"
/>
>
<svg-icon slot="prefix" icon-class="search" />
</el-input>
</template>
<template slot-scope="{row}">
<span>{{ row.name }}</span>
@ -24,10 +26,24 @@
<br>
<el-button-group class="actions-buttons">
<el-tooltip :content="$t('quickAccess.newRecord')" placement="top">
<el-button v-if="row.action === 'window'" size="mini" circle @click.stop="windowAction(row, 'create-new')"><i class="el-icon-circle-plus-outline" /></el-button>
<el-button
v-if="row.action === 'window'"
size="mini"
circle
@click.stop="windowAction(row, 'create-new')"
>
<i class="el-icon-circle-plus-outline" />
</el-button>
</el-tooltip>
<el-tooltip :content="$t('quickAccess.listRecords')" placement="top">
<el-button v-if="row.action === 'window'" size="mini" circle @click.stop="windowAction(row, 'listRecords')"><i class="el-icon-search" /></el-button>
<el-button
v-if="row.action === 'window'"
size="mini"
circle
@click.stop="windowAction(row, 'listRecords')"
>
<i class="el-icon-search" />
</el-button>
</el-tooltip>
</el-button-group>
</template>
@ -38,40 +54,25 @@
</template>
<script>
import { getFavoritesFromServer } from '@/api/ADempiere/dashboard/dashboard'
import { convertAction } from '@/utils/ADempiere/dictionaryUtils'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import { getFavoritesFromServer } from '@/api/ADempiere/dashboard/dashboard.js'
import { convertAction } from '@/utils/ADempiere/dictionaryUtils.js'
import mixinDashboard from '@/components/ADempiere/Dashboard/mixinDashboard.js'
export default {
name: 'Favorites',
props: {
metadata: {
type: Object,
required: true
}
},
mixins: [mixinDashboard],
data() {
return {
favorites: [],
unsubscribe: () => {},
isLoaded: true,
search: '',
accentRegexp: /[\u0300-\u036f]/g
isLoaded: true
}
},
computed: {
cachedViews() {
return this.$store.getters.cachedViews
},
dataResult() {
if (this.search.length) {
return this.filterResult(this.search)
}
return this.favorites
},
permissionRoutes() {
return this.$store.getters.permission_routes
}
},
mounted() {
@ -83,7 +84,6 @@ export default {
this.unsubscribe()
},
methods: {
showMessage,
getFavoritesList() {
const userUuid = this.$store.getters['user/getUserUuid']
return new Promise(resolve => {
@ -115,51 +115,8 @@ export default {
}
})
},
handleClick(row) {
const viewSearch = recursiveTreeSearch({
treeData: this.permissionRoutes,
attributeValue: row.referenceUuid,
attributeName: 'meta',
secondAttribute: 'uuid',
attributeChilds: 'children'
})
if (viewSearch) {
let recordUuid
if (!this.isEmptyValue(row.uuidRecord)) {
recordUuid = row.uuidRecord
}
let tabParent
if (row.action === 'window') {
tabParent = 0
}
this.$router.push({
name: viewSearch.name,
query: {
action: recordUuid,
tabParent
}
})
} else {
this.showMessage({
type: 'error',
message: this.$t('notifications.noRoleAccess')
})
}
},
filterResult(search) {
return this.favorites.filter(item => this.ignoreAccent(item.name).toLowerCase().includes(this.ignoreAccent(search.toLowerCase())))
},
ignoreAccent(s) {
if (!s) { return '' }
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
},
translateDate(value) {
return this.$d(new Date(value), 'long', this.language)
},
windowAction(row, param) {
const viewSearch = recursiveTreeSearch({
const viewSearch = this.recursiveTreeSearch({
treeData: this.permissionRoutes,
attributeValue: row.referenceUuid,
attributeName: 'meta',
@ -174,9 +131,11 @@ export default {
action: param,
tabParent: 0
}
}).catch(error => {
console.info(`Dashboard/userfavorites Component: ${error.name}, ${error.message}`)
})
} else {
this.showMessage({
this.$message({
type: 'error',
message: this.$t('notifications.noRoleAccess')
})

View File

@ -249,6 +249,7 @@ import TableContextMenu from '@/components/ADempiere/DataTable/menu/tableContext
import TableMainMenu from '@/components/ADempiere/DataTable/menu'
import IconElement from '@/components/ADempiere/IconElement'
import { formatField } from '@/utils/ADempiere/valueFormat'
import { typeValue } from '@/utils/ADempiere/valueUtils.js'
import MainPanel from '@/components/ADempiere/Panel'
import { sortFields } from '@/utils/ADempiere/dictionaryUtils'
import { FIELDS_DECIMALS, FIELDS_QUANTITY, FIELDS_READ_ONLY_FORM } from '@/utils/ADempiere/references'
@ -620,7 +621,7 @@ export default {
return row[field.columnName] ? this.$t('components.switchActiveText') : this.$t('components.switchInactiveText')
} else if (field.componentPath === 'FieldDate' || field.componentPath === 'FieldTime') {
let cell = row[field.columnName]
if (Object.prototype.toString.call(cell) === '[object Date]') {
if (typeValue(cell) === 'DATE') {
cell = cell.getTime()
}
// replace number timestamp value for date
@ -1234,7 +1235,7 @@ export default {
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
@ -1259,7 +1260,7 @@ export default {
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;

View File

@ -27,7 +27,7 @@
v-for="(process, key) in processMenu"
:key="key"
:disabled="process.type === 'application' ? false : Boolean(getDataSelection.length < 1)"
index="process"
:index="'process' + key"
@click="process.type === 'application' ? sortTab(process) : showModalTable(process)"
>
{{ process.name }}
@ -83,7 +83,7 @@
</template>
<script>
import { menuTableMixin } from '@/components/ADempiere/DataTable/menu/menuTableMixin'
import menuTableMixin from './menuTableMixin.js'
export default {
name: 'TableMainMenu',
@ -97,32 +97,32 @@ export default {
</script>
<style>
.el-menu--vertical .nest-menu .el-submenu>.el-submenu__title:hover, .el-menu--vertical .el-menu-item:hover {
background-color: #74bcff94 !important;
background: #74bcff94 !important;
}
.el-menu--collapse {
width: auto;
}
.el-menu-item:hover {
background-color: #ffffff !important
}
.hover {
background-color: initial !important;
}
.el-menu-item {
height: 56px;
line-height: 56px;
font-size: 14px;
color: #303133;
padding: 0 20px;
list-style: none;
cursor: pointer;
position: relative;
-webkit-transition: border-color .3s, background-color .3s, color .3s;
transition: border-color .3s, background-color .3s, color .3s;
-webkit-box-sizing: border-box;
box-sizing: border-box;
white-space: nowrap;
}
.el-menu--vertical .nest-menu .el-submenu>.el-submenu__title:hover, .el-menu--vertical .el-menu-item:hover {
background-color: #74bcff94 !important;
background: #74bcff94 !important;
}
.el-menu--collapse {
width: auto;
}
.el-menu-item:hover {
background-color: #ffffff !important
}
.hover {
background-color: initial !important;
}
.el-menu-item {
height: 56px;
line-height: 56px;
font-size: 14px;
color: #303133;
padding: 0 20px;
list-style: none;
cursor: pointer;
position: relative;
-webkit-transition: border-color .3s, background-color .3s, color .3s;
transition: border-color .3s, background-color .3s, color .3s;
-webkit-box-sizing: border-box;
box-sizing: border-box;
white-space: nowrap;
}
</style>

View File

@ -1,9 +1,9 @@
import { supportedTypes, exportFileFromJson, exportFileZip } from '@/utils/ADempiere/exportUtil'
import { showNotification } from '@/utils/ADempiere/notification'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils'
import { supportedTypes, exportFileFromJson, exportFileZip } from '@/utils/ADempiere/exportUtil.js'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
import { FIELDS_QUANTITY } from '@/utils/ADempiere/references'
export const menuTableMixin = {
export default {
name: 'MixinMenuTable',
props: {
parentUuid: {
type: String,
@ -155,7 +155,6 @@ export const menuTableMixin = {
}
},
methods: {
showNotification,
sortTab(actionSequence) {
// TODO: Refactor and remove redundant dispatchs
this.$store.dispatch('setShowDialog', {
@ -260,6 +259,7 @@ export const menuTableMixin = {
})
this.$message({
message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty,
showClose: true,
type: 'info'
})
},
@ -305,18 +305,22 @@ export const menuTableMixin = {
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(rowData => filterVal.map(j => rowData[j]))
return jsonData.map(row => {
return filterVal.map(column => {
return row[column]
})
})
},
zoomRecord() {
const browserMetadata = this.$store.getters.getBrowser(this.$route.meta.uuid)
const { elementName } = browserMetadata.fieldList.find(field => field.columnName === browserMetadata.keyColumn)
const records = []
this.getDataSelection.forEach(record => {
if (isNaN(record[browserMetadata.keyColumn])) {
records.push(record[browserMetadata.keyColumn])
} else {
records.push(Number(record[browserMetadata.keyColumn]))
this.getDataSelection.forEach(recordItem => {
let record = recordItem[browserMetadata.keyColumn]
if (!isNaN(record)) {
record = Number(record)
}
records.push(record)
})
const viewSearch = recursiveTreeSearch({
@ -333,6 +337,8 @@ export const menuTableMixin = {
action: 'advancedQuery',
[elementName]: records
}
}).catch(error => {
console.info(`Table Menu Mixin: ${error.name}, ${error.message}`)
})
}
}

View File

@ -39,7 +39,7 @@
</template>
<script>
import { menuTableMixin } from '@/components/ADempiere/DataTable/menu/menuTableMixin'
import menuTableMixin from './menuTableMixin.js'
export default {
name: 'TableContextMenu',

View File

@ -96,9 +96,6 @@ export default {
},
getterDataRecordsAndSelection() {
return this.$store.getters.getDataRecordAndSelection(this.containerUuid)
},
getDataSelection() {
return this.getterDataRecordsAndSelection.selection
}
},
watch: {
@ -140,9 +137,11 @@ export default {
this.$router.push({
name: this.$route.name,
query: {
action: this.windowRecordSelected.UUID,
...this.$route.query
...this.$route.query,
action: this.windowRecordSelected.UUID
}
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
this.closeDialog()
} else if (action !== undefined) {

View File

@ -77,24 +77,24 @@ export default {
},
methods: {
redirect(item) {
let tabParent
if (item.meta && item.meta.type === 'window') {
this.$router.push({
name: item.name,
params: {
childs: item.children
},
query: {
tabParent: 0
}
})
} else {
this.$router.push({
name: item.name,
params: {
childs: item.children
}
})
tabParent = 0
}
this.$router.push({
name: item.name,
query: {
...this.$router.query,
tabParent
},
params: {
...this.$router.params,
childs: item.children
}
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
}
}
}

View File

@ -0,0 +1,257 @@
<template>
<el-autocomplete
v-model="displayedValue"
:placeholder="placeholder"
:fetch-suggestions="localSearch"
clearable
value-key="name"
style="width: 100%;"
popper-class="custom-field-bpartner-info"
@focus="isFocus = true"
@blur="isFocus = false"
>
<template slot="suffix">
<i
class="el-icon-arrow-down el-input__icon"
/>
</template>
</el-autocomplete>
</template>
<script>
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { convertBooleanToString } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'FieldAutocomplete',
mixins: [fieldMixin],
data() {
// label with '' value is assumed to be undefined non-existent
const label = ' '
const blankOption = {
label,
id: undefined,
uuid: undefined
}
return {
controlDisplayed: this.displayedValue,
isFocus: false,
isLoading: false,
optionsList: [blankOption],
blankValues: [null, undefined, -1],
blankOption,
timeOut: null
}
},
computed: {
isPanelWindow() {
return this.metadata.panelType === 'window'
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSelectMultiple() {
return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery
},
cssClassStyle() {
let styleClass = this.metadata.cssClassName + ' custom-field-select'
if (this.isSelectMultiple) {
styleClass += ' custom-field-select-multiple'
}
return styleClass
},
placeholder() {
if (this.isFocus) {
return this.displayedValue
}
return this.$t('quickAccess.searchWithEnter')
},
getterLookupList() {
if (this.isEmptyValue(this.metadata.reference.query) ||
!this.metadata.displayed) {
return [this.blankOption]
}
return this.$store.getters.getLookupList({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
query: this.metadata.reference.query,
tableName: this.metadata.reference.tableName
})
},
getterLookupAll() {
const allOptions = this.$store.getters.getLookupAll({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
query: this.metadata.reference.query,
directQuery: this.metadata.reference.directQuery,
tableName: this.metadata.reference.tableName,
value: this.value
})
// sets the value to blank when the lookupList or lookupItem have no
// values, or if only lookupItem does have a value
if (this.isEmptyValue(allOptions) || (allOptions.length &&
(!this.blankValues.includes(allOptions[0].id)))) {
allOptions.unshift(this.blankOption)
}
return allOptions
},
value: {
get() {
const value = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
if (this.isEmptyValue(value)) {
/* eslint-disable */
this.displayedValue = undefined
/* eslint-disable */
return value
}
let label = this.findLabel(value)
if (!label) {
label = this.displayedValue
/* eslint-disable */
this.optionsList.push({
// TODO: Add uuid
id: value,
label
})
/* eslint-disable */
}
return value
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
value
})
}
},
displayedValue: {
get() {
return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName,
value
})
}
}
},
created() {
this.changeBlankOption()
},
methods: {
parseValue(value) {
if (typeof value === 'boolean') {
// value ? 'Y' : 'N'
value = convertBooleanToString(value)
}
return value
},
changeBlankOption() {
if (Number(this.metadata.defaultValue) === -1) {
this.blankOption.id = -1
}
},
setNewDisplayedValue() {
this.isFocus = true
const displayValue = this.displayedValue
if (this.controlDisplayed !== displayValue) {
this.controlDisplayed = displayValue
}
},
localSearch(stringToMatch, callBack) {
if (this.isEmptyValue(stringToMatch)) {
// not show list
callBack([])
return
}
const recordsList = this.getterLookupList
let results = recordsList
if (stringToMatch || true) {
const parsedValue = stringToMatch.toLowerCase().trim()
results = recordsList.filter(rowBPartner => {
// columns: id, uuid, label
for (const columnBPartner in rowBPartner) {
const valueToCompare = String(rowBPartner[columnBPartner]).toLowerCase()
if (valueToCompare.includes(parsedValue)) {
return true
}
}
return false
})
// Remote search
if (this.isEmptyValue(results)) {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(() => {
this.remoteSearch(stringToMatch)
.then(remoteResponse => {
callBack(remoteResponse)
})
}, 2000)
return
}
}
// call callback function to return suggestions
callBack(results)
},
remoteSearch(searchValue) {
return new Promise(resolve => {
const message = {
message: 'Sin resultados coincidentes con la busqueda',
type: 'info',
showClose: true
}
this.$store.dispatch('getLookupListFromServer', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
tableName: this.metadata.reference.tableName,
query: this.metadata.reference.query,
isAddBlankValue: true,
blankValue: this.blankOption.id,
valuesList: searchValue
})
.then(() => {
const recordsList = this.getterLookupAll
if (this.isEmptyValue(recordsList)) {
this.$message(message)
}
resolve(recordsList)
})
.catch(error => {
console.warn(error.message)
this.$message(message)
resolve([])
})
.finally(() => {
this.isLoading = false
})
})
}
}
}
</script>

View File

@ -28,7 +28,11 @@ export default {
mixins: [fieldMixin],
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' image-uploader'
let styleClass = ' image-uploader '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
}
},
methods: {

View File

@ -112,7 +112,11 @@ export default {
return picker
},
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-date'
let styleClass = ' custom-field-date '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
},
/**
* Parse the date format to be compatible with element-ui
@ -150,6 +154,7 @@ export default {
value: {
get() {
let value = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
@ -158,6 +163,7 @@ export default {
}
const valueTo = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnNameTo
})

View File

@ -21,7 +21,11 @@ export default {
mixins: [fieldMixin],
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-image'
let styleClass = ' custom-field-image '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
}
},
methods: {

View File

@ -0,0 +1,94 @@
const fieldBase = {
tableName: 'C_Location',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
index: 0
}
}
export default [
{
...fieldBase,
columnName: 'C_Location_ID',
overwriteDefinition: {
size: 24,
isDisplayed: false,
index: 1
}
},
{
...fieldBase,
columnName: 'C_Country_ID',
overwriteDefinition: {
isActiveLogics: true, // enable logics
defaultValue: '@#C_Country_ID@',
size: 24,
sequenceFields: 'CO',
index: 2
}
},
{
...fieldBase,
columnName: 'C_Region_ID',
overwriteDefinition: {
size: 24,
sequenceFields: 'R',
index: 3
}
},
{
...fieldBase,
columnName: 'C_City_ID',
overwriteDefinition: {
size: 24,
sequenceFields: 'C',
index: 4
}
},
{
...fieldBase,
columnName: 'Address1',
overwriteDefinition: {
size: 24,
sequenceFields: 'A1',
index: 5
}
},
{
...fieldBase,
columnName: 'Address2',
overwriteDefinition: {
size: 24,
sequenceFields: 'A2',
index: 6
}
},
{
...fieldBase,
columnName: 'Address3',
overwriteDefinition: {
size: 24,
sequenceFields: 'A3',
index: 7
}
},
{
...fieldBase,
columnName: 'Address4',
overwriteDefinition: {
size: 24,
sequenceFields: 'A4',
index: 8
}
},
{
...fieldBase,
columnName: 'Postal',
overwriteDefinition: {
size: 24,
sequenceFields: 'P',
index: 9
}
}
]

View File

@ -0,0 +1,111 @@
<template>
<div>
<el-popover
ref="locationAddress"
v-model="isShowedLocationForm"
:placement="popoverPlacement"
width="300"
trigger="manual"
>
<location-address-form
v-if="isShowedLocationForm"
:values="localValues"
:parent-metadata="metadata"
/>
</el-popover>
<el-input
v-model="displayedValue"
readonly
@focus="setShowedLocationForm(true)"
>
<i slot="prefix" class="el-icon-location-information el-input__icon" />
</el-input>
</div>
</template>
<script>
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import mixinLocation from './mixinLocation.js'
import LocationAddressForm from './locationAddressForm'
export default {
name: 'FieldLocation',
components: {
LocationAddressForm
},
mixins: [
fieldMixin,
mixinLocation
],
data() {
return {
localValues: {}
}
},
computed: {
displayedValue: {
get() {
/**
* TODO: Add DisplayColumn (to locator's and location's fields) in entities
* list response, to set value or empty value in fieldValue state when
* change records with dataTable.
*/
if (this.isEmptyValue(this.value)) {
return undefined
}
return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName,
value
})
}
},
popoverPlacement() {
return this.metadata.popoverPlacement || 'top'
}
},
mounted() {
if (!this.metadata.isAdvancedQuery) {
this.getLocation()
}
},
methods: {
getLocation() {
if (!this.isEmptyValue(this.displayedValue)) {
return
}
const value = this.value
if (this.isEmptyValue(value)) {
return
}
this.requestGetLocationAddress({
id: value
})
.then(responseLocation => {
const { values } = responseLocation
this.localValues = values
// TODO: Get Display_ColumnName from server request
this.displayedValue = this.getDisplayedValue(values) || value
})
.catch(error => {
console.warn(`Get Location Address, Field Location - Error ${error.code}: ${error.message}.`)
})
}
}
}
</script>

View File

@ -0,0 +1,359 @@
<template>
<div class="wrapper">
<el-form
v-shortkey="{ closeForm: ['esc'] }"
label-position="top"
size="small"
class="location-address"
@shortkey.native="keyAction"
>
<el-row :gutter="24">
<template v-if="isLoaded">
<field
v-for="(field) in fieldsListLocation"
:key="field.columnName"
:metadata-field="field"
/>
</template>
<div
v-else
key="form-loading"
v-loading="!isLoaded"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
style="min-height: calc(50vh - 84px)"
class="loading-panel"
/>
<el-col :span="24">
<samp style="float: right; padding-right: 10px;">
<el-button
:disabled="!isLoaded"
type="primary"
class="custom-button-address-location"
icon="el-icon-check"
@click="sendValuesToServer"
/>
<el-button
type="danger"
class="custom-button-address-location"
icon="el-icon-close"
@click="setShowedLocationForm(false)"
/>
</samp>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import mixinLocation from './mixinLocation.js'
import fieldsList from './fieldsList.js'
import {
requestCreateLocationAddress,
requestUpdateLocationAddress
} from '@/api/ADempiere/field/location.js'
import { showNotification } from '@/utils/ADempiere/notification.js'
import { getSequenceAsList } from '@/utils/ADempiere/location'
/**
* TODO: Add sequence fields by country selected
*/
export default {
name: 'LocationAdressFrom',
mixins: [
formMixin,
mixinLocation
],
props: {
metadata: {
type: Object,
default: () => {
return {
// TODO: Add container uuid parent
uuid: 'Location-Address-Create',
containerUuid: 'Location-Address-Create'
}
}
},
parentMetadata: {
type: Object,
default: () => {}
},
// TODO: Not working props
values: {
type: Object,
default: () => {}
}
},
data() {
return {
fieldsList,
isCustomForm: true,
request: 0
}
},
computed: {
fieldsListLocation() {
if (!this.isEmptyValue(this.$store.getters.getFieldLocation)) {
return this.$store.getters.getFieldLocation
}
return this.fieldsList
},
locationId() {
return this.$store.getters.getValueOfField({
parentUuid: this.parentMetadata.parentUuid,
containerUuid: this.parentMetadata.containerUuid,
columnName: this.parentMetadata.columnName
})
}
},
created() {
this.unsubscribe = this.subscribeChanges()
},
mounted() {
this.getLocation()
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
keyAction(event) {
if (event.srcKey === 'closeForm') {
this.toggleShowedLocationForm()
}
},
sortSequence(itemA, itemB) {
return itemA.index - itemB.index
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
const withOutColumnNames = ['C_Country_ID', 'DisplayColumn_C_Country_ID', 'C_Location_ID']
if (mutation.type === 'updateValueOfField' &&
mutation.payload.containerUuid === this.metadata.containerUuid) {
if (mutation.payload.columnName === 'C_Country_ID') {
const values = []
// Get country definition to sequence fields and displayed value
if (mutation.value !== this.currentCountryDefinition.id) {
this.getCountryDefinition({
id: mutation.payload.value
})
.then(responseCountry => {
const newSequence = getSequenceAsList(responseCountry.captureSequence)
const newFieldsList = this.fieldsList.map(item => {
if (newSequence.includes(item.sequenceFields)) {
return {
...item,
isDisplayed: true,
index: newSequence.indexOf(item.sequenceFields)
}
}
return {
...item,
isDisplayed: false
}
})
this.$store.dispatch('changeSequence', newFieldsList.sort(this.sortSequence))
})
.catch(error => {
this.$message({
message: error.message,
isShowClose: true,
type: 'error'
})
console.warn(`Error getting Country Definition: ${error.message}. Code: ${error.code}.`)
})
}
fieldsList.forEach(item => {
if (!withOutColumnNames.includes(item.columnName)) {
values.push({
columnName: item.columnName,
value: undefined
})
}
})
this.setValues({
values,
withOutColumnNames
})
}
}
})
},
setParentValues(values) {
const {
parentUuid,
containerUuid,
columnName, // 'C_Location_ID' by default
displayColumnName
} = this.parentMetadata
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
columnName,
value: values[columnName]
})
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
// DisplayColumn_'ColumnName'
columnName: displayColumnName,
value: this.getDisplayedValue(values)
})
// active update record to server
this.$store.dispatch('notifyFieldChange', {
containerUuid,
field: this.parentMetadata
})
},
sendValuesToServer() {
const fieldsNotReady = this.$store.getters.getFieldListEmptyMandatory({
containerUuid: this.containerUuid
})
if (!this.isEmptyValue(fieldsNotReady)) {
showNotification({
type: 'warning',
title: this.$t('notifications.emptyValues'),
name: '<b>' + fieldsNotReady + '.</b> ',
message: this.$t('notifications.fieldMandatory'),
isRedirect: false
})
return
}
const locationId = this.locationId
const attributes = this.$store.getters.getValuesView({
containerUuid: this.containerUuid
})
const attributesToServer = attributes.filter(attributeItem => {
const { columnName } = attributeItem
if (columnName.includes('DisplayColumn_')) {
return false
}
if (columnName === 'C_Location_ID') {
return false
}
return true
})
const updateLocation = (responseLocation) => {
const { values } = responseLocation
// set form values
this.setValues({
values
})
// set field parent values
this.setParentValues(values)
this.setShowedLocationForm(false)
// set context values to parent continer
if (this.parentMetadata.isSendParentValues) {
this.$store.dispatch('updateValuesOfContainer', {
parentUuid: this.parentMetadata.parentUuid,
containerUuid: this.parentMetadata.containerUuid,
attributes
})
}
}
if (this.isEmptyValue(locationId) || locationId === 0) {
requestCreateLocationAddress({
attributes: attributesToServer
})
.then(updateLocation)
.catch(error => {
this.$message({
message: error.message,
isShowClose: true,
type: 'error'
})
console.warn(`Error create Location Address: ${error.message}. Code: ${error.code}.`)
})
// break to only create
return
}
requestUpdateLocationAddress({
id: locationId,
attributes: attributesToServer
})
.then(updateLocation)
.catch(error => {
this.$message({
message: error.message,
isShowClose: true,
type: 'error'
})
console.warn(`Error update Location Address: ${error.message}. Code: ${error.code}.`)
})
this.$store.dispatch('changeSequence', fieldsList)
},
getLocation() {
if (this.request > 0) {
return
}
if (!this.isEmptyValue(this.values)) {
this.setValues({
values: this.values
})
return
}
const id = this.locationId
if (this.isEmptyValue(id)) {
return
}
this.requestGetLocationAddress({
id
})
.then(responseLocation => {
const { values } = responseLocation
this.setValues({
values
})
this.request++
})
.catch(error => {
console.warn(`Get Location Address, Form Location - Error ${error.code}: ${error.message}.`)
})
}
}
}
</script>
<style scoped lang="scss">
.location-address {
.el-form-item {
margin-bottom: 0px !important;
}
.custom-button-address-location {
float: right;
margin-right: 10px;
}
}
</style>
<style lang="scss">
.location-address {
.el-form-item--small .el-form-item__label {
line-height: 22px !important;
}
.el-form-item--small.el-form-item {
margin-bottom: 5px !important;
}
}
</style>

View File

@ -0,0 +1,53 @@
import { getCountryDefinition } from '@/api/ADempiere/system-core.js'
import { requestGetLocationAddress } from '@/api/ADempiere/field/location.js'
export default {
name: 'MixinLocationField',
computed: {
currentCountryDefinition() {
return this.$store.getters['user/getCountry']
},
isShowedLocationForm: {
get() {
return this.$store.getters.getIsShowedLocation
},
set() {
// empty
}
}
},
methods: {
requestGetLocationAddress,
getCountryDefinition,
toggleShowedLocationForm() {
this.$store.commit('setShowedLocation', !this.isShowedLocationForm)
},
setShowedLocationForm(isShow) {
this.$store.commit('setShowedLocation', isShow)
},
/**
* TODO: Add support with sequence to displayed
* @param {object} entityValues
*/
getDisplayedValue(entityValues) {
let value = ''
if (!this.isEmptyValue(entityValues)) {
if (!this.isEmptyValue(entityValues.Address1)) {
value = entityValues.Address1
}
if (!this.isEmptyValue(entityValues.City)) {
value += ', ' + entityValues.City
}
if (!this.isEmptyValue(entityValues.RegionName)) {
value += ', ' + entityValues.RegionName
}
if (!this.isEmptyValue(entityValues.Postal)) {
value += ', ' + entityValues.Postal
}
}
return value
}
}
}

View File

@ -8,6 +8,7 @@
>
<el-input-number
v-if="isFocus"
key="number-input-focus"
:ref="metadata.columnName"
v-model="value"
type="number"
@ -19,6 +20,7 @@
:controls="isShowControls"
:controls-position="controlsPosition"
:class="cssClassStyle"
autofocus
@change="preHandleChange"
@blur="customFocusLost"
@focus="focusGained"
@ -27,16 +29,15 @@
/>
<el-input
v-else
key="number-displayed-blur"
:ref="metadata.columnName"
v-model="displayedValue"
:placeholder="metadata.help"
:disabled="isDisabled"
:class="cssClassStyle"
readonly
@blur="customFocusLost"
style="text-align-last: end !important"
@focus="customFocusGained"
@keydown.native="keyPressed"
@keyup.native="keyReleased"
/>
</el-tooltip>
</template>
@ -60,7 +61,11 @@ export default {
},
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-number'
let styleClass = ' custom-field-number '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
},
maxValue() {
if (this.isEmptyValue(this.metadata.valueMax)) {
@ -144,17 +149,6 @@ export default {
return this.$store.getters['user/getCurrency']
}
},
watch: {
isFocus(value) {
if (value) {
// focus into input number
this.$nextTick()
.then(() => {
this.$refs[this.metadata.columnName].$el.children[2].firstElementChild.focus()
})
}
}
},
methods: {
parseValue(value) {
if (this.isEmptyValue(value)) {
@ -165,6 +159,10 @@ export default {
customFocusGained(event) {
this.isFocus = true
// this.focusGained(event)
this.$nextTick(() => {
this.$refs[this.metadata.columnName].focus()
})
},
customFocusLost(event) {
this.isFocus = false
@ -230,12 +228,4 @@ export default {
.el-input-number, .el-input {
width: 100% !important; /* ADempiere Custom */
}
/** Align text in right input **/
.custom-field-number {
text-align: right !important;
input, .el-input__inner {
text-align: right !important;
}
}
</style>

View File

@ -5,7 +5,7 @@
:filterable="!isMobile"
:placeholder="metadata.help"
:loading="isLoading"
value-key="key"
value-key="id"
:class="cssClassStyle"
clearable
:multiple="isSelectMultiple"
@ -19,7 +19,7 @@
<el-option
v-for="(option, key) in optionsList"
:key="key"
:value="option.key"
:value="option.id"
:label="option.label"
/>
</el-select>
@ -27,7 +27,7 @@
<script>
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { convertBooleanToString } from '@/utils/ADempiere/valueUtils.js'
import { convertBooleanToString } from '@/utils/ADempiere/valueFormat.js'
/**
* This component is a lookup type field, use as a replacement for fields:
@ -45,18 +45,17 @@ export default {
data() {
// label with '' value is assumed to be undefined non-existent
const label = ' '
const blankOption = {
label,
id: undefined,
uuid: undefined
}
return {
isLoading: false,
optionsList: [{
label,
key: undefined
}],
optionsList: [blankOption],
blankValues: [null, undefined, -1],
blankOption: {
label,
key: undefined
}
blankOption
}
},
computed: {
@ -70,9 +69,12 @@ export default {
return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery
},
cssClassStyle() {
let styleClass = this.metadata.cssClassName + ' custom-field-select'
let styleClass = ' custom-field-select '
if (this.isSelectMultiple) {
styleClass += ' custom-field-select-multiple'
styleClass += ' custom-field-select-multiple '
}
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
},
@ -101,7 +103,7 @@ export default {
// sets the value to blank when the lookupList or lookupItem have no
// values, or if only lookupItem does have a value
if (this.isEmptyValue(allOptions) || (allOptions.length &&
(!this.blankValues.includes(allOptions[0].key)))) {
(!this.blankValues.includes(allOptions[0].id)))) {
allOptions.unshift(this.blankOption)
}
return allOptions
@ -113,19 +115,33 @@ export default {
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
let label = this.findLabel(value)
if (!label) {
label = this.displayColumn
if (this.isEmptyValue(value)) {
/* eslint-disable */
this.displayedValue = undefined
this.uuidValue = undefined
/* eslint-disable */
return value
}
const option = this.findOption(value)
if (!option.label) {
const label = this.displayedValue
/* eslint-disable */
this.optionsList.push({
key: value,
// TODO: Add uuid
id: value,
label
})
/* eslint-disable */
}
return value
},
set(value) {
const option = this.findOption(value)
// always update uuid
this.uuidValue = option.uuid
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
@ -134,7 +150,26 @@ export default {
})
}
},
displayColumn: {
uuidValue: {
get() {
return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// 'ColumnName'_UUID
columnName: this.metadata.columnName + '_UUID',
})
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// 'ColumnName'_UUID
columnName: this.metadata.columnName + '_UUID',
value
})
}
},
displayedValue: {
get() {
return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
@ -156,61 +191,25 @@ export default {
},
watch: {
isSelectMultiple(isMultiple) {
let value = this.value
if (isMultiple) {
const valueInArray = []
if (!this.isEmptyValue(this.value)) {
valueInArray.push(this.value)
if (!this.isEmptyValue(value)) {
valueInArray.push(value)
}
this.value = valueInArray
value = valueInArray
} else {
if (Array.isArray(this.value)) {
if (this.value.length) {
if (Array.isArray(value)) {
if (value.length) {
// set first value
this.value = this.value[0]
value = value[0]
} else {
this.value = this.blankOption.key
value = this.blankOption.id
}
}
}
this.value = value
},
/*
'metadata.value'(value) {
if (!this.metadata.inTable) {
value = this.parseValue(value)
if (this.metadata.displayed) {
if (!this.optionsList.some(option => option.key === value) &&
!this.isEmptyValue(this.metadata.displayColumn)) {
this.optionsList.push({
key: value,
label: this.metadata.displayColumn
})
}
}
if (!this.findLabel(value) &&
this.metadata.displayed &&
this.isEmptyValue(this.metadata.displayColumn)) {
value = undefined
}
this.value = value
}
},
'metadata.displayColumn'(value) {
if (this.metadata.displayed) {
if (!this.isEmptyValue(this.value)) {
if (!this.isEmptyValue(value)) {
// verify if exists to add
if (!this.findLabel(this.value)) {
this.optionsList.push({
key: this.value,
label: value
})
}
}
}
}
}
*/
'metadata.displayed'(value) {
if (value) {
// if is field showed, search into store all options to list
@ -226,14 +225,17 @@ export default {
this.optionsList = this.getterLookupAll
const value = this.value
if (!this.isEmptyValue(value) && !this.metadata.isAdvancedQuery) {
const label = this.findLabel(value)
if (label) {
this.displayColumn = label
const option = this.findOption(value)
if (option.label) {
this.displayedValue = option.label
this.uuidValue = option.uuid
} else {
// TODO: Property displayColumn is @deprecated
if (!this.isEmptyValue(this.metadata.displayColumn)) {
// verify if exists to add
// verify if exists to add
this.optionsList.push({
key: value,
id: value,
// TODO: Add uuid
label: this.metadata.displayColumn
})
} else {
@ -257,19 +259,34 @@ export default {
},
changeBlankOption() {
if (Number(this.metadata.defaultValue) === -1) {
this.blankOption.key = -1
this.blankOption.id = -1
}
},
preHandleChange(value) {
const label = this.findLabel(this.value)
this.displayColumn = label
this.displayedValue = label
this.handleFieldChange({
value,
label
})
},
findOption(value) {
const option = this.optionsList.find(item => item.id === value)
if (option && option.label) {
return option
}
return {
label: undefined,
value: undefined,
uuid: undefined
}
},
/**
* TODO: Verify used
* @deprecated use findOption
*/
findLabel(value) {
const selected = this.optionsList.find(item => item.key === value)
const selected = this.optionsList.find(item => item.id === value)
if (selected) {
return selected.label
}
@ -289,7 +306,8 @@ export default {
value: this.value
})
.then(responseLookupItem => {
this.displayColumn = responseLookupItem.label
this.displayedValue = responseLookupItem.label
this.uuidValue = responseLookupItem.uuid
this.optionsList = this.getterLookupAll
})
.finally(() => {
@ -301,7 +319,7 @@ export default {
*/
getDataLookupList(isShowList) {
if (isShowList) {
// TODO: Evaluate if length = 1 and this element key = blankOption
// TODO: Evaluate if length = 1 and this element id = blankOption
const list = this.getterLookupList
if (this.isEmptyValue(list) || (list.length === 1 && this.blankValues.includes(list[0]))) {
this.remoteMethod()
@ -315,8 +333,9 @@ export default {
containerUuid: this.metadata.containerUuid,
tableName: this.metadata.reference.tableName,
query: this.metadata.reference.query,
// valuesList: this.value
isAddBlankValue: true,
blankValue: this.blankOption.key
blankValue: this.blankOption.id
})
.then(responseLookupList => {
if (!this.isEmptyValue(responseLookupList)) {
@ -345,7 +364,7 @@ export default {
})
// set empty value
this.value = this.blankOption.key
this.value = this.blankOption.id
}
}
}

View File

@ -12,12 +12,14 @@
:maxlength="maxLength"
:show-password="Boolean(metadata.isEncrypted)"
:autofocus="metadata.inTable"
:size="inputSize"
@change="preHandleChange"
@blur="focusLost"
@focus="focusGained"
@keydown.native="keyPressed"
@keyup.native="keyReleased"
@keyup.native.enter="actionKeyPerformed"
@submit="false"
/>
</template>
@ -49,6 +51,13 @@ export default {
}
},
computed: {
cssClassStyle() {
let styleClass = ' custom-field-text '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
},
// Only used when input type='TextArea'
rows() {
if (this.metadata.inTable) {
@ -68,6 +77,12 @@ export default {
}
return typeInput
},
inputSize() {
if (this.isEmptyValue(this.metadata.inputSize)) {
return 'medium'
}
return this.metadata.inputSize
},
maxLength() {
if (!this.isEmptyValue(this.metadata.fieldLength) && this.metadata.fieldLength > 0) {
return Number(this.metadata.fieldLength)
@ -77,3 +92,9 @@ export default {
}
}
</script>
<style scoped>
.custom-field-text {
max-height: 34px;
}
</style>

View File

@ -40,9 +40,12 @@ export default {
},
computed: {
cssClassStyle() {
let styleClass = this.metadata.cssClassName
let styleClass = ' custom-field-text-long '
if (this.isDisabled) {
styleClass += ' custom-field-text-long-disable'
styleClass += ' custom-field-text-long-disable '
}
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
},

View File

@ -46,7 +46,11 @@ export default {
return -Infinity
},
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-time'
let styleClass = ' custom-field-time '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
}
},
methods: {

View File

@ -35,7 +35,11 @@ export default {
},
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-yes-no'
let styleClass = ' custom-field-yes-no '
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass += this.metadata.cssClassName
}
return styleClass
}
},
methods: {

View File

@ -118,7 +118,7 @@ export default {
})
},
preHandleChange(value) {
if (this.clean) {
if (this.isEmptyValue(value)) {
this.$store.dispatch('setchatText', value)
.then(responseComment => {
this.$store.dispatch('setMarkDown', false)

View File

@ -38,17 +38,20 @@
v-if="isDocuemntStatus"
:field="fieldAttributes"
/>
<translated
v-if="field.isTranslatedField"
:field-attributes="fieldAttributes"
:record-uuid="field.recordUuid"
/>
<calculator
v-if="field.isNumericField && !field.isReadOnlyFromLogic"
:field-attributes="fieldAttributes"
:field-value="field.value"
/>
</template>
<component
:is="componentRender"
:ref="field.columnName"
@ -130,6 +133,9 @@ export default {
let field
switch (this.field.componentPath) {
case 'FieldAutocomplete':
field = () => import('@/components/ADempiere/Field/FieldAutocomplete')
break
case 'FieldBinary':
field = () => import('@/components/ADempiere/Field/FieldBinary')
break
@ -145,6 +151,9 @@ export default {
case 'FieldImage':
field = () => import('@/components/ADempiere/Field/FieldImage')
break
case 'FieldLocation':
field = () => import('@/components/ADempiere/Field/FieldLocation')
break
case 'FieldLocator':
field = () => import('@/components/ADempiere/Field/FieldLocator')
break
@ -187,7 +196,8 @@ export default {
if (this.isAdvancedQuery) {
return this.field.isShowedFromUser
}
return fieldIsDisplayed(this.field) && (this.isMandatory || this.field.isShowedFromUser || this.inTable)
return fieldIsDisplayed(this.field) &&
(this.isMandatory || this.field.isShowedFromUser || this.inTable)
},
isMandatory() {
if (this.isAdvancedQuery) {
@ -235,7 +245,7 @@ export default {
return this.field.isReadOnlyFromLogic
}
// other type of panels (process/report)
return isUpdateableAllFields
return Boolean(isUpdateableAllFields)
},
isFieldOnly() {
if (this.inTable || this.field.isFieldOnly) {
@ -338,11 +348,11 @@ export default {
return false
},
isContextInfo() {
if (!this.isAdvancedQuery) {
if (this.field.panelType !== 'window') {
return false
}
return (this.field.contextInfo && this.field.contextInfo.isActive) ||
(this.field.reference && this.field.reference.windowsList.length)
return Boolean(this.field.contextInfo && this.field.contextInfo.isActive) ||
Boolean(this.field.reference && this.field.reference.windowsList.length)
}
},
watch: {

View File

@ -28,11 +28,16 @@ export default {
return Boolean(this.metadata.readonly || this.metadata.disabled)
},
cssClassStyle() {
return this.metadata.cssClassName
let styleClass = ''
if (!this.isEmptyValue(this.metadata.cssClassName)) {
styleClass = this.metadata.cssClassName
}
return styleClass
},
value: {
get() {
return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
@ -63,18 +68,6 @@ export default {
this.requestFocus()
}
},
watch: {
// valueModel(value) {
// if (this.metadata.inTable) {
// this.value = this.parseValue(value)
// }
// },
// 'metadata.value'(value) {
// if (!this.metadata.inTable) {
// this.value = this.parseValue(value)
// }
// }
},
methods: {
/**
* Parse the value to a new value if required for element-ui component
@ -177,6 +170,11 @@ export default {
// if is custom field, set custom handle change value
if (this.metadata.isCustomField) {
if (this.metadata.isActiveLogics) {
this.$store.dispatch('changeDependentFieldsList', {
field: this.metadata
})
}
return
}
this.$store.dispatch('notifyFieldChange', {

View File

@ -3,10 +3,12 @@ export default {
value: {
get() {
const value = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
const valueTo = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})

View File

@ -34,8 +34,7 @@
</template>
<script>
import { showMessage } from '@/utils/ADempiere/notification'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
export default {
name: 'FieldContextInfo',
@ -65,7 +64,6 @@ export default {
}
},
methods: {
showMessage,
redirect({ window }) {
const viewSearch = recursiveTreeSearch({
treeData: this.permissionRoutes,
@ -83,10 +81,13 @@ export default {
tabParent: 0,
[this.fieldAttributes.columnName]: this.value
}
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
} else {
this.showMessage({
this.$message({
type: 'error',
showClose: true,
message: this.$t('notifications.noRoleAccess')
})
}

View File

@ -1,74 +1,14 @@
import { TEXT } from '@/utils/ADempiere/references'
export default [
// Product Code
{
elementColumnName: 'ProductValue',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
size: 12,
sequence: 10,
cssClassName: 'price-inquiry',
inputSize: 'large',
handleActionKeyPerformed: true
}
},
// Product Name
{
elementColumnName: 'ProductName',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 20,
isReadOnly: true,
cssClassName: 'price-inquiry'
}
},
// Product Description
{
elementColumnName: 'ProductDescription',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 30,
displayType: TEXT.id,
isReadOnly: true,
cssClassName: 'price-inquiry'
}
},
// Price List
{
elementColumnName: 'PriceList',
isFromDictionary: true,
overwriteDefinition: {
size: 16,
sequence: 40,
isReadOnly: true,
cssClassName: 'price-inquiry',
help: '0.00'
}
},
// Tax Amount
{
elementColumnName: 'TaxAmt',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
sequence: 50,
isReadOnly: true,
cssClassName: 'price-inquiry',
help: '0.00'
}
},
// Total
{
elementColumnName: 'GrandTotal',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 60,
isReadOnly: true,
cssClassName: 'price-inquiry',
help: '0.00'
}
}
]

View File

@ -1,43 +1,99 @@
<template>
<div class="wrapper">
<el-form
v-if="isLoaded"
key="form-loaded"
label-position="top"
label-width="200px"
>
<el-row>
<field
v-for="(field) in fieldsList"
:key="field.columnName"
:metadata-field="field"
:v-model="field.value"
/>
</el-row>
</el-form>
<div
v-else
key="form-loading"
v-loading="!isLoaded"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel"
/>
<div
v-if="isLoaded"
style="height: 100% !important;"
@click="focusProductValue"
>
<el-container style="height: 100% !important;">
<img
fit="contain"
:src="valuesImage.length > 1 ? valuesImage.value : getDefaultImage()"
class="background-price-checking"
>
<el-main>
<div class="inquiry-form">
<el-form
key="form-loaded"
label-position="top"
label-width="10px"
@submit.native.prevent="notSubmitForm"
>
<field
v-for="(field) in fieldsList"
ref="ProductValue"
:key="field.columnName"
:metadata-field="field"
:v-model="field.value"
class="product-value"
/>
</el-form>
</div>
<div class="inquiry-product">
<el-row v-if="!isEmptyValue(productPrice)" :gutter="20">
<el-col style="padding-left: 0px; padding-right: 0%;">
<div class="product-description">
{{ productPrice.productName }} {{ productPrice.productDescription }}
</div>
<br><br><br>
<div class="product-price-base">
Precio Base
<span class="amount">
{{ formatPrice(productPrice.priceBase, productPrice.currency.iSOCode) }}
</span>
</div>
<br><br><br>
<div class="product-tax">
{{ productPrice.taxName }}
<span class="amount">
{{ formatPrice(productPrice.taxAmt, productPrice.currency.iSOCode) }}
</span>
</div>
<br><br><br>
<div class="product-price amount">
{{ formatPrice(productPrice.grandTotal, productPrice.currency.iSOCode) }}
</div>
</el-col>
</el-row>
</div>
</el-main>
</el-container>
</div>
<div
v-else
key="form-loading"
v-loading="!isLoaded"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel"
/>
<!-- </div> -->
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin'
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import fieldsList from './fieldsList.js'
import { getProductPrice } from '@/api/ADempiere/form/price-checking'
import { getProductPrice } from '@/api/ADempiere/form/price-checking.js'
import { formatPercent, formatPrice } from '@/utils/ADempiere/valueFormat.js'
import { getResource } from '@/api/ADempiere/persistence.js'
import { mergeByteArray, buildImageFromArray } from '@/utils/ADempiere/resource.js'
export default {
name: 'PriceInquiry',
name: 'PriceChecking',
mixins: [formMixin],
data() {
return {
fieldsList,
productPrice: {},
resource: {},
valuesImage: [{
identifier: 'undefined',
value: 'price-checking-background',
isLoaded: true
}],
unsubscribe: () => {}
}
},
@ -48,57 +104,204 @@ export default {
this.unsubscribe()
},
methods: {
buildImageFromArray,
getDefaultImage() {
return require('@/image/ADempiere/priceChecking/price-checking-background.png')
},
getImage(resource) {
let isImage
if (resource) {
if (resource.image) {
if (!this.valuesImage.some(item => item.identifier === resource.image)) {
this.valuesImage.push({
identifier: resource.image,
value: '',
isLoaded: false
})
}
if (this.resource[resource.image]) {
this.valuesImage.map(item => {
if (item.identifier === resource.image) {
return {
...item,
value: this.buildImageFromArray(resource, this.resource[resource.image]),
isLoaded: true
}
}
return item
})
} else { // Reload
if (!this.valuesImage.some(item => item.identifier === resource.image)) {
this.valuesImage.push({
identifier: resource.image,
value: '',
isLoaded: false
})
}
let result = new Uint8Array()
const callBack = {}
callBack.onData = (response) => {
result = mergeByteArray(result, response.getData())
}
callBack.onStatus = (status) => {
}
callBack.onEnd = (end) => {
this.resource[resource.image] = result
this.valuesImage.map(item => {
if (item.identifier === resource.image) {
return {
...item,
value: this.buildImageFromArray(resource, this.resource[isImage]),
isLoaded: true
}
}
return item
})
}
getResource({
resourceUuid: '1816f354-a868-4f4f-9a83-b0eb98cf1d05'
},
callBack)
}
}
}
},
focusProductValue() {
this.$refs.ProductValue[0].$children[0].$children[0].$children[1].$children[0].focus()
},
formatPercent,
formatPrice,
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'addActionKeyPerformed' && mutation.payload.columnName === 'ProductValue') {
// cleans all values except column name 'ProductValue'
this.setValues({ withOutColumnNames: ['ProductValue'] })
getProductPrice({
searchValue: mutation.payload.value
})
.then(productPrice => {
const { product, taxRate } = productPrice
const { product, taxRate, priceStd: priceBase } = productPrice
const { rate } = taxRate
const values = {
ProductName: product.name,
ProductDescription: product.description,
PriceList: productPrice.priceList,
TaxAmt: this.getTaxAmount(productPrice.priceList, taxRate.rate),
GrandTotal: this.getGrandTotal(productPrice.priceList, taxRate.rate)
this.productPrice = {
productName: product.name,
productDescription: product.description,
priceBase,
priceStd: productPrice.priceStd,
priceList: productPrice.priceList,
priceLimit: productPrice.priceLimit,
taxRate: rate,
image: product.imageURL,
taxName: taxRate.name,
taxIndicator: taxRate.taxIndicator,
taxAmt: this.getTaxAmount(priceBase, rate),
grandTotal: this.getGrandTotal(priceBase, rate),
currency: productPrice.currency
}
// set new values except column name 'ProductValue'
this.setValues({ values, withOutColumnNames: ['ProductValue'] })
})
.catch(error => {
this.$message({
type: 'info',
message: error.message
})
this.productPrice = {}
})
.finally(() => {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'ProductValue',
value: ''
})
this.getImage(this.productPrice)
})
}
})
},
getTaxAmount(priceList, taxRate) {
if (this.isEmptyValue(priceList) || this.isEmptyValue(taxRate)) {
getTaxAmount(basePrice, taxRate) {
if (this.isEmptyValue(basePrice) || this.isEmptyValue(taxRate)) {
return 0
}
return (priceList * taxRate) / 100
return (basePrice * taxRate) / 100
},
getGrandTotal(priceList, taxRate) {
if (this.isEmptyValue(priceList)) {
getGrandTotal(basePrice, taxRate) {
if (this.isEmptyValue(basePrice)) {
return 0
}
return priceList + this.getTaxAmount(priceList, taxRate)
return basePrice + this.getTaxAmount(basePrice, taxRate)
}
}
}
</script>
<style lang="scss" scoped>
.background-price-checking {
width: 100%;
height: 100%;
float: inherit;
// color: white;
// opacity: 0.5;
}
.product-description {
color: #32363a;
font-size: 25px;
float: right;
padding-bottom: 0px;
}
.product-price-base, .product-tax {
font-size: 35px;
float: right;
}
.product-price {
padding-top: 15px;
font-size: 50px;
float: right;
}
.inquiry-form {
position: absolute;
right: 5%;
width: 100%;
top: 10%;
z-index: 0;
}
.inquiry-product {
position: absolute;
right: 5%;
width: 100%;
top: 33%;
.amount {
color: black;
font-weight: bold;
}
}
</style>
<style lang="scss">
.price-inquiry {
input {
color: #606266 !important;
font-size: 200% !important;
font-size: 100% !important;
}
}
.product-value {
float: right;
padding-right: 0% !important;
z-index: 0;
.el-form-item__label {
font-size: 15px !important;
color: #000 !important;
}
}
.el-aside {
background: white;
width: 60%;
overflow: hidden;
}
.el-form-item {
margin-bottom: 10px !important;
margin-left: 10px;
margin-right: 0px !important;
}
</style>

View File

@ -4,25 +4,38 @@ import { createFieldFromDefinition, createFieldFromDictionary } from '@/utils/AD
export default {
name: 'FormMixn',
components: {
Field
Field,
FieldDefinition: Field
},
props: {
metadata: {
type: Object,
required: true
default: () => {}
}
},
data() {
let containerUuid = this.$route.meta.uuid
if (!this.isEmptyValue(this.metadata)) {
containerUuid = this.metadata.containerUuid
if (this.isEmptyValue(containerUuid)) {
containerUuid = this.metadata.uuid
}
}
return {
formUuid: this.$route.meta.uuid,
containerUuid,
fieldsList: [],
panelMetadata: {},
isLoaded: false,
isCustomForm: false,
unsubscribe: () => {},
panelType: 'form'
}
},
computed: {
getterPanel() {
return this.$store.getters.getPanel(this.metadata.containerUuid)
return this.$store.getters.getPanel(this.containerUuid)
}
},
created() {
@ -31,16 +44,26 @@ export default {
methods: {
createFieldFromDefinition,
createFieldFromDictionary,
/**
* Using forms and events with the enter key prevents the page from reloading
* with @submit.native.prevent="notSubmitForm" in el-form component
*/
notSubmitForm(event) {
event.preventDefault()
return false
},
async getPanel() {
const panel = this.getterPanel
if (panel) {
if (!this.isEmptyValue(panel)) {
this.fieldsList = panel.fieldList
this.isLoaded = true
this.panelMetadata = panel
} else {
await this.generateFieldsList()
this.$store.dispatch('addPanel', {
...this.metadata,
uuid: this.metadata.containerUuid,
isCustomForm: this.isCustomForm,
uuid: this.containerUuid,
panelType: this.panelType,
fieldList: this.fieldsList
})
@ -48,16 +71,21 @@ export default {
this.fieldsList = responsePanel.fieldList
this.$store.dispatch('changeFormAttribute', {
containerUuid: this.metadata.containerUuid,
containerUuid: this.containerUuid,
attributeName: 'fieldList',
attributeValue: this.fieldsList
})
this.panelMetadata = responsePanel
this.runAfterLoadPanel()
})
.finally(() => {
this.isLoaded = true
})
}
},
runAfterLoadPanel() {
// some actions after load form panel
},
generateFieldsList() {
let sequence = 0
const incrementSequence = (newValue) => {
@ -68,73 +96,75 @@ export default {
return sequence
}
return new Promise(resolve => {
const additionalAttributes = {
containerUuid: this.metadata.containerUuid,
isEvaluateValueChanges: false,
panelType: this.panelType
}
if (this.metadata) {
return new Promise(resolve => {
const additionalAttributes = {
containerUuid: this.containerUuid,
isEvaluateValueChanges: false,
panelType: this.panelType
}
const fieldsListFromDictionary = []
const fieldsListFromMetadata = []
const fieldsListFromDictionary = []
const fieldsListFromMetadata = []
this.fieldsList.forEach(fieldElement => {
if (fieldElement.isFromDictionary) {
// set sequence
if (fieldElement.overwriteDefinition) {
if (this.isEmptyValue(fieldElement.overwriteDefinition.sequence)) {
this.fieldsList.forEach(fieldElement => {
if (fieldElement.isFromDictionary) {
// set sequence
if (fieldElement.overwriteDefinition) {
if (this.isEmptyValue(fieldElement.overwriteDefinition.sequence)) {
fieldElement.overwriteDefinition.sequence = incrementSequence()
} else {
incrementSequence(fieldElement.overwriteDefinition.sequence)
}
} else {
fieldElement.overwriteDefinition = {}
fieldElement.overwriteDefinition.sequence = incrementSequence()
} else {
incrementSequence(fieldElement.overwriteDefinition.sequence)
}
} else {
fieldElement.overwriteDefinition = {}
fieldElement.overwriteDefinition.sequence = incrementSequence()
}
fieldsListFromDictionary.push(
this.createFieldFromDictionary({
...fieldElement,
...additionalAttributes
})
)
} else {
// set sequence
if (fieldElement.definition) {
if (this.isEmptyValue(fieldElement.definition.sequence)) {
fieldsListFromDictionary.push(
this.createFieldFromDictionary({
...fieldElement,
...additionalAttributes
})
)
} else {
// set sequence
if (fieldElement.definition) {
if (this.isEmptyValue(fieldElement.definition.sequence)) {
fieldElement.definition.sequence = incrementSequence()
} else {
incrementSequence(fieldElement.definition.sequence)
}
} else {
fieldElement.definition = {}
fieldElement.definition.sequence = incrementSequence()
} else {
incrementSequence(fieldElement.definition.sequence)
}
} else {
fieldElement.definition = {}
fieldElement.definition.sequence = incrementSequence()
}
fieldsListFromMetadata.push(
this.createFieldFromDefinition({
...fieldElement,
...additionalAttributes
fieldsListFromMetadata.push(
this.createFieldFromDefinition({
...fieldElement,
...additionalAttributes
})
)
}
})
let fieldsList = fieldsListFromMetadata
if (this.isEmptyValue(fieldsListFromDictionary)) {
this.fieldsList = fieldsList
resolve(fieldsList)
this.isLoaded = true
} else {
Promise.all(fieldsListFromDictionary)
.then(responsefields => {
fieldsList = fieldsList.concat(responsefields)
resolve(fieldsList)
this.fieldsList = fieldsList
this.isLoaded = true
})
)
}
})
let fieldsList = fieldsListFromMetadata
if (this.isEmptyValue(fieldsListFromDictionary)) {
this.fieldsList = fieldsList
resolve(fieldsList)
this.isLoaded = true
} else {
Promise.all(fieldsListFromDictionary)
.then(responsefields => {
fieldsList = fieldsList.concat(responsefields)
resolve(fieldsList)
this.fieldsList = fieldsList
this.isLoaded = true
})
}
})
}
},
// Set value for one field from panel
// use example: setValue('ProductName', 'Patio Fun')
@ -150,9 +180,9 @@ export default {
// Use example: setValues(values)
setValues({ values = {}, withOutColumnNames = [] }) {
this.$store.dispatch('notifyPanelChange', {
containerUuid: this.metadata.containerUuid,
containerUuid: this.containerUuid,
panelType: this.metadata.panelType,
newValues: values,
attributes: values,
withOutColumnNames,
isChangedAllValues: true
})
@ -161,7 +191,7 @@ export default {
this.$store.dispatch('addAction', {
name: action.name,
action: action.action,
containerUuid: this.metadata.containerUuid
containerUuid: this.containerUuid
})
}
}

View File

@ -72,7 +72,7 @@ export default {
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
@ -93,7 +93,7 @@ export default {
vertical-align: middle;
height: 28px;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
@ -117,7 +117,7 @@ export default {
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
@ -136,7 +136,7 @@ export default {
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;

View File

@ -0,0 +1,75 @@
<template>
<el-footer style="height: 30px;">
<div style="float: right;">
<el-pagination
:current-page="currentPage"
small
layout="slot, total, prev, pager, next"
:page-size="pageSize"
:total="total"
@current-change="handleChangePage"
>
<template v-slot>
<span v-if="isSelection">
{{ $t('table.dataTable.selected') }}: {{ selection }} / <!-- show total records -->
</span>
</template>
</el-pagination>
</div>
</el-footer>
</template>
<script>
export default {
name: 'CustomPagination',
props: {
parentUuid: {
type: String,
default: undefined
},
containerUuid: {
type: String,
default: undefined
},
panelType: {
type: String,
default: 'window'
},
currentPage: {
type: Number,
default: undefined
},
selection: {
type: Number,
default: undefined
},
pageSize: {
type: Number,
default: 50
},
total: {
type: Number,
default: undefined
},
handleChangePage: {
type: Function,
default: (pageNumber) => {
this.$store.dispatch('setPageNumber', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
pageNumber,
panelType: this.panelType
})
}
}
},
computed: {
isSelection() {
if (this.isEmptyValue(this.selection)) {
return false
}
return true
}
}
}
</script>

View File

@ -121,7 +121,7 @@
</template>
<script>
import { mainPanelMixin } from '@/components/ADempiere/Panel/mainPanelMixin.js'
import mainPanelMixin from './mainPanelMixin.js'
import draggable from 'vuedraggable'
export default {

View File

@ -4,7 +4,7 @@ import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils.js'
import { parsedValueComponent } from '@/utils/ADempiere/valueUtils.js'
import { convertObjectToKeyValue } from '@/utils/ADempiere/valueFormat.js'
export const mainPanelMixin = {
export default {
name: 'MainPanelMixin',
components: {
FieldDefinition,
@ -461,6 +461,10 @@ export const mainPanelMixin = {
return groupsList
},
/**
* Set title in tag view
* @param {string} actionValue
*/
setTagsViewTitle(actionValue) {
if (actionValue !== 'create-new' && !this.isEmptyValue(actionValue) && this.panelMetadata.isDocument && this.getterDataStore.isLoaded) {
this.$store.dispatch('listWorkflows', this.metadata.tableName)
@ -476,11 +480,17 @@ export const mainPanelMixin = {
} else {
const { identifierColumns } = this.panelMetadata
if (!this.isEmptyValue(identifierColumns)) {
if (this.dataRecords[identifierColumns[0]]) {
this.tagTitle.action = this.dataRecords[identifierColumns[0]]
const keyName = identifierColumns[0].columnName
if (this.dataRecords[keyName]) {
this.tagTitle.action = this.dataRecords[keyName]
} else {
const field = this.fieldList.find(fieldItem => fieldItem.isIdentifier)
this.tagTitle.action = field.value
const value = this.$store.getters.getValueOfField({
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
columnName: field.columnName
})
this.tagTitle.action = value
}
} else {
this.tagTitle.action = this.$t('tagsView.seeRecord')
@ -509,12 +519,15 @@ export const mainPanelMixin = {
}
})
}
const currentRecord = this.getterDataStore.record.find(record => record.UUID === uuidRecord) || {}
this.dataRecords = currentRecord
this.$store.dispatch('currentRecord', currentRecord)
this.setTagsViewTitle(uuidRecord)
if (this.$route.query && this.$route.query.action === 'create-new') {
this.setFocus()
}
const currentRecord = this.getterDataStore.record.find(record => record.UUID === uuidRecord)
this.$store.dispatch('currentRecord', currentRecord)
},
async setFocus() {
return new Promise(resolve => {

View File

@ -112,7 +112,7 @@
</template>
<script>
import { mainPanelMixin } from '@/components/ADempiere/Panel/mainPanelMixin'
import mainPanelMixin from './mainPanelMixin.js'
export default {
name: 'MainPanelMobile',

View File

@ -25,8 +25,9 @@
</template>
<script>
import { tabMixin } from '@/components/ADempiere/Tab/tabMixin'
import tabMixin from './tabMixin.js'
import MainPanel from '@/components/ADempiere/Panel'
import { parseContext } from '@/utils/ADempiere/contextUtils'
export default {
name: 'TabParent',
@ -72,7 +73,10 @@ export default {
params: {
...this.$route.params
}
}).catch(error => {
console.info(`Tab Component: ${error.name}, ${error.message}`)
})
this.$route.meta.tabUuid = this.tabUuid
}
},
@ -88,6 +92,18 @@ export default {
window: this.windowMetadata
})
this.$route.meta.tabUuid = this.tabUuid
},
handleBeforeLeave(activeName) {
const tabIndex = parseInt(activeName, 10)
const metadataTab = this.tabsList.find(tab => tab.tabParentIndex === tabIndex)
if (!this.isEmptyValue(metadataTab.whereClause) && metadataTab.whereClause.includes('@')) {
metadataTab.whereClause = parseContext({
parentUuid: metadataTab.parentUuid,
containerUuid: metadataTab.uuid,
value: metadataTab.whereClause,
isBooleanToString: true
}).value
}
}
}
}

View File

@ -23,7 +23,7 @@
</template>
<script>
import { tabMixin } from '@/components/ADempiere/Tab/tabMixin'
import tabMixin from './tabMixin.js'
import DataTable from '@/components/ADempiere/DataTable'
export default {
@ -76,6 +76,8 @@ export default {
params: {
...this.$route.params
}
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
}
},

View File

@ -1,6 +1,5 @@
import { parseContext } from '@/utils/ADempiere/contextUtils'
export const tabMixin = {
export default {
name: 'MixinTab',
props: {
windowUuid: {
type: String,
@ -46,17 +45,6 @@ export const tabMixin = {
if (this.tabUuid !== tabHTML.$attrs.tabuuid) {
this.tabUuid = tabHTML.$attrs.tabuuid
}
},
handleBeforeLeave(activeName) {
const metadataTab = this.tabsList.find(tab => tab.index === parseInt(activeName, 10))
if (!this.isEmptyValue(metadataTab.whereClause) && metadataTab.whereClause.includes('@')) {
metadataTab.whereClause = parseContext({
parentUuid: metadataTab.parentUuid,
containerUuid: metadataTab.uuid,
value: metadataTab.whereClause,
isBooleanToString: true
}).value
}
}
}
}

View File

@ -3,17 +3,18 @@
<el-step
v-for="(node, index) in listDocumentStatus"
:key="index"
:icon="index < getActive ? 'el-icon-finished' : ( index === getActive ? 'el-icon-s-flag' : 'el-icon-d-arrow-right')"
:icon="index < getActive ? 'el-icon-finished' : (index === getActive ? 'el-icon-s-flag' : 'el-icon-d-arrow-right')"
>
<template slot="title">
<el-popover
v-if="index === getActive"
index="popver-active"
placement="top-start"
width="400"
trigger="click"
>
<el-select
v-model="valueActionDocument"
v-model="value"
@change="documentActionChange"
@visible-change="listActionDocument"
>
@ -24,27 +25,41 @@
:value="item.value"
/>
</el-select>
<el-tag
v-if="isEmptyValue(valueActionDocument)"
:type="tagStatus(getValueStatus)"
v-if="!isEmptyValue(value)"
index="tag-with-value"
:type="tagStatus(value)"
>
{{ getValue.displayColumn }}
{{ displayedValue }}
</el-tag>
<el-tag
v-else
:type="tagStatus(valueActionDocument)"
index="tag-without-value"
:type="tagStatus(value)"
>
{{ labelDocumentActions }}
{{ infoDocumentAction.name }}
</el-tag>
<p v-if="isEmptyValue(descriptionDocumentActions)"> {{ getValue.description }} </p>
<p v-else> {{ descriptionDocumentActions }} </p>
<el-link slot="reference" :autofocus="true" :underline="false" class="title"> {{ node.name }} </el-link>
<p v-if="!isEmptyValue(infoDocumentAction.description)" index="with-description">
{{ infoDocumentAction.description }}
</p>
<p v-else index="without-description">
{{ fieldDocStatus.description }}
</p>
<el-link slot="reference" :autofocus="true" :underline="false" class="title">
{{ node.name }}
</el-link>
</el-popover>
<span v-else> {{ node.name }} </span>
<span v-else index="node-name">
{{ node.name }}
</span>
</template>
</el-step>
</el-steps>
</template>
<script>
export default {
name: 'WorkflowStatusBar',
@ -67,103 +82,83 @@ export default {
}
},
data() {
// TODO: See 'DocAction'
const columnName = 'DocStatus'
return {
currentKey: 100,
typeAction: 0,
chatNote: '',
documentStatusesList: [],
valueActionDocument: ''
columnName,
displayColumnName: `DisplayColumn_${columnName}`,
documentStatusesList: []
}
},
computed: {
getPanelRight() {
return this.$store.getters.getPanelRight
value: {
get() {
return this.$store.getters.getValueOfField({
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
columnName: this.columnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
columnName: this.columnName,
value
})
}
},
getterPanel() {
return this.$store.getters.getPanel(this.containerUuid)
displayedValue() {
return this.$store.getters.getValueOfField({
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.displayColumnName
})
},
getValueStatus() {
const panel = this.getterPanel
var status
fieldDocStatus() {
const panel = this.$store.getters.getPanel(this.containerUuid)
if (!this.isEmptyValue(panel)) {
status = panel.fieldList.find(field => {
if (field.columnName === 'DocStatus') {
return field
}
const field = panel.fieldList.find(fieldItem => {
return fieldItem.columnName === this.columnName
})
return field
}
if (!this.isEmptyValue(status)) {
return status.value
}
return 'CL'
},
getValue() {
if (!this.isEmptyValue(this.getterPanel)) {
var value = this.getterPanel.fieldList.find(field => {
if (field.columnName === 'DocStatus') {
return field
}
})
return value
}
return 'CL'
return undefined
},
getActive() {
const active = this.listDocumentStatus.findIndex(index => index.value === this.getValueStatus)
return active
},
gettersNodeList() {
var node = this.$store.getters.getNodeWorkflow
if (!this.isEmptyValue(node.workflowsList)) {
return node.workflowsList[0].workflowNodesList
}
return node.workflowsList
const valueStatus = this.value
return this.listDocumentStatus.findIndex(index => index.value === valueStatus)
},
listDocumentStatus() {
return this.$store.getters.getListDocumentStatus.documentActionsList
},
typeStatus() {
if (this.getValueStatus === 'VO') {
return 'error'
} else {
return 'success'
}
},
documentActions() {
return this.$store.getters.getListDocumentActions
},
listDocumentActions() {
// TODO: Add current value in disabled
return this.documentActions.documentActionsList
},
labelDocumentActions() {
infoDocumentAction() {
const value = this.value
const found = this.listDocumentActions.find(element => {
if (element.value === this.valueActionDocument) {
return element
}
return element.value === value
})
if (this.isEmptyValue(found)) {
return this.valueActionDocument
return value
}
return found.name
},
descriptionDocumentActions() {
const found = this.listDocumentActions.find(element => {
if (element.value === this.valueActionDocument) {
return element
}
})
if (this.isEmptyValue(found)) {
return this.valueActionDocument
}
return found.description
return found
},
processOrderUuid() {
return this.$store.getters.getOrders
}
},
created() {
this.gettersNodeList
},
methods: {
listActionDocument(isShowList) {
if (isShowList) {
@ -197,14 +192,14 @@ export default {
// recordUuid: this.$route.query.action,
// parametersList: [{
// columnName: 'DocAction',
// value: this.valueActionDocument
// value: this.value
// }],
// isActionDocument: true,
// parentUuid: this.parentUuid,
// panelType: this.panelType,
// containerUuid: this.containerUuid// determinate if get table name and record id (window) or selection (browser)
// })
// this.valueActionDocument = ''
// this.value = ''
// })
}
}
@ -217,7 +212,6 @@ export default {
color: #000000;
}
</style>
<style>
.scroll-window-log-change {
max-height: 74vh !important;

View File

@ -48,14 +48,18 @@ export default {
}
</script>
<style scoped>
.drag-select >>> .sortable-ghost {
opacity: .8;
color: #fff!important;
background: #42b983!important;
}
<style lang="scss" scoped>
.drag-select {
::v-deep {
.sortable-ghost {
opacity: .8;
color: #fff !important;
background: #42b983 !important;
}
.drag-select >>> .el-tag {
cursor: pointer;
.el-tag {
cursor: pointer;
}
}
}
</style>

View File

@ -202,7 +202,8 @@ export default {
border-radius: 0;
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;

View File

@ -54,19 +54,24 @@ export default {
}
</script>
<style scoped>
.json-editor{
<style lang="scss" scoped>
.json-editor {
height: 100%;
position: relative;
}
.json-editor >>> .CodeMirror {
height: auto;
min-height: 300px;
}
.json-editor >>> .CodeMirror-scroll{
min-height: 300px;
}
.json-editor >>> .cm-s-rubyblue span.cm-string {
color: #F08047;
::v-deep {
.CodeMirror {
height: auto;
min-height: 300px;
}
.CodeMirror-scroll {
min-height: 300px;
}
.cm-s-rubyblue span.cm-string {
color: #F08047;
}
}
}
</style>

View File

@ -104,7 +104,7 @@ export default {
<style lang="scss" scoped>
.editor-slide-upload {
margin-bottom: 20px;
/deep/ .el-upload--picture-card {
::v-deep .el-upload--picture-card {
width: 100%;
}
}

View File

@ -220,28 +220,37 @@ export default {
}
</script>
<style scoped>
<style lang="scss" scoped>
.tinymce-container {
position: relative;
line-height: normal;
}
.tinymce-container>>>.mce-fullscreen {
z-index: 10000;
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}

View File

@ -1,11 +1,11 @@
import store from '@/store'
export default {
inserted(el, binding, vnode) {
const { value } = binding
const roles = store.getters && store.getters.roles
function checkPermission(el, binding) {
const { value } = binding
const roles = store.getters && store.getters.roles
if (value && value instanceof Array && value.length > 0) {
if (value && value instanceof Array) {
if (value.length > 0) {
const permissionRoles = value
const hasPermission = roles.some(role => {
@ -15,8 +15,17 @@ export default {
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
}
}
export default {
inserted(el, binding) {
checkPermission(el, binding)
},
update(el, binding) {
checkPermission(el, binding)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

View File

@ -35,6 +35,7 @@ export default {
processError: 'Was not executed',
//
emptyValues: 'Parameter(s) empty value',
fieldCannotBeEmpty: 'The field value cannot be empty.',
fieldMandatory: 'The field is mandatory',
requestError: 'Error executing the request',
successChangeRole: 'The role has been changed',
@ -322,6 +323,75 @@ export default {
},
quickAccess: {
newRecord: 'Quick Access to Create New Record',
listRecords: 'Quick Access to List All Records'
listRecords: 'Quick Access to List All Records',
searchWithEnter: 'Press enter to search'
},
businessPartner: {
notFound: 'Business partner not found.'
},
form: {
pos: {
title: 'POS',
optionsPoinSales: {
title: 'Quick Point of Sales Options',
salesOrder: {
title: 'Sale Order',
newOrder: 'New Order',
ordersHistory: 'Orders History',
generateImmediateInvoice: 'Generate Immediate Invoice',
completePreparedOrder: 'Complete Prepared Order',
cancelSaleTransaction: 'Cancel Sale Transaction',
createPos: 'Create Point of Sale Withdrawal',
toPrint: 'To Print'
},
cashManagement: {
title: 'Cash Management',
cashOpening: 'Cash Opening',
cashwithdrawal: 'Cash withdrawa',
closeBox: 'Close the box'
},
generalOptions: {
title: 'General Options',
changePos: 'Change Point of Sale',
listProducts: 'Change Point of Sale'
}
},
tableProduct: {
product: 'Product',
quantity: 'Quantity',
options: 'Options',
editQuantities: 'Edit Quantities',
remove: 'Remove'
},
product: {
productInformation: 'Product information',
code: 'Code',
name: 'Name',
description: 'Description',
price: 'Price',
taxRate: 'Tax Rate',
quantityAvailable: 'Quantity Avalible'
},
order: {
order: 'Order',
seller: 'Seller',
date: 'Date',
subTotal: 'Sub-Total',
type: 'Type',
discount: 'Descuento',
tax: 'Tax',
total: 'Total',
itemQuantity: 'Item Quantity',
numberLines: 'Number of Lines',
pointSale: 'Point of Sale',
collect: 'Collect'
},
collect: {
orderTotal: 'Order Total',
pending: 'Pending',
payment: 'Payment',
change: 'Change'
}
}
}
}

View File

@ -35,6 +35,7 @@ export default {
processError: 'No fue ejecutado',
//
emptyValues: 'Parametro(s) con valores vacios',
fieldCannotBeEmpty: 'El valor del campo no puede estar vacío.',
fieldMandatory: 'El campo es obligatorio',
requestError: 'Error al ejecutar la petición',
successChangeRole: 'El rol se ha cambiado',
@ -238,7 +239,7 @@ export default {
currentRole: 'Rol actual',
clientName: 'Nombre del cliente',
description: 'Descripción',
changeRole: 'Cambiar rol',
changeRole: 'Cambiar Rol',
changeLanguage: 'Cambiar idioma',
changeLanguagePlaceholder: 'Elija un idioma'
},
@ -297,6 +298,75 @@ export default {
},
quickAccess: {
newRecord: 'Acceso Rápido para Crear Registro Nuevo',
listRecords: 'Acceso Rápido para Listar los Registros'
listRecords: 'Acceso Rápido para Listar los Registros',
searchWithEnter: 'Pulse enter para realizar la busqueda'
},
businessPartner: {
notFound: 'Socio de negocio no encontrado.'
},
form: {
pos: {
title: 'Punto de Venta',
optionsPoinSales: {
title: 'Opciones Rápidas del Punto de Ventas',
salesOrder: {
title: 'Orden de Venta',
newOrder: 'Nueva Orden',
ordersHistory: 'Histórico de Órdenes ',
generateImmediateInvoice: 'Generar Factura Inmediata',
completePreparedOrder: 'Completar Orden Preparada',
cancelSaleTransaction: 'Anular Transacción de Venta',
createPos: 'Crear Retiro de Punto de Venta',
toPrint: 'Imprimir'
},
cashManagement: {
title: 'Gestión de Caja',
cashOpening: 'Apertura de Caja',
cashwithdrawal: 'Retiro de Efectivo',
closeBox: 'Cierre de Caja'
},
generalOptions: {
title: 'Opciones Generales',
changePos: 'Cambiar Punto de Venta',
listProducts: 'Lista de Productos y Precios'
}
},
tableProduct: {
product: 'Producto',
quantity: 'Cantidad',
options: 'Opciones',
editQuantities: 'Editar Cantidades',
remove: 'Eliminar'
},
product: {
productInformation: 'Información de Producto',
code: 'Código',
name: 'Nombre',
description: 'Descripción',
price: 'Precio',
taxRate: 'Tasa de Impuesto',
quantityAvailable: 'Cantidad Disponible'
},
order: {
order: 'Orden',
seller: 'Vendedor',
date: 'Date',
subTotal: 'Sub-Total',
type: 'Tipo',
discount: 'Descuento',
tax: 'Impuesto',
total: 'Total',
itemQuantity: 'Cantidad de Árticulo',
numberLines: 'Cantidad de Lineas',
pointSale: 'Punto de Venta',
collect: 'Cobrar'
},
collect: {
orderTotal: 'Total de Orden',
pending: 'Pendiente',
payment: 'Pago',
change: 'Cambio'
}
}
}
}

View File

@ -123,7 +123,11 @@ export default {
},
async logout() {
await this.$store.dispatch('user/logout')
this.$router.push({ path: '/login', query: { redirect: this.$route.fullPath }})
this.$router.push({
path: '/login'
}).catch(error => {
console.info(error)
})
},
handleClick() {
this.$router.push({ name: 'Profile' })

View File

@ -17,7 +17,11 @@ export default {
const vnodes = []
if (icon) {
vnodes.push(<svg-icon icon-class={icon}/>)
if (icon.includes('el-icon')) {
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
} else {
vnodes.push(<svg-icon icon-class={icon}/>)
}
}
if (title) {
@ -27,3 +31,11 @@ export default {
}
}
</script>
<style scoped>
.sub-el-icon {
color: currentColor;
width: 1em;
height: 1em;
}
</style>

View File

@ -94,7 +94,7 @@ export default {
position: relative;
overflow: hidden;
width: 100%;
/deep/ {
::v-deep {
.el-scrollbar__bar {
bottom: 0px;
}

View File

@ -13,7 +13,13 @@
ref="tag"
:key="tag.path"
:class="isActive(tag)?'active':''"
:to="{ name: tag.name, path: tag.path, query: tag.query, fullPath: tag.fullPath, params: tag.params }"
:to="{
name: tag.name,
path: tag.path,
query: tag.query,
fullPath: tag.fullPath,
params: tag.params
}"
tag="span"
class="tags-view-item"
@click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"

View File

@ -25,7 +25,7 @@ import nestedRouter from './modules/nested'
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
noCache: true if set true, the page will no be cached(default is false)
affix: true if set true, the tag will affix in the tags-view
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
@ -223,7 +223,7 @@ export const asyncRoutes = [
name: 'Example',
meta: {
title: 'example',
icon: 'example'
icon: 'el-icon-s-help'
},
children: [
{

View File

@ -1,9 +1,11 @@
import { getMenu } from '@/api/user'
import { getToken } from '@/utils/auth'
import { convertAction } from '@/utils/ADempiere/dictionaryUtils'
import store from '@/store'
/* Layout */
import Layout from '@/layout'
import { isEmptyValue } from '@adempiere/grpc-core-client'
const staticRoutes = [
{
@ -71,22 +73,22 @@ const staticRoutes = [
]
// Get Menu from server
export function loadMainMenu() {
export function loadMainMenu(organizationId = 0) {
return new Promise(resolve => {
organizationId = isEmptyValue(store.getters['user/getOrganization']) ? 0 : store.getters['user/getOrganization'].id
getMenu(getToken()).then(menuResponse => {
const asyncRoutesMap = []
menuResponse.childsList.forEach(menuElement => {
const optionMenu = getRouteFromMenuItem(menuElement)
const optionMenu = getRouteFromMenuItem(menuElement, organizationId)
if (menuElement.isSummary) {
menuElement.childsList.forEach(menu => {
const childsSumaryConverted = getChildFromAction(menu, 0)
const childsSumaryConverted = getChildFromAction({ menu, index: 0, organizationId })
optionMenu.children.push(childsSumaryConverted)
optionMenu.children[0].meta.childs.push(childsSumaryConverted)
optionMenu.meta.childs.push(childsSumaryConverted)
})
} else {
const childsConverted = getChildFromAction(menuElement)
const childsConverted = getChildFromAction({ menu: menuElement, index: undefined, organizationId })
optionMenu.children.push(childsConverted)
optionMenu.meta.childs.push(childsConverted)
@ -101,16 +103,17 @@ export function loadMainMenu() {
}
// Get Only Child
function getChildFromAction(menu, index) {
function getChildFromAction({ menu, index, organizationId }) {
const action = menu.action
const actionAttributes = convertAction(action)
const clientId = store.getters['user/getRole'].clientId
let routeIdentifier = actionAttributes.name + '/' + menu.id
if (menu.isSummary) {
routeIdentifier = '/' + menu.id
}
const option = {
path: routeIdentifier,
path: '/' + clientId + '/' + organizationId + '/' + routeIdentifier,
component: actionAttributes.component,
name: menu.uuid,
hidden: index > 0,
@ -136,7 +139,7 @@ function getChildFromAction(menu, index) {
if (actionAttributes.isIndex || actionAttributes.name === 'summary') {
option['children'] = []
menu.childsList.forEach(child => {
const menuConverted = getChildFromAction(child, 1)
const menuConverted = getChildFromAction({ menu: child, index: 1, organizationId })
option.children.push(menuConverted)
option.meta.childs.push(menuConverted)
})
@ -145,11 +148,12 @@ function getChildFromAction(menu, index) {
}
// Convert menu item from server to Route
function getRouteFromMenuItem(menu) {
function getRouteFromMenuItem(menu, organizationId) {
const action = menu.action
const actionAttributes = convertAction(action)
const clientId = store.getters['user/getRole'].clientId
const optionMenu = {
path: '/' + menu.id,
path: '/' + clientId + '/' + organizationId + '/' + menu.id,
redirect: '/' + menu.id + '/index',
component: Layout,
name: menu.uuid,

View File

@ -118,7 +118,6 @@ const browserControl = {
// datatables attributes
isNew: false,
isEdit: false,
isSelected: false,
isReadOnlyFromRow: false
}
})

View File

@ -9,9 +9,11 @@ import {
unlockPrivateAccessFromServer
} from '@/api/ADempiere/private-access'
import {
isEmptyValue,
convertArrayPairsToObject
extractPagingToken,
isEmptyValue
} from '@/utils/ADempiere/valueUtils.js'
import { convertArrayKeyValueObject } from '@/utils/ADempiere/valueFormat.js'
import { typeValue } from '@/utils/ADempiere/valueUtils.js'
import { parseContext } from '@/utils/ADempiere/contextUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import { TABLE, TABLE_DIRECT } from '@/utils/ADempiere/references'
@ -210,14 +212,14 @@ const data = {
// TODO: Evaluate if is field is read only and FieldSelect
.filter(itemField => {
return itemField.componentPath === 'FieldSelect' ||
String(values[itemField.columnName]) === '[object Object]' ||
typeValue(values[itemField.columnName]) === 'OBJECT' ||
itemField.isSQLValue
})
.map(async itemField => {
const { columnName, componentPath } = itemField
let valueGetDisplayColumn = values[columnName]
if (String(values[columnName]) === '[object Object]') {
if (typeValue(values[columnName]) === 'OBJECT') {
if (componentPath === 'FieldSelect') {
values[columnName] = ' '
values[itemField.displayColumnName] = ' '
@ -248,7 +250,7 @@ const data = {
}
if (!isEmptyValue(valueGetDisplayColumn) &&
String(valueGetDisplayColumn) === '[object Object]' &&
typeValue(valueGetDisplayColumn) === 'OBJECT' &&
valueGetDisplayColumn.isSQL) {
// get value from Query
valueGetDisplayColumn = await dispatch('getValueBySQL', {
@ -532,14 +534,10 @@ const data = {
const recordsList = dataResponse.recordsList.map(itemRecord => {
const values = itemRecord.values
// datatables attributes
values.isNew = false
values.isEdit = false
values.isSelected = false
values.isReadOnlyFromRow = false
let isEdit = false
if (isAddDefaultValues) {
if (inEdited.find(itemEdit => itemEdit.UUID === values.UUID)) {
values.isEdit = true
isEdit = true
}
}
@ -547,7 +545,11 @@ const data = {
// server (empty fields are not brought from the server)
return {
...defaultValues,
...values
...values,
// datatables attributes
isNew: false,
isEdit,
isReadOnlyFromRow: false
}
})
@ -556,10 +558,7 @@ const data = {
if (isEmptyValue(token)) {
token = dataStore.nextPageToken
} else {
token = token.slice(0, -2)
if (token.substr(-1, 1) === '-') {
token = token.slice(0, -1)
}
token = extractPagingToken(token)
}
if (isShowNotification) {
let searchMessage = 'searchWithOutRecords'
@ -579,7 +578,7 @@ const data = {
selection: dataStore.selection,
recordCount: dataResponse.recordCount,
nextPageToken: token,
originalNextPageToken: originalNextPageToken,
originalNextPageToken,
isAddRecord,
pageNumber: dataStore.pageNumber,
tableName,
@ -670,7 +669,7 @@ const data = {
})
}
if (Array.isArray(values)) {
values = convertArrayPairsToObject({
values = convertArrayKeyValueObject({
arrayToConvert: values
})
}
@ -702,7 +701,7 @@ const data = {
displayColumn,
withOutColumnNames = []
}) {
dispatch('setContext', {
dispatch('setPreferenceContext', {
parentUuid,
containerUuid,
columnName,
@ -985,7 +984,7 @@ const data = {
*/
getSelectionToServer: (state, getters, rootState, rootGetters) => ({ containerUuid, selection = [] }) => {
const selectionToServer = []
const withOut = ['isEdit', 'isSelected', 'isSendToServer']
const withOut = ['isEdit', 'isSendToServer']
if (selection.length <= 0) {
selection = getters.getDataRecordSelection(containerUuid)

View File

@ -3,7 +3,9 @@ import { getField as getFieldFromDictionary } from '@/api/ADempiere/dictionary'
const initStateLookup = {
referenceList: [],
fieldList: [],
validationRuleList: []
validationRuleList: [],
fieldListLocation: [],
isShowedLocation: false
}
const field = {
@ -20,11 +22,17 @@ const field = {
},
resetStateLookup(state) {
state = initStateLookup
},
setShowedLocation(state, isShowed) {
state.isShowedLocation = isShowed
},
setfieldListLocation(state, fieldListLocation) {
state.fieldListLocation = fieldListLocation
}
},
actions: {
// Get Reference from Server based on criteria
getFieldFromServer({ commit, rootGetters }, {
getFieldFromServer({ commit }, {
fieldUuid,
columnUuid,
elementUuid,
@ -52,35 +60,41 @@ const field = {
fieldResponse.tableName = tableName
fieldResponse.columnName = columnName
}
commit('addField', {
fieldResponse
})
commit('addField', fieldResponse)
return fieldResponse
})
.catch(error => {
console.warn(`Get Field, Select Base - Error ${error.code}: ${error.message}.`)
console.warn(`Get Field - Error ${error.code}: ${error.message}.`)
})
},
changeSequence({ commit }, params) {
commit('setfieldListLocation', params)
}
},
getters: {
getIsShowedLocation: (state) => {
return state.isShowedLocation
},
getFieldFromUuid: (state) => (uuid) => {
return state.fieldList.find(fieldItem => {
return fieldItem.fieldResponse.uuid === uuid
return fieldItem.uuid === uuid
})
},
getFieldFromColumnUuid: (state) => (columnUuid) => {
return state.fieldList.find(fieldItem => {
return fieldItem.fieldResponse.columnUuid === columnUuid
return fieldItem.columnUuid === columnUuid
})
},
getFieldFromElementUuid: (state) => (elementUuid) => {
return state.fieldList.find(fieldItem => {
return fieldItem.fieldResponse.elementUuid === elementUuid
return fieldItem.elementUuid === elementUuid
})
},
getFieldFromElementColumnName: (state) => (elementColumnName) => {
return state.fieldList.find(fieldItem => {
return fieldItem.fieldResponse.elementColumnName === elementColumnName
return fieldItem.elementColumnName === elementColumnName
})
},
getFieldFromTableNameAndColumnName: (state) => ({
@ -88,8 +102,11 @@ const field = {
columnName
}) => {
return state.fieldList.find(fieldItem => {
return fieldItem.fieldResponse.tableName === tableName && fieldItem.fieldResponse.columnName === columnName
return fieldItem.tableName === tableName && fieldItem.columnName === columnName
})
},
getFieldLocation: (state) => {
return state.fieldListLocation
}
}
}

View File

@ -14,19 +14,41 @@ const value = {
field: {}
}
},
updateValueOfField(state, payload) {
/**
*
* @param {string} parentUuid
* @param {string} containerUuid
* @param {string} columnName
* @param {mixed} value
* @param {boolean} isOverWriteParent // overwite parent context values
*/
updateValueOfField(state, {
parentUuid,
containerUuid,
columnName,
value,
isOverWriteParent = true
}) {
// Only Parent
if (payload.parentUuid) {
const keyParent = payload.parentUuid + '_' + payload.columnName
if (payload.value !== state.field[keyParent]) {
Vue.set(state.field, keyParent, payload.value)
if (parentUuid) {
const keyParent = parentUuid + '_' + columnName
const valueParent = state.field[keyParent]
if (value !== valueParent) {
if (isOverWriteParent) {
Vue.set(state.field, keyParent, value)
} else {
if (isEmptyValue(value)) {
// tab child no replace parent context with empty
Vue.set(state.field, keyParent, value)
}
}
}
}
// Only Container
if (payload.containerUuid) {
const keyContainer = payload.containerUuid + '_' + payload.columnName
if (payload.value !== state.field[keyContainer]) {
Vue.set(state.field, keyContainer, payload.value)
if (containerUuid) {
const keyContainer = containerUuid + '_' + columnName
if (value !== state.field[keyContainer]) {
Vue.set(state.field, keyContainer, value)
}
}
},
@ -65,16 +87,26 @@ const value = {
}
},
getters: {
getValueOfField: (state) => ({ containerUuid, columnName }) => {
return state.field[containerUuid + '_' + columnName]
},
getValueOfContainer: (state) => ({ parentUuid, containerUuid, columnName }) => {
// get in tab level
let value = state.field[containerUuid + '_' + columnName]
if (isEmptyValue(value) && parentUuid) {
getValueOfField: (state) => ({
parentUuid,
containerUuid,
columnName
}) => {
let key = ''
let value
if (containerUuid) {
// get in tab level
key += containerUuid + '_'
}
key += columnName
value = state.field[key]
if (parentUuid && isEmptyValue(value)) {
// get in window level
key = parentUuid + '_' + columnName
value = state.field[parentUuid + '_' + columnName]
}
return value
},
/**
@ -87,9 +119,9 @@ const value = {
getValuesView: (state) => ({
parentUuid,
containerUuid,
isOnlyColumns = true,
format = 'array'
}) => {
console.log(parentUuid, containerUuid)
// generate context with parent uuid or container uuid associated
const contextAllContainers = {}
Object.keys(state.field).forEach(key => {
@ -102,26 +134,15 @@ const value = {
const objectValues = {}
const pairsValues = Object.keys(contextAllContainers).map(key => {
const value = contextAllContainers[key]
if (isEmptyValue(value)) {
return
}
let columnName
if (parentUuid) {
if (!key.includes(containerUuid)) {
columnName = key
.replace(`${parentUuid}_`, '')
.replace(`${containerUuid}_`, '')
// set window parent context
objectValues[columnName] = value
}
// next if is tab context
return {
columnName,
value
}
if (isOnlyColumns) {
key = key
.replace(`${parentUuid}_`, '')
.replace(`${containerUuid}_`, '')
}
// TODO: Verify if overwrite key with empty value
const columnName = key
// set container context (smart browser, process/report, form)
columnName = key.replace(`${containerUuid}_`, '')
objectValues[columnName] = value
return {
columnName,

View File

@ -20,10 +20,17 @@ const form = {
if (payload.attributeNameControl) {
value = payload.form[payload.attributeNameControl]
}
payload.form[payload.attributeName] = value
if (isEmptyValue(payload.attributeName)) {
payload.form[payload.attributeName] = value
}
}
},
actions: {
addForm({ commit, getters }, metadataForm) {
if (!getters.getForm(metadataForm.uuid)) {
commit('addForm', metadataForm)
}
},
getFormFromServer({ commit, dispatch }, {
id,
containerUuid,

View File

@ -64,7 +64,8 @@ const lookup = {
const label = lookupItemResponse.values.DisplayColumn
const option = {
label: isEmptyValue(label) ? ' ' : label,
key: value // lookupItemResponse.values.KeyColumn
uuid: lookupItemResponse.uuid,
id: value // lookupItemResponse.values.KeyColumn
}
commit('addLoockupItem', {
@ -121,21 +122,23 @@ const lookup = {
const list = []
lookupListResponse.recordsList.forEach(itemLookup => {
const {
KeyColumn: key,
KeyColumn: id,
DisplayColumn: label
} = itemLookup.values
if (!isEmptyValue(key)) {
if (!isEmptyValue(id)) {
list.push({
label,
key
id,
uuid: itemLookup.uuid
})
}
})
if (isAddBlankValue) {
list.unshift({
label: ' ',
key: blankValue
id: blankValue,
uuid: undefined
})
}
commit('addLoockupList', {

View File

@ -5,7 +5,11 @@
// - Window: Just need storage tab and fields
// - Process & Report: Always save a panel and parameters
// - Smart Browser: Can have a search panel, table panel and process panel
import { isEmptyValue, parsedValueComponent } from '@/utils/ADempiere/valueUtils.js'
import {
isEmptyValue,
parsedValueComponent,
typeValue
} from '@/utils/ADempiere/valueUtils.js'
import { convertObjectToKeyValue } from '@/utils/ADempiere/valueFormat.js'
import evaluator, { getContext, parseContext, specialColumns } from '@/utils/ADempiere/contextUtils.js'
import { showMessage } from '@/utils/ADempiere/notification.js'
@ -25,7 +29,7 @@ const panel = {
payload.panel = payload.newPanel
},
changeFieldLogic(state, payload) {
if (payload.isDisplayedFromLogic !== undefined && payload.isDisplayedFromLogic !== null) {
if (!isEmptyValue(payload.isDisplayedFromLogic)) {
payload.field.isDisplayedFromLogic = Boolean(payload.isDisplayedFromLogic)
}
payload.field.isMandatoryFromLogic = Boolean(payload.isMandatoryFromLogic)
@ -57,7 +61,12 @@ const panel = {
},
actions: {
addPanel({ commit, dispatch, getters }, params) {
const { panelType, uuid: containerUuid } = params
const {
panelType,
// isParentTab,
// parentUuid,
uuid: containerUuid
} = params
let keyColumn = ''
let selectionColumn = []
let identifierColumns = []
@ -86,13 +95,16 @@ const panel = {
}
}
// For all
if (['browser', 'process', 'report', 'form', 'table'].includes(panelType) || (panelType === 'window' && params.isParentTab)) {
dispatch('setContext', {
parentUuid: params.parentUuid,
containerUuid,
columnName: itemField.columnName,
value: itemField.value
})
if (['browser', 'process', 'report', 'form', 'table'].includes(panelType) ||
(panelType === 'window' && params.isParentTab)) {
// TODO: Verity with updateValueOfField, setContext, setPreferenceContext
// commit('updateValueOfField', {
// parentUuid,
// containerUuid,
// // isOverWriteParent: Boolean(isParentTab),
// columnName: itemField.columnName,
// value: itemField.value
// })
}
// Get dependent fields
if (!isEmptyValue(itemField.parentFieldsList) && itemField.isActive) {
@ -138,13 +150,17 @@ const panel = {
commit('addPanel', params)
if (!['form', 'table'].includes(panelType)) {
if (!['table'].includes(panelType)) {
dispatch('setDefaultValues', {
parentUuid: params.parentUuid,
containerUuid,
// isOverWriteParent: Boolean(isParentTab),
panelType
})
}
if (params.isCustomForm) {
dispatch('addForm', params)
}
return params
},
@ -317,6 +333,7 @@ const panel = {
parentUuid,
containerUuid,
panelType = 'window',
isOverWriteParent = true,
isNewRecord = false
}) {
return new Promise(resolve => {
@ -346,6 +363,8 @@ const panel = {
...oldRoute.query,
action: 'create-new'
}
}).catch(error => {
console.info(`Panel Store: ${error.message}`)
})
}
showMessage({
@ -381,6 +400,7 @@ const panel = {
dispatch('updateValuesOfContainer', {
parentUuid,
containerUuid,
isOverWriteParent,
attributes: defaultAttributes
})
// .then(() => {
@ -421,11 +441,16 @@ const panel = {
})
},
// Change all values of panel and dispatch actions for each field
notifyPanelChange({ commit }, {
notifyPanelChange({ commit, dispatch }, {
parentUuid,
containerUuid,
attributes = []
}) {
if (typeValue(attributes) === 'OBJECT') {
attributes = convertObjectToKeyValue({
object: attributes
})
}
// Update field
commit('updateValuesOfContainer', {
parentUuid,
@ -517,6 +542,10 @@ const panel = {
// }
// }
// })
dispatch('setIsloadContext', {
containerUuid
})
},
/**
* Handle all trigger for a field:
@ -539,6 +568,7 @@ const panel = {
field = fieldsList.find(fieldItem => fieldItem.columnName === columnName)
}
const value = getters.getValueOfField({
parentUuid: field.parentUuid,
containerUuid: field.containerUuid,
columnName: field.columnName
})
@ -596,6 +626,11 @@ const panel = {
})
})
},
/**
* Change dependent fields (default value, logics displayed, mandatory and read only)
* @param {object} field, definition and attributes
* TODO: Not working with fields generated on lookupFactory
*/
changeDependentFieldsList({ commit, dispatch, getters }, {
field
}) {
@ -669,7 +704,7 @@ const panel = {
columnName: fieldDependent.columnName,
value: newValue
})
//
// dispatch('notifyFieldChange', {
// parentUuid,
// containerUuid,
@ -841,6 +876,7 @@ const panel = {
// all optionals (not mandatory) fields
fieldsList.forEach(fieldItem => {
const value = getters.getValueOfField({
parentUuid: fieldItem.parentUuid,
containerUuid,
columnName: fieldItem.columnName
})
@ -1023,7 +1059,7 @@ const panel = {
}
}
if (String(valueToReturn) === '[object Object]') {
if (typeValue(valueToReturn) === 'OBJECT') {
if (!valueToReturn.isSQL) {
valueToReturn = valueToReturn.value
}
@ -1066,7 +1102,7 @@ const panel = {
isSQL: isSQLTo
})
}
// TODO: Check with typeValue function
if (typeof valueTo === 'object') {
valueTo = {
...valueTo,
@ -1074,7 +1110,7 @@ const panel = {
}
}
}
if (String(valueTo) === '[object Object]') {
if (typeValue(valueTo) === 'OBJECT') {
if (!valueTo.isSQL) {
valueTo = valueTo.value
}
@ -1251,12 +1287,14 @@ const panel = {
// from field value
const value = rootGetters.getValueOfField({
parentUuid: fieldItem.parentUuid,
containerUuid,
columnName
})
let valueTo
if (fieldItem.isRange && fieldItem.componentPath !== 'FieldNumber') {
valueTo = rootGetters.getValueOfField({
parentUuid: fieldItem.parentUuid,
containerUuid,
columnName: fieldItem.columnNameTo
})
@ -1281,6 +1319,7 @@ const panel = {
valueTo = row[parameterItem.columnNameTo]
} else {
value = rootGetters.getValueOfField({
parentUuid: parameterItem.parentUuid,
containerUuid,
columnName: columnName
})
@ -1315,6 +1354,7 @@ const panel = {
// manage as Array = [value, valueTo]
if (isRange && parameterItem.componentPath !== 'FieldNumber') {
valueTo = rootGetters.getValueOfField({
parentUuid: parameterItem.parentUuid,
containerUuid,
columnName: parameterItem.columnNameTo
})

View File

@ -1,6 +1,6 @@
import Vue from 'vue'
// Delete when get global context and account context
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
import { isEmptyValue, typeValue } from '@/utils/ADempiere/valueUtils.js'
const preference = {
state: {
@ -14,7 +14,7 @@ const preference = {
* @param {string} payload.columnName
* @param {mixed} payload.value
*/
setContext(state, payload) {
setPreferenceContext(state, payload) {
let key = ''
if (payload.parentUuid) {
key += payload.parentUuid + '|'
@ -51,8 +51,8 @@ const preference = {
}
},
actions: {
setContext({ commit }, objectValue) {
commit('setContext', objectValue)
setPreferenceContext({ commit }, objectValue) {
commit('setPreferenceContext', objectValue)
},
setMultiplePreference({ dispatch }, {
parentUuid,
@ -60,7 +60,7 @@ const preference = {
values
}) {
let actionToDispatch = 'setMultiplePreferenceObject'
if (Object.prototype.toString.call(values) === '[object Map]') {
if (typeValue(values) === 'MAP') {
actionToDispatch = 'setMultiplePreferenceMap'
}
return dispatch(actionToDispatch, {
@ -77,7 +77,7 @@ const preference = {
return new Promise(resolve => {
if (!isEmptyValue(containerUuid) || !isEmptyValue(parentUuid)) {
Object.keys(values).forEach(key => {
commit('setContext', {
commit('setPreferenceContext', {
parentUuid,
containerUuid,
columnName: key,
@ -99,7 +99,7 @@ const preference = {
return new Promise(resolve => {
if (!isEmptyValue(containerUuid) || !isEmptyValue(parentUuid)) {
values.forEach((value, key) => {
commit('setContext', {
commit('setPreferenceContext', {
parentUuid,
containerUuid,
columnName: key,

View File

@ -29,7 +29,13 @@ const initStateUtils = {
isLoaded: false
},
panelRight: '',
currentRecord: {}
currentRecord: {},
showOrder: false,
showTitleFrom: false,
showPanelRightPos: false,
showCollectionPos: false,
splitWidthRight: 3,
splitWidthLeft: 3
}
const utils = {
@ -101,6 +107,24 @@ const utils = {
},
setCurrentRecor(state, payload) {
state.currentRecord = payload
},
setShowOrder(state, showOrder) {
state.showOrder = showOrder
},
setShowTitleFrom(state, showTitleFrom) {
state.showTitleFrom = showTitleFrom
},
setShowPanelRightPos(state, showPanelRightPos) {
state.showPanelRightPos = showPanelRightPos
},
setShowCollectionPos(state, showCollectionPos) {
state.showCollectionPos = showCollectionPos
},
setSplitWidthRight(state, splitWidthRight) {
state.splitWidthRight = splitWidthRight
},
setSplitWidthLeft(state, splitWidthLeft) {
state.splitWidthLeft = splitWidthLeft
}
},
actions: {
@ -167,6 +191,24 @@ const utils = {
},
currentRecord({ commit }, record) {
commit('setCurrentRecor', record)
},
showOrder({ commit }, isOrder) {
commit('setShowOrder', isOrder)
},
showTitleFrom({ commit }, isTitleFrom) {
commit('setShowTitleFrom', isTitleFrom)
},
showPanelRightPos({ commit }, isPanelRight) {
commit('setShowPanelRightPos', isPanelRight)
},
showCollectionPos({ commit }, isCollection) {
commit('setShowCollectionPos', isCollection)
},
changeWidthRight({ commit }, newWidthRight) {
commit('setSplitWidthRight', newWidthRight)
},
changeWidthLeft({ commit }, newWidthLeft) {
commit('setSplitWidthLeft', newWidthLeft)
}
},
getters: {
@ -242,6 +284,24 @@ const utils = {
},
getCurrentRecord: (state) => {
return state.currentRecord
},
getShowPanelLeft: (state) => {
return state.showOrder
},
getShowTitleFrom: (state) => {
return state.showTitleFrom
},
getShowPanelRightPos: (state) => {
return state.showPanelRightPos
},
getShowCollectionPos: (state) => {
return state.showCollectionPos
},
getWidthRight: (state) => {
return state.splitWidthRight
},
getWidthLeft: (state) => {
return state.splitWidthLeft
}
}
}

View File

@ -5,7 +5,7 @@ import {
rollbackEntity
} from '@/api/ADempiere/persistence'
import { getReferencesList } from '@/api/ADempiere/values'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { isEmptyValue, typeValue } from '@/utils/ADempiere/valueUtils.js'
import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils'
import { parseContext } from '@/utils/ADempiere/contextUtils'
import { showMessage } from '@/utils/ADempiere/notification'
@ -72,8 +72,9 @@ const windowControl = {
value
}) {
// get value from store
if (!value) {
if (isEmptyValue(value)) {
value = getters.getValueOfField({
parentUuid: field.parentUuid,
containerUuid: field.containerUuid,
columnName: field.columnName
})
@ -157,6 +158,7 @@ const windowControl = {
}) {
// get value from store
const value = getters.getValueOfField({
parentUuid: field.parentUuid,
containerUuid: field.containerUuid,
columnName: field.columnName
})
@ -175,7 +177,7 @@ const windowControl = {
value: sqlStatement,
isSQL
}).value
if (isSQL && String(sqlStatement) === '[object Object]') {
if (isSQL && typeValue(sqlStatement) === 'OBJECT') {
sqlStatement = sqlStatement.query
}
}

View File

@ -66,6 +66,9 @@ const window = {
const tabsListChildren = []
const tabsSequence = []
// indexes related to visualization
let tabParentIndex = 0
let tabChildrenIndex = 0
// TODO Add source tab on the server for tabs Translation and Sort
const tabs = responseWindow.tabsList.filter(itemTab => {
if (itemTab.isSortTab) {
@ -103,7 +106,7 @@ const window = {
isAssociatedTabSequence: false, // show modal with order tab
isShowedRecordNavigation: !(tabItem.isSingleRow),
isLoadFieldsList: false,
index
index // this index is not related to the index in which the tabs are displayed
}
delete tab.processesList
@ -213,10 +216,14 @@ const window = {
})
if (tab.isParentTab) {
tab.tabParentIndex = tabParentIndex
tabParentIndex++
tabsListParent.push(tab)
return tab
}
if (!tab.isSortTab) {
tab.tabChildrenIndex = tabChildrenIndex
tabChildrenIndex++
tabsListChildren.push(tab)
}
return tab

View File

@ -14,9 +14,9 @@ const mutations = {
}
const actions = {
generateRoutes({ commit }) {
generateRoutes({ commit }, organizationId) {
return new Promise(resolve => {
loadMainMenu().then(menuResponse => {
loadMainMenu(organizationId).then(menuResponse => {
commit('SET_ROUTES', menuResponse)
resolve(menuResponse)
})

View File

@ -1,7 +1,7 @@
import variables from '@/styles/element-variables.scss'
import defaultSettings from '@/settings'
const { showSettings, tagsView, fixedHeader, sidebarLogo, supportPinyinSearch } = defaultSettings
const { showSettings, tagsView, fixedHeader, sidebarLogo, supportPinyinSearch, showContextMenu } = defaultSettings
const state = {
theme: variables.theme,
@ -9,7 +9,8 @@ const state = {
tagsView,
fixedHeader,
sidebarLogo,
supportPinyinSearch
supportPinyinSearch,
showContextMenu
}
const mutations = {

View File

@ -23,7 +23,7 @@ import router, { resetRouter } from '@/router'
import { showMessage } from '@/utils/ADempiere/notification'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { convertDateFormat } from '@/utils/ADempiere/valueFormat'
import language, { getLanguage } from '@/lang'
import language from '@/lang'
const state = {
token: getToken(),
@ -116,19 +116,22 @@ const actions = {
})
},
getCountryFormServer({ commit }, {
countryId,
countryUuid
id,
uuid
}) {
return new Promise(resolve => {
getCountryDefinition({
countryId,
countryUuid
id,
uuid
})
.then(responseCountry => {
commit('setCountry', responseCountry)
resolve(responseCountry)
})
.catch(error => {
console.warn(`Error getting Country Definition: ${error.message}. Code: ${error.code}.`)
})
})
},
// user login
@ -162,9 +165,8 @@ const actions = {
return new Promise((resolve, reject) => {
getSessionInfo(sessionUuid)
.then(responseGetInfo => {
.then(async responseGetInfo => {
const { role } = responseGetInfo
commit('setIsSession', true)
commit('setSessionInfo', {
id: responseGetInfo.id,
@ -196,10 +198,9 @@ const actions = {
commit('SET_ROLE', role)
setCurrentRole(role.uuid)
await dispatch('getOrganizationsList', role.uuid)
resolve(sessionResponse)
dispatch('getOrganizationsList', role.uuid)
const countryId = parseInt(
responseGetInfo.defaultContextMap.get('#C_Country_ID'),
10
@ -209,7 +210,7 @@ const actions = {
} else {
// get country and currency
dispatch('getCountryFormServer', {
countryId
id: countryId
})
}
@ -278,30 +279,30 @@ const actions = {
},
// user logout
logout({ commit, state, dispatch }) {
const token = state.token
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
commit('setIsSession', false)
dispatch('resetStateBusinessData', null, {
root: true
})
dispatch('dictionaryResetCache', null, {
root: true
})
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
dispatch('tagsView/delAllViews', null, { root: true })
removeToken()
removeCurrentRole()
resetRouter()
commit('setIsSession', false)
dispatch('resetStateBusinessData', null, {
root: true
})
dispatch('dictionaryResetCache', null, {
root: true
})
// reset visited views and cached views
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
dispatch('tagsView/delAllViews', null, { root: true })
// reset visited views and cached views
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
dispatch('tagsView/delAllViews', null, { root: true })
removeCurrentRole()
resetRouter()
logout(token).catch(error => {
console.warn(error)
}).finally(() => {
resolve()
}).catch(error => {
reject(error)
})
})
},
@ -318,11 +319,14 @@ const actions = {
if (isEmptyValue(roleUuid)) {
roleUuid = getCurrentRole()
}
return getOrganizationsList({ roleUuid })
.then(response => {
commit('SET_ORGANIZATIONS_LIST', response.organizationsList)
let organization = response.organizationsList.find(item => item.uuid === getCurrentOrganization())
let organization = response.organizationsList.find(item => {
if (item.uuid === getCurrentOrganization()) {
return item
}
})
if (isEmptyValue(organization)) {
organization = response.organizationsList[0]
}
@ -340,19 +344,57 @@ const actions = {
console.warn(`Error ${error.code} getting Organizations list: ${error.message}.`)
})
},
changeOrganization({ dispatch }, {
organizationUuid
changeOrganization({ commit, dispatch, getters }, {
organizationUuid,
organizationId,
isCloseAllViews = true
}) {
setCurrentOrganization(organizationUuid)
const organization = getters.getOrganizations.find(org => org.uuid === organizationUuid)
commit('SET_ORGANIZATION', organization)
dispatch('getWarehousesList', organizationUuid)
// TODO: Check if there are no tagViews in the new routes to close them, and
// if they exist, reload with the new route using name (uuid)
const route = router.app._route
const selectedTag = {
fullPath: route.fullPath,
hash: route.hash,
matched: route.matched,
meta: route.meta,
name: route.name,
params: route.params,
path: route.path,
query: route.query,
title: route.meta.title
}
let actionToDispatch = 'tagsView/delOthersViews'
if (isCloseAllViews) {
actionToDispatch = 'tagsView/delAllViews'
}
dispatch(actionToDispatch, selectedTag, { root: true })
resetRouter()
dispatch('permission/generateRoutes', organizationId, {
root: true
})
.then(response => {
router.addRoutes(response)
})
},
getWarehousesList({ commit }, organizationUuid) {
if (isEmptyValue(organizationUuid)) {
organizationUuid = getCurrentOrganization()
}
return getWarehousesList({ organizationUuid })
return getWarehousesList({
organizationUuid
})
.then(response => {
commit('SET_WAREHOUSES_LIST', response.warehousesList)
let warehouse = response.warehousesList.find(item => item.uuid === getCurrentWarehouse())
if (isEmptyValue(warehouse)) {
warehouse = response.warehousesList[0]
@ -409,6 +451,7 @@ const actions = {
})
.then(changeRoleResponse => {
const { role } = changeRoleResponse
commit('SET_ROLE', role)
setCurrentRole(role.uuid)
commit('SET_TOKEN', changeRoleResponse.uuid)
@ -466,14 +509,14 @@ const getters = {
}
return currency
},
getCountryLanguage(state) {
getCountryLanguage: (state) => {
return state.country.language.replace('_', '-')
},
getLanguagesList: (state) => {
return state.languagesList
},
getCurrentLanguageDefinition: (state) => {
return state.languagesList.find(definition => definition.languageISO === getLanguage())
return state.languagesList.find(definition => definition.language === state.country.language)
},
getRoles: (state) => {
return state.rolesList

View File

@ -57,6 +57,11 @@
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-menu {
border: none;
height: 100%;
@ -109,6 +114,10 @@
.svg-icon {
margin-left: 20px;
}
.sub-el-icon {
margin-left: 19px;
}
}
}
@ -122,6 +131,10 @@
margin-left: 20px;
}
.sub-el-icon {
margin-left: 19px;
}
.el-submenu__icon-arrow {
display: none;
}
@ -182,6 +195,10 @@
.svg-icon {
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
}
.nest-menu .el-submenu>.el-submenu__title,

Some files were not shown because too many files have changed in this diff Show More