chore: 恢复开发文档全目录进库并同步阅读页与脚本改动

Made-with: Cursor
This commit is contained in:
卡若
2026-04-14 16:00:31 +08:00
parent f26c2aedc3
commit 3dd75746e6
519 changed files with 22167 additions and 8 deletions

View File

@@ -78,10 +78,14 @@
<view wx:elif="{{item.length === 1 && item[0].type === 'image'}}" class="paragraph">
<image class="content-image" src="{{item[0].src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{item[0].src}}"></image>
</view>
<view wx:elif="{{item.length === 1 && item[0].type === 'video'}}" class="paragraph content-video-wrap">
<video class="content-video" src="{{item[0].src}}" controls show-center-play-btn object-fit="contain"></video>
</view>
<view wx:else class="paragraph">
<text user-select><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><text wx:if="{{seg.type === 'text'}}">{{seg.text}}</text><text wx:elif="{{seg.type === 'mention'}}" class="mention" bindtap="onMentionTap" data-user-id="{{seg.userId}}" data-nickname="{{seg.nickname}}">{{seg.mentionDisplay}}</text><text wx:elif="{{seg.type === 'linkTag'}}" class="link-tag" bindtap="onLinkTagTap" data-url="{{seg.url}}" data-label="{{seg.label}}" data-tag-type="{{seg.tagType}}" data-page-path="{{seg.pagePath}}" data-tag-id="{{seg.tagId}}" data-app-id="{{seg.appId}}" data-mp-key="{{seg.mpKey}}">#{{seg.label}}</text></block></text>
<block wx:for="{{item}}" wx:key="index" wx:for-item="seg">
<image wx:if="{{seg.type === 'image'}}" class="content-image" src="{{seg.src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{seg.src}}"></image>
<video wx:elif="{{seg.type === 'video'}}" class="content-video" src="{{seg.src}}" controls show-center-play-btn object-fit="contain"></video>
</block>
</view>
</block>
@@ -153,7 +157,8 @@
<scroll-view wx:elif="{{item.length === 1 && item[0].type === 'table'}}" scroll-x class="table-scroll"><view class="content-table"><view class="table-row table-header-row" wx:if="{{item[0].headers.length}}"><text class="table-cell table-header-cell" wx:for="{{item[0].headers}}" wx:key="index" wx:for-item="hdr">{{hdr}}</text></view><view class="table-row" wx:for="{{item[0].rows}}" wx:key="index" wx:for-item="row"><text class="table-cell" wx:for="{{row}}" wx:key="index" wx:for-item="cell">{{cell}}</text></view></view></scroll-view>
<view wx:elif="{{item.length === 1 && item[0].type === 'listItem'}}" class="seg-list-item"><text class="seg-list-marker" wx:if="{{item[0].ordered}}">{{item[0].number}}.</text><text class="seg-list-marker" wx:else>•</text><text class="seg-list-text" user-select>{{item[0].text}}</text></view>
<view wx:elif="{{item.length === 1 && item[0].type === 'image'}}" class="paragraph"><image class="content-image" src="{{item[0].src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{item[0].src}}"></image></view>
<view wx:else class="paragraph"><text user-select><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><text wx:if="{{seg.type === 'text'}}">{{seg.text}}</text><text wx:elif="{{seg.type === 'mention'}}" class="mention" bindtap="onMentionTap" data-user-id="{{seg.userId}}" data-nickname="{{seg.nickname}}">{{seg.mentionDisplay}}</text><text wx:elif="{{seg.type === 'linkTag'}}" class="link-tag" bindtap="onLinkTagTap" data-url="{{seg.url}}" data-label="{{seg.label}}" data-tag-type="{{seg.tagType}}" data-page-path="{{seg.pagePath}}" data-tag-id="{{seg.tagId}}" data-app-id="{{seg.appId}}" data-mp-key="{{seg.mpKey}}">#{{seg.label}}</text></block></text><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><image wx:if="{{seg.type === 'image'}}" class="content-image" src="{{seg.src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{seg.src}}"></image></block></view>
<view wx:elif="{{item.length === 1 && item[0].type === 'video'}}" class="paragraph content-video-wrap"><video class="content-video" src="{{item[0].src}}" controls show-center-play-btn object-fit="contain"></video></view>
<view wx:else class="paragraph"><text user-select><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><text wx:if="{{seg.type === 'text'}}">{{seg.text}}</text><text wx:elif="{{seg.type === 'mention'}}" class="mention" bindtap="onMentionTap" data-user-id="{{seg.userId}}" data-nickname="{{seg.nickname}}">{{seg.mentionDisplay}}</text><text wx:elif="{{seg.type === 'linkTag'}}" class="link-tag" bindtap="onLinkTagTap" data-url="{{seg.url}}" data-label="{{seg.label}}" data-tag-type="{{seg.tagType}}" data-page-path="{{seg.pagePath}}" data-tag-id="{{seg.tagId}}" data-app-id="{{seg.appId}}" data-mp-key="{{seg.mpKey}}">#{{seg.label}}</text></block></text><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><image wx:if="{{seg.type === 'image'}}" class="content-image" src="{{seg.src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{seg.src}}"></image><video wx:elif="{{seg.type === 'video'}}" class="content-video" src="{{seg.src}}" controls show-center-play-btn object-fit="contain"></video></block></view>
</block>
</view>
<view class="fade-mask"></view>
@@ -245,7 +250,8 @@
<scroll-view wx:elif="{{item.length === 1 && item[0].type === 'table'}}" scroll-x class="table-scroll"><view class="content-table"><view class="table-row table-header-row" wx:if="{{item[0].headers.length}}"><text class="table-cell table-header-cell" wx:for="{{item[0].headers}}" wx:key="index" wx:for-item="hdr">{{hdr}}</text></view><view class="table-row" wx:for="{{item[0].rows}}" wx:key="index" wx:for-item="row"><text class="table-cell" wx:for="{{row}}" wx:key="index" wx:for-item="cell">{{cell}}</text></view></view></scroll-view>
<view wx:elif="{{item.length === 1 && item[0].type === 'listItem'}}" class="seg-list-item"><text class="seg-list-marker" wx:if="{{item[0].ordered}}">{{item[0].number}}.</text><text class="seg-list-marker" wx:else>•</text><text class="seg-list-text" user-select>{{item[0].text}}</text></view>
<view wx:elif="{{item.length === 1 && item[0].type === 'image'}}" class="paragraph"><image class="content-image" src="{{item[0].src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{item[0].src}}"></image></view>
<view wx:else class="paragraph"><text user-select><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><text wx:if="{{seg.type === 'text'}}">{{seg.text}}</text><text wx:elif="{{seg.type === 'mention'}}" class="mention" bindtap="onMentionTap" data-user-id="{{seg.userId}}" data-nickname="{{seg.nickname}}">{{seg.mentionDisplay}}</text><text wx:elif="{{seg.type === 'linkTag'}}" class="link-tag" bindtap="onLinkTagTap" data-url="{{seg.url}}" data-label="{{seg.label}}" data-tag-type="{{seg.tagType}}" data-page-path="{{seg.pagePath}}" data-tag-id="{{seg.tagId}}" data-app-id="{{seg.appId}}" data-mp-key="{{seg.mpKey}}">#{{seg.label}}</text></block></text><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><image wx:if="{{seg.type === 'image'}}" class="content-image" src="{{seg.src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{seg.src}}"></image></block></view>
<view wx:elif="{{item.length === 1 && item[0].type === 'video'}}" class="paragraph content-video-wrap"><video class="content-video" src="{{item[0].src}}" controls show-center-play-btn object-fit="contain"></video></view>
<view wx:else class="paragraph"><text user-select><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><text wx:if="{{seg.type === 'text'}}">{{seg.text}}</text><text wx:elif="{{seg.type === 'mention'}}" class="mention" bindtap="onMentionTap" data-user-id="{{seg.userId}}" data-nickname="{{seg.nickname}}">{{seg.mentionDisplay}}</text><text wx:elif="{{seg.type === 'linkTag'}}" class="link-tag" bindtap="onLinkTagTap" data-url="{{seg.url}}" data-label="{{seg.label}}" data-tag-type="{{seg.tagType}}" data-page-path="{{seg.pagePath}}" data-tag-id="{{seg.tagId}}" data-app-id="{{seg.appId}}" data-mp-key="{{seg.mpKey}}">#{{seg.label}}</text></block></text><block wx:for="{{item}}" wx:key="index" wx:for-item="seg"><image wx:if="{{seg.type === 'image'}}" class="content-image" src="{{seg.src}}" mode="widthFix" show-menu-by-longpress bindtap="onImageTap" data-src="{{seg.src}}"></image><video wx:elif="{{seg.type === 'video'}}" class="content-video" src="{{seg.src}}" controls show-center-play-btn object-fit="contain"></video></block></view>
</block>
</view>
<view class="fade-mask"></view>

