增加导出功能.
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;
|
||||
top: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-header>
|
||||
<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-radio-button v-for="item in data.dateGroup" :key="item.key" :label="item.value" :value="item.value">{{ item.label }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<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-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-option v-for="item in data.select.items" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<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>
|
||||
</el-header>
|
||||
<el-main v-loading="statloading">
|
||||
@ -40,18 +43,25 @@
|
||||
<script>
|
||||
import xEcharts from '@/components/xEcharts';
|
||||
import xStatistic from '@/components/xStatistic';
|
||||
import xFileExport from '@/components/xFileExport';
|
||||
export default {
|
||||
name: 'chartlist',
|
||||
components: {
|
||||
xEcharts,
|
||||
xStatistic,
|
||||
xFileExport,
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object, default: () => ({
|
||||
statistic: [],
|
||||
chartList: [],
|
||||
dateGroup: [],
|
||||
select: {
|
||||
options: {},
|
||||
items: [],
|
||||
key: 'value'
|
||||
},
|
||||
export: {},
|
||||
table: {},
|
||||
})
|
||||
},
|
||||
@ -60,8 +70,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: this.info,
|
||||
dateType: null,
|
||||
search: this.info
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -77,13 +86,7 @@ export default {
|
||||
this.search = this.info;
|
||||
},
|
||||
methods: {
|
||||
changedateGroup() {
|
||||
this.data.dateGroup.forEach((item) => {
|
||||
if (this.dateType === item.value) {
|
||||
this.search[item.key] = item.value;
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user