chore: 初始提交 - 移除所有硬编码凭据,统一从环境变量读取
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
import { createUniver, defaultTheme, LocaleType } from '@univerjs/presets'
|
||||
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'
|
||||
import { UniverSheetsDrawingPreset } from '@univerjs/preset-sheets-drawing'
|
||||
import { UniverSheetsFilterPreset } from '@univerjs/preset-sheets-filter'
|
||||
import { UniverSheetsSortPreset } from '@univerjs/preset-sheets-sort'
|
||||
import { UniverSheetsDataValidationPreset } from '@univerjs/preset-sheets-data-validation'
|
||||
import { UniverSheetsConditionalFormattingPreset } from '@univerjs/preset-sheets-conditional-formatting'
|
||||
import { UniverSheetsFindReplacePreset } from '@univerjs/preset-sheets-find-replace'
|
||||
|
||||
import zhCNCore from '@univerjs/preset-sheets-core/locales/zh-CN'
|
||||
import zhCNDrawing from '@univerjs/preset-sheets-drawing/locales/zh-CN'
|
||||
import zhCNFilter from '@univerjs/preset-sheets-filter/locales/zh-CN'
|
||||
import zhCNSort from '@univerjs/preset-sheets-sort/locales/zh-CN'
|
||||
import zhCNDataValidation from '@univerjs/preset-sheets-data-validation/locales/zh-CN'
|
||||
import zhCNConditionalFormatting from '@univerjs/preset-sheets-conditional-formatting/locales/zh-CN'
|
||||
import zhCNFindReplace from '@univerjs/preset-sheets-find-replace/locales/zh-CN'
|
||||
|
||||
import '@univerjs/presets/lib/styles/preset-sheets-core.css'
|
||||
import '@univerjs/presets/lib/styles/preset-sheets-filter.css'
|
||||
|
||||
// 引入 UI 样式和主题,新版 Univer 必须引入 UI 包本身才会自动注入 React 组件树
|
||||
import '@univerjs/design/lib/index.css'
|
||||
import '@univerjs/ui/lib/index.css'
|
||||
import '@univerjs/sheets-ui/lib/index.css'
|
||||
import '@univerjs/sheets-formula-ui/lib/index.css'
|
||||
|
||||
import * as React from 'react'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
import * as ReactDOMClient from 'react-dom/client'
|
||||
|
||||
window.React = React
|
||||
window.ReactDOM = ReactDOM
|
||||
window.ReactDOMClient = ReactDOMClient
|
||||
|
||||
export const createRuntime = (config) => {
|
||||
const container = config.container
|
||||
const isDark = config.theme === 'dark'
|
||||
|
||||
// 在这里强制配置 UI,保证 React 的根节点注入逻辑被激活
|
||||
const { univerAPI } = createUniver({
|
||||
locale: LocaleType.ZH_CN,
|
||||
locales: {
|
||||
[LocaleType.ZH_CN]: {
|
||||
...zhCNCore,
|
||||
...zhCNDrawing,
|
||||
...zhCNFilter,
|
||||
...zhCNSort,
|
||||
...zhCNDataValidation,
|
||||
...zhCNConditionalFormatting,
|
||||
...zhCNFindReplace
|
||||
}
|
||||
},
|
||||
theme: defaultTheme,
|
||||
presets: [
|
||||
UniverSheetsCorePreset({
|
||||
container,
|
||||
header: true,
|
||||
footer: true,
|
||||
workerURL: '/tools/cloud_sheets/vendor/univer/univer.worker.js'
|
||||
}),
|
||||
UniverSheetsDrawingPreset(),
|
||||
UniverSheetsFilterPreset(),
|
||||
UniverSheetsSortPreset(),
|
||||
UniverSheetsDataValidationPreset(),
|
||||
UniverSheetsConditionalFormattingPreset(),
|
||||
UniverSheetsFindReplacePreset()
|
||||
]
|
||||
})
|
||||
|
||||
let activeWorkbook = null
|
||||
|
||||
const parseWorkbookJson = raw => {
|
||||
try {
|
||||
if (typeof raw === 'string') return JSON.parse(raw || '{}')
|
||||
if (raw && typeof raw === 'object') return raw
|
||||
return {}
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
const stringifyWorkbook = data => {
|
||||
try {
|
||||
return JSON.stringify(data)
|
||||
} catch (err) {
|
||||
console.error('[UniverAdapter] stringifyWorkbook error', err)
|
||||
const safeClone = (obj, ancestors = new WeakSet()) => {
|
||||
if (obj === null || typeof obj !== 'object') return obj
|
||||
if (ancestors.has(obj)) return undefined // 忽略真正的循环引用
|
||||
ancestors.add(obj)
|
||||
if (Array.isArray(obj)) {
|
||||
const arr = []
|
||||
for (let i = 0; i < obj.length; i++) arr[i] = safeClone(obj[i], ancestors)
|
||||
ancestors.delete(obj)
|
||||
return arr
|
||||
}
|
||||
const res = {}
|
||||
for (const k in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, k)) {
|
||||
res[k] = safeClone(obj[k], ancestors)
|
||||
}
|
||||
}
|
||||
ancestors.delete(obj)
|
||||
return res
|
||||
}
|
||||
return JSON.stringify(safeClone(data))
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeWorkbook = wb => {
|
||||
const defaultData = {
|
||||
id: 'workbook-main',
|
||||
sheetOrder: ['sheet-1'],
|
||||
name: '云表格',
|
||||
appVersion: '1.0.0',
|
||||
locale: 'zhCN',
|
||||
styles: {},
|
||||
sheets: {
|
||||
'sheet-1': {
|
||||
id: 'sheet-1',
|
||||
name: 'Sheet1',
|
||||
tabColor: '',
|
||||
hidden: 0,
|
||||
rowCount: 1000,
|
||||
columnCount: 30,
|
||||
zoomRatio: 1,
|
||||
defaultColumnWidth: 80,
|
||||
defaultRowHeight: 24,
|
||||
cellData: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return { ...defaultData, ...wb }
|
||||
}
|
||||
|
||||
const makeDefaultWorkbook = () => normalizeWorkbook({})
|
||||
|
||||
const loadWorkbook = workbook => {
|
||||
const data = normalizeWorkbook(workbook)
|
||||
// 强制生成一个绝对唯一的 ID,防止 Univer 内部根据 ID 缓存旧的快照或产生冲突
|
||||
data.id = `workbook-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
||||
|
||||
if (activeWorkbook && typeof activeWorkbook.getId === 'function') {
|
||||
try { univerAPI.disposeUnit(activeWorkbook.getId()) } catch {}
|
||||
}
|
||||
activeWorkbook = univerAPI.createWorkbook(data)
|
||||
return activeWorkbook
|
||||
}
|
||||
|
||||
loadWorkbook(makeDefaultWorkbook())
|
||||
|
||||
// 对于某些 Univer 版本,必须调用挂载才能将 React 根节点插入到 DOM 中。
|
||||
try {
|
||||
if (univerAPI && typeof univerAPI.mount === 'function') {
|
||||
univerAPI.mount(container)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('挂载 Univer 失败', e)
|
||||
}
|
||||
|
||||
window.univerAPI = univerAPI
|
||||
|
||||
return {
|
||||
setWorkbookJSON: raw => {
|
||||
const wb = parseWorkbookJson(raw)
|
||||
loadWorkbook(wb)
|
||||
},
|
||||
commitPendingChanges: async () => {
|
||||
try {
|
||||
const active = univerAPI.getActiveWorkbook() || activeWorkbook
|
||||
if (!active) return { ok: false, reason: 'no_active_workbook' }
|
||||
|
||||
// 在新版 Univer 架构中,直接触发表格失焦或退出编辑状态的最有效方式:
|
||||
// 执行一个空操作,或者利用内部的 command 服务退出编辑。
|
||||
// 为了稳定,这里使用原生的 DOM focus 转移,配合 Univer 提供的 isCellEditing 方法判断。
|
||||
let isEditing = false
|
||||
if (typeof active.isCellEditing === 'function') {
|
||||
isEditing = active.isCellEditing()
|
||||
}
|
||||
|
||||
// 如果我们没找到现成的 endEditingAsync,也可以尝试派发命令
|
||||
if (isEditing) {
|
||||
try {
|
||||
// 很多版本提供 endEditing 方法
|
||||
if (typeof active.endEditing === 'function') {
|
||||
active.endEditing()
|
||||
} else if (typeof active.endEditingAsync === 'function') {
|
||||
await active.endEditingAsync(true)
|
||||
} else {
|
||||
// 触发原生的回车/失焦事件作为降级方案
|
||||
const activeEl = document.activeElement
|
||||
if (activeEl && typeof activeEl.blur === 'function') {
|
||||
activeEl.blur()
|
||||
}
|
||||
// 模拟触发 Enter 键事件让其结束编辑
|
||||
const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true })
|
||||
if (activeEl) activeEl.dispatchEvent(enterEvent)
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
return { ok: true, isCellEditingBefore: isEditing }
|
||||
} catch (e) {
|
||||
console.error('[UniverAdapter] commitPendingChanges error', e)
|
||||
return { ok: false, reason: e && e.message ? e.message : String(e || 'unknown_error') }
|
||||
}
|
||||
},
|
||||
getWorkbookJSON: () => {
|
||||
try {
|
||||
const active = univerAPI.getActiveWorkbook() || activeWorkbook
|
||||
if (active && typeof active.save === 'function') {
|
||||
const workbookModel = typeof active.getWorkbook === 'function' ? active.getWorkbook() : null
|
||||
let data = null
|
||||
if (workbookModel && typeof workbookModel.save === 'function') {
|
||||
data = workbookModel.save()
|
||||
}
|
||||
if ((!data || Object.keys(data).length === 0) && typeof active.save === 'function') {
|
||||
data = active.save()
|
||||
}
|
||||
if ((!data || Object.keys(data).length === 0) && workbookModel && typeof workbookModel.getSnapshot === 'function') {
|
||||
data = workbookModel.getSnapshot()
|
||||
}
|
||||
if ((!data || Object.keys(data).length === 0) && workbookModel && typeof workbookModel.getConfig === 'function') {
|
||||
data = workbookModel.getConfig()
|
||||
}
|
||||
if ((!data || Object.keys(data).length === 0) && typeof active.getSnapshot === 'function') {
|
||||
data = active.getSnapshot()
|
||||
}
|
||||
try {
|
||||
const sheet1 = data.sheets && data.sheets['sheet-1']
|
||||
const cellData = sheet1 && sheet1.cellData
|
||||
const sampleCell = cellData && cellData['0'] && cellData['0']['0']
|
||||
console.log('[UniverAdapter] Sample cell 0,0:', sampleCell)
|
||||
console.log('[UniverAdapter] Workbook name:', workbookModel && workbookModel.getName ? workbookModel.getName() : active.getName ? active.getName() : '')
|
||||
} catch(e){}
|
||||
return stringifyWorkbook(data)
|
||||
} else {
|
||||
console.error('[UniverAdapter] active workbook error:', active)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[UniverAdapter] getWorkbookJSON error', e)
|
||||
}
|
||||
return '{}'
|
||||
},
|
||||
dispose: () => {
|
||||
try {
|
||||
if (activeWorkbook && typeof activeWorkbook.getId === 'function') {
|
||||
univerAPI.disposeUnit(activeWorkbook.getId())
|
||||
}
|
||||
} catch {}
|
||||
try {
|
||||
if (univerAPI && typeof univerAPI.dispose === 'function') {
|
||||
univerAPI.dispose()
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.CloudSheetsUniverAdapter = { create: createRuntime }
|
||||
Reference in New Issue
Block a user