代码:把相关lucksheet相关代码放到publick下面 (资源已上传)
父组件:
<template>
<div>
<a-row :gutter="24">
<a-col :span="3">
<a-card class="card">
<time-select-common ref="timeSelect" @setTime="setTime" @queryExcel="queryExcel"></time-select-common>
</a-card>
</a-col>
<a-col :span="21">
<a-card class="card">
<span class="table-page-search-submitButtons">
<a-button type="primary" key="import-data" style="margin-right: 20px" @click="importExcelHandleOpen" v-hasPermi="['product:report:upload']" >
<a-icon type="import" />
导入
</a-button>
<a-button key="export-data" style="margin-right: 20px" @click="exportExcelHandleOpen" v-hasPermi="['product:report:upload']" >
<a-icon type="export" />
导出
</a-button>
<a-button type="primary" v-hasPermi="['product:report:upload']" key="save-data" @click="saveExcelHandleOpen" >
<a-icon type="default" />
保存
</a-button>
</span>
<div :loading="loading">
<a-spin tip="加载中..." :spinning="spinning">
<sheet-table ref="sheetTable" @closeModal="excelVisible = false" @getExcelContent="queryExcel" @uploadExcel="uploadExcel"></sheet-table>
</a-spin>
</div>
</a-card>
</a-col>
</a-row>
<!-- 上传文件 -->
<a-modal
:title="'当前上传日期:'+selectDate"
:visible="excelVisible"
@cancel="importExcelHandleCancel"
:footer="null"
:maskClosable="false"
>
<file-upload-drg ref="fileUpload" @fileLook="fileLook" @uploadFile="importFile" :date="selectDate" @closeModal="excelVisible = false" @prievwExce="prievwExcel" @submitFile="submitFile"></file-upload-drg>
</a-modal>
</div>
</template>
<script>
import moment from 'moment'
import TimeSelectCommon from './component/time-select-common'
import storage from 'store'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import FileUploadDrg from '@/components/FileUploadDrg'
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@/assets/css/excel.css'
import axios from 'axios'
import {queryFiles} from '@/api/files/files'
import { previewImg } from '@/api/files/files'
import { getProductReport,saveProductReport } from '@/api/report/reportInfo'
import SheetTable from '@/components/SheetTable'
import { exportExcel } from '@/utils/lucksheetexport'
export default {
name: 'reportManage',
components:{TimeSelectCommon,
FileUploadDrg,
VueOfficeExcel,
SheetTable
},
props:{},
data(){
return{
monthValue: moment().format('YYYY-MM'), // 当前月份,初始值为当前月份
treeData: [], // 树的数据
isCanUpload:true,
excelVisible:false,
// 用户导入参数
upload: {
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: '文件上传',
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
modelId: undefined,
// 设置上传的请求头部
headers: { Authorization: 'Bearer ' + storage.get(ACCESS_TOKEN) },
// 上传的地址
url: process.env.VUE_APP_API_BASE_URL + '/calc/calcParam/importData',
},
selectDate:'',
excelData: [],
excel:'',
loading:false,
downloadImgUrl:process.env.VUE_APP_API_BASE_URL + '/file/getFileByPath',
option: {
title: '生产日报', // 设定表格名称
lang: 'zh', // 设定表格语言
plugins: [],
showinfobar: false,
showtoolbar: true,
},
style: {
margin: '0px',
padding: '0px',
width: '100%',
height: '100%'
},
id:null,
form:{},
spinning:false
}
},
created() {
},
mounted() {
},
methods:{
importFile(file){
this.$refs.sheetTable.importFile(file)
},
/** 导入excel窗体关闭 */
importExcelHandleCancel(e) {
this.excelVisible = false
},
/** 导入excel窗体开启 */
importExcelHandleOpen(e) {
if(this.$refs.timeSelect.isCanUpload ===true){
this.$message.warning('请选择日期后上传')
return
}
this.excelVisible = true
},
exportExcelHandleOpen() {
exportExcel(luckysheet.getAllSheets(), '泗水热电公司'+this.selectDate.split('-')[0]+'年'+this.selectDate.split('-')[1]+'月'+this.selectDate.split('-')[2]+'日'+'生产日报')
},
saveExcelHandleOpen(){
this.$refs.sheetTable.handleSave()
},
setTime(time){
this.selectDate = time
},
/** 上传文件确定按钮**/
submitFile(file){
},
rendered(){
console.log('渲染完成')
},
prievwExcel(data){
this.excelData = data
},
fileLook(file){
console.log('文件流'+file)
this.excel = file
this.excelVisible = false
},
queryExcel(){
console.log('日期'+this.selectDate)
this.spinning = true
const params = {
name:this.selectDate
}
getProductReport(params).then((res) => {
this.form = res.data
console.log('from:'+this.form)
this.spinning = false
if (res.data && res.data.content) {
var jsarr = JSON.parse(res.data.content)
this.$refs.sheetTable.createSheet(jsarr)
} else {
var data = [
{
index: 0,
name: 'sheet1',
data:[]
},
]
this.$refs.sheetTable.createSheet(data)
}
})
},
getExcelContent(id){
},
uploadExcel(form){
this.spinning = true
const formData={
content:form,
name:this.selectDate
}
saveProductReport(formData).then((response) => {
this.spinning = false
if (response.code === 200) {
this.$refs.timeSelect.getStatusByMouth()
this.$message.success(response.msg,1)
}else{
this.$message.error(response.msg,1)
}
}).catch(()=>{
}).finally(()=>{
this.spinning = false
})
}
}
}
</script>
<style scoped lang="scss">
.card{
height: calc(100vh - 100px);
overflow: auto;
padding:10px;
overflow-x:hidden
}
::v-deep .x-spreadsheet-scrollbar{
height: 10px!important;
}
</style>
左侧时间组件
<template>
<div>
<a-month-picker
v-model="monthValue"
format="YYYY-MM"
:allowClear="false"
picker="month"
style="width:100%"
@change="handleMonthValueChange" />
<br>
<a-tree
:show-line="true"
:show-icon="true"
:default-expanded-keys="['0-0']"
:data-source="treeData"
@select="onSelect"
>
<a-icon slot="icon" type="carry-out" />
<a-tree-node key="0-0" disabled>
<a-icon slot="icon" type="carry-out"/>
<span slot="title" style="color: #1890ff">{{ monthValue }}</span>
<a-tree-node :key="key" :title="item.title" v-for="(item,key) in treeDataObject"
:class="{ 'selected-node': item.flag == 'true'}">
<a-icon slot="icon" type="carry-out" />
</a-tree-node>
</a-tree-node>
</a-tree>
</div>
</template>
<script>
import moment from 'moment'
import { getStatusByMouth, saveProductReport } from '@/api/report/reportInfo'
export default {
name: 'TimeSelectCommon',
components:{},
props:{},
data(){
return{
monthValue: moment().format('YYYY-MM'), // 当前月份,初始值为当前月份
treeData: [], // 树的数据,
treeDataObject:null,
isCanUpload:true,
selectData:'',
currentMonth:''//当前月份
}
},
created() {
this.$nextTick(()=>{
// this.initTreeData()
this.getStatusByMouth()
})
},
mounted() {
this.currentMonth = moment().format('MM')
console.log('当前月份'+this.currentMonth)
},
methods:{
//初始化日期
getStatusByMouth(){
const formData={
yearAndMonth:this.monthValue
}
getStatusByMouth(formData).then((response) => {
if (response.code === 200 && response.data) {
this.treeDataObject = response.data
const sortedData = this.treeDataObject.sort((a, b) => {
const dateA = new Date(`2023-${a.title}`)
const dateB = new Date(`2023-${b.title}`)
return dateB.getTime() - dateA.getTime()
})
this.treeDataObject = sortedData
}
}).catch(()=>{
}).finally(()=>{
})
},
// 初始化树的数据
initTreeData() {
const { year, month } = this.getYearAndMonth(this.monthValue) // 获取年份和月份
const daysInMonth = moment(`${year}-${month}`, 'YYYY-MM').daysInMonth() // 获取当月的天数
const today = moment().format('DD') // 当前日期的天数
const parentNode = { // 父节点数据
title: `${year}-${month}`, // 父节点标题
key: '0-0',
children: [], // 子节点数据
}
//获取当前月份天数
const date = daysInMonth
if(this.currentMonth !== Number(month)){ //选中了其他月份
for (let i = parseInt(date); i >= 1; i--) {
const day = moment(`${year}-${month}-${i}`, 'YYYY-MM-DD').format('MM-DD') // 当前日期的格式化字符串
const childNode = {
title: day,
key: `0-0-${i}`, // 设置唯一的子节点 key 值
}
parentNode.children.push(childNode) // 将后面插入的日期依次比当前日期小,倒序插入到数组的最后面
}
}else{
for (let i = parseInt(today); i >= parseInt(today); i--) {
const day = moment(`${year}-${month}-${i}`, 'YYYY-MM-DD').format('MM-DD') // 当前日期的格式化字符串
const childNode = {
title: day,
key: `0-0-${i}`, // 设置唯一的子节点 key 值
}
parentNode.children.unshift(childNode) // 将当前天插入到数组的最前面
}
for (let i = parseInt(today) - 1; i >= 1; i--) {
const day = moment(`${year}-${month}-${i}`, 'YYYY-MM-DD').format('MM-DD') // 当前日期的格式化字符串
const childNode = {
title: day,
key: `0-0-${i}`, // 设置唯一的子节点 key 值
}
parentNode.children.push(childNode) // 将后面插入的日期依次比当前日期小,倒序插入到数组的最后面
}
}
this.treeData = [parentNode] // 将父节点数据设置为树的数据
this.treeDataObject = this.treeData[0] && this.treeData[0].children
console.log('节点数据'+JSON.stringify(this.treeDataObject))
},
// 处理月份选择事件
handleMonthValueChange(val) {
this.monthValue = moment(val).format('YYYY-MM')
this.getStatusByMouth()
// this.initTreeData() // 根据新的月份重新初始化树的数据
},
// 获取年份和月份
getYearAndMonth(dateString) {
const [year, month] = dateString.split('-')
return { year, month }
},
onSelect(selectedKeys, info) {
this.isCanUpload = false
this.selectData = moment(new Date()).format('YYYY') +'-'+info.selectedNodes[0].componentOptions.propsData.title
this.$emit('setTime',this.selectData)
this.$emit('queryExcel')
},
}
}
</script>
<style scoped lang="scss">
::v-deep .selected-node span:nth-child(2) {
background-color: #97c0ec;
}
</style>
封装的lucksheet组件直接拿来使用
lucksheet组件
<template>
<div>
<div :id="'luckysheet_content_' + id" :style="style"></div>
</div>
</template>
<script>
import LuckyExcel from 'luckyexcel'
export default {
name: 'ReportContent',
components: {
},
data() {
return {
formOpen:false,//是否有窗口已打开
id: null,
loading: false,
form: null,
selCell: null,
option: {
title: '报表维护', // 设定表格名称
lang: 'zh', // 设定表格语言
plugins: [],
showinfobar: false,
showtoolbar: true,
},
style: {
margin: '0px',
padding: '0px',
position: 'absolute',
width: '100%',
height: '100%'
},
}
},
filters: {},
created() {
const id = ''
this.id = id
this.option.container = 'luckysheet_content_' + id
this.$emit('getExcelContent',this.id)
},
activated() {},
mounted() {
this.style.height = document.body.scrollHeight - 120 + 'px'
},
beforeDestroy() {
console.log('报表配置销毁')
luckysheet.destroy(console.log('报表展示销毁成功'))
},
computed: {},
watch: {},
methods: {
importFile(file){
console.log('上传文件'+file)
LuckyExcel.transformExcelToLucky(file, (exportJson, luckysheetfile) => {
if (exportJson.sheets === null || exportJson.sheets.length === 0) {
this.$message.error('无法读取excel文件的内容,当前不支持xls文件!')
return
}
luckysheet.destroy()
this.option.data = exportJson.sheets
luckysheet.create(this.option)
//关掉弹窗
this.$emit('closeModal')
})
},
createSheet(data) {
var that = this
const hook = {
save: function () {
//保存
// that.handleSave()
},
//单元格选中回调
cellMousedown: function (cell, postion, sheetFile, ctx) {
that.selCell = postion
that.selCell.v = cell
console.log(that.selCell)
},
workbookCreateAfter: function (book) {
// for (let i = 0; i < that.tmpCellData.length; i++) {
// const cd = that.tmpCellData[i]
// }
},
}
this.option.hook = hook
this.option.data = data
// this.option.showtoolbarConfig = showtoolbarConfig
luckysheet.create(this.option)
this.selCell = {
r: 0,
c: 0,
}
},
setFormula(formula) {
luckysheet.setCellValue(formula.r, formula.c, formula.v)
},
onClose() {
this.formOpen=false
},
handleSave() {
const allSheets = luckysheet.getAllSheets()
for (var i = 0; i < allSheets.length; i++) {
if (allSheets[i].celldata.length > 0) {
this.num = ++this.num
}
allSheets[i].data = []
allSheets[i].scrollLeft = 0
allSheets[i].scrollTop = 0
allSheets[i].luckysheet_select_save = []
allSheets[i].luckysheet_selection_range = []
}
if (this.num === 0) {
this.$message.error('报表数据不能为空')
return
}
var jsonStr = JSON.stringify(allSheets)
this.$emit('uploadExcel',jsonStr)
},
},
}
</script>
<style lang="less">
.luckysheet * {
box-sizing: initial;
outline: 0 !important;
}
.luckysheet-row-count-show{
line-height: 1;
}
.luckysheet-scrollbar-ltr{
z-index: 99!important;
}
.luckysheet-wa-calculate-size {
z-index: 99 !important;
}
.luckysheet-module-selection{
.ant-input{
border-color: #40a9ff;
border-right-width: 1px !important;
outline: 0;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.ant-select-selection {
border-color: #40a9ff;
border-right-width: 1px !important;
outline: 0;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.has-error {
.ant-select-selection, .ant-input {
border-color: #ff4d4f;
border-right-width: 1px !important;
outline: 0;
box-shadow: 0 0 0 2px rgba(245, 34, 45, 0.2);
}
}
}
.luckysheet-input-box {
position: fixed;
}
.luckysheet-wa-editor{
z-index: 99!important;
}
.luckysheet-stat-area{
background-color: unset;
}
.model-style {
.ant-layout {
background: #ffffff00;
.ant-card {
background: #fff0;
.ant-card-head {
padding:0;
.ant-card-head-title{
padding:0;
div{
padding: 16px 24px;
}
}
.ant-card-extra{
padding:0;
i{
padding: 16px 24px;
}
}
}
.ant-card-actions {
margin: 0;
padding: 10px 16px;
list-style: none;
background: #FFFFFF00;
border-top: 1px solid #e8e8e8;
zoom: 1;
li {
float: right;
width: auto !important;
margin: 0 0 0 8px;
}
}
}
}
}
#data-link-module {
max-height: 500px;
overflow-y: auto;
}
</style>
文件导入组件
<template>
<div class="clearfix">
<a-upload-dragger
:action="uploadImgUrl"
accept=".xlsx"
:show-upload-list="true"
:headers="headers"
:fileList="fileList"
:custom-request="customRequest"
@change="handleChange"
>
<p class="ant-upload-drag-icon">
<a-icon type="inbox" />
</p>
<p class="ant-upload-text">
请点击或者将文件拖拽到此处上传
</p>
</a-upload-dragger>
<!-- <div class="buttons" style="text-align: right;margin-top:10px">-->
<!-- <a-button type="primary" @click="handleConfirm">确定</a-button>-->
<!-- <a-button style="margin-left: 8px" @click="handleCancel">取消</a-button>-->
<!-- </div>-->
</div>
</template>
<script>
import storage from 'store'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import moment from 'moment'
import axios from 'axios'
export default {
name: 'ImageUploadDrg',
props: {
value: {
type: String,
default: ''
},
type: {
type: String,
default: 'image'
},
count: {
type: Number,
default: 1
},
date:{
}
},
components: {
},
data () {
return {
loading: false,
open: false,
uploadImgUrl: process.env.VUE_APP_API_BASE_URL + '/file/uploadExcelByType',
headers: {
Authorization: 'Bearer ' + storage.get(ACCESS_TOKEN)
},
previewData:null,
uploadedCount: 0,
fileList:[]
}
},
mounted () {
},
methods: {
handleCancel () {
this.$emit('closeModal')
},
customRequest({ file, onProgress, onSuccess, onError }) {
console.log('==========='+file)
this.fileList = []
// const date = new Date().toLocaleDateString();
const fileType = file.type.split('/')[1];
const formData = new FormData();
formData.append('file', file);
formData.append('date', this.date);
axios.post(this.uploadImgUrl, formData, {
headers: this.headers,
onUploadProgress: progressEvent => {
const percent = Math.floor((progressEvent.loaded / progressEvent.total) * 100);
onProgress({ percent });
this.$emit('uploadFile',file)
}
})
.then(response => {
onSuccess(response.data);
})
.catch(error => {
onError(error);
});
},
async handleChange (info) {
if (info.file.status === 'uploading') {
this.loading = true
return
}
if (info.file.status === 'done') {
if (info.file.response.code !== 200) {
this.$message.error('上传失败' + info.file.response.msg)
this.loading = false
return
}
this.loading = false
this.$emit('input', info.file.response.url)
}
},
handleConfirm(){
this.$emit('submitFile')
}
}
}
</script>
<style lang="less" scoped>
img {
width: 128px;
height: 128px;
}
</style>