wangguoyu 1 maand geleden
bovenliggende
commit
972fd968f6
1 gewijzigde bestanden met toevoegingen van 288 en 334 verwijderingen
  1. 288 334
      pages/chanpinneirong/index.vue

+ 288 - 334
pages/chanpinneirong/index.vue

@@ -1,243 +1,247 @@
 <template>
 	<view class="container">
-		<view @click="aaaa">asdfasdfdasfads</view>
-		<view class="icon-title-navBar-box">
-			<view class="nav-bar-icon" @click="handleBack"></view>
-			<view class="nav-bar-title">学习</view>
+		<!-- 当前单元标题(吸顶效果) -->
+		<view class="sticky-title" v-if="currentUnitName">
+			{{ currentUnitName }}
 		</view>
-		<!-- z-paging 列表 -->
-		<z-paging ref="paging" @scroll="onScroll" @query="loadData" :refresher-enabled="false"
-			:loading-more-enabled="false" :auto="false" :fixed="false" :hide-empty-view="true">
 
+		<!-- 返回顶部按钮 -->
+		<view class="back-top" v-if="showBackTop" @click="scrollToTop">
+			<text>↑</text>
+		</view>
+
+		<scroll-view scroll-y class="scroll-view" :scroll-top="scrollTop" @scroll="onScroll">
+			<view class="subject-info" v-if="subjectDetail">
+				<text class="course-name">{{ subjectDetail.chanpinName }}</text>
+				<text class="course-name">等级:{{ subjectDetail.dengjiName }}</text>
+				<text class="course-name">版本:{{ subjectDetail.dengjiName }}</text>
+				<text class="course-name">单元:{{ subjectDetail.curDanyuanName }}</text>
+			</view>
 			<!-- 单元列表 -->
-			<view v-for="(danyuan, danyuanIndex) in danyuanList" :key="danyuan.danyuanId"
-				:id="'danyuan-' + danyuanIndex" class="danyuan-item">
-				<!-- 当前学科信息 -->
-				<view class="subject-info" v-if="subjectDetail">
-					<text class="course-name">{{ subjectDetail.chanpinName }}</text>
-					<text class="course-name">等级:{{ subjectDetail.dengjiName }}</text>
-					<text class="course-name">版本:{{ subjectDetail.dengjiName }}</text>
-					<text class="course-name">单元:{{ subjectDetail.curDanyuanName }}</text>
-					<text class="course-name">课程:{{ subjectDetail.chanpinName }}</text>
-				</view>
+			<view v-for="(unit, index) in danyuanList" :key="unit.danyuanId" :id="'unit-' + index" class="unit-item">
 				<!-- 单元标题 -->
-				<view class="danyuan-header">
-					<text class="danyuan-title">{{ danyuan.danyuanName }}</text>
-					<text class="danyuan-intro">{{ danyuan.danyuanIntro }}</text>
+				<view class="unit-title">
+					<text class="unit-name">{{ unit.danyuanName }}</text>
+					<text class="unit-intro">{{ unit.danyuanIntro }}</text>
 				</view>
 
 				<!-- 节列表 -->
-				<view v-if="danyuan.jieList && danyuan.jieList.length > 0">
-					<view v-for="jie in danyuan.jieList" :key="jie.jieId" class="jie-item">
-						<text class="jie-name">{{ jie.number }}. {{ jie.jieName }}</text>
-						<text class="jie-desc">{{ jie.jieIntro }}</text>
+				<view v-for="section in unit.jieList" :key="section.jieId" class="section-item">
+					<view class="status" :class="section.wanchengFlag === 1 ? 'completed' : 'uncompleted'">
+						{{ section.wanchengFlag === 1 ? '已完成' : '未开始' }}
+					</view>
+					<view class="section-left">
+						<image class="section-cover" :src="section.cover" mode="aspectFill"></image>
+						<view class="section-info">
+							<text class="section-name">{{ section.jieName }}</text>
+							<text class="section-desc">{{ section.jieIntro }}</text>
+						</view>
+					</view>
+					<view class="section-right">
+						<text class="section-number">第{{ section.number }}节</text>
+						<text>播放按钮</text>
 					</view>
-				</view>
-
-				<!-- 无课程内容提示 -->
-				<view v-else class="empty-jie">
-					<text class="empty-text">暂无课程内容</text>
 				</view>
 			</view>
-		</z-paging>
 
