Compare commits

..

23 Commits

Author SHA1 Message Date
Pan
913f6c8bec [release] 2.2.1 2017-10-25 17:14:57 +08:00
Pan
76f4017470 fix: fix getUserInfo by cookie bug 2017-10-25 17:12:36 +08:00
Pan
87a44ae7f5 doc: add note for NProgress.done 2017-10-23 10:28:19 +08:00
dingyi1993
1c852db0ef fix:fix undone NProgress. 2017-10-22 21:22:43 -05:00
Pan
9463c50e06 feature: tinymce add setContent && getContent method 2017-10-18 17:02:35 +08:00
Pan
658abf664d refine: add parseTime timestamp demo 2017-10-16 10:16:44 +08:00
spiritree
4940dd4040 fix:fix undefined bug in export excel 2017-10-12 03:46:49 -05:00
spiritree
91bd31e1e2 refine:refine code 2017-10-12 02:36:56 -05:00
spiritree
a8602e78f0 refine:export adaptive colwidth in excel 2017-10-12 02:36:56 -05:00
Pan
516897b97a Fix:fix autoprefixer explanation 2017-10-08 11:19:20 +08:00
Pan
2725285d26 fix build_config bug 2017-09-29 16:31:44 +08:00
Pan
a842a4b451 refine:refine build_config 2017-09-29 16:31:44 +08:00
Pan
be0606ebbc update echarts 2017-09-28 15:31:49 +08:00
Pan
a10de2e8d8 [release] 2.2.0 2017-09-27 10:43:53 +08:00
Pan
2282135b44 refine:refine directive waves 2017-09-27 10:34:48 +08:00
Pan
329f3b3714 refine:rm export selected to zip example 2017-09-27 10:29:32 +08:00
Pan
065eaa93a2 refine:icon demo add clipboard 2017-09-27 10:18:40 +08:00
Pan
4f2f136dd0 add:add clipboard example 2017-09-27 10:18:40 +08:00
Pan
8d53ae1259 add:add clipboard 2017-09-27 10:18:40 +08:00
spiritree
a185412446 add Export2Zip demo 2017-09-27 10:18:23 +08:00
spiritree
3cf048e80b add Export2Zip vendor 2017-09-27 10:18:23 +08:00
spiritree
fcf7c0ba50 ignore package-lock.json 2017-09-27 10:18:23 +08:00
Pan
807aa548b2 refine:rm duplicate code && split xlsx 2017-09-26 16:08:20 +08:00
34 changed files with 428 additions and 84 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ test/unit/coverage
test/e2e/reports
selenium-debug.log
.idea
package-lock.json

View File

@@ -2,7 +2,7 @@
module.exports = {
"plugins": {
// to edit target browsers: use "browserlist" field in package.json
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}

View File

@@ -32,8 +32,9 @@
- ECharts
- 401, 404 error page
- Error log
- Exporting to Excel
- Export Excel
- Upload Excel
- Export Zip
- Table example
- Interactive table example
- Drag & drop table example
@@ -47,6 +48,7 @@
- screenfull
- markdown2html
- views-tab
- clipboard
## Development

View File

@@ -63,6 +63,7 @@
- 401404错误页面
- 错误日志
- 导出excel
- zip
- 前端可视化excel
- table example
- 动态table example
@@ -78,6 +79,7 @@
- screenfull
- markdown2html
- views-tab
- clipboard
## 开发

View File

@@ -9,9 +9,7 @@ var webpack = require('webpack');
var config = require('../config');
var webpackConfig = require('./webpack.prod.conf');
console.log(process.env.NODE_ENV)
var spinner = ora('building for ' + process.env.NODE_ENV + '...')
var spinner = ora('building for ' + process.env.NODE_ENV + ' of ' + process.env.env_config+ ' mode...' )
spinner.start()

View File

@@ -1,4 +1,5 @@
require('./check-versions')(); // 检查 Node 和 npm 版本
var config = require('../config');
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
@@ -28,8 +29,8 @@ var devMiddleware = require('webpack-dev-middleware')(compiler, {
});
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: () => {
}
log: false,
heartbeat: 2000
});
// force page reload when html-webpack-plugin template changes
@@ -40,8 +41,6 @@ compiler.plugin('compilation', function (compilation) {
})
});
// compiler.apply(new DashboardPlugin());
// proxy api requests
Object.keys(proxyTable).forEach(function (context) {
var options = proxyTable[context]
@@ -67,18 +66,26 @@ app.use(staticPath, express.static('./static'));
var uri = 'http://localhost:' + port
devMiddleware.waitUntilValid(function () {
console.log('> Listening at ' + uri + '\n')
});
var _resolve
var readyPromise = new Promise(resolve => {
_resolve = resolve
})
module.exports = app.listen(port, function (err) {
if (err) {
console.log(err);
return
}
console.log('> Starting dev server...')
devMiddleware.waitUntilValid(() => {
console.log('> Listening at ' + uri + '\n')
// when env is testing, don't need open it
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
opn(uri)
}
_resolve()
})
// when env is testing, don't need open it
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
opn(uri)
}
});
var server = app.listen(port)
module.exports = {
ready: readyPromise,
close: () => {
server.close()
}
}

