feat(mindspace): 全部页面管理、级联删除与页面同步去重

支持全部页面分页/多选/删除/分享,删除时可选移除广场帖并清理工作区附件;修复并发同步重复创建页面,并补齐预览下载链接重写与 iframe 下载权限。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-30 01:22:38 +08:00
parent 6e6d00568a
commit ea6c49f046
30 changed files with 2562 additions and 351 deletions
+29 -1
View File
@@ -35,6 +35,23 @@ function extractHtmlSummary(content) {
return match?.[1]?.trim().slice(0, 1000) ?? '';
}
async function findPageByWorkspaceRelativePath(pool, userId, relativePath) {
const [rows] = await pool.query(
`SELECT p.id, p.updated_at
FROM h5_page_records p
JOIN h5_page_versions pv ON pv.id = p.current_version_id
WHERE p.user_id = ?
AND p.status <> 'deleted'
AND JSON_UNQUOTE(JSON_EXTRACT(pv.source_snapshot_json, '$.relative_path')) = ?
ORDER BY p.updated_at DESC, p.id DESC
LIMIT 1`,
[userId, relativePath],
);
const row = rows[0];
if (!row) return null;
return { id: row.id, updatedAt: Number(row.updated_at ?? 0) };
}
async function loadIndexedWorkspacePages(pool, userId) {
const [rows] = await pool.query(
`SELECT p.id, p.updated_at, p.source_asset_id, pv.source_snapshot_json
@@ -99,6 +116,7 @@ async function listPublishPublicHtmlFiles(publishDir) {
}
async function upsertWorkspaceHtmlPage({
pool,
pageService,
userId,
indexedPages,
@@ -109,10 +127,18 @@ async function upsertWorkspaceHtmlPage({
}) {
const title = extractHtmlTitle(content) || titleFromRelativePath(relativePath);
const summary = extractHtmlSummary(content);
const existing =
let existing =
indexedPages.get(relativePath) ??
(assetId ? indexedPages.get(`asset:${assetId}`) : null);
if (!existing && pool) {
existing = await findPageByWorkspaceRelativePath(pool, userId, relativePath);
if (existing) {
indexedPages.set(relativePath, existing);
if (assetId) indexedPages.set(`asset:${assetId}`, existing);
}
}
const pageInput = {
title,
summary,
@@ -186,6 +212,7 @@ export async function syncGeneratedPagesFromPublicAssets({
continue;
}
const result = await upsertWorkspaceHtmlPage({
pool,
pageService,
userId,
indexedPages,
@@ -237,6 +264,7 @@ export async function syncGeneratedPagesFromPublicAssets({
const { path: assetPath } = await assetService.readAsset(userId, asset.id);
const content = await fs.readFile(assetPath, 'utf8');
const result = await upsertWorkspaceHtmlPage({
pool,
pageService,
userId,
indexedPages,