feat(write): poll window.__tiptap_uploads for upload events and counts
This commit is contained in:
parent
cb14924de8
commit
d90dd60e89
@ -33,6 +33,33 @@ struct UploadErrorEntry {
|
|||||||
message: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// window.__tiptap_uploads 快照(轮询消费用)。
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct UploadSnapshot {
|
||||||
|
events: Vec<UploadSnapshotEvent>,
|
||||||
|
counts: UploadSnapshotCounts,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct UploadSnapshotEvent {
|
||||||
|
kind: String,
|
||||||
|
#[serde(rename = "uploadId")]
|
||||||
|
upload_id: String,
|
||||||
|
#[serde(rename = "fileName")]
|
||||||
|
file_name: String,
|
||||||
|
#[serde(rename = "errorMsg")]
|
||||||
|
error_msg: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[derive(serde::Deserialize, Default, Clone, Copy)]
|
||||||
|
struct UploadSnapshotCounts {
|
||||||
|
uploading: u32,
|
||||||
|
error: u32,
|
||||||
|
}
|
||||||
|
|
||||||
/// 新建文章页面组件。
|
/// 新建文章页面组件。
|
||||||
///
|
///
|
||||||
/// 内部委托给 `write_editor`,以 `None` 表示新建模式。
|
/// 内部委托给 `write_editor`,以 `None` 表示新建模式。
|
||||||
@ -262,6 +289,71 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 轮询 window.__tiptap_uploads,消费上传事件并更新 signal(仅 WASM)
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
use std::collections::HashSet;
|
||||||
|
let mut seen_error_ids: HashSet<String> = HashSet::new();
|
||||||
|
use_future(move || {
|
||||||
|
let mut uploads_in_flight = uploads_in_flight;
|
||||||
|
let mut upload_errors = upload_errors;
|
||||||
|
async move {
|
||||||
|
loop {
|
||||||
|
// 500ms 间隔
|
||||||
|
if let Ok(promise_val) = js_sys::eval("new Promise(r => setTimeout(r, 500))") {
|
||||||
|
if let Ok(promise) = promise_val.dyn_into::<js_sys::Promise>() {
|
||||||
|
let _ = wasm_bindgen_futures::JsFuture::from(promise).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取并清空 events,读取 counts
|
||||||
|
let snapshot = js_sys::eval(
|
||||||
|
r#"
|
||||||
|
(function() {
|
||||||
|
var u = window.__tiptap_uploads;
|
||||||
|
if (!u) return null;
|
||||||
|
var events = u.events || [];
|
||||||
|
u.events = [];
|
||||||
|
return JSON.stringify({ events: events, counts: u.counts || {uploading:0,error:0} });
|
||||||
|
})()
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| v.as_string());
|
||||||
|
|
||||||
|
if let Some(json) = snapshot {
|
||||||
|
if let Ok(parsed) = serde_json::from_str::<UploadSnapshot>(&json) {
|
||||||
|
for ev in parsed.events {
|
||||||
|
match ev.kind.as_str() {
|
||||||
|
"error" => {
|
||||||
|
if !seen_error_ids.contains(&ev.upload_id) {
|
||||||
|
seen_error_ids.insert(ev.upload_id.clone());
|
||||||
|
upload_errors.write().push(UploadErrorEntry {
|
||||||
|
id: ev.upload_id,
|
||||||
|
file_name: ev.file_name,
|
||||||
|
message: ev.error_msg
|
||||||
|
.unwrap_or_else(|| "上传失败".to_string()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"success" | "removed" => {
|
||||||
|
seen_error_ids.remove(&ev.upload_id);
|
||||||
|
upload_errors.write().retain(|e| e.id != ev.upload_id);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uploads_in_flight.set(UploadsInFlight {
|
||||||
|
uploading: parsed.counts.uploading,
|
||||||
|
error: parsed.counts.error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 提交表单:校验标题与内容,读取 Tiptap 编辑器 Markdown,调用 create_post 或 update_post。
|
// 提交表单:校验标题与内容,读取 Tiptap 编辑器 Markdown,调用 create_post 或 update_post。
|
||||||
let on_submit = move |_| {
|
let on_submit = move |_| {
|
||||||
if title().trim().is_empty() {
|
if title().trim().is_empty() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user