commit
7466c2be8d
|
@ -198,6 +198,14 @@ If you find this project useful, you can buy author a glass of juice :tropical_d
|
|||
|
||||
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
|
||||
|
||||
## Browsers support
|
||||
|
||||
Modern browsers and Internet Explorer 10+.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||
| --------- | --------- | --------- | --------- |
|
||||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||
|
|
|
@ -210,6 +210,14 @@ Detailed changes for each release are documented in the [release notes](https://
|
|||
|
||||
[Paypal Me](https://www.paypal.me/panfree23)
|
||||
|
||||
## Browsers support
|
||||
|
||||
Modern browsers and Internet Explorer 10+.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||
| --------- | --------- | --------- | --------- |
|
||||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||
|
|
|
@ -58,8 +58,10 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
|||
inject: true,
|
||||
favicon: resolve('favicon.ico'),
|
||||
title: 'vue-element-admin',
|
||||
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
|
||||
})
|
||||
templateParameters: {
|
||||
BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory,
|
||||
},
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
@ -56,7 +56,9 @@ const webpackConfig = merge(baseWebpackConfig, {
|
|||
inject: true,
|
||||
favicon: resolve('favicon.ico'),
|
||||
title: 'vue-element-admin',
|
||||
path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
|
||||
templateParameters: {
|
||||
BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory,
|
||||
},
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<title>vue-element-admin</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js></script>
|
||||
<script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vue-element-admin",
|
||||
"version": "3.9.0",
|
||||
"version": "3.9.1",
|
||||
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
||||
"author": "Pan <panfree23@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
@ -94,6 +94,7 @@
|
|||
"node-sass": "^4.7.2",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.0",
|
||||
"ora": "3.0.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"portfinder": "1.0.13",
|
||||
"postcss-import": "11.1.0",
|
||||
"postcss-loader": "2.1.6",
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
<script>
|
||||
import { generateTitle } from '@/utils/i18n'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
@ -29,7 +30,15 @@ export default {
|
|||
methods: {
|
||||
generateTitle,
|
||||
getBreadcrumb() {
|
||||
let matched = this.$route.matched.filter(item => item.name)
|
||||
const { params } = this.$route
|
||||
let matched = this.$route.matched.filter(item => {
|
||||
if (item.name) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
var toPath = pathToRegexp.compile(item.path)
|
||||
item.path = toPath(params)
|
||||
return true
|
||||
}
|
||||
})
|
||||
const first = matched[0]
|
||||
if (first && first.name.trim().toLocaleLowerCase() !== 'Dashboard'.toLocaleLowerCase()) {
|
||||
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item :disabled="language==='zh'" command="zh">中文</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="language==='en'" command="en">English</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="language==='es'" command="es">Español</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
export default {
|
||||
route: {
|
||||
dashboard: 'Panel de control',
|
||||
introduction: 'Introducción',
|
||||
documentation: 'Documentación',
|
||||
guide: 'Guía',
|
||||
permission: 'Permisos',
|
||||
pagePermission: 'Permisos de la página',
|
||||
directivePermission: 'Permisos de la directiva',
|
||||
icons: 'Iconos',
|
||||
components: 'Componentes',
|
||||
componentIndex: 'Introducción',
|
||||
tinymce: 'Tinymce',
|
||||
markdown: 'Markdown',
|
||||
jsonEditor: 'Editor JSON',
|
||||
dndList: 'Lista Dnd',
|
||||
splitPane: 'Panel dividido',
|
||||
avatarUpload: 'Subir avatar',
|
||||
dropzone: 'Subir ficheros',
|
||||
sticky: 'Sticky',
|
||||
countTo: 'CountTo',
|
||||
componentMixin: 'Mixin',
|
||||
backToTop: 'Ir arriba',
|
||||
dragDialog: 'Drag Dialog',
|
||||
dragKanban: 'Drag Kanban',
|
||||
charts: 'Gráficos',
|
||||
keyboardChart: 'Keyboard Chart',
|
||||
lineChart: 'Gráfico de líneas',
|
||||
mixChart: 'Mix Chart',
|
||||
example: 'Ejemplo',
|
||||
nested: 'Rutas anidadass',
|
||||
menu1: 'Menu 1',
|
||||
'menu1-1': 'Menu 1-1',
|
||||
'menu1-2': 'Menu 1-2',
|
||||
'menu1-2-1': 'Menu 1-2-1',
|
||||
'menu1-2-2': 'Menu 1-2-2',
|
||||
'menu1-3': 'Menu 1-3',
|
||||
menu2: 'Menu 2',
|
||||
Table: 'Tabla',
|
||||
dynamicTable: 'Tabla dinámica',
|
||||
dragTable: 'Arrastrar tabla',
|
||||
inlineEditTable: 'Editor',
|
||||
complexTable: 'Complex Table',
|
||||
treeTable: 'Tree Table',
|
||||
customTreeTable: 'Custom TreeTable',
|
||||
tab: 'Pestaña',
|
||||
form: 'Formulario',
|
||||
createArticle: 'Crear artículo',
|
||||
editArticle: 'Editar artículo',
|
||||
articleList: 'Listado de artículos',
|
||||
errorPages: 'Páginas de error',
|
||||
page401: '401',
|
||||
page404: '404',
|
||||
errorLog: 'Registro de errores',
|
||||
excel: 'Excel',
|
||||
exportExcel: 'Exportar a Excel',
|
||||
selectExcel: 'Export seleccionado',
|
||||
uploadExcel: 'Subir Excel',
|
||||
zip: 'Zip',
|
||||
exportZip: 'Exportar a Zip',
|
||||
theme: 'Tema',
|
||||
clipboardDemo: 'Clipboard',
|
||||
i18n: 'I18n',
|
||||
externalLink: 'Enlace externo'
|
||||
},
|
||||
navbar: {
|
||||
logOut: 'Salir',
|
||||
dashboard: 'Panel de control',
|
||||
github: 'Github',
|
||||
screenfull: 'Pantalla completa',
|
||||
theme: 'Tema',
|
||||
size: 'Tamaño global'
|
||||
},
|
||||
login: {
|
||||
title: 'Formulario de acceso',
|
||||
logIn: 'Acceso',
|
||||
username: 'Usuario',
|
||||
password: 'Contraseña',
|
||||
any: 'nada',
|
||||
thirdparty: 'Conectar con',
|
||||
thirdpartyTips: 'No se puede simular en local, así que combine su propia simulación de negocios. ! !'
|
||||
},
|
||||
documentation: {
|
||||
documentation: 'Documentación',
|
||||
github: 'Repositorio Github'
|
||||
},
|
||||
permission: {
|
||||
roles: 'Tus permisos',
|
||||
switchRoles: 'Cambiar permisos'
|
||||
},
|
||||
guide: {
|
||||
description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
|
||||
button: 'Ver guía'
|
||||
},
|
||||
components: {
|
||||
documentation: 'Documentación',
|
||||
tinymceTips: '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. See documentation for more detailed rich text editor comparisons and introductions.',
|
||||
dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
|
||||
stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
|
||||
backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
|
||||
backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally',
|
||||
imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.'
|
||||
},
|
||||
table: {
|
||||
dynamicTips1: 'Fixed header, sorted by header order',
|
||||
dynamicTips2: 'Not fixed header, sorted by click order',
|
||||
dragTips1: 'Orden por defecto',
|
||||
dragTips2: 'The after dragging order',
|
||||
title: 'Título',
|
||||
importance: 'Importancia',
|
||||
type: 'Tipo',
|
||||
remark: 'Remark',
|
||||
search: 'Buscar',
|
||||
add: 'Añadir',
|
||||
export: 'Exportar',
|
||||
reviewer: 'reviewer',
|
||||
id: 'ID',
|
||||
date: 'Fecha',
|
||||
author: 'Autor',
|
||||
readings: 'Lector',
|
||||
status: 'Estado',
|
||||
actions: 'Acciones',
|
||||
edit: 'Editar',
|
||||
publish: 'Publicar',
|
||||
draft: 'Draft',
|
||||
delete: 'Eliminar',
|
||||
cancel: 'Cancelar',
|
||||
confirm: 'Confirmar'
|
||||
},
|
||||
errorLog: {
|
||||
tips: 'Please click the bug icon in the upper right corner',
|
||||
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
|
||||
documentation: 'Documento de introducción'
|
||||
},
|
||||
excel: {
|
||||
export: 'Exportar',
|
||||
selectedExport: 'Exportar seleccionados',
|
||||
placeholder: 'Por favor escribe un nombre de fichero'
|
||||
},
|
||||
zip: {
|
||||
export: 'Exportar',
|
||||
placeholder: 'Por favor escribe un nombre de fichero'
|
||||
},
|
||||
theme: {
|
||||
change: 'Cambiar tema',
|
||||
documentation: 'Documentación del tema',
|
||||
tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.'
|
||||
},
|
||||
tagsView: {
|
||||
refresh: 'Actualizar',
|
||||
close: 'Cerrar',
|
||||
closeOthers: 'Cerrar otros',
|
||||
closeAll: 'Cerrar todos'
|
||||
}
|
||||
}
|
|
@ -3,8 +3,10 @@ import VueI18n from 'vue-i18n'
|
|||
import Cookies from 'js-cookie'
|
||||
import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang
|
||||
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang
|
||||
import elementEsLocale from 'element-ui/lib/locale/lang/es'// element-ui lang
|
||||
import enLocale from './en'
|
||||
import zhLocale from './zh'
|
||||
import esLocale from './es'
|
||||
|
||||
Vue.use(VueI18n)
|
||||
|
||||
|
@ -16,12 +18,16 @@ const messages = {
|
|||
zh: {
|
||||
...zhLocale,
|
||||
...elementZhLocale
|
||||
},
|
||||
es: {
|
||||
...esLocale,
|
||||
...elementEsLocale
|
||||
}
|
||||
}
|
||||
|
||||
const i18n = new VueI18n({
|
||||
// set locale
|
||||
// options: en or zh
|
||||
// options: en | zh | es
|
||||
locale: Cookies.get('language') || 'en',
|
||||
// set locale messages
|
||||
messages
|
||||
|
|
|
@ -4,6 +4,16 @@ import articleAPI from './article'
|
|||
import remoteSearchAPI from './remoteSearch'
|
||||
import transactionAPI from './transaction'
|
||||
|
||||
// 修复在使用 MockJS 情况下,设置 withCredentials = true,且未被拦截的跨域请求丢失 Cookies 的问题
|
||||
// https://github.com/nuysoft/Mock/issues/300
|
||||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
|
||||
Mock.XHR.prototype.send = function() {
|
||||
if (this.custom.xhr) {
|
||||
this.custom.xhr.withCredentials = this.withCredentials || false
|
||||
}
|
||||
this.proxy_send(...arguments)
|
||||
}
|
||||
|
||||
// Mock.setup({
|
||||
// timeout: '350-600'
|
||||
// })
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
.is-active > .el-submenu__title{
|
||||
color: #f4f4f5!important;
|
||||
}
|
||||
}
|
||||
.hideSidebar {
|
||||
.sidebar-container {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// translate router.meta.title, be used in breadcrumb sidebar tagsview
|
||||
export function generateTitle(title) {
|
||||
const hasKey = this.$te('route.' + title)
|
||||
const translatedTitle = this.$t('route.' + title) // $t :this method from vue-i18n, inject in @/lang/index.js
|
||||
|
||||
if (hasKey) {
|
||||
// $t :this method from vue-i18n, inject in @/lang/index.js
|
||||
const translatedTitle = this.$t('route.' + title)
|
||||
|
||||
return translatedTitle
|
||||
}
|
||||
return title
|
||||
|
|
|
@ -296,3 +296,7 @@ export function deepClone(source) {
|
|||
export function uniqueArr(arr) {
|
||||
return Array.from(new Set(arr))
|
||||
}
|
||||
|
||||
export function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
/* eslint-disable */
|
||||
/* Blob.js
|
||||
* A Blob implementation.
|
||||
* 2014-05-27
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
* By Devin Samarin, https://github.com/eboyjr
|
||||
* License: X11/MIT
|
||||
* See LICENSE.md
|
||||
*/
|
||||
|
||||
/*global self, unescape */
|
||||
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
|
||||
plusplus: true */
|
||||
|
||||
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
|
||||
|
||||
(function (view) {
|
||||
"use strict";
|
||||
|
||||
view.URL = view.URL || view.webkitURL;
|
||||
|
||||
if (view.Blob && view.URL) {
|
||||
try {
|
||||
new Blob;
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Internally we use a BlobBuilder implementation to base Blob off of
|
||||
// in order to support older browsers that only have BlobBuilder
|
||||
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) {
|
||||
var
|
||||
get_class = function (object) {
|
||||
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
|
||||
},
|
||||
FakeBlobBuilder = function BlobBuilder() {
|
||||
this.data = [];
|
||||
},
|
||||
FakeBlob = function Blob(data, type, encoding) {
|
||||
this.data = data;
|
||||
this.size = data.length;
|
||||
this.type = type;
|
||||
this.encoding = encoding;
|
||||
},
|
||||
FBB_proto = FakeBlobBuilder.prototype,
|
||||
FB_proto = FakeBlob.prototype,
|
||||
FileReaderSync = view.FileReaderSync,
|
||||
FileException = function (type) {
|
||||
this.code = this[this.name = type];
|
||||
},
|
||||
file_ex_codes = (
|
||||
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " +
|
||||
"NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
|
||||
).split(" "),
|
||||
file_ex_code = file_ex_codes.length,
|
||||
real_URL = view.URL || view.webkitURL || view,
|
||||
real_create_object_URL = real_URL.createObjectURL,
|
||||
real_revoke_object_URL = real_URL.revokeObjectURL,
|
||||
URL = real_URL,
|
||||
btoa = view.btoa,
|
||||
atob = view.atob
|
||||
|
||||
,
|
||||
ArrayBuffer = view.ArrayBuffer,
|
||||
Uint8Array = view.Uint8Array;
|
||||
FakeBlob.fake = FB_proto.fake = true;
|
||||
while (file_ex_code--) {
|
||||
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
|
||||
}
|
||||
if (!real_URL.createObjectURL) {
|
||||
URL = view.URL = {};
|
||||
}
|
||||
URL.createObjectURL = function (blob) {
|
||||
var
|
||||
type = blob.type,
|
||||
data_URI_header;
|
||||
if (type === null) {
|
||||
type = "application/octet-stream";
|
||||
}
|
||||
if (blob instanceof FakeBlob) {
|
||||
data_URI_header = "data:" + type;
|
||||
if (blob.encoding === "base64") {
|
||||
return data_URI_header + ";base64," + blob.data;
|
||||
} else if (blob.encoding === "URI") {
|
||||
return data_URI_header + "," + decodeURIComponent(blob.data);
|
||||
}
|
||||
if (btoa) {
|
||||
return data_URI_header + ";base64," + btoa(blob.data);
|
||||
} else {
|
||||
return data_URI_header + "," + encodeURIComponent(blob.data);
|
||||
}
|
||||
} else if (real_create_object_URL) {
|
||||
return real_create_object_URL.call(real_URL, blob);
|
||||
}
|
||||
};
|
||||
URL.revokeObjectURL = function (object_URL) {
|
||||
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
|
||||
real_revoke_object_URL.call(real_URL, object_URL);
|
||||
}
|
||||
};
|
||||
FBB_proto.append = function (data /*, endings*/ ) {
|
||||
var bb = this.data;
|
||||
// decode data to a binary string
|
||||
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
|
||||
var
|
||||
str = "",
|
||||
buf = new Uint8Array(data),
|
||||
i = 0,
|
||||
buf_len = buf.length;
|
||||
for (; i < buf_len; i++) {
|
||||
str += String.fromCharCode(buf[i]);
|
||||
}
|
||||
bb.push(str);
|
||||
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
|
||||
if (FileReaderSync) {
|
||||
var fr = new FileReaderSync;
|
||||
bb.push(fr.readAsBinaryString(data));
|
||||
} else {
|
||||
// async FileReader won't work as BlobBuilder is sync
|
||||
throw new FileException("NOT_READABLE_ERR");
|
||||
}
|
||||
} else if (data instanceof FakeBlob) {
|
||||
if (data.encoding === "base64" && atob) {
|
||||
bb.push(atob(data.data));
|
||||
} else if (data.encoding === "URI") {
|
||||
bb.push(decodeURIComponent(data.data));
|
||||
} else if (data.encoding === "raw") {
|
||||
bb.push(data.data);
|
||||
}
|
||||
} else {
|
||||
if (typeof data !== "string") {
|
||||
data += ""; // convert unsupported types to strings
|
||||
}
|
||||
// decode UTF-16 to binary string
|
||||
bb.push(unescape(encodeURIComponent(data)));
|
||||
}
|
||||
};
|
||||
FBB_proto.getBlob = function (type) {
|
||||
if (!arguments.length) {
|
||||
type = null;
|
||||
}
|
||||
return new FakeBlob(this.data.join(""), type, "raw");
|
||||
};
|
||||
FBB_proto.toString = function () {
|
||||
return "[object BlobBuilder]";
|
||||
};
|
||||
FB_proto.slice = function (start, end, type) {
|
||||
var args = arguments.length;
|
||||
if (args < 3) {
|
||||
type = null;
|
||||
}
|
||||
return new FakeBlob(
|
||||
this.data.slice(start, args > 1 ? end : this.data.length), type, this.encoding
|
||||
);
|
||||
};
|
||||
FB_proto.toString = function () {
|
||||
return "[object Blob]";
|
||||
};
|
||||
FB_proto.close = function () {
|
||||
this.size = this.data.length = 0;
|
||||
};
|
||||
return FakeBlobBuilder;
|
||||
}(view));
|
||||
|
||||
view.Blob = function Blob(blobParts, options) {
|
||||
var type = options ? (options.type || "") : "";
|
||||
var builder = new BlobBuilder();
|
||||
if (blobParts) {
|
||||
for (var i = 0, len = blobParts.length; i < len; i++) {
|
||||
builder.append(blobParts[i]);
|
||||
}
|
||||
}
|
||||
return builder.getBlob(type);
|
||||
};
|
||||
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable */
|
||||
require('script-loader!file-saver');
|
||||
require('script-loader!@/vendor/Blob');
|
||||
import XLSX from 'xlsx'
|
||||
|
||||
function generateArray(table) {
|
||||
|
@ -149,7 +148,8 @@ export function export_json_to_excel({
|
|||
header,
|
||||
data,
|
||||
filename,
|
||||
autoWidth = true
|
||||
autoWidth = true,
|
||||
bookType= 'xlsx'
|
||||
} = {}) {
|
||||
/* original data */
|
||||
filename = filename || 'excel-list'
|
||||
|
@ -196,11 +196,11 @@ export function export_json_to_excel({
|
|||
wb.Sheets[ws_name] = ws;
|
||||
|
||||
var wbout = XLSX.write(wb, {
|
||||
bookType: 'xlsx',
|
||||
bookType: bookType,
|
||||
bookSST: false,
|
||||
type: 'binary'
|
||||
});
|
||||
saveAs(new Blob([s2ab(wbout)], {
|
||||
type: "application/octet-stream"
|
||||
}), filename + ".xlsx");
|
||||
}), `${filename}.${bookType}`);
|
||||
}
|
||||
|
|
|
@ -149,6 +149,9 @@ export default {
|
|||
computed: {
|
||||
contentShortLength() {
|
||||
return this.postForm.content_short.length
|
||||
},
|
||||
lang() {
|
||||
return this.$store.getters.language
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -166,10 +169,18 @@ export default {
|
|||
// Just for test
|
||||
this.postForm.title += ` Article Id:${this.postForm.id}`
|
||||
this.postForm.content_short += ` Article Id:${this.postForm.id}`
|
||||
|
||||
// Set tagsview title
|
||||
this.setTagsViewTitle()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
setTagsViewTitle() {
|
||||
const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article'
|
||||
const route = Object.assign({}, this.$route, { title: `${title}-${this.postForm.id}` })
|
||||
this.$store.dispatch('updateVisitedView', route)
|
||||
},
|
||||
submitForm() {
|
||||
this.postForm.display_time = parseInt(this.display_time / 1000)
|
||||
console.log(this.postForm)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-table v-loading.body="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column align="center" label="ID" width="80">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
|
@ -87,7 +87,7 @@ export default {
|
|||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 10
|
||||
limit: 20
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div style="display:inline-block;">
|
||||
<label class="radio-label">Cell Auto-Width: </label>
|
||||
<el-radio-group v-model="autoWidth">
|
||||
<el-radio :label="true" border>True</el-radio>
|
||||
<el-radio :label="false" border>False</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
autoWidth: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<div style="display:inline-block;">
|
||||
<label class="radio-label">Book Type: </label>
|
||||
<el-select v-model="bookType" style="width:120px;" >
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: 'xlsx'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: ['xlsx', 'csv', 'txt']
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
bookType: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div style="display:inline-block;">
|
||||
<!-- $t is vue-i18n global function to translate lang -->
|
||||
<label class="radio-label" style="padding-left:0;">Filename: </label>
|
||||
<el-input :placeholder="$t('excel.placeholder')" v-model="filename" style="width:340px;" prefix-icon="el-icon-document"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filename: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -2,14 +2,15 @@
|
|||
<!-- $t is vue-i18n global function to translate lang -->
|
||||
<div class="app-container">
|
||||
|
||||
<label class="radio-label" style="padding-left:0;">Filename: </label>
|
||||
<el-input :placeholder="$t('excel.placeholder')" v-model="filename" style="width:340px;" prefix-icon="el-icon-document"/>
|
||||
<label class="radio-label">Cell Auto-Width: </label>
|
||||
<el-radio-group v-model="autoWidth">
|
||||
<el-radio :label="true" border>True</el-radio>
|
||||
<el-radio :label="false" border>False</el-radio>
|
||||
</el-radio-group>
|
||||
<div>
|
||||
<FilenameOption v-model="filename" />
|
||||
<AutoWidthOption v-model="autoWidth" />
|
||||
<BookTypeOption v-model="bookType" />
|
||||
<el-button :loading="downloadLoading" style="margin:0 0 20px 20px;" type="primary" icon="document" @click="handleDownload">{{ $t('excel.export') }} Excel</el-button>
|
||||
<a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;">
|
||||
<el-tag type="info">Documentation</el-tag>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row>
|
||||
<el-table-column align="center" label="Id" width="95">
|
||||
|
@ -46,15 +47,22 @@
|
|||
import { fetchList } from '@/api/article'
|
||||
import { parseTime } from '@/utils'
|
||||
|
||||
// options components
|
||||
import FilenameOption from './components/FilenameOption'
|
||||
import AutoWidthOption from './components/AutoWidthOption'
|
||||
import BookTypeOption from './components/BookTypeOption'
|
||||
|
||||
export default {
|
||||
name: 'ExportExcel',
|
||||
components: { FilenameOption, AutoWidthOption, BookTypeOption },
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
listLoading: true,
|
||||
downloadLoading: false,
|
||||
filename: '',
|
||||
autoWidth: true
|
||||
autoWidth: true,
|
||||
bookType: 'xlsx'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -79,7 +87,8 @@ export default {
|
|||
header: tHeader,
|
||||
data,
|
||||
filename: this.filename,
|
||||
autoWidth: this.autoWidth
|
||||
autoWidth: this.autoWidth,
|
||||
bookType: this.bookType
|
||||
})
|
||||
this.downloadLoading = false
|
||||
})
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
<!-- $t is vue-i18n global function to translate lang -->
|
||||
<el-input :placeholder="$t('excel.placeholder')" v-model="filename" style="width:340px;" prefix-icon="el-icon-document"/>
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="document" @click="handleDownload">{{ $t('excel.selectedExport') }}</el-button>
|
||||
<a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;">
|
||||
<el-tag type="info">Documentation</el-tag>
|
||||
</a>
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
ref="multipleTable"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<el-radio-group v-model="lang" size="small">
|
||||
<el-radio label="zh" border>简体中文</el-radio>
|
||||
<el-radio label="en" border>English</el-radio>
|
||||
<el-radio label="es" border>Español</el-radio>
|
||||
</el-radio-group>
|
||||
<el-tag style="margin-top:15px;display:block;" type="info">{{ $t('i18nView.note') }}</el-tag>
|
||||
</div>
|
||||
|
@ -101,6 +102,7 @@ export default {
|
|||
if (!this.$i18n.getLocaleMessage('en')[viewName]) {
|
||||
this.$i18n.mergeLocaleMessage('en', local.en)
|
||||
this.$i18n.mergeLocaleMessage('zh', local.zh)
|
||||
this.$i18n.mergeLocaleMessage('es', local.es)
|
||||
}
|
||||
this.setOptions() // set default select options
|
||||
},
|
||||
|
|
|
@ -39,5 +39,25 @@ export default {
|
|||
two: 'Two',
|
||||
three: 'Three'
|
||||
}
|
||||
},
|
||||
es: {
|
||||
i18nView: {
|
||||
title: 'Switch Language',
|
||||
note: 'The internationalization of this project is based on vue-i18n',
|
||||
datePlaceholder: 'Pick a day',
|
||||
selectPlaceholder: 'Select',
|
||||
tableDate: 'tableDate',
|
||||
tableName: 'tableName',
|
||||
tableAddress: 'tableAddress',
|
||||
default: 'default:',
|
||||
primary: 'primary',
|
||||
success: 'success',
|
||||
info: 'info',
|
||||
warning: 'warning',
|
||||
danger: 'danger',
|
||||
one: 'One',
|
||||
two: 'Two',
|
||||
three: 'Three'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
export default {
|
||||
computed: {
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// In order to fix the click on menu on the ios device will trigger the mouseeleave bug
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
||||
this.fixBugIniOS()
|
||||
},
|
||||
methods: {
|
||||
fixBugIniOS() {
|
||||
const $submenu = this.$refs.submenu
|
||||
if ($submenu) {
|
||||
const handleMouseleave = $submenu.handleMouseleave
|
||||
$submenu.handleMouseleave = (e) => {
|
||||
if (this.device === 'mobile') {
|
||||
return
|
||||
}
|
||||
handleMouseleave(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { validateURL } from '@/utils/validate'
|
||||
import { isExternal } from '@/utils'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -18,7 +18,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
isExternalLink(routePath) {
|
||||
return validateURL(routePath)
|
||||
return isExternal(routePath)
|
||||
},
|
||||
linkProps(url) {
|
||||
if (this.isExternalLink(url)) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</app-link>
|
||||
</template>
|
||||
|
||||
<el-submenu v-else :index="item.name||item.path">
|
||||
<el-submenu v-else ref="submenu" :index="resolvePath(item.path)">
|
||||
<template slot="title">
|
||||
<item v-if="item.meta" :icon="item.meta.icon" :title="generateTitle(item.meta.title)" />
|
||||
</template>
|
||||
|
@ -37,13 +37,15 @@
|
|||
<script>
|
||||
import path from 'path'
|
||||
import { generateTitle } from '@/utils/i18n'
|
||||
import { validateURL } from '@/utils/validate'
|
||||
import { isExternal } from '@/utils'
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
// route object
|
||||
item: {
|
||||
|
@ -96,7 +98,7 @@ export default {
|
|||
return path.resolve(this.basePath, routePath)
|
||||
},
|
||||
isExternalLink(routePath) {
|
||||
return validateURL(routePath)
|
||||
return isExternal(routePath)
|
||||
},
|
||||
generateTitle
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
text-color="#bfcbd9"
|
||||
active-text-color="#409EFF"
|
||||
>
|
||||
<sidebar-item v-for="route in permission_routers" :key="route.name" :item="route" :base-path="route.path"/>
|
||||
<sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
<div class="tags-view-container">
|
||||
<scroll-pane ref="scrollPane" class="tags-view-wrapper">
|
||||
<router-link
|
||||
v-for="tag in Array.from(visitedViews)"
|
||||
v-for="tag in visitedViews"
|
||||
ref="tag"
|
||||
:class="isActive(tag)?'active':''"
|
||||
:to="tag"
|
||||
:to="tag.fullPath"
|
||||
:key="tag.path"
|
||||
tag="span"
|
||||
class="tags-view-item"
|
||||
@click.middle.native="closeSelectedTag(tag)"
|
||||
@contextmenu.prevent.native="openMenu(tag,$event)">
|
||||
{{ generateTitle(tag.title) }}
|
||||
<span class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)"/>
|
||||
|
@ -59,21 +61,15 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
generateTitle, // generateTitle by vue-i18n
|
||||
generateRoute() {
|
||||
if (this.$route.name) {
|
||||
return this.$route
|
||||
}
|
||||
return false
|
||||
},
|
||||
isActive(route) {
|
||||
return route.path === this.$route.path
|
||||
},
|
||||
addViewTags() {
|
||||
const route = this.generateRoute()
|
||||
if (!route) {
|
||||
return false
|
||||
const { name } = this.$route
|
||||
if (name) {
|
||||
this.$store.dispatch('addView', this.$route)
|
||||
}
|
||||
this.$store.dispatch('addView', route)
|
||||
return false
|
||||
},
|
||||
moveToCurrentTag() {
|
||||
const tags = this.$refs.tag
|
||||
|
@ -149,6 +145,7 @@ export default {
|
|||
.tags-view-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
border: 1px solid #d8dce5;
|
||||
|
|
Loading…
Reference in New Issue