亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue3+luckysheet實現在線編輯Excel的項目實踐

 更新時間:2025年07月01日 09:55:43   作者:Passerby_K  
本文介紹了使用Luckysheet實現在線Excel表格功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

效果圖奉上:

在這里插入圖片描述

引入的依賴:

 "dependencies": {
    "@types/jquery": "^3.5.32",
    "@types/xlsx": "^0.0.36",
     "jquery": "^3.7.1",
   	 "xlsx": "^0.18.5",
 }

在index.html中引入:

    <!-- Luckysheet CSS -->
    <link rel="stylesheet"  rel="external nofollow"  />
    <link rel="stylesheet"  rel="external nofollow"  />
    <link rel="stylesheet"  rel="external nofollow"  />
    <link rel="stylesheet"  rel="external nofollow"  />
	
	    <!-- jQuery 和 Luckysheet 的JS CDN -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
    <!-- jQuery mousewheel 插件 -->
    <script src="https://cdn.jsdelivr.net/npm/jquery-mousewheel@3.1.13/jquery.mousewheel.min.js"></script>
    <!-- XLSX 庫 -->
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/luckysheet@2.1.13/dist/luckysheet.umd.js"></script>

完整代碼塊

<template>
    <div class="luckysheet-container">
        <!-- 工具欄 -->
        <div class="toolbar">
            <el-button type="primary" @click="importExcel">
                <el-icon>
                    <Upload />
                </el-icon>
                導入Excel
            </el-button>
            <el-button type="success" @click="exportExcel">
                <el-icon>
                    <Download />
                </el-icon>
                導出Excel
            </el-button>
            <el-button type="warning" @click="clearData">
                <el-icon>
                    <Delete />
                </el-icon>
                清空數據
            </el-button>
            <el-button type="info" @click="addSheet">
                <el-icon>
                    <Plus />
                </el-icon>
                添加工作表
            </el-button>
            <el-button type="success" @click="getData">
                <el-icon>
                    <Document />
                </el-icon>
                保存
            </el-button>
            <!-- <el-button type="info" @click="printSheet">
                <el-icon>
                    <Document />
                </el-icon>
                打印
            </el-button> -->
        </div>

        <!-- 隱藏的文件輸入框 -->
        <input ref="fileInput" type="file" accept=".xlsx,.xls" style="display: none" @change="handleFileChange" />

        <!-- Luckysheet容器 -->
        <div id="luckysheet" class="luckysheet-wrapper" ref="luckysheetRef"></div>
    </div>
</template>

<script setup lang="ts">
declare global {
    interface Window {
        luckysheet: any;
        XLSX: any;
        $: any;
        jQuery: any;
    }
}
import { ref, onMounted, onUnmounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Upload, Download, Delete, Plus, Document } from '@element-plus/icons-vue'


// 響應式數據
const fileInput = ref<HTMLInputElement>()
let luckysheetInstance: any = null
const luckysheetRef = ref<HTMLDivElement>()
// 默認數據
const defaultData = [
    {
        name: 'Sheet1',
        color: '',
        index: 0,
        status: 1,
        order: 0,
        hide: 0,
        row: 36,
        column: 18,
        defaultRowHeight: 19,
        defaultColWidth: 73,
        celldata: [
            {
                r: 0,
                c: 0,
                v: {
                    v: '歡迎使用Luckysheet在線編輯器',
                    ct: { fa: 'General', t: 'g' },
                    m: '歡迎使用Luckysheet在線編輯器',
                    bg: '#f4f5f8',
                    bl: 1,
                    it: 0,
                    ff: 0,
                    fs: 14,
                    fc: '#000000',
                    cl: 0,
                    un: 0,
                    vt: 0
                }
            },
            {
                r: 1,
                c: 0,
                v: {
                    v: '這是一個示例表格',
                    ct: { fa: 'General', t: 'g' },
                    m: '這是一個示例表格',
                    bg: '#ffffff',
                    bl: 0,
                    it: 0,
                    ff: 0,
                    fs: 12,
                    fc: '#000000',
                    cl: 0,
                    un: 0,
                    vt: 0
                }
            }
        ] as any[],
        config: {},
        scrollLeft: 0,
        scrollTop: 0,
        luckysheet_select_save: [],
        calcChain: [],
        isPivotTable: false,
        pivotTable: {},
        filter_select: {},
        filter: null,
        luckysheet_alternateformat_save: [],
        luckysheet_alternateformat_save_modelCustom: [],
        luckysheet_conditionformat_save: {},
        frozen: {},
        chart: [],
        zoomRatio: 1,
        image: [],
        showGridLines: 1,
        dataVerification: {}
    }
]