View File

@@ -14,7 +14,7 @@ module.exports = {
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV !== 'development' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
@@ -38,13 +38,13 @@ module.exports = {
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: "pre",
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: "pre",
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,

View File

@@ -9,7 +9,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv
var env = config.build[process.env.env_config+'Env']
function resolveApp(relativePath) {
return path.resolve(relativePath);
@@ -95,6 +95,14 @@ var webpackConfig = merge(baseWebpackConfig, {
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
}
}),
// split xlsx into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'xlsx',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('xlsx') >= 0);
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
@@ -109,9 +117,11 @@ var webpackConfig = merge(baseWebpackConfig, {
}])
]
})
if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

View File

@@ -1,5 +1,6 @@
module.exports = {
NODE_ENV: '"development"',
ENV_CONFIG: '"dev"',
BASE_API: '"https://api-dev"',
APP_ORIGIN: '"https://wallstreetcn.com"'
}

View File

@@ -3,37 +3,37 @@ var path = require('path')
module.exports = {
build: {
sitEnv: require('./sit.env'),
prodEnv: require('./prod.env'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './', //请根据自己路径配置更改
productionSourceMap: false,
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
sitEnv: require('./sit.env'),
prodEnv: require('./prod.env'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './', //请根据自己路径配置更改
productionSourceMap: false,
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
},
dev: {
env: require('./dev.env'),
port: 9527,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false
env: require('./dev.env'),
port: 9527,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false
}
}

View File

@@ -1,5 +1,6 @@
module.exports = {
NODE_ENV: '"production"',
ENV_CONFIG: '"prod"',
BASE_API: '"https://api-prod"',
APP_ORIGIN: '"https://wallstreetcn.com"'
};

View File

@@ -1,5 +1,6 @@
module.exports = {
NODE_ENV: '"production"',
ENV_CONFIG: '"sit"',
BASE_API: '"https://api-sit"',
APP_ORIGIN: '"https://wallstreetcn.com"'
};

View File

@@ -1,22 +1,23 @@
{
"name": "juicy",
"version": "2.1.1",
"version": "2.2.1",
"description": "A Vue.js admin",
"author": "Pan <panfree23@gmail.com>",
"license": "MIT",
"private": true,
"scripts": {
"dev": "node build/dev-server.js",
"build:prod": "cross-env NODE_ENV=production node build/build.js",
"build:sit": "cross-env NODE_ENV=sit node build/build.js",
"build:sit-preview": "cross-env NODE_ENV=sit npm_config_preview=true npm_config_report=true node build/build.js",
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
"build:sit-preview": "cross-env NODE_ENV=production env_config=sit npm_config_preview=true npm_config_report=true node build/build.js",
"lint": "eslint --ext .js,.vue src"
},
"dependencies": {
"axios": "0.16.2",
"clipboard": "1.7.1",
"codemirror": "5.26.0",
"dropzone": "5.1.0",
"echarts": "3.6.2",
"echarts": "3.7.2",
"element-ui": "1.4.2",
"file-saver": "1.3.3",
"js-cookie": "2.1.4",
@@ -35,7 +36,8 @@
"vue-splitpane": "^1.0.0",
"vuedraggable": "2.14.1",
"vuex": "2.3.1",
"xlsx": "^0.10.8"
"xlsx": "^0.10.8",
"jszip": "^3.1.4"
},
"devDependencies": {
"autoprefixer": "7.1.1",
@@ -90,7 +92,7 @@
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserlist": [
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"

View File

@@ -150,6 +150,12 @@ export default {
})
},
methods: {
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
const _this = this
arr.forEach(v => {

View File

@@ -0,0 +1,49 @@
// Inspired by https://github.com/Inndy/vue-clipboard2
const Clipboard = require('clipboard')
if (!Clipboard) {
throw new Error('you shold npm install `clipboard` --save at first ')
}
export default {
bind(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
const clipboard = new Clipboard(el, {
text() { return binding.value },
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
})
clipboard.on('success', e => {
const callback = el._v_clipboard_success
callback && callback(e) // eslint-disable-line
})
clipboard.on('error', e => {
const callback = el._v_clipboard_error
callback && callback(e) // eslint-disable-line
})
el._v_clipboard = clipboard
}
},
update(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
el._v_clipboard.text = function() { return binding.value }
el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
}
},
unbind(el, binding) {
if (binding.arg === 'success') {
delete el._v_clipboard_success
} else if (binding.arg === 'error') {
delete el._v_clipboard_error
} else {
el._v_clipboard.destroy()
delete el._v_clipboard
}
}
}

View File

@@ -0,0 +1,13 @@
import Clipboard from './clipboard'
const install = function(Vue) {
Vue.directive('Clipboard', Clipboard)
}
if (window.Vue) {
window.clipboard = Clipboard
Vue.use(install); // eslint-disable-line
}
Clipboard.install = install
export default Clipboard

View File

@@ -0,0 +1,13 @@
import waves from './waves'
const install = function(Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install); // eslint-disable-line
}
waves.install = install
export default waves

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1506419860538" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4662" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M438.857143 950.857143l512 0 0-365.714286-237.714286 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-237.714286-219.428571 0 0 658.285714zM585.142857 128l0-36.571429q0-7.460571-5.412571-12.873143t-12.873143-5.412571l-402.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 36.571429q0 7.460571 5.412571 12.873143t12.873143 5.412571l402.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143zM731.428571 512l170.861714 0-170.861714-170.861714 0 170.861714zM1024 585.142857l0 384q0 22.820571-16.018286 38.838857t-38.838857 16.018286l-548.571429 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-91.428571-310.857143 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-768q0-22.820571 16.018286-38.838857t38.838857-16.018286l621.714286 0q22.820571 0 38.838857 16.018286t16.018286 38.838857l0 187.465143q11.995429 7.460571 20.553143 16.018286l233.179429 233.179429q16.018286 16.018286 27.428571 43.446857t11.410286 50.322286z" p-id="4663"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
src/icons/svg/zip.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1506326020470" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2561" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M619.364365 933.396352c1.372783 0.06385 2.681715 0.191551 4.054497 0.191551h309.291099a65.670086 65.670086 0 0 0 65.606235-65.606235V150.974154a65.670086 65.670086 0 0 0-65.606235-65.606235H623.418862c-1.372783 0-2.71364 0.127701-4.054497 0.191551V-0.031925L15.691224 80.547217v858.404116l603.673141 82.654279v-88.20926z m0-810.101325c1.340857-0.191551 2.681715-0.415027 4.054497-0.415027h309.291099c15.515635 0 28.12608 12.610444 28.12608 28.12608v717.007513a28.158005 28.158005 0 0 1-28.12608 28.12608H623.418862c-1.372783 0-2.71364-0.223476-4.054497-0.415028V123.326952zM248.329977 605.429026l-143.918691-3.671395v-23.401154l86.868402-133.255682v-1.181231l-78.919033 1.308932v-36.043523l134.564614-3.51177v26.082869l-87.506906 133.734559v1.149307l88.911614 1.404707v37.352456z m72.406297 1.85166l-44.759096-1.149306v-201.192456l44.759096-1.149306v203.491068z m171.087015-92.966111c-16.664942 15.356009-41.151551 22.060296-69.341481 21.868745a113.81325 113.81325 0 0 1-16.122213-1.05353v74.353733l-46.099954-1.181231v-202.788714c14.238628-2.809415 34.383414-5.171878 63.179923-5.938083 29.498862-0.766204 50.792954 4.309899 65.191208 15.292159 13.887451 10.439532 23.305378 27.966454 23.305378 48.845518s-7.119314 38.629462-20.080936 50.601403z m-65.925487-79.174435a80.13219 80.13219 0 0 0-19.538207 2.202837v61.392113c4.022572 0.92583 8.970974 1.213157 15.834887 1.213156 25.380514-0.031925 41.215401-12.897771 41.215401-34.479189 0-19.378581-13.63205-30.712019-37.480156-30.296992z m306.322058-296.233702h73.523679v30.328917h-73.523679v-30.328917z m-73.555604 45.397599h73.523679v30.360842h-73.523679v-30.360842z m73.555604 49.675573h73.523679v30.360842h-73.523679v-30.360842z m0 95.903227h73.523679v30.328917h-73.523679v-30.328917z m-73.555604-48.717818h73.523679v30.328917h-73.523679v-30.328917z m72.821325 376.142417a72.7894 72.7894 0 0 0 72.7894-72.821325l-13.440499-121.986095c0-40.225721-19.155105-72.821325-59.380827-72.821325s-59.348901 32.595604-59.348901 72.821325l-13.472424 121.986095a72.7894 72.7894 0 0 0 72.821325 72.821325z m-24.103508-133.862261h48.207015v101.84131h-48.207015v-101.84131z" p-id="2562"></path></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -34,7 +34,7 @@ export default {
if (userMap[token]) {
return userMap[token]
} else {
return Promise.reject('error')
return false
}
},
logout: () => 'success'

View File

@@ -3,6 +3,7 @@ import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { getToken } from '@/utils/auth' // 验权
import { Message } from 'element-ui'
// permissiom judge
function hasPermission(roles, permissionRoles) {
@@ -18,6 +19,7 @@ router.beforeEach((to, from, next) => {
if (getToken()) { // 判断是否有token
if (to.path === '/login') {
next({ path: '/' })
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 pshistory模式下无问题可删除该行
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
@@ -28,6 +30,7 @@ router.beforeEach((to, from, next) => {
})
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
Message.error('验证失败,请重新登录')
next({ path: '/login' })
})
})
@@ -37,6 +40,7 @@ router.beforeEach((to, from, next) => {
next()//
} else {
next({ path: '/401', query: { noGoBack: true }})
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 pshistory模式下无问题可删除该行
}
// 可删 ↑
}
@@ -46,7 +50,7 @@ router.beforeEach((to, from, next) => {
next()
} else {
next('/login') // 否则全部重定向到登录页
NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 pshistory模式下无问题可删除该行
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 pshistory模式下无问题可删除该行
}
}
})