-		<!-- 回到顶部按钮 -->
-		<view v-if="showBackToTop" class="back-to-top" @click="scrollToTop">
-			<text class="back-to-top-icon">↑</text>
-			<text class="back-to-top-text">顶部</text>
-		</view>
-
-		<!-- 当前单元提示 -->
-		<view v-if="currentUnitName" class="current-unit-tip">
-			<text>{{ currentUnitName }}</text>
-		</view>
-	
-		<CustomTabBar :currentTabNumber="0"></CustomTabBar>
-		
+			<!-- 底部占位 -->
+			<view style="height: 100px; text-align: center;">查看更多内容</view>
+		</scroll-view>
+		<CustomTabBar :currentTabNumber="1"></CustomTabBar>
 	</view>
 </template>
 
 <script>
+	import CustomTabBar from '@/components/custom-tabbar/custom-tabbar.vue';
 	import {
 		shuxueChanpinBanben
 	} from "@/api/chanpinneirong.js"
-	import CustomTabBar from '@/components/custom-tabbar/custom-tabbar.vue';
 	export default {
 		data() {
 			return {
-				activeSubjectId: 2,
-
-				// 学科详情数据
-				subjectDetail: null,
-
-				// 单元列表
 				danyuanList: [],
-
-				// 当前单元名称
-				currentUnitName: '',
-
-				// 单元位置信息
-				unitPositions: [],
-
-				// 新增:是否显示回到顶部按钮
-				showBackToTop: false,
-
-				// 新增:显示回到顶部按钮的阈值(滚动多少距离后显示)
-				backToTopThreshold: 500
+				currentUnitName: "",
+				subjectDetail: null,
+				showBackTop: false,
+				scrollTop: 0,
+				pageCacheKey: 'learn_page_scroll_cache',
+				hasRestoredScroll: false
 			}
 		},
 		components: {
 			CustomTabBar
 		},
-		mounted() {
-			//初始化加载数据
-			this.$nextTick(() => {
-			//	this.$refs.paging.reload()
-			})
+		onShow() {
+				debugger
+			console.log('学习页面显示,尝试恢复滚动位置')
+			// 如果没有恢复过,从缓存恢复
+			if (!this.hasRestoredScroll) {
+				this.restoreScrollPosition()
+			}
+		},
+
+		// 新增:页面隐藏时保存滚动位置
+		onHide() {
+				debugger
+			console.log('学习页面隐藏,保存滚动位置')
+			this.saveScrollPosition()
+		},
+
+		onLoad() {
+				debugger
+			this.loadDataFromApi()
+		},
+
+		onReady() {
+			debugger
+			// 页面渲染完成后执行
+			setTimeout(() => {
+				this.getUnitPositions();
+			}, 300);
 		},
 
 		methods: {
-			aaaa(){
-				this.$refs.paging.reload()
-			},
-			handleBack() {
 
-			},
-			// z-paging 加载数据
-			async loadData() {
-				// 目前只处理数学学科
-				if (this.activeSubjectId !== 2) {
-					this.$refs.paging.complete([])
-					return
+
+			loadDataFromApi() {
+				const req = {
+					banbenId: 7
 				}
+				shuxueChanpinBanben(req).then(res => {
+					this.subjectDetail = res.data
+					this.danyuanList = res.data.danyuanList || []
+					// 初始化当前单元
+					if (this.danyuanList.length > 0) {
+						this.currentUnitName = this.danyuanList[0].danyuanName
+					}
+				})
+			},
 
-				try {
-					// 调用数学API
-					const req = {
-						banbenId: 7
+			// 新增:保存滚动位置到缓存
+			saveScrollPosition() {
+				if (this.scrollTop > 0) {
+					const scrollData = {
+						scrollTop: this.scrollTop,
+						currentUnit: this.currentUnitName,
+						timestamp: Date.now()
 					}
-					const res = await shuxueChanpinBanben(req)
+					uni.setStorageSync(this.pageCacheKey, scrollData)
+					console.log('保存滚动位置到缓存:', scrollData.scrollTop, '当前单元:', scrollData.currentUnit)
+				}
+			},
 
-					if (res.code === 0 && res.data) {
-						// 直接使用后端返回的数据
-						this.subjectDetail = res.data
-						this.danyuanList = res.data.danyuanList || []
+			// 新增:从缓存恢复滚动位置
+			restoreScrollPosition() {
+				try {
+					const saved = uni.getStorageSync(this.pageCacheKey)
+					if (saved && saved.scrollTop > 0) {
+						// 延迟执行滚动
+						setTimeout(() => {
+							this.scrollTop = saved.scrollTop
+
+							// 恢复当前单元名称
+							if (saved.currentUnit) {
+								this.currentUnitName = saved.currentUnit
+							}
 
-						// 告诉z-paging加载完成
-						this.$refs.paging.complete(this.danyuanList)
+							this.hasRestoredScroll = true
 
-						// 计算单元位置
-						this.$nextTick(() => {
-							this.calculateUnitPositions()
-						})
+							// 再次延迟确保滚动生效
+							setTimeout(() => {
+								this.scrollTop = saved.scrollTop + 0.01
+							}, 50)
+						}, 100)
 					}
-				} catch (error) {
-					console.error('加载失败:', error)
-					this.$refs.paging.complete(false)
+				} catch (e) {
+					console.error('读取缓存失败:', e)
 				}
 			},
-			// 计算单元位置
-			calculateUnitPositions() {
-				if (!this.danyuanList || this.danyuanList.length === 0) return
-				// 清空位置信息
-				this.unitPositions = []
-				// 使用 $nextTick 确保DOM已更新
-				this.$nextTick(() => {
-					// 稍微延迟确保渲染完成
-					setTimeout(() => {
-						const query = uni.createSelectorQuery().in(this)
-
-						// 一次性查询所有单元
-						const selectors = this.danyuanList.map((_, index) => {
-							return query.select(`#danyuan-${index}`).boundingClientRect()
-						})
-						// 执行查询
-						query.exec((results) => {
-							if (results && results.length === this.danyuanList.length) {
-								results.forEach((rect, index) => {
-									if (rect) {
-										// 保存相对位置(注意:这是相对于屏幕的位置)
-										this.$set(this.unitPositions, index, {
-											top: rect.top,
-											height: rect.height,
-											name: this.danyuanList[index]
-												.danyuanName
-										})
-									}
-								})
-								console.log('单元位置计算完成:', this.unitPositions)
-							}
-						})
-					}, 100)
-				})
+
+			// 获取每个单元的位置信息
+			getUnitPositions() {
+				const query = uni.createSelectorQuery().in(this);
+
+				this.danyuanList.forEach((unit, index) => {
+					query.select('#unit-' + index).boundingClientRect();
+				});
+
+				query.exec((res) => {
+					console.log('单元位置信息:', res);
+				});
 			},
-			// 滚动事件 - 修改后版本
-			onScroll(e) {
-				const scrollTop = e.detail.scrollTop
-				console.log('滚动位置:', scrollTop)
 
-				// 新增:控制回到顶部按钮的显示/隐藏
-				this.showBackToTop = scrollTop > this.backToTopThreshold
+			// 滚动事件处理
+			onScroll(e) {
+				const scrollTop = e.detail.scrollTop;
 
-				// 查找当前滚动到的单元
-				let currentUnitName = ''
+				// 更新滚动位置
+				this.scrollTop = scrollTop;
 
-				for (let i = this.unitPositions.length - 1; i >= 0; i--) {
-					const position = this.unitPositions[i]
-					if (position && scrollTop >= position.top - 50) {
-						currentUnitName = position.name
-						break
-					}
+				// 实时保存到缓存
+				const saveData = {
+					scrollTop: scrollTop,
+					currentUnit: this.currentUnitName,
+					timestamp: Date.now()
 				}
+				uni.setStorageSync(this.pageCacheKey, saveData)
 
-				// 更新当前单元提示
-				if (currentUnitName && currentUnitName !== this.currentUnitName) {
-					this.currentUnitName = currentUnitName
-					console.log('切换到单元:', currentUnitName)
-				}
+				// 显示/隐藏返回顶部按钮
+				this.showBackTop = scrollTop > 400;
+
+				// 监听滚动,更新当前显示的单元
+				this.updateCurrentUnit(scrollTop);
 			},
 
-			// 新增:回到顶部方法
-			scrollToTop() {
-				console.log('执行回到顶部')
-
-				// 方法1: 使用z-paging的scrollToTop方法(最简单)
-				if (this.$refs.paging) {
-					this.$refs.paging.scrollToTop({
-						animated: true,
-						duration: 300
-					})
+			// 更新当前显示的单元
+			updateCurrentUnit(scrollTop) {
+				const query = uni.createSelectorQuery().in(this);
+
+				for (let i = 0; i < this.danyuanList.length; i++) {
+					query.select('#unit-' + i).boundingClientRect();
 				}
 
-				// 方法2: 对于H5环境,额外滚动整个页面
-				// #ifdef H5
-				setTimeout(() => {
-					window.scrollTo({
-						top: 0,
-						behavior: 'smooth'
-					})
-				}, 100)
-				// #endif
-
-				// 方法3: 对于App环境,使用uni的pageScrollTo
-				// #ifdef APP-PLUS
-				uni.pageScrollTo({
-					scrollTop: 0,
-					duration: 300
-				})
-				// #endif
+				query.exec((res) => {
+					// 添加一个偏移量,让切换更平滑
+					const offset = 80;
+					for (let i = 0; i < res.length; i++) {
+						const rect = res[i];
+						if (rect) {
+							// 计算单元在页面中的实际位置(考虑滚动)
+							const unitTop = rect.top + scrollTop;
+							if (scrollTop + offset >= unitTop) {
+								if (i === res.length - 1 || scrollTop + offset < (res[i + 1].top + scrollTop)) {
+									if (this.currentUnitName !== this.danyuanList[i].danyuanName) {
+										this.currentUnitName = this.danyuanList[i].danyuanName;
+
+										// 单元变化时立即保存
+										const saveData = {
+											scrollTop: this.scrollTop,
+											currentUnit: this.currentUnitName,
+											timestamp: Date.now()
+										}
+										uni.setStorageSync(this.pageCacheKey, saveData)
+									}
+									break;
+								}
+							}
+						}
+					}
+				});
+			},
 
-				// 隐藏回到顶部按钮
-				this.showBackToTop = false
+			// 返回顶部
+			scrollToTop() {
+				// 清除缓存
+				uni.removeStorageSync(this.pageCacheKey)
+				this.hasRestoredScroll = false
 
-				// 可选:显示提示
-				uni.showToast({
-					title: '回到顶部',
-					icon: 'none',
-					duration: 800
-				})
+				// 回到顶部
+				this.scrollTop = this.scrollTop + 1; // 先改变值触发重新渲染
+				this.$nextTick(() => {
+					this.scrollTop = 0;
+					this.currentUnitName = this.danyuanList[0].danyuanName;
+				});
 			}
-
 		}
 	}
 </script>
@@ -245,204 +249,154 @@
 <style scoped>
 	.container {
 		height: 100vh;
-		background-color: #f8f9fa;
-	}
-
-	/* 学科标签页 */
-	.subject-tabs {
-		background-color: white;
-		padding: 20rpx 0;
-		border-bottom: 1rpx solid #eee;
+		background-color: #f5f5f5;
 	}
 
-	.tabs-scroll {
-		white-space: nowrap;
-		height: 80rpx;
-	}
-
-	.tabs-content {
-		display: inline-flex;
-		padding: 0 30rpx;
+	/* 吸顶标题 */
+	.sticky-title {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		z-index: 100;
+		background-color: #1890ff;
+		color: white;
+		padding: 12px 16px;
+		font-size: 16px;
+		font-weight: bold;
+		text-align: center;
+		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
 	}
 
-	.tab-item {
-		padding: 0 40rpx;
-		height: 60rpx;
+	/* 返回顶部按钮 */
+	.back-top {
+		position: fixed;
+		right: 16px;
+		bottom: 100px;
+		z-index: 99;
+		width: 44px;
+		height: 44px;
+		background-color: #1890ff;
+		border-radius: 50%;
 		display: flex;
 		align-items: center;
 		justify-content: center;
+		color: white;
+		font-size: 20px;
+		box-shadow: 0 2px 8px rgba(24, 144, 255, 0.4);
 	}
 
-	.tab-text {
-		font-size: 32rpx;
-		color: #666;
-		position: relative;
-		padding: 10rpx 0;
-	}
-
-	.tab-item.active .tab-text {
-		color: #4a6fe3;
-		font-weight: bold;
-	}
-
-	.tab-item.active .tab-text::after {
-		content: '';
-		position: absolute;
-		bottom: 0;
-		left: 0;
-		right: 0;
-		height: 4rpx;
-		background-color: #4a6fe3;
-		border-radius: 2rpx;
-	}
-
-	/* 学科信息 */
-	.subject-info {
-		padding: 30rpx;
-		background-color: white;
-		margin-bottom: 20rpx;
-	}
-
-	.course-name {
-		display: block;
-		font-size: 36rpx;
-		font-weight: bold;
-		color: #333;
-		margin-bottom: 10rpx;
+	.back-top:active {
+		background-color: #096dd9;
+		transform: scale(0.95);
 	}
 
-	.current-info {
-		display: block;
-		font-size: 28rpx;
-		color: #666;
+	/* 滚动区域 */
+	.scroll-view {
+		height: 100%;
+		padding-top: 50px;
+		/* 给吸顶标题留出空间 */
+		box-sizing: border-box;
 	}
 
 	/* 单元样式 */
-	.danyuan-item {
-		background-color: white;
-		margin: 20rpx;
-		border-radius: 16rpx;
+	.unit-item {
+		margin: 12px;
+		background: white;
+		border-radius: 8px;
 		overflow: hidden;
-		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
-		margin-bottom: 30rpx;
+		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
 	}
 
-	.danyuan-header {
-		background: #4a6fe3;
-		padding: 30rpx;
+	.unit-title {
+		padding: 16px;
+		background: linear-gradient(135deg, #1890ff, #36cfc9);
 		color: white;
 	}
 
-	.danyuan-title {
-		display: block;
-		font-size: 32rpx;
+	.unit-name {
+		font-size: 18px;
 		font-weight: bold;
-		margin-bottom: 10rpx;
+		display: block;
+		margin-bottom: 4px;
 	}
 
-	.danyuan-intro {
-		font-size: 28rpx;
+	.unit-intro {
+		font-size: 14px;
 		opacity: 0.9;
 	}
 
 	/* 节样式 */
-	.jie-item {
-		padding: 24rpx 30rpx;
-		border-bottom: 1rpx solid #f0f0f0;
+	.section-item {
+		padding: 12px 16px;
+		border-bottom: 1px solid #f0f0f0;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
 	}
 
-	.jie-item:last-child {
+	.section-item:last-child {
 		border-bottom: none;
 	}
 
-	.jie-name {
-		display: block;
-		font-size: 30rpx;
-		font-weight: 500;
-		color: #333;
-		margin-bottom: 8rpx;
+	.section-left {
+		display: flex;
+		align-items: center;
+		flex: 1;
 	}
 
-	.jie-desc {
-		display: block;
-		font-size: 26rpx;
-		color: #666;
+	.section-cover {
+		width: 60px;
+		height: 60px;
+		border-radius: 6px;
+		margin-right: 12px;
 	}
 
-	/* 空课程提示 */
-	.empty-jie {
-		padding: 40rpx;
-		text-align: center;
+	.section-info {
+		flex: 1;
 	}
 
-	.empty-text {
-		font-size: 28rpx;
-		color: #999;
+	.section-name {
+		font-size: 16px;
+		color: #333;
+		display: block;
+		margin-bottom: 4px;
+		font-weight: 500;
 	}
 
-	/* 新增:回到顶部按钮样式 */
-	.back-to-top {
-		position: fixed;
-		bottom: 120rpx;
-		right: 30rpx;
-		width: 100rpx;
-		height: 100rpx;
-		background-color: rgba(74, 111, 227, 0.9);
-		border-radius: 50%;
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		justify-content: center;
-		z-index: 999;
-		box-shadow: 0 4rpx 20rpx rgba(74, 111, 227, 0.3);
-		transition: all 0.3s ease;
+	.section-desc {
+		font-size: 13px;
+		color: #666;
 	}
 
-	.back-to-top:active {
-		transform: scale(0.95);
-		background-color: rgba(74, 111, 227, 1);
+	.section-right {
+		display: flex;
+		flex-direction: column;
+		align-items: flex-end;
+		margin-left: 12px;
 	}
 
-	.back-to-top-icon {
-		font-size: 40rpx;
-		color: white;
-		font-weight: bold;
+	.section-number {
+		font-size: 12px;
+		color: #999;
+		margin-bottom: 4px;
 	}
 
-	.back-to-top-text {
-		font-size: 22rpx;
-		color: white;
-		margin-top: 4rpx;
+	.status {
+		font-size: 12px;
+		padding: 2px 8px;
+		border-radius: 10px;
 	}
 
-	/* 当前单元提示 */
-	.current-unit-tip {
-		position: fixed;
-		top: 200rpx;
-		left: 50%;
-		transform: translateX(-50%);
-		background-color: rgba(74, 111, 227, 0.9);
-		color: white;
-		padding: 20rpx 40rpx;
-		border-radius: 50rpx;
-		font-size: 28rpx;
-		z-index: 1000;
-		box-shadow: 0 4rpx 20rpx rgba(74, 111, 227, 0.3);
-		animation: fadeInOut 3s ease-in-out;
+	.status.completed {
+		background-color: #f6ffed;
+		color: #52c41a;
+		border: 1px solid #b7eb8f;
 	}
 
-	@keyframes fadeInOut {
-
-		0%,
-		100% {
-			opacity: 0;
-			transform: translateX(-50%) translateY(-20rpx);
-		}
-
-		10%,
-		90% {
-			opacity: 1;
-			transform: translateX(-50%) translateY(0);
-		}
+	.status.uncompleted {
+		background-color: #fff7e6;
+		color: #fa8c16;
+		border: 1px solid #ffd591;
 	}
 </style>