From 27fa9e605fb5d79f03c9b2c0b0ddf079ad7c7ebd Mon Sep 17 00:00:00 2001 From: bigcode Date: Mon, 2 Nov 2026 00:27:15 +0800 Subject: [PATCH] =?UTF-8?q?v0.10.18:=20H18=20=E6=9C=80=E6=96=B0=E5=8D=9A?= =?UTF-8?q?=E6=96=87(8bc6b68)=E5=AE=8C=E6=88=90=20+=20=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E5=85=B3=E7=B3=BB=E6=95=B0=E6=8D=AE=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PostsWidget 忠实重写(skin cards):预取架构 loader 按 widget 收集术语→查文章→ PostsDataContext 分发;卡 DOM/缩略图比率 0.66/NEWS 徽章(uppercase)/日期 F j,Y/ 摘要 18 词(空回退正文);右列纯文本卡(44px 两行钳制+箭头图标,custom_css 注入) - posts cards 基础 CSS + slim 白名单 cards_*/_skin/posts_include* 全键 - scripts/repair-content-terms.ts:从 legacy dump wp_term_relationships 提取 67709 对, 经 legacy_id 映射补插 1162 条 content_terms(Blog 302/News 22 篇,原仅 61 篇有关联) - 补 icon-arrow-light-orange.png;双端节内几何/样式全等(sec 521),截图目视一致 --- docs/sections-inventory.md | 2 +- package.json | 2 +- scripts/repair-content-terms.ts | 55 ++++++++++ src/components/elementor/Renderer.tsx | 138 +++++++++++++++++++------- src/components/elementor/slim.ts | 26 +++++ src/routes/index.tsx | 38 ++++++- src/server/data.ts | 48 +++++++++ src/styles/app.css | 32 ++++++ 8 files changed, 297 insertions(+), 44 deletions(-) create mode 100644 scripts/repair-content-terms.ts diff --git a/docs/sections-inventory.md b/docs/sections-inventory.md index ec702b3e7..50a449eec 100644 --- a/docs/sections-inventory.md +++ b/docs/sections-inventory.md @@ -52,7 +52,7 @@ | H15 | Trusted By 世界领先品牌 | heading + text + 3 行×5 列 logo 格(9 图 + 6 空占位) + 世界地图底图 | ✅ v0.10.16(审计仅剩口径/亚像素 3 项:heading 40/600/#000 + _padding 左右 10%、text 20px/_margin 顶 10/_padding 9rem、space_between_widgets=0 列内间距 0(scoped 覆盖 kit-spacing)、三行 logo 列 populated flex 纵向垂直居中 + 扣 margin(scoped auto,272-16=256)、列 margin 8px + 边框 #474DFF26 设置驱动、空占位列裸渲染(原站无 populated 盒,margin/边框 0)、logo 图 254 宽 text-align center(Elementor image widget 默认);节 margin-top 3.5%+padding 底 4.5rem;随此版块:ColumnNode 空列裸渲染、populated 语义辨析(H4 溢出=基线 100%,H11/H14/H15 扣减=scoped auto)——曾试基线改 auto 致 H4 -7.7 回归后回滚) | | H16 | Developer Ecosystem | heading ×2 + 内嵌 section 两卡(heading+text+button/social-icons+image) | ✅ v0.10.17(审计 0 差异:节 ab35847 bg #F4F5F8 + heading 40/600/#000(_padding 10%)+副题 20px/_margin 顶 -6;两卡 680×528.4 白底圆角 6 边框 #E0E5F9、padding 48/48/16、margin 12(populated 扣减 scoped)、卡标题 24/700/#0D152E、文本 18px/_padding 3rem、Join Now 白底橙字 12px 56px、图 544×282 居中;随此版块:SocialIconsWidget 忠实重写(wrapper grid gap 10/a 44×44 官方底色 linkedin #0077B5/youtube #CD201F/facebook #3B5998/圆角 10%/白色字形)+FA Brands 字体子集(public/fonts/fa-brands-400.woff2 + 三码位 content 规则)+elementor-animation-shrink 通用类) | | H17 | News & Updates 标题 | heading | ⬜ | -| H18 | 最新博文 *2 | posts widget ×2(标题行 + 列卡) | ⬜ | +| H18 | 最新博文 ×2 | 8bc6b68:左 posts 卡×2(3025217)+右 Latest blogs>>标题(1c96d68)+posts 列表×5(a22c185) | ✅ v0.10.18(双端节内几何/样式全等(sec 521):左 skin-cards grid 335×2/gap 16 10、卡 520 高(custom_css .ele-post-dif)、缩略图比率 0.66×内宽+img 铺满、NEWS 徽章(uppercase/白 70%/12px/圆角 4,绝对右上)、标题 18/400/#000+mb16、日期 F j,Y/#ADADAD/padding 10 12、摘要 18 词/#767676/底距 44(空摘要回退正文 18 词);右列卡 grid 630、卡 bg #F4F5F8/圆角 3、纯标题 44px 两行钳制+右侧箭头图标(custom_css);Latest blogs>> 标题 24px+#E0E5F9 下划线+橙线图背景;随此版块:PostsWidget 忠实重写(PostsDataContext 预取架构:loader 按 widget 收集 posts_include_term_ids→listPostsByTermLegacy)、posts cards 基础 CSS、slim 白名单 cards_* 全键、**数据修复** scripts/repair-content-terms.ts(从 legacy dump wp_term_relationships 补 1162 条分类关联,Blog 302/News 22——原导入仅 61/609 篇有关联)) | | H19 | 定制 CTA | button(大按钮) | ⬜ | ## 四、其他核心页型版块(自上而下,概览) diff --git a/package.json b/package.json index 19b123a83..f42b44624 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dusuniot-rebuild", - "version": "0.10.17", + "version": "0.10.18", "private": true, "type": "module", "scripts": { diff --git a/scripts/repair-content-terms.ts b/scripts/repair-content-terms.ts new file mode 100644 index 000000000..a0c7ac9f4 --- /dev/null +++ b/scripts/repair-content-terms.ts @@ -0,0 +1,55 @@ +/** + * # 脚本 修复 posts 的分类关联(content_terms) + * 背景:导入管线只落了部分文章的分类(609 篇中 548 篇无关联),首页 H18 posts widget + * (按 Blog/News 分类查最新文章)因此查不到数据。原站完整关系在 legacy 镜像 + * dusuniot-db-20261029.sql 的 wp_term_relationships INSERT 段中((post_id,term_id,0) 行)。 + * 做法:从 dump 提取全部 (wp_post_id, wp_term_id) 对 → 经 contents.legacy_id / + * categories.legacy_id 映射为本库 id → 补插缺失的 content_terms(幂等)。 + * 运行:bun scripts/repair-content-terms.ts + */ +import { SQL } from "bun"; + +const DUMP = "/home/bigcode/data/dev/sites/dusuniot/legacy/dusuniot-db-20261029.sql"; +const db = new SQL("postgres://dusuniot:dusuniot@127.0.0.1:25432/dusuniot"); + +// 1) 提取 dump 中的关系对 +const text = await Bun.file(DUMP).text(); +const pairs = new Set(); +const re = /\((\d+),(\d+),0\)/g; +for (const m of text.matchAll(re)) { + pairs.add(`${m[1]}:${m[2]}`); +} +console.log("dump 关系对:", pairs.size); + +// 2) 本库映射表:legacyId → id +const contents = await db`SELECT id, legacy_id FROM contents WHERE legacy_id IS NOT NULL`; +const contentMap = new Map(contents.map((r) => [Number(r.legacy_id), Number(r.id)])); +const cats = await db`SELECT id, legacy_id FROM categories WHERE legacy_id IS NOT NULL`; +const catMap = new Map(cats.map((r) => [Number(r.legacy_id), Number(r.id)])); + +// 3) 已有关联集合(幂等) +const existing = await db`SELECT content_id, category_id FROM content_terms`; +const have = new Set(existing.map((r) => `${r.content_id}:${r.category_id}`)); + +// 4) 补插 +let inserted = 0; +for (const p of pairs) { + const [wpPost, wpTerm] = p.split(":").map(Number); + const cid = contentMap.get(wpPost); + const tid = catMap.get(wpTerm); + if (!cid || !tid) continue; + if (have.has(`${cid}:${tid}`)) continue; + await db`INSERT INTO content_terms (content_id, category_id) VALUES (${cid}, ${tid})`; + have.add(`${cid}:${tid}`); + inserted++; +} +console.log(`补插 ${inserted} 条 content_terms`); + +// 5) 验证:Blog(53)/News(54) 分类下的文章数 +const check = await db` + SELECT ca.name, COUNT(*) AS n FROM content_terms ct + JOIN categories ca ON ca.id = ct.category_id AND ca.legacy_id IN (53, 54) + JOIN contents c ON c.id = ct.content_id AND c.type = 'post' AND c.status = 'published' + GROUP BY ca.name`; +console.log("验证:", JSON.stringify(check)); +await db.end(); diff --git a/src/components/elementor/Renderer.tsx b/src/components/elementor/Renderer.tsx index f3dfc2f46..e7cea80d1 100644 --- a/src/components/elementor/Renderer.tsx +++ b/src/components/elementor/Renderer.tsx @@ -5,8 +5,8 @@ * 样式以内联 style 复现视觉效果(背景、内边距、对齐、列宽百分比), * 未识别的 widgetType 优雅降级:渲染 heading_title / editor 文本或忽略。 */ -import { Component, Fragment, useEffect, useState, type CSSProperties, type ReactNode } from "react"; -import { getLatestPosts, getLatestProducts, type LatestItem } from "~/server/data"; +import { Component, createContext, useContext, Fragment, useEffect, useState, type CSSProperties, type ReactNode } from "react"; +import { getLatestPosts, getLatestProducts, type LatestItem, type PostCardItem } from "~/server/data"; import TickerBar from "~/components/website/TickerBar"; import { InquiryForm } from "~/components/website/InquiryForm"; import { localSiteUrl } from "~/utils/media"; @@ -232,18 +232,23 @@ function normalizeDoc(doc: ElDocument): ElElement[] { return []; } +/** # 成员变量 posts widget 文章数据上下文(loader 预取,经 widget id 分发) **/ +const PostsDataContext = createContext>({}); + /** # 组件 Elementor 渲染器入口 */ -export function ElementorRenderer({ doc }: { doc: ElDocument }) { +export function ElementorRenderer({ doc, postsData }: { doc: ElDocument; postsData?: Record }) { const elements = normalizeDoc(doc); if (!elements.length) return null; const css = collectCustomCss(elements) + collectResponsiveCss(elements); return ( -
- {css ?