// 初始化Luckysheet
const initLuckysheet = (): Promise<boolean> => {
    return new Promise((resolve) => {
        console.log('開始初始化Luckysheet...')
        console.log('window.luckysheet:', window.luckysheet)

        // 檢查容器是否存在
        const container = document.getElementById('luckysheet')
        console.log('容器元素:', container)

        if (!container) {
            console.error('找不到luckysheet容器')
            resolve(false)
            return
        }

        // 清空容器
        container.innerHTML = ''

        const options = {
            container: 'luckysheet',
            title: '在線Excel編輯器',
            lang: 'zh',
            data: defaultData,
            showinfobar: true,
            showsheetbar: true,
            showstatisticBar: true,
            enableAddRow: true,
            enableAddCol: true,
            userInfo: false,
            myFolderUrl: '',
            showtoolbar: true,
            showtoolbarConfig: {
                // 隱藏Luckysheet自帶打印按鈕
                print: false
            },
            hook: {
                cellEditBefore: (r: number, c: number, value: any) => {
                    console.log('編輯前:', r, c, value)
                    return value
                },
                cellEditAfter: (r: number, c: number, oldValue: any, newValue: any) => {
                    console.log('編輯后:', r, c, oldValue, newValue)
                },
                cellUpdated: (r: number, c: number, oldValue: any, newValue: any) => {
                    console.log('單元格更新:', r, c, oldValue, newValue)
                }
            }
        }

        try {
            console.log('創(chuàng)建Luckysheet實例...')
            console.log('使用的配置:', options)

            // 直接調用全局方法
            window.luckysheet.create(options)

            // 檢查是否創(chuàng)建成功
            setTimeout(() => {
                const sheets = window.luckysheet.getAllSheets()
                console.log('初始化后獲取到的sheets:', sheets)
                if (sheets && sheets.length > 0) {
                    console.log('Luckysheet初始化成功')
                    luckysheetInstance = window.luckysheet // 使用全局對象作為實例
                    resolve(true)
                } else {
                    console.error('Luckysheet初始化失敗,沒有獲取到sheets')
                    resolve(false)
                }
            }, 1000)
        } catch (error) {
            console.error('創(chuàng)建Luckysheet實例失敗:', error)
            resolve(false)
        }
    })
}

// 等待Luckysheet加載
const waitForLuckysheet = (maxAttempts = 10): Promise<boolean> => {
    return new Promise((resolve) => {
        let attempts = 0

        const checkLuckysheet = () => {
            attempts++
            console.log(`檢查Luckysheet加載狀態(tài) (${attempts}/${maxAttempts})`)

            if (window.luckysheet && typeof window.luckysheet.create === 'function') {
                console.log('Luckysheet已加載完成')
                resolve(true)
            } else if (attempts >= maxAttempts) {
                console.error('Luckysheet加載超時')
                resolve(false)
            } else {
                setTimeout(checkLuckysheet, 500)
            }
        }

        checkLuckysheet()
    })
}

// 導入Excel文件
const importExcel = () => {
    console.log('importExcel被調用')
    console.log('window.XLSX:', window.XLSX)

    // 檢查XLSX庫是否可用
    if (!window.XLSX || !window.XLSX.utils) {
        ElMessage.error('XLSX庫未加載,請刷新頁面重試')
        return
    }

    fileInput.value?.click()
}

// 處理文件選擇
const handleFileChange = async (event: Event) => {
    const target = event.target as HTMLInputElement
    const file = target.files?.[0]
    if (!file) return

    console.log('選擇的文件:', file.name, file.size)

    try {
        ElMessage.info('正在解析Excel文件...')
        const data = await parseExcelFile(file)
        console.log('解析到的數據:', data)

        if (data && data.length > 0) {
            // 直接進行重新初始化,不再檢查可用方法
            console.log('開始加載數據到Luckysheet...')
            console.log('解析到的數據:', data)

            try {
                // 直接使用重新初始化的方式,避免transToData的錯誤
                console.log('跳過transToData方法,直接重新初始化...')
                ElMessage.info('正在加載Excel數據...')

                const initSuccess = await initLuckysheetWithData(data)
                if (initSuccess) {
                    // 初始化成功后,檢查導入結果
                    setTimeout(() => {
                        try {
                            const sheets = window.luckysheet.getAllSheets()
                            console.log('導入完成,檢查結果:')
                            console.log('- 工作表數量:', sheets.length)
                            sheets.forEach((sheet: any, index: number) => {
                                console.log(`- 工作表 ${index}: ${sheet.name}`)
                                console.log(`  - 行數: ${sheet.row}`)
                                console.log(`  - 列數: ${sheet.column}`)
                                console.log(`  - 單元格數據: ${sheet.celldata ? sheet.celldata.length : 0} 個`)
                                if (sheet.config && sheet.config.merge) {
                                    console.log(`  - 合并單元格: ${sheet.config.merge.length} 個`)
                                }
                            })

                            // 顯示成功消息
                            const totalCells = sheets.reduce((total: number, sheet: any) => {
                                return total + (sheet.celldata ? sheet.celldata.length : 0)
                            }, 0)

                            // 生成詳細的導入報告
                            const importReport = {
                                totalSheets: sheets.length,
                                totalCells,
                                sheets: sheets.map((sheet: any) => ({
                                    name: sheet.name,
                                    cells: sheet.celldata ? sheet.celldata.length : 0,
                                    rows: sheet.row,
                                    columns: sheet.column
                                }))
                            }

                            console.log('導入報告:', importReport)

                            // 顯示詳細成功消息
                            const sheetDetails = importReport.sheets.map(s =>
                                `${s.name}(${s.cells}個單元格)`
                            ).join('、')

                            ElMessage.success(`Excel文件導入成功!共導入 ${importReport.totalSheets} 個工作表,${importReport.totalCells} 個單元格數據`)
                            console.log(`工作表詳情: ${sheetDetails}`)

                            // 顯示合并單元格檢測信息
                            if (data.some((sheet: any) => sheet.config && sheet.config.merge && sheet.config.merge.length > 0)) {
                                const mergeInfo = data
                                    .filter((sheet: any) => sheet.config && sheet.config.merge && sheet.config.merge.length > 0)
                                    .map((sheet: any) => `${sheet.name}(${sheet.config.merge.length}個)`)
                                    .join('、')

                                console.log(`檢測到合并單元格: ${mergeInfo}`)
                                ElMessage.info(`注意:檢測到合并單元格但暫時未應用,以避免顯示錯誤`)
                            }
                        } catch (error) {
                            console.error('檢查導入結果時出錯:', error)
                            ElMessage.success('Excel文件導入成功!')
                        }
                    }, 500)
                } else {
                    ElMessage.error('表格初始化失敗,請刷新頁面重試')
                }
            } catch (loadError) {
                console.error('加載數據失敗:', loadError)
                ElMessage.error('加載數據失敗: ' + (loadError instanceof Error ? loadError.message : '未知錯誤'))
            }
        } else {
            ElMessage.warning('Excel文件為空或格式不正確')
        }
    } catch (error) {
        console.error('導入Excel失敗:', error)
        const errorMessage = error instanceof Error ? error.message : '未知錯誤'
        ElMessage.error('導入Excel失敗: ' + errorMessage)
    }
    target.value = ''
}

