@@ -1,6 +1,6 @@
< template >
< div :style = "styleObj" >
< superslide v-if = "hackReset" :options="options" class="txtScroll-top" >
< superslide v-if = "hackReset" :options="options" class="txtScroll-top" ref="superslide" >
< ! - -表头 - - >
< div class = "title" >
< div v-for = "(item, index) in header" :key="index"
@@ -27,6 +27,48 @@
< / ul >
< / div >
< / superslide >
<!-- 添加导出按钮 , 仅在预览模式显示 -- >
< div v-if = "ispreview && optionsSetUp.showExportButton" class="export-button-container" :style="exportButtonContainerStyle" >
< div class = "export-button" :style = "exportButtonStyle" @click ="openExportDialog" >
< span class = "button-text" > 导出 < / span >
< / div >
< / div >
<!-- 导出对话框 -- >
< el-dialog
title = "导出表格数据"
:visible.sync = "exportDialogVisible"
:width = "dialogWidth"
:fullscreen = "isMobile"
:close-on-click-modal = "false"
center
:modal-append-to-body = "true"
append -to -body
:z-index = "9999"
class = "export-dialog" >
< el-form :model = "exportForm" label -width = " 100px " size = "small" >
< el-form-item label = "文件名称" >
< el-input v-model = "exportForm.fileName" placeholder="请输入文件名称" clearable > < / el-input >
< / el-form-item >
< el-form-item label = "导出格式" >
< el-radio-group v-model = "exportForm.format" >
< el -radio label = "excel" > Excel格式 ( . xlsx ) < / el-radio >
< el-radio label = "csv" > CSV格式 ( . csv ) < / el-radio >
< / el-radio-group >
< / el-form-item >
< el-form-item >
< div class = "export-info" >
< p > < i class = "el-icon-info" > < / i > 表格名称 : 数据表 < / p >
< p > < i class = "el-icon-tickets" > < / i > 数据总量 : { { list . length } } 行 { { header . length } } 列 < / p >
< / div >
< / el-form-item >
< / el-form >
< span slot = "footer" class = "dialog-footer" >
< el-button size = "small" @click ="exportDialogVisible = false" > 取 消 < / el -button >
< el-button size = "small" type = "primary" @click ="confirmExport" :loading = "exporting" > 确定导出 < / el-button >
< / span >
< / el-dialog >
< / div >
< / template >
< script >
@@ -60,6 +102,16 @@ export default {
optionsPosition : { } ,
optionsData : { } ,
flagInter : null ,
// 新增导出对话框相关数据
exportDialogVisible : false ,
exporting : false ,
exportForm : {
fileName : '' ,
format : 'excel'
} ,
// 添加设备检测变量
isMobile : false ,
screenWidth : window . innerWidth
} ;
} ,
computed : {
@@ -107,6 +159,57 @@ export default {
"border-color" : bodyStyle . borderColor ,
"color" : bodyStyle . bodyColor ,
} ;
} ,
// 新增样式计算属性
exportButtonStyle ( ) {
// 根据表头字体大小动态计算按钮大小
const headerFontSize = parseInt ( this . optionsSetUp . fontSizeHeader || 16 ) ;
// 计算图标尺寸,基于表头字体大小
const iconSize = Math . max ( 14 , Math . min ( 24 , headerFontSize * 1.1 ) ) ;
// 计算按钮高度,略大于图标尺寸
const buttonHeight = Math . round ( iconSize * 1.8 ) ;
return {
height : ` ${ buttonHeight } px ` ,
padding : '0 12px' ,
fontSize : ` ${ iconSize } px ` ,
backgroundColor : 'rgba(39, 174, 96, 0.9)' ,
borderRadius : '4px' ,
display : 'flex' ,
alignItems : 'center' ,
justifyContent : 'center' ,
boxShadow : '0 2px 12px 0 rgba(0, 0, 0, 0.1)' ,
color : '#ffffff'
} ;
} ,
exportButtonContainerStyle ( ) {
// 计算按钮容器的位置,使其恰好超出表头几个像素
const headerHeight = this . optionsSetUp . rowHeight || 50 ;
// 按钮高度
const buttonHeight = parseInt ( this . exportButtonStyle . height ) ;
// 设置按钮位置
return {
position : 'absolute' ,
top : ` - ${ buttonHeight + 5 } px ` , // 按钮高度 + 5px的间距
right : '10px' ,
zIndex : '100'
} ;
} ,
// 添加对话框宽度计算属性
dialogWidth ( ) {
if ( this . isMobile ) {
return '100%' ;
} else if ( this . screenWidth < 768 ) {
return '90%' ;
} else if ( this . screenWidth < 992 ) {
return '80%' ;
} else if ( this . screenWidth < 1200 ) {
return '60%' ;
} else {
return '420px' ;
}
}
} ,
watch : {
@@ -126,6 +229,13 @@ export default {
this . optionsData = this . value . data ;
this . initData ( ) ;
targetWidgetLinkageLogic ( this ) ; // 联动-目标组件逻辑
// 添加窗口大小变化监听
this . checkDeviceType ( ) ;
window . addEventListener ( 'resize' , this . handleResize ) ;
} ,
beforeDestroy ( ) {
// 移除窗口大小变化监听
window . removeEventListener ( 'resize' , this . handleResize ) ;
} ,
methods : {
initData ( ) {
@@ -230,7 +340,163 @@ export default {
styleJson [ "width" ] = this . optionsSetUp . dynamicAddTable [ index ] . width ;
}
return styleJson ;
}
} ,
// 添加的方法 - 设备类型检测
checkDeviceType ( ) {
this . screenWidth = window . innerWidth ;
this . isMobile = this . screenWidth <= 576 ;
} ,
// 处理窗口大小变化
handleResize ( ) {
this . checkDeviceType ( ) ;
} ,
// 打开导出对话框前检查设备类型
openExportDialog ( ) {
if ( ! this . list || this . list . length === 0 ) {
this . $message . warning ( '没有数据可导出' ) ;
return ;
}
// 重新检查设备类型
this . checkDeviceType ( ) ;
// 设置默认文件名(表格名称+日期时间)
const now = new Date ( ) ;
const dateStr = ` ${ now . getFullYear ( ) } ${ ( now . getMonth ( ) + 1 ) . toString ( ) . padStart ( 2 , '0' ) } ${ now . getDate ( ) . toString ( ) . padStart ( 2 , '0' ) } ` ;
const timeStr = ` ${ now . getHours ( ) . toString ( ) . padStart ( 2 , '0' ) } ${ now . getMinutes ( ) . toString ( ) . padStart ( 2 , '0' ) } ` ;
// 准备对话框数据
this . exportForm . fileName = ` 表格数据_ ${ dateStr } _ ${ timeStr } ` ;
this . exportForm . format = 'excel' ; // 默认选择Excel格式
// 显示导出对话框
this . exportDialogVisible = true ;
} ,
// 确认导出方法
confirmExport ( ) {
// 检查文件名是否为空
if ( ! this . exportForm . fileName || this . exportForm . fileName . trim ( ) === '' ) {
this . $message . warning ( '请输入文件名' ) ;
return ;
}
// 设置导出中状态
this . exporting = true ;
// 根据选择的格式执行不同的导出方法
try {
if ( this . exportForm . format === 'excel' ) {
this . doExportExcel ( ) ;
} else {
this . doExportCSV ( ) ;
// 只有CSV导出直接在这里显示成功消息和关闭对话框
this . $message . success ( '导出成功' ) ;
this . exportDialogVisible = false ;
this . exporting = false ;
}
} catch ( error ) {
console . error ( '导出失败:' , error ) ;
this . $message . error ( '导出失败,请重试' ) ;
this . exporting = false ;
}
} ,
// 执行Excel导出
doExportExcel ( ) {
// 引入xlsx库, 使用动态导入以减少初始加载时间
import ( 'xlsx' ) . then ( XLSX => {
// 准备数据:表头和内容
const tableHeaders = this . header . map ( header => header . name ) ;
const tableKeys = this . header . map ( header => header . key ) ;
// 创建表格数据数组,从列表数据映射
const tableData = this . list . map ( row => {
const rowData = { } ;
tableKeys . forEach ( ( key , index ) => {
rowData [ tableHeaders [ index ] ] = row [ key ] ;
} ) ;
return rowData ;
} ) ;
// 创建工作簿和工作表
const wb = XLSX . utils . book _new ( ) ;
const ws = XLSX . utils . json _to _sheet ( tableData , { header : tableHeaders } ) ;
// 计算列宽 - 动态计算合适的列宽
ws [ '!cols' ] = tableHeaders . map ( ( header , index ) => {
// 尝试计算合适的列宽,考虑标题和内容
const headerLength = header ? header . toString ( ) . length : 0 ;
// 计算该列数据的最大长度
let maxLength = headerLength ;
tableData . forEach ( row => {
const cellValue = row [ header ] ;
const cellLength = cellValue ? cellValue . toString ( ) . length : 0 ;
maxLength = Math . max ( maxLength , cellLength ) ;
} ) ;
// 为确保列宽适合内容,添加一些额外空间
return { wch : Math . min ( 50 , maxLength + 2 ) } ; // 限制最大宽度为50个字符
} ) ;
// 添加工作表到工作簿
XLSX . utils . book _append _sheet ( wb , ws , '数据表' ) ;
// 导出文件,使用用户指定的文件名
XLSX . writeFile ( wb , ` ${ this . exportForm . fileName } .xlsx ` ) ;
// 导出成功
this . $message . success ( '导出成功' ) ;
this . exportDialogVisible = false ;
this . exporting = false ;
} ) . catch ( err => {
console . error ( '导出Excel失败:' , err ) ;
this . $message . error ( '导出Excel失败, 请重试' ) ;
this . exporting = false ;
} ) ;
} ,
// 执行CSV导出
doExportCSV ( ) {
// 准备表头和数据
const tableHeaders = this . header . map ( header => header . name ) ;
const tableKeys = this . header . map ( header => header . key ) ;
// 创建CSV内容
let csvContent = '\uFEFF' ; // 添加BOM标记以支持中文
// 添加表头
csvContent += tableHeaders . join ( ',' ) + '\r\n' ;
// 添加数据行
this . list . forEach ( row => {
const rowValues = tableKeys . map ( key => {
const value = row [ key ] !== undefined && row [ key ] !== null ? row [ key ] : '' ;
// 如果值包含逗号、引号或换行符,需要用引号包裹并转义内部引号
if ( typeof value === 'string' && ( value . includes ( ',' ) || value . includes ( '"' ) || value . includes ( '\n' ) ) ) {
return ` " ${ value . replace ( /"/g , '""' ) } " ` ;
}
return value ;
} ) ;
csvContent += rowValues . join ( ',' ) + '\r\n' ;
} ) ;
// 创建Blob对象
const blob = new Blob ( [ csvContent ] , {
type : 'text/csv;charset=utf-8'
} ) ;
// 创建下载链接,使用用户指定的文件名
const link = document . createElement ( 'a' ) ;
link . href = URL . createObjectURL ( blob ) ;
link . download = ` ${ this . exportForm . fileName } .csv ` ;
document . body . appendChild ( link ) ;
link . click ( ) ;
document . body . removeChild ( link ) ;
} ,
}
} ;
< / script >
@@ -272,11 +538,134 @@ export default {
flex - wrap : wrap ;
}
/*.txtScroll-top .infoList li:nth-child(n) {
background: rgb(0, 59, 81);
/* 添加导出按钮样式 */
. export - button - container {
position : absolute ;
right : 0 px ;
z - index : 100 ;
. export - button {
transition : all 0.3 s ease ;
cursor : pointer ;
box - shadow : 0 2 px 8 px rgba ( 0 , 0 , 0 , 0.15 ) ;
& : hover {
transform : scale ( 1.05 ) ;
background - color : rgba ( 39 , 174 , 96 , 1 ) ! important ;
box - shadow : 0 4 px 12 px rgba ( 0 , 0 , 0 , 0.2 ) ;
}
i {
margin - right : 5 px ;
}
. button - text {
font - size : 14 px ;
font - weight : 500 ;
}
}
}
.txtScroll-top .infoList li:nth-child(2n) {
background: rgb(10, 39, 50);
}*/
/* 添加导出信息样式 */
. export - info {
background - color : # f5f7fa ;
border - radius : 4 px ;
padding : 10 px 15 px ;
margin - top : 5 px ;
p {
margin : 5 px 0 ;
font - size : 13 px ;
color : # 606266 ;
display : flex ;
align - items : center ;
i {
margin - right : 5 px ;
color : # 409 EFF ;
}
}
}
/* 确保对话框在大屏中显示正常 */
: : v - deep . el - dialog {
background - color : # fff ;
border - radius : 6 px ;
box - shadow : 0 3 px 10 px rgba ( 0 , 0 , 0 , 0.3 ) ;
position : relative ;
z - index : 9999 ! important ;
. el - dialog _ _header {
padding : 15 px 20 px ;
border - bottom : 1 px solid # e4e7ed ;
}
. el - dialog _ _body {
padding : 20 px ;
}
. el - dialog _ _footer {
padding : 10 px 20 px 15 px ;
border - top : 1 px solid # e4e7ed ;
}
. el - form - item {
margin - bottom : 15 px ;
}
}
/* 为移动设备添加特定样式 */
: : v - deep . export - dialog {
@ media screen and ( max - width : 576 px ) {
display : flex ;
flex - direction : column ;
margin : 0 ! important ;
. el - dialog {
width : 100 % ! important ;
margin : 0 ! important ;
max - width : 100 % ;
border - radius : 0 ;
display : flex ;
flex - direction : column ;
height : 100 % ;
. el - dialog _ _body {
flex : 1 ;
overflow - y : auto ;
padding : 15 px ;
}
. el - form - item _ _label {
width : 80 px ! important ;
}
. el - radio - group {
display : flex ;
flex - direction : column ;
. el - radio {
margin - left : 0 ;
margin - bottom : 10 px ;
}
}
}
}
@ media screen and ( max - width : 768 px ) {
. el - form - item _ _label {
width : 80 px ! important ;
}
. el - form {
. el - radio - group {
flex - wrap : wrap ;
}
}
}
}
: : v - deep . v - modal {
z - index : 9998 ! important ;
}
< / style >