+
+```
+
+Por ejemplo: [@/views/nested/menu1/index.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/views/nested/menu1/index.vue).
+
+**NOTA:** Agrega tantos `` como nivel de rutas anidadas.
+
+
+
+
+
+## Crear vista
+
+Después de agregar la ruta, crea una vista debajo de `@/views`. Como de costumbre, un enrutador corresponde a una vista.
+
+Sugerencia: si un componente o una función de utilidades solo se usa en esta vista, simplemente crea una carpeta de componentes en esta vista, es más conveniente para cada módulo mantener sus propios `utils` o `components`.
+
+
+
+
+
+## Crear API
+
+Finalmente, bajo la carpeta [@/api](https://github.com/adempiere/adempiere-vue/tree/master/src/api) crea el servicio api correspondiente para este módulo.
+
+## Crear componente
+
+Escribe personalmente hábitos de proyecto vue, el `@/components` global solo escribirá algunos componentes globales, como texto enriquecido, varios componentes de búsqueda, componentes de fecha empaquetada, etc., pueden ser componentes compartidos. Cada página o componente comercial específico del módulo se escribe bajo las vistas actuales. Por ejemplo: `@/views/article/components/xxx.vue`. Esta división reduce en gran medida los costos de mantenimiento.
+
+** ¡Recuerda que el mayor beneficio de dividir componentes no es el código compartido sino la mantenibilidad! **
+
+## Crear estilo
+
+El estilo y los componentes de la página son los mismos. `@/style` global escribe un estilo común global. El estilo de cada página está escrito bajo el `views` actual. Recuerda agregar `scoped` o espacio de nombres para evitar Causas de contaminación de estilo global.
+
+```css
+
+
+
+```
diff --git a/docs/es/guide/essentials/permission.md b/docs/es/guide/essentials/permission.md
new file mode 100755
index 00000000..b33ecfe7
--- /dev/null
+++ b/docs/es/guide/essentials/permission.md
@@ -0,0 +1,79 @@
+# Permisos
+
+Se ha introducido en detalle en este artículo--[手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac).
+
+La implementación de permisos de este proyecto es: comparar la tabla de enrutamiento obteniendo con el permiso del usuario actual, generar la tabla de enrutamiento accesible por el usuario, y montarla dinámicamente en `router` a través de `router.addRoutes`.
+
+Pero, en realidad, la lógica empresarial de muchas organizaciones puede no ser el caso. Por ejemplo, el requisito de muchas empresas es que los permisos de cada página se configuren dinámicamente, a diferencia de la configuración predeterminada en este proyecto. Pero, de hecho, el principio es el mismo. Por ejemplo, puedes configurar dinámicamente los permisos para cada página a través de un control de árbol u otra representación, y luego almacenar esta tabla de enrutamiento en el back-end. Cuando el usuario inicia sesión para obtener 'roles', el front-end solicita la tabla de enrutamiento accesible al back-end de acuerdo con 'roles', de modo que las páginas accesibles se generan dinámicamente. Después de eso, router.addRoutes se monta dinámicamente en el enrutador. Encontrarás lo mismo, nunca cambian su caso.
+
+Solo un paso más para mapear la tabla de enrutamiento de retorno del back-end con los componentes locales. [issue](https://github.com/adempiere/adempiere-vue/issues/293)
+
+```js
+const map={
+ login:require('login/index').default // síncrono
+ login:()=>import('login/index') // asíncrono
+}
+// El mapa en el que tienes un servidor es similar a
+const serviceMap=[
+ { path: '/login', component: 'login', hidden: true }
+]
+// Después de recorrer este mapa, genera dinámicamente asyncRoutes
+// y reemplaza el componente con map[component]
+```
+
+Ps: No descartes que este proyecto aumente el panel de control para admitir permisos de configuración dinámica real.
+
+## Modificación lógica
+
+El código de control del nivel de enrutamiento ahora está en `@/permission.js`. Si deseas cambiar la lógica, puedes utilizar el hook `next()` directamente en la lógica de juicio apropiada.
+
+## Directiva de permiso
+
+Escribe una directiva de permisos, y podrás implementar fácil y rápidamente el juicio de permisos a nivel de botón. [v-permission](https://github.com/adempiere/adempiere-vue/tree/master/src/directive/permission)
+
+**Uso**
+
+```html
+
+
+ admin
+
+
+ editor
+
+
+ Tanto admin como editor pueden ver esto
+
+
+
+```
+
+**Limitaciones**
+
+En algunos casos, no es adecuado usar v-permission, como en el componente de element 'Tab', que solo se puede lograr configurando manualmente v-if.
+
+Puedes usar la función de juicio de permiso global. El uso es similar a la instrucción `v-permission`.
+
+```html
+
+ Admin puede ver esto
+ Editor puede ver esto
+ Tanto admin como editor pueden ver esto
+
+
+
+```
diff --git a/docs/es/guide/essentials/router-and-nav.md b/docs/es/guide/essentials/router-and-nav.md
new file mode 100755
index 00000000..5f2126ce
--- /dev/null
+++ b/docs/es/guide/essentials/router-and-nav.md
@@ -0,0 +1,310 @@
+# Enrutador y Navegación
+
+El enrutador y la navegación son el esqueleto clave para organizar un sistema de gestión.
+
+El enrutador de este proyecto y la navegación están unidos, por lo que solo debes configurar la ruta en `@/router/index.js` y la navegación de la barra lateral se generará de manera dinámica automáticamente. Esto reduce en gran medida la carga de trabajo al no editar manualmente la barra lateral de navegación. Por supuesto, debes seguir muchos convenios al configurar la ruta.
+
+## Configuración
+
+En primer lugar, vamos a conocer la configuración que se le proporciona a una ruta.
+
+```js
+// si es true, no aparecerá en la barra lateral de navegación.
+// p.ej. inicio de sesión, página 401 o como algunas de edición /edit/1 (Predeterminado: false)
+hidden: true
+
+// No se puede hacer clic en esta ruta en breadcrumb cuando se establece noRedirect
+redirect: noRedirect
+
+// cuando agregas más de un hijo a un elemento ruta, automáticamente se
+// convierte en modo anidado, cuando solo hay un hijo se muestra como ruta
+// raíz de forma predeterminada, pero si deseas mostrarla en modo anidado,
+// aunque solo sea una puedes establecer:
+// alwaysShow: true
+// para que ignore las reglas definidas previamente y siempre se muestre
+// en modo anidado
+alwaysShow: true
+
+// establece el nombre del enrutador. Debe configurarse para evitar problemas con .
+name: 'router-name'
+
+meta: {
+ // roles requeridos para navegar a esta ruta. Admite múltiples permisos de apilamiento.
+ // si no se establece significa que no necesita ningún permiso.
+ roles: ['admin', 'editor']
+
+ // El título de la ruta para mostrar en varios componentes (por ejemplo, barra lateral, breadcrumbs).
+ title: 'title'
+
+ // clase de icono SVG
+ icon: 'svg-name' // or el-icon-x
+
+ // si es true, la ruta no será almacenada en caché por (Predeterminado: false)
+ noCache: true
+
+ // si es false, el elemento estará oculto en el breadcrumb (Predeterminado: true)
+ breadcrumb: false
+
+ // if set to true, it can be fixed in tags-view (default false)
+ affix: true // this is very useful in some scenarios, // click on the article to enter the article details page,
+
+ // When you set, the related item in the sidebar will be highlighted
+ // for example: a list page route of an article is: /article/list
+ // at this time the route is /article/1, but you want to highlight the route of the article list in the sidebar,
+ // you can set the following
+ activeMenu: '/article/list'
+}
+```
+
+
+
+**Ejemplo**
+
+```js
+{
+ path: '/permission',
+ component: Layout,
+ redirect: '/permission/index',
+ hidden: true,
+ alwaysShow: true,
+ meta: { roles: ['admin','editor'] }, // puedes establecer roles en la navegación raíz
+ children: [{
+ path: 'index',
+ component: _import('permission/index'),
+ name: 'permission',
+ meta: {
+ title: 'permission',
+ icon: 'lock',
+ roles: ['admin','editor'], // o puedes establecer roles solamente en la subnavegación
+ noCache: true
+ }
+ }]
+}
+```
+
+## Enrutador
+
+Hay dos tipos de rutas aquí, `constantRoutes` y `asyncRoutes`.
+
+**constantRoutes:** representa rutas que no requieren acceso dinámico, como la página de inicio de sesión, 404, página general, etc.
+
+**asyncRoutes:** representa las páginas que requieren permisos de juicio dinámico y se agregan dinámicamente a través de `addRouters`. Los detalles se introducirán en [Permisos](permission.md).
+
+::: tip
+Todas las páginas de enrutamiento aquí usan la `carga diferida del enrutador`, como se describe en el [documento](/guide/advanced/lazy-loading.md).
+
+Si deseas saber más sobre browserHistory y hashHistory, consulta [Compilar y Desplegar](deploy.md).
+:::
+
+Las otras configuraciones no son diferentes a las de [vue-router](https://router.vuejs.org/en/) oficial, así que consulta la documentación tú mismo.
+
+::: warning ADVERTENCIA
+Hay algo en lo que debes tener cuidado, la página 404 debe ser la última en cargarse, si se declara en constantRoutes. Las páginas declaradas posteriormente se bloquearán en 404, consulta los detalles del problema: [cuando addRoutes tiene una ruta comodín para 404 no funciona](https://github.com/vuejs/vue-router/issues/1176)
+:::
+
+## Barra lateral
+
+La barra lateral del proyecto se basa principalmente en `el-menu` de element-ui.
+
+Se introdujo en el front, la barra lateral se genera dinámicamente al leer la ruta y se combina con el juez de permisos, pero también debe soportar la anidación infinita de rutas, por lo que aquí también se usa para los componentes recursivos.
+
+> Código: [@/layout/components/Sidebar](https://github.com/adempiere/adempiere-vue/tree/master/src/layout/components/Sidebar)
+
+Es posible modificar el estilo predeterminado de la barra lateral de `element-ui`. Todo el CSS lo puedes encontrar en [@/styles/sidebar.scss](https://github.com/adempiere/adempiere-vue/blob/master/src/styles/sidebar.scss) y modificarlo para satisfacer tus necesidades.
+
+**Aquí hay que prestar atención**. La barra lateral general tiene dos formas, `submenu` y `el-menu-item`. Uno es un submenú anidado, el otro es un enlace directo. Como se muestra abajo:
+
+
+
+La barra lateral ya te ha ayudado a hacer un juicio. Cuando agregas más de un hijo a un elemento, automáticamente se convierte en modo anidado. Si la ruta hijo es exactamente igual a 1, esta se muestra como ruta raíz en la barra lateral de forma predeterminada. Si no quieres que esto suceda, puedes desactivar esta función configurando `alwaysShow: true` en la ruta raíz. Como:
+
+```js
+// sin submenu, porque children.length === 1
+{
+ path: '/icon',
+ component: Layout,
+ children: [{
+ path: 'index',
+ component: ()=>import('svg-icons/index'),
+ name: 'icons',
+ meta: { title: 'icons', icon: 'icon'}
+ }]
+},
+
+// con submenu, porque children.length >= 1
+{
+ path: '/components',
+ component: Layout,
+ name: 'component-demo',
+ meta: {
+ title: 'components',
+ icon: 'component'
+ },
+ children: [
+ { path: 'tinymce', component: ()=>import('components-demo/tinymce'), name: 'tinymce-demo', meta: { title: 'tinymce' }},
+ { path: 'markdown', component: ()=>import('components-demo/markdown'), name: 'markdown-demo', meta: { title: 'markdown' }},
+ ]
+}
+```
+
+::: tip unique-opened
+Puedes configurar `unique-opened` en [Sidebar/index.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/Sidebar/index.vue). Para controlar la barra lateral, si deseas mantener solo un submenú expandido.
+:::
+
+## Rutas anidadas
+
+Si tienes una ruta anidada, como [@/views/nested](https://github.com/adempiere/adempiere-vue/tree/master/src/views/nested),
+**No olvides agregar manualmente `` al archivo raíz del directorio secundario**.
+
+```html
+
+
+
+
+
+
+
+```
+
+Tal como: [@/views/nested/menu1/index.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/views/nested/menu1/index.vue).
+
+**NOTA:** Tantos `` como nivel de rutas anidadas.
+
+
+
+
+
+## Clic en la barra lateral para actualizar la ruta actual
+
+Antes de utilizar el modelo de desarrollo spa (aplicación de página única), cada vez que el usuario hace clic en la barra lateral solicitará nuevamente esta página, el usuario gradualmente desarrolló el hábito de hacer clic en la ruta actual en la barra lateral para actualizar la vista. Pero ahora en el spa no es lo mismo, el usuario hace clic en la ruta resaltada actualmente y no actualiza la vista, porque el vue-router interceptará tu ruta, determina que la url no cambia, por lo que no activará ningún hook o cambios en la vista. [Problema relacionado](https://github.com/vuejs/vue-router/issues/296), la comunidad también ha discutido sobre el tema.
+
+
+
+`yyx990803` también dijo que quería agregar una forma de actualizar la vista, y luego cambió de opinión nuevamente /(ㄒ o ㄒ)/~~ Pero la cuestión es la siguiente, ¿qué debemos hacer? Dijo que no activaría nada sin cambiar la URL actual, así que ¿puedo forzar al activador? El truco es simple. Al cambiar la consulta de la URL para activar los cambios de vista: escuchamos el evento clic de cada enlace en la barra lateral, cada clic realizará una consulta diferente en el enrutador para garantizar que la vista se actualice.
+
+```js
+clickLink(path) {
+ this.$router.push({
+ path,
+ query: {
+ //Asegúrate de que, en cada clic, query no sea el mismo
+ //para garantizar que se actualice la vista
+ t: +new Date()
+ }
+ })
+}
+```
+
+ps: No olvides agregar una `key` única a `router-view`, como ``.
+
+También hay un inconveniente con el feo sufijo `query` al final de la URL, como `xxx.com/article/list?t=1496832345025`
+
+Puedes saber del problema anterior que hay muchas otras opciones. En el proyecto de mi empresa, la solución adoptada es determinar si la ruta del menú en la que se hace clic actualmente es coherente con la ruta actual. Sin embargo, cuando sea coherente, saltará a una página de redireccionamiento dedicada, que a su vez Redirigirá la ruta para Ir a la página, esto tendrá un efecto de actualización.
+
+**Ejemplo**
+
+
+
+Haz clic en el botón de cambio de tamaño global que se muestra en la imagen y verás que la página `app-main` se ha actualizado. Se utiliza el método de redireccionamiento a la página `Redirect` y luego redirecciona de nuevo a la página original.
+
+Redireccionar la página a `/redirect` al hacer clic
+
+```js
+const { fullPath } = this.$route
+this.$router.replace({
+ path: '/redirect' + fullPath
+})
+```
+
+La página `redirect` se redirige de nuevo a la página original
+
+```js
+// redirect.vue
+// https://github.com/adempiere/adempiere-vue/blob/master/src/views/redirect/index.vue
+export default {
+ beforeCreate() {
+ const { params, query } = this.$route
+ const { path } = params
+ this.$router.replace({ path: '/' + path, query })
+ },
+ render: function(h) {
+ return h() // evitar mensaje de advertencia
+ }
+}
+```
+
+
+
+## Breadcrumb
+
+Este proyecto también incluye una navegación con breadcrumb, que también se genera dinámicamente por el cambio de ruta al observar $route. Es lo mismo con el menú, también puedes configurarlo en el enrutamiento y agregar algunos atributos personalizados a las necesidades de tu negocio en route.meta attr. Por ejemplo, puedes declarar `breadcrumb:false` en la ruta para que no se muestre en la sección breadcrumb.
+
+
+
+> Código correspondiente: [@/components/Breadcrumb](https://github.com/adempiere/adempiere-vue/blob/master/src/components/Breadcrumb/index.vue)
+
+## Problema de desplazamiento de la barra lateral
+
+Las versiones anteriores de scroll se manejaban con css
+
+```css
+overflow-y: scroll;
+
+::-webkit-scrollbar {
+ display: none;
+}
+```
+
+Pero usar algún hack de CSS tiene algunos problemas, en Firefox u otras versiones inferiores del navegador serán menos hermosas.
+En segundo lugar, en el caso de colapsos de la barra lateral, limitados al `menu` de `element-ui`, no se pueden manejar de esta manera.
+
+Entonces, la versión actual usa `el-scrollbar` para encargarse del problema de desplazamiento de la barra lateral.
+
+::: tip Código
+[@/layout/components/Sidebar](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/Sidebar/index.vue)
+:::
+
+## Enlace externo en la barra lateral
+
+También puedes configurar un enlace externo en la barra lateral. Siempre y cuando coloques una dirección URL correcta en `path`, podrás abrir esta página cuando hagas clic en la barra lateral.
+
+P.ej.
+
+```json
+{
+ "path": "external-link",
+ "component": Layout,
+ "children": [
+ {
+ "path": "https://github.com/adempiere/adempiere-vue",
+ "meta": { "title": "externalLink", "icon": "link" }
+ }
+ ]
+}
+```
+
+## Sidebar expands by default
+
+In some scenarios, users need to expand some of the `sub-menu` in the sidebar by default, as shown below:
+
+
+
+Can be set through `default-openeds`, first find [Sidebar Code](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/Sidebar/index.vue)
+
+```html
+
+
+
+```
+
+**Note: default-openeds = "['example', 'nested']" is filled with route-path of submenu**
diff --git a/docs/es/guide/essentials/server.md b/docs/es/guide/essentials/server.md
new file mode 100755
index 00000000..cce2af7f
--- /dev/null
+++ b/docs/es/guide/essentials/server.md
@@ -0,0 +1,101 @@
+# Trabajar con el Servidor
+
+## Flujo de solicitudes de front-end
+
+En `adempiere-vue`, una interfaz de usuario completa interactúa con el flujo de procesamiento del lado del servidor de la siguiente manera:
+
+1. Interacción de componentes UI;
+2. Llamar a la función de solicitud de servicio API de gestión unificada;
+3. Enviar solicitudes utilizando request.js;
+4. Obtener respuesta del servidor;
+5. Actualizar datos;
+
+Como puedes ver en el flujo anterior, para facilitar la administración y el mantenimiento, el procesamiento de solicitudes unificadas se coloca en la carpeta `src/api` y los archivos generalmente se dividen de acuerdo con la latitud del modelo, como:
+
+```
+api/
+ login.js
+ article.js
+ remoteSearch.js
+ ...
+```
+
+## request.js
+
+`@/utils/request.js` se basa en [axios](https://github.com/axios/axios), para facilitar el manejo uniforme de POST, GET y otros parámetros de solicitud, encabezados de solicitud y mensajes de error. Para ver mas específico vea [request.js](https://github.com/adempiere/adempiere-vue/blob/master/src/utils/request.js).
+
+Encapsula el 'interceptor de solicitud' global, el 'interceptor de respuesta', el 'manejo unificado de errores', el 'tiempo de espera unificado, la configuración de baseURL, etc.'
+
+## Un ejemplo de solicitud de una lista de artículos:
+
+```js
+// api/article.js
+import request from '../utils/request';
+export function fetchList(query) {
+ return request({
+ url: '/article/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// views/example/list
+import { fetchList } from '@/api/article'
+export default {
+ data() {
+ list: null,
+ listLoading: true
+ },
+ methods: {
+ fetchData() {
+ this.listLoading = true
+ fetchList().then(response => {
+ this.list = response.data.items
+ this.listLoading = false
+ })
+ }
+ }
+}
+```
+
+## Establecer múltiples baseURLs
+
+Podemos solicitar múltiples direcciones api configurando múltiples `baseURL`s a través de [variables de entorno](/guide/essentials/deploy.html).
+
+```bash
+# .env.development
+VUE_APP_BASE_API = '/dev-api' #Inyecta la ruta raíz de la api
+VUE_APP_BASE_API2 = '/dev-api2' #Inyecta la ruta raíz de la api
+```
+
+Luego crea una instancia `axios` basada en la variable de entorno, dándole una `baseURL` [@/utils/request.js](https://github.com/adempiere/adempiere-vue/blob/master/src/utils/request.js) diferente.
+
+```js
+// crear una instancia de axios
+const service = axios.create({
+ baseURL: process.env.BASE_API, // api base_url
+ timeout: 5000 // tiempo de espera agotado
+})
+
+const service2 = axios.create({
+ baseURL: process.env.BASE_API2, // api base_url
+ timeout: 5000 // tiempo de espera agotado
+})
+```
+
+O
+
+```js
+export function fetchList(query) {
+ return request({
+ url: '/article/list',
+ method: 'get',
+ params: query,
+ baseURL: 'xxxx' // cobertura directa
+ })
+}
+```
+
+## Cambiar de Mock directamente a la solicitud del servidor
+
+Ver [Mock Data](mock-api.md)
diff --git a/docs/es/guide/essentials/style.md b/docs/es/guide/essentials/style.md
new file mode 100755
index 00000000..aee8d9a1
--- /dev/null
+++ b/docs/es/guide/essentials/style.md
@@ -0,0 +1,146 @@
+# Estilo
+
+## Módulos CSS
+
+En el proceso de desarrollo del estilo, hay dos cuestiones más destacadas:
+
+- Contaminación global —— El selector en el archivo CSS es global. Si el mismo nombre del selector esta en diferentes archivos, de acuerdo con el orden en el archivo de generación de compilación, los estilos generados más adelante sobrescribirán los anteriores.
+
+- Selector complejo —— Para evitar los problemas anteriores, debemos tener cuidado al escribir estilos, el nombre de la clase estará marcado con una serie de restricciones, el desarrollo entre varias personas también es muy fácil de conducir al caos con los nombres de los estilos. Los nombres de las clases son cada vez más largos. Eventualmente, es difícil de mantener.
+
+Afortunadamente, vue nos proporciona [scoped](https://vue-loader.vuejs.org/guide/scoped-css.html#mixing-local-and-global-styles) el cual puede resolver fácilmente el problema anterior. Como su nombre indica, agrega un concepto de alcance (scoped) al css.
+
+```css
+/* Antes de compilar */
+.example {
+ color: red;
+}
+
+/* Despues de compilar */
+.example[_v-f3f3eg9] {
+ color: red;
+}
+```
+
+Si agregas `
+
+
+```
+
+## Estilo de element-ui personalizado
+
+Ahora hablemos sobre cómo sobrescribir el estilo de element-ui. Debido a que el estilo de element-ui esta importado de manera global, no puedes agregar `scoped` a una página para sobrescribirlo, en caso de que quieras sobrescribir el estilo de element solamente en esa página, puedes agregar una clase en su padre, utilizando espacio de nombres para resolver este problema.
+
+```css
+.article-page {
+ /* tu espacio de nombres */
+ .el-tag {
+ /* etiqueta del elemento de element-ui */
+ margin-right: 0px;
+ }
+}
+```
+
+**Por supuesto, también puedes usar los selectores profundos como se describe a continuación.**
+
+## Selectores profundos
+
+**El componente principal cambia el estilo del componente secundario.**
+
+Si quieres que un selector en estilos con scoped sea "profundo", es decir, que afecte a los componentes secundarios, puedes usar el combinador `>>>`:
+
+```css
+
+```
+
+Se compilará como:
+
+```css
+.a[data-v-f3f3eg9] .b {
+ /* ... */
+}
+```
+
+Es posible que algunos preprocesadores, como SASS, no puedan analizar `>>>` correctamente. En esos casos, puedes usar el combinador /deep/ en su lugar, es un alias para `>>>` y funciona exactamente igual.
+
+```css
+.xxx-container >>> .el-button{
+ xxxx
+}
+```
+
+[Documentación oficial](https://vue-loader.vuejs.org/en/features/scoped-css.html)
+
+## Postcss
+
+Hablemos de la configuración de postcss. Después de la nueva versión de la inicialización [plantilla vue-cli de webpack](https://github.com/vuejs-templates/webpack), hay un `postcss.config.js` predeterminado en el directorio raíz. Por defecto, `vue-loader` leerá la configuración de postcss, así que aquí puede cambiar la configuración directamente. La configuración es la misma que [postcss](https://github.com/postcss/postcss).
+
+```javascript
+// postcss.config.js
+module.exports = {
+ plugins: {
+ autoprefixer: {}
+ }
+}
+
+// package.json
+"browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not ie <= 8"
+ ]
+```
+
+Como se describe en el código anterior, el corrector automático lee los parámetros de configuración de browserslist en package.json.
+
+- `> 1%` Compatible con navegadores con uso global superior al 1%
+- `last 2 versions` Compatible con las dos últimas versiones de cada navegador
+- `not ie <= 8` No compatible con ie8 e inferiores
+
+Más detalles [browserslist](https://github.com/ai/browserslist)
+
+`postcss` tiene muchas otras características [para explorar por tu cuenta](https://www.postcss.parts/)
+
+## Mixin
+
+Este proyecto no está configurado para inyectar automáticamente sass mixin en el estilo global, por lo que debes insertarlo manualmente.
+
+```scss
+
+```
+
+Si necesitas inyectar automáticamente mixin global, puedes usar [sass-resources-loader](https://github.com/shakacode/sass-resources-loader).
diff --git a/docs/es/guide/essentials/tags-view.md b/docs/es/guide/essentials/tags-view.md
new file mode 100755
index 00000000..e63f0172
--- /dev/null
+++ b/docs/es/guide/essentials/tags-view.md
@@ -0,0 +1,111 @@
+# Etiquetas View
+
+Esta característica es para responder a las necesidades de las personas. De hecho, no utilizo esta característica en proyectos de la empresa o proyectos personales. En el pasado, esos frameworks tradicionales de back-end a menudo incluían esta característica. Dado que la mayoría de los proyectos de back-end anteriores tenían varias páginas, la característica de navegación Etiquetas View todavía tiene un significado básico. La mayoría de ellos se basan en el iframe.
+
+Sin embargo, con el paso del tiempo, los proyectos en back-end son casi todos spa (desarrollo de una aplicación web de una sola página), y obviamente no es apropiado usar la forma anterior para implementar la navegación con etiquetas.
+
+Entonces el plan actual es:
+
+Usar una combinación de `keep-alive` y `router-view`.
+
+Código: `@/layout/components/AppMain.vue`
+
+```html
+
+
+
+```
+
+La acción real de las etiquetas de navegación view es equivalente a otro modo de visualización de navegación. De hecho, es un router-link, y al hacer clic salta a la página correspondiente. Luego estamos escuchando los cambios en la ruta `$route` para determinar si la página actual necesita ser recargada o almacenada en caché.
+
+## visitedViews && cachedViews
+
+La etiqueta view actual mantiene dos matrices.
+
+- visitedViews : La página que el usuario ha visitado es una colección de matrices de etiquetas que se muestran en la barra de navegación de etiquetas.
+- cachedViews : La ruta actual keep-alive. Puedes establecer si deseas o no almacenar en caché la ruta, configurandola con `meta.noCache`. [Documento de configuración](router-and-nav.md)
+
+## Precauciones
+
+Debido a que keep-alive y router-view están fuertemente acoplados, y no es difícil encontrar que keep-alive incluye el nombre predeterminado del componente, es necesario mirar el documento y el código fuente al escribir el componente de enrutamiento correspondiente al enrutador y la ruta de enrutamiento.
+
+Asegúrate de que el nombre de ambos sea exactamente el mismo. (Ten en cuenta que el nombre debe ser tan único como sea posible. Recuerda no duplicar el nombre de algunos componentes o hacer referencia al último problema de desbordamiento de memoria de forma recursiva).
+
+**DEMO:**
+
+```js
+//Definir rutas
+{
+ path: 'create-form',
+ component: ()=>import('@/views/form/create'),
+ name: 'createForm',
+ meta: { title: 'createForm', icon: 'table' }
+}
+```
+
+```js
+//La vista correspondiente de la ruta. tales como: form/create
+export default {
+ name: 'createForm'
+}
+```
+
+Asegúrate de que los dos nombres sean iguales. Recuerda no escribir duplicados o errores. De forma predeterminada, si no escribes el nombre, no se almacenará en caché.
+
+Para más detalles, ver [issue](https://github.com/vuejs/vue/issues/6938#issuecomment-345728620).
+
+## Cuando la caché no es adecuada para la situación
+
+Las soluciones actualmente en caché no son adecuadas para ciertos servicios, como la página de detalles del artículo, por ejemplo `/article/1`, `/article/2`, sus rutas son diferentes pero los componentes correspondientes son los mismos, por lo que el nombre de su componente es igual, como se mencionó anteriormente, con la inclusión de `keep-alive` solo se puede almacenar en caché basándose en el nombre del componente, por lo que esto es un problema. Actualmente hay dos soluciones:
+
+- En lugar de utilizar la inclusión de keep-alive, este almacenará directamente todos los componentes en caché. De esta manera, se ayudara a la situación antes mencionada.
+ En [@/layout/components/AppMain.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/AppMain.vue) elimina el código relacionado con `include`. Por supuesto, usar keep-alive directamente también tiene desventajas. No puedes eliminar dinámicamente la caché. Solo puedes ayudar estableciendo un límite máximo de instancia de caché.
+ [issue](https://github.com/vuejs/vue/issues/6509)
+
+- Utiliza un esquema de caché del navegador como localStorage, para controlar la caché.
+
+## Affix
+
+Si el atributo Affix se agrega a la ruta, `tag` quedará fija en `tags-view` (no se podrá quitar).
+
+
+
+```js {14}
+ {
+ path: '',
+ component: Layout,
+ redirect: 'dashboard',
+ children: [
+ {
+ path: 'dashboard',
+ component: () => import('@/views/dashboard/index'),
+ name: 'Dashboard',
+ meta: {
+ title: 'dashboard',
+ icon: 'dashboard',
+ noCache: true,
+ affix: true
+ }
+ }
+ ]
+ }
+```
+
+## Eliminar
+
+De hecho, el [código fuente](<(https://github.com/vuejs/vue/blob/dev/src/core/components/keep-alive.js)>) de keep-alive no es complicado, y la lógica sigue siendo bastante clara. Antes de que el autor de `vue` corrigiera un error, no tuvo cuidado e hizo dos versiones para solucionarlo, por lo que si no hay ningún usuario que necesite la barra de navegación, se recomienda Eliminar esta función.
+
+Primero encuentra
+`@/layout/components/AppMain.vue` y elimina `keep-alive`
+
+```html
+
+
+
+
+
+
+
+```
+
+Elimina el archivo `@/layout/components/TagsView.vue`. Luego, elimina la referencia a `TagsView` en los archivos `@/layout/components/index` y `@/layout/Layout.vue`. Finalmente, elimina el archivo `@/store/modules/tagsView`.
diff --git a/docs/es/guide/other/gitter.md b/docs/es/guide/other/gitter.md
new file mode 100644
index 00000000..b9ebbe38
--- /dev/null
+++ b/docs/es/guide/other/gitter.md
@@ -0,0 +1,11 @@
+# Gitter
+
+[Gitter](https://gitter.im/adempiere-vue/discuss)
+
+
diff --git a/docs/es/guide/other/release-notes.md b/docs/es/guide/other/release-notes.md
new file mode 100644
index 00000000..0cd84a7c
--- /dev/null
+++ b/docs/es/guide/other/release-notes.md
@@ -0,0 +1,11 @@
+# Notas de la versión
+
+[Notas de la versión](https://github.com/adempiere/adempiere-vue/releases)
+
+
diff --git a/docs/feature/component/clipboard.md b/docs/feature/component/clipboard.md
new file mode 100644
index 00000000..e9f055eb
--- /dev/null
+++ b/docs/feature/component/clipboard.md
@@ -0,0 +1,65 @@
+---
+sidebarDepth: 3
+---
+
+# Clipboard
+
+Here's the copy and paste based on [clipboard](https://github.com/zenorocha/clipboard.js)
+
+This project provides two ways to use.
+
+## Use directly
+
+```html
+copy
+```
+
+```js
+import clip from '@/utils/clipboard.js' // use clipboard directly
+
+methods: {
+ handleCopy(text, event) {
+ clip(text, event)
+ }
+}
+```
+
+First of all, import `clipboard.js` and set `click` function.
+
+`clip()` The first parameter is the contents of the copy, the second parameter is the event event. Both parameters are required.
+
+
+
+
+## v-directive
+
+This project also encapsulates a `v-clipboard`.
+
+```html
+
+ copy
+
+```
+
+```js
+import clipboard from '@/directive/clipboard/index.js' // use clipboard by v-directive
+
+directives: {
+ clipboard
+},
+methods: {
+ clipboardSuccess() {
+ this.$message({
+ message: 'Copy successfully',
+ type: 'success',
+ duration: 1500
+ })
+ }
+}
+```
+
+`v-clipboard:copy`: the copy of the content.
+
+`v-clipboard:success`: success callback function.
diff --git a/docs/feature/component/excel.md b/docs/feature/component/excel.md
new file mode 100644
index 00000000..cac17133
--- /dev/null
+++ b/docs/feature/component/excel.md
@@ -0,0 +1,104 @@
+# Excel
+
+## Excel Export
+
+Import and export of Excel is implemented by relying on [js-xlsx](https://github.com/SheetJS/js-xlsx).
+
+[Export2Excel.js](https://github.com/adempiere/adempiere-vue/blob/master/src/vendor/Export2Excel.js) is packaged on the on `js-xlsx` to facilitate exporting data.
+
+### Use
+
+Since `Export2Excel` depends not only on `js-xlsx` but also on `file-saver` and `script-loader`.
+
+So you first need to install the following command:
+
+```bash
+npm install xlsx file-saver -S
+npm install script-loader -S -D
+```
+
+Since `js-xlsx` size is still very large, the export function is not a very common function, so lazy loading is recommended when using it. The method of use is as follows:
+
+```js
+import('@/vendor/Export2Excel').then(excel => {
+ excel.export_json_to_excel({
+ header: tHeader, //Header Required
+ data, //Specific data Required
+ filename: 'excel-list', //Optional
+ autoWidth: true, //Optional
+ bookType: 'xlsx' //Optional
+ })
+})
+```
+
+:::warning Warning
+The compatibility code for Blob has been removed in the later versions of `v3.9.1+`. If you need to be compatible with very low-level browsers, you can manually introduce [blob-polyfill](https://www.npmjs.com/package/blob-polyfill) .
+:::
+
+### Params
+
+| Params | Description | Type | Accepted Values | Default |
+| --------- | --------------------------- | ------- | ----------------------------------------------------------------------------------- | ---------- |
+| header | Export header of data | Array | / | [] |
+| data | Exported specific data | Array | / | [] |
+| filename | Export file name | String | / | excel-list |
+| autoWidth | Whether the cell auto width | Boolean | true / false | true |
+| bookType | Export file type | String | xlsx, csv, txt, [more](https://github.com/SheetJS/js-xlsx#supported-output-formats) | xlsx |
+
+### Example
+
+```js
+import('@/vendor/Export2Excel').then(excel => {
+ const tHeader = ['Id', 'Title', 'Author', 'Readings', 'Date']
+ const data = this.list
+ excel.export_json_to_excel({
+ header: tHeader, //Header Required
+ data, //Specific data Required
+ filename: 'excel-list', //Optional
+ autoWidth: true, //Optional
+ bookType: 'xlsx' //Optional
+ })
+})
+```
+
+- [Online Demo](https://adempiere.github.io/adempiere-vue/#/excel/export-excel)
+- [Online Code](https://github.com/adempiere/adempiere-vue/blob/master/src/views/excel/export-excel.vue)
+
+## Excel Import
+
+Encapsulated [UploadExcel](https://github.com/adempiere/adempiere-vue/blob/master/src/components/UploadExcel/index.vue) Excel import component, support click and drag upload, also it is also Depends on `js-xlsx`.
+
+It provides two callback functions:
+
+- beforeUpload
+
+ You can make some special judgments before uploading. For example, if the size of the file is greater than 1 megabyte? If it is greater than 1 megabyte, it stops parsing and prompts an error message.
+
+```js
+ beforeUpload(file) {
+ const isLt1M = file.size / 1024 / 1024 < 1
+
+ if (isLt1M) {
+ return true
+ }
+
+ this.$message({
+ message: 'Please do not upload files larger than 1m in size.',
+ type: 'warning'
+ })
+ return false
+ }
+```
+
+- onSuccess
+ A callback function that fires when parsing succeeds, which returns the header and content of the table.
+
+```js
+ handleSuccess({ results, header }) {
+ this.tableData = results
+ this.tableHeader = header
+ }
+```
+
+- [Online Demo](https://adempiere.github.io/adempiere-vue/#/excel/upload-excel)
+- [Online Code](https://github.com/adempiere/adempiere-vue/blob/master/src/views/excel/upload-excel.vue)
diff --git a/docs/feature/component/markdown-editor.md b/docs/feature/component/markdown-editor.md
new file mode 100644
index 00000000..01a253d4
--- /dev/null
+++ b/docs/feature/component/markdown-editor.md
@@ -0,0 +1,77 @@
+# Markdown Editor
+
+Originally used [simplemde-markdown-editor](https://github.com/sparksuite/simplemde-markdown-editor) as the markdown editor, but this library has not been updated and maintained for a long time, and there is also the risk of xss. So after the version, use [tui.editor](https://github.com/nhnent/tui.editor) as the new editor. All the next documents are Based on tui.editor it. [More Content](https://github.com/nhnent/tui.editor).
+
+## Props
+
+| Name | Type | Default | Description |
+| -------- | ------ | -------------------------- | ------------------------------------------------------------------------------------- |
+| value | String | " " | This prop can change content of the editor. **If you using `v-model`, don't use it**. |
+| options | Object | following `defaultOptions` | Options of tui.editor. This is for initailize tui.editor. |
+| height | String | '300px' | This prop can control the height of the editor. |
+| mode | String | 'markdown' | This prop can change mode of the editor. (`markdown`or `wysiwyg`) |
+| language | String | 'en_US' | i18n |
+
+```js
+const defaultOptions = {
+ minHeight: '200px',
+ previewStyle: 'vertical',
+ useCommandShortcut: true,
+ useDefaultHTMLSanitizer: true,
+ usageStatistics: false,
+ hideModeSwitch: false,
+ toolbarItems: [
+ 'heading',
+ 'bold',
+ 'italic',
+ 'strike',
+ 'divider',
+ 'hr',
+ 'quote',
+ 'divider',
+ 'ul',
+ 'ol',
+ 'task',
+ 'indent',
+ 'outdent',
+ 'divider',
+ 'table',
+ 'image',
+ 'link',
+ 'divider',
+ 'code',
+ 'codeblock'
+ ]
+}
+```
+
+## Methods
+
+- setValue
+- getValue
+- setHtml
+- getHtml
+
+## Example
+
+```html
+
+
+
+
+```
+
+## Online Example
+
+[link](https://adempiere.github.io/adempiere-vue/#/components/markdown)
diff --git a/docs/feature/component/pagination.md b/docs/feature/component/pagination.md
new file mode 100644
index 00000000..4adceb73
--- /dev/null
+++ b/docs/feature/component/pagination.md
@@ -0,0 +1,62 @@
+# Pagination
+
+Pagination component is mainly based on Element 'el-pagination' for the secondary packaging, and expanded the function of auto-scroll.
+
+## Basic Usage
+
+```html
+
+
+
+
+
+```
+
+## Attributes
+
+| Attribute | Description | Type | Default |
+| :---------: | :---------------------------------------------------------- | :-------: | :-------------: |
+| total | total item count | Number | / |
+| page | current page number, supports the .sync modifier | Number | 1 |
+| limit | item count of each page, supports the .sync modifier | Number | 20 |
+| page-sizes | options of item count per page | Number [] | 10, 20, 30, 50] |
+| hidden | whether to hide | Boolean | false |
+| auto-scroll | whether to automatically scroll to the top after pagination | Boolean | true |
+
+Other attributes of the element's `el-pagination` support are also supported. See [Documentation](http://element.eleme.io/#/zh-CN/component/pagination) for details.
+
+## Events
+
+| Event Name | Description | Parameters |
+| ---------- | ---------------------------------------- | ------------ |
+| pagination | Triggered when the limit or page changes | {page,limit} |
+
+## Source Code && Demo
+
+- [Source Code](https://github.com/adempiere/adempiere-vue/blob/master/src/components/Pagination/index.vue)
+
+- [Online Demo](https://adempiere.github.io/adempiere-vue/#/table/complex-table)
diff --git a/docs/feature/component/rich-editor.md b/docs/feature/component/rich-editor.md
new file mode 100644
index 00000000..cba904ef
--- /dev/null
+++ b/docs/feature/component/rich-editor.md
@@ -0,0 +1,65 @@
+# Rich text editor
+
+Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose [Tinymce](https://github.com/tinymce/tinymce).
+
+Here is a brief introduction to the reasons why `tinymce` is recommended: `tinymce` is a veteran to do rich text company(Here also recommended `ckeditor`, is also a company that has been doing rich text, the new version is very good), its products have stood the test of the market, and it has detailed documentation and rich configuration. One of the keys to using rich text is to copy formatting. Before using a Korean text rich `summernote`, It wasted me a lot of time, very unfriendly. But `tinymce`'s formatting is pretty good. It also has a value-added feature is powerpaste, it is extremely powerful, support for copying everything from word or any other place. Extensibility is also critical for rich text. I use `tinymce` to write several plug-ins, learning costs and ease of study are good, and very easy to expand. The last point is that the documentation is very good, basically you want to get the configuration item, it has. Tinymce also supports on-demand loading, you can customize plugins through its official build page.
+
+Let me analyze some of the other rich texts on the market:
+
+- **[summernote](https://github.com/summernote/summernote)** Let me start with a rich text that I definitely would not recommend.It is inconsistent with many recognized default behaviors between others. And only for the use of a dialog feature, they import the bootstrap, A bunch of people protest. Formatting is also very bad. Do not use anyway! Do not use it! Do not use it!
+
+- **[ckeditor](https://github.com/galetahub/ckeditor)** Ckeditor is also a veteran company to do rich text,
+ I used to use it in company project.This year, the 5.0 version of the UI has also become more beautiful, quite good, and it has the richest plugins. It's recommended that you try it.
+
+- **[quill](https://github.com/quilljs/quill)** Is also a very hot rich text, the skin is very elegant. Writing a plug-in based on it is also very simple. The API design is very cool. The reason I did not choose it was because it was not good for operation picture and was hard to change. If there is no operation of the picture of the user, it is recommended.
+
+- **[medium-_editor_](https://github.com/yabwe/medium-editor)** The famous medium rich text (unofficial produced), but the degree of completion is still not very good, scalability is not bad. However, I think most users still will not be used medium this way of writing.
+
+- **[Squire](https://github.com/neilj/Squire)** A relatively light, rich text, compressed only 11.5kb, relative to other rich text is very small, recommended features is not complicated suggestion.
+
+- **[UEditor](http://ueditor.baidu.com/website/index.html)** Not used in depth, only a simple project used in the angular1X, but ui really ugly, does not meet the aesthetic today, the official has also been a long time did not go with the new.
+
+- **[slate](https://github.com/ianstormtaylor/slate)** A completely customizable framework for building rich text editors. Slate lets you build rich, intuitive editors like those in Medium, Dropbox Paper or Google Docs—which are becoming table stakes for applications on the web—without your codebase getting mired in complexity. Looks cool, after a chance I will practice in the project try it.
+
+I listed a lot of rich text, but I didn't list any rich text related to vue, mainly because rich text is really more complex than thought. Also said in the previous article, in fact, encapsulation vue components is very convenient, there is no need to use someone else's package of things.
+What kind of vue-quill vue-editor is just a simple package, no difficulty. You might as well encapsulate it yourself, and be a little more flexible and controllable. In addition vue really doesn't have any good rich text, unlike react has [draft](https://github.com/facebook/draft-js) produced by facebook, [editor](https://github.com/ory/editor) produced by ory. Vue doesn't have this product from a big company.
+
+Of course, you can also choose some paid rich text editor, the author's own company has a project in the use of the [froala-editor](https://www.froala.com/wysiwyg-editor). Whether it is beautiful and easy to use are good, the company bought a professional version, $ 349 a year, the price is also very reasonable, but in fact save the cost of developer development may go far beyond the price.
+
+## Tinymce
+
+Here to briefly talk about the use of Tinymce in you own projects.
+
+:::warning Deprecated
+The current method of using the global reference. Code in: `static/tinymce` (The files in the static directory will not be build by webpack), import in index.html .And make sure it's in the order before your `app.js`!
+:::
+
+After will dynamic import tinymce by `CDN` .
+
+If you want to change the cdn address or the version of tinymce, just find tinymce cdn in [@/components/Tinymce](https://github.com/adempiere/adempiere-vue/blob/master/src/components/Tinymce/index.vue) then modified it. It will be automatically injected into `index.html` via `dynamicLoadScript`.
+
+> The current use of the npm installation 'Tinymce' method is more complex and has some problems (which may be used in the future). :space_invader:
+
+**Usage**
+Because rich text is not suitable for two-way data, so only watch the content changes once, and then will not be watch again. If later you need to change the rich text content.Can be set by `this.refs.xxx.setContent ()`.
+
+The source code is also very simple, any other needs can be modified in `@/components/Tinymce/index.vue`.
+
+```html
+
+```
+
+At present, the following attributes are provided, and there are requirements that can be added by themselves or an issue.
+
+| Property | Description | Type | Default |
+| :------: | :-------------------------: | :-----------: | :--------------------------------------: |
+| id | Component unique identifier | String | Default to help you generate a unique id |
+| value | Rich text content | String | Only monitor changes once |
+| toolbar | Rich text toolbar | Array | [] |
+| menubar | Rich text menubar | String | 'file edit insert view format table' |
+| height | Rich text height | Number | 360 |
+| width | Rich text width | Number String | / |
+
+## tinymce-vue
+
+The tinymce official also released the vue version of [tinymce-vue](https://github.com/tinymce/tinymce-vue), which has helped you package a lot of things, but at the same time it has reduced flexibility. If you are interested, you can study it by yourself.
diff --git a/docs/feature/component/svg-icon.md b/docs/feature/component/svg-icon.md
new file mode 100644
index 00000000..b5923d35
--- /dev/null
+++ b/docs/feature/component/svg-icon.md
@@ -0,0 +1,38 @@
+---
+sidebarDepth: 3
+---
+
+# Svg Icon
+
+Global icon component: Svg Icon.
+
+By default, the Svg Icon component is registered in [@/icons](https://github.com/adempiere/adempiere-vue/blob/master/src/icons/index.js#L6), and can be used anywhere in the project. All icons can be found in [@/icons/svg](https://github.com/adempiere/adempiere-vue/tree/master/src/icons/svg). You can add or remove the icon by yourself, and the icon will be imported automatically without manual operation.
+
+## Usage
+
+```html
+
+
+```
+
+## Change color
+
+By default, `svg-icon` reads its parent color `fill: currentColor;`
+
+You can change the parent `color` or directly `fill` color.
+
+## Import from url
+
+Support import `svg` from external url. E.g:
+
+``
+
+## Size
+
+If you are downloading an icon from [iconfont](https://www.iconfont.cn/), remember to use a tool such as Sketch to specify the size of the icon. Otherwise, the size of the icons in the project may not be uniform.
+
+The icons used in this project are all 128\*128 size specifications.
+
+:::tip
+If you encounter the wrong color of the icon, you can refer to the [issue](https://github.com/adempiere/adempiere-vue/issues/330) for modification
+:::
diff --git a/docs/feature/component/tree-table.md b/docs/feature/component/tree-table.md
new file mode 100644
index 00000000..c2f19fac
--- /dev/null
+++ b/docs/feature/component/tree-table.md
@@ -0,0 +1,108 @@
+# Tree-Table
+
+## Brief
+
+This component only provides a solution for creating `TreeTable`. It is based on the `element-ui` table component. It uses the `row-style` method of `el-table` to determine whether the element needs to be hidden or displayed.
+
+And this component makes full use of the features of the `vue` slot to make it user-friendly.
+
+In `evel.js`, the `addAttrs` method adds several properties to the data, and `treeTotable` flattens the array. None of these operations will destroy the source data, just add properties.
+
+## Props
+
+| Attribute | Description | Type | Default |
+| :--------------: | :----------------------------------------------------------- | :-----: | :------: |
+| data | original display data | Array | [] |
+| columns | column attribute | Array | [] |
+| defaultExpandAll | whether to expand all nodes by default | Boolean | false |
+| defaultChildren | specify which node object is used as the node's subtree | String | children |
+| indent | horizontal indentation of nodes in adjacent levels in pixels | Number | 50 |
+
+> Any of the `el-table` properties are supported, such as `border`, `fit`, `size` or `@select`, `@cell-click`. See the ʻel-table` documentation for details.
+
+---
+
+### Example
+
+```html
+
+```
+
+#### data(**Required**)
+
+```js
+const data = [
+ {
+ name:'1'
+ children: [
+ {
+ name: '1-1'
+ },
+ {
+ name: '1-2'
+ }
+ ]
+ },
+ {
+ name: `2`
+ }
+]
+```
+
+#### columns(**Required**)
+
+- label: text displayed in the header
+- key: data.key will show in column
+- expand: `true` or `false`
+- checkbox: `true` or `false`
+- width: column width 。such as `200`
+- align: alignment `left/center/right`
+- header-align: alignment of the table header `left/center/right`
+
+```javascript
+const columns = [
+ {
+ label: 'Checkbox',
+ checkbox: true
+ },
+ {
+ label: '',
+ key: 'id',
+ expand: true
+ },
+ {
+ label: 'Event',
+ key: 'event',
+ width: 200,
+ align: 'left'
+ },
+ {
+ label: 'Scope',
+ key: 'scope'
+ }
+]
+```
+
+> The tree table component will generate a named slot based on the key property of columns. If you need to customize the column data, you can do it through the slot.
+
+```html
+
+ level: {{ scope.row._level }}
+ expand: {{ scope.row._expand }}
+ select: {{ scope.row._select }}
+
+```
+
+## Events
+
+Several methods are currently available, but only the `beta` version, which is likely to be modified later.
+
+```js
+this.$refs.TreeTable.addChild(row, data) //Add child elements
+this.$refs.TreeTable.addBrother(row, data) //Add a sibling element
+this.$refs.TreeTable.delete(row) //Delete the element
+```
+
+## Other
+
+If you have other requirements, please refer to the [el-table](http://element-cn.eleme.io/#/en-US/component/table) api to modify the index.vue
diff --git a/docs/feature/script/new.md b/docs/feature/script/new.md
new file mode 100644
index 00000000..c6fc3a63
--- /dev/null
+++ b/docs/feature/script/new.md
@@ -0,0 +1,19 @@
+# New
+
+In daily work, the most common is to write modules and business components. When you open a new `view` or `component` every time you need to manually create a new `.vue`, create a ``, `
+<% } %>
+```
+
+There is also a small detail. If you use the global object method to introduce vue, you don't need to manually Vue.use(Vuex), it will be mounted automatically. [issue](https://github.com/vuejs/vuex/issues/731)
+
+Complete [code modification](https://github.com/adempiere/vue-admin-template/commit/eaaa3c1ddadd114451a1a83e042f1fc56a9809a1)
+
+Finally you can use `npm run preview -- --report` to see the effect as shown:
+
+
+
+::: tip
+By the same token, other third-party dependencies can be handled in the same way(such as `vuex`, `vue-router`, etc.). Of course, you can also choose to use [DLLPlugin](https://webpack.docschina.org/plugins/dll-plugin/) to handle third-party dependencies to optimize the build.
+:::
diff --git a/docs/guide/advanced/chart.md b/docs/guide/advanced/chart.md
new file mode 100755
index 00000000..450687e0
--- /dev/null
+++ b/docs/guide/advanced/chart.md
@@ -0,0 +1,133 @@
+# Chart
+
+Managing background charts is also a common requirement. The chart here only recommends ECharts, full-featured, community demo is also rich [gallery](http://gallery.echartsjs.com/explore.html)。
+
+I still have that point of view. Most plug-ins recommend that use vue for packaging by yourself. It's really simple. ECharts supports the import of webpack, you can import the whole ECharts `var echarts = require ('echarts')` However, ECharts is not small, if you use only a small part of the features or chart type, then recommend on-demand import.
+
+```js
+// Import on demand -- import ECharts main module
+var echarts = require('echarts/lib/echarts')
+// Import bar
+require('echarts/lib/chart/bar')
+// Import tooltip&title
+require('echarts/lib/component/tooltip')
+require('echarts/lib/component/title')
+
+// Import all ECharts module
+var echarts = require('echarts')
+```
+
+[Use ECharts with webpack](https://ecomfe.github.io/echarts-doc/public/en/tutorial.html#Use%20ECharts%20with%20webpack)
+
+[Include ECharts charts and components on demand](https://ecomfe.github.io/echarts-doc/public/en/tutorial.html#Use%20ECharts%20with%20webpack)
+
+Next we will declare the initialization of ECharts in vue. Because ECharts initialization must be bound to dom, we can only initialize it during vue's mounted lifetime.
+
+```js
+mounted() {
+ this.initCharts();
+},
+methods: {
+ initCharts() {
+ this.chart = echarts.init(this.$el);
+ this.setOptions();
+ },
+ setOptions() {
+ this.chart.setOption({
+ title: {
+ text: 'ECharts 入门示例'
+ },
+ tooltip: {},
+ xAxis: {
+ data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
+ },
+ yAxis: {},
+ series: [{
+ name: '销量',
+ type: 'bar',
+ data: [5, 20, 36, 10, 10, 20]
+ }]
+ })
+ }
+}
+```
+
+It's that simple, ECharts is configured, at this point you want to say that my data is obtained remotely, or how do I dynamically change the configuration of ECharts? We can trigger the setOptions method with watch
+
+```js
+// The first watch options change Using the depth of vue watcher, options are re-setOption
+watch: {
+ options: {
+ handler(options) {
+ this.chart.setOption(this.options)
+ },
+ deep: true
+ },
+}
+// The second only watch data changes trigger ECharts only when the data changes
+watch: {
+ seriesData(val) {
+ this.setOptions({series:val})
+ }
+}
+```
+
+In fact, they are all similar, or they must be combined with their own business. There is no difference between using ECharts in peacetime.
+
+## Demo
+
+
+
+::: tip Code
+`@/views/dashboard/admin/components`
+:::
+
+## ECharts chart width is displayed incorrectly?
+
+Sometimes you put ECharts in `el-tab` or`el-dialog`, and you will find that the width of the chart will be displayed incorrectly. As shown below:
+
+
+
+Because ECharts itself is not adaptive, you need to manually call its `.resize ()` method when the width of your parent container changes.
+For example, `el-tab`, you can listen to the`change` event, and call the `.resize ()` method after finding the chart when the change occurs.
+
+```html
+
+
+
+
+
+ 配置管理
+ 角色管理
+ 定时任务补偿
+
+
+
+
+```
+
+It is relatively simple to put the chart in the `el-dialog`, as long as the init chart is displayed after the dialog appears.
+
+## Others
+
+Of course there are many other libraries in the community, such as [d3](https://github.com/d3/d3) , [Chart.js](https://github.com/chartjs/Chart.js) , [chartist-js](https://github.com/gionkunz/chartist-js). The packaging methods are almost the same, and they are no longer here.
diff --git a/docs/guide/advanced/cors.md b/docs/guide/advanced/cors.md
new file mode 100755
index 00000000..8a7a4e64
--- /dev/null
+++ b/docs/guide/advanced/cors.md
@@ -0,0 +1,20 @@
+# Cors
+
+The most question be asked is still about `cross-domain` issues. In fact, the `cross-domain` issue is really not a very difficult question to solve. Here I will briefly summarize several `cross-domain` solutions I recommend.
+
+The most recommended way is `cors`, full name is `Cross Origin Resource Sharing`. This solution does not make any difference to the front-end write request as usual. The workload is basically on the back-end. For each request, the browser must first send a pre-request as `OPTIONS`, to know the server-side HTTP method supported for cross-source requests. After confirming that the server allows the cross-source request, then send the real request with the actual HTTP request method. Details [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
+
+The recommended reason is: as long as the first time is configured, no matter how many API interfaces and projects, they can be directly reused, and the cross-domain problem can be solved once and for all, and it can be conveniently used in both the development environment and the formal environment.
+
+But there are always some back-end developers who think `cors` is too much `trouble`, they don't want to help the front end to solve cross-domain issues. That pure front-end is also has solutions.
+
+In `dev` environment, you can use webpack `proxy`, it is also very easy to use。 It's recommended that you look at the [document](https://www.webpackjs.com/configuration/dev-server/#devserver-proxy) and we're not going to discuss it here. Some of the author's personal projects use this method
+
+But this method can not used in the `production` environment. In `production` environment, you need to use `nginx` reverse proxy. Whether `proxy` or `nginx`, the principle is the same. Solve the cross-domain issues by building a transit server to forward requests.
+
+| development | production |
+| :---------: | ---------- |
+| cors | cors |
+| proxy | nginx |
+
+Here I only recommend these two ways to cross-domain, there are many other cross-domain methods but not recommended.
diff --git a/docs/guide/advanced/error.md b/docs/guide/advanced/error.md
new file mode 100755
index 00000000..136100bf
--- /dev/null
+++ b/docs/guide/advanced/error.md
@@ -0,0 +1,98 @@
+# Error Handling
+
+## Page
+
+**404**
+
+Page-level error handling is handled uniformly by the `vue-router`. All pages that do not match the correct route will advance to the `404` page.
+
+```js
+{ path: '*', redirect: '/404' }
+```
+
+::: warning
+One thing that needs special attention here is that the `404` page must be loaded last. If you put `404` in the constantRoutes , then the following page will be blocked to `404`. See the problem for details [addRoutes when you've got a wildcard route for 404s does not work](https://github.com/vuejs/vue-router/issues/1176)
+:::
+
+**401**
+
+Permission control is done in `@/permission.js`. All users who do not have permission to access this route will be redirected to the `401` page.
+
+
+
+## Request
+
+All the requests in the project will go through the axios instance created in `@/utils/request.js`. [code](https://github.com/adempiere/adempiere-vue/blob/master/src/utils/request.js)。
+
+You can use the `service.interceptors.response`, the response interceptor to harmonize different status codes according to your actual business or to perform error handling according to custom code. Such as:
+
+```js
+service.interceptors.response.use(
+ response => {
+ /**
+ * The code is non-20000 error-free
+ */
+ const res = response.data
+ if (res.code !== 20000) {
+ Message({
+ message: res.data,
+ type: 'error',
+ duration: 5 * 1000
+ })
+
+ // 50008: illegal token; 50012: other client logged in; 50014: Token expired;
+ if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+ MessageBox.confirm(
+ '你已被登出,可以取消继续留在该页面,或者重新登录',
+ '确定登出',
+ {
+ confirmButtonText: '重新登录',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }
+ ).then(() => {
+ store.dispatch('FedLogOut').then(() => {
+ location.reload() // 为了重新实例化vue-router对象 避免bug
+ })
+ })
+ }
+ return Promise.reject('error')
+ } else {
+ return response.data
+ }
+ },
+ error => {
+ console.log('err' + error) // for debug
+ Message({
+ message: error.message,
+ type: 'error',
+ duration: 5 * 1000
+ })
+ return Promise.reject(error)
+ }
+)
+```
+
+Since all requests return a `promise`, you can also pass a `catch` error for each request, which allows for separate processing.
+
+```js
+getInfo()
+ .then(res => {})
+ .catch(err => {
+ xxxx
+ })
+```
+
+## Coding
+
+This project also does code-level error handling. If you enable `eslint`, you will be prompted for errors when writing code. Such as:
+
+
+Of course there are many errors that cannot be checked by `eslint`, vue also provides global error handling hooks[errorHandler](https://vuejs.org/v2/api/#errorHandler). The project also made a corresponding error collection.
+
+
+::: tip
+Listening error: [@/errorLog.js](https://github.com/adempiere/adempiere-vue/blob/master/src/errorLog.js)
+
+Error display component: [@/components/ErrorLog](https://github.com/adempiere/adempiere-vue/blob/master/src/components/ErrorLog/index.vue)
+:::
diff --git a/docs/guide/advanced/eslint.md b/docs/guide/advanced/eslint.md
new file mode 100755
index 00000000..948cf7f0
--- /dev/null
+++ b/docs/guide/advanced/eslint.md
@@ -0,0 +1,77 @@
+# ESLint
+
+Whether it's a multi-person collaboration or personal projects, code specifications are important. It can not only avoids basic syntax errors, but also ensures the readability of the code.
+
+## Config
+
+All configuration files are in [.eslintrc.js](https://github.com/adempiere/adempiere-vue/blob/master/.eslintrc.js).
+The basic eslint rules of this project is based on the official eslint rules of vue [eslint-config-vue](https://github.com/vuejs/eslint-config-vue) but made minor changes. You can customize your configuration according to your needs.
+
+Such as: my personal or project team is accustomed to using two spaces, but you may feel that the four spaces are more pleasing, and you can make the following changes.
+
+Enter the project of `.eslintrc.js`, find `indent`,and then set it to `4` 。There are a variety of configuration information, see details [ESLint Document](https://eslint.org/docs/rules/)。
+
+After [v3.8.1](https://github.com/adempiere/adempiere-vue/releases/tag/v3.8.1), [eslint-plugin-vue](https://github.Com/vuejs/eslint-plugin-vue) has been added to better verify vue related code.
+
+By default, the most restrictive config `plugin:vue/recommended` is used to verify the code. If you think it is too strict, you can modify it yourself.
+
+```js
+// https://github.com/adempiere/adempiere-vue/blob/master/.eslintrc.js
+
+module.exports = {
+ extends: ['plugin:vue/recommended', 'eslint:recommended']
+ //You can change it to extends: ['plugin:vue/essential', 'eslint:recommended']
+}
+```
+
+## Cancel ESLint
+
+If you don't want to use ESLint (not recommended for cancellation), just find the [vue.config.js](https://github.com/adempiere/adempiere-vue/blob/master/vue.config.js) file.
+Make the following settings `lintOnSave: false`.
+
+## Configure ESLint in vscode
+
+Sharp tools make good work! Personally recommend eslint+vscode to write VUE, there is definitely a very cool
+
+
+
+
+Every time you save your code, vscode will be able to mark red areas that do not conform to the eslint rules, and make some simple self-fixes at the same time. The installation steps are as follows:
+
+First install the eslint plugin
+
+
+After we have installed ESLint, we back to VSCode to set up . Go to `Code` > `Preferences` > `Settings` and add the following configuration.
+
+```json
+{
+ "files.autoSave": "off",
+ "eslint.validate": [
+ "javascript",
+ "javascriptreact",
+ "vue-html",
+ {
+ "language": "vue",
+ "autoFix": true
+ }
+ ],
+ "eslint.run": "onSave",
+ "eslint.autoFixOnSave": true
+}
+```
+
+Everyone and the team have their own code specification, unification is good, to create their own eslint rules and upload it to the npm will be fun. Such as ElemeFE [config](https://www.npmjs.com/package/eslint-config-elemefe) or Vue official [config](https://github.com/vuejs/eslint-config-vue).
+
+[vscode plugin and configuration recommendations](https://github.com/varHarrie/Dawn-Blossoms/issues/10)
+
+## More configuration
+
+Since this project is built based on `vue-cli`, more configuration can be found in the official [documentation](https://cli.vuejs.org/en/config/#lintonsave)
+
+## Auto fix
+
+```bash
+npm run lint -- --fix
+```
+
+Running the above command, eslint will automatically fix some simple errors.
diff --git a/docs/guide/advanced/git-hook.md b/docs/guide/advanced/git-hook.md
new file mode 100755
index 00000000..5fc2b743
--- /dev/null
+++ b/docs/guide/advanced/git-hook.md
@@ -0,0 +1,78 @@
+# Git Hooks
+
+Programmers with engineering literacy will pay attention to coding standards, and Code Linting (Lint) is an important means to ensure code specification and consistency.
+
+What are the benefits of using `Lint`? In my opinion, it has at least the following three points:
+
+- Fewer bugs
+- With higher development efficiency, Lint can easily find low-level, obvious errors.
+- Higher code readability
+
+Many times our `lint` check is placed in the continuous integration phase, the approximate process is as follows:
+
+> Code Submission --> Run CI Found Problem (Remote) --> Local Fix Issue --> Resubmit --> Pass Check (Remote)
+
+But there is a problem with this. Our `CI` (continuous integration) often doesn't just do `Lint` work, it also has many other tasks (such as packaging files, static resources uploaded to CDN, etc.), which leads to It's a special waste of time, it may take a few minutes for you to find the problem, or sometimes you don't find your `CI` is failed.
+
+Common process: write the code locally, submit, start running lint, find that it does not pass, modify the code locally, submit it, wait for the result of CI, and repeat the previous operation if there are any problems.
+
+## husky
+
+The most effective solution is to put the `Lint` checksum locally. The common practice is to use [husky](https://github.com/typicode/husky) or [pre-commit](https://github.com/observing/pre-commit) Do a `Lint` check before committing locally.
+
+> Of course, if you use `vue-cli@3` when creating your project, you can also use its built-in [yorkie](https://github.com/yyx990803/yorkie), which is based on `husky`, but Changed the interface. But here we still use `husky` as an example.
+
+```bash
+# Note: Our examples are all 1.3.1+ versions!
+npm install husky -D -S
+```
+
+Then modify `package.json` to add the configuration:
+
+```json
+"husky": {
+ "hooks": {
+ "pre-commit": "eslint --ext .js,.vue src"
+ }
+ }
+```
+
+Finally try the `Git` submission and you will receive feedback soon:
+
+```
+git commit -m "Keep calm and commit"
+```
+
+But there is a problem. In my this git submission, I may have only modified one file. For example, I modified the content of `foo.js`, but it will still check all the '.js' files in `src`. It is very unfriendly. Every time I submit the code I wrote, I have to solve the other person's code lint problem first, then I can submit the code smoothly, and when the project is big, the inspection speed will become more and more slow.
+
+## lint-staged
+
+To solve the pain points above, you need to use [lint-staged](https://github.com/okonet/lint-staged). It will only check to check what you submitted or what you modified.
+
+```bash
+npm install lint-staged -D -S
+```
+
+Then, modify the package.json configuration:
+
+```json
+"husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+},
+"lint-staged": {
+ "src/**/*.{js,vue}": [
+ "eslint --fix",
+ "git add"
+ ]
+ }
+```
+
+As configured above, each time it will only check your local configuration for the `eslint` rule (this see the document [ESLint](eslint.md)) before your local `commit`, if it meets the rules, it will be submitted successfully. If it does not match, it will automatically execute `eslint --fix` to try to help you fix it automatically. If the repair is successful, it will help you to submit the repaired code. If it fails, you will be prompted with an error, and you will be allowed to submit the code only after you fix it.
+
+## To sum up
+
+The best `lint` specification process is to recommend team members to configure `eslint` in their own editor, and turn on the `eslint-loader` error in webpack, so the editor can help you automatically fixed some simple errors when you write. At the same time, it can obviously remind you of the code that does not meet the `lint` specification. See [ESLint](eslint.md) for details on this.
+
+But this is not mandatory. Some team members or newly arrived interns have not configured the lint rule in the editor or ignored the error in the command line. In this case, you need to configure the mandatory pre-commit. Check that everything submitted to the remote repository is in compliance with the team's specifications.
diff --git a/docs/guide/advanced/i18n.md b/docs/guide/advanced/i18n.md
new file mode 100755
index 00000000..ad4eb7d8
--- /dev/null
+++ b/docs/guide/advanced/i18n.md
@@ -0,0 +1,96 @@
+# I18n
+
+This project is a collection of internationalized i18n solutions. Implemented via [vue-i18n](https://github.com/kazupon/vue-i18n).
+
+Since the project's ui framework uses `element`, internationalization also needs to be internationalized.
+[code](https://github.com/adempiere/adempiere-vue/blob/master/src/lang/index.js).
+At the same time, the current `lang` language save in the `cookie`, and the last language setting can be remembered for opening the page next time.
+
+## Global lang
+
+Code: [@/lang](https://github.com/adempiere/adempiere-vue/tree/master/src/lang)
+Currently set English and Chinese languages.
+
+Meanwhile, import a language package in `@/lang/index.js` for `element-ui`.
+
+## Async lang
+
+There are some langs that are needed for specific pages, such as the `@/views/i18n` page, you can use async lang.
+
+```js
+import local from './local'
+
+this.$i18n.mergeLocaleMessage('en', local.en)
+this.$i18n.mergeLocaleMessage('zh', local.zh)
+```
+
+# Use $t in js
+
+If you use a component such as `select`, its value comes through `v-for`, such as:
+
+```html
+
+
+
+```
+
+```js
+this.options = [
+ {
+ value: '1',
+ label: this.$t('i18nView.one')
+ },
+ {
+ value: '2',
+ label: this.$t('i18nView.two')
+ },
+ {
+ value: '3',
+ label: this.$t('i18nView.three')
+ }
+]
+```
+
+In this case, i18n will only be executed once, because `this.options` in js will only be executed once during `created`, and its data will not change as your local `lang` changes, so You need to manually reset `this.options` when the `lang` changes.
+
+```js
+export default {
+ watch: {
+ lang() {
+ this.setOptions()
+ }
+ },
+ methods: {
+ setOptions() {
+ this.options = [
+ {
+ value: '1',
+ label: this.$t('i18nView.one')
+ },
+ {
+ value: '2',
+ label: this.$t('i18nView.two')
+ },
+ {
+ value: '3',
+ label: this.$t('i18nView.three')
+ }
+ ]
+ }
+ }
+}
+```
+
+## Remove i18n
+
+In `src/main.js` remove `import i18n from './lang'` and delete `src/lang` folder.
+
+And remove `this.$t('route.xxxx')` in `src/layout/components/Levelbar`、`src/layout/components/SidebarItem`、`src/layout/components/TabsView` or others.
+
+After the version, the default master will no longer provide i18n. Because most users are not need i18n, the removal of i18n workload is quite large.
+
+If you have i18n requirements, please use [i18n Branch](https://github.com/adempiere/adempiere-vue/tree/i18n), which is updated synchronously with master.
diff --git a/docs/guide/advanced/icon.md b/docs/guide/advanced/icon.md
new file mode 100755
index 00000000..f15e912e
--- /dev/null
+++ b/docs/guide/advanced/icon.md
@@ -0,0 +1,49 @@
+# Icon
+
+If you do not find the desired icon in the [Icon](https://github.com/adempiere/adempiere-vue/tree/master/src/icons/svg) of this project, you can select and generate your own business icon library on [iconfont.cn](http://iconfont.cn/)and use it again. Or other svg icon website, download svg and put it in this folder.
+
+## Generate icon library code
+
+First, search for and find the icon you need, and collect it into your shopping cart. In the shopping cart, you can add the selected icon to the project (if not, create a new one), and the subsequent generated resources/code are It is based on the dimension of the project.
+
+> If you already have a design draft, just need to generate the relevant code, you can upload your icon, and then do the above operation.
+
+
+
+
+
+** This project now supports and recommends separate export of svg usage. Download method as shown below:**
+
+
+
+
+
+After the download is complete, the downloaded .svg file is automatically imported after it is placed in the `@/icons/svg` folder.
+
+## How to use
+
+```js
+ // icon-class is the icon's name usage
+```
+
+[Component](/feature/component/svg-icon.md)
+
+## Change color
+
+`svg-icon` reads its parent's color `fill: currentColor;' by default.
+
+You can change the parent's `color` or change the color of `fill` directly.
+
+:::tip
+If you encounter an incorrect icon color, you can refer to this[issue](https://github.com/adempiere/adempiere-vue/issues/330)
+:::
+
+## Detailed articles
+
+[手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
+
+## Currently available icons
+
+[src/icons/svg](https://github.com/adempiere/adempiere-vue/tree/master/src/icons/svg)
+
+Online [Preview Address](https://adempiere.github.io/adempiere-vue/#/icon/index)
diff --git a/docs/guide/advanced/lazy-loading.md b/docs/guide/advanced/lazy-loading.md
new file mode 100755
index 00000000..fcc2e1e7
--- /dev/null
+++ b/docs/guide/advanced/lazy-loading.md
@@ -0,0 +1,112 @@
+# Lazy Loading Routes
+
+When you package an application, the Javascript package becomes very large, affecting the page load. If we can split the components corresponding to different routes into different code blocks and then load the corresponding components when the route is accessed, this will be more efficient.
+
+Combining Vue's [async component feature](https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components) and webpack's [code splitting feature](https://webpack.js.org/guides/code-splitting/), it's trivially easy to lazy-load route components.
+
+```js
+const Foo = () => import('./Foo.vue')
+```
+
+
+
+**When you think your page's hot reload is slow, you need to look down ↓**
+
+## Differentiating development and production environments
+
+**[This solution has been eliminated]**
+
+When you have more and more pages in your project, using `lazy-loading` in the development environment becomes less appropriate, and every change of code that triggers a hot update becomes very slow. Therefore, it is recommended to only use the lazy loading function in the build environment.
+
+**Development:**
+
+```js
+// vue-loader at least v13.0.0+
+module.exports = file => require('@/views/' + file + '.vue').default
+```
+
+**Note here that this method only supports `vue-loader at least v13.0.0+`**[adempiere-vue/issues/231](https://github.com/adempiere/adempiere-vue/issues/231)
+
+Production:
+
+```js
+module.exports = file => () => import('@/views/' + file + '.vue')
+```
+
+## Elimination reason
+
+Of course, there are some side effects of writing this way. due to
+
+> Every module that could potentially be requested on an import() call is included. For example, import(./locale/${language}.json) will cause every .json file in the ./locale directory to be bundled into the new chunk. At run time, when the variable language has been computed, any file like english.json or german.json will be available for consumption.
+
+::: tip
+The user can measure whether to adopt this method according to the business situation. If your project is not large and you can also accept the local development hot update speed. You can continue to use lazy loading to avoid this side effect in all environments.
+:::
+
+## New Plan
+
+Use `babel plugins` [babel-plugin-dynamic-import-node](https://github.com/airbnb/babel-plugin-dynamic-import-node).
+It only does one thing by converting all `import()` to `require()`, so that all asynchronous components can be import synchronously using this plugin. Combined with the babel environment variable [BABEL_ENV](https://babeljs.io/docs/usage/babelrc/#env-option), let it only work in the development environment, in the development environment will convert all import () into require ().
+
+This solution to solve the problem of repeated packaging before, while the invasiveness of the code is also very small, you usually write routing only need to follow the lazy loading method of the [official document](https://router.vuejs.org/guide/advanced/lazy-loading.html) routing on it, the other are handed to the handle of the cable, When you don't want to use this program, just remove it from Babel's plugins.
+
+**Code:**
+
+First add `BABEL_ENV` to `package.json`
+
+```json
+"dev": "cross-env BABEL_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"
+```
+
+Then `.babelrc` can only include the `babel-plugin-dynamic-import-node` `plugins` and make it work only in the `development` mode.
+
+```json
+{
+ "env": {
+ "development": {
+ "plugins": ["dynamic-import-node"]
+ }
+ }
+}
+```
+
+After that, you're done. Routing can be written as usual.
+
+```js
+ { path: '/login', component: () => import('@/views/login/index')}
+```
+
+[Related code changes](https://github.com/adempiere/adempiere-vue/pull/727)
+
+## vue-cli@3 [The plan has been eliminated]
+
+`adempiere-vue@4` has been modified to build based on `vue-cli` in the new version. So in the new version you just need to set `VUE_CLI_BABEL_TRANSPILE_MODULES:true` in the `.env.development` environment variable configuration file, specifically [code](https://github.com/adempiere/adempiere-vue/blob/master/.env.development).
+
+Its implementation logic and principle are the same as before, it based on `babel-plugin-dynamic-import-node`.The only thing you need to set a variable in `vue-cli` is to borrow the default configuration of `vue-cli`. By reading [source code](https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js), `vue-cli` will pass `VUE_CLI_BABEL_TRANSPILE_MODULES`,this environment variable to distinguish whether to use `babel-plugin-dynamic-import-node`, so we only need to set it to true. Although its original intention was for unit testing, it just met our needs.
+
+### Elimination reason
+
+In the era of `vue-cli@3`, using `VUE_CLI_BABEL_TRANSPILE_MODULES` is ok, but it is actually fragile, as in `vue-cli@4`, vue-cli introduces `babel-plugin-dynamic-import-node The logic of`has changed, it needs to be `VUE_CLI_BABEL_TRANSPILE_MODULES` and `VUE_CLI_BABEL_TARGET_NODE` to be true at the same time, so as long as the judgment logic of vue-cli changes, we need to make corresponding changes, or be very passive and coupled . So in the `vue-cli@4` version, we no longer set it by `VUE_CLI_BABEL_TRANSPILE_MODULES: true`, but by manually introducing `'babel-plugin-dynamic-import-node'`, see the next section for details.
+
+## vue-cli@4
+
+1. No need to configure `VUE_CLI_BABEL_TRANSPILE_MODULES = true` in the `.env.development` file, just delete it.
+
+2. Run `npm install babel-plugin-dynamic-import-node -S -D`
+
+3. The way to add the dynamic-import-node plugin in `babel.config.js`, see the next section for details.
+
+```js
+module.exports = {
+ presets: ['@vue/cli-plugin-babel/preset'],
+ env: {
+ development: {
+ plugins: ['dynamic-import-node']
+ }
+ }
+}
+```
+
+## Improve
+
+`webpack5` is about to be released, greatly improving the speed of packaging and compiling. After that, it may not need to be so complicated at all. More page hot updates can be very fast, and the solution mentioned above is completely unnecessary.
diff --git a/docs/guide/advanced/sass.md b/docs/guide/advanced/sass.md
new file mode 100644
index 00000000..ced60116
--- /dev/null
+++ b/docs/guide/advanced/sass.md
@@ -0,0 +1,56 @@
+# Node Sass to Dart Sass
+
+Before `v4.3.0`, this project was built based on `node-sass`, but `node-sass` low-level dependencies [libsass](https://github.com/sass/libsass), resulting in many users installing Especially difficult for Windows users, it forces users to install `python2` and `Visual Studio` in the `windows` environment to compile successfully.
+
+So in order to solve this problem, this project was modified to build `dart-sass` in [v4.3.0](https://github.com/adempiere/adempiere-vue/pull/3040), it can guarantee performance Under the premise of greatly simplifying the user's installation costs. Through this [issue](https://github.com/adempiere/adempiere-vue/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) the relevant comments below can be known, install` Node-sass is such a troublesome thing.
+
+There is a more important reason for choosing to use dart-sass here. Officially, `sass` has taken dart-sass as the main development direction in the future. Any new features will be supported first, and it It has been running steadily in the community for a long time, and there are basically no pits. The main reason why dart-sass is easy to install is because it will be compiled into pure js, so that it can be used directly in the node environment. Although its running speed will be slower than that based on [libsass](https://github.com/sass/libsass), the difference in these speeds is almost negligible. The entire community is now embracing `dart-sass`, and we have no reason to refuse! And it does greatly simplify the user's installation costs.
+
+Currently, `vue-cli` will also prefer to use `dart-scss` by default when selecting `sass` preprocessing, related: [pr](https://github.com/vuejs/vue-cli/pull/3321)
+
+Related instructions can be found in this article: [Announcing Dart Sass](https://sass-lang.com/blog/announcing-dart-sass)
+
+Specific `dart-sass` performance evaluation can be seen: [Perf Report](https://github.com/sass/dart-sass/blob/master/perf.md)
+
+## Upgrade plan
+
+The upgrade is also very simple, requiring only two steps
+
+```bash
+npm uninstall node-sass
+
+npm install sass -S -D
+```
+
+The upgrade can also be seen in detail: [Pull Request](https://github.com/adempiere/adempiere-vue/pull/3040) is simple and only requires two steps
+
+## Not compatible
+
+One thing to note after replacing `node-sass` is that it no longer supports the `/deep/` writing style of `sass` before, and it needs to be changed to the writing style of `::v-deep`. Related: [issue](https://github.com/vuejs/vue-cli/issues/3399)
+
+Concrete demo:
+
+```css
+.a {
+ /deep/ {
+ .b {
+ color: red;
+ }
+ }
+}
+
+/* change into */
+.a {
+ ::v-deep {
+ .b {
+ color: red;
+ }
+ }
+}
+```
+
+Regardless of whether you use `dart-sass` or not, I suggest you use `::v-deep` notation, which is not only compatible with the css `>>>` notation, but also compatible with sass `/deep/` . And it's the way of writing specified in [vue 3.0 RFC](https://github.com/vuejs/rfcs/blob/scoped-styles-changes/active-rfcs/0023-scoped-styles-changes.md).
+
+And the original writing of `/deep/` itself was abandoned by Chrome. You can often find a warning in the console that Chrome reminds you not to use `/deep/`.
+
+More: [scope css writing](https://vue-loader.vuejs.org/guide/scoped-css.html)
diff --git a/docs/guide/advanced/style-guide.md b/docs/guide/advanced/style-guide.md
new file mode 100644
index 00000000..8c3d9a34
--- /dev/null
+++ b/docs/guide/advanced/style-guide.md
@@ -0,0 +1,43 @@
+## Style Guide
+
+The style guide for this project is mainly based on the official [style guide](https://vuejs.org/v2/style-guide/index.html) . It is recommended to read the guide before you start using the project, which will help you write more standardized and unified code. Most of these rules are also configured in [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue). When the rules are not followed, will throw an error. For details, see [eslint](./eslint.md) section.
+
+Of course, there are some special specifications that cannot be verified by eslint. You need to pay attention to yourself and follow. The most important thing is the naming rules for files. Take the example of `adempiere-vue` here.
+
+## Component
+
+All `Component` files start with uppercase (PascalCase), which is also official [recommended](https://vuejs.org/v2/style-guide/index.html#Single-file-component-filename-casing-strongly-recommended)。
+
+But except for `index.vue`.
+
+Example:
+
+- `@/components/BackToTop/index.vue`
+- `@/components/Charts/Line.vue`
+- `@/views/example/components/Button.vue`
+
+## JS files
+
+All `.js` files follow `kebab-case`.
+
+Example:
+
+- `@/utils/open-window.js`
+- `@/views/svg-icons/require-icons.js`
+- `@/components/MarkdownEditor/default-options.js`
+
+## Views
+
+Under the `views` file, the `.vue` files representing the routes path all use `kebab-case`, and the same rules are used for folders.
+
+Example:
+
+- `@/views/svg-icons/index.vue`
+- `@/views/svg-icons/require-icons.js`
+
+The use of a kebab-case to name `views` is mainly due to the following considerations.
+
+- `kebab-case` is also one of the officially recommended naming conventions [Document](https://vuejs.org/v2/style-guide/index.html#Single-file-component-filename-casing-strongly-recommended)
+- The `.vue` file under `views` represents a route, so it needs to be distinguished from `component` (components are `PascalCase`)
+- The `url` of the page is follow `kebab-case` , such as `https://www.xxx.admin/export-excel`. So the `view` corresponding to the route should be kept uniform.
+- No case sensitive issues
diff --git a/docs/guide/advanced/theme.md b/docs/guide/advanced/theme.md
new file mode 100755
index 00000000..5eb69a69
--- /dev/null
+++ b/docs/guide/advanced/theme.md
@@ -0,0 +1,108 @@
+# Theme
+
+This project is based on the element-ui default visual style. If you have additional requirements for visual style, you can follow the official custom theme [guide](http://element.eleme.io/#/en-US/component/custom-theme). The method is implemented by covering style variables.
+
+## Style override
+
+The generic style variables for element-ui may not satisfy all custom requirements, and you can do this by overriding the default component style.Since the element-ui style is introduced globally, you can't add scoped if you want to override its style in a `view`, but if you want to override only the element style of the page, you can use it. Add a class to the parent to use the namespace to solve the problem.
+
+Or use [Deep Selectors](https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors)。
+
+```css
+/* Your namespace */
+.article-page {
+ /* element-ui tag */
+ .el-tag {
+ margin-right: 0px;
+ }
+}
+```
+
+Some global element-ui style modifications can be set in [@/styles/element-ui.scss](https://github.com/adempiere/adempiere-vue/blob/master/src/styles/element-ui.scss).
+
+
+
+## Dynamic theme
+
+This project provides two kinds of dynamic skinning functions, each has its own advantages and disadvantages. Please choose according to your own needs.
+
+### Element-ui official method
+
+After the element-ui is upgraded to 2.0, the dynamic peel function is provided in the upper right corner of the official document. This project also provides a change function.
+
+Code: [@/components/ThemePicker](https://github.com/adempiere/adempiere-vue/blob/master/src/components/ThemePicker/index.vue)。
+
+**Briefly explain its principle:** All styles after element-ui version 2.0 are based on SCSS, all colors are set based on a few basic color [variables](https://github.com/adempiere/custom-element-theme/blob/master/element-variables.scss), so it is not difficult to achieve dynamic skinning, as long as find a few color variables to modify it. First, we need to get the version number of element-ui through `package.json` and request the corresponding style according to the version number. After you get the style, you will change the color, replace it with the color variable you want, and then dynamically add the `style` tag to override the original CSS style.
+
+::: tip
+It is necessary to obtain the version of element-ui to lock the version so as to avoid the impact of non-compatible updates when the Element is upgraded in the future.
+:::
+
+```js
+const version = require('element-ui/package.json').version
+
+const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+this.getCSSString(url, chalkHandler, 'chalk')
+
+getCSSString(url, callback, variable) {
+ const xhr = new XMLHttpRequest()
+ xhr.onreadystatechange = () => {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+ callback()
+ }
+ }
+ xhr.open('GET', url)
+ xhr.send()
+}
+```
+
+**How to use**
+
+Import the ThemePicker component to your project
+
+```js
+import ThemePicker from '@/components/ThemePicker'
+```
+
+- Advantage
+ - No need to prepare multiple sets of themes, free dynamic theme
+- Shortcomings
+ - Not enough customization, only support switching of basic colors
+
+
+
+
+### Multiple sets of theme
+
+This method is the most common way of theme, storing multiple sets of themes locally, both with different namespaces, such as writing two sets of themes, a set called `day-theme`, a set called `night-theme`, and `night-theme.` Themes are all under a `.night-theme` namespace, and we dynamically add `.night-theme` on body; remove `.night-theme`.
+
+#### How to use
+
+> We have made corresponding changes here based on the official theme generation library [element-theme](https://github.com/ElementUI/element-theme).
+
+First download [custom-element-theme](https://github.com/adempiere/custom-element-theme)
+
+```bash
+git@github.com:PanJiaChen/custom-element-theme.git
+```
+
+Globally installed theme generation tool
+
+```bash
+npm i element-theme -g
+```
+
+Enter the project directory Install dependencies
+
+```bash
+npm install
+```
+
+First execute `et -i` to generate `element-variables.scss` file that stores style variables, then enter `element-variables.scss` file to modify your own variables, execute `et` after modification, compile subject, and finally Execute `gulp` to generate a namespace. All generated files are in the `dist` directory. You just copy all the contents of the file to `src/assets/custom-theme` in the `adempiere-vue` project.
+
+::: tip
+If you need to modify the name of the package generation style namespace, just modify the [variable](https://github.com/adempiere/custom-element-theme/blob/master/gulpfile.js#L6).
+:::
+
+
diff --git a/docs/guide/advanced/webpack.md b/docs/guide/advanced/webpack.md
new file mode 100644
index 00000000..67aa066d
--- /dev/null
+++ b/docs/guide/advanced/webpack.md
@@ -0,0 +1,11 @@
+## Webpack Guide
+
+Recommended [survivejs](https://survivejs.com/webpack/foreword/)
+
+Here to share the webpack trilogy, basically read the webpack configuration engineer in this field.
+
+**No English translation**
+
+- [Getting started with webpack 4 and single page applications](https://github.com/wallstreetcn/webpack-and-spa-guide)
+- [Hands touch your hand, use you with a reasonable posture using webpack4 (on)](https://juejin.im/post/5b56909a518825195f499806)
+- [Hands touch your hand, use you with a reasonable posture using webpack4 (below)](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc)
diff --git a/docs/guide/essentials/deploy.md b/docs/guide/essentials/deploy.md
new file mode 100755
index 00000000..2782e93b
--- /dev/null
+++ b/docs/guide/essentials/deploy.md
@@ -0,0 +1,220 @@
+# Build & Deploy
+
+## Build
+
+When projects are completed, you can build your application only run one command:
+
+```bash
+# build for production environment
+npm run build:prod
+
+# build for stage environment
+npm run build:stage
+```
+
+After the build package is successful, the `dist` folder will be generated in the root directory, which is to build a packaged file, usually static files such as `***.js`, `***.css`, `index.html`, etc. .
+
+If you need a custom build, such as specifying the dist directory, you need to configure it through `outputDir` in [config](https://github.com/adempiere/adempiere-vue/blob/master/vue.config.js).
+
+### Environmental variables
+
+The configuration of all test environments or formal environment variables is in the `.env.xxxx` file such as [.env.development](https://github.com/adempiere/adempiere-vue/blob/master/.env.development).
+
+They all inject into the global context via the `webpack.DefinePlugin` plug-ins.
+
+::: tip note! ! !
+Environment variables must start with `VUE_APP_`. Such as: `VUE_APP_API`, `VUE_APP_TITLE`
+
+You can access them in your application code:
+
+```js
+console.log(process.env.VUE_APP_xxxx)
+```
+
+### Analyze the build file size
+
+If your build file is large, you can optimize your code by building and analyzing the size distribution of dependent modules using the `webpack-bundle-analyzer`.
+
+```bash
+npm run preview -- --report
+```
+
+After running you can see the specific size distribution at [http://localhost:9526/report.html](http://localhost:9526/report.html)
+
+
+
+::: tip
+It is recommended to use gzip, after using the volume will be only the original 1/3 or so. You can also use lazy loading or Code Splitting.
+:::
+
+## Publish
+
+For publishing, you only have to publish the resulting static file after build, which is usually the static file in the `dist` folder, to your cdn or static server. Note that the `index.html` usually will be an entry page for your backend service. You may need to change the page's import path after determining static for JS and css.
+
+::: tip
+In deployment may find that the resource path is wrong, just modify the `@/config/index.js` file resource path.
+:::
+
+```js
+// changes configure depending on your own path
+publicPath: './'
+```
+
+### Router & Server
+
+In adempiere-vue, the front-end routing uses `vue-router`, so you have two options:`browserHistory` and `hashHistory`.
+
+Simply speaking, the difference between them is the deal with routing. `hashHistory` is processed by the path following `#`, front-end routing management through [HTML 5 History](https://developer.mozilla.org/en-US/docs/Web/API/History_API), and `browserHistory` is similar to our usual page access path, and with not `#`, but must through the server's configuration.
+
+This project uses `hashHistory` by default, so if you have`#`in your url and you want to get rid of it, you need to switch to`browserHistory`.
+
+Modify `src/router/index.js` mode。
+
+```js
+export default new Router({
+ // mode: 'history' // Need backend support
+})
+```
+
+::: tip
+Detail see [vue-router document](https://router.vuejs.org/zh-cn/essentials/history-mode.html)
+:::
+
+## Deploy All Ecosystem
+
+### For all enviroment you should run the follow images:
+
+- [ADempiere gRPC](https://hub.docker.com/r/erpya/adempiere-grpc-all-in-one)
+
+```shell
+docker pull erpya/adempiere-grpc-all-in-one
+```
+
+- [Proxy ADempiere API](https://hub.docker.com/r/erpya/proxy-adempiere-api)
+
+```shell
+docker pull erpya/proxy-adempiere-api
+```
+
+- [ADempiere Vue](https://hub.docker.com/r/erpya/adempiere-vue)
+
+```shell
+docker pull erpya/adempiere-vue
+```
+
+- [ADempiere eCommerce](https://hub.docker.com/r/erpya/adempiere-ecommerce)
+
+```shell
+docker pull erpya/adempiere-ecommerce
+```
+
+### Run Docker Stack
+
+```yaml
+# docker-compose.yaml
+version: '3.7'
+
+services:
+ grpc-backend:
+ image: erpya/adempiere-grpc-all-in-one
+ container_name: adempiere-backend
+ stdin_open: true
+ tty: true
+ environment:
+ - SERVER_PORT=50059
+ - SERVICES_ENABLED=access; business; core; dashboarding; dictionary; enrollment; log; ui; workflow; store; pos; updater;
+ - SERVER_LOG_LEVEL=WARNING
+ - DB_HOST=postgres_host
+ - DB_PORT=5432
+ - DB_NAME=adempiere
+ - DB_USER=adempiere
+ - DB_PASSWORD=adempiere
+ - DB_TYPE=PostgreSQL
+ ports:
+ - 50059:50059
+
+ redis:
+ image: redis:4-alpine
+ container_name: adempiere-redis
+ stdin_open: true
+ tty: true
+ ports:
+ - '6379:6379'
+
+ es7:
+ image: docker.elastic.co/elasticsearch/elasticsearch:7.3.2
+ container_name: adempiere-eslastic-search
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ volumes:
+ - ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
+ ports:
+ - '9200:9200'
+ - '9300:9300'
+ environment:
+ - discovery.type=single-node
+ - cluster.name=docker-cluster
+ - bootstrap.memory_lock=true
+ - ES_JAVA_OPTS=-Xmx512m -Xms512m
+
+ api-rest:
+ image: erpya/proxy-adempiere-api
+ container_name: adempiere-proxy
+ depends_on:
+ - es7
+ - redis
+ stdin_open: true
+ tty: true
+ environment:
+ - SERVER_PORT=8085
+ - AD_DEFAULT_HOST=adempiere-backend
+ - AD_DEFAULT_PORT=50059
+ - ES_HOST=adempiere-eslastic-search
+ - ES_PORT=9200
+ - VS_ENV=dev
+ - INDEX=vue_storefront_catalog
+ - RESTORE_DB=N
+ ports:
+ - 8085:8085
+
+ vue-app:
+ image: erpya/adempiere-vue
+ container_name: adempiere-frontend
+ stdin_open: true
+ tty: true
+ environment:
+ - API_URL=http://adempiere-proxy:8085
+ ports:
+ - 9526:80
+
+ e-commerce:
+ image: erpya/adempiere-ecommerce
+ container_name: adempiere-ecommerce
+ stdin_open: true
+ tty: true
+ environment:
+ - SERVER_PORT=3000
+ - API_URL=http://adempiere-proxy:8085
+ - STORE_INDEX=vue_storefront_catalog
+ - VS_ENV=dev
+ ports:
+ - 3000:3000
+```
+
+Note: Eslastic Search container requires a config file `elasticsearch.yaml`.
+
+```shell
+# requires superuser permissions of the operating system ('su' or 'sudo')
+docker-compose up
+```
+
+Containers Running:
+
+- adempiere-backend
+- adempiere-redis
+- adempiere-eslastic-search
+- adempiere-proxy
+- adempiere-frontend
+- adempiere-ecommerce
diff --git a/docs/guide/essentials/env.md b/docs/guide/essentials/env.md
new file mode 100644
index 00000000..14485644
--- /dev/null
+++ b/docs/guide/essentials/env.md
@@ -0,0 +1,41 @@
+## Environment Variables
+
+`adempiere-vue` 4.0+ is built o `vue-cli`, so all environment variables are controlled based on `vue-cli`.
+
+[Official document](https://cli.vuejs.org/guide/mode-and-env.html)
+
+```
+.env # loaded in all cases
+.env.[mode] # only loaded in specified mode
+```
+
+An env file simply contains key=value pairs of environment variables:
+
+```
+FOO=bar
+VUE_APP_SECRET=secret
+```
+
+::: tip note! ! !
+Environment variables must start with `VUE_APP_`. Such as: `VUE_APP_API`, `VUE_APP_TITLE`
+
+You can access them in your application code:
+
+```js
+console.log(process.env.VUE_APP_xxxx)
+```
+
+:::
+
+In addition to `VUE_APP_*` variables, there are also two special variables that will always be available in your app code:
+
+- `NODE_ENV` - this will be one of "development"、"production" or "test" depending on the mode the app is running in.
+- `BASE_URL` - this corresponds to the `publicPath` option in `vue.config.js` and is the base path your app is deployed at.
+
+### Build related
+
+In addition to some environment variables written in `.env`, there are some build and deployment related variables that need to be configured in `vue.config.js`.
+
+You can set the different parameters by executing the judgment environment with `process.env.NODE_ENV`.
+
+Specific code can learn from [vue.config.js](https://github.com/adempiere/adempiere-vue/blob/master/vue.config.js)
diff --git a/docs/guide/essentials/import.md b/docs/guide/essentials/import.md
new file mode 100755
index 00000000..31484408
--- /dev/null
+++ b/docs/guide/essentials/import.md
@@ -0,0 +1,63 @@
+# Import Third-party Modules
+
+In addition to the element-ui components and the business components built into the scaffolding, sometimes we also need to import other external components.
+
+Here to import [vue-count-to](https://github.com/adempiere/vue-countTo) as an example to introduce.
+
+## Install dependence
+
+Enter the following command in the terminal to complete the installation:
+
+```bash
+$ npm install vue-count-to --save
+```
+
+> add `--save` will automatically add dependencies to package.json.
+
+
+
+## Usage
+
+### Global Registration
+
+**main.js**
+
+```js
+import countTo from 'vue-count-to'
+Vue.component('countTo', countTo)
+```
+
+```html
+
+
+
+```
+
+### Local Registration
+
+```html
+
+
+
+
+
+```
+
+
+
+
+
+## Use Any Javascript Library With Vue.js
+
+[Use Any Javascript Library With Vue.js](https://vuejsdevelopers.com/2017/04/22/vue-js-libraries-plugins/)
diff --git a/docs/guide/essentials/layout.md b/docs/guide/essentials/layout.md
new file mode 100755
index 00000000..e9468a7a
--- /dev/null
+++ b/docs/guide/essentials/layout.md
@@ -0,0 +1,115 @@
+# Layout
+
+The overall layout of the page is the outermost frame structure of a product and often includes navigation, sidebars, breadcrumbs, and content. To understand a admin project, first understand its basic layout.
+
+
+
+::: tip Code
+[@/layout](https://github.com/adempiere/adempiere-vue/tree/master/src/layout)
+:::
+
+`@` is webpack's [alias](https://webpack.js.org/configuration/resolve/#resolve-alias). If don't understand please study it yourself.
+
+
+
+Most of the pages in `adempiere-vue` are based on this `layout`, except that individual pages such as: `login` , `404`, `401` , etc., do not use this layout. It is also easy if you want to have multiple layouts in a project, as long as you choose different layout component in the first-level routing.
+
+```js
+// No layout
+{
+ path: '/401',
+ component: () => import('errorPage/401')
+}
+
+// Has layout
+{
+ path: '/documentation',
+
+ // You can choose different layout components
+ component: Layout,
+
+ // Here the route is displayed in app-main
+ children: [{
+ path: 'index',
+ component: () => import('documentation/index'),
+ name: 'documentation'
+ }]
+}
+```
+
+This uses vue-router [routing nesting](https://router.vuejs.org/guide/essentials/nested-routes.html), so in general, adding or modifying a page will only affect the main body of app-main. Other content in the layout, such as: the sidebar or navigation bar will not change with your main page.
+
+```
+/foo /bar
++------------------+ +-----------------+
+| layout | | layout |
+| +--------------+ | | +-------------+ |
+| | foo.vue | | +------------> | | bar.vue | |
+| | | | | | | |
+| +--------------+ | | +-------------+ |
++------------------+ +-----------------+
+```
+
+
+
+## app-main
+
+::: tip Code
+[@/layout/components/AppMain](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/AppMain.vue)
+:::
+
+Here is a layer of `keep-alive` outside the `app-main` is mainly to cache ``, with the `tabs-view` tab navigation of the page, if you do not need to [remove](tags-view.md) it.
+
+The `transition` defines the switching animation between pages, you can modify the transition animation according to your own needs. Related [documentation](https://vuejs.org/v2/guide/transitions.html).
+Two transition animations of `fade` and `fade-transform` are provided by default. For specific css implementation, see [transition.scss](https://github.com/adempiere/adempiere-vue/blob/master/src /styles/transition.scss). If you need to adjust, you can adjust the `name` of `transition` in [AppMain.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/AppMain.vue).
+
+
+
+## router-view
+
+**Different router the same component vue** In a real work, there are many situations. such as:
+
+
+
+The same component is used to create pages and edit pages. By default, when these two pages are switched, it will not trigger the created or mounted hooks of vue. [Officials say](https://router.vuejs.org/guide/advanced/data-fetching.html#data-fetching) that you can do this through the change of watch `$route`. To tell the truth it's still very troublesome. Later I discovered that I could simply add a unique key to the router-view to ensure that the routing hooks are re-rendered when the route is switched. This is much simpler.
+
+```js
+
+
+computed: {
+ key() {
+ // just make sure the key is the unique
+ return this.$route.fullPath
+ }
+ }
+```
+
+::: tip
+**Or** You can declare two different views like the `editForm` and `createForm` in this project but introduce the same component.
+
+Code: [@/views/example](https://github.com/adempiere/adempiere-vue/tree/master/src/views/example)
+:::
+
+```html
+
+
+ //create
+
+
+
+
+
+ //edit
+
+
+```
+
+## Mobile
+
+The `element-ui` official position is the desktop-side framework, and most of admin project is complex, it is impossible to meet the desktop-side and mobile-side interactions through simple adaptation. Therefore, the interaction between the two ends must be different. it is recommended to re-do a system for mobile.
+
+So, this project will not adapt to the mobile. It just does a simple response and you can modify it yourself.
diff --git a/docs/guide/essentials/mock-api.md b/docs/guide/essentials/mock-api.md
new file mode 100755
index 00000000..f0d521ff
--- /dev/null
+++ b/docs/guide/essentials/mock-api.md
@@ -0,0 +1,202 @@
+# Mock Data
+
+Mock data is an integral part of the front-end development, the key link to separate the front and back-end development. By pre-agreed with the server-side interface, analog request data and even logic, can make the front-end development independent, will not be blocked by the development of the server.
+
+## Swagger
+
+In my company project, the data is usually simulated by the backend using [swagger](https://swagger.io/).
+
+**swagger** is a REST APIs document generation tool that automatically generates documentation from code comments. It can be cross-platform, open source, supports most languages, community is good, in short, very good, highly recommended.
+
+[Online Demo](http://petstore.swagger.io/?_ga=2.222649619.983598878.1509960455-2044209180.1509960455#/pet/addPet)
+
+## Easy-mock
+
+[vue-admin-template](https://github.com/adempiere/vue-admin-template) previously used [easy-mock](https://easy-mock.com/login) to simulate data.
+It is a pure front-end visualization and can quickly generate persistence services for analog data. Very easy to use and can also be combined with `swagger`, support for cross-domain, whether it is a team or a personal project is worth a try.
+
+[Online Demo](https://easy-mock.com/)
+
+::: warning
+The online version of `vue-admin-template` is no longer using `easy-mock`. Because the online free service provided by `easy-mock` is very unstable, it will hang from time to time. If you need it, you can build your own service according to its tutorial.
+:::
+
+## Mockjs
+
+Since [adempiere-vue](https://github.com/adempiere/adempiere-vue) is a pure front-end personal project, all data is [mockjs] (https://github.com/ Nuysoft/Mock) Simulation generation. Its principle is: Intercept all requests and proxy to the local, and then mock data, so you will find that no requests are issued in `network`.
+
+But its biggest problem is its implementation mechanism. It overrides the browser's `XMLHttpRequest` object to intercept all requests and proxy to the local. In most cases it is quite convenient to use, but because it rewrites the `XMLHttpRequest` object, so for example, the `progress` method, or some third-party libraries that rely on `XMLHttpRequest` will be incompatible with it. Looking at my project's [issues](https://github.com/adempiere/adempiere-vue/issues?utf8=%E2%9C%93&q=mock), you will know how many people have problems.
+
+It also has a problem because it is data that is simulated locally and does not actually take any network requests. Therefore, local debugging is very troublesome and can only be debugged by `console.log`. Take the example of `adempiere-vue`. If you want to find out what data is returned by the `getInfo()` api, you can only know it by looking at the source code or manually `Debug`.
+
+## New way
+
+After the `v4.0` version, a `mock-server` will be launched locally to simulate the data, and the online environment will continue to use `mockjs` for simulation.(Because this project is a pure front-end project, you can also build an online server to provide data.)
+
+The advantage of this way is to solve the previous pain points while preserving the advantages of `mockjs`. Since our mock is implemented entirely based on `webpack-dev-serve`, `mock-server` will start automatically when you start the project, and it will also pass [chokidar](https://github.com/paulmillr/chokidar) to observe the changes in the contents of the `mock` folder. When a change occurs, the previously registered `mock-api` interface is cleared and the new interface is dynamically remounted to support hot updates. If you are interested, you can look at the code [mock-server.js](https://github.com/adempiere/adempiere-vue/blob/master/mock/mock-server.js). Since it is a real `server`, you can clearly know the data structure returned by the interface through `network` of Chrome. At the same time, it solves the problem that the previous `mockjs` will rewrite the `XMLHttpRequest` object, which causes many third-party libraries to fail.
+
+All requests for this project are sent via the packaged [request.js](https://github.com/adempiere/adempiere-vue/blob/master/src/utils/request.js) by reading The source code can find that all requests are set to a `baseURL`, and this `baseURL` is dynamically set by reading the `process.env.VUE_APP_BASE_API` environment variable, so that we can use different environments for different environments. Api` address
+
+## Remove
+
+If you don't want to use `mock-server`, just the `after` Middleware of `webpack-dev-server` from [vue.config.js](https://github.com/adempiere/adempiere-vue/blob/master/vue.config.js).
+
+By default, local requests are proxy to `http://localhost:${port}/mock`, and you can modify `proxy` if you want to adjust to your own mock address.
+
+```js
+proxy: {
+ // change xxx-api/login => mock/login
+ // detail: https://cli.vuejs.org/config/#devserver-proxy
+ [process.env.VUE_APP_BASE_API]: {
+ target: `http://localhost:${port}/mock`,
+ changeOrigin: true,
+ pathRewrite: {
+ ['^' + process.env.VUE_APP_BASE_API]: ''
+ }
+ }
+},
+after: require('./mock/mock-server.js')
+```
+
+**Please note: this operation requires a restart of the server.**
+
+## Add
+
+If you want to add mock data, just find the `mock` file in the root folder, add the corresponding route, intercept it and simulate the data.
+
+For example, I need to add an api to get the number of comments below an article in [src/api/article](https://github.com/adempiere/adempiere-vue/blob/master/src/api/article.js) through `fetchComments`. First create a new api:
+
+```js
+export function fetchComments(id) {
+ return request({
+ url: `/article/${id}/comments`,
+ method: 'get'
+ })
+}
+```
+
+After declaring the api, we need to find the corresponding mock folder [mock/article.js](https://github.com/adempiere/adempiere-vue/blob/master/mock/article.js), below Create a mock api that intercepts routes.
+
+**Please note that the mock interception is based on routing. Please make sure that the mock data path will match your api route path(support regular)**
+
+```js
+// fetchComments 的 mock
+{
+ // uUrl must match your api route
+ // For example, the route of fetchComments may be /article/1/comments or /article/2/comments
+ // So you need to match by regular
+ url: '/article/[A-Za-z0-9]/comments',
+ type: 'get', // Must be the same type as your interface defines
+ response: (req, res) => {
+ // return result
+ // req and res detail see
+ // https://expressjs.com/zh-cn/api.html#req
+ return {
+ code: 20000,
+ data: {
+ status: 'success'
+ }
+ }
+ }
+}
+```
+
+## Change
+
+The most common operation is: You have simulated some data locally, and after the backend completes the api, it gradually replaces the api of the original mock.
+
+Let's take the `getRoles` api in [src/api/role.js](https://github.com/adempiere/adempiere-vue/blob/master/src/api/role.js) as an example. It was originally mocked in [mock/role/index.js](https://github.com/adempiere/adempiere-vue/blob/master/mock/role/index.js). Now we need to switch it to real backend data, as long as it is in [mock/role/index.js](https://github.com/adempiere/adempiere-vue/blob/master/mock/role/index.js) Find the corresponding route, then delete it. At this time you can view the real data in `network`.
+
+```js
+// The declared in the api
+export function getRoles() {
+ return request({
+ url: '/roles',
+ method: 'get'
+ })
+}
+
+// Find the corresponding route and delete
+{
+ url: '/roles',
+ type: 'get',
+ response: _ => {
+ return {
+ code: 20000,
+ data: roles
+ }
+ }
+ },
+```
+
+## Multiple servers
+
+Currently the project only starts a `mock-server`, of course you can also have your own other `mock-server` or proxy interface. Some api can take this service, others can take another service. Just set them to a different `baseURL`. [@/utils/request.js](https://github.com/adempiere/adempiere-vue/blob/master/src/utils/request.js)
+
+Then configure multiple `proxy` according to the set url rules in [vue.config.js](https://github.com/adempiere/adempiere-vue/blob/master/vue.config.js).
+
+[相关文档](https://webpack.docschina.org/configuration/dev-server/#devserver-proxy)
+
+## Enable pure front end Mock
+
+Now in [mock/index.js](https://github.com/adempiere/adempiere-vue/blob/master/mock/index.js#L19) also encapsulates a pure front-end mock method, you only Need to be in [src/main.js](https://github.com/adempiere/adempiere-vue/tree/master/src):
+
+```js
+import { mockXHR } from '../mock'
+mockXHR()
+```
+
+This will become pure front-end mock data and the same as the mock way before the `v4.0` version, the principle is as above. The online [demo](https://adempiere.github.io/adempiere-vue) that you are currently seeing is just that way.
+
+## Switch local and online Mock data
+
+There are many times when we encounter local use of mock data, online environments that use real data, or different environments that use different data.
+
+- **Easy-Mock**
+
+You need to ensure that your local simulated api is consistent with all other addresses except the root path. such as:
+
+```
+https://api-dev/login // Local request
+
+https://api-prod/login // Online request
+```
+
+We can use the [environment variables](/guide/essentials/deploy.html#environmental-variables) to do different environments and request different api base path.
+
+```bash
+# .env.development
+VUE_APP_BASE_API = '/dev-api' #Inject the root path of the local api
+```
+
+```bash
+# .env.production
+VUE_APP_BASE_API = '/prod-api' #Inject the root path of the production api
+```
+
+Then create an `axios` instance based on the environment variable to have a different `baseURL`.
+[@/utils/request.js](https://github.com/adempiere/adempiere-vue/blob/master/src/utils/request.js)
+
+```js
+// create an axios instance
+const service = axios.create({
+ baseURL: process.env.BASE_API, // base_url of the API
+ timeout: 5000 // request timeout
+})
+```
+
+In this way we can automatically switched local and online apis based on environment variables.
+
+- **Mock.js**
+
+When we use `Mock.js` to simulate data locally, the real-world api method is used online. This is similar to the easy-mock method above. We mainly judge that when it is an online environment, we use real-world api. We only import `Mock.js` locally.
+
+```js
+// main.js
+// use environment variables to determine is required
+if (process.env.NODE_ENV === 'development') {
+ require('./mock') // simulation data
+}
+```
+
+Mock data is only import in the local environment.
diff --git a/docs/guide/essentials/new-page.md b/docs/guide/essentials/new-page.md
new file mode 100755
index 00000000..3ea44ae1
--- /dev/null
+++ b/docs/guide/essentials/new-page.md
@@ -0,0 +1,144 @@
+# New Page
+
+If you are familiar with the `vue-router` then it will be very simple.
+
+First add the route to the `@/router/index.js`.
+
+**Such as: add an excel page**
+
+```js
+{
+ path: '/excel',
+ component: Layout,
+ redirect: '/excel/export-excel',
+ name: 'excel',
+ meta: {
+ title: 'excel',
+ icon: 'excel'
+ }
+}
+```
+
+::: tip
+It just creates a blank route based on 'layout', and you also need to add a route to the 'children' below it.
+:::
+
+```js
+{
+ path: '/excel',
+ component: Layout,
+ redirect: '/excel/export-excel',
+ name: 'excel',
+ meta: {
+ title: 'excel',
+ icon: 'excel'
+ },
+ children: [
+ {
+ path: 'export-excel',
+ component: ()=>import('excel/exportExcel'),
+ name: 'exportExcel',
+ meta: { title: 'exportExcel' }
+ }
+ ]
+}
+```
+
+**This sidebar will appear the menu-item**
+
+
+
+
+
+:::tip
+Since `children` only declares one route below, there will be no expansion arrow. If the number of routes under `children` is greater than 1, there will be an expansion arrow, as shown below.
+
+If you want to ignore this automatic decision, you can use `alwaysShow: true`, so that it will ignore the previously defined rule and display the root route. See the [Router and Nav](router-and-nav.md) for details.
+
+:::
+
+```js
+{
+ path: '/excel',
+ component: Layout,
+ redirect: '/excel/export-excel',
+ name: 'excel',
+ meta: {
+ title: 'excel',
+ icon: 'excel'
+ },
+ children: [
+ { path: 'export-excel', component:()=>import('excel/exportExcel'), name: 'exportExcel', meta: { title: 'exportExcel' }},
+ { path: 'export-selected-excel', component:()=>import('excel/selectExcel'), name: 'selectExcel', meta: { title: 'selectExcel' }},
+ { path: 'upload-excel', component:()=>import('excel/uploadExcel'), name: 'uploadExcel', meta: { title: 'uploadExcel' }}
+ ]
+}
+```
+
+
+
+**The sidebar will appear the `submenu`.**
+
+
+
+## Nested Routes
+
+If you have a nested Route, such as [@/views/nested](https://github.com/adempiere/adempiere-vue/tree/master/src/views/nested),
+**Don't forget to manually add an `< router-view >` to the root file of the secondary directory**.
+
+```html
+
+
+
+
+
+
+
+```
+
+Such as: [@/views/nested/menu1/index.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/views/nested/menu1/index.vue).
+
+**Note:** As many `` as the level of routes nested.
+
+
+
+
+
+## Create View
+
+After adding the route, create a view under the `@/views`. As usual, a router correspond
+a view.
+
+Suggestion if a component or utils function only used in this view, just create a component folder under this view, lt is more convenient for each module to maintain its own `utils` or `components`.
+
+
+
+
+
+## Create Api
+
+Finally, under the [@/api](https://github.com/adempiere/adempiere-vue/tree/master/src/api) folder, create the corresponding api service for this module.
+
+## Create Component
+
+Personally write vue project habits, the global `@/components` will only write some global components, such as rich text, various search components, packaged date components, etc. can be shared components. Each page or module-specific business component is written under the current views. Such as: `@/views/article/components/xxx.vue`. This split greatly reduces maintenance costs.
+
+**Remember that the biggest benefit of splitting components is not shared code but maintainability! **
+
+## Create Style
+
+The page's style and components are the same. The global `@/style` writes a global common style. The style of each page is written under the current `views`. Please remember to add `scoped` or namespace to avoid Causes global style pollution.
+
+```css
+
+
+
+```
diff --git a/docs/guide/essentials/permission.md b/docs/guide/essentials/permission.md
new file mode 100755
index 00000000..bae87d27
--- /dev/null
+++ b/docs/guide/essentials/permission.md
@@ -0,0 +1,79 @@
+# Permission
+
+It has been introduced in detail in this article--[手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac).
+
+The implementation of this project's permission is: compare the routing table by obtaining the current user's permission, and generate the routing table accessible by the current user with the permission, and dynamically mount it to `router` through `router.addRoutes`.
+
+But in fact, the business logic of many companies may not be the case. For example, the requirement of many companies is that the permissions of each page are dynamically configured, unlike the default settings in this project. But in fact the principle is the same. For example, you can dynamically configure permissions for each page through a tree control or other presentation, and then store this routing table to the back end. When the user logs in to get `roles`, the front end requests the accessible routing table to the backend according to `roles`, so that the accessible pages are dynamically generated. After that, the router.addRoutes is dynamically mounted to the router. You will find the same. , never change their case.
+
+Just one more step to map the back-end return routing table with the local components. [issue](https://github.com/adempiere/adempiere-vue/issues/293)
+
+```js
+const map={
+ login:require('login/index').default // sync
+ login:()=>import('login/index') // async
+}
+// The map on which you have a server is similar with
+const serviceMap=[
+ { path: '/login', component: 'login', hidden: true }
+]
+// After traversing this map, dynamically generate asyncRoutes
+And replace component with map[component]
+```
+
+Ps: Do not rule out this project will increase the permissions control panel to support true dynamic configuration permissions.
+
+## Logical modification
+
+The control code of the routing level right now is in `@/permission.js`. If you want to change the logic, you can release the hook `next()` directly in the appropriate judgment logic.
+
+## Permission directive
+
+Write a permission directive, and can easily and quickly implement button-level permission judgment. [v-permission](https://github.com/adempiere/adempiere-vue/tree/master/src/directive/permission)
+
+**Use**
+
+```html
+
+
+ admin
+
+
+ editor
+
+
+ Both admin or editor can see this
+
+
+
+```
+
+**Limitations**
+
+In some cases it is not suitable to use v-permission, such as element Tab component which can only be achieved by manually setting the v-if.
+
+You can use the global permission judgment function. The usage is similar to the instruction `v-permission`.
+
+```html
+
+ Admin can see this
+ Editor can see this
+ Both admin or editor can see this
+
+
+
+```
diff --git a/docs/guide/essentials/router-and-nav.md b/docs/guide/essentials/router-and-nav.md
new file mode 100755
index 00000000..b7cddcf5
--- /dev/null
+++ b/docs/guide/essentials/router-and-nav.md
@@ -0,0 +1,310 @@
+# Router and Nav
+
+Router and Nav are the key skeleton for organizing a management system.
+
+This project router and nav are bound together, so you only have to configure the route under `@/router/index.js` and the sidebar nav will be dynamically generated automatically. This greatly reduces the workload of manually editing the sidebar nav. Of course, so you need to follow many conventions in configuring the route.
+
+## Config
+
+First let us know what configuration items are provided config route.
+
+```js
+// if set to true, lt will not appear in sidebar nav.
+// e.g. login or 401 page or as some editing pages /edit/1 (Default: false)
+hidden: true
+
+// this route cannot be clicked in breadcrumb navigation when noRedirect is set
+redirect: noRedirect
+
+// when you route a children below the declaration of more than one route,
+// it will automatically become a nested mode - such as the component page
+// when there is only one, the child route will be displayed as the root route
+// if you want to display your root route
+// regardless of the number of children declarations under the route
+// you can set alwaysShow: true
+// so that it will ignore the previously defined rules and always show the root route
+alwaysShow: true
+
+// set router name. It must be set,in order to avoid problems with .
+name: 'router-name'
+
+meta: {
+ // required roles to navigate to this route. Support multiple permissions stacking.
+ // if not set means it doesn't need any permission.
+ roles: ['admin', 'editor']
+
+ // the title of the route to show in various components (e.g. sidebar, breadcrumbs).
+ title: 'title'
+
+ // svg icon class
+ icon: 'svg-name' // or el-icon-x
+
+ // when set true, the route will not be cached by (default false)
+ noCache: true
+
+ // if false, the item will hidden in breadcrumb(default is true)
+ breadcrumb: false
+
+ // if set to true, it can be fixed in tags-view (default false)
+ affix: true // this is very useful in some scenarios, // click on the article to enter the article details page,
+
+ // When you set, the related item in the sidebar will be highlighted
+ // for example: a list page route of an article is: /article/list
+ // at this time the route is /article/1, but you want to highlight the route of the article list in the sidebar,
+ // you can set the following
+ activeMenu: '/article/list'
+}
+```
+
+
+
+**Example:**
+
+```js
+{
+ path: '/permission',
+ component: Layout,
+ redirect: '/permission/index',
+ hidden: true,
+ alwaysShow: true,
+ meta: { roles: ['admin','editor'] }, // you can set roles in root nav
+ children: [{
+ path: 'index',
+ component: _import('permission/index'),
+ name: 'permission',
+ meta: {
+ title: 'permission',
+ icon: 'lock',
+ roles: ['admin','editor'], // or you can only set roles in sub nav
+ noCache: true
+ }
+ }]
+}
+```
+
+## Router
+
+There are two types of routes here , `constantRoutes` and `asyncRoutes`.
+
+**constantRoutes:** represents routes that do not require dynamic access, such as login page, 404, general page, and so on.
+
+**asyncRoutes:** represents pages that require dynamic judgment permissions and are dynamically added through `addRouters`. The details will be introduced on the [permission](permission.md).
+
+::: tip
+All routing pages here use the `router lazy loading`, as described in [document](/guide/advanced/lazy-loading.md)
+
+If you want to know more about browserHistory and hashHistory, please refer to [Build & Deploy](deploy.md).
+:::
+
+The other configurations are no different from the [vue-router](https://router.vuejs.org/en/) official, so check the documentation for yourself.
+
+::: warning
+There is one thing to be careful about is that the 404 page must be the last to load, if it is declared in constantRoutes. Later declared pages will be blocked to 404, see the details of the problem: [addRoutes when you've got a wildcard route for 404s does not work](https://github.com/vuejs/vue-router/issues/1176)
+:::
+
+## Sidebar
+
+The project sidebar is mainly based on the `el-menu` of element-ui.
+
+Also introduced in the front, the sidebar is generated dynamically by reading the route and combined with the permission judge, but also need to support the infinite nesting of routes, so here is also used to the recursive components.
+
+> Code: [@/layout/components/Sidebar](https://github.com/adempiere/adempiere-vue/tree/master/src/layout/components/Sidebar)
+
+This also modify many default sidebar styles of `element-ui`. All css can be found in [@/styles/sidebar.scss](https://github.com/adempiere/adempiere-vue/blob/master/src/styles/sidebar.scss) and can be modified to suit your needs.
+
+**Here need to pay attention**. The general sidebar has two forms, `submenu` and`el-menu-item`. One is a nested submenu, the other is a direct link. As shown below:
+
+
+
+The sidebar has already helped you to make a judgment. When you route a children below the declaration of more than >1 routes, it will automatically become a nested mode. If the sub-route is exactly equal to one, the sub-route is displayed as a root route in the sidebar by default. If you do not want to, you can disable this feature by setting `alwaysShow: true` in the root route. Such as:
+
+```js
+// no submenu, because children.length===1
+{
+ path: '/icon',
+ component: Layout,
+ children: [{
+ path: 'index',
+ component: ()=>import('svg-icons/index'),
+ name: 'icons',
+ meta: { title: 'icons', icon: 'icon'}
+ }]
+},
+
+// has submenu, because children.length>=1
+{
+ path: '/components',
+ component: Layout,
+ name: 'component-demo',
+ meta: {
+ title: 'components',
+ icon: 'component'
+ },
+ children: [
+ { path: 'tinymce', component: ()=>import('components-demo/tinymce'), name: 'tinymce-demo', meta: { title: 'tinymce' }},
+ { path: 'markdown', component: ()=>import('components-demo/markdown'), name: 'markdown-demo', meta: { title: 'markdown' }},
+ ]
+}
+```
+
+::: tip unique-opened
+You can set `unique-opened` in [Sidebar/index.vue](https://github.com/adempiere/adempiere-vue/blob/master/src/layout/components/Sidebar/index.vue). To control the sidebar, whether to keep only one submenu expanded.
+:::
+
+## Nested Routes
+
+If you have a nested Route, such as [@/views/nested](https://github.com/adempiere/adempiere-vue/tree/master/src/views/nested),
+**Don't forget to manually add an `< router-view >` to the root file of the secondary directory**.
+
+```html
+
+
+