// 使用新數據初始化Luckysheet
const initLuckysheetWithData = (data: any[]): Promise<boolean> => {
    return new Promise((resolve) => {
        console.log('開始使用新數據初始化Luckysheet...')
        console.log('新數據:', data)

        // 檢查容器是否存在
        const container = document.getElementById('luckysheet')
        console.log('容器元素:', container)

        if (!container) {
            console.error('找不到luckysheet容器')
            resolve(false)
            return
        }

        // 清空容器
        container.innerHTML = ''

        // 驗證和清理數據
        const cleanData = data.map((sheet: any, index: number) => {
            console.log(`清理工作表 ${index}:`, sheet.name)

            // 確保必要的字段存在
            const cleanSheet = {
                name: sheet.name || `Sheet${index + 1}`,
                color: sheet.color || '',
                index: sheet.index || index,
                status: sheet.status || 1,
                order: sheet.order || index,
                hide: sheet.hide || 0,
                row: Math.max(sheet.row || 36, 36),
                column: Math.max(sheet.column || 18, 18),
                defaultRowHeight: sheet.defaultRowHeight || 19,
                defaultColWidth: sheet.defaultColWidth || 73,
                celldata: Array.isArray(sheet.celldata) ? sheet.celldata : [],
                config: sheet.config || {},
                scrollLeft: sheet.scrollLeft || 0,
                scrollTop: sheet.scrollTop || 0,
                luckysheet_select_save: sheet.luckysheet_select_save || [],
                calcChain: sheet.calcChain || [],
                isPivotTable: sheet.isPivotTable || false,
                pivotTable: sheet.pivotTable || {},
                filter_select: sheet.filter_select || {},
                filter: sheet.filter || null,
                luckysheet_alternateformat_save: sheet.luckysheet_alternateformat_save || [],
                luckysheet_alternateformat_save_modelCustom: sheet.luckysheet_alternateformat_save_modelCustom || [],
                luckysheet_conditionformat_save: sheet.luckysheet_conditionformat_save || {},
                frozen: sheet.frozen || {},
                chart: sheet.chart || [],
                zoomRatio: sheet.zoomRatio || 1,
                image: sheet.image || [],
                showGridLines: sheet.showGridLines || 1,
                dataVerification: sheet.dataVerification || {}
            }

            // 暫時禁用合并單元格處理以避免內部錯誤
            if (cleanSheet.config.merge) {
                console.log(`工作表 ${index} 移除合并單元格配置以避免內部錯誤`)
                delete cleanSheet.config.merge
            }

            console.log(`清理后的工作表 ${index}:`, cleanSheet)
            return cleanSheet
        })

        const options = {
            container: 'luckysheet',
            title: '在線Excel編輯器',
            lang: 'zh',
            data: cleanData,
            showinfobar: true,
            showsheetbar: true,
            showstatisticBar: true,
            enableAddRow: true,
            enableAddCol: true,
            userInfo: false,
            myFolderUrl: '',
            showtoolbar: true,
            showtoolbarConfig: {
                // 隱藏Luckysheet自帶打印按鈕
                print: false
            },
            hook: {
                cellEditBefore: (r: number, c: number, value: any) => {
                    console.log('編輯前:', r, c, value)
                    return value
                },
                cellEditAfter: (r: number, c: number, oldValue: any, newValue: any) => {
                    console.log('編輯后:', r, c, oldValue, newValue)
                },
                cellUpdated: (r: number, c: number, oldValue: any, newValue: any) => {
                    console.log('單元格更新:', r, c, oldValue, newValue)
                }
            }
        }

        try {
            console.log('使用新數據創(chuàng)建Luckysheet實例...')
            console.log('使用的配置:', options)

            // 直接調用全局方法
            window.luckysheet.create(options)

            // 檢查是否創(chuàng)建成功
            setTimeout(() => {
                try {
                    const sheets = window.luckysheet.getAllSheets()
                    console.log('重新初始化后獲取到的sheets:', sheets)
                    if (sheets && sheets.length > 0) {
                        console.log('Luckysheet重新初始化成功')
                        luckysheetInstance = window.luckysheet // 使用全局對象作為實例
                        resolve(true)
                    } else {
                        console.error('Luckysheet重新初始化失敗,沒有獲取到sheets')
                        resolve(false)
                    }
                } catch (error) {
                    console.error('檢查初始化結果時出錯:', error)
                    // 即使有錯誤,如果容器中有內容,也認為初始化成功
                    if (container.children.length > 0) {
                        console.log('容器中有內容,認為初始化成功')
                        luckysheetInstance = window.luckysheet
                        resolve(true)
                    } else {
                        resolve(false)
                    }
                }
            }, 1000)
        } catch (error) {
            console.error('使用新數據創(chuàng)建Luckysheet實例失敗:', error)
            resolve(false)
        }
    })
}

