Prechádzať zdrojové kódy

Merge branch 'master' of http://139.9.50.163:3000/Project2024/menber-center

LinWuTai 3 dní pred
rodič
commit
e449a23e53

+ 12 - 0
api/edu.js

@@ -89,4 +89,16 @@ export function courseCancelFavi(data) {
 		'method': 'post',
 		data: data
 	})
+}
+
+// 获取已观看记录
+export function loadCourseHistory(data) {
+	return request({
+		'url': '/course/history',
+		headers: {
+			isToken: true
+		},
+		'method': 'post',
+		data: data
+	})
 }

+ 31 - 21
pages/goOnEdu/course/courseDetail/courseOrder.vue

@@ -99,6 +99,8 @@
 		onLoad
 	} from '@dcloudio/uni-app'
 	import configService from '@/utils/baseurl.js'
+	import { loadCourseDetail } from "@/api/edu.js"
+	
 	const FILE_URL = configService.FILE_URL;
 	const courseId = ref("");
 	const course = ref({})
@@ -106,8 +108,6 @@
 	const activePayType = ref("微信支付")
 	const list = ref([{
 		text: '微信支付'
-	}, {
-		text: '支付宝支付'
 	}])
 	const show = ref(false)
 	const toBuy = () => {
@@ -122,25 +122,25 @@
 		show.value = false
 	}
 	// 加载数据
-	const init = (id) => {
-		// 加载数据
-		courseId.value = id
-		course.value = {
-			id: id,
-			courseName: "11Vue.js 从入门到精通",
-			courseType: "领袖锻造营",
-			name: "李老师11",
-			courseDate: "2023-09-15",
-			imgUrl: "https://tse4-mm.cn.bing.net/th/id/OIP-C.X_J8jL0bSPQ_jgOrdIbsgQHaEK?rs=1&pid=ImgDetMain",
-			price: 199.00,
-			hasBuy: true,
-			hasFavi: false,
-			payType: "会员免费",
-			expirationDate: "用户注销前有效"
-		}
-		course.courseTime = "18:00"
-		price.value = course.value.price
-	}
+	// const init = (id) => {
+	// 	// 加载数据
+	// 	courseId.value = id
+	// 	course.value = {
+	// 		id: id,
+	// 		courseName: "11Vue.js 从入门到精通",
+	// 		courseType: "领袖锻造营",
+	// 		name: "李老师11",
+	// 		courseDate: "2023-09-15",
+	// 		imgUrl: "https://tse4-mm.cn.bing.net/th/id/OIP-C.X_J8jL0bSPQ_jgOrdIbsgQHaEK?rs=1&pid=ImgDetMain",
+	// 		price: 199.00,
+	// 		hasBuy: true,
+	// 		hasFavi: false,
+	// 		payType: "会员免费",
+	// 		expirationDate: "用户注销前有效"
+	// 	}
+	// 	course.courseTime = "18:00"
+	// 	price.value = course.value.price
+	// }
 	// 日期格式:xxxx年xx月xx日(星期x)
 	function getDateWeek(val) {
 		const date = new Date(val);
@@ -152,6 +152,16 @@
 		// const result = `${year}年${month}月${day}日(星期${dayOfWeek})`
 		return `${year}年${month}月${day}日(星期${dayOfWeek})`
 	}
+	
+	// 初始化
+	function init(id) {
+		loadCourseDetail(id).then(res=>{
+			if(res?.data){
+				course.value = res.data;
+			}
+		})
+	}
+	
 	onLoad((option) => {
 		const {
 			id

+ 75 - 49
pages/goOnEdu/course/courseHome/courseHome.vue

@@ -41,59 +41,75 @@
 				<u-line />
 			</view>
 		</view>
-		<view>
-			<uni-load-more :status="loadMoreStatus"></uni-load-more>
+		<view style="margin: 20rpx 0;">
+			<u-loadmore :status="loadMoreStatus" @loadmore="loadmore" :load-text="loadText" />
+			<!-- <uni-load-more :status="loadMoreStatus" :load-text="loadText" @loadmore="loadmore"></uni-load-more> -->
 		</view>
 	</view>
 </template>
 
 <script setup>
 	import {
-		ref, onMounted, watch, 
+		ref,
+		onMounted,
+		watch,
 	} from 'vue';
 	import {
 		onReachBottom
 	} from '@dcloudio/uni-app'
-	import { loadCourseCate, loadCourseList, courseFavi, courseCancelFavi } from "@/api/edu.js"
-	import { useCourseStore } from "@/store/courseStore.js"
-	import { useAuthStore } from '@/store/authStore.js';
+	import {
+		loadCourseCate,
+		loadCourseList,
+		courseFavi,
+		courseCancelFavi
+	} from "@/api/edu.js"
+	import {
+		useCourseStore
+	} from "@/store/courseStore.js"
+	import {
+		useAuthStore
+	} from '@/store/authStore.js';
 	import configService from '@/utils/baseurl.js'
 	const FILE_URL = configService.FILE_URL;
 	const courseStore = useCourseStore();
 	const authStore = useAuthStore();
 	const isMember = ref(false);
 	const tabsList = ref([]);
-	const currentTab = ref(courseStore.currentTab); 
+	const currentTab = ref(courseStore.currentTab);
 	const searchForm = ref({
 		keyword: "",
 		pageNumber: 1,
 		pageSize: 10,
 	})
 	const pageNumber = ref(1)
-	const pageSize = ref(10)
+	const pageSize = ref(20)
 	const total = ref(0)
-	const loadMoreStatus = ref('more')
-	
+	const loadMoreStatus = ref('loadmore')
+
 	const courseMember = {
 		1: "免费",
 		2: "会员免费",
 		3: "付费",
 	}
+	const loadText = {
+		loadmore: '点击或上拉加载更多',
+		loading: '努力加载中',
+		nomore: '实在没有了'
+	}
 	// 展示的课程
 	const filterCourses = ref([]);
 	const courses = ref([{
-			id: 1,
-			courseName: "前端开发基础前端开发基础前端开发基础",
-			courseType: "精英训练营",
-			name: "张老师",
-			courseDate: "2023-10-01",
-			imgUrl: "https://tse3-mm.cn.bing.net/th/id/OIP-C.YKoZzgmubNBxQ8j-mmoTKAHaEK?rs=1&pid=ImgDetMain",
-			price: 99.00,
-			hasBuy: false,
-			hasFavi: true,
-			payType: "免费" // 新增字段,标识课程的付费类型
-		},
-	]);
+		id: 1,
+		courseName: "前端开发基础前端开发基础前端开发基础",
+		courseType: "精英训练营",
+		name: "张老师",
+		courseDate: "2023-10-01",
+		imgUrl: "https://tse3-mm.cn.bing.net/th/id/OIP-C.YKoZzgmubNBxQ8j-mmoTKAHaEK?rs=1&pid=ImgDetMain",
+		price: 99.00,
+		hasBuy: false,
+		hasFavi: true,
+		payType: "免费" // 新增字段,标识课程的付费类型
+	}, ]);
 
 	// 按钮的文字
 	function getButtonText(course) {
@@ -157,7 +173,8 @@
 		}
 		filterCourses.value = courses.value.filter(item => item.courseType == tabsList.value[index].name)
 	}