View File

@@ -149,11 +149,21 @@ export const asyncRouterMap = [
name: 'excel',
icon: 'excel',
children: [
{ path: 'download', component: _import('excel/index'), name: '导出excel' },
{ path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' },
{ path: 'download', component: _import('excel/index'), name: 'export excel' },
{ path: 'download2', component: _import('excel/selectExcel'), name: 'export selected' },
{ path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel' }
]
},
{
path: '/zip',
component: Layout,
redirect: '/zip/download',
name: 'zip',
icon: 'zip',
children: [
{ path: 'download', component: _import('zip/index'), name: 'export zip' }
]
},
{
path: '/theme',
component: Layout,
@@ -163,6 +173,14 @@ export const asyncRouterMap = [
noDropdown: true,
children: [{ path: 'index', component: _import('theme/index'), name: '换肤' }]
},
{
path: '/clipboard',
component: Layout,
redirect: 'noredirect',
icon: 'clipboard',
noDropdown: true,
children: [{ path: 'index', component: _import('clipboard/index'), name: 'clipboard' }]
},
{ path: '*', redirect: '/404', hidden: true }
]

View File

@@ -63,6 +63,9 @@ const user = {
GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getUserInfo(state.token).then(response => {
if (!response.data) { // 由于mockjs 不支持自定义状态码只能这样hack
reject('error')
}
const data = response.data
commit('SET_ROLES', data.role)
commit('SET_NAME', data.name)

36
src/utils/clipboard.js Normal file
View File

@@ -0,0 +1,36 @@
import Clipboard from 'clipboard'
import Vue from 'vue'
function clipboardSuccess() {
Vue.prototype.$message({
message: '复制成功',
type: 'success',
duration: 1500
})
}
function clipboardError() {
Vue.prototype.$message({
message: '复制失败',
type: 'error'
})
}
export default function handleClipboard(text, event) {
const clipboard = new Clipboard(event.target, {
text: () => text
})
clipboard.on('success', () => {
clipboardSuccess()
clipboard.off('error')
clipboard.off('success')
clipboard.destroy()
})
clipboard.on('error', () => {
clipboardError()
clipboard.off('error')
clipboard.off('success')
clipboard.destroy()
})
clipboard.onClick(event)
}

View File

@@ -1,7 +1,8 @@
/* eslint-disable */
require('script-loader!file-saver');
require('script-loader!vendor/Blob');
require('script-loader!xlsx/dist/xlsx.core.min');
import XLSX from 'xlsx'
function generateArray(table) {
var out = [];
var rows = table.querySelectorAll('tr');
@@ -93,14 +94,12 @@ function s2ab(s) {
export function export_table_to_excel(id) {
var theTable = document.getElementById(id);
console.log('a')
var oo = generateArray(theTable);
var ranges = oo[1];
/* original data */
var data = oo[0];
var ws_name = "SheetJS";
console.log(data);
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
@@ -117,9 +116,6 @@ export function export_table_to_excel(id) {
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
}
function formatJson(jsonData) {
console.log(jsonData)
}
export function export_json_to_excel(th, jsonData, defaultTitle) {
/* original data */
@@ -130,6 +126,29 @@ export function export_json_to_excel(th, jsonData, defaultTitle) {
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/*设置worksheet每列的最大宽度*/
const colWidth = data.map(row => row.map(val => {
/*先判断是否为null/undefined*/
if (val == null) {
return {'wch': 10};
}
/*再判断是否为中文*/
else if (val.toString().charCodeAt(0) > 255) {
return {'wch': val.toString().length * 2};
} else {
return {'wch': val.toString().length};
}
}))
/*以第一行为初始值*/
let result = colWidth[0];
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j]['wch'] < colWidth[i][j]['wch']) {
result[j]['wch'] = colWidth[i][j]['wch'];
}
}
}
ws['!cols'] = result;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);

22
src/vendor/Export2Zip.js vendored Normal file
View File

@@ -0,0 +1,22 @@
/* eslint-disable */
require('script-loader!file-saver');
import JSZip from 'jszip'
export function export_txt_to_zip(th, jsonData, txtName, zipName) {
const zip = new JSZip()
const txt_name = txtName || '文本'
const zip_name = zipName || '压缩包'
const data = jsonData
let txtData = `${th}\r\n`
data.forEach((row) => {
let tempStr = ''
tempStr = row.toString()
txtData += `${tempStr}\r\n`
})
zip.file(`${txt_name}.txt`, txtData)
zip.generateAsync({type:"blob"}).then((blob) => {
saveAs(blob, `${zip_name}.zip`)
}, (err) => {
alert('导出失败')
})
}

View File

@@ -0,0 +1,44 @@
<template>
<div class="app-container">
<el-tabs v-model="activeName">
<el-tab-pane label="use clipboard directly" name="directly">
<el-input v-model="inputData" placeholder="请输入内容" style='width:400px;'></el-input>
<el-button type="primary" icon="document" @click='handleCopy(inputData,$event)'>copy</el-button>
</el-tab-pane>
<el-tab-pane label="use clipboard by v-directive" name="v-directive">
<el-input v-model="inputData" placeholder="请输入内容" style='width:400px;'></el-input>
<el-button type="primary" icon="document" v-clipboard:copy='inputData' v-clipboard:success='clipboardSuccess'>copy</el-button>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import clip from '@/utils/clipboard' // use clipboard directly
import clipboard from '@/directive/clipboard/index.js' // use clipboard by v-directive
export default {
directives: {
clipboard
},
data() {
return {
activeName: 'directly',
inputData: 'https://github.com/PanJiaChen/vue-element-admin'
}
},
methods: {
handleCopy(text, event) {
clip(text, event)
},
clipboardSuccess() {
this.$message({
message: '复制成功',
type: 'success',
duration: 1500
})
}
}
}
</script>

View File

@@ -26,7 +26,7 @@
<script>
import PanThumb from '@/components/PanThumb'
import MdInput from '@/components/MDinput'
import waves from '@/directive/waves.js' // 水波纹指令
import waves from '@/directive/waves/index.js' // 水波纹指令
export default {
components: {

View File

@@ -151,7 +151,7 @@
<script>
import { fetchList, fetchPv } from '@/api/article'
import waves from '@/directive/waves.js'// 水波纹指令
import waves from '@/directive/waves/index.js' // 水波纹指令
import { parseTime } from '@/utils'
const calendarTypeOptions = [

View File

@@ -25,7 +25,7 @@
<el-table-column align="center" prop="created_at" label="发布时间" width="220">
<template scope="scope">
<i class="el-icon-time"></i>
<span>{{scope.row.display_time}}</span>
<span>{{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
</template>
</el-table-column>
</el-table>
@@ -34,6 +34,7 @@
<script>
import { fetchList } from '@/api/article'
import { parseTime } from 'utils'
export default {
data() {
@@ -67,7 +68,13 @@ export default {
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}

View File

@@ -1,10 +1,10 @@
<template>
<div class="icons-container">
<div class="icons-wrapper">
<div v-for='item of iconsMap' :key='item' class='icon-item'>
<div v-for='item of iconsMap' :key='item' class='icon-item' @click='handleClipboard(generateIconCode(item),$event)'>
<el-tooltip placement="top" effect="light">
<div slot="content">
{{`&lt;icon-svg :icon-class=&quot;${item}&quot; /&gt;`}}
{{generateIconCode(item)}}
</div>
<icon-svg :icon-class="item" />
</el-tooltip>
@@ -16,6 +16,7 @@
<script>
import icons from './generateIconsView'
import clipboard from '@/utils/clipboard' // use clipboard directly
export default {
data() {
@@ -28,6 +29,14 @@ export default {
return i.default.id.split('-')[1]
})
this.iconsMap = iconsMap
},
methods: {
generateIconCode(symbol) {
return `<icon-svg :icon-class="${symbol}" />`
},
handleClipboard(text, event) {
clipboard(text, event)
}
}
}
</script>

74
src/views/zip/index.vue Normal file
View File

@@ -0,0 +1,74 @@
<template>
<div class="app-container">
<el-button style='margin-bottom:20px;' type="primary" icon="document" @click="handleDownload" :loading="downloadLoading">导出zip</el-button>
<el-table :data="list" v-loading.body="listLoading" element-loading-text="拼命加载中" border fit highlight-current-row>
<el-table-column align="center" label='ID' width="95">
<template scope="scope">
{{scope.$index}}
</template>
</el-table-column>
<el-table-column label="文章标题">
<template scope="scope">
{{scope.row.title}}
</template>
</el-table-column>
<el-table-column label="作者" width="95" align="center">
<template scope="scope">
<el-tag>{{scope.row.author}}</el-tag>
</template>
</el-table-column>
<el-table-column label="阅读数" width="115" align="center">
<template scope="scope">
{{scope.row.pageviews}}
</template>
</el-table-column>
<el-table-column align="center" prop="created_at" label="发布时间" width="220">
<template scope="scope">
<i class="el-icon-time"></i>
<span>{{scope.row.display_time}}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { fetchList } from '@/api/article'
export default {
data() {
return {
list: null,
listLoading: true,
downloadLoading: false
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
this.listLoading = true
fetchList().then(response => {
this.list = response.data.items
this.listLoading = false
})
},
handleDownload() {
this.downloadLoading = true
require.ensure([], () => {
const { export_txt_to_zip } = require('vendor/Export2Zip')
const tHeader = ['序号', '文章标题', '作者', '阅读数', '发布时间']
const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time']
const list = this.list
const data = this.formatJson(filterVal, list)
export_txt_to_zip(tHeader, data, '列表文本', '压缩文本')
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
}
}
}
</script>