// 解析Excel文件
const parseExcelFile = (file: File): Promise<any[]> => {
    return new Promise((resolve, reject) => {
        console.log('開始解析Excel文件...')
        console.log('文件信息:', {
            name: file.name,
            size: file.size,
            type: file.type,
            lastModified: file.lastModified
        })

        // 檢查XLSX庫是否可用
        if (!window.XLSX || !window.XLSX.utils) {
            console.error('XLSX庫未加載')
            reject(new Error('XLSX庫未加載'))
            return
        }

        // 檢查文件類型
        const validTypes = [
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
            'application/vnd.ms-excel', // .xls
            'application/octet-stream' // 某些系統(tǒng)可能顯示為這個類型
        ]

        if (!validTypes.includes(file.type) && !file.name.match(/\.(xlsx|xls)$/i)) {
            console.error('不支持的文件類型:', file.type)
            reject(new Error('不支持的文件類型,請選擇.xlsx或.xls文件'))
            return
        }

        const reader = new FileReader()

        reader.onload = (e) => {
            try {
                console.log('文件讀取完成,開始解析...')
                const result = e.target?.result
                console.log('讀取結果類型:', typeof result)

                if (!result) {
                    reject(new Error('文件讀取結果為空'))
                    return
                }

                const data = new Uint8Array(result as ArrayBuffer)
                console.log('轉換為Uint8Array,長度:', data.length)

                // 嘗試不同的解析方式
                let workbook
                try {
                    workbook = window.XLSX.read(data, { type: 'array', cellStyles: true })
                } catch (readError) {
                    console.error('使用array類型解析失敗,嘗試binary類型:', readError)
                    try {
                        workbook = window.XLSX.read(data, { type: 'binary', cellStyles: true })
                    } catch (binaryError) {
                        console.error('使用binary類型解析也失敗:', binaryError)
                        reject(new Error('無法解析Excel文件,請檢查文件格式'))
                        return
                    }
                }

                console.log('工作簿解析成功:', workbook)
                console.log('工作表名稱:', workbook.SheetNames)

                if (!workbook.SheetNames || workbook.SheetNames.length === 0) {
                    reject(new Error('Excel文件中沒有找到工作表'))
                    return
                }

                const sheets = workbook.SheetNames.map((sheetName: string, index: number) => {
                    console.log(`處理工作表: ${sheetName}`)
                    const worksheet = workbook.Sheets[sheetName]

                    if (!worksheet) {
                        console.warn(`工作表 ${sheetName} 為空`)
                        return {
                            name: sheetName,
                            color: '',
                            index,
                            status: 1,
                            order: index,
                            hide: 0,
                            row: 36,
                            column: 18,
                            defaultRowHeight: 19,
                            defaultColWidth: 73,
                            celldata: [],
                            config: {},
                            scrollLeft: 0,
                            scrollTop: 0,
                            luckysheet_select_save: [],
                            calcChain: [],
                            isPivotTable: false,
                            pivotTable: {},
                            filter_select: {},
                            filter: null,
                            luckysheet_alternateformat_save: [],
                            luckysheet_alternateformat_save_modelCustom: [],
                            luckysheet_conditionformat_save: {},
                            frozen: {},
                            chart: [],
                            zoomRatio: 1,
                            image: [],
                            showGridLines: 1,
                            dataVerification: {}
                        }
                    }

                    // 獲取單元格范圍
                    const range = window.XLSX.utils.decode_range(worksheet['!ref'] || 'A1')
                    console.log(`工作表 ${sheetName} 范圍:`, range)

                    const celldata: any[] = []
                    const merges: any[] = []

                    // 處理合并單元格 - 暫時禁用以避免mergeCalculation錯誤
                    if (worksheet['!merges']) {
                        console.log(`工作表 ${sheetName} 檢測到合并單元格:`, worksheet['!merges'].length, '個')
                        console.log('注意:合并單元格已識別但暫時禁用以避免內部錯誤')

                        // 暫時注釋掉合并單元格處理,但保留識別信息
                        /*
                        worksheet['!merges'].forEach((merge: any, mergeIndex: number) => {
                          try {
                            // 確保合并單元格數據格式正確
                            const mergeData = {
                              r: merge.s.r,
                              c: merge.s.c,
                              rs: merge.e.r - merge.s.r + 1,
                              cs: merge.e.c - merge.s.c + 1
                            }
                            
                            // 驗證合并單元格數據
                            if (mergeData.r >= 0 && mergeData.c >= 0 && 
                                mergeData.rs > 0 && mergeData.cs > 0 &&
                                mergeData.r + mergeData.rs <= range.e.r + 1 &&
                                mergeData.c + mergeData.cs <= range.e.c + 1) {
                              merges.push(mergeData)
                              console.log(`合并單元格 ${mergeIndex}:`, mergeData)
                            } else {
                              console.warn(`跳過無效的合并單元格 ${mergeIndex}:`, mergeData)
                            }
                          } catch (mergeError) {
                            console.warn(`處理合并單元格 ${mergeIndex} 時出錯:`, mergeError)
                          }
                        })
                        */
                    }

                    // 遍歷所有單元格
                    for (let r = range.s.r; r <= range.e.r; r++) {
                        for (let c = range.s.c; c <= range.e.c; c++) {
                            const cellAddress = window.XLSX.utils.encode_cell({ r, c })
                            const cell = worksheet[cellAddress]

                            if (cell) {
                                const cellData: any = {
                                    r,
                                    c,
                                    v: {
                                        v: cell.v,
                                        ct: { fa: 'General', t: 'g' },
                                        m: String(cell.v),
                                        // 只有有背景色時才加bg字段
                                        ...(cell.s && cell.s.fill && cell.s.fill.fgColor && cell.s.fill.fgColor.rgb
                                            ? { bg: '#' + cell.s.fill.fgColor.rgb.substring(2) }
                                            : {}),
                                        bl: 0,
                                        it: 0,
                                        ff: 0,
                                        fs: 10,
                                        fc: '#000000',
                                        cl: 0,
                                        un: 0,
                                        vt: 0
                                    }
                                }

                                // 處理單元格格式
                                if (cell.s) {
                                    const style = cell.s

                                    // 字體格式
                                    if (style.font) {
                                        if (style.font.bold) cellData.v.bl = 1
                                        if (style.font.italic) cellData.v.it = 1
                                        if (style.font.size) cellData.v.fs = style.font.size
                                        if (style.font.color) {
                                            const color = style.font.color
                                            if (color.rgb) {
                                                cellData.v.fc = '#' + color.rgb.substring(2)
                                            }
                                        }
                                    }

                                    // 背景色
                                    if (style.fill) {
                                        if (style.fill.fgColor) {
                                            const bgColor = style.fill.fgColor
                                            if (bgColor.rgb) {
                                                cellData.v.bg = '#' + bgColor.rgb.substring(2)
                                            }
                                        }
                                    }

                                    // 對齊方式
                                    if (style.alignment) {
                                        const alignment = style.alignment
                                        if (alignment.horizontal) {
                                            switch (alignment.horizontal) {
                                                case 'left':
                                                    cellData.v.ff = 0
                                                    break
                                                case 'center':
                                                    cellData.v.ff = 1
                                                    break
                                                case 'right':
                                                    cellData.v.ff = 2
                                                    break
                                            }
                                        }
                                        if (alignment.vertical) {
                                            switch (alignment.vertical) {
                                                case 'top':
                                                    cellData.v.vt = 0
                                                    break
                                                case 'middle':
                                                    cellData.v.vt = 1
                                                    break
                                                case 'bottom':
                                                    cellData.v.vt = 2
                                                    break
                                            }
                                        }
                                    }

                                    // 邊框
                                    if (style.border) {
                                        const border = style.border
                                        if (border.top || border.bottom || border.left || border.right) {
                                            cellData.v.cl = 1
                                        }
                                    }
                                }

                                // 處理數字格式
                                if (cell.t === 'n' && cell.z) {
                                    cellData.v.ct = { fa: cell.z, t: 'n' }
                                } else if (cell.t === 'd') {
                                    cellData.v.ct = { fa: 'yyyy-mm-dd', t: 'd' }
                                } else if (cell.t === 'b') {
                                    cellData.v.ct = { fa: 'General', t: 'b' }
                                }

                                celldata.push(cellData)
                            }
                        }
                    }

                    console.log(`工作表 ${sheetName} 轉換后的celldata:`, celldata)
                    console.log(`工作表 ${sheetName} 合并單元格:`, merges)

                    // 驗證數據完整性
                    if (celldata.length === 0) {
                        console.warn(`工作表 ${sheetName} 沒有數據,添加默認單元格`)
                        celldata.push({
                            r: 0,
                            c: 0,
                            v: {
                                v: '',
                                ct: { fa: 'General', t: 'g' },
                                m: '',
                                bg: '#ffffff',
                                bl: 0,
                                it: 0,
                                ff: 0,
                                fs: 10,
                                fc: '#000000',
                                cl: 0,
                                un: 0,
                                vt: 0
                            }
                        })
                    }

                    // 創(chuàng)建工作表配置 - 不處理邊框
                    const sheetConfig: any = {}
                    // 不再賦值borderInfo,保持默認網格線

                    return {
                        name: sheetName,
                        color: '',
                        index,
                        status: 1,
                        order: index,
                        hide: 0,
                        row: Math.max(range.e.r + 1, 36),
                        column: Math.max(range.e.c + 1, 18),
                        defaultRowHeight: 19,
                        defaultColWidth: 73,
                        celldata,
                        config: sheetConfig,
                        scrollLeft: 0,
                        scrollTop: 0,
                        luckysheet_select_save: [],
                        calcChain: [],
                        isPivotTable: false,
                        pivotTable: {},
                        filter_select: {},
                        filter: null,
                        luckysheet_alternateformat_save: [],
                        luckysheet_alternateformat_save_modelCustom: [],
                        luckysheet_conditionformat_save: {},
                        frozen: {},
                        chart: [],
                        zoomRatio: 1,
                        image: [],
                        showGridLines: 1,
                        dataVerification: {}
                    }
                })

                console.log('所有工作表轉換完成:', sheets)
                resolve(sheets)
            } catch (error) {
                console.error('解析Excel文件時出錯:', error)
                reject(error)
            }
        }

        reader.onerror = (error) => {
            console.error('文件讀取失敗:', error)
            reject(new Error('文件讀取失敗'))
        }

        reader.onprogress = (event) => {
            if (event.lengthComputable) {
                const progress = (event.loaded / event.total) * 100
                console.log(`文件讀取進度: ${progress.toFixed(2)}%`)
            }
        }

        console.log('開始讀取文件...')
        reader.readAsArrayBuffer(file)
    })
}