View File

@@ -728,6 +728,20 @@
margin-left: 8rpx;
}
/* 正文内嵌视频(管理端 rich-video-wrap → contentParser type:video */
.content-video-wrap {
width: 100%;
margin: 24rpx 0;
box-sizing: border-box;
}
.content-video {
width: 100%;
max-width: 100%;
min-height: 360rpx;
border-radius: 12rpx;
background: #0a0f14;
}
.paywall-singlepage-note {
display: block;
margin-top: 8rpx;

View File

@@ -7,6 +7,7 @@
* { type: 'mention', userId, nickname } — @某人,点击加好友(提交存客宝见 utils/soulBridge.submitCkbLead
* { type: 'linkTag', label, url, ... } — #链接标签,点击跳转(阅读页 onLinkTagTap外链→link-preview、小程序→navigateToMiniProgram
* { type: 'image', src, alt } — 图片
* { type: 'video', src } — 正文内嵌视频(管理端 rich-video-wrap / <video>
*/
/** 判断内容是否为 HTML */
@@ -249,6 +250,24 @@ function parseHtmlToSegments(html, config) {
return '\n__Q_' + idx + '__\n'
})
// 2.5 内嵌视频去掉管理端「rich-video-caption」说明仅编辑器用整段 <video> 抽成占位
// 须在列表拆解之前执行,否则 li/段落内 video 会在 parseBlockToSegments 里被 strip 成纯文本
const videos = []
text = text.replace(/<div[^>]*\brich-video-caption\b[^>]*>[\s\S]*?<\/div>/gi, '')
text = text.replace(/<video\b[^>]*>[\s\S]*?<\/video>/gi, function (match) {
const sm = match.match(/\bsrc\s*=\s*"([^"]*)"/i) || match.match(/\bsrc\s*=\s*'([^']*)'/i)
const rawSrc = sm ? String(sm[1] || '').trim() : ''
if (!rawSrc) return match
const decoded = decodeEntities(rawSrc)
const src =
config && config.assetBase
? resolveArticleImageSrc(decoded, config.assetBase)
: resolveArticleImageSrc(decoded, '')
const idx = videos.length
videos.push({ src })
return '\n__VIDEO_' + idx + '__\n'
})
// 3. 列表 → listItem 占位(保留 ordered 标记)
var olDepth = 0
var olCounter = 0
@@ -259,6 +278,11 @@ function parseHtmlToSegments(html, config) {
text = text.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, function (_, inner) {
var cleaned = inner.replace(/<p[^>]*>/gi, '').replace(/<\/p>/gi, '').trim()
if (!cleaned) return '\n'
// 列表项内仅有视频占位时,提升为独立视频块(避免 __VIDEO_n__ 当正文展示)
var onlyVid = cleaned.match(/^__VIDEO_(\d+)__$/)
if (onlyVid) {
return '\n__VIDEO_' + onlyVid[1] + '__\n'
}
if (olDepth > 0) {
olCounter++
return '\n__LI_O_' + olCounter + '__ ' + cleaned + '\n'
@@ -292,6 +316,17 @@ function parseHtmlToSegments(html, config) {
continue
}
// video
var vidM = block.trim().match(/^__VIDEO_(\d+)__$/)
if (vidM) {
var vid = videos[parseInt(vidM[1], 10)]
if (vid && vid.src) {
lines.push('')
segments.push([{ type: 'video', src: vid.src }])
}
continue
}
// heading
var hM = block.trim().match(/^__H_(\d+)__$/)
if (hM) {