-	function toSearch(e){
+
+	function toSearch(e) {
 		pageNumber.value = 1
 		search(e)
 	}
@@ -166,46 +183,51 @@
 		searchForm.value.keyword = e
 		searchForm.value.pageNumber = pageNumber.value
 		searchForm.value.pageSize = pageSize.value
-		courses.value = pageNumber.value == 1? [] : courses.value
+		courses.value = pageNumber.value == 1 ? [] : courses.value
 		loadMoreStatus.value = 'loading'
-		loadCourseList(searchForm.value).then(res=>{
-			if(res?.data){
+		loadCourseList(searchForm.value).then(res => {
+			if (res?.data) {
 				total.value = res.count;
-				courses.value = [...courses.value,...res.data];
+				courses.value = [...courses.value, ...res.data];
 				const i = currentTab.value
-				if( i == 0){
+				if (i == 0) {
 					filterCourses.value = [...courses.value];
-				}else{
+				} else {
 					filterCourses.value = courses.value.filter(item => item.courseType == tabsList.value[i].name)
 				}
-				loadMoreStatus.value = total.value === courses.value.length ? 'nomore': 'more';
+				loadMoreStatus.value = total.value === courses.value.length ? 'nomore' : 'loadmore';
 				pageNumber.value++;
 			}
 		})
 	}
 	// 收藏
-	async function collectCourse(id,index,hasFavi) {
-		try{
+	async function collectCourse(id, index, hasFavi) {
+		try {
 			let res;
-			if(hasFavi){
+			if (hasFavi) {
 				res = await courseCancelFavi({
 					id
 				})
-			}else{
-				res = await courseFavi({id})
+			} else {
+				res = await courseFavi({
+					id
+				})
 			}
-			if(res.code == 0){
+			if (res.code == 0) {
 				courses.value[index].hasFavi = !courses.value[index].hasFavi
 			}
-		}catch(err){
+		} catch (err) {
 			courses.value[index].hasFavi = courses.value[index].hasFavi
 		}
 	}
 	// 初始化
 	function init() {
-		loadCourseCate().then(res=>{
-			if(res?.data){
-				tabsList.value = [{ code: '', name: '全部'}, ...res.data]
+		loadCourseCate().then(res => {
+			if (res?.data) {
+				tabsList.value = [{
+					code: '',
+					name: '全部'
+				}, ...res.data]
 			}
 		})
 		pageNumber.value = 1;
@@ -219,19 +241,23 @@
 			url: `/pages/goOnEdu/course/courseDetail/courseDetail?id=${course.id}&name=${course.courseName}`
 		});
 	}
+
+	function loadmore() {
+		if (courses.value.length === total.value) {
+			return;
+		}
+		search(searchForm.value.keyword);
+	}
 	onMounted(() => {
 		isMember.value = authStore.userInfo.isMember === 1 ? true : false
 		// console.log(authStore.userInfo.isMember)
-	    init();
-	    watch(currentTab, (newValue) => {
-	        courseStore.setCurrentTab(newValue); // 如果需要在切换时更新 Pinia 状态
-	    });
+		init();
+		watch(currentTab, (newValue) => {
+			courseStore.setCurrentTab(newValue); // 如果需要在切换时更新 Pinia 状态
+		});
 	});
-	onReachBottom(()=>{
-		if(courses.value.length === total.value){
-			return;
-		}
-		search(searchForm.value.keyword);
+	onReachBottom(() => {
+		loadmore()
 	})
 </script>
 

+ 140 - 125
pages/goOnEdu/course/courseMine/mineFavi/mineFavi.vue

@@ -1,37 +1,46 @@
 <template>
 	<view class="container">
-		<view class="course-list">
-			<view v-for="(course,index) in courses" :key="course.id">
-				<view class="course-item">
-					<view class="course-item-image">
-						<image class="course-image" :src="course.keChengTuPian" mode="aspectFill"></image>
-					</view>
-					<view class="course-item-content">
-						<view class="course-title">
-							<text>{{ course.keChengMingCheng }}</text>
+		<u-empty
+			mode="data"
+			v-if="courses.length === 0"
+			iconSize="120"
+			textSize="58"
+			text="暂无数据"
+		>
+		</u-empty>
+		<view class="course-list" style="margin-bottom: 20rpx;">
+			<view class="list-box">
+				<view class="list-item-box" v-for="item in courses" :key="item.id" @click="toCourse(item)">
+					<view class="info-box">
+						<view class="title">
+							{{item.title}}
 						</view>
-						<view class="course-type">{{ course.keChengLeXing }}</view>
-						<view class="course-teacher">
-							<u-icon name="account" size="28"></u-icon>
-							{{ course.shouKeZhe }}
+						<view class="text">
+							【{{item.typeName}}】
 						</view>
-						<view class="course-date">
-							<u-icon name="clock" size="28"></u-icon>
-							{{ getDateWeek(course.shouKeShiJian) }}
+					</view>
+					<view class="suffix-box">
+						<view class="button">
+							查看
 						</view>
-						<!-- <view class="course-price">¥{{ course.jiaGe }}元</view> -->
-						<!-- <button :class="['button', getButtonClass(course)]">{{ getButtonText(course) }}</button> -->
 					</view>
 				</view>
-				<u-line />
 			</view>
 		</view>
+		<u-loadmore :status="status" v-if="courses.length !== 0 && status!=='nomore'"/>
 	</view>
 </template>
 
 <script setup>
-	import { ref } from 'vue'
-	import { onLoad } from '@dcloudio/uni-app'
+	import {
+		ref
+	} from 'vue'
+	import {
+		onLoad, onReachBottom
+	} from '@dcloudio/uni-app'
+	import {
+		query
+	} from '@/api/collect.js'
 	// 日期格式:xxxx年xx月xx日(星期x)
 	function getDateWeek(val) {
 		const date = new Date(val);
@@ -43,140 +52,96 @@
 		// const result = `${year}年${month}月${day}日(星期${dayOfWeek})`
 		return `${year}年${month}月${day}日(星期${dayOfWeek})`
 	}
-	
+	const form = ref({
+		"keyword": "",
+		"type": "2",
+		"pageNumber": 1,
+		"pageSize": 30
+	})
+	const status = ref('loadmore')
+	const count = ref(0)
 	const courses = ref([]);
-	const initCourse = () =>{
-		// 获取列表
-		courses.value = [{
-			id: 1,
-			keChengMingCheng: "前端开发基础前端开发基础前端开发基础",
-			keChengLeXing: "精英训练营",
-			shouKeZhe: "张老师",
-			shouKeShiJian: "2023-10-01",
-			keChengTuPian: "https://tse3-mm.cn.bing.net/th/id/OIP-C.YKoZzgmubNBxQ8j-mmoTKAHaEK?rs=1&pid=ImgDetMain",
-			jiaGe: 99.00,
-			isGouMai: false,
-			isShouCang: true,
-			fuFeiLeiXing: "免费" // 新增字段,标识课程的付费类型
-		},
-		{
-			id: 2,
-			keChengMingCheng: "Vue.js 从入门到精通",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "李老师",
-			shouKeShiJian: "2023-09-15",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 199.00,
-			isGouMai: false,
-			isShouCang: false,
-			fuFeiLeiXing: "会员免费"
-		},
-		{
-			id: 3,
-			keChengMingCheng: "React 开发实战",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "王老师",
-			shouKeShiJian: "2023-11-05",
-			keChengTuPian: "https://desk-fd.zol-img.com.cn/t_s960x600c5/g4/M03/00/0C/Cg-4zFS8bC-Ie9zBADCvovJAqiEAATJ8wDX__cAMK-6184.jpg",
-			jiaGe: 149.00,
-			isGouMai: false,
-			isShouCang: false,
-			fuFeiLeiXing: "付费"
-		},
-		{
-			id: 4,
-			keChengMingCheng: "Node.js 全栈开发",
-			keChengLeXing: "合规专训营",
-			shouKeZhe: "赵老师",
-			shouKeShiJian: "2023-08-20",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 299.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "付费"
-		},
-		{
-			id: 5,
-			keChengMingCheng: "移动端开发技巧",
-			keChengLeXing: "精英训练营",
-			shouKeZhe: "钱老师",
-			shouKeShiJian: "2025-07-18",
-			keChengTuPian: "https://desk-fd.zol-img.com.cn/t_s960x600c5/g4/M03/00/0C/Cg-4zFS8bC-Ie9zBADCvovJAqiEAATJ8wDX__cAMK-6184.jpg",
-			jiaGe: 89.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "付费"
-		},
-		{
-			id: 6,
-			keChengMingCheng: "11Vue.js 从入门到精通",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "李老师11",
-			shouKeShiJian: "2023-09-15",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 199.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "会员免费"
-		},
-		{
-			id: 7,
-			keChengMingCheng: "113Vue.js 从入门到精通",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "李老师11",
-			shouKeShiJian: "2025-09-15",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 199.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "会员免费"
-		}]
+	const initCourse = () => {
+		if(status.value === 'nomore'){
+			return;
+		}
+		status.value = 'loading'
+		query(form.value).then(res=>{
+			if(res && res?.code ===0){
+				count.value = res.count
+				if(form.value.pageNumber===1){
+					courses.value = res.data
+				}else{
+					courses.value = [...courses.value, ...res.data]
+				}
+				
+				if(courses.value.length === res.count){
+					status.value = 'nomore'
+				}else{
+					status.value = 'loadmore'
+				}
+				
+				form.value.pageNumber = form.value.pageNumber + 1
+			}else{
+				status.value = 'loadmore'
+			}
+		})
+	}
+	const toCourse = (item)=>{
+		uni.navigateTo({
+			url: `/pages/goOnEdu/course/courseDetail/courseDetail?id=${item.id}&name=${item.title}`
+		});
 	}
 	onLoad(() => {
+		form.value.pageNumber = 1;
 		initCourse();
-		console.log('onLoad')
+	})
+	onReachBottom(()=>{
+		// 加载
+		initCourse()
 	})
 </script>
 
 <style lang="scss" scoped>
 	.container {
-		// height: 100vh;
+		height: 100vh;
 		width: 100vw;
 		background-color: #fff;
 		padding: 0 20rpx env(safe-area-inset-bottom, 0);
 	}
+
 	.course-item {
 		margin: 20rpx 0;
 		display: flex;
 		overflow: hidden;
-	
+
 		.course-item-image {
 			width: 200rpx;
 			height: 260rpx;
 			flex: 0 0 auto;
 			margin-right: 20rpx;
-	
+
 			.course-image {
 				width: 100%;
 			}
-	
+
 		}
-	
+
 		.course-item-content {
 			flex: 1;
 			position: relative;
-	
+
 			view {
 				margin-bottom: 15rpx;
 			}
-	
+
 			.course-title {
 				font-weight: bold;
 				margin-right: 10px;
 				font-size: 28rpx;
 				color: #000;
 			}
-	
+
 			.course-type,
 			.course-teacher,
 			.course-date,
@@ -184,17 +149,17 @@
 				font-size: 30rpx;
 				color: #000;
 			}
-	
+
 			.course-price {
 				color: #fe0000;
 				letter-spacing: 2rpx;
 			}
-	
+
 			.button::after {
 				content: none;
 				/* 移除内容 */
 			}
-	
+
 			.button {
 				position: absolute;
 				right: 0;
@@ -210,15 +175,15 @@
 				color: white;
 				border: none;
 			}
-	
+
 			.free {
 				background-color: #006af4;
 			}
-	
+
 			.purchase {
 				background-color: #fe0000;
 			}
-	
+
 			.member-free {
 				background-color: transparent;
 				background-image: url('http://www.gzrea.org.cn:8543/icon/wxmp/bg-label.png');
@@ -229,14 +194,64 @@
 				padding: 6rpx 0 3rpx;
 				border-radius: 0;
 			}
-	
+
 			.replay {
 				background-color: #006af4;
 			}
-	
+
 			.purchased {
 				background-color: #006af4;
 			}
 		}
 	}
+	
+	.list-box {
+		.list-item-box {
+			padding: 20rpx 10rpx;
+			border-bottom: 5rpx solid #E6E6E6;
+			display: flex;
+			&:active {
+				background-color: $uni-bg-color-hover;
+			}
+			.icon-box {
+				width: 3%;
+				padding-top: 10rpx;
+				.icon {
+					width: 10rpx;
+					height: 10rpx;
+					background-color: $uni-color-primary;
+					border-radius: 50%;
+				}
+			}
+			.info-box {
+				width: 82%;
+				.title {
+					font-size: $uni-title-font-size-2;
+					font-weight: bold;
+					margin-bottom: 5rpx;
+					@include text-overflow()
+				}
+				.text {
+					line-height: 40rpx;
+					font-size: $uni-font-size-2;
+					font-weight: bold;
+				}
+			}
+			.suffix-box {
+				width: 15%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				
+				.button {
+					color: $uni-text-color-inverse;
+					padding: 5rpx 18rpx;
+					border-radius: $uni-card-border-radius;
+					background-color: $uni-color-primary;
+					font-size: $uni-font-size-3;
+					letter-spacing: 3rpx;
+				}
+			}
+		}
+	}
 </style>

+ 77 - 117
pages/goOnEdu/course/courseMine/mineRecord/mineRecord.vue

@@ -1,39 +1,49 @@
 <template>
 	<view class="container">
+		<u-empty
+			mode="data"
+			v-if="courses.length === 0"
+			iconSize="120"
+			textSize="58"
+			text="暂无数据"
+		>
+		</u-empty>
 		<view class="course-list">
 			<view v-for="(course,index) in courses" :key="course.id">
 				<view class="course-item">
 					<view class="course-item-image">
-						<image class="course-image" :src="course.keChengTuPian" mode="aspectFill"></image>
+						<image class="course-image" :src="course.imgUrl" mode="aspectFill"></image>
 					</view>
 					<view class="course-item-content">
 						<view class="course-title">
-							<text>{{ course.keChengMingCheng }}</text>
-							
-						</view>
-						<view class="course-type">{{ course.keChengLeXing }}</view>
-						<view class="course-teacher">
-							<u-icon name="account" size="28"></u-icon>
-							{{ course.shouKeZhe }}
+							<text>{{ course.courseName }}</text>
+
 						</view>
+						<view class="course-type">{{ course.courseType }}</view>
 						<view class="course-date">
 							<u-icon name="clock" size="28"></u-icon>
-							{{ getDateWeek(course.shouKeShiJian) }}
+							{{ getDateWeek(course.viewDate) }}
 						</view>
-						<!-- <view class="course-price">¥{{ course.jiaGe }}元</view> -->
-						<!-- <button :class="['button', getButtonClass(course)]">{{ getButtonText(course) }}</button> -->
 					</view>
 				</view>
 				<u-line />
 			</view>
 		</view>
+		<u-loadmore :status="status" v-if="courses.length !== 0 && status!=='nomore'"/>
 	</view>
 </template>
 
 <script setup>
-	import { ref } from 'vue'
-	import { onLoad } from '@dcloudio/uni-app'
-	// 日期格式:xxxx年xx月xx日(星期x)
+	import {
+		ref
+	} from 'vue'
+	import {
+		onLoad, onReachBottom
+	} from '@dcloudio/uni-app'
+	import {
+		loadCourseHistory
+	} from '@/api/edu.js'
+
 	function getDateWeek(val) {
 		const date = new Date(val);
 		const daysOfWeek = ['日', '一', '二', '三', '四', '五', '六'];
@@ -44,140 +54,90 @@
 		// const result = `${year}年${month}月${day}日(星期${dayOfWeek})`
 		return `${year}年${month}月${day}日(星期${dayOfWeek})`
 	}
+	const form = ref({
+		pageNumber: 1,
+		pageSize: 20
+	})
+	const status = ref('loadmore')
 	
+	const total = ref(0)
 	const courses = ref([]);
-	const initCourse = () =>{
-		// 获取列表
-		courses.value = [{
-			id: 1,
-			keChengMingCheng: "前端开发基础前端开发基础前端开发基础",
-			keChengLeXing: "精英训练营",
-			shouKeZhe: "张老师",
-			shouKeShiJian: "2023-10-01",
-			keChengTuPian: "https://tse3-mm.cn.bing.net/th/id/OIP-C.YKoZzgmubNBxQ8j-mmoTKAHaEK?rs=1&pid=ImgDetMain",
-			jiaGe: 99.00,
-			isGouMai: false,
-			isShouCang: true,
-			fuFeiLeiXing: "免费" // 新增字段,标识课程的付费类型
-		},
-		{
-			id: 2,
-			keChengMingCheng: "Vue.js 从入门到精通",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "李老师",
-			shouKeShiJian: "2023-09-15",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 199.00,
-			isGouMai: false,
-			isShouCang: false,
-			fuFeiLeiXing: "会员免费"
-		},
-		{
-			id: 3,
-			keChengMingCheng: "React 开发实战",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "王老师",
-			shouKeShiJian: "2023-11-05",
-			keChengTuPian: "https://desk-fd.zol-img.com.cn/t_s960x600c5/g4/M03/00/0C/Cg-4zFS8bC-Ie9zBADCvovJAqiEAATJ8wDX__cAMK-6184.jpg",
-			jiaGe: 149.00,
-			isGouMai: false,
-			isShouCang: false,
-			fuFeiLeiXing: "付费"
-		},
-		{
-			id: 4,
-			keChengMingCheng: "Node.js 全栈开发",
-			keChengLeXing: "合规专训营",
-			shouKeZhe: "赵老师",
-			shouKeShiJian: "2023-08-20",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 299.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "付费"
-		},
-		{
-			id: 5,
-			keChengMingCheng: "移动端开发技巧",
-			keChengLeXing: "精英训练营",
-			shouKeZhe: "钱老师",
-			shouKeShiJian: "2025-07-18",
-			keChengTuPian: "https://desk-fd.zol-img.com.cn/t_s960x600c5/g4/M03/00/0C/Cg-4zFS8bC-Ie9zBADCvovJAqiEAATJ8wDX__cAMK-6184.jpg",
-			jiaGe: 89.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "付费"
-		},
-		{
-			id: 6,
-			keChengMingCheng: "11Vue.js 从入门到精通",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "李老师11",
-			shouKeShiJian: "2023-09-15",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 199.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "会员免费"
-		},
-		{
-			id: 7,
-			keChengMingCheng: "113Vue.js 从入门到精通",
-			keChengLeXing: "领袖锻造营",
-			shouKeZhe: "李老师11",
-			shouKeShiJian: "2025-09-15",
-			keChengTuPian: "https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c",
-			jiaGe: 199.00,
-			isGouMai: true,
-			isShouCang: false,
-			fuFeiLeiXing: "会员免费"
-		}]
+	const initCourse = () => {
+		if(status.value==='nomore'){
+			return
+		}
+		status.value === 'loading'
+		loadCourseHistory(form.value).then(res=>{
+			if(res && res?.code===0){
+				total.value = res.count;
+				if(form.value.pageNumber===1){
+					courses.value = res.data
+				}else{
+					courses.value = [...courses.value, ...res.data]
+				}
+				if(courses.value.length === res.count){
+					status.value = 'nomore'
+				}else{
+					status.value = 'loadmore'
+				}
+				
+			}else{
+				status.value = 'loadmore'
+			}
+		})
 	}
 	onLoad(() => {
+		form.value.pageNumber = 1
 		initCourse();
-		console.log('onLoad')
+		// console.log('onLoad')
+	})
+	
+	onReachBottom(()=>{
+		// 加载
+		initCourse()
 	})
 </script>
 
 <style lang="scss" scoped>
 	.container {
-		// height: 100vh;
+		height: 100vh;
 		width: 100vw;
 		background-color: #fff;
 		padding: 0 20rpx env(safe-area-inset-bottom, 0);
 	}
+
 	.course-item {
 		margin: 20rpx 0;
 		display: flex;
 		overflow: hidden;
-	
+
 		.course-item-image {
 			width: 200rpx;
 			height: 260rpx;
 			flex: 0 0 auto;
 			margin-right: 20rpx;
-	
+
 			.course-image {
 				width: 100%;
 			}
-	
+
 		}
-	
+
 		.course-item-content {
 			flex: 1;
 			position: relative;
-	
+
 			view {
 				margin-bottom: 15rpx;
 			}
-	
+
 			.course-title {
 				font-weight: bold;
 				margin-right: 10px;
 				font-size: 28rpx;
 				color: #000;
 			}
-	
+
 			.course-type,
 			.course-teacher,
 			.course-date,
@@ -185,17 +145,17 @@
 				font-size: 30rpx;
 				color: #000;
 			}
-	
+
 			.course-price {
 				color: #fe0000;
 				letter-spacing: 2rpx;
 			}
-	
+
 			.button::after {
 				content: none;
 				/* 移除内容 */
 			}
-	
+
 			.button {
 				position: absolute;
 				right: 0;
@@ -211,15 +171,15 @@
 				color: white;
 				border: none;
 			}
-	
+
 			.free {
 				background-color: #006af4;
 			}
-	
+
 			.purchase {
 				background-color: #fe0000;
 			}
-	
+
 			.member-free {
 				background-color: transparent;
 				background-image: url('http://www.gzrea.org.cn:8543/icon/wxmp/bg-label.png');
@@ -230,11 +190,11 @@
 				padding: 6rpx 0 3rpx;
 				border-radius: 0;
 			}
-	
+
 			.replay {
 				background-color: #006af4;
 			}
-	
+
 			.purchased {
 				background-color: #006af4;
 			}

+ 87 - 52
pages/researchReport/reportHome/reportHome.vue

@@ -2,10 +2,8 @@
 	<view class="container">
 		<view v-show="menuCurrent === 0">
 			<view class="menus-box">
-				<view class="menus-item-box"
-				@click="toReportList(key, data.value)"
-				v-for="(data,key) in categoryList"
-				:key="key">
+				<view class="menus-item-box" @click="toReportList(key, data.value)" v-for="(data,key) in categoryList"
+					:key="key">
 					<view class="icon-box">
 						<view class="iconfont icon-hetong"></view>
 					</view>
@@ -42,17 +40,14 @@
 		<view v-show="menuCurrent === 1">
 			<view class="header-box">
 				<view class="search-box">
-					<u-search
-						v-model="searchForm.keyword"
-						:clearabled="true"
-						bg-color="#E5E5E5"
-						:input-style="searchInputStyle"
-						placeholder="搜索您想要的内容"
+					<u-search v-model="searchForm.keyword" :clearabled="true" bg-color="#E5E5E5"
+						:input-style="searchInputStyle" placeholder="搜索您想要的内容"
 						@search="searchHistory(searchForm.keyword, 1)"
-						@custom="searchHistory(searchForm.keyword, 1)"
-					></u-search>
+						@custom="searchHistory(searchForm.keyword, 1)"></u-search>
 				</view>
 			</view>
+			<u-empty margin-top="50" mode="data" v-if="list.length === 0" iconSize="120" textSize="58" text="暂无数据">
+			</u-empty>
 			<view class="list-box">
 				<view class="list-item-box" v-for="item in list" :key="item.id" @click="onClickReport(item)">
 					<view class="image-box">
@@ -69,7 +64,9 @@
 						<view class="func">
 							<view v-if="item.free > 0" class="button free">免费</view>
 							<view v-else-if="item.memberFree > 0" class="button member-free">会员免费</view>
-							<view v-else :class="['button', item.status > 0 ? 'free' : 'buy']">{{item.status > 0 ? '已购买' : '立即购买'}}</view>
+							<view v-else :class="['button', item.status > 0 ? 'free' : 'buy']">
+								{{item.status > 0 ? '已购买' : '立即购买'}}
+							</view>
 						</view>
 					</view>
 				</view>
@@ -79,17 +76,15 @@
 		<view v-show="menuCurrent === 2">
 			<view class="header-box">
 				<view class="search-box">
-					<u-search
-						v-model="searchForm.keyword"
-						:clearabled="true"
-						bg-color="#E5E5E5"
-						:input-style="searchInputStyle"
-						placeholder="搜索您想要的内容"
-						@search="searchMy(searchForm.keyword, 1)"
-						@custom="searchMy(searchForm.keyword, 1)"
-					></u-search>
+					<u-search v-model="searchForm.keyword" :clearabled="true" bg-color="#E5E5E5"
+						:input-style="searchInputStyle" placeholder="搜索您想要的内容" @search="searchMy(searchForm.keyword, 1)"
+						@custom="searchMy(searchForm.keyword, 1)"></u-search>
 				</view>
 			</view>
+			<u-empty 
+			margin-top="50"
+			mode="data" v-if="list2.length === 0" iconSize="120" textSize="58" text="暂无数据">
+			</u-empty>
 			<view class="list-box">
 				<view class="list-item-box" v-for="item in list2" :key="item.id" @click="onClickReport(item)">
 					<view class="image-box">
@@ -109,7 +104,8 @@
 				</view>
 			</view>
 		</view>
-		<u-loadmore v-if="menuCurrent !== 0" :status="status" margin-top="20" margin-bottom="20"  @loadmore="loadMore"/>
+		<u-loadmore v-if="menuCurrent !== 0 && status !== 'nomore'" :status="status" margin-top="20" margin-bottom="20"
+			@loadmore="loadMore" />
 		<view class="bottom-block"></view>
 		<view class="bottom-box">
 			<view class="menu-box">
@@ -131,15 +127,23 @@
 </template>
 
 <script setup>
-	import { ref, computed } from 'vue'
-	import { onLoad } from '@dcloudio/uni-app'
+	import {
+		ref,
+		computed
+	} from 'vue'
+	import {
+		onLoad,
+		onReachBottom
+	} from '@dcloudio/uni-app'
 	import {
 		getReportCate,
 		loadReportHistory,
 		loadMyReport
 	} from '@/api/report.js'
 
-	import { useReportStore } from '@/store/reportStore.js'
+	import {
+		useReportStore
+	} from '@/store/reportStore.js'
 
 	const reportStore = useReportStore();
 
@@ -170,32 +174,32 @@
 		menuCurrent.value = index;
 		searchForm.value.keyword = ""
 		status.value = 'loadmore'
-		if(index===1){
+		if (index === 1) {
 			// 浏览记录
 			searchHistory("", 1)
-		}else if(index===2){
+		} else if (index === 2) {
 			// 我的报告
 			searchMy("", 1)
 		}
 	}
 
-	function searchHistory(keyword, pageNumber, pageSize){
+	function searchHistory(keyword, pageNumber, pageSize) {
 		status.value = 'loading'
 		loadReportHistory({
 			keyword,
 			pageNumber: pageNumber,
-			pageSize: pageSize?pageSize:10
-		}).then(res=>{
-			if(res.code===0){
-				if(pageNumber===1){
+			pageSize: pageSize ? pageSize : 10
+		}).then(res => {
+			if (res.code === 0) {
+				if (pageNumber === 1) {
 					list.value = res.data
-				}else{
+				} else {
 					list.value = [...list.value, ...res.data]
 				}
 				listCount.value = res.count
-				if(list.value.length === res.count){
+				if (list.value.length === res.count) {
 					status.value = 'nomore'
-				}else{
+				} else {
 					status.value = 'loadmore'
 				}
 				pageNum.value = pageNumber + 1;
@@ -203,23 +207,23 @@
 		})
 	}
 
-	function searchMy(keyword, pageNumber, pageSize){
+	function searchMy(keyword, pageNumber, pageSize) {
 		status.value = 'loading'
 		loadMyReport({
 			keyword,
 			pageNumber: pageNumber,
-			pageSize: pageSize?pageSize:10
-		}).then(res=>{
-			if(res.code===0){
-				if(pageNumber===1){
+			pageSize: pageSize ? pageSize : 10
+		}).then(res => {
+			if (res.code === 0) {
+				if (pageNumber === 1) {
 					list2.value = res.data
-				}else{
+				} else {
 					list2.value = [...list2.value, ...res.data]
 				}
 				listCount2.value = res.count
-				if(list2.value.length === res.count){
+				if (list2.value.length === res.count) {
 					status.value = 'nomore'
-				}else{
+				} else {
 					status.value = 'loadmore'
 				}
 				pageNum.value = pageNumber + 1;
@@ -234,7 +238,7 @@
 		})
 	}
 
-	async function init(){
+	async function init() {
 		const cateRes = await getReportCate();
 		if (cateRes.code === 0) {
 			const result = cateRes.data.reduce((acc, curr) => {
@@ -266,15 +270,23 @@
 			url: `/pages/reportDetail/reportDetail?id=${report.id}&title=${report.title}`
 		})
 	}
-	
-	function loadMore(){
-		if(menuCurrent.value === 1){
+
+	function loadMore() {
+		if (menuCurrent.value === 1) {
+			if (list.value.length === listCount) {
+				return
+			}
 			searchHistory(searchForm.value.keyword, pageNum.value)
-		}else{
+		} else {
+			if (list2.value.length === listCount2) {
+				return
+			}
 			searchMy(searchForm.value.keyword, pageNum.value)
 		}
 	}
-
+	onReachBottom(() => {
+		loadMore()
+	})
 	onLoad((load) => {
 		// console.log(load,"reporthome")
 		if (load.menuCurrent) {
@@ -282,7 +294,6 @@
 		}
 		init()
 	})
-
 </script>
 
 <style lang="scss" scoped>
@@ -301,6 +312,7 @@
 
 		.search-box {
 			margin-bottom: 20rpx;
+
 			::v-deep(.u-search) {
 				background-color: #e5e5e5;
 				border-radius: 50rpx;
@@ -321,17 +333,21 @@
 
 		.list-box {
 			padding: 0 20rpx;
+
 			.list-item-box {
 				padding: 30rpx 20rpx;
 				display: flex;
 				gap: 20rpx;
 				height: 210rpx;
 				border-bottom: 5rpx solid #E6E6E6;
+
 				&:active {
 					background-color: $uni-bg-color-hover;
 				}
+
 				.image-box {
 					width: $image-width;
+
 					image {
 						width: $image-width;
 						flex: 0 0 $image-width;
@@ -339,6 +355,7 @@
 						border-radius: $uni-card-border-radius;
 					}
 				}
+
 				.info-box {
 					.title {
 						font-size: $uni-title-font-size-2;
@@ -347,39 +364,47 @@
 						margin-bottom: 15rpx;
 						@include text-line-overflow(2);
 					}
+
 					.time {
 						font-size: $uni-font-size-2;
 						color: $uni-text-color-grey;
+
 						.iconfont {
 							font-size: $uni-font-size-2;
 							padding-right: 10rpx;
 						}
 					}
+
 					.func {
 						display: flex;
 						justify-content: flex-end;
 						font-size: $uni-font-size-2;
 						font-weight: bold;
+
 						.button {
 							text-align: center;
 							width: 130rpx;
 						}
+
 						.price {
 							color: $uni-color-error;
 							font-size: $uni-title-font-size-2;
 						}
+
 						.buy {
 							padding: 6rpx 25rpx;
 							background-color: $uni-color-error;
 							border-radius: $uni-card-border-radius;
 							color: $uni-text-color-inverse;
 						}
+
 						.free {
 							padding: 6rpx 25rpx;
 							background-color: $uni-color-primary;
 							border-radius: $uni-card-border-radius;
 							color: $uni-text-color-inverse;
 						}
+
 						.member-free {
 							padding: 10rpx 20rpx;
 							@include backgroundImg('http://www.gzrea.org.cn:8543/icon/wxmp/bg-label.png');
@@ -392,6 +417,7 @@
 
 		.menus-box {
 			padding: 0 20rpx;
+
 			.menus-item-box {
 				width: 100%;
 				padding: 35rpx 50rpx;
@@ -401,9 +427,11 @@
 				align-items: center;
 				background-color: #006AF4;
 				border-radius: $uni-card-border-radius;
+
 				&:active {
 					background-color: #005AF4;
 				}
+
 				.icon-box {
 					width: 40%;
 					text-align: center;
@@ -414,11 +442,13 @@
 					border-radius: 50%;
 					border: 3rpx solid $uni-text-color-inverse;
 					background-color: #004DC9;
+
 					.iconfont {
 						font-size: 60rpx;
 						color: $uni-text-color-inverse;
 					}
 				}
+
 				.text-box {
 					font-size: 50rpx;
 					font-weight: bold;
@@ -431,6 +461,7 @@
 			// height: 112rpx;
 			height: calc(112rpx + env(safe-area-inset-bottom, 0));
 		}
+
 		.bottom-box {
 			padding: 5rpx 20rpx;
 			background-color: $uni-bg-color-grey;
@@ -442,20 +473,24 @@
 				height: 100rpx;
 				display: flex;
 				align-items: center;
+
 				.menu-item-box {
 					width: calc(100% / 3);
 					text-align: center;
+
 					.iconfont {
 						font-size: 55rpx;
 					}
+
 					.text {
 						font-size: $uni-font-size-2;
 					}
 				}
+
 				.is-active {
 					color: $uni-color-primary;
 				}
 			}
 		}
 	}
-</style>
+</style>

+ 23 - 49
pages/researchReport/reportList/reportList.vue

@@ -12,6 +12,15 @@
 					height="45"></u-tabs>
 			</view>
 		</view>
+		<u-empty
+			mode="data"
+			v-if="list.length === 0"
+			iconSize="120"
+			textSize="58"
+			text="暂无数据"
+			margin-top="50"
+		>
+		</u-empty>
 		<view class="list-box">
 			<view class="list-item-box" v-for="item in list" :key="item.id" @click="onClickReport(item)">
 				<view class="image-box">
@@ -69,7 +78,9 @@
 				</view>
 			</view>
 		</view>
-		<u-loadmore :status="status" margin-top="20" margin-bottom="20" @loadmore="loadmore" />
+		<u-loadmore v-if="list.length !==0 && status !== 'nomore'" 
+		:status="status" margin-top="20" margin-bottom="20" 
+		@loadmore="loadmore" />
 	</view>
 </template>
 
@@ -79,7 +90,7 @@
 		computed
 	} from 'vue'
 	import {
-		onLoad
+		onLoad, onReachBottom
 	} from '@dcloudio/uni-app'
 	import {
 		loadReportList
@@ -129,52 +140,8 @@
 
 	const modelName = ref()
 
-	const list = ref([
-		// {
-	// 		id: 66,
-	// 		imgUrl: "http://www.gzrea.org.cn/upload/news/2025/03/teicvnoekviwelkv214234kk.png",
-	// 		model: "二手住宅市场",
-	// 		price: 0,
-	// 		priceMember: 0,
-	// 		title: "2025年2月从化区二手住宅市场交易简报",
-	// 		type: "月度成交简报",
-	// 		viewMode: "1",
-	// 		viewObject: "4",
-	// 	},
-	// 	{
-	// 		id: 33,
-	// 		imgUrl: "http://www.gzrea.org.cn/upload/news/2025/03/teicvnoekviwelkv214234kk.png",
-	// 		model: "二手住宅市场2",
-	// 		price: 20,
-	// 		priceMember: 30,
-	// 		title: "2025年2月从化区二手住宅市场交易简报2",
-	// 		type: "月度成交简报",
-	// 		viewMode: "2",
-	// 		viewObject: "4",
-	// 	},
-	// 	{
-	// 		id: 663,
-	// 		imgUrl: "http://www.gzrea.org.cn/upload/news/2025/03/teicvnoekviwelkv214234kk.png",
-	// 		model: "二手住宅市场3",
-	// 		price: 10,
-	// 		priceMember: 40,
-	// 		title: "2025年2月从化区二手住宅市场交易简报3",
-	// 		type: "月度成交简报",
-	// 		viewMode: "3",
-	// 		viewObject: "4",
-	// 	},
-	// 	{
-	// 		id: 663,
-	// 		imgUrl: "http://www.gzrea.org.cn/upload/news/2025/03/teicvnoekviwelkv214234kk.png",
-	// 		model: "二手住宅市场3",
-	// 		price: 10,
-	// 		priceMember: 10,
-	// 		title: "2025年2月从化区二手住宅市场交易简报3",
-	// 		type: "月度成交简报",
-	// 		viewMode: "3",
-	// 		viewObject: "4",
-	// 	},
-	])
+	const list = ref([])
+	
 	const listFilter = ref([])
 
 	function onClickReport(report) {
@@ -221,6 +188,9 @@
 	}
 
 	function loadmore() {
+		if(list.value.length === count.value){
+			return
+		}
 		search(searchForm.value.keyword, pageNum.value, model.value, currentType.value);
 	}
 
@@ -228,6 +198,10 @@
 		search(searchForm.value.keyword, 1, model.value, currentType.value);
 	}
 
+	onReachBottom(()=>{
+		loadmore()
+	})
+
 	onLoad((load) => {
 		isMember.value = authStore.userInfo.isMember === '0' ? false : true;
 		if (load.model) {
@@ -251,7 +225,7 @@
 	$image-width: 230rpx;
 
 	.container {
-		height: 100vh;
+		// height: 100vh;
 		width: 100vw;
 		background-color: $uni-text-color-inverse;