// 導出Excel
const exportExcel = async () => {
    console.log('exportExcel被調用')
    console.log('luckysheetInstance:', luckysheetInstance)
    console.log('window.luckysheet:', window.luckysheet)
    console.log('window.XLSX:', window.XLSX)

    try {
        // 檢查XLSX庫是否可用
        if (!window.XLSX || !window.XLSX.utils) {
            ElMessage.error('XLSX庫未加載,請刷新頁面重試')
            return
        }

        // 檢查是否有可用的Luckysheet實例
        const availableInstance = luckysheetInstance || window.luckysheet

        if (!availableInstance || typeof availableInstance.getAllSheets !== 'function') {
            console.log('Luckysheet實例不可用,嘗試重新初始化...')

            // 等待Luckysheet加載
            const isLoaded = await waitForLuckysheet()
            if (!isLoaded) {
                ElMessage.error('Luckysheet加載失敗,請刷新頁面重試')
                return
            }

            // 嘗試初始化
            const initSuccess = await initLuckysheet()
            if (initSuccess) {
                // 等待初始化完成
                setTimeout(() => {
                    exportExcel()
                }, 1500)
            } else {
                ElMessage.error('表格初始化失敗,請刷新頁面重試')
            }
            return
        }

        ElMessage.info('正在導出Excel文件...')
        console.log('開始導出,使用實例:', availableInstance)

        const data = availableInstance.getAllSheets()
        console.log('獲取到的數據:', data)

        if (!data || data.length === 0) {
            ElMessage.warning('沒有數據可導出')
            return
        }

        const workbook = window.XLSX.utils.book_new()

        data.forEach((sheet: any, index: number) => {
            console.log(`處理工作表 ${index}:`, sheet.name)

            const sheetData: any[][] = []
            const celldata = Array.isArray(sheet.celldata) ? sheet.celldata : []

            if (celldata.length === 0) {
                console.log(`工作表 ${sheet.name} 為空,創(chuàng)建空工作表`)
                const worksheet = window.XLSX.utils.aoa_to_sheet([['']])
                window.XLSX.utils.book_append_sheet(workbook, worksheet, sheet.name)
                return
            }

            // 計算最大行列
            const maxRow = Math.max(...celldata.map((cell: any) => cell.r)) + 1
            const maxCol = Math.max(...celldata.map((cell: any) => cell.c)) + 1

            console.log(`工作表 ${sheet.name} 大小: ${maxRow}行 x ${maxCol}列`)

            // 初始化二維數組
            for (let r = 0; r < maxRow; r++) {
                sheetData[r] = []
                for (let c = 0; c < maxCol; c++) {
                    sheetData[r][c] = ''
                }
            }

            // 填充數據
            celldata.forEach((cell: any) => {
                if (cell.v && cell.v.v !== undefined) {
                    sheetData[cell.r][cell.c] = cell.v.v
                }
            })

            console.log(`工作表 ${sheet.name} 數據:`, sheetData)

            const worksheet = window.XLSX.utils.aoa_to_sheet(sheetData)
            window.XLSX.utils.book_append_sheet(workbook, worksheet, sheet.name)
        })

        const fileName = `luckysheet_export_${new Date().getTime()}.xlsx`
        console.log('導出文件名:', fileName)

        window.XLSX.writeFile(workbook, fileName)
        ElMessage.success('Excel文件導出成功!')
    } catch (error) {
        console.error('導出Excel失敗:', error)
        const errorMessage = error instanceof Error ? error.message : '未知錯誤'
        ElMessage.error('導出Excel失敗: ' + errorMessage)
    }
}

