增加导出功能.
This commit is contained in:
parent
e5f2d27184
commit
71e21f9189
2
dist/index.html
vendored
2
dist/index.html
vendored
@ -1,4 +1,4 @@
|
|||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/><meta content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0" name="viewport"/><link rel="icon" href="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/favicon.ico"><title>X-PHP</title><script>document.write("<script src='config.js'><\/script>");</script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/echarts.49558cc4.js"></script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/elicons.4bccae06.js"></script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/modules.af2834df.js"></script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/app.b3dc07da.js"></script><link href="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/css/modules.34563575.css" rel="stylesheet"><link href="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/css/app.661f9899.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but X-PHP doesn't work properly without JavaScript enabled.</strong></noscript><div id="app" class="aminui"><div class="app-loading"><div class="app-loading__logo"></div><div class="app-loading__loader"></div></div></div></body><div id="versionCheck" class="versionCheck"><h2>当前浏览器内核版本过低</h2><p>当前版本:<span id="versionCheck-type">--</span> <span id="versionCheck-version">--</span></p><p>最低版本要求:Chrome 71+、Firefox 65+、Safari 12+、Edge 97+。</p><p>请升级浏览器版本,或更换现代浏览器,如果你使用的是双核浏览器,请切换到极速/高速模式。</p></div><style>.app-loading {
|
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/><meta content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0" name="viewport"/><link rel="icon" href="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/favicon.ico"><title>X-PHP</title><script>document.write("<script src='config.js'><\/script>");</script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/echarts.49558cc4.js"></script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/elicons.4bccae06.js"></script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/modules.af2834df.js"></script><script defer="defer" src="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/js/app.6e805385.js"></script><link href="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/css/modules.34563575.css" rel="stylesheet"><link href="https://ansnid.oss-cn-shenzhen.aliyuncs.com/x-Admin/static/css/app.f6c11b91.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but X-PHP doesn't work properly without JavaScript enabled.</strong></noscript><div id="app" class="aminui"><div class="app-loading"><div class="app-loading__logo"></div><div class="app-loading__loader"></div></div></div></body><div id="versionCheck" class="versionCheck"><h2>当前浏览器内核版本过低</h2><p>当前版本:<span id="versionCheck-type">--</span> <span id="versionCheck-version">--</span></p><p>最低版本要求:Chrome 71+、Firefox 65+、Safari 12+、Edge 97+。</p><p>请升级浏览器版本,或更换现代浏览器,如果你使用的是双核浏览器,请切换到极速/高速模式。</p></div><style>.app-loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top:0px;
|
top:0px;
|
||||||
left:0px;
|
left:0px;
|
||||||
|
4
dist/report.html
vendored
4
dist/report.html
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/static/js/app.6e805385.js
vendored
Normal file
1
dist/static/js/app.6e805385.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/static/js/app.b3dc07da.js
vendored
1
dist/static/js/app.b3dc07da.js
vendored
File diff suppressed because one or more lines are too long
@ -1,53 +0,0 @@
|
|||||||
|
|
||||||
<template>
|
|
||||||
<el-table ref="table" :data="columnData" row-key="prop" style="width: 100%" border>
|
|
||||||
<el-table-column prop="" label="排序" width="60">
|
|
||||||
<el-tag disable-transitions class="move" style="cursor: move;"><el-icon style="cursor: move;"><el-icon-d-caret/></el-icon></el-tag>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="label" label="列名">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-tag round disable-transitions :effect="scope.row.hide?'light':'dark'" :type="scope.row.hide?'info':''">{{ scope.row.label }}</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="hide" label="显示" width="60">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-switch v-model="scope.row.hide" size="small" :active-value="false" :inactive-value="true"/>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Sortable from 'sortablejs'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
emits: ['success'],
|
|
||||||
props: {
|
|
||||||
column: { type: Array, default: () => [] }
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
columnData: this.column
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.rowDrop()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
rowDrop(){
|
|
||||||
const _this = this
|
|
||||||
const tbody = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody')
|
|
||||||
Sortable.create(tbody, {
|
|
||||||
handle: ".move",
|
|
||||||
animation: 200,
|
|
||||||
ghostClass: "ghost",
|
|
||||||
onEnd({ newIndex, oldIndex }) {
|
|
||||||
const tableData = _this.columnData
|
|
||||||
const currRow = tableData.splice(oldIndex, 1)[0]
|
|
||||||
tableData.splice(newIndex, 0, currRow)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,193 +0,0 @@
|
|||||||
<!--
|
|
||||||
* @Descripttion: 文件导出
|
|
||||||
-->
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<slot :open="open">
|
|
||||||
<el-button type="primary" plain @click="open">导出</el-button>
|
|
||||||
</slot>
|
|
||||||
<el-drawer v-model="dialog" title="导出" :size="400" direction="rtl" append-to-body destroy-on-close>
|
|
||||||
<el-main style="padding: 0 20px 20px 20px;">
|
|
||||||
<div v-loading="downLoading" element-loading-text="正在处理中...">
|
|
||||||
<div v-if="downLoading && progress" style="position: absolute;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;z-index: 3000;">
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="downLoadProgress" style="width: 100%;margin-bottom: 120px;"/>
|
|
||||||
</div>
|
|
||||||
<el-tabs>
|
|
||||||
<el-tab-pane label="常规" lazy>
|
|
||||||
<el-form label-width="100px" label-position="left" style="margin: 10px 0 20px 0;">
|
|
||||||
<el-form-item label="文件名">
|
|
||||||
<el-input v-model="formData.fileName" placeholder="请输入文件名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="文件类型">
|
|
||||||
<el-select v-model="formData.fileType" placeholder="请选择文件类型">
|
|
||||||
<el-option v-for="item in fileTypes" :key="item" :label="'*.'+item" :value="item" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<slot name="form" :formData="formData"></slot>
|
|
||||||
</el-form>
|
|
||||||
<el-button v-if="async" type="primary" size="large" icon="el-icon-plus" style="width: 100%;" @click="download" :loading="asyncLoading">发起导出任务</el-button>
|
|
||||||
<el-button v-else type="primary" size="large" icon="el-icon-download" style="width: 100%;" @click="download">下 载</el-button>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="列设置" v-if="columnData.length>0" lazy>
|
|
||||||
<columnSet :column="columnData"></columnSet>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="其他参数" v-if="data && showData" lazy>
|
|
||||||
<el-descriptions :column="1" border size="small">
|
|
||||||
<el-descriptions-item v-for=" (val, key) in data" :key="key" :label="key">{{val}}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
</el-main>
|
|
||||||
|
|
||||||
</el-drawer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import columnSet from './column'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
columnSet
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
apiObj: { type: Object, default: () => {} },
|
|
||||||
fileName: { type: String, default: "" },
|
|
||||||
fileTypes: { type: Array, default: () => ['xlsx'] },
|
|
||||||
data: { type: Object, default: () => {} },
|
|
||||||
showData: { type: Boolean, default: false },
|
|
||||||
async: { type: Boolean, default: false },
|
|
||||||
column: { type: Array, default: () => [] },
|
|
||||||
blob: { type: Boolean, default: false },
|
|
||||||
progress: { type: Boolean, default: true }
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dialog: false,
|
|
||||||
formData: {
|
|
||||||
fileName: this.fileName,
|
|
||||||
fileType: this.fileTypes[0]
|
|
||||||
},
|
|
||||||
columnData: [],
|
|
||||||
downLoading: false,
|
|
||||||
downLoadProgress: 0,
|
|
||||||
asyncLoading: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch:{
|
|
||||||
'formData.fileType'(val) {
|
|
||||||
if(this.formData.fileName.includes(".")){
|
|
||||||
this.formData.fileName = this.formData.fileName.substring(0, this.formData.fileName.lastIndexOf('.')) + "." + val
|
|
||||||
}else{
|
|
||||||
this.formData.fileName = this.formData.fileName + "." + val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
open() {
|
|
||||||
this.dialog = true
|
|
||||||
this.formData = {
|
|
||||||
fileName: (this.fileName?this.fileName:(new Date().getTime()+'')) + "." + this.fileTypes[0],
|
|
||||||
fileType: this.fileTypes[0]
|
|
||||||
}
|
|
||||||
this.columnData = JSON.parse(JSON.stringify(this.column))
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.dialog = false
|
|
||||||
},
|
|
||||||
download() {
|
|
||||||
let columnArr = {
|
|
||||||
column: this.columnData.filter(n => !n.hide).map(n => n.prop).join(",")
|
|
||||||
}
|
|
||||||
let assignData = {...this.data, ...this.formData, ...columnArr}
|
|
||||||
if(this.async){
|
|
||||||
this.asyncDownload(this.apiObj, this.formData.fileName, assignData)
|
|
||||||
}else if(this.blob){
|
|
||||||
this.downloadFile(this.apiObj, this.formData.fileName, assignData)
|
|
||||||
}else{
|
|
||||||
this.linkFile(this.apiObj.url, this.formData.fileName, assignData)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
linkFile(url, fileName, data={}){
|
|
||||||
let a = document.createElement("a")
|
|
||||||
a.style = "display: none"
|
|
||||||
a.target = "_blank"
|
|
||||||
//a.download = fileName
|
|
||||||
a.href = url + this.toQueryString(data)
|
|
||||||
document.body.appendChild(a)
|
|
||||||
a.click()
|
|
||||||
document.body.removeChild(a)
|
|
||||||
},
|
|
||||||
downloadFile(apiObj, fileName, data={}){
|
|
||||||
this.downLoading = true
|
|
||||||
var _this = this
|
|
||||||
apiObj.get(data, {
|
|
||||||
responseType: 'blob',
|
|
||||||
onDownloadProgress(e){
|
|
||||||
if(e.lengthComputable){
|
|
||||||
_this.downLoadProgress = parseInt(e.loaded / e.total * 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).then(res => {
|
|
||||||
this.downLoading = false
|
|
||||||
this.downLoadProgress = 0
|
|
||||||
let url = URL.createObjectURL(res)
|
|
||||||
let a = document.createElement("a")
|
|
||||||
a.style = "display: none"
|
|
||||||
a.target = "_blank"
|
|
||||||
a.download = fileName
|
|
||||||
a.href = url
|
|
||||||
document.body.appendChild(a)
|
|
||||||
a.click()
|
|
||||||
document.body.removeChild(a)
|
|
||||||
URL.revokeObjectURL(url)
|
|
||||||
}).catch(err => {
|
|
||||||
this.downLoading = false
|
|
||||||
this.downLoadProgress = 0
|
|
||||||
this.$notify.error({
|
|
||||||
title: '下载文件失败',
|
|
||||||
message: err
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
asyncDownload(apiObj, fileName, data={}){
|
|
||||||
this.asyncLoading = true
|
|
||||||
apiObj.get(data).then(res => {
|
|
||||||
this.asyncLoading = false
|
|
||||||
if(res.code == 200){
|
|
||||||
this.dialog = false
|
|
||||||
this.$msgbox({
|
|
||||||
title: "成功发起任务",
|
|
||||||
message: `<div><img style="height:200px" src="@/assets/img/tasks-example.png"/></div><p>已成功发起导出任务,您可以操作其他事务</p><p>稍后可在 <b>任务中心</b> 查看执行结果</p>`,
|
|
||||||
type: "success",
|
|
||||||
confirmButtonText: "知道了",
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
center: true
|
|
||||||
}).catch(() => {})
|
|
||||||
}else{
|
|
||||||
this.$alert(res.message || "未知错误", "发起任务失败", {
|
|
||||||
type: "error",
|
|
||||||
center: true
|
|
||||||
}).catch(() => {})
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
this.asyncLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
toQueryString(obj){
|
|
||||||
let arr = []
|
|
||||||
for (var k in obj) {
|
|
||||||
arr.push(`${k}=${obj[k]}`)
|
|
||||||
}
|
|
||||||
return (arr.length>0?"?":"") + arr.join('&')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,128 +0,0 @@
|
|||||||
<!--
|
|
||||||
* @Descripttion: 文件导入
|
|
||||||
-->
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<slot :open="open">
|
|
||||||
<el-button type="primary" plain @click="open">导入</el-button>
|
|
||||||
</slot>
|
|
||||||
<el-dialog v-model="dialog" title="导入" :width="550" :close-on-click-modal="false" append-to-body destroy-on-close>
|
|
||||||
<el-progress v-if="loading" :text-inside="true" :stroke-width="20" :percentage="percentage" style="margin-bottom: 15px;"/>
|
|
||||||
<div v-loading="loading">
|
|
||||||
<el-upload ref="uploader"
|
|
||||||
drag
|
|
||||||
:accept="accept"
|
|
||||||
:maxSize="maxSize"
|
|
||||||
:limit="1"
|
|
||||||
:data="data"
|
|
||||||
:show-file-list="false"
|
|
||||||
:http-request="request"
|
|
||||||
:before-upload="before"
|
|
||||||
:on-progress="progress"
|
|
||||||
:on-success="success"
|
|
||||||
:on-error="error"
|
|
||||||
>
|
|
||||||
<slot name="uploader">
|
|
||||||
<el-icon class="el-icon--upload"><el-icon-upload-filled /></el-icon>
|
|
||||||
<div class="el-upload__text">
|
|
||||||
将文件拖到此处或 <em>点击选择文件上传</em>
|
|
||||||
</div>
|
|
||||||
</slot>
|
|
||||||
<template #tip>
|
|
||||||
<div class="el-upload__tip">
|
|
||||||
<template v-if="tip">{{tip}}</template>
|
|
||||||
<template v-else>请上传小于或等于 {{maxSize}}M 的 {{accept}} 格式文件</template>
|
|
||||||
<p v-if="templateUrl" style="margin-top: 7px;">
|
|
||||||
<el-link :href="templateUrl" target="_blank" type="primary" :underline="false">下载导入模板</el-link>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-upload>
|
|
||||||
<el-form v-if="$slots.form" inline label-width="100px" label-position="left" style="margin-top: 18px;">
|
|
||||||
<slot name="form" :formData="formData"></slot>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
emits: ['success'],
|
|
||||||
props: {
|
|
||||||
apiObj: { type: Object, default: () => {} },
|
|
||||||
data: { type: Object, default: () => {} },
|
|
||||||
accept: { type: String, default: ".xls, .xlsx" },
|
|
||||||
maxSize: { type: Number, default: 10 },
|
|
||||||
tip: { type: String, default: "" },
|
|
||||||
templateUrl: { type: String, default: "" }
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dialog: false,
|
|
||||||
loading: false,
|
|
||||||
percentage: 0,
|
|
||||||
formData: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
open(){
|
|
||||||
this.dialog = true
|
|
||||||
this.formData = {}
|
|
||||||
},
|
|
||||||
close(){
|
|
||||||
this.dialog = false
|
|
||||||
},
|
|
||||||
before(file){
|
|
||||||
const maxSize = file.size / 1024 / 1024 < this.maxSize;
|
|
||||||
if (!maxSize) {
|
|
||||||
this.$message.warning(`上传文件大小不能超过 ${this.maxSize}MB!`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.loading = true
|
|
||||||
},
|
|
||||||
progress(e){
|
|
||||||
this.percentage = e.percent
|
|
||||||
},
|
|
||||||
success(res, file){
|
|
||||||
this.$refs.uploader.handleRemove(file)
|
|
||||||
this.$refs.uploader.clearFiles()
|
|
||||||
this.loading = false
|
|
||||||
this.percentage = 0
|
|
||||||
this.$emit('success', res, this.close)
|
|
||||||
},
|
|
||||||
error(err){
|
|
||||||
this.loading = false
|
|
||||||
this.percentage = 0
|
|
||||||
this.$notify.error({
|
|
||||||
title: '上传文件未成功',
|
|
||||||
message: err
|
|
||||||
})
|
|
||||||
},
|
|
||||||
request(param){
|
|
||||||
Object.assign(param.data, this.formData)
|
|
||||||
const data = new FormData();
|
|
||||||
data.append(param.filename, param.file);
|
|
||||||
for (const key in param.data) {
|
|
||||||
data.append(key, param.data[key]);
|
|
||||||
}
|
|
||||||
this.apiObj.post(data, {
|
|
||||||
onUploadProgress: e => {
|
|
||||||
const complete = parseInt(((e.loaded / e.total) * 100) | 0, 10)
|
|
||||||
param.onProgress({percent: complete})
|
|
||||||
}
|
|
||||||
}).then(res => {
|
|
||||||
param.onSuccess(res)
|
|
||||||
}).catch(err => {
|
|
||||||
param.onError(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
53
src/components/xFileExport/column.vue
Normal file
53
src/components/xFileExport/column.vue
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<el-table ref="table" :data="columnData" row-key="prop" style="width: 100%" border>
|
||||||
|
<el-table-column prop="" label="排序" width="60">
|
||||||
|
<el-tag disable-transitions class="move" style="cursor: move;"><el-icon style="cursor: move;"><el-icon-d-caret /></el-icon></el-tag>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="label" label="列名">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag round disable-transitions :effect="scope.row.hide ? 'light' : 'dark'" :type="scope.row.hide ? 'info' : ''">{{ scope.row.label }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="hide" label="显示" width="60">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch v-model="scope.row.hide" size="small" :active-value="false" :inactive-value="true" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Sortable from 'sortablejs'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
emits: ['success'],
|
||||||
|
props: {
|
||||||
|
column: { type: Array, default: () => [] }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
columnData: this.column
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.rowDrop()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
rowDrop() {
|
||||||
|
const _this = this
|
||||||
|
const tbody = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody')
|
||||||
|
Sortable.create(tbody, {
|
||||||
|
handle: ".move",
|
||||||
|
animation: 200,
|
||||||
|
ghostClass: "ghost",
|
||||||
|
onEnd({ newIndex, oldIndex }) {
|
||||||
|
const tableData = _this.columnData
|
||||||
|
const currRow = tableData.splice(oldIndex, 1)[0]
|
||||||
|
tableData.splice(newIndex, 0, currRow)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
188
src/components/xFileExport/index.vue
Normal file
188
src/components/xFileExport/index.vue
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<!--
|
||||||
|
* @Descripttion: 文件导出
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<slot :open="open">
|
||||||
|
<el-button type="primary" plain @click="open">导出</el-button>
|
||||||
|
</slot>
|
||||||
|
<el-drawer v-model="dialog" title="导出" :size="400" direction="rtl" append-to-body destroy-on-close>
|
||||||
|
<el-main style="padding: 0 20px 20px 20px;">
|
||||||
|
<div v-loading="downLoading" element-loading-text="正在处理中...">
|
||||||
|
<div v-if="downLoading && progress" style="position: absolute;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;z-index: 3000;">
|
||||||
|
<el-progress :text-inside="true" :stroke-width="20" :percentage="downLoadProgress" style="width: 100%;margin-bottom: 120px;" />
|
||||||
|
</div>
|
||||||
|
<el-tabs>
|
||||||
|
<el-tab-pane label="常规" lazy>
|
||||||
|
<el-form label-width="100px" label-position="left" style="margin: 10px 0 20px 0;">
|
||||||
|
<el-form-item label="文件名">
|
||||||
|
<el-input v-model="formData.filename" placeholder="请输入文件名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件类型">
|
||||||
|
<el-select v-model="formData.fileType" placeholder="请选择文件类型">
|
||||||
|
<el-option v-for="item in fileTypes" :key="item" :label="'*.' + item" :value="item" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<slot name="form" :formData="formData"></slot>
|
||||||
|
</el-form>
|
||||||
|
<el-button v-if="async" type="primary" size="large" icon="el-icon-plus" style="width: 100%;" @click="download" :loading="asyncLoading">发起导出任务</el-button>
|
||||||
|
<el-button v-else type="primary" size="large" icon="el-icon-download" style="width: 100%;" @click="download">下 载</el-button>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="列设置" v-if="columnData.length > 0" lazy>
|
||||||
|
<columnSet :column="columnData"></columnSet>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="其他参数" v-if="data && showData" lazy>
|
||||||
|
<el-descriptions :column="1" border size="small">
|
||||||
|
<el-descriptions-item v-for=" (val, key) in data" :key="key" :label="key">{{ val }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import columnSet from './column'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
columnSet
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
api: { type: Object, default: () => { } },
|
||||||
|
filename: { type: String, default: "" },
|
||||||
|
fileTypes: { type: Array, default: () => ['xlsx'] },
|
||||||
|
data: { type: Object, default: () => { } },
|
||||||
|
showData: { type: Boolean, default: false },
|
||||||
|
async: { type: Boolean, default: false },
|
||||||
|
column: { type: Array, default: () => [] },
|
||||||
|
blob: { type: Boolean, default: false },
|
||||||
|
progress: { type: Boolean, default: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialog: false,
|
||||||
|
formData: {
|
||||||
|
filename: this.filename,
|
||||||
|
fileType: this.fileTypes[0]
|
||||||
|
},
|
||||||
|
columnData: [],
|
||||||
|
downLoading: false,
|
||||||
|
downLoadProgress: 0,
|
||||||
|
asyncLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'formData.fileType'(val) {
|
||||||
|
if (this.formData.filename.includes(".")) {
|
||||||
|
this.formData.filename = this.formData.filename.substring(0, this.formData.filename.lastIndexOf('.')) + "." + val
|
||||||
|
} else {
|
||||||
|
this.formData.filename = this.formData.filename + "." + val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.dialog = true
|
||||||
|
this.formData = {
|
||||||
|
filename: (this.filename ? this.filename : (new Date().getTime() + '')) + "." + this.fileTypes[0],
|
||||||
|
fileType: this.fileTypes[0]
|
||||||
|
}
|
||||||
|
this.columnData = JSON.parse(JSON.stringify(this.column))
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.dialog = false
|
||||||
|
},
|
||||||
|
download() {
|
||||||
|
let columnArr = {
|
||||||
|
column: this.columnData.filter(n => !n.hide).map(n => n.prop).join(",")
|
||||||
|
}
|
||||||
|
let assignData = { ...this.data, ...this.formData, ...columnArr }
|
||||||
|
if (this.async) {
|
||||||
|
this.asyncDownload(this.api, this.formData.filename, assignData)
|
||||||
|
} else if (this.blob) {
|
||||||
|
this.downloadFile(this.api, this.formData.filename, assignData)
|
||||||
|
} else {
|
||||||
|
this.linkFile(this.api, this.formData.filename, assignData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
linkFile(url, filename, data = {}) {
|
||||||
|
let a = document.createElement("a")
|
||||||
|
a.style = "display: none"
|
||||||
|
a.target = "_blank"
|
||||||
|
a.download = filename
|
||||||
|
a.href = url + (url.match('[?]') ? '&' : '?') + this.toQueryString(data);
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click()
|
||||||
|
document.body.removeChild(a)
|
||||||
|
},
|
||||||
|
downloadFile(api, filename, data = {}) {
|
||||||
|
this.downLoading = true
|
||||||
|
var _this = this
|
||||||
|
this.$http.get(api, data, {
|
||||||
|
responseType: 'blob',
|
||||||
|
onDownloadProgress(e) {
|
||||||
|
if (e.lengthComputable) {
|
||||||
|
_this.downLoadProgress = parseInt(e.loaded / e.total * 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
this.downLoading = false
|
||||||
|
this.downLoadProgress = 0
|
||||||
|
let url = URL.createObjectURL(res)
|
||||||
|
let a = document.createElement("a")
|
||||||
|
a.style = "display: none"
|
||||||
|
a.target = "_blank"
|
||||||
|
a.download = filename
|
||||||
|
a.href = url
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click()
|
||||||
|
document.body.removeChild(a)
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
}).catch(err => {
|
||||||
|
this.downLoading = false
|
||||||
|
this.downLoadProgress = 0
|
||||||
|
this.$notify.error({
|
||||||
|
title: '下载文件失败',
|
||||||
|
message: err
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
asyncDownload(api, filename, data = {}) {
|
||||||
|
this.asyncLoading = true
|
||||||
|
this.$http.get(api, data).then(res => {
|
||||||
|
this.asyncLoading = false
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.dialog = false
|
||||||
|
this.$msgbox({
|
||||||
|
title: "成功发起任务",
|
||||||
|
message: `<div><img style="height:200px" src="@/assets/img/tasks-example.png"/></div><p>已成功发起导出任务,您可以操作其他事务</p><p>稍后可在 <b>任务中心</b> 查看执行结果</p>`,
|
||||||
|
type: "success",
|
||||||
|
confirmButtonText: "知道了",
|
||||||
|
dangerouslyUseHTMLString: true,
|
||||||
|
center: true
|
||||||
|
}).catch(() => { })
|
||||||
|
} else {
|
||||||
|
this.$alert(res.message || "未知错误", "发起任务失败", {
|
||||||
|
type: "error",
|
||||||
|
center: true
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.asyncLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toQueryString(obj) {
|
||||||
|
let arr = []
|
||||||
|
for (var k in obj) {
|
||||||
|
arr.push(`${k}=${obj[k]}`)
|
||||||
|
}
|
||||||
|
return arr.join('&')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
114
src/components/xFileImport/index.vue
Normal file
114
src/components/xFileImport/index.vue
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<!--
|
||||||
|
* @Descripttion: 文件导入
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<slot :open="open">
|
||||||
|
<el-button type="primary" plain @click="open">导入</el-button>
|
||||||
|
</slot>
|
||||||
|
<el-dialog v-model="dialog" title="导入" :width="550" :close-on-click-modal="false" append-to-body destroy-on-close>
|
||||||
|
<el-progress v-if="loading" :text-inside="true" :stroke-width="20" :percentage="percentage" style="margin-bottom: 15px;" />
|
||||||
|
<div v-loading="loading">
|
||||||
|
<el-upload ref="uploader" drag :accept="accept" :maxSize="maxSize" :limit="1" :data="data" :show-file-list="false" :http-request="request" :before-upload="before" :on-progress="progress" :on-success="success" :on-error="error">
|
||||||
|
<slot name="uploader">
|
||||||
|
<el-icon class="el-icon--upload"><el-icon-upload-filled /></el-icon>
|
||||||
|
<div class="el-upload__text">
|
||||||
|
将文件拖到此处或 <em>点击选择文件上传</em>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">
|
||||||
|
<template v-if="tip">{{ tip }}</template>
|
||||||
|
<template v-else>请上传小于或等于 {{ maxSize }}M 的 {{ accept }} 格式文件</template>
|
||||||
|
<p v-if="templateUrl" style="margin-top: 7px;">
|
||||||
|
<el-link :href="templateUrl" target="_blank" type="primary" :underline="false">下载导入模板</el-link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
<el-form v-if="$slots.form" inline label-width="100px" label-position="left" style="margin-top: 18px;">
|
||||||
|
<slot name="form" :formData="formData"></slot>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['success'],
|
||||||
|
props: {
|
||||||
|
apiObj: { type: Object, default: () => { } },
|
||||||
|
data: { type: Object, default: () => { } },
|
||||||
|
accept: { type: String, default: ".xls, .xlsx" },
|
||||||
|
maxSize: { type: Number, default: 10 },
|
||||||
|
tip: { type: String, default: "" },
|
||||||
|
templateUrl: { type: String, default: "" }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialog: false,
|
||||||
|
loading: false,
|
||||||
|
percentage: 0,
|
||||||
|
formData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.dialog = true
|
||||||
|
this.formData = {}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.dialog = false
|
||||||
|
},
|
||||||
|
before(file) {
|
||||||
|
const maxSize = file.size / 1024 / 1024 < this.maxSize;
|
||||||
|
if (!maxSize) {
|
||||||
|
this.$message.warning(`上传文件大小不能超过 ${this.maxSize}MB!`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.loading = true
|
||||||
|
},
|
||||||
|
progress(e) {
|
||||||
|
this.percentage = e.percent
|
||||||
|
},
|
||||||
|
success(res, file) {
|
||||||
|
this.$refs.uploader.handleRemove(file)
|
||||||
|
this.$refs.uploader.clearFiles()
|
||||||
|
this.loading = false
|
||||||
|
this.percentage = 0
|
||||||
|
this.$emit('success', res, this.close)
|
||||||
|
},
|
||||||
|
error(err) {
|
||||||
|
this.loading = false
|
||||||
|
this.percentage = 0
|
||||||
|
this.$notify.error({
|
||||||
|
title: '上传文件未成功',
|
||||||
|
message: err
|
||||||
|
})
|
||||||
|
},
|
||||||
|
request(param) {
|
||||||
|
Object.assign(param.data, this.formData)
|
||||||
|
const data = new FormData();
|
||||||
|
data.append(param.filename, param.file);
|
||||||
|
for (const key in param.data) {
|
||||||
|
data.append(key, param.data[key]);
|
||||||
|
}
|
||||||
|
this.apiObj.post(data, {
|
||||||
|
onUploadProgress: e => {
|
||||||
|
const complete = parseInt(((e.loaded / e.total) * 100) | 0, 10)
|
||||||
|
param.onProgress({ percent: complete })
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
param.onSuccess(res)
|
||||||
|
}).catch(err => {
|
||||||
|
param.onError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
@ -2,10 +2,13 @@
|
|||||||
<el-container>
|
<el-container>
|
||||||
<el-header>
|
<el-header>
|
||||||
<div class="left-panel">
|
<div class="left-panel">
|
||||||
<el-radio-group v-model="dateType" v-if="data.dateGroup && data.dateGroup.length > 0" @change="changedateGroup" style="margin-right: 10px;">
|
<el-select v-if="data.select && data.select.items && data.select.items.length > 0" v-model="search[data.select.key || 'value']" v-bind="data.select.options" style="max-width: 240px; margin-right: 10px;">
|
||||||
<el-radio-button v-for="item in data.dateGroup" :key="item.key" :label="item.value" :value="item.value">{{ item.label }}</el-radio-button>
|
<el-option v-for="item in data.select.items" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-radio-group>
|
</el-select>
|
||||||
<el-date-picker class="hidden-sm-and-down" @change="changedate" format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm" v-model="search.date" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
|
<el-date-picker class="hidden-sm-and-down" format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm" v-model="search.date" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel" v-if="data.export && data.export.api">
|
||||||
|
<x-file-export v-bind="data.export"> </x-file-export>
|
||||||
</div>
|
</div>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main v-loading="statloading">
|
<el-main v-loading="statloading">
|
||||||
@ -40,18 +43,25 @@
|
|||||||
<script>
|
<script>
|
||||||
import xEcharts from '@/components/xEcharts';
|
import xEcharts from '@/components/xEcharts';
|
||||||
import xStatistic from '@/components/xStatistic';
|
import xStatistic from '@/components/xStatistic';
|
||||||
|
import xFileExport from '@/components/xFileExport';
|
||||||
export default {
|
export default {
|
||||||
name: 'chartlist',
|
name: 'chartlist',
|
||||||
components: {
|
components: {
|
||||||
xEcharts,
|
xEcharts,
|
||||||
xStatistic,
|
xStatistic,
|
||||||
|
xFileExport,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: {
|
data: {
|
||||||
type: Object, default: () => ({
|
type: Object, default: () => ({
|
||||||
statistic: [],
|
statistic: [],
|
||||||
chartList: [],
|
chartList: [],
|
||||||
dateGroup: [],
|
select: {
|
||||||
|
options: {},
|
||||||
|
items: [],
|
||||||
|
key: 'value'
|
||||||
|
},
|
||||||
|
export: {},
|
||||||
table: {},
|
table: {},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -60,8 +70,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
search: this.info,
|
search: this.info
|
||||||
dateType: null,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -77,13 +86,7 @@ export default {
|
|||||||
this.search = this.info;
|
this.search = this.info;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changedateGroup() {
|
|
||||||
this.data.dateGroup.forEach((item) => {
|
|
||||||
if (this.dateType === item.value) {
|
|
||||||
this.search[item.key] = item.value;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -97,7 +100,7 @@ export default {
|
|||||||
padding: 10px
|
padding: 10px
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart .el-col{
|
.chart .el-col {
|
||||||
margin: 15px 0;
|
margin: 15px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user