Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
90d3e314c0 | ||
|
4780ac334f | ||
|
b0bd91cd0f | ||
|
ae2754a568 | ||
|
6e07d18b1d | ||
|
f58db95be5 | ||
|
616b65c238 | ||
|
68cd051bb6 | ||
|
935d9aaba8 | ||
|
616f173aab | ||
|
d1cceb69b7 | ||
|
ff13ee1f27 | ||
|
dc84e7b9fb | ||
|
b82e8e860d | ||
|
98a8277a37 | ||
|
63ff44f8e5 | ||
|
dd5646ffbc |
@@ -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",
|
||||
|
@@ -1,199 +0,0 @@
|
||||
/* eslint-disable */
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['exports', 'echarts'], factory);
|
||||
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
|
||||
// CommonJS
|
||||
factory(exports, require('echarts'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory({}, root.echarts);
|
||||
}
|
||||
}(this, function (exports, echarts) {
|
||||
var log = function (msg) {
|
||||
if (typeof console !== 'undefined') {
|
||||
console && console.error && console.error(msg);
|
||||
}
|
||||
};
|
||||
if (!echarts) {
|
||||
log('ECharts is not Loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
var colorPalette = [
|
||||
'#2ec7c9','#b6a2de','#5ab1ef','#ffb980','#d87a80',
|
||||
'#8d98b3','#e5cf0d','#97b552','#95706d','#dc69aa',
|
||||
'#07a2a4','#9a7fd1','#588dd5','#f5994e','#c05050',
|
||||
'#59678c','#c9ab00','#7eb00a','#6f5553','#c14089'
|
||||
];
|
||||
|
||||
|
||||
var theme = {
|
||||
color: colorPalette,
|
||||
|
||||
title: {
|
||||
textStyle: {
|
||||
fontWeight: 'normal',
|
||||
color: '#008acd'
|
||||
}
|
||||
},
|
||||
|
||||
visualMap: {
|
||||
itemWidth: 15,
|
||||
color: ['#5ab1ef','#e0ffff']
|
||||
},
|
||||
|
||||
toolbox: {
|
||||
iconStyle: {
|
||||
normal: {
|
||||
borderColor: colorPalette[0]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
backgroundColor: 'rgba(50,50,50,0.5)',
|
||||
axisPointer : {
|
||||
type : 'line',
|
||||
lineStyle : {
|
||||
color: '#008acd'
|
||||
},
|
||||
crossStyle: {
|
||||
color: '#008acd'
|
||||
},
|
||||
shadowStyle : {
|
||||
color: 'rgba(200,200,200,0.2)'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dataZoom: {
|
||||
dataBackgroundColor: '#efefff',
|
||||
fillerColor: 'rgba(182,162,222,0.2)',
|
||||
handleColor: '#008acd'
|
||||
},
|
||||
|
||||
grid: {
|
||||
borderColor: '#eee'
|
||||
},
|
||||
|
||||
categoryAxis: {
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#008acd'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: ['#eee']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
valueAxis: {
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#008acd'
|
||||
}
|
||||
},
|
||||
splitArea : {
|
||||
show : true,
|
||||
areaStyle : {
|
||||
color: ['rgba(250,250,250,0.1)','rgba(200,200,200,0.1)']
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: ['#eee']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
timeline : {
|
||||
lineStyle : {
|
||||
color : '#008acd'
|
||||
},
|
||||
controlStyle : {
|
||||
normal : { color : '#008acd'},
|
||||
emphasis : { color : '#008acd'}
|
||||
},
|
||||
symbol : 'emptyCircle',
|
||||
symbolSize : 3
|
||||
},
|
||||
|
||||
line: {
|
||||
smooth : true,
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 3
|
||||
},
|
||||
|
||||
candlestick: {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#d87a80',
|
||||
color0: '#2ec7c9',
|
||||
lineStyle: {
|
||||
color: '#d87a80',
|
||||
color0: '#2ec7c9'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
scatter: {
|
||||
symbol: 'circle',
|
||||
symbolSize: 4
|
||||
},
|
||||
|
||||
map: {
|
||||
label: {
|
||||
normal: {
|
||||
textStyle: {
|
||||
color: '#d87a80'
|
||||
}
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderColor: '#eee',
|
||||
areaColor: '#ddd'
|
||||
},
|
||||
emphasis: {
|
||||
areaColor: '#fe994e'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
graph: {
|
||||
color: colorPalette
|
||||
},
|
||||
|
||||
gauge : {
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: [[0.2, '#2ec7c9'],[0.8, '#5ab1ef'],[1, '#d87a80']],
|
||||
width: 10
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
splitNumber: 10,
|
||||
length :15,
|
||||
lineStyle: {
|
||||
color: 'auto'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
length :22,
|
||||
lineStyle: {
|
||||
color: 'auto'
|
||||
}
|
||||
},
|
||||
pointer : {
|
||||
width : 5
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
echarts.registerTheme('macarons', theme);
|
||||
}));
|
@@ -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)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<input id="excel-upload-input" ref="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
|
||||
<div id="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
|
||||
<input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
|
||||
<div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
|
||||
Drop excel file here or
|
||||
<el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">Browse</el-button>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
e.dataTransfer.dropEffect = 'copy'
|
||||
},
|
||||
handleUpload() {
|
||||
document.getElementById('excel-upload-input').click()
|
||||
this.$refs['excel-upload-input'].click()
|
||||
},
|
||||
handleClick(e) {
|
||||
const files = e.target.files
|
||||
@@ -126,11 +126,11 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#excel-upload-input{
|
||||
.excel-upload-input{
|
||||
display: none;
|
||||
z-index: -9999;
|
||||
}
|
||||
#drop{
|
||||
.drop{
|
||||
border: 2px dashed #bbb;
|
||||
width: 600px;
|
||||
height: 160px;
|
||||
|
@@ -47,6 +47,9 @@
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
.is-active > .el-submenu__title{
|
||||
color: #f4f4f5!important;
|
||||
}
|
||||
}
|
||||
.hideSidebar {
|
||||
.sidebar-container {
|
||||
@@ -120,3 +123,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--vertical{
|
||||
& >.el-menu{
|
||||
.svg-icon{
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
176
src/vendor/Blob.js
vendored
176
src/vendor/Blob.js
vendored
@@ -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));
|
8
src/vendor/Export2Excel.js
vendored
8
src/vendor/Export2Excel.js
vendored
@@ -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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
30
src/views/excel/components/AutoWidthOption.vue
Normal file
30
src/views/excel/components/AutoWidthOption.vue
Normal file
@@ -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>
|
38
src/views/excel/components/BookTypeOption.vue
Normal file
38
src/views/excel/components/BookTypeOption.vue
Normal file
@@ -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>
|
28
src/views/excel/components/FilenameOption.vue
Normal file
28
src/views/excel/components/FilenameOption.vue
Normal file
@@ -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>
|
||||
<el-button :loading="downloadLoading" style="margin:0 0 20px 20px;" type="primary" icon="document" @click="handleDownload">{{ $t('excel.export') }} Excel</el-button>
|
||||
<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"
|
||||
|
26
src/views/layout/components/Sidebar/FixiOSBug.js
Normal file
26
src/views/layout/components/Sidebar/FixiOSBug.js
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
src/views/layout/components/Sidebar/Link.vue
Normal file
39
src/views/layout/components/Sidebar/Link.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
<template>
|
||||
<!-- eslint-disable vue/require-component-is-->
|
||||
<component v-bind="linkProps(to)">
|
||||
<slot/>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validateURL } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isExternalLink(routePath) {
|
||||
return validateURL(routePath)
|
||||
},
|
||||
linkProps(url) {
|
||||
if (this.isExternalLink(url)) {
|
||||
return {
|
||||
is: 'a',
|
||||
href: url,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
is: 'router-link',
|
||||
to: url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -2,14 +2,14 @@
|
||||
<div v-if="!item.hidden&&item.children" class="menu-wrapper">
|
||||
|
||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||
<a :href="onlyOneChild.path" target="_blank" @click="clickLink(onlyOneChild.path,$event)">
|
||||
<app-link :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<item v-if="onlyOneChild.meta" :icon="onlyOneChild.meta.icon||item.meta.icon" :title="generateTitle(onlyOneChild.meta.title)" />
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</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>
|
||||
@@ -23,11 +23,11 @@
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu" />
|
||||
|
||||
<a v-else :href="child.path" :key="child.name" target="_blank" @click="clickLink(child.path,$event)">
|
||||
<app-link v-else :to="resolvePath(child.path)" :key="child.name">
|
||||
<el-menu-item :index="resolvePath(child.path)">
|
||||
<item v-if="child.meta" :icon="child.meta.icon" :title="generateTitle(child.meta.title)" />
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</app-link>
|
||||
</template>
|
||||
</el-submenu>
|
||||
|
||||
@@ -39,10 +39,13 @@ import path from 'path'
|
||||
import { generateTitle } from '@/utils/i18n'
|
||||
import { validateURL } from '@/utils/validate'
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
components: { Item },
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
// route object
|
||||
item: {
|
||||
@@ -89,18 +92,14 @@ export default {
|
||||
return false
|
||||
},
|
||||
resolvePath(routePath) {
|
||||
if (this.isExternalLink(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
return path.resolve(this.basePath, routePath)
|
||||
},
|
||||
isExternalLink(routePath) {
|
||||
return validateURL(routePath)
|
||||
},
|
||||
clickLink(routePath, e) {
|
||||
if (!this.isExternalLink(routePath)) {
|
||||
e.preventDefault()
|
||||
const path = this.resolvePath(routePath)
|
||||
this.$router.push(path)
|
||||
}
|
||||
},
|
||||
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;
|
||||
|
@@ -111,8 +111,7 @@
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
|
||||
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">{{ $t('table.confirm') }}</el-button>
|
||||
<el-button v-else type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
|
||||
<el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">{{ $t('table.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
|
Reference in New Issue
Block a user