// 清空數據
const clearData = async () => {
    try {
        await ElMessageBox.confirm('確定要清空所有數據嗎?此操作不可恢復。', '確認清空', {
            confirmButtonText: '確定',
            cancelButtonText: '取消',
            type: 'warning'
        })

        console.log('開始清空數據...')
        // 重新初始化 Luckysheet 使用默認數據
        const success = await initLuckysheetWithData(defaultData)
        if (success) {
            ElMessage.success('數據已清空')
        } else {
            ElMessage.error('清空數據失敗,請刷新頁面重試')
        }
    } catch (error) {
        if (error !== 'cancel') {
            console.error('清空數據失敗:', error)
            ElMessage.error('清空數據失敗')
        }
    }
}

// 添加工作表
const addSheet = async () => {
    try {
        console.log('開始添加工作表...')

        // 獲取當前所有工作表
        let currentSheets: any[] = []
        if (window.luckysheet && typeof window.luckysheet.getAllSheets === 'function') {
            currentSheets = window.luckysheet.getAllSheets() || []
        }

        console.log('當前工作表數量:', currentSheets.length)

        const sheetCount = currentSheets.length
        const newSheet = {
            name: `Sheet${sheetCount + 1}`,
            color: '',
            index: sheetCount,
            status: 1,
            order: sheetCount,
            hide: 0,
            row: 36,
            column: 18,
            defaultRowHeight: 19,
            defaultColWidth: 73,
            celldata: [] as any[],
            config: {},
            scrollLeft: 0,
            scrollTop: 0,
            luckysheet_select_save: [],
            calcChain: [],
            isPivotTable: false,
            pivotTable: {},
            filter_select: {},
            filter: null,
            luckysheet_alternateformat_save: [],
            luckysheet_alternateformat_save_modelCustom: [],
            luckysheet_conditionformat_save: {},
            frozen: {},
            chart: [],
            zoomRatio: 1,
            image: [],
            showGridLines: 1,
            dataVerification: {}
        }

        console.log('新工作表配置:', newSheet)

        // 合并現有工作表和新工作表
        const newData = [...currentSheets, newSheet]
        console.log('合并后的數據:', newData)

        // 重新初始化 Luckysheet 使用新數據
        const success = await initLuckysheetWithData(newData)
        if (success) {
            ElMessage.success('工作表添加成功')
        } else {
            ElMessage.error('添加工作表失敗,請刷新頁面重試')
        }
    } catch (error) {
        console.error('添加工作表失敗:', error)
        ElMessage.error('添加工作表失敗: ' + (error instanceof Error ? error.message : '未知錯誤'))
    }
}

