Compare commits

...

10 Commits

Author SHA1 Message Date
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
21 changed files with 306 additions and 14 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

@@ -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

@@ -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({

View File

@@ -1,6 +1,6 @@
{
"name": "juicy",
"version": "2.1.1",
"version": "2.2.0",
"description": "A Vue.js admin",
"author": "Pan <panfree23@gmail.com>",
"license": "MIT",
@@ -14,6 +14,7 @@
},
"dependencies": {
"axios": "0.16.2",
"clipboard": "1.7.1",
"codemirror": "5.26.0",
"dropzone": "5.1.0",
"echarts": "3.6.2",
@@ -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",

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

@@ -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 }
]

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,7 +94,6 @@ 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];
@@ -117,9 +117,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 */

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(function (blob) {
saveAs(blob, `${zip_name}.zip`)
}, function (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

@@ -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>