From 24147cb2de6f8761e7d0d27e49e00f8d499ae8d8 Mon Sep 17 00:00:00 2001
From: 13404089107 <puwei@sinata.cn>
Date: 星期五, 15 五月 2026 17:59:17 +0800
Subject: [PATCH] feat: 优化文章详情页图片自适应,完善课程ID解析逻辑

---
 traditionalApp/pages/articleDetail/articleDetail.vue |  375 ++++++++++++++++++++---------------------
 traditionalApp/pages/courseDetail/courseDetail.vue   |  106 +++++-----
 traditionalApp/manifest.json                         |    4 
 3 files changed, 241 insertions(+), 244 deletions(-)

diff --git a/traditionalApp/manifest.json b/traditionalApp/manifest.json
index 9aff6cf..b3efb10 100644
--- a/traditionalApp/manifest.json
+++ b/traditionalApp/manifest.json
@@ -3,8 +3,8 @@
     "name" : "海诊康道",
     "appid" : "__UNI__1A90541",
     "description" : "",
-    "versionName" : "1.0.11",
-    "versionCode" : 111,
+    "versionName" : "1.0.14",
+    "versionCode" : 114,
     "transformPx" : false,
     /* 5+App特有相关 */
     "app-plus" : {
diff --git a/traditionalApp/pages/articleDetail/articleDetail.vue b/traditionalApp/pages/articleDetail/articleDetail.vue
index f23851c..8404f2b 100644
--- a/traditionalApp/pages/articleDetail/articleDetail.vue
+++ b/traditionalApp/pages/articleDetail/articleDetail.vue
@@ -2,7 +2,7 @@
 	<view class="container">
 		<!-- 状态栏占位 -->
 		<view class="status-bar-placeholder" :style="{ height: statusBarHeight + 'px' }"></view>
-		
+
 		<!-- 导航栏 -->
 		<view class="nav-bar">
 			<image class="back-icon" src="/static/image/home/left.png" mode="aspectFit" @tap="goBack"></image>
@@ -11,12 +11,7 @@
 
 		<!-- 视频播放器区域 -->
 		<view v-if="isVideoType" class="video-container">
-			<video
-				class="video-player"
-				:src="detail.videoUrl"
-				controls
-				:autoplay="false"
-			></video>
+			<video class="video-player" :src="detail.videoUrl" controls :autoplay="false"></video>
 		</view>
 
 		<!-- 图文封面区域 -->
@@ -35,217 +30,219 @@
 </template>
 
 <script setup lang="ts">
-import { computed, onMounted, ref } from 'vue'
-import { onLoad } from '@dcloudio/uni-app'
-import { getHealthPopularizationDetail } from './service'
+	import { computed, onMounted, ref } from 'vue'
+	import { onLoad } from '@dcloudio/uni-app'
+	import { getHealthPopularizationDetail } from './service'
 
-interface PopularizationDetail {
-	id?: number | null
-	title: string
-	coverImage: string
-	contentType?: number | null
-	contentTypeText: string
-	content: string
-	videoUrl: string
-	videoFileName: string
-}
-
-const statusBarHeight = ref(0)
-const loading = ref(false)
-const popularizationId = ref('')
-const detail = ref<PopularizationDetail>(createDefaultDetail())
-
-/**
- * 创建健康科普详情页默认数据,避免接口返回前页面闪空。
- */
-function createDefaultDetail(): PopularizationDetail {
-	return {
-		id: null,
-		title: '',
-		coverImage: '',
-		contentType: null,
-		contentTypeText: '',
-		content: '',
-		videoUrl: '',
-		videoFileName: '',
+	interface PopularizationDetail {
+		id ?: number | null
+		title : string
+		coverImage : string
+		contentType ?: number | null
+		contentTypeText : string
+		content : string
+		videoUrl : string
+		videoFileName : string
 	}
-}
 
-/**
- * 根据内容类型判断当前详情是否属于视频详情页。
- */
-const isVideoType = computed(() => Number(detail.value.contentType) === 2)
+	const statusBarHeight = ref(0)
+	const loading = ref(false)
+	const popularizationId = ref('')
+	const detail = ref<PopularizationDetail>(createDefaultDetail())
 
-/**
- * 将富文本正文转换为 `rich-text` 可直接消费的节点字符串。
- */
-const contentNodes = computed(() => buildRichTextNodes(detail.value.content, '暂无详情内容'))
-
-/**
- * 初始化导航栏所需的状态栏高度。
- */
-onMounted(() => {
-	uni.getSystemInfo({
-		success: (res) => {
-			statusBarHeight.value = res.statusBarHeight || 0
+	/**
+	 * 创建健康科普详情页默认数据,避免接口返回前页面闪空。
+	 */
+	function createDefaultDetail() : PopularizationDetail {
+		return {
+			id: null,
+			title: '',
+			coverImage: '',
+			contentType: null,
+			contentTypeText: '',
+			content: '',
+			videoUrl: '',
+			videoFileName: '',
 		}
-	})
-})
-
-/**
- * 页面加载时读取科普主键并拉取详情接口。
- */
-onLoad((options) => {
-	popularizationId.value = typeof options?.id === 'string' ? options.id : ''
-	loadDetail()
-})
-
-/**
- * 拉取健康科普详情接口并更新页面状态。
- */
-async function loadDetail() {
-	if (!popularizationId.value) {
-		detail.value = createDefaultDetail()
-		return
 	}
-	loading.value = true
-	try {
-		const response = await getHealthPopularizationDetail(popularizationId.value)
-		if (response?.code !== 0 || !response.data) {
-			showLoadFailedToast()
+
+	/**
+	 * 根据内容类型判断当前详情是否属于视频详情页。
+	 */
+	const isVideoType = computed(() => Number(detail.value.contentType) === 2)
+
+	/**
+	 * 将富文本正文转换为 `rich-text` 可直接消费的节点字符串。
+	 */
+	const contentNodes = computed(() => buildRichTextNodes(detail.value.content, '暂无详情内容'))
+
+	/**
+	 * 初始化导航栏所需的状态栏高度。
+	 */
+	onMounted(() => {
+		uni.getSystemInfo({
+			success: (res) => {
+				statusBarHeight.value = res.statusBarHeight || 0
+			}
+		})
+	})
+
+	/**
+	 * 页面加载时读取科普主键并拉取详情接口。
+	 */
+	onLoad((options) => {
+		popularizationId.value = typeof options?.id === 'string' ? options.id : ''
+		loadDetail()
+	})
+
+	/**
+	 * 拉取健康科普详情接口并更新页面状态。
+	 */
+	async function loadDetail() {
+		if (!popularizationId.value) {
+			detail.value = createDefaultDetail()
 			return
 		}
-		// 图文和视频共用一个详情接口,前端只按内容类型切换展示结构。
-		detail.value = {
-			...createDefaultDetail(),
-			...response.data,
+		loading.value = true
+		try {
+			const response = await getHealthPopularizationDetail(popularizationId.value)
+			if (response?.code !== 0 || !response.data) {
+				showLoadFailedToast()
+				return
+			}
+			// 图文和视频共用一个详情接口,前端只按内容类型切换展示结构。
+			detail.value = {
+				...createDefaultDetail(),
+				...response.data,
+			}
+		} catch {
+			showLoadFailedToast()
+		} finally {
+			loading.value = false
 		}
-	} catch {
-		showLoadFailedToast()
-	} finally {
-		loading.value = false
 	}
-}
 
-/**
- * 详情加载失败时给出统一提示。
- */
-function showLoadFailedToast() {
-	uni.showToast({
-		title: '健康科普详情加载失败',
-		icon: 'none',
-	})
-}
+	/**
+	 * 详情加载失败时给出统一提示。
+	 */
+	function showLoadFailedToast() {
+		uni.showToast({
+			title: '健康科普详情加载失败',
+			icon: 'none',
+		})
+	}
 
-/**
- * 将富文本内容转换为 `rich-text` 可直接渲染的节点。
- */
-function buildRichTextNodes(content?: string, fallbackText?: string) {
-	if (typeof content === 'string' && content.trim()) {
-		return content
+	/**
+	 * 将富文本内容转换为 `rich-text` 可直接渲染的节点。
+	 */
+	function buildRichTextNodes(content ?: string, fallbackText ?: string) {
+		if (typeof content === 'string' && content.trim()) {
+			return content.replace(/<img/gi,
+				'<img style="max-width:100%;height:auto;margin:0 auto;display:block"')
+		}
+		if (typeof fallbackText === 'string' && fallbackText.trim()) {
+			return `<p>${fallbackText.trim()}</p>`
+		}
+		return '<p></p>'
 	}
-	if (typeof fallbackText === 'string' && fallbackText.trim()) {
-		return `<p>${fallbackText.trim()}</p>`
-	}
-	return '<p></p>'
-}
 
-/**
- * 返回上一页;若没有历史栈,则回到首页避免停留在空白上下文。
- */
-function goBack() {
-	const currentPages = getCurrentPages()
-	if (currentPages.length > 1) {
-		uni.navigateBack()
-		return
+	/**
+	 * 返回上一页;若没有历史栈,则回到首页避免停留在空白上下文。
+	 */
+	function goBack() {
+		const currentPages = getCurrentPages()
+		if (currentPages.length > 1) {
+			uni.navigateBack()
+			return
+		}
+		uni.switchTab({
+			url: '/pages/home/home'
+		})
 	}
-	uni.switchTab({
-		url: '/pages/home/home'
-	})
-}
 </script>
 
 <style>
-page, html {
-	background-color: #F5F6F8;
-}
+	page,
+	html {
+		background-color: #F5F6F8;
+	}
 </style>
 
 <style lang="scss" scoped>
-.container {
-	min-height: 100vh;
-	background-color: #F5F6F8;
-}
+	.container {
+		min-height: 100vh;
+		background-color: #F5F6F8;
+	}
 
-.nav-bar {
-	height: 88rpx;
-	display: flex;
-	align-items: center;
-	padding: 0 24rpx;
-	background-color: #fff;
-	position: relative;
-}
+	.nav-bar {
+		height: 88rpx;
+		display: flex;
+		align-items: center;
+		padding: 0 24rpx;
+		background-color: #fff;
+		position: relative;
+	}
 
-.back-icon {
-	width: 40rpx;
-	height: 40rpx;
-	position: absolute;
-	left: 24rpx;
-	z-index: 10;
-}
+	.back-icon {
+		width: 40rpx;
+		height: 40rpx;
+		position: absolute;
+		left: 24rpx;
+		z-index: 10;
+	}
 
-.nav-title {
-	flex: 1;
-	text-align: center;
-	font-size: 36rpx;
-	font-weight: 500;
-	color: #333;
-}
+	.nav-title {
+		flex: 1;
+		text-align: center;
+		font-size: 36rpx;
+		font-weight: 500;
+		color: #333;
+	}
 
-.video-container {
-	width: 100%;
-	height: 402rpx;
-}
+	.video-container {
+		width: 100%;
+		height: 402rpx;
+	}
 
-.video-player {
-	width: 100%;
-	height: 100%;
-}
+	.video-player {
+		width: 100%;
+		height: 100%;
+	}
 
-.cover-container {
-	width: 100%;
-	height: 402rpx;
-}
+	.cover-container {
+		width: 100%;
+		height: 402rpx;
+	}
 
-.cover-image {
-	width: 100%;
-	height: 100%;
-}
+	.cover-image {
+		width: 100%;
+		height: 100%;
+	}
 
-.content-area {
-	padding: 32rpx;
-	background-color: #F5F6F8;
-}
+	.content-area {
+		padding: 32rpx;
+		background-color: #F5F6F8;
+	}
 
-.content-title {
-	font-size: 32rpx;
-	font-weight: 500;
-	color: #333;
-	line-height: 48rpx;
-}
+	.content-title {
+		font-size: 32rpx;
+		font-weight: 500;
+		color: #333;
+		line-height: 48rpx;
+	}
 
-.rich-content {
-	margin-top: 24rpx;
-	width: 100%;
-	font-size: 28rpx;
-	line-height: 1.8;
-	color: #333;
-}
+	.rich-content {
+		margin-top: 24rpx;
+		width: 100%;
+		font-size: 28rpx;
+		line-height: 1.8;
+		color: #333;
+	}
 
-.status-text {
-	margin-top: 24rpx;
-	font-size: 26rpx;
-	line-height: 40rpx;
-	color: #86909C;
-}
-</style>
+	.status-text {
+		margin-top: 24rpx;
+		font-size: 26rpx;
+		line-height: 40rpx;
+		color: #86909C;
+	}
+</style>
\ No newline at end of file
diff --git a/traditionalApp/pages/courseDetail/courseDetail.vue b/traditionalApp/pages/courseDetail/courseDetail.vue
index 5566596..acb2131 100644
--- a/traditionalApp/pages/courseDetail/courseDetail.vue
+++ b/traditionalApp/pages/courseDetail/courseDetail.vue
@@ -205,7 +205,7 @@
 					<view v-if="!loading && allVideos.length === 0" class="empty-text">暂无课程章节</view>
 				</view>
 			</template>
-  
+
 			<view v-if="loading" class="loading-text">加载中...</view>
 			<view v-if="isReadonlyDisplayMode" class="open-app-banner" @tap="openApp">
 				<view class="app-logo-placeholder"></view>
@@ -529,32 +529,32 @@
 	 * 页面加载时读取课程主键并拉取详情接口。
 	 */
 	onLoad((options) => {
-	courseId.value = resolveCourseId(options)
+		courseId.value = resolveCourseId(options)
 		loadCourseDetail()
 	})
 
-/**
- * 统一解析课程 id,兼容 App 路由参数和 H5 分享页地址参数。
- */
-function resolveCourseId(options?: Record<string, unknown>) {
-	const routeCourseId = typeof options?.id === 'string' ? options.id.trim() : ''
-	if (routeCourseId) {
-		return routeCourseId
-	}
-	// #ifdef H5
-	try {
-		const searchCourseId = new URLSearchParams(window.location.search).get('id')?.trim() || ''
-		if (searchCourseId) {
-			return searchCourseId
+	/**
+	 * 统一解析课程 id,兼容 App 路由参数和 H5 分享页地址参数。
+	 */
+	function resolveCourseId(options ?: Record<string, unknown>) {
+		const routeCourseId = typeof options?.id === 'string' ? options.id.trim() : ''
+		if (routeCourseId) {
+			return routeCourseId
 		}
-		const hashQuery = window.location.hash.split('?')[1] || ''
-		return new URLSearchParams(hashQuery).get('id')?.trim() || ''
-	} catch (error) {
-		console.log('解析课程分享参数失败', error)
+		// #ifdef H5
+		try {
+			const searchCourseId = new URLSearchParams(window.location.search).get('id')?.trim() || ''
+			if (searchCourseId) {
+				return searchCourseId
+			}
+			const hashQuery = window.location.hash.split('?')[1] || ''
+			return new URLSearchParams(hashQuery).get('id')?.trim() || ''
+		} catch (error) {
+			console.log('解析课程分享参数失败', error)
+		}
+		// #endif
+		return ''
 	}
-	// #endif
-	return ''
-}
 
 	/**
 	 * 页面显示时开启播放器安全能力。
@@ -890,19 +890,19 @@
 	 * 拉起或跳转下载 APP
 	 */
 	function openApp() {
-	const openAppUrl = 'https://m.malink.cn/s/7bIzeu'
-	// #ifdef H5
-	window.location.href = openAppUrl
-	return
-	// #endif
-	// #ifdef APP-PLUS
-	plus.runtime.openURL(openAppUrl)
-	return
-	// #endif
-	uni.showToast({
-		title: '当前环境不支持打开链接',
-		icon: 'none',
-	})
+		const openAppUrl = 'https://m.malink.cn/s/7bIzeu'
+		// #ifdef H5
+		window.location.href = openAppUrl
+		return
+		// #endif
+		// #ifdef APP-PLUS
+		plus.runtime.openURL(openAppUrl)
+		return
+		// #endif
+		uni.showToast({
+			title: '当前环境不支持打开链接',
+			icon: 'none',
+		})
 	}
 
 	/**
@@ -918,26 +918,26 @@
 	 * 生成课程 H5 分享链接,供微信好友打开页面详情。
 	 */
 	function buildCourseShareUrl() {
-	const shareBaseUrl = 'https://haizhentong.com/share/'
-	const shareCourseId = resolveShareCourseId()
-	if (!shareCourseId) {
-		return shareBaseUrl
-	}
-	return `${shareBaseUrl}?id=${encodeURIComponent(shareCourseId)}`
+		const shareBaseUrl = 'https://haizhentong.com/share/'
+		const shareCourseId = resolveShareCourseId()
+		if (!shareCourseId) {
+			return shareBaseUrl
+		}
+		return `${shareBaseUrl}?id=${encodeURIComponent(shareCourseId)}`
 	}
 
-/**
- * 生成分享使用的课程 id,优先使用路由参数,详情数据兜底。
- */
-function resolveShareCourseId() {
-	if (courseId.value) {
-		return courseId.value
+	/**
+	 * 生成分享使用的课程 id,优先使用路由参数,详情数据兜底。
+	 */
+	function resolveShareCourseId() {
+		if (courseId.value) {
+			return courseId.value
+		}
+		if (courseDetail.value.id !== undefined && courseDetail.value.id !== null) {
+			return String(courseDetail.value.id)
+		}
+		return ''
 	}
-	if (courseDetail.value.id !== undefined && courseDetail.value.id !== null) {
-		return String(courseDetail.value.id)
-	}
-	return ''
-}
 
 	/**
 	 * 通过微信好友聊天场景分享当前课程。
@@ -1924,4 +1924,4 @@
 		background-color: #E5E6EB;
 		color: #86909C;
 	}
-</style>
+</style>
\ No newline at end of file

--
Gitblit v1.7.1