// 獲取數據
const getData = async () => {
    console.log("1111111");

    console.log('getData被調用')
    console.log('luckysheetInstance:', luckysheetInstance)
    console.log('window.luckysheet:', window.luckysheet)

    // 檢查是否有可用的Luckysheet實例
    const availableInstance = luckysheetInstance || window.luckysheet

    if (!availableInstance || typeof availableInstance.getAllSheets !== 'function') {
        console.log('Luckysheet實例不可用,嘗試重新初始化...')

        // 等待Luckysheet加載
        const isLoaded = await waitForLuckysheet()
        if (!isLoaded) {
            ElMessage.error('Luckysheet加載失敗,請刷新頁面重試')
            return
        }

        // 嘗試初始化
        const initSuccess = await initLuckysheet()
        if (initSuccess) {
            // 等待初始化完成
            setTimeout(() => {
                getData()
            }, 1500)
        } else {
            ElMessage.error('表格初始化失敗,請刷新頁面重試')
        }
        return
    }

    try {
        // 使用可用的實例
        const instance = availableInstance

        // 獲取所有工作表數據
        const sheets = instance.getAllSheets()
        console.log('所有工作表數據:', sheets)

        // 獲取當前工作表數據
        const currentSheet = instance.getSheetData()
        console.log('當前工作表數據:', currentSheet)

        // 獲取選中的單元格數據
        const selectedRange = instance.getRangeByTxt()
        console.log('選中的單元格范圍:', selectedRange)

        ElMessage.success('數據已獲取,請查看控制臺')
    } catch (error) {
        console.error('獲取數據失敗:', error)
        ElMessage.error('獲取數據失敗')
    }
}

// 打印工作表
const printSheet = () => {
    const container = document.getElementById('luckysheet');
    if (!container) {
        window.print();
        return;
    }
    // 獲取內容實際高度和寬度
    const grid = container.querySelector('.luckysheet-grid-container');
    const contentHeight = grid ? grid.scrollHeight : container.scrollHeight;
    const contentWidth = grid ? grid.scrollWidth : container.scrollWidth;

    // 記錄原始尺寸
    const originalHeight = container.style.height;
    const originalWidth = container.style.width;

    // 設置為內容實際尺寸
    container.style.height = contentHeight + 'px';
    container.style.width = contentWidth + 'px';

    // 等待渲染后打印
    setTimeout(() => {
        window.print();
        // 恢復原始尺寸
        container.style.height = originalHeight;
        container.style.width = originalWidth;
    }, 500);
};

