Files
training/miniprogram/src/pages/content-detail/index.jsx
T
Pine e6152cb932 feat(content): C端正文富文本渲染(HTML)
- 小程序 content-detail:<RichText nodes=body> 渲染 HTML(图片/视频/排版),样式对齐
- 网站 Content.jsx 详情展开:dangerouslySetInnerHTML 渲染富文本

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 15:01:05 +08:00

71 lines
2.7 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { View, Text, Image, Video, ScrollView, Button, RichText } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { useState, useEffect } from 'react';
import { getContent } from '@/utils/content';
import './index.scss';
/** 资讯详情:封面/视频 + 正文 + 图集 + 外链 + 发布人。 */
export default function ContentDetail() {
const [item, setItem] = useState(null);
const [err, setErr] = useState('');
const [loaded, setLoaded] = useState(false);
useEffect(() => {
const inst = Taro.getCurrentInstance();
const id = (inst && inst.router && inst.router.params && inst.router.params.id) || '';
if (!id) { setErr('无效内容'); setLoaded(true); return; }
getContent(id).then(setItem).catch(() => setErr('加载失败')).finally(() => setLoaded(true));
}, []);
if (!loaded) return <View className="cd page-in"><Text className="cd-err">加载中</Text></View>;
if (err || !item) return <View className="cd page-in"><Text className="cd-err">{err || '内容不存在'}</Text></View>;
const img = item.cover || (item.video ? item.video_cover : '');
const images = Array.isArray(item.images) ? item.images : [];
return (
<View className="cd page-in">
{/* 视频或封面 */}
{item.video
? <Video className="cd-video" src={item.video} poster={item.video_cover || item.cover || ''} controls />
: img
? <Image className="cd-cover" src={img} mode="widthFix" />
: null}
<Text className="cd-title">{item.title}</Text>
{/* 发布人行 */}
<View className="cd-meta-row">
{item.publisher_avatar
? <Image className="cd-ava" src={item.publisher_avatar} mode="aspectFill" />
: <View className="cd-ava" />}
<Text className="cd-author">{item.publisher_name || '云超服'}</Text>
<Text className="cd-dot">·</Text>
<Text className="cd-meta-at">{fmt(item.created_at)}</Text>
</View>
{item.summary ? <Text className="cd-summary">{item.summary}</Text> : null}
{item.body
? <RichText className="cd-body" nodes={item.body} />
: <Text className="cd-body">暂无正文</Text>}
{/* 图集 */}
{images.length > 0 && (
<ScrollView className="cd-gallery" scrollX>
{images.map((u, i) => <Image key={i} className="cd-gal-img" src={u} mode="aspectFill" />)}
</ScrollView>
)}
{item.link ? (
<Button className="btn btn-ghost cd-link" type="default" onClick={() => Taro.setClipboardData({ data: item.link })}>
原文链接点击复制
</Button>
) : null}
</View>
);
}
function fmt(s) {
return (s || '').replace('T', ' ').replace('Z', '').slice(0, 16);
}