fix: 修复 Rust OnlyOffice 附件打开链路

This commit is contained in:
lix-2026
2026-05-11 08:27:52 +08:00
parent 2f9ef85350
commit b7dddd2a66
20 changed files with 3484 additions and 109 deletions
+112 -10
View File
@@ -1819,6 +1819,72 @@ const SPIKE_STYLE: &str = r#"
text-decoration: none;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-row {
display: inline-flex;
align-items: center;
gap: 7px;
max-width: 100%;
min-height: 28px;
margin: 1px 0;
padding: 2px 4px;
border: 0;
border-radius: 4px;
color: #37352f;
font-weight: 500;
line-height: 1.4;
text-decoration: none;
background: transparent;
box-shadow: none;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-row::before {
content: "";
width: 18px;
height: 18px;
flex: 0 0 auto;
border-radius: 4px;
background: var(--attachment-icon-bg, #e9ecef);
border: 1px solid var(--attachment-icon-border, rgba(55, 53, 47, 0.14));
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-row::after {
content: "";
flex: 0 0 auto;
margin-left: 4px;
color: #9ca3af;
font-size: 11px;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-row:hover {
background: rgba(55, 53, 47, 0.06);
text-decoration: none;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-word {
--attachment-icon-bg: #4f82ff;
--attachment-icon-border: #3366d6;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-ppt {
--attachment-icon-bg: #ea581f;
--attachment-icon-border: #cf4817;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-sheet {
--attachment-icon-bg: #2f9e44;
--attachment-icon-border: #25813a;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-pdf {
--attachment-icon-bg: #ef4444;
--attachment-icon-border: #dc2626;
}
.editor-surface .ProseMirror a.mnote-uploaded-attachment-file {
--attachment-icon-bg: #9ca3af;
--attachment-icon-border: #6b7280;
}
.footer-strip {
display: flex;
justify-content: space-between;
@@ -1964,6 +2030,7 @@ enum SlashActionKind {
Divider,
SimpleTable,
Image,
UploadAttachment,
Toc,
}
@@ -2013,7 +2080,7 @@ const FOLDED_HEADING_ACTIONS: [FoldedHeadingAction; 4] = [
},
];
const SLASH_ACTIONS: [SlashAction; 20] = [
const SLASH_ACTIONS: [SlashAction; 21] = [
SlashAction {
kind: SlashActionKind::AiAssistant,
id: "ai-assistant",
@@ -2182,9 +2249,18 @@ const SLASH_ACTIONS: [SlashAction; 20] = [
category: "媒体与附件",
icon: "",
label: "图片",
description: "插入图片",
description: "上传并插入图片",
shortcut: "/tp",
},
SlashAction {
kind: SlashActionKind::UploadAttachment,
id: "upload-attachment",
category: "媒体与附件",
icon: "",
label: "上传附件",
description: "上传 Office、PDF 或其他文件",
shortcut: "/fj",
},
SlashAction {
kind: SlashActionKind::Toc,
id: "toc",
@@ -4058,7 +4134,9 @@ fn turn_into_block(node: &Value, action: SlashActionKind) -> Value {
node_with_attrs("codeBlock", Some(attrs), content)
}
SlashActionKind::Divider => node_with_attrs("horizontalRule", None, Vec::new()),
SlashActionKind::SimpleTable | SlashActionKind::Toc => paragraph_node(inline),
SlashActionKind::SimpleTable | SlashActionKind::UploadAttachment | SlashActionKind::Toc => {
paragraph_node(inline)
}
SlashActionKind::Image => {
let mut attrs = Map::new();
attrs.insert("src".to_string(), json!(E24_IMAGE_PLACEHOLDER_SRC));
@@ -5437,6 +5515,25 @@ fn table_option_checked(document: &Value, action: TableOptionAction) -> bool {
}
}
fn dispatch_editor_upload_request(kind: &str, accept: &str) -> Result<(), String> {
let win = window().ok_or_else(|| "当前浏览器窗口不可用".to_string())?;
let detail = json!({
"kind": kind,
"accept": accept,
"multiple": true,
"insertIntoEditor": true,
});
let detail =
serde_wasm_bindgen::to_value(&detail).map_err(|err| format!("构造上传请求失败:{err}"))?;
let init = CustomEventInit::new();
init.set_detail(&detail);
let event = CustomEvent::new_with_event_init_dict("mnote:editor-upload-request", &init)
.map_err(|_| "构造上传事件失败".to_string())?;
win.dispatch_event(&event)
.map(|_| ())
.map_err(|_| "派发上传事件失败".to_string())
}
fn run_slash_action(
editor: TiptapEditorHandle,
action: SlashActionKind,
@@ -5464,11 +5561,14 @@ fn run_slash_action(
let _ = editor.focus();
editor.insert_table(4, 3, false)
}
SlashActionKind::Image => editor.set_image(TiptapImageResource {
src: E24_IMAGE_PLACEHOLDER_SRC.into(),
alt: Some(E24_IMAGE_PLACEHOLDER_ALT.into()),
title: Some(E24_IMAGE_PLACEHOLDER_TITLE.into()),
}),
SlashActionKind::Image => {
dispatch_editor_upload_request("image", "image/*")?;
return Ok("已打开图片上传");
}
SlashActionKind::UploadAttachment => {
dispatch_editor_upload_request("attachment", "")?;
return Ok("已打开附件上传");
}
SlashActionKind::Toc => editor.insert_toc_node(TiptapTocNodeAttrs {
top_offset: Some(0),
max_show_count: Some(20),
@@ -5495,7 +5595,8 @@ fn run_slash_action(
SlashActionKind::CodeBlock => "已切到代码块",
SlashActionKind::Divider => "已插入分割线",
SlashActionKind::SimpleTable => "已插入简单表格",
SlashActionKind::Image => "插入图片",
SlashActionKind::Image => "打开图片上传",
SlashActionKind::UploadAttachment => "已打开附件上传",
SlashActionKind::Toc => "已插入页面目录",
})
.map_err(|err| format!("命令执行失败:{err}"))
@@ -5844,6 +5945,7 @@ fn top_level_block_matches_action(
SlashActionKind::Divider => node_type == "horizontalRule",
SlashActionKind::SimpleTable => node_type == "table",
SlashActionKind::Image => node_type == "image",
SlashActionKind::UploadAttachment => false,
SlashActionKind::Toc => node_type == "tocNode",
SlashActionKind::AiAssistant
| SlashActionKind::AiWrite
@@ -9052,7 +9154,7 @@ fn App(mount_options: MountOptions) -> impl IntoView {
<div class="block-drag-submenu" data-testid="block-transform-submenu" data-e30-testid="block-turn-into-menu">
{SLASH_ACTIONS
.iter()
.filter(|action| !matches!(action.kind, SlashActionKind::Divider | SlashActionKind::SimpleTable | SlashActionKind::Image | SlashActionKind::Toc | SlashActionKind::AiAssistant | SlashActionKind::AiWrite | SlashActionKind::ContinueWriting | SlashActionKind::Summarize | SlashActionKind::MoreAi))
.filter(|action| !matches!(action.kind, SlashActionKind::Divider | SlashActionKind::SimpleTable | SlashActionKind::Image | SlashActionKind::UploadAttachment | SlashActionKind::Toc | SlashActionKind::AiAssistant | SlashActionKind::AiWrite | SlashActionKind::ContinueWriting | SlashActionKind::Summarize | SlashActionKind::MoreAi))
.map(|action| {
let kind = action.kind;
let label = action.label;