// 組件掛載時初始化
onMounted(async () => {
    console.log('組件掛載,開始初始化...')
    console.log('window.luckysheet:', window.luckysheet)

    // 等待Luckysheet加載完成
    const isLoaded = await waitForLuckysheet()
    if (isLoaded) {
        console.log('Luckysheet已加載,開始初始化')
        await initLuckysheet()
    } else {
        console.error('Luckysheet加載失敗')
        ElMessage.error('Luckysheet加載失敗,請刷新頁面重試')
    }
})

// 組件卸載時清理
onUnmounted(() => {
    if (luckysheetInstance) {
        luckysheetInstance.destroy()
    }
})
</script>

<style scoped lang="scss">
.luckysheet-container {
    width: 100%;
    height: 100%;
    display: flex;
   
    flex-direction: column;
}

.toolbar {
    padding: 16px;
    background: #f5f5f5;
    border-bottom: 1px solid #e0e0e0;
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    flex-wrap: wrap;
}

.luckysheet-wrapper {
    flex: 1;
    min-height: 600px;
    position: relative;
}

/* 確保Luckysheet容器有足夠的高度 */
#luckysheet {
    width: 100%;
    height: 100%;
    min-height: 600px;
}


/* 響應式設計 */
@media (max-width: 768px) {
    .toolbar {
        padding: 12px;
        gap: 8px;
    }

    .toolbar .el-button {
        padding: 8px 12px;
        font-size: 12px;
    }
}
</style>

<style>
.luckysheet_info_detail div.luckysheet_info_detail_back{
    display: none !important;
}
.luckysheet_info_detail_update,.luckysheet_info_detail_save{
    display: none !important;
}
#luckysheet .luckysheet-share-logo,
.luckysheet .luckysheet-share-logo,
.luckysheet-share-logo{
    background-image:url('@/assets/imgs/logo.png') !important;
    background-size: contain !important;
    background-repeat: no-repeat !important;
    background-position: center !important;
    width: 120px !important;
    height: 40px !important;
}
@media print {
    body * {
        visibility: hidden;
    }

    #luckysheet,
    #luckysheet * {
        visibility: visible;
    }

    #luckysheet {
        position: static !important;
        left: 0 !important;
        top: 0 !important;
        width: 100% !important;
        min-height: 100vh !important;
        height: auto !important;
        background: #fff !important;
        overflow: visible !important;
        box-sizing: border-box !important;
        padding: 0 !important;
        margin: 0 !important;
        page-break-inside: avoid !important;
    }

    .toolbar {
        display: none !important;
    }
}
</style>

到此這篇關于vue3+luckysheet實現在線編輯Excel的項目實踐的文章就介紹到這了,更多相關vue3 luckysheet 在線編輯Excel內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • vue調用本地攝像頭實現拍照功能

    vue調用本地攝像頭實現拍照功能

    這篇文章主要介紹了vue調用本地攝像頭實現拍照功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Vue3如何利用xlsx、xlsx-js-style導出Excel表格使用(適合新手)

    Vue3如何利用xlsx、xlsx-js-style導出Excel表格使用(適合新手)

    在Vue項目中導出Excel表格是常見的功能,特別是在后臺管理系統(tǒng)中,為了方便用戶將大量數據保存為本地文件,這篇文章主要給大家介紹了關于Vue3如何利用xlsx、xlsx-js-style導出Excel表格使用的相關資料,需要的朋友可以參考下
    2024-06-06
  • vue配置根目錄詳細步驟(用@代表src目錄)

    vue配置根目錄詳細步驟(用@代表src目錄)

    vue用@表示src文件夾,引入時找文件路徑更方便,下面這篇文章主要給大家介紹了關于vue配置根目錄(用@代表src目錄)的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • vue中provide、inject的使用方法案例詳解

    vue中provide、inject的使用方法案例詳解

    本教程是介紹如何在vue中使用provide和inject,在 Vue 中,provide 和 inject 是用于實現祖先組件向后代組件傳遞數據的一種方式,對vue中provide、inject的使用方法感興趣的朋友一起看看吧
    2024-02-02
  • 使用Vue 自定義文件選擇器組件的實例代碼

    使用Vue 自定義文件選擇器組件的實例代碼

    這篇文章主要介紹了使用Vue 自定義文件選擇器組件的實例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • vue中表格設置某列樣式、不顯示表頭問題

    vue中表格設置某列樣式、不顯示表頭問題

    這篇文章主要介紹了vue中表格設置某列樣式、不顯示表頭問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue 使用自定義指令實現表單校驗的方法

    vue 使用自定義指令實現表單校驗的方法

    今天小編就為大家分享一篇vue 使用自定義指令實現表單校驗的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • 讓你30分鐘快速掌握vue3教程

    讓你30分鐘快速掌握vue3教程

    這篇文章主要介紹了讓你30分鐘快速掌握vue3,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • vue elementUi+sortable.js實現嵌套表格拖拽問題

    vue elementUi+sortable.js實現嵌套表格拖拽問題

    這篇文章主要介紹了vue elementUi+sortable.js實現嵌套表格拖拽問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • vue組件實現進度條效果

    vue組件實現進度條效果

    這篇文章主要為大家詳細介紹了vue組件實現進度條效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06

最新評論