收口 MNote P0 P1 P2 审查尾项

- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目
- 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线
- 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径

验证:
- cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1
- cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1
- git diff --check
- git diff --cached --check
- codegraph index . --force && codegraph status .
- codegraph sync . && codegraph status .
This commit is contained in:
lix-2026
2026-06-01 09:29:12 +08:00
parent 49a0545148
commit 1882db7681
143 changed files with 29810 additions and 3228 deletions
@@ -15,6 +15,18 @@ export const firstNonEmptyText = (...values) => {
return '';
};
export const normalizeMindmapDimension = (value, kind) => {
const raw = typeof value === 'number'
? value
: typeof value === 'string'
? Number(value.trim().replace(/px$/i, ''))
: NaN;
if (!Number.isFinite(raw)) return null;
const rounded = Math.round(raw);
const min = kind === 'height' ? 240 : 900;
return rounded >= min ? rounded : null;
};
// 过渡适配(TODO step-4):legacy→Tiptap inline marks 转换函数组。
// AST/block 迁移 complete 后,前端应直接消费 block document 中的
// tiptap 格式 marks(已由 Rust 侧 local_markdown_parser 输出),
@@ -125,19 +137,26 @@ export const legacyBlockToTiptap = (block, index = 0) => {
}
if (type === 'divider' || type === 'horizontalRule' || type === 'horizontal_rule') return { type: 'horizontalRule', attrs: { blockId } };
if (type === 'mindmap') {
const attrs = block?.attrs && typeof block.attrs === 'object' ? block.attrs : null;
const data = block?.props?.data && typeof block.props.data === 'object' ? block.props.data : null;
const mindmapId = firstNonEmptyText(
block?.props?.mindmapId,
block?.props?.mindmap_id,
block?.props?.sourcePath,
block?.props?.source_path,
attrs?.mindmapId,
attrs?.mindmap_id,
attrs?.sourcePath,
attrs?.source_path,
block?.mindmapId,
block?.mindmap_id,
data?.mindmapId,
data?.mindmap_id,
data?.id
);
const rootNodeId = firstNonEmptyText(block?.props?.rootNodeId, block?.props?.root_node_id, data?.rootNodeId, data?.root_node_id) || 'root';
const rootNodeId = firstNonEmptyText(block?.props?.rootNodeId, block?.props?.root_node_id, attrs?.rootNodeId, attrs?.root_node_id, data?.rootNodeId, data?.root_node_id) || 'root';
const mindmapWidth = normalizeMindmapDimension(block?.props?.mindmapWidth ?? block?.props?.mindmap_width ?? attrs?.mindmapWidth ?? attrs?.mindmap_width ?? data?.mindmapWidth ?? data?.mindmap_width, 'width');
const mindmapHeight = normalizeMindmapDimension(block?.props?.mindmapHeight ?? block?.props?.mindmap_height ?? attrs?.mindmapHeight ?? attrs?.mindmap_height ?? data?.mindmapHeight ?? data?.mindmap_height, 'height');
return {
type: 'paragraph',
attrs: withTextAlign({
@@ -145,6 +164,8 @@ export const legacyBlockToTiptap = (block, index = 0) => {
mnoteBlockType: 'mindmap',
mindmapId,
rootNodeId,
...(mindmapWidth !== null ? { mindmapWidth } : {}),
...(mindmapHeight !== null ? { mindmapHeight } : {}),
}),
};
}
@@ -225,7 +246,9 @@ export const mindmapDomDescriptors = (root) => {
const rootNodeId = typeof node.dataset.mnoteRootNodeId === 'string' && node.dataset.mnoteRootNodeId.trim()
? node.dataset.mnoteRootNodeId.trim()
: 'root';
return [{ mindmapId, rootNodeId }];
const mindmapWidth = normalizeMindmapDimension(node.dataset.mnoteMindmapWidth, 'width');
const mindmapHeight = normalizeMindmapDimension(node.dataset.mnoteMindmapHeight, 'height');
return [{ mindmapId, rootNodeId, mindmapWidth, mindmapHeight }];
});
};
@@ -246,6 +269,12 @@ export const hydrateMindmapAttrsFromDom = (tiptapDocument, root) => {
if (typeof node.attrs.rootNodeId !== 'string' || !node.attrs.rootNodeId.trim()) {
node.attrs.rootNodeId = descriptor.rootNodeId;
}
if (normalizeMindmapDimension(node.attrs.mindmapWidth, 'width') === null && descriptor.mindmapWidth !== null) {
node.attrs.mindmapWidth = descriptor.mindmapWidth;
}
if (normalizeMindmapDimension(node.attrs.mindmapHeight, 'height') === null && descriptor.mindmapHeight !== null) {
node.attrs.mindmapHeight = descriptor.mindmapHeight;
}
}
return tiptapDocument;
};
@@ -445,20 +474,17 @@ export const localizeTiptapAssetUrls = (node, context) => {
};
export const pageBodyTiptapDocumentSource = (body, fallbackText = '') => {
const blockDocument = body?.blockDocument || body?.block_document || body?.editorDocument || body?.editor_document || null;
if (blockDocument) return 'page_aggregate.block_document';
if (String(body?.projectionSource || body?.projection_source || '') === 'local_markdown.content' && body?.content) {
return 'local_markdown.content';
}
const blockDocument = body?.blockDocument || body?.block_document || body?.editorDocument || body?.editor_document || null;
if (blockDocument) return 'page_aggregate.block_document';
if (body?.content) return 'compat.legacy_content';
return fallbackText ? 'degraded.fallback_text' : 'empty';
};
export const pageBodyTiptapDocument = (body, fallbackText = '', context = null) => {
const projectionContext = { ...(context || {}), body };
if (pageBodyTiptapDocumentSource(body, fallbackText) === 'local_markdown.content') {
return localizeTiptapAssetUrls(toTiptapDocument(body.content, fallbackText), projectionContext);
}
const blockDocument = body?.blockDocument || body?.block_document || body?.editorDocument || body?.editor_document || null;
if (blockDocument) return localizeTiptapAssetUrls(toTiptapDocument(blockDocument, fallbackText), projectionContext);
return localizeTiptapAssetUrls(toTiptapDocument(body?.content, fallbackText), projectionContext);
@@ -533,10 +559,14 @@ export const mindmapPropsFromAttrs = (attrs, fallbackMindmapId) => {
);
const rootNodeId = firstNonEmptyText(attrs?.rootNodeId, attrs?.root_node_id, data?.rootNodeId, data?.root_node_id) || 'root';
const projectionVersion = Number(attrs?.projectionVersion ?? attrs?.projection_version);
const mindmapWidth = normalizeMindmapDimension(attrs?.mindmapWidth ?? attrs?.mindmap_width ?? data?.mindmapWidth ?? data?.mindmap_width, 'width');
const mindmapHeight = normalizeMindmapDimension(attrs?.mindmapHeight ?? attrs?.mindmap_height ?? data?.mindmapHeight ?? data?.mindmap_height, 'height');
return {
mindmapId,
rootNodeId,
...(Number.isFinite(projectionVersion) ? { projectionVersion } : {}),
...(mindmapWidth !== null ? { mindmapWidth } : {}),
...(mindmapHeight !== null ? { mindmapHeight } : {}),
};
};