| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="utf-8">
- <link rel='stylesheet' href='lib/luckysheet/plugins/css/pluginsCss.css' />
- <link rel='stylesheet' href='lib/luckysheet/plugins/plugins.css' />
- <link rel='stylesheet' href='lib/luckysheet/css/luckysheet.css' />
- <link rel='stylesheet' href='lib/luckysheet/assets/iconfont/iconfont.css' />
- <script src="lib/luckysheet/plugins/js/plugin.js"></script>
- <script src="lib/luckysheet/luckysheet.umd.js"></script>
- <style>
- body, html {
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
- overflow: hidden;
- }
- #luckysheet {
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
- }
- </style>
- </head>
- <body>
- <div id="luckysheet"></div>
- <script>
- let isInitialized = false
-
- // 修复luckysheet公式数据
- function fixSheetDataFormulas(sheetData) {
- if (!sheetData || !Array.isArray(sheetData)) return sheetData
-
- return sheetData.map(sheet => {
- if (!sheet) return sheet
-
- // 第一步:修复公式语法问题
- sheet = fixFormulaSyntax(sheet)
-
- // 第二步:修复计算链问题
- sheet = fixLuckysheetCalcChain(sheet)
-
- return sheet
- })
- }
-
- // 修复公式语法问题(与导入模块相同的逻辑)
- function fixFormulaSyntax(sheet) {
- if (!sheet) return sheet
-
- // 修复celldata中的公式
- if (Array.isArray(sheet.celldata)) {
- sheet.celldata.forEach(cell => {
- if (cell && cell.v && cell.v.f) {
- let formula = cell.v.f
- let newFormula = formula
-
- // 将 _xleta.N 替换为 "N"
- if (formula.includes('_xleta.')) {
- newFormula = newFormula.replace(/_xleta\.([A-Za-z]+)/g, (match, variable) => {
- // 如果是单个字母,替换为字符串
- if (/^[A-Za-z]$/.test(variable)) {
- return `"${variable}"`
- }
- return variable
- })
- }
-
- // 修复百分比格式问题
- // 将百分比转换为数值,因为Excel中100%就是数值1,0.01%就是0.0001
- // 支持整数和小数百分比,如 100%、0.01%、1.5%
-
- // 第一步:先修复可能存在的重复小数点问题(如0.0.01应该修正为0.0001)
- const duplicateDotRegex = /(\d+)\.(\d+)\.(\d+)/g
- const duplicateDotMatches = [...newFormula.matchAll(duplicateDotRegex)]
-
- if (duplicateDotMatches.length > 0) {
- duplicateDotMatches.forEach(match => {
- const fullMatch = match[0]
- const integerPart = match[1] // 如 "0"
- const firstDecimalPart = match[2] // 如 "0"
- const secondDecimalPart = match[3] // 如 "01"
-
- // 处理常见的百分比解析错误模式
- let correctNumber
- if (integerPart === '0' && firstDecimalPart === '0') {
- // 针对 0.0.xxx 模式的特殊修复
- // 规则:转换为 0.00xxx,其中 xxx 是 secondDecimalPart
- correctNumber = parseFloat(`0.00${secondDecimalPart}`)
- } else {
- // 其他情况:使用更保守的修复
- correctNumber = parseFloat(`${integerPart}.${firstDecimalPart}${secondDecimalPart}`)
- }
-
- newFormula = newFormula.replace(fullMatch, correctNumber.toString())
- })
- }
-
- // 第二步:处理百分比转换为数值的问题
- const percentRegex = /(\d+(?:\.\d+)?)%/g
- const percentMatches = [...newFormula.matchAll(percentRegex)]
-
- if (percentMatches.length > 0) {
- percentMatches.forEach(match => {
- const fullMatch = match[0]
- const number = match[1]
- const percentValue = parseFloat(number) / 100
-
- // 将百分比转换为数值
- newFormula = newFormula.replace(fullMatch, percentValue.toString())
- })
- }
-
- if (newFormula !== formula) {
- cell.v.f = newFormula
- }
- }
- })
- }
-
- // 修复data数组中的公式
- if (Array.isArray(sheet.data)) {
- sheet.data.forEach(row => {
- if (Array.isArray(row)) {
- row.forEach(cell => {
- if (cell && cell.f) {
- let formula = cell.f
- let newFormula = formula
-
- // 将 _xleta.N 替换为 "N"
- if (formula.includes('_xleta.')) {
- newFormula = newFormula.replace(/_xleta\.([A-Za-z]+)/g, (match, variable) => {
- // 如果是单个字母,替换为字符串
- if (/^[A-Za-z]$/.test(variable)) {
- return `"${variable}"`
- }
- return variable
- })
- }
-
- // 修复百分比格式问题
- // 支持整数和小数百分比,如 100%、0.01%、1.5%
-
- // 第一步:先修复可能存在的重复小数点问题(如0.0.01应该修正为0.0001)
- const duplicateDotRegex = /(\d+)\.(\d+)\.(\d+)/g
- const duplicateDotMatches = [...newFormula.matchAll(duplicateDotRegex)]
-
- if (duplicateDotMatches.length > 0) {
- duplicateDotMatches.forEach(match => {
- const fullMatch = match[0]
- const integerPart = match[1] // 如 "0"
- const firstDecimalPart = match[2] // 如 "0"
- const secondDecimalPart = match[3] // 如 "01"
-
- // 处理常见的百分比解析错误模式
- let correctNumber
- if (integerPart === '0' && firstDecimalPart === '0') {
- // 针对 0.0.xxx 模式的特殊修复
- // 规则:转换为 0.00xxx,其中 xxx 是 secondDecimalPart
- correctNumber = parseFloat(`0.00${secondDecimalPart}`)
- } else {
- // 其他情况:使用更保守的修复
- correctNumber = parseFloat(`${integerPart}.${firstDecimalPart}${secondDecimalPart}`)
- }
-
- newFormula = newFormula.replace(fullMatch, correctNumber.toString())
- })
- }
-
- // 第二步:处理百分比转换为数值的问题
- const percentRegex = /(\d+(?:\.\d+)?)%/g
- const percentMatches = [...newFormula.matchAll(percentRegex)]
-
- if (percentMatches.length > 0) {
- percentMatches.forEach(match => {
- const fullMatch = match[0]
- const number = match[1]
- const percentValue = parseFloat(number) / 100
-
- // 将百分比转换为数值
- newFormula = newFormula.replace(fullMatch, percentValue.toString())
- })
- }
-
- if (newFormula !== formula) {
- cell.f = newFormula
- }
- }
- })
- }
- })
- }
-
- return sheet
- }
-
- /**
- * 修复luckysheet计算链问题
- * 确保所有包含公式的单元格都能正常计算
- * 这是解决"G11和H11公式工作,但I11及以后不工作"问题的关键
- *
- * @param {Object} sheet - 工作表数据
- * @returns {Object} 修复后的工作表
- */
- function fixLuckysheetCalcChain(sheet) {
- if (!sheet) return sheet
-
- // 确保calcChain存在
- if (!sheet.calcChain) {
- sheet.calcChain = []
- }
-
- // 创建现有计算链的快速查找映射
- const existingCalcMap = new Map()
- sheet.calcChain.forEach(item => {
- if (item && typeof item.r === 'number' && typeof item.c === 'number') {
- const key = `${item.r}_${item.c}`
- existingCalcMap.set(key, true)
- }
- })
-
- /**
- * 添加单元格到计算链
- * @param {number} row - 行索引
- * @param {number} col - 列索引
- */
- const addToCalcChain = (row, col) => {
- const key = `${row}_${col}`
-
- // 如果已经存在,跳过
- if (existingCalcMap.has(key)) {
- return
- }
-
- // 添加到计算链
- sheet.calcChain.push({
- r: row,
- c: col,
- index: sheet.index || "0"
- })
-
- // 更新映射
- existingCalcMap.set(key, true)
- }
-
- // 遍历celldata,查找有公式的单元格
- if (Array.isArray(sheet.celldata)) {
- sheet.celldata.forEach(cell => {
- if (cell && typeof cell.r === 'number' && typeof cell.c === 'number') {
- // 检查是否有公式
- const hasFormula = cell.v && cell.v.f
- if (hasFormula) {
- addToCalcChain(cell.r, cell.c)
- }
- }
- })
- }
-
- // 遍历data数组,查找有公式的单元格
- if (Array.isArray(sheet.data)) {
- sheet.data.forEach((row, rowIndex) => {
- if (Array.isArray(row)) {
- row.forEach((cell, colIndex) => {
- if (cell && cell.f) {
- addToCalcChain(rowIndex, colIndex)
- }
- })
- }
- })
- }
-
- return sheet
- }
-
- window.addEventListener('message', function(event) {
- const { type, data, readonly } = event.data
-
- if (type === 'init' && !isInitialized) {
- luckysheet.create({
- container: 'luckysheet',
- lang: 'zh', // 设置中文语言,工具栏提示为中文
- // 控制顶部工具栏显示:
- // - readonly=true (查阅模式): showtoolbar=false 隐藏工具栏
- // - readonly=false (添加/编辑模式): showtoolbar=true 显示工具栏
- showtoolbar: !readonly,
- showinfobar: false,
- showsheetbar: true,
- // 控制是否允许增加行/列
- enableAddRow: !readonly,
- enableAddCol: !readonly,
- userInfo: false,
- // 状态栏设置(包含缩放控制):
- // - showstatisticBar: true 显示状态栏(包含缩放控制)
- showstatisticBar: true,
- // 控制编辑栏显示:
- // - readonly=true: sheetFormulaBar=false 隐藏编辑栏
- // - readonly=false: sheetFormulaBar=true 显示编辑栏
- sheetFormulaBar: !readonly,
- allowEdit: !readonly,
- // 启用缩放控制 - 优化配置
- showtoolbarConfig: {
- zoom: true, // 启用缩放控制,包括右下角的缩放组件
- },
- // 缩放比例配置
- zoomRatio: {
- default: 100, // 默认缩放比例
- max: 400, // 最大缩放比例
- min: 10 // 最小缩放比例
- },
- // 显示行号列标
- showRowBar: true,
- showColumnBar: true,
- // 单元格右键菜单
- cellRightClickConfig: {
- copy: true,
- paste: true,
- insertRow: !readonly,
- insertColumn: !readonly,
- deleteRow: !readonly,
- deleteColumn: !readonly,
- hideRow: !readonly,
- hideColumn: !readonly,
- rowHeight: !readonly,
- columnWidth: !readonly
- },
- data: data ? fixSheetDataFormulas(data) : [{ name: 'Sheet1', color: '', status: 1, order: 0, data: [[{ v: '' }]] }],
- hook: {}
- })
- isInitialized = true
- } else if (type === 'getData') {
- const data = luckysheet.getAllSheets()
- event.source.postMessage({ type: 'dataResult', data: data }, event.origin)
- } else if (type === 'setData') {
- luckysheet.destroy()
- isInitialized = false
- luckysheet.create({
- container: 'luckysheet',
- lang: 'zh',
- showtoolbar: !readonly,
- showinfobar: false,
- showsheetbar: true,
- enableAddRow: !readonly,
- enableAddCol: !readonly,
- userInfo: false,
- showstatisticBar: true,
- sheetFormulaBar: !readonly,
- allowEdit: !readonly,
- // 启用缩放控制 - 优化配置
- showtoolbarConfig: {
- zoom: true, // 启用缩放控制,包括右下角的缩放组件
- },
- // 缩放比例配置
- zoomRatio: {
- default: 100, // 默认缩放比例
- max: 400, // 最大缩放比例
- min: 10 // 最小缩放比例
- },
- // 显示行号列标
- showRowBar: true,
- showColumnBar: true,
- // 单元格右键菜单
- cellRightClickConfig: {
- copy: true,
- paste: true,
- insertRow: !readonly,
- insertColumn: !readonly,
- deleteRow: !readonly,
- deleteColumn: !readonly,
- hideRow: !readonly,
- hideColumn: !readonly,
- rowHeight: !readonly,
- columnWidth: !readonly
- },
- data: fixSheetDataFormulas(data),
- hook: {}
- })
- isInitialized = true
- }
- })
-
- // 通知父页面已准备好
- window.parent.postMessage({ type: 'ready' }, '*')
- </script>
- </body>
- </html>
|