516 lines
30 KiB
Plaintext
516 lines
30 KiB
Plaintext
<!--pages/read/read.wxml-->
|
||
<!--卡若创业派对 - 阅读页-->
|
||
<view class="page">
|
||
<!-- 阅读进度条 -->
|
||
<view class="progress-bar-fixed" style="top: {{statusBarHeight}}px;">
|
||
<view class="progress-fill" style="width: {{readingProgress}}%;"></view>
|
||
</view>
|
||
|
||
<!-- 顶部导航栏 -->
|
||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||
<view class="nav-content">
|
||
<view class="nav-back" bindtap="goBack">
|
||
<icon name="chevron-left" size="44" color="#ffffff" customClass="back-arrow"></icon>
|
||
</view>
|
||
<view class="nav-info">
|
||
<text class="nav-chapter" wx:if="{{section.title || chapterTitle}}">{{section.title || chapterTitle}}</text>
|
||
</view>
|
||
<view class="nav-right-placeholder"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 导航栏占位 -->
|
||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||
|
||
<!-- 阅读内容 -->
|
||
<view class="read-content">
|
||
<!-- 骨架屏:加载中时展示,模拟章节标题+正文布局 -->
|
||
<view class="skeleton-wrap" wx:if="{{accessState === 'unknown' && loading}}">
|
||
<view class="skeleton-header">
|
||
<view class="skeleton-meta"></view>
|
||
<view class="skeleton-title"></view>
|
||
</view>
|
||
<view class="skeleton-lines">
|
||
<view class="skeleton skeleton-1"></view>
|
||
<view class="skeleton skeleton-2"></view>
|
||
<view class="skeleton skeleton-3"></view>
|
||
<view class="skeleton skeleton-4"></view>
|
||
<view class="skeleton skeleton-5"></view>
|
||
<view class="skeleton skeleton-6"></view>
|
||
<view class="skeleton skeleton-7"></view>
|
||
<view class="skeleton skeleton-8"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 章节标题(加载完成后) -->
|
||
<view class="chapter-header" wx:elif="{{!loading}}">
|
||
<view class="chapter-meta">
|
||
<text class="chapter-id">{{section.id}}</text>
|
||
<text class="tag tag-free" wx:if="{{section.isFree}}">免费</text>
|
||
</view>
|
||
<text class="chapter-title" user-select>{{section.title}}</text>
|
||
</view>
|
||
|
||
<!-- 完整内容 - 免费或已购买 -->
|
||
<view class="article" wx:if="{{accessState === 'free' || accessState === 'unlocked_purchased'}}">
|
||
<block wx:for="{{contentSegments}}" wx:key="index">
|
||
<view wx:if="{{item.length === 1 && item[0].type === 'heading'}}" class="seg-heading seg-h{{item[0].level}}">
|
||
<text user-select>{{item[0].text}}</text>
|
||
</view>
|
||
<view wx:elif="{{item.length === 1 && item[0].type === 'quote'}}" class="seg-quote">
|
||
<text user-select>{{item[0].text}}</text>
|
||
</view>
|
||
<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: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 class="chapter-nav">
|
||
<view class="nav-buttons">
|
||
<view
|
||
class="nav-btn nav-prev {{!prevSection ? 'nav-disabled' : ''}}"
|
||
bindtap="goToPrev"
|
||
wx:if="{{prevSection}}"
|
||
>
|
||
<text class="btn-label">上一篇</text>
|
||
<text class="btn-title">{{prevSection.title}}</text>
|
||
</view>
|
||
<view class="nav-btn-placeholder" wx:else></view>
|
||
|
||
<view
|
||
class="nav-btn nav-next"
|
||
bindtap="goToNext"
|
||
wx:if="{{nextSection}}"
|
||
>
|
||
<text class="btn-label">下一篇</text>
|
||
<view class="btn-row">
|
||
<text class="btn-title">{{nextSection.title}}</text>
|
||
<icon name="chevron-right" size="28" color="#00CED1" customClass="btn-arrow"></icon>
|
||
</view>
|
||
</view>
|
||
<view class="nav-btn nav-end" wx:else>
|
||
<text class="btn-end-text">已是最后一篇</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 分享区:仅好友/海报/代付;完整小程序发圈见右下角悬浮钮 -->
|
||
<view class="action-section">
|
||
<view class="action-row-inline">
|
||
<button plain class="action-share-native action-tile-unified" open-type="share" hover-class="action-share-native-hover" hover-stop-propagation>
|
||
<icon name="share" size="32" color="#00CED1" customClass="action-icon-small"></icon>
|
||
<text class="action-text-small">分享给好友</text>
|
||
</button>
|
||
<button plain class="action-share-native action-tile-unified" bindtap="generatePoster" hover-class="action-share-native-hover" hover-stop-propagation>
|
||
<icon name="image" size="32" color="#00CED1" customClass="action-icon-small"></icon>
|
||
<text class="action-text-small">生成海报</text>
|
||
</button>
|
||
<button plain class="action-share-native action-tile-unified" bindtap="showGiftShareModal" wx:if="{{isLoggedIn && !auditMode}}" hover-class="action-share-native-hover" hover-stop-propagation>
|
||
<icon name="gift" size="32" color="#00CED1" customClass="action-icon-small"></icon>
|
||
<text class="action-text-small">代付分享</text>
|
||
</button>
|
||
</view>
|
||
<view class="share-tip-inline" wx:if="{{!auditMode}}">
|
||
<text class="share-tip-text">{{readUi.shareTipLine}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 预览内容 + 付费墙 - 未登录(规则更新:前端按百分比裁切显示,后端不截断正文) -->
|
||
<view class="article preview" wx:if="{{accessState === 'locked_not_login'}}">
|
||
<view class="preview-wrap">
|
||
<view
|
||
id="previewContentMeasure"
|
||
class="preview-body"
|
||
style="{{previewMaxHeightPx > 0 ? ('max-height:' + previewMaxHeightPx + 'px; overflow:hidden;') : ''}}"
|
||
>
|
||
<block wx:for="{{contentSegments}}" wx:key="index">
|
||
<view wx:if="{{item.length === 1 && item[0].type === 'heading'}}" class="seg-heading seg-h{{item[0].level}}"><text user-select>{{item[0].text}}</text></view>
|
||
<view wx:elif="{{item.length === 1 && item[0].type === 'quote'}}" class="seg-quote"><text user-select>{{item[0].text}}</text></view>
|
||
<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: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>
|
||
|
||
<!-- 付费墙 - 未登录(营销主标题与「购买本章」同框体系) -->
|
||
<view class="paywall {{readSinglePageMode ? 'paywall--single-preview paywall--compact-sp' : ''}}">
|
||
<view class="paywall-icon paywall-icon--compact" wx:if="{{readSinglePageMode}}"><icon name="lock" size="64" color="#00CED1"></icon></view>
|
||
<view class="paywall-icon" wx:elif="{{!readSinglePageMode}}"><icon name="lock" size="80" color="#00CED1"></icon></view>
|
||
|
||
<block wx:if="{{readSinglePageMode}}">
|
||
<view class="paywall-marketing-box">
|
||
<view class="paywall-title-row paywall-title-row--boxed">
|
||
<text class="paywall-title paywall-title--inline">解锁完整内容,分享得到</text>
|
||
<text class="paywall-highlight-pct">{{shareRate || 90}}</text>
|
||
<text class="paywall-title paywall-title--inline">% 收益</text>
|
||
</view>
|
||
</view>
|
||
<view class="purchase-options paywall-sp-compact-btns" wx:if="{{!auditMode}}">
|
||
<view class="purchase-btn purchase-section purchase-btn--fulltext purchase-btn--compact-sp" bindtap="onUnlockTapInSinglePage">
|
||
<text class="btn-label btn-label--block">{{readUi.singlePagePayButtonText}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="paywall-audit-tip" wx:if="{{auditMode}}">审核中,暂不支持购买</view>
|
||
</block>
|
||
|
||
<block wx:else>
|
||
<view class="paywall-marketing-box" wx:if="{{!auditMode}}">
|
||
<view class="paywall-title-row paywall-title-row--boxed">
|
||
<text class="paywall-title paywall-title--inline">解锁完整内容,分享得到</text>
|
||
<text class="paywall-highlight-pct">{{shareRate || 90}}</text>
|
||
<text class="paywall-title paywall-title--inline">% 收益</text>
|
||
</view>
|
||
</view>
|
||
<view class="purchase-options" wx:if="{{!auditMode}}">
|
||
<view class="purchase-btn purchase-section purchase-section--primary" bindtap="handlePurchaseSection">
|
||
<text class="btn-label">购买本章</text>
|
||
<text class="btn-price">¥{{section && section.price != null ? section.price : sectionPrice}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="login-btn" bindtap="showLoginModal" style="margin-top:12px">
|
||
<text class="login-btn-text">手机号登录后购买</text>
|
||
</view>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 章节导航 -->
|
||
<view class="chapter-nav chapter-nav-locked">
|
||
<view class="nav-buttons">
|
||
<view
|
||
class="nav-btn nav-prev {{!prevSection ? 'nav-disabled' : ''}}"
|
||
bindtap="goToPrev"
|
||
wx:if="{{prevSection}}"
|
||
>
|
||
<text class="btn-label">上一篇</text>
|
||
<text class="btn-title">章节 {{prevSection.id}}</text>
|
||
</view>
|
||
<view class="nav-btn-placeholder" wx:else></view>
|
||
|
||
<view
|
||
class="nav-btn nav-next"
|
||
bindtap="goToNext"
|
||
wx:if="{{nextSection}}"
|
||
>
|
||
<text class="btn-label">下一篇</text>
|
||
<view class="btn-row">
|
||
<text class="btn-title">{{nextSection.title}}</text>
|
||
<icon name="chevron-right" size="28" color="#00CED1" customClass="btn-arrow"></icon>
|
||
</view>
|
||
</view>
|
||
<view class="nav-btn nav-end" wx:else>
|
||
<text class="btn-end-text">已是最后一篇</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 预览内容 + 付费墙 - 已登录未购买 -->
|
||
<view class="article preview" wx:if="{{accessState === 'locked_not_purchased'}}">
|
||
<view class="preview-wrap">
|
||
<view
|
||
id="previewContentMeasure"
|
||
class="preview-body"
|
||
style="{{previewMaxHeightPx > 0 ? ('max-height:' + previewMaxHeightPx + 'px; overflow:hidden;') : ''}}"
|
||
>
|
||
<block wx:for="{{contentSegments}}" wx:key="index">
|
||
<view wx:if="{{item.length === 1 && item[0].type === 'heading'}}" class="seg-heading seg-h{{item[0].level}}"><text user-select>{{item[0].text}}</text></view>
|
||
<view wx:elif="{{item.length === 1 && item[0].type === 'quote'}}" class="seg-quote"><text user-select>{{item[0].text}}</text></view>
|
||
<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: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>
|
||
|
||
<!-- 付费墙 - 已登录未购买:营销框 + 双按钮(浏览满 N 篇凸显读书会) -->
|
||
<view class="paywall {{readSinglePageMode ? 'paywall--single-preview paywall--compact-sp' : ''}} {{(!readSinglePageMode && ((paywall365Primary && showFullBookCta) || pay365AnchorVisible)) ? 'paywall--pay365-focus' : ''}}">
|
||
<view class="paywall-icon paywall-icon--compact" wx:if="{{readSinglePageMode}}"><icon name="lock" size="64" color="#00CED1"></icon></view>
|
||
<view class="paywall-icon" wx:elif="{{!readSinglePageMode && !pay365AnchorVisible}}"><icon name="lock" size="80" color="#00CED1"></icon></view>
|
||
|
||
<block wx:if="{{readSinglePageMode}}">
|
||
<view class="paywall-marketing-box">
|
||
<view class="paywall-title-row paywall-title-row--boxed">
|
||
<text class="paywall-title paywall-title--inline">解锁完整内容,分享得到</text>
|
||
<text class="paywall-highlight-pct">{{shareRate || 90}}</text>
|
||
<text class="paywall-title paywall-title--inline">% 收益</text>
|
||
</view>
|
||
</view>
|
||
<view class="purchase-options paywall-sp-compact-btns" wx:if="{{!auditMode}}">
|
||
<view class="purchase-btn purchase-section purchase-btn--fulltext purchase-btn--compact-sp" bindtap="onUnlockTapInSinglePage">
|
||
<text class="btn-label btn-label--block">{{readUi.singlePagePayButtonText}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="paywall-audit-tip" wx:if="{{auditMode}}">审核中,暂不支持购买</view>
|
||
</block>
|
||
|
||
<block wx:else>
|
||
<view class="paywall-marketing-box" wx:if="{{!auditMode}}">
|
||
<view class="paywall-title-row paywall-title-row--boxed">
|
||
<text class="paywall-title paywall-title--inline">解锁完整内容,分享得到</text>
|
||
<text class="paywall-highlight-pct">{{shareRate || 90}}</text>
|
||
<text class="paywall-title paywall-title--inline">% 收益</text>
|
||
</view>
|
||
</view>
|
||
<view class="pay365-anchor-row" wx:if="{{pay365AnchorVisible && !readSinglePageMode}}" id="pay365-marketing-anchor" bindtap="onPay365AnchorTap">
|
||
<text class="pay365-anchor-row-badge">365</text>
|
||
<text class="pay365-anchor-row-text">{{pay365AnchorLabel}}</text>
|
||
<text class="pay365-anchor-row-chevron">›</text>
|
||
</view>
|
||
<view class="purchase-options {{paywall365Primary && showFullBookCta ? 'purchase-options--365-first' : ''}}" wx:if="{{!auditMode}}">
|
||
<view class="{{sectionPurchaseBtnClass}}" bindtap="handlePurchaseSection">
|
||
<text class="btn-label">购买本章</text>
|
||
<text class="btn-price">¥{{section && section.price != null ? section.price : sectionPrice}}</text>
|
||
</view>
|
||
<view class="{{fullbookPurchaseBtnClass}}" bindtap="handlePurchaseFullBook" wx:if="{{showFullBookCta}}">
|
||
<text class="btn-label">加入读书会</text>
|
||
<text class="btn-price">¥{{fullBookPrice}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="paywall-audit-tip" wx:if="{{auditMode}}">审核中,暂不支持购买</view>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 章节导航 -->
|
||
<view class="chapter-nav chapter-nav-locked">
|
||
<view class="nav-buttons">
|
||
<view
|
||
class="nav-btn nav-prev {{!prevSection ? 'nav-disabled' : ''}}"
|
||
bindtap="goToPrev"
|
||
wx:if="{{prevSection}}"
|
||
>
|
||
<text class="btn-label">上一篇</text>
|
||
<text class="btn-title">章节 {{prevSection.id}}</text>
|
||
</view>
|
||
<view class="nav-btn-placeholder" wx:else></view>
|
||
|
||
<view
|
||
class="nav-btn nav-next"
|
||
bindtap="goToNext"
|
||
wx:if="{{nextSection}}"
|
||
>
|
||
<text class="btn-label">下一篇</text>
|
||
<view class="btn-row">
|
||
<text class="btn-title">{{nextSection.title}}</text>
|
||
<icon name="chevron-right" size="28" color="#00CED1" customClass="btn-arrow"></icon>
|
||
</view>
|
||
</view>
|
||
<view class="nav-btn nav-end" wx:else>
|
||
<text class="btn-end-text">已是最后一篇</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 错误状态 - 网络异常 -->
|
||
<view class="article preview" wx:if="{{accessState === 'error'}}">
|
||
<view class="paragraph" wx:for="{{previewParagraphs}}" wx:key="index" wx:if="{{item}}">
|
||
<text user-select>{{item}}</text>
|
||
</view>
|
||
|
||
<!-- 渐变遮罩 -->
|
||
<view class="fade-mask"></view>
|
||
|
||
<!-- 错误提示 -->
|
||
<view class="paywall">
|
||
<view class="paywall-icon"><icon name="warning" size="80" color="#ff9500"></icon></view>
|
||
<text class="paywall-title">网络异常</text>
|
||
<text class="paywall-desc">无法确认权限,请检查网络后重试</text>
|
||
|
||
<view class="login-btn" bindtap="handleRetry">
|
||
<text class="login-btn-text">重新加载</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 海报生成弹窗:居中 + z-index 高于右下角悬浮,避免「空白」错觉 -->
|
||
<view class="modal-overlay modal-overlay-center" wx:if="{{showPosterModal}}" bindtap="closePosterModal">
|
||
<view class="modal-content modal-content-center poster-modal" catchtap="stopPropagation">
|
||
<view class="modal-header">
|
||
<text class="modal-title">生成海报</text>
|
||
<view class="modal-close" bindtap="closePosterModal"><icon name="x" size="36" color="#8e8e93"></icon></view>
|
||
</view>
|
||
|
||
<!-- 海报预览 -->
|
||
<view class="poster-preview">
|
||
<canvas type="2d" id="posterCanvas" class="poster-canvas" style="width: 300px; height: 450px;"></canvas>
|
||
</view>
|
||
|
||
<view class="poster-actions">
|
||
<view class="poster-btn btn-save" bindtap="savePoster">
|
||
<icon name="save" size="36" color="#8e8e93" customClass="btn-icon"></icon>
|
||
<text>保存到相册</text>
|
||
</view>
|
||
</view>
|
||
|
||
<text class="poster-tip">长按海报可直接分享给好友</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 代付分享弹窗:阅读页内发起代付并支付 -->
|
||
<view class="modal-overlay modal-overlay-center" wx:if="{{showGiftModal}}" bindtap="closeGiftModal">
|
||
<view class="modal-content modal-content-center gift-modal-v2" catchtap="stopPropagation">
|
||
<view class="modal-header">
|
||
<text class="modal-title">{{giftPaid ? '代付已完成' : '生成代付链接'}}</text>
|
||
<view class="modal-close" bindtap="closeGiftModal"><icon name="x" size="36" color="#8e8e93"></icon></view>
|
||
</view>
|
||
|
||
<view class="gift-article-card">
|
||
<text class="gift-article-title">{{section.title || '代付商品'}}</text>
|
||
<text class="gift-article-desc" wx:if="{{section.desc}}">{{section.desc}}</text>
|
||
</view>
|
||
|
||
<view wx:if="{{!giftPaid}}">
|
||
<text class="gift-label">选择代付名额数</text>
|
||
<view class="gift-spots-grid">
|
||
<view class="gift-spot-btn {{giftQuantity===6?'gift-spot-active':''}}" bindtap="selectGiftQuantity" data-q="6">6</view>
|
||
<view class="gift-spot-btn {{giftQuantity===30?'gift-spot-active':''}}" bindtap="selectGiftQuantity" data-q="30">30</view>
|
||
<view class="gift-spot-btn {{giftQuantity===100?'gift-spot-active':''}}" bindtap="selectGiftQuantity" data-q="100">100</view>
|
||
<view class="gift-spot-btn {{giftQuantity===1000?'gift-spot-active':''}}" bindtap="selectGiftQuantity" data-q="1000">1000</view>
|
||
</view>
|
||
|
||
<view class="gift-price-box">
|
||
<text class="gift-price-label">待支付总价格</text>
|
||
<view class="gift-price-row">
|
||
<text class="gift-price-formula">¥{{giftUnitPrice}} × {{giftQuantity}} =</text>
|
||
<text class="gift-price-total">¥{{giftTotalPrice}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<button class="gift-pay-btn" bindtap="confirmGiftPay" disabled="{{giftPaying}}">
|
||
{{giftPaying ? '支付中...' : '确认并支付'}}
|
||
</button>
|
||
<view class="gift-cancel-text" bindtap="closeGiftModal">取消</view>
|
||
</view>
|
||
|
||
<view wx:else class="gift-paid-wrap">
|
||
<text class="gift-paid-tip">支付成功,点击下方按钮直接分享给好友。好友打开阅读页将自动领取并解锁。</text>
|
||
<button class="gift-share-btn" open-type="share" data-gift="1" data-request-sn="{{giftRequestSn}}">
|
||
发送给好友
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 登录弹窗(公用组件) -->
|
||
<login-modal
|
||
show="{{showLoginModal}}"
|
||
desc="登录后可购买章节、解锁更多内容"
|
||
showPrivacyModal="{{showPrivacyModal}}"
|
||
bind:close="onLoginModalClose"
|
||
bind:success="onLoginModalSuccess"
|
||
bind:privacyagree="onLoginModalPrivacyAgree"
|
||
/>
|
||
|
||
<!-- 支付中提示 -->
|
||
<view class="modal-overlay" wx:if="{{isPaying}}" catchtap="">
|
||
<view class="loading-box">
|
||
<view class="loading-spinner"></view>
|
||
<text class="loading-text">支付处理中...</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 单页预览(朋友圈):指向底栏「前往小程序」,字少;完整小程序仍保留发圈悬浮钮 -->
|
||
<view class="singlepage-launch-pointer" wx:if="{{readSinglePageMode && momentsPaywallExpanded}}" aria-hidden="true">
|
||
<view class="singlepage-launch-pointer__arrow">↓</view>
|
||
</view>
|
||
|
||
<view class="fab-share-moments" wx:if="{{!readSinglePageMode}}" bindtap="shareToMoments" hover-class="fab-share-moments-hover" aria-label="分享到朋友圈">
|
||
<icon name="share" size="44" color="#ffffff" customClass="fab-share-moments-icon"></icon>
|
||
</view>
|
||
|
||
<!-- 分享到朋友圈 自定义弹窗 -->
|
||
<view class="modal-overlay modal-overlay-center" wx:if="{{showMomentsModal}}" bindtap="closeMomentsModal">
|
||
<view class="modal-content modal-content-center moments-modal" catchtap="stopPropagation">
|
||
<view class="modal-header">
|
||
<text class="modal-title">分享到朋友圈</text>
|
||
<view class="modal-close" bindtap="closeMomentsModal"><icon name="x" size="36" color="#8e8e93"></icon></view>
|
||
</view>
|
||
|
||
<view class="moments-earn-banner">
|
||
<text class="moments-earn-text">好友购买,你获得</text>
|
||
<text class="moments-earn-pct">{{shareRate || 90}}%</text>
|
||
<text class="moments-earn-text">收益</text>
|
||
</view>
|
||
|
||
<view class="moments-steps">
|
||
<view class="moments-step">
|
||
<view class="moments-step-num">1</view>
|
||
<text class="moments-step-text">点击下方按钮复制文案</text>
|
||
</view>
|
||
<view class="moments-step">
|
||
<view class="moments-step-num">2</view>
|
||
<text class="moments-step-text">点击右上角「···」→「分享到朋友圈」</text>
|
||
</view>
|
||
<view class="moments-step">
|
||
<view class="moments-step-num">3</view>
|
||
<text class="moments-step-text">粘贴文案发布即可</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="moments-copy-btn {{momentsCopied ? 'moments-copy-btn--done' : ''}}" bindtap="onMomentsCopy">
|
||
<text>{{momentsCopied ? '已复制,去发朋友圈' : '复制发圈文案'}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 朋友圈单页预览:点「支付解锁全文」→ 半透明遮罩 + 底部提示 + 向下箭头指向系统「前往小程序」底栏 -->
|
||
<view
|
||
class="moments-launch-guide-mask"
|
||
wx:if="{{readSinglePageMode && showMomentsLaunchGuideModal}}"
|
||
bindtap="closeMomentsLaunchGuideModal"
|
||
>
|
||
<view class="moments-launch-guide-sheet" catchtap="stopPropagation">
|
||
<text class="moments-launch-guide-text">请点击下方「前往小程序」查看全文</text>
|
||
<view class="moments-launch-guide-arrow-wrap" aria-hidden="true">
|
||
<text class="moments-launch-guide-arrow">↓</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 已解锁阅读时:365 营销锚点(规则 revealMode=anchor),点击后再弹窗确认支付 -->
|
||
<view
|
||
class="pay365-anchor-float"
|
||
wx:if="{{pay365AnchorVisible && !readSinglePageMode && (accessState === 'free' || accessState === 'unlocked_purchased')}}"
|
||
bindtap="onPay365AnchorTap"
|
||
>
|
||
<text class="pay365-anchor-float-text">{{pay365AnchorLabel}}</text>
|
||
<text class="pay365-anchor-float-chevron">›</text>
|
||
</view>
|
||
</view>
|