feat(mini-program): 剧本卡片支持 Markdown 渲染

实现内容:
- 扩展 Markdown 组件支持三级标题 (###) 和粗体 (**text**)
- ScriptView.vue 卡片摘要使用 Markdown 组件渲染
- 新增 ScriptDetailView.vue 剧本详情页,展示完整 Markdown 内容
- 点击卡片可跳转查看详情,"路径映射"按钮使用@click.stop 避免事件冒泡

修改文件:
- components/Markdown.vue: 添加 h3 标题、粗体解析和样式
- pages/main/ScriptView.vue: 导入 Markdown 组件,修改摘要渲染方式,添加跳转逻辑
- pages/main/ScriptDetailView.vue: 新建详情页,展示剧本完整内容
- pages.json: 注册 ScriptDetailView 页面

解决 issues: 小程序"创造未来"页面剧本内容以纯文本显示,
            无法正确渲染 Markdown 格式(标题、列表、粗体等)
This commit is contained in:
2026-04-07 21:28:44 +08:00
parent 42d7bb3cb5
commit 86b3fa8f84
4 changed files with 486 additions and 80 deletions
@@ -0,0 +1,226 @@
<template>
<view class="detail-view">
<view class="detail-header">
<view class="header-left" @click="goBack">
<text class="back-icon"></text>
<text class="back-text">返回</text>
</view>
<text class="detail-title">{{ script?.title || '剧本详情' }}</text>
</view>
<scroll-view class="detail-content" scroll-y>
<view class="content-container">
<!-- 基本信息卡片 -->
<view class="info-card glass-card">
<view class="info-row">
<text class="info-label">主题</text>
<text class="info-value">{{ script?.theme || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">风格</text>
<text class="info-value">{{ script?.style || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">篇幅</text>
<text class="info-value">{{ script?.length || '-' }}</text>
</view>
</view>
<!-- 完整内容 -->
<view class="full-content glass-card">
<view class="content-header">
<text class="content-icon">📖</text>
<text class="content-label">完整剧本</text>
</view>
<Markdown :content="fullContent" />
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useAppStore } from '../../stores/app.js'
import Markdown from '../../components/Markdown.vue'
const store = useAppStore()
const script = ref(null)
const fullContent = ref('')
const scripts = computed(() => store.scripts || [])
onMounted(() => {
// 获取剧本 ID
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const scriptId = currentPage.options.id
// 从 store 获取剧本详情
if (scriptId) {
script.value = scripts.value.find(s => s.id === scriptId)
if (script.value?.plotJson?.fullContent) {
fullContent.value = script.value.plotJson.fullContent
} else {
fullContent.value = '暂无完整内容'
}
}
})
const goBack = () => {
uni.navigateBack()
}
</script>
<style scoped>
.detail-view {
display: flex;
flex-direction: column;
height: 100vh;
background: linear-gradient(180deg, #0F071A 0%, #1A0B2E 50%, #0F071A 100%);
}
/* ==================== 顶部导航栏 ==================== */
.detail-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 32rpx;
background: rgba(168, 85, 247, 0.1);
border-bottom: 1px solid rgba(168, 85, 247, 0.2);
flex-shrink: 0;
}
.header-left {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 16rpx;
border-radius: 24rpx;
background: rgba(168, 85, 247, 0.15);
border: 1px solid rgba(168, 85, 247, 0.2);
}
.back-icon {
font-size: 32rpx;
color: #C084FC;
font-weight: 600;
}
.back-text {
font-size: 24rpx;
color: rgba(243, 232, 255, 0.8);
}
.detail-title {
font-size: 32rpx;
font-weight: 500;
color: rgba(243, 232, 255, 0.9);
font-family: 'Cinzel', 'Inter', serif;
}
/* ==================== 滚动内容区 ==================== */
.detail-content {
flex: 1;
padding: 32rpx;
}
.content-container {
display: flex;
flex-direction: column;
gap: 32rpx;
padding-bottom: 40rpx;
}
/* ==================== 信息卡片 ==================== */
.info-card {
padding: 32rpx;
background: linear-gradient(135deg, rgba(168, 85, 247, 0.12), rgba(232, 121, 249, 0.08));
border: 1px solid rgba(168, 85, 247, 0.25);
border-radius: 40rpx;
box-shadow: inset 0 0 20rpx rgba(168, 85, 247, 0.05),
0 4rpx 20rpx rgba(168, 85, 247, 0.08);
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 0;
border-bottom: 1px solid rgba(168, 85, 247, 0.1);
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-size: 22rpx;
color: rgba(192, 132, 252, 0.7);
font-weight: 600;
letter-spacing: 2rpx;
text-transform: uppercase;
}
.info-value {
font-size: 26rpx;
color: rgba(243, 232, 255, 0.9);
}
/* ==================== 完整内容卡片 ==================== */
.full-content {
padding: 40rpx 32rpx;
background: rgba(168, 85, 247, 0.08);
border: 1px solid rgba(168, 85, 247, 0.2);
border-radius: 40rpx;
min-height: 400rpx;
}
.content-header {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 32rpx;
padding-bottom: 20rpx;
border-bottom: 2rpx solid rgba(168, 85, 247, 0.2);
}
.content-icon {
font-size: 36rpx;
filter: drop-shadow(0 0 8rpx rgba(192, 132, 252, 0.6));
}
.content-label {
font-size: 26rpx;
color: rgba(192, 132, 252, 0.8);
font-weight: 600;
letter-spacing: 4rpx;
text-transform: uppercase;
}
/* Markdown 内容间距调整 */
.full-content .markdown-container {
gap: 24rpx;
}
.full-content .markdown-h3 {
margin-top: 32rpx;
margin-bottom: 16rpx;
font-size: 32rpx;
}
.full-content .markdown-h4 {
margin-top: 24rpx;
margin-bottom: 12rpx;
}
.full-content .markdown-p {
font-size: 26rpx;
line-height: 1.8;
color: rgba(243, 232, 255, 0.85);
}
.full-content .markdown-hr {
margin: 40rpx 0;
}
</style>