Procházet zdrojové kódy

Signed-off-by: 李妹妹 <1639016684@qq.com>

李妹妹 před 15 hodinami
rodič
revize
20af39074e

+ 12 - 5
api/class.js

@@ -39,15 +39,22 @@ export function courseList() {
  export function addCommentt(data) {
  	 return request('/publicApp/store/app/course/comment/addComment',data,'POST','application/json;charset=UTF-8');
  }
- //答题状态
+ /** 答题状态(status:1未答题 2可答题 3已达上限 4已完成) */
  export function courseAnswerStatus(data) {
  	 return request('/publicApp/app/course/publicCourseAnswer/status',data,'GET');
  }
- //答题
+ //答题提交
  export function courseAnswer(data) {
  	 return request('/publicApp/app/course/publicCourseAnswer',data,'POST','application/json;charset=UTF-8');
  }
- //答题奖励
- export function getIntegral(data) {
+ /** 答题奖励领取积分 */
+ export function claimCourseAnswerIntegral(data) {
  	 return request('/publicApp/app/course/publicCourseAnswer/claimIntegral',data,'POST','application/json;charset=UTF-8');
- }
+ }
+ // 流量(缓冲百分比)
+ export function getInternetTraffic(data) {
+ 	return request('/publicApp/app/course/getInternetTraffic', data, 'POST', 'application/json;charset=UTF-8');
+ }
+ 
+ /** @deprecated 使用 claimCourseAnswerIntegral */
+ export const getIntegral = claimCourseAnswerIntegral;

+ 1 - 1
common/request.js

@@ -17,7 +17,7 @@ export default class Request {
 		// let path = 'http://jc5cb469.natappfree.cc/store'; //本地
 		// let path2 = 'http://jc5cb469.natappfree.cc'; //本地
 		let token = uni.getStorageSync('AppToken');
-		console.log('token',token)
+		//console.log('token',token)
 		let type = 0
 		uni.setStorageSync('requestPath', path2)
 		// uni.showLoading({

+ 15 - 14
pages.json

@@ -338,7 +338,7 @@
 				{
 						"path": "course",
 						"style": {
-								"navigationBarTitleText": "课程",
+								"navigationBarTitleText": "精品课程",
 								"enablePullDownRefresh": false
 								//"navigationStyle": "custom"
 							}
@@ -1431,27 +1431,28 @@
 		"fontSize": "16px",
 		"iconWidth": "24px",
 		"spacing": "4px",
-		"list": [{
-				"pagePath": "pages/home/newindex",
-				//"pagePath": "pages/home/index",
+		"list": [
+			{
+				//"pagePath": "pages/home/newindex",
+				"pagePath": "pages/home/index",
 				"iconPath": "/static/tabbar/home.png",
 				"selectedIconPath": "/static/tabbar/home_sel.png",
 				"text": "首页"
 			},
-
-			{
-				"pagePath": "pages/healthy/index",
-				//"pagePath": "pages/home/newindex",
-				"iconPath": "/static/tabbar/mall.png",
-				"selectedIconPath": "/static/tabbar/mall_sel.png",
-				"text": "原乡行"
-			},
+             {
+             	"pagePath": "pages/home/newindex",
+             	"iconPath": "/static/tabbar/mall.png",
+             	"selectedIconPath": "/static/tabbar/mall_sel.png",
+             	"text": "商城"
+             },
 			// {
-			// 	"pagePath": "pages/home/newindex",
+			// 	"pagePath": "pages/healthy/index",
+			// 	//"pagePath": "pages/home/newindex",
 			// 	"iconPath": "/static/tabbar/mall.png",
 			// 	"selectedIconPath": "/static/tabbar/mall_sel.png",
-			// 	"text": "商城"
+			// 	"text": "原乡行"
 			// },
+			
 			// {
 			// 	//"pagePath": "pages/shopping/cart",
 			// 	"pagePath": "pages_user/user/storeOrder",

+ 2 - 2
pages/common/launch.vue

@@ -37,8 +37,8 @@
 			},
 			navigatHandler: function() {
 				uni.reLaunch({
-					url: '/pages/home/newindex',
-					//url:"/pages/home/index",
+					//url: '/pages/home/newindex',
+					url:"/pages/home/index",
 					animationType: 'pop-in',
 					animationDuration: 100
 				})

+ 42 - 22
pages/home/index.vue

@@ -61,9 +61,9 @@
 							<text>{{ tag.cateName }}</text>
 						</view>
 					</scroll-view>
-					<view class="x-bc" @click="onWatchLive">
+					<view class="x-bc" @click="onWatchLive(videos)">
 						<view class="fv-thumb">
-							<image class="fv-img" src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/banner.png" mode="aspectFill"></image>
+							<image class="fv-img" :src="videos.imgUrl" mode="aspectFill"></image>
 							<!-- <view class="live-tag">
 								<text class="live-dot"></text>
 								<text>直播中</text>
@@ -175,7 +175,7 @@ export default {
 		},
 		async initPublicVideoData() {
 			try {
-				const res = await listPublicCourseCategory({yxxTag:1, pageNum: 1, pageSize: 10 });
+				const res = await listPublicCourseCategory({homePage:1,yxxTag:1, pageNum: 1, pageSize: 4 });
 				const list = (res && res.data && res.data.list) || [];
 				this.videoTags = list
 				if (this.videoTags.length > 0) {
@@ -191,19 +191,15 @@ export default {
 		},
 		async initPublicCourseData() {
 			try {
-				const res = await listPublicCourseCategory({ pageNum: 1, pageSize: 10 });
+				const res = await listPublicCourseCategory({ homePage:1, pageNum: 1, pageSize: 10 });
 				const list = (res && res.data && res.data.list) || [];
-				this.navList = list.map(item => ({
+				const mapped = list.map(item => ({
 					id: item.cateId,
 					categoryName: item.cateName
 				}));
-				if (this.navList.length > 0) {
-					this.activeId = this.navList[0].id;
-					await this.getPublicCourseList(this.activeId, { reset: true });
-				} else {
-					this.courses = [];
-					this.courseHasMore = false;
-				}
+				this.navList = [{ id:0, categoryName: '精选' }, ...mapped];
+				this.activeId = 0;
+				await this.getPublicCourseList(this.activeId, { reset: true });
 			} catch (e) {
 				this.navList = [];
 				this.courses = [];
@@ -235,14 +231,17 @@ export default {
 				this.courses = [];
 			}
 			this.courseLoading = true;
+			const params={
+				recommendSlot:3,
+				yxxTag:0,
+				pageNum: this.coursePageNum,
+				pageSize: this.coursePageSize,
+			}
+			if (subCateId!==0) {
+				params.subCateId = subCateId
+			}
 			try {
-				const res = await listPublicCourse({
-					recommendSlot:3,
-					yxxTag:0,
-					pageNum: this.coursePageNum,
-					pageSize: this.coursePageSize,
-					subCateId: subCateId || null
-				});
+				const res = await listPublicCourse(params);
 				const list = (res && res.data && res.data.list) || [];
 				const mappedList = list.map(item => ({
 					courseId: item.courseId,
@@ -286,7 +285,7 @@ export default {
 			uni.navigateTo({ url: '/pages_index/courseSearch' })
 		},
 		onBannerClick() {
-			uni.navigateTo({ url: '/pages_index/course' })
+			//uni.navigateTo({ url: '/pages_index/course' })
 		},
 		onMoreVideos() {
 			uni.navigateTo({ url: '/pages_index/video' })
@@ -454,7 +453,7 @@ export default {
 	display: flex;
 	align-items: center;
 	justify-content: space-between;
-	margin-bottom: 24rpx;
+	margin-bottom: 28rpx;
 }
 .section-title {
 	width: 226rpx;
@@ -481,10 +480,13 @@ export default {
 /* 横向标签 */
 .tag-scroll {
 	white-space: nowrap;
-	margin-bottom: 20rpx;
+	margin-bottom: 5rpx;
+	height: 80rpx;
 }
 .tag-item {
+	position: relative;
 	display: inline-block;
+	/* 底部预留空间,避免伪元素三角被 scroll-view / 父级 overflow 裁切 */
 	padding: 6rpx 24rpx;
 	margin-right: 24rpx;
 	border-radius: 10rpx;
@@ -499,6 +501,19 @@ export default {
 .tag-item.active {
 	background: linear-gradient( 135deg, #FF5267 0%, #FF233C 100%);
 }
+.tag-item.active::after {
+	content: '';
+	position: absolute;
+	left: 50%;
+	bottom: -13rpx;
+	z-index: 10;
+	width: 0;
+	height: 0;
+	transform: translateX(-50%);
+	border-left: 18rpx solid transparent;
+	border-right: 18rpx solid transparent;
+	border-top: 14rpx solid #FF233C;
+}
 .tag-item.active text {
 	color: #fff;
 }
@@ -570,6 +585,11 @@ export default {
 	text-align:center;
 	font-style: normal;
 	margin-bottom: 8rpx;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 1;
+	-webkit-box-orient: vertical;
 }
 .fv-desc {
 	font-family: PingFangSC, PingFang SC;

+ 8 - 8
pages/shopping/confirmOrder.vue

@@ -411,14 +411,14 @@
 									})
 								}, 200);
 							} else {
-								try {
-									const urlInfo = uni.getStorageSync('urlInfo') || {};
-									if (urlInfo.videoId) {
-										uni.setStorageSync('videovip_myPurchase_' + urlInfo.videoId, {
-											ts: Date.now()
-										});
-									}
-								} catch (e) {}
+								// try {
+								// 	const urlInfo = uni.getStorageSync('urlInfo') || {};
+								// 	if (urlInfo.videoId) {
+								// 		uni.setStorageSync('videovip_myPurchase_' + urlInfo.videoId, {
+								// 			ts: Date.now()
+								// 		});
+								// 	}
+								// } catch (e) {}
 								setTimeout(function() {
 									uni.redirectTo({
 										url: './paymentOrder?orderId=' + res.order.id

+ 3 - 3
pages_course/components/goodsList.vue

@@ -54,10 +54,10 @@
 		},
 		methods: {
 			goBuy(item) {
-				let data = uni.getStorageSync('H5course')
+				//let data = uni.getStorageSync('urlInfo')
 				uni.navigateTo({
-					url: '/pages/shopping/productDetails?productId='+item.productId+'&companyId='+data.companyId+ '&companyUserId='+data.companyUserId+'&courseId='+data.courseId+'&videoId='+data.videoId
-					+'&projectId='+data.projectId+'&periodId='+data.periodId
+					url: '/pages/shopping/productDetails?productId='+item.productId+'&companyId='+this.urlOption.companyId+ '&companyUserId='+this.urlOption.companyUserId+'&courseId='+this.urlOption.courseId+'&videoId='+this.urlOption.videoId
+					+'&projectId='+(this.urlOption.projectId || '')+'&periodId='+ (this.urlOption.periodId || '')
 				})
 			},
 			goBuy2(item) {

+ 211 - 70
pages_course/videovip.vue

@@ -15,7 +15,7 @@
 				</view>
 			</view>
 		</view>
-		<view class="video-box" :style="{'height':isShu?'calc(100vh - 264rpx)':'420rpx'}">
+		<view class="video-box" :style="{'height':isShu?'calc(100vh - 264rpx)':'420rpx'}" >
 			<image v-if="!isLogin || isAddKf!=1" class="video-poster" :src="courseInfo.imgUrl" mode="aspectFill">
 			</image>
 			<video @timeupdate="onTimeUpdate" @progress="progressChange" @error="videoErrorCallback" @play="getPlay"
@@ -36,7 +36,7 @@
 						</cover-view>
 					</cover-view>
 					<!-- 虚拟下单跑马灯:视频顶层覆盖,向上滚动淡出切换 -->
-					<cover-view class="vip-order-cover-wrap vip-order-cover-wrap--triple" v-if="fakeMarqueeEligible && isTripleMarqueeMode && marqueeTriplePayloads.length">
+					<cover-view class="vip-order-cover-wrap vip-order-cover-wrap--triple" v-if="showFakeMarqueeOnVideoCover && isTripleMarqueeMode && marqueeTriplePayloads.length">
 						<cover-view class="vip-order-cover-triple-panel vip-order-cover-triple-current" :class="[marqueeTripleSwitching ? 'vip-order-triple-leave' : '']">
 							<cover-view
 								class="vip-order-cover-item vip-order-cover-triple-item"
@@ -46,8 +46,8 @@
 							>
 								<cover-view class="vip-order-cover-content" v-if="row.type === 'virtual' || row.type === 'self'">
 									<cover-view class="vip-order-seg vip-order-seg-user">{{ row.nickname }}{{ row.maskedId }}</cover-view>
-									<cover-view class="vip-order-seg vip-order-seg-time">{{ row.timeOffset }}</cover-view>
-									<cover-view class="vip-order-seg vip-order-seg-suffix">{{ row.suffix }}</cover-view>
+									<cover-view class="vip-order-seg vip-order-seg-time">{{ row.timeOffset }}{{ row.suffix }}</cover-view>
+									<!-- <cover-view class="vip-order-seg vip-order-seg-suffix"></cover-view> -->
 								</cover-view>
 								<cover-view class="vip-order-cover-content" v-else>
 									{{ row.fullText }}
@@ -63,8 +63,8 @@
 							>
 								<cover-view class="vip-order-cover-content" v-if="row.type === 'virtual' || row.type === 'self'">
 									<cover-view class="vip-order-seg vip-order-seg-user">{{ row.nickname }}{{ row.maskedId }}</cover-view>
-									<cover-view class="vip-order-seg vip-order-seg-time">{{ row.timeOffset }}</cover-view>
-									<cover-view class="vip-order-seg vip-order-seg-suffix">{{ row.suffix }}</cover-view>
+									<cover-view class="vip-order-seg vip-order-seg-time">{{ row.timeOffset }}{{ row.suffix }}</cover-view>
+									<!-- <cover-view class="vip-order-seg vip-order-seg-suffix"></cover-view> -->
 								</cover-view>
 								<cover-view class="vip-order-cover-content" v-else>
 									{{ row.fullText }}
@@ -72,8 +72,7 @@
 							</cover-view>
 						</cover-view>
 					</cover-view>
-					</cover-view>
-					<cover-view class="vip-order-cover-wrap" v-else-if="fakeMarqueeEligible && marqueeDisplayPayload">
+					<cover-view class="vip-order-cover-wrap" v-else-if="showFakeMarqueeOnVideoCover && marqueeDisplayPayload">
 						<cover-view
 							class="vip-order-cover-item vip-order-cover-current"
 							:class="[
@@ -83,8 +82,8 @@
 						>
 							<cover-view class="vip-order-cover-content" v-if="marqueeDisplayPayload.type === 'virtual' || marqueeDisplayPayload.type === 'self'">
 								<cover-view class="vip-order-seg vip-order-seg-user">{{ marqueeDisplayPayload.nickname }}{{ marqueeDisplayPayload.maskedId }}</cover-view>
-								<cover-view class="vip-order-seg vip-order-seg-time">{{ marqueeDisplayPayload.timeOffset }}</cover-view>
-								<cover-view class="vip-order-seg vip-order-seg-suffix">{{ marqueeDisplayPayload.suffix }}</cover-view>
+								<cover-view class="vip-order-seg vip-order-seg-time">{{ marqueeDisplayPayload.timeOffset }}{{ marqueeDisplayPayload.suffix }}</cover-view>
+								<!-- <cover-view class="vip-order-seg vip-order-seg-suffix"></cover-view> -->
 							</cover-view>
 							<cover-view class="vip-order-cover-content" v-else>
 								{{ marqueeDisplayPayload.fullText }}
@@ -100,8 +99,8 @@
 						>
 							<cover-view class="vip-order-cover-content" v-if="marqueeIncomingPayload.type === 'virtual' || marqueeIncomingPayload.type === 'self'">
 								<cover-view class="vip-order-seg vip-order-seg-user">{{ marqueeIncomingPayload.nickname }}{{ marqueeIncomingPayload.maskedId }}</cover-view>
-								<cover-view class="vip-order-seg vip-order-seg-time">{{ marqueeIncomingPayload.timeOffset }}</cover-view>
-								<cover-view class="vip-order-seg vip-order-seg-suffix">{{ marqueeIncomingPayload.suffix }}</cover-view>
+								<cover-view class="vip-order-seg vip-order-seg-time">{{ marqueeIncomingPayload.timeOffset }}{{ marqueeIncomingPayload.suffix }}</cover-view>
+								<!-- <cover-view class="vip-order-seg vip-order-seg-suffix"></cover-view> -->
 							</cover-view>
 							<cover-view class="vip-order-cover-content" v-else>
 								{{ marqueeIncomingPayload.fullText }}
@@ -702,6 +701,8 @@
 				hasReportedAfterCountdown: false,
 				notice:'',//跑马灯,
 				isHeight:false,
+				// 跑马灯数据就绪门禁:避免首次进入时使用旧状态导致闪现
+				marqueeDataReady: false,
 				// 虚拟下单跑马灯
 				fakeOrderPool: [],
 				marqueeTriplePayloads: [],
@@ -716,9 +717,14 @@
 				marqueeSwitching: false,
 				pendingSelfMarqueeFirst: false,
 				_fakeMarqueeStarted: false,
+				/** 与 computed fakeMarqueeEligible 上次值比较,避免无 watch 时在 updateProductAndCardDisplay 高频调用中反复重置防抖 */
+				_fakeMarqueeEligiblePrev: undefined,
+				_marqueeStartDebounceTimer: null,
 				_fakeMarqueeTimer: null,
 				_marqueeSwitchTimer: null,
 				_marqueeTripleSwitchTimer: null,
+				/** 本人下单条按缓存 ts 与当前时间差定时回显刷新 */
+				_selfMarqueeClockTimer: null,
 			}
 		},
 		filters: {
@@ -782,26 +788,24 @@
 				return minSec === Infinity ? Infinity : minSec
 			},
 			fakeMarqueeEligible() {
+				// 商品/回放数据未完成刷新前,不允许启动展示,避免首次闪现
+				if (!this.marqueeDataReady) return false
 				if (this.showTreatment !== 0) return false
-				const list = this.treatmentPackage || []
-				if (!list.length) return false
-				const firstSec = this.firstShelfSecondsAmongProducts
-				if (!Number.isFinite(firstSec)) return false
-				const cur = Number(this.playTime) || 0
-				return cur >= firstSec
+				// 以“当前应展示的商品列表非空”作为跑马灯出现条件
+				// 这样能对齐你说的“商品上架才出现”,避免只用最早上架秒点导致的一帧差异
+				return Array.isArray(this.displayProductList) && this.displayProductList.length > 0
+			},
+			// 竖屏课打开小黄车 goodsList 弹窗时先藏住视频上的虚拟下单条,关闭后再显(不影响底层跑马灯计时)
+			showFakeMarqueeOnVideoCover() {
+				if (!this.fakeMarqueeEligible) return false
+				if (this.displayType === 'portrait' && this.isCart) return false
+				return true
 			},
 			isTripleMarqueeMode() {
 				return !!(this.isShu || this.isFull)
 			},
 		},
 		watch: {
-			fakeMarqueeEligible(val) {
-				if (val) {
-					this.$nextTick(() => this.ensureFakeMarqueeStarted())
-				} else {
-					this.stopFakeMarqueeLoop()
-				}
-			},
 			coureLogin: {
 				immediate: true, // 页面一进入就检查一次
 				handler(val) {
@@ -813,6 +817,11 @@
 						this.goLogin()
 					}
 				}
+			},
+			isTripleMarqueeMode(now, was) {
+				if (!now || was) return
+				if (!this.fakeMarqueeEligible || !this._fakeMarqueeStarted) return
+				this.syncTripleMarqueeImmediate()
 			}
 		},
 		onLoad(option) {
@@ -874,6 +883,10 @@
 			// #endif
 		},
 		onShow() {
+			// 每次进入页面先关闭门禁,并清空旧跑马灯状态,等 getH5CourseVideoDetails 拉完数据再开启
+			this.stopFakeMarqueeLoop()
+			this.marqueeDataReady = false
+			this._fakeMarqueeEligiblePrev = undefined
 			this.userinfos = uni.getStorageSync('userinfos')
 			this.userInfo = uni.getStorageSync('userInfo')
 			this.tipsOpen = false
@@ -883,11 +896,6 @@
 			if (this.videoId) {
 				this.getH5CourseByVideo()
 			}
-			this.$nextTick(() => {
-				if (this.fakeMarqueeEligible && !this._fakeMarqueeStarted) {
-					this.ensureFakeMarqueeStarted()
-				}
-			})
 			const AppToken = uni.getStorageSync('TOKEN_WEXIN')
 			console.log(AppToken)
 			if (AppToken) {
@@ -990,20 +998,45 @@
 				if (timeStr === '00:00:00') return false
 				return this._vipTimeStrToSec(timeStr) > 0
 			},
+			/** 缓存下单时间戳(videovip_myPurchase_*)序列化后可能为字符串,统一为毫秒数 */
+			_normalizePurchaseTs(ts) {
+				if (ts == null || ts === '') return 0
+				const n = typeof ts === 'number' ? ts : Number(ts)
+				return Number.isFinite(n) && n > 0 ? n : 0
+			},
+			_readVipSelfPurchaseTsMs() {
+				const row = uni.getStorageSync('videovip_myPurchase_' + this.videoId)
+				return this._normalizePurchaseTs(row && row.ts)
+			},
 			refreshVipPurchaseMarqueeFlag() {
 				const key = 'videovip_myPurchase_' + this.videoId
+				const consumedKey = 'videovip_myPurchaseMarqueeConsumed_' + this.videoId
 				const row = uni.getStorageSync(key)
-				if (row && row.ts && Date.now() - row.ts <= 10 * 60 * 1000) {
-					this.pendingSelfMarqueeFirst = true
+				const consumed = uni.getStorageSync(consumedKey)
+				const tsMs = this._normalizePurchaseTs(row && row.ts)
+				if (tsMs && Date.now() - tsMs <= 10 * 60 * 1000) {
+					// 同一笔下单 ts 仅允许跑马灯展示一次;中途退出再进不再展示(新下单 ts 变化后会再展示一次)
+					const consumedTs = this._normalizePurchaseTs(consumed && consumed.ts)
+					this.pendingSelfMarqueeFirst = !(consumedTs > 0 && consumedTs === tsMs)
 				} else {
 					this.pendingSelfMarqueeFirst = false
-					if (row && row.ts) uni.removeStorageSync(key)
+					if (row && row.ts != null && row.ts !== '') {
+						uni.removeStorageSync(key)
+						const consumedTs = this._normalizePurchaseTs(consumed && consumed.ts)
+						if (consumedTs > 0 && consumedTs === tsMs) uni.removeStorageSync(consumedKey)
+					}
 				}
 			},
+			_markSelfPurchaseMarqueeConsumed() {
+				const tsMs = this._readVipSelfPurchaseTsMs()
+				if (!tsMs) return
+				try {
+					uni.setStorageSync('videovip_myPurchaseMarqueeConsumed_' + this.videoId, { ts: tsMs })
+				} catch (e) {}
+			},
 			formatSelfPurchaseMarqueePayload() {
-				const key = 'videovip_myPurchase_' + this.videoId
-				const row = uni.getStorageSync(key)
-				if (!row || !row.ts) {
+				const tsMs = this._readVipSelfPurchaseTsMs()
+				if (!tsMs) {
 					return {
 						type: 'self',
 						nickname: '您本人',
@@ -1013,7 +1046,7 @@
 						fullText: '您本人刚刚已下单'
 					}
 				}
-				const secTotal = Math.floor((Date.now() - row.ts) / 1000)
+				const secTotal = Math.floor((Date.now() - tsMs) / 1000)
 				if (secTotal < 60) {
 					const text = `${Math.max(1, secTotal)}秒前`
 					return {
@@ -1036,6 +1069,29 @@
 					fullText: `您本人${text}已下单`
 				}
 			},
+			_syncFakeMarqueeIfEligibleChanged() {
+				const val = this.fakeMarqueeEligible
+				if (val === this._fakeMarqueeEligiblePrev) return
+				this._fakeMarqueeEligiblePrev = val
+				if (val) {
+					if (this._marqueeStartDebounceTimer) {
+						clearTimeout(this._marqueeStartDebounceTimer)
+						this._marqueeStartDebounceTimer = null
+					}
+					this._marqueeStartDebounceTimer = setTimeout(() => {
+						this._marqueeStartDebounceTimer = null
+						if (this.fakeMarqueeEligible && !this._fakeMarqueeStarted) {
+							this.ensureFakeMarqueeStarted()
+						}
+					}, 300)
+				} else {
+					if (this._marqueeStartDebounceTimer) {
+						clearTimeout(this._marqueeStartDebounceTimer)
+						this._marqueeStartDebounceTimer = null
+					}
+					this.stopFakeMarqueeLoop()
+				}
+			},
 			ensureFakeMarqueeStarted() {
 				if (!this.fakeMarqueeEligible || this._fakeMarqueeStarted) return
 				this._fakeMarqueeStarted = true
@@ -1044,11 +1100,17 @@
 				}
 				this.applyFakeMarqueeTick()
 				this.scheduleFakeMarqueeNext()
+				this._startSelfMarqueeClockIfNeeded()
 			},
 			applyFakeMarqueeTick() {
 				if (this.isTripleMarqueeMode) {
 					const rows = this.buildTripleMarqueePayloads()
 					this.setTripleMarqueeDisplayWithAnim(rows)
+					// 本人下单在三联模式也只展示一轮,下一轮起恢复纯虚拟随机
+					if (rows.some(item => item && item.type === 'self')) {
+						this.pendingSelfMarqueeFirst = false
+						this._markSelfPurchaseMarqueeConsumed()
+					}
 					if (rows.length) {
 						this.marqueeDisplayPayload = rows[0]
 						this.marqueeDisplaySelf = this.marqueeDisplayPayload.type === 'self'
@@ -1058,14 +1120,14 @@
 				this.marqueeTriplePayloads = []
 				this.marqueeTripleIncomingPayloads = []
 				this.marqueeTripleSwitching = false
-				const key = 'videovip_myPurchase_' + this.videoId
-				const row = uni.getStorageSync(key)
-				const purchaseOk = row && row.ts && Date.now() - row.ts <= 10 * 60 * 1000
+				const tsMs = this._readVipSelfPurchaseTsMs()
+				const purchaseOk = !!(tsMs && Date.now() - tsMs <= 10 * 60 * 1000)
 				if (purchaseOk && this.pendingSelfMarqueeFirst) {
 					const selfPayload = this.formatSelfPurchaseMarqueePayload()
 					this.marqueeCurrentText = selfPayload.fullText
 					this.marqueeSelfHighlight = true
 					this.pendingSelfMarqueeFirst = false
+					this._markSelfPurchaseMarqueeConsumed()
 					this.setMarqueeDisplayWithAnim(selfPayload, true)
 					return
 				}
@@ -1088,14 +1150,18 @@
 			},
 			buildTripleMarqueePayloads() {
 				const rows = []
-				const hasSelf = this.hasRecentSelfPurchase()
+				const hasSelf = this.hasRecentSelfPurchase() && this.pendingSelfMarqueeFirst
 				if (!this.fakeOrderPool.length) {
 					this.fakeOrderPool = buildFakeOrderPool()
 				}
 				let guard = 0
-				// 有本人记录时,先补足前两条虚拟数据,最后一条固定放本人下单
+				// 有本人记录时,把本人下单放第一条,其它再补足虚拟数据
+				if (hasSelf) {
+					rows.push(this.formatSelfPurchaseMarqueePayload())
+				}
 				const targetVirtualCount = hasSelf ? 2 : 3
-				while (rows.length < targetVirtualCount && this.fakeOrderPool.length && guard < 10) {
+				let virtualCount = 0
+				while (virtualCount < targetVirtualCount && this.fakeOrderPool.length && guard < 10) {
 					const line = this.fakeOrderPool.shift()
 					guard += 1
 					if (!line) break
@@ -1107,16 +1173,63 @@
 						timeOffset: line.timeOffset,
 						suffix: line.suffix
 					})
-				}
-				if (hasSelf) {
-					rows.push(this.formatSelfPurchaseMarqueePayload())
+					virtualCount += 1
 				}
 				return rows.slice(0, 3)
 			},
 			hasRecentSelfPurchase() {
-				const key = 'videovip_myPurchase_' + this.videoId
-				const row = uni.getStorageSync(key)
-				return !!(row && row.ts && Date.now() - row.ts <= 10 * 60 * 1000)
+				const tsMs = this._readVipSelfPurchaseTsMs()
+				return !!(tsMs && Date.now() - tsMs <= 10 * 60 * 1000)
+			},
+			/** 按缓存 ts 与当前时间重新计算本人下单文案(停留同一轮跑马灯时也能更新相对时间) */
+			refreshSelfPurchaseMarqueeDisplayedTiming() {
+				const fresh = this.formatSelfPurchaseMarqueePayload()
+				if (this.isTripleMarqueeMode && this.marqueeTriplePayloads.length) {
+					const upd = (arr) =>
+						arr.map((r) => (r && r.type === 'self' ? Object.assign({}, fresh) : r))
+					this.marqueeTriplePayloads = upd(this.marqueeTriplePayloads)
+					if (this.marqueeTripleIncomingPayloads.length) {
+						this.marqueeTripleIncomingPayloads = upd(this.marqueeTripleIncomingPayloads)
+					}
+				}
+				if (this.marqueeDisplayPayload && this.marqueeDisplayPayload.type === 'self') {
+					this.marqueeDisplayPayload = Object.assign({}, fresh)
+				}
+				if (this.marqueeIncomingPayload && this.marqueeIncomingPayload.type === 'self') {
+					this.marqueeIncomingPayload = Object.assign({}, fresh)
+				}
+			},
+			_startSelfMarqueeClockIfNeeded() {
+				if (this._selfMarqueeClockTimer != null) return
+				if (!this.hasRecentSelfPurchase()) return
+				this._selfMarqueeClockTimer = setInterval(() => {
+					if (!this._fakeMarqueeStarted || !this.hasRecentSelfPurchase()) {
+						this._stopSelfMarqueeClock()
+						return
+					}
+					this.refreshSelfPurchaseMarqueeDisplayedTiming()
+				}, 10000)
+			},
+			_stopSelfMarqueeClock() {
+				if (this._selfMarqueeClockTimer != null) {
+					clearInterval(this._selfMarqueeClockTimer)
+					this._selfMarqueeClockTimer = null
+				}
+			},
+			/** 进入三联布局时立即补足 marqueeTriplePayloads,否则 v-if 会因 length 为 0 仍走单条分支直到下一轮定时 tick */
+			syncTripleMarqueeImmediate() {
+				if (!this.fakeMarqueeEligible || !this._fakeMarqueeStarted || !this.isTripleMarqueeMode) return
+				const rows = this.buildTripleMarqueePayloads()
+				if (!rows.length) return
+				this.setTripleMarqueeDisplayWithAnim(rows)
+				if (rows.some(item => item && item.type === 'self')) {
+					this.pendingSelfMarqueeFirst = false
+					this._markSelfPurchaseMarqueeConsumed()
+				}
+				if (rows[0]) {
+					this.marqueeDisplayPayload = rows[0]
+					this.marqueeDisplaySelf = rows[0].type === 'self'
+				}
 			},
 			setTripleMarqueeDisplayWithAnim(rows) {
 				if (!rows || !rows.length) return
@@ -1179,6 +1292,10 @@
 				}, delay)
 			},
 			stopFakeMarqueeLoop() {
+				if (this._marqueeStartDebounceTimer) {
+					clearTimeout(this._marqueeStartDebounceTimer)
+					this._marqueeStartDebounceTimer = null
+				}
 				if (this._fakeMarqueeTimer) {
 					clearTimeout(this._fakeMarqueeTimer)
 					this._fakeMarqueeTimer = null
@@ -1193,11 +1310,17 @@
 				}
 				this._fakeMarqueeStarted = false
 				this.marqueeSwitching = false
+				// 重要:清空非三联跑马灯展示 payload,避免下一次门禁打开前渲染旧内容
+				this.marqueeDisplayPayload = null
+				this.marqueeDisplaySelf = false
+				this.marqueeCurrentText = ''
+				this.marqueeSelfHighlight = false
 				this.marqueeIncomingPayload = null
 				this.marqueeIncomingSelf = false
 				this.marqueeTriplePayloads = []
 				this.marqueeTripleIncomingPayloads = []
 				this.marqueeTripleSwitching = false
+				this._stopSelfMarqueeClock()
 			},
 			goRate(index){
 				this.aindex = index
@@ -1758,6 +1881,7 @@
 					this.displayProductList = []
 					this.cardPopup = false
 					this.currentCardItem = null
+					this._syncFakeMarqueeIfEligibleChanged()
 					return
 				}
 				// 按“上架时间”倒序排序,保证后上架商品展示在列表最前
@@ -1817,6 +1941,7 @@
 				this.cardPopup = !!activeCard && this.dismissedCardKey !== activeCardKey
 				//this.getVideoContainerHeight()
 				this.currentCardItem = activeCard
+				this._syncFakeMarqueeIfEligibleChanged()
 			},
 			closeCardPopup() {
 				if (this.currentCardItem) {
@@ -2051,6 +2176,11 @@
 							this.updateTime();
 							// 初始扫描商品栏展示(根据上架/下架时间)
 							this.updateProductAndCardDisplay(this.playTime ?? this.playDuration ?? 0);
+							// 商品栏扫描完成后再允许虚拟跑马灯启动(延后到下一轮渲染,避免一帧闪现)
+							this.$nextTick(() => {
+								this.marqueeDataReady = true
+								this._syncFakeMarqueeIfEligibleChanged()
+							})
 							if (res.data.courseVideoDetails.questionBankList.length == 0) {
 								this.isquestion = true
 							} else {
@@ -2713,11 +2843,13 @@
 	}
 	.vip-order-cover-wrap {
 		position: fixed;
-		left: 6px;
-		top: 10px;
-		height: 40px;
-		z-index: 99999999;
-		overflow: hidden;
+		left: 10px;
+		bottom:40px;
+		height: 26px;
+		z-index: 999;
+		/* 容器按内容宽度自适应 */
+		display: inline-block;
+		overflow: visible;
 		pointer-events: none;
 		width: 200px;
 	}
@@ -2726,9 +2858,12 @@
 		//width: 240px;
 	}
 	.vip-order-cover-triple-panel {
+		display: flex;
+		align-items: flex-start;
+		flex-direction: column;
 		position: absolute;
 		left: 0;
-		right: 0;
+		right: auto;
 		top: 0;
 	}
 	.vip-order-cover-triple-current {
@@ -2740,24 +2875,27 @@
 	.vip-order-cover-item {
 		position: absolute;
 		left: 0;
-		right: 0;
+		/* 不再撑满整块固定宽度,让背景宽度随内容变化 */
+		right: auto;
 		top: 0;
-		padding: 6px 8px;
-		border-radius: 50px;
-		background: rgba(0, 0, 0, 0.45);
+		display: inline-flex;
+		align-items: center;
+		background: rgba(0,0,0,0.35);
+		border-radius: 26rpx;
 		text-align: center;
 		//border: 1px solid rgba(255, 12, 77, 0.2);
 		font-family: PingFangSC, PingFang SC;
 		font-size: 16px;
-		line-height: 20px;
+		height: 26px;
+		line-height: 26px;
 		color: #fff;
-		font-weight: 500;
+		font-weight: 400;
 		box-sizing: border-box;
 	}
 	.vip-order-cover-triple-item {
 		position: relative;
 		top: auto;
-		margin-bottom: 6px;
+		margin-bottom: 8px;
 	}
 	.vip-order-cover-triple-item:last-child {
 		margin-bottom: 0;
@@ -2797,8 +2935,11 @@
 		align-items: center;
 		flex-wrap: nowrap;
 		white-space: nowrap;
-		overflow: hidden;
-		justify-content: center;
+		overflow: visible;
+		justify-content: flex-start;
+		height: 26px;
+		line-height: 26px;
+		padding:0 8px;
 	}
 	.vip-order-seg {
 		display: inline-block;
@@ -2808,15 +2949,16 @@
 		//font-weight: 600;
 	}
 	.vip-order-seg-time {
-		font-size: 14px;
-		margin-left: 4px;
+		// font-size: 14px;
+		margin-left: 6px;
 	}
 	.vip-order-seg-suffix {
 		color: #fff;
-		margin-left: 2px;
+		// margin-left: 2px;
 	}
 	.vip-order-cover-self {
-		background: rgba(180, 83, 9, 0.45);
+		// width: 180px !important;
+		background: rgba(230,0,26,0.5);
 		// border: 1px solid #FFB020;
 		color: #fff;
 	}
@@ -2826,11 +2968,10 @@
 	}
 	.vip-order-cover-self .vip-order-seg-time {
 		color: #fff;
-		margin-left: 4px;
+		margin-left: 6px;
 	}
 	.vip-order-cover-self .vip-order-seg-suffix {
 		color: #fff;
-		margin-left: 4px;
 	}
 	.vip-order-enter {
 		animation: vip-order-enter-up 0.46s ease-out forwards;

+ 46 - 12
pages_index/course.vue

@@ -61,7 +61,7 @@
 						<view class="x-end" style="justify-content: space-between;">
 							<view class="course-meta">
 								<image src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/renshu.png"></image>
-								<text class="meta-count">{{ course.views }}</text>
+								<text class="meta-count">{{ courseViewsDisplay(course.views) }}</text>
 							</view>
 							<view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
 						</view>
@@ -118,7 +118,7 @@
 							@click="onCourseClick(course)"
 						>
 							<view class="card-cover">
-								<image :src="course.cover || '/static/logo.jpg'" mode="aspectFill" class="cover-img"></image>
+								<image :src="course.imgUrl" mode="aspectFill" class="cover-img"></image>
 							</view>
 							
 							<view class="card-footer">
@@ -126,7 +126,7 @@
 								<view class="x-end" style="justify-content: space-between;">
 									<view class="course-meta">
 										<image src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/renshu.png"></image>
-										<text class="meta-count">{{ course.views }}</text>
+										<text class="meta-count">{{ courseViewsDisplay(course.views) }}</text>
 									</view>
 									<view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
 								</view>
@@ -148,7 +148,7 @@ export default {
 		return {
 			statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
 			tabIndex: 0,
-			categoryExpand: true,
+			categoryExpand: false,
 			categoryIndex: 0,
 			categories: [],
 			categoryRows: [],
@@ -169,23 +169,53 @@ export default {
 				// }
 			],
 			recommendList: [
-				{ title: '刘金的《0基础金曲演唱速练课》', views: '9239', cover: '' },
-				{ title: '邹方斌讲《毛笔书法修心课》', views: '10.8w', cover: '' },
-				{ title: '张斌《元气八段锦》系列课', views: '2.5w', cover: '' },
-				{ title: '翔哥精讲摄影课-手机微距拍摄技巧...', views: '100w+', cover: '' }
+				// { title: '刘金的《0基础金曲演唱速练课》', views: '9239', cover: '' },
+				// { title: '邹方斌讲《毛笔书法修心课》', views: '10.8w', cover: '' },
+				// { title: '张斌《元气八段锦》系列课', views: '2.5w', cover: '' },
+				// { title: '翔哥精讲摄影课-手机微距拍摄技巧...', views: '100w+', cover: '' }
 			]
 		}
 	},
 	onLoad() {
 		// 默认先查一次课程(不带分类参数),再加载分类标签
 		this.initPublicCourseData()
+		this.getNewCourseList()
 	},
 	methods: {
+		courseViewsDisplay(views) {
+			const raw = views;
+			const n = Number(raw);
+			if (!Number.isFinite(n) || n < 0) {
+				return "0";
+			}
+			if (n < 100000) {
+				return String(Math.floor(n));
+			}
+			if (n < 1000000) {
+				return (n / 10000).toFixed(1) + "w";
+			}
+			return "100w+";
+		},
 		async initPublicCourseData() {
           await this.getCategoryList()
 			await this.getCourseList()
 			await this.getCourseStudyList()
 		},
+		async getNewCourseList() {
+			try {
+				const params = { pageNum: 1, pageSize:6 }
+				const res = await listPublicCourse(params)
+				const list = (res && res.data && res.data.list) || []
+				this.recommendList = list.map(item => ({
+					courseId: item.courseId,
+					title: item.courseTitle || item.courseName || '',
+					views: item.watchUserCount || 0,
+					cover: item.imgUrl || ''
+				}))
+			} catch (e) {
+				this.recommendList = []
+			}
+		},
 		async getCategoryList() {
 			try {
 				const res = await listPublicCourseCategory({ pageNum: 1, pageSize: 10 })
@@ -199,7 +229,7 @@ export default {
 		},
 		async getCourseList(subCateId) {
 			try {
-				const params = { pageNum: 1, pageSize: 10 }
+				const params = {yxxTag:0, pageNum: 1, pageSize: 10 }
 				if (subCateId) {
 					params.subCateId = subCateId
 				}
@@ -217,7 +247,7 @@ export default {
 		},
 		async getCourseStudyList() {
 			try {
-				const params = { pageNum: 1, pageSize: 10 }
+				const params = { courseType:0,pageNum: 1, pageSize: 10 }
 				const res = await getCourseStudyList(params)
 				const list = (res && res.data && res.data.list) || []
 				this.recentList = list
@@ -236,7 +266,6 @@ export default {
 				uni.navigateTo({ url: '/pages_index/courseDetail?courseId=' + course.courseId + '&type=1' })
 				return
 			}
-			uni.showToast({ title: course.title || '立即观看', icon: 'none' })
 		}
 	}
 }
@@ -328,7 +357,7 @@ export default {
 	justify-content: flex-start;
 }
 .category-tags.collapsed {
-	max-height: 88rpx;
+	max-height: 336rpx;
 	overflow: hidden;
 }
 .tag-item {
@@ -343,6 +372,11 @@ export default {
 	font-weight: 400;
 	font-size: 40rpx;
 	color: rgba(0,0,0,0.85);
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 1;
+	-webkit-box-orient: vertical;
 }
 .tag-item.active {
 	background: linear-gradient( 135deg, #FF5267 0%, #FF233C 100%);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 538 - 137
pages_index/courseDetail.vue


+ 62 - 29
pages_index/courseSearch.vue

@@ -5,13 +5,12 @@
 			    <view class="search-cont">
 			    	<view class="inner">
 			    		<image class="icon-search" src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/search.png" mode=""></image>
-			    		<input type="text" v-model="keyword" placeholder="请输入关键字搜索内容" placeholder-style="font-size:28rpx;color:#BBBBBB;font-family: PingFang SC;"  @input="clearInput"/>
-			    	</view>
+			    		<input type="text" v-model="keyword" @input="clearInput" placeholder="请输入关键字搜索内容" placeholder-style="font-size:28rpx;color:#BBBBBB;"/>
+						 <view class="close-circle" v-if="showClearIcon"  @click="clearIcon">
+							 <u-icon name="close-circle" color="#999" size="22" ></u-icon>
+						 </view>
+					</view>
 					<view class="sousuo" @click="goSearch">搜索</view>
-			    	<!-- <view class="icon-search">
-			    		<image @click="showChange(2)" v-if="showType==1"  src="https://jnlzjk-1323137866.cos.ap-chongqing.myqcloud.com/shop/images/search1.png" mode=""></image>
-			    		<image @click="showChange(1)" v-if="showType==2"  src="https://jnlzjk-1323137866.cos.ap-chongqing.myqcloud.com/shop/images/search2.png" mode=""></image>
-			    	</view> -->
 			    </view>
 				<!-- <view class="nav-row">
 					<view class="nav-all" :class="{ active: activeId === 'all'}" @tap.stop="onSelectAll" @click.stop="onSelectAll">
@@ -35,7 +34,7 @@
 		<!-- 最近学习 内容 -->
 		<scroll-view scroll-y class="scroll-wrap" :show-scrollbar="false">
 			<!-- 有学习记录:按日期分组列表 -->
-			<template v-if="keyword">
+			<template v-if="isSearch">
 				<view class="course-grid">
 					<view
 						v-for="(course, idx) in courseList"
@@ -51,7 +50,7 @@
 							<view class="x-end" style="justify-content: space-between;">
 								<view class="course-meta">
 									<image src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/renshu.png"></image>
-									<text class="meta-count">{{ course.views }}</text>
+									<text class="meta-count">{{ courseViewsDisplay(course.views)}}</text>
 								</view>
 								<view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
 							</view>
@@ -81,7 +80,7 @@
 								<view class="x-end" style="justify-content: space-between;">
 									<view class="course-meta">
 										<image src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/renshu.png"></image>
-										<text class="meta-count">{{ course.views }}</text>
+										<text class="meta-count">{{ courseViewsDisplay(course.views) }}</text>
 									</view>
 									<view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
 								</view>
@@ -93,7 +92,7 @@
 			<template v-if="keyword&&courseList.length==0">
 				<view class="empty-state">
 					<!-- <view class="empty-icon"></view> -->
-					<image class="empty-icon" src="@/static/images/new/nodata.png"></image>
+					<image class="empty-icon" src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/nodata.png"></image>
 					<text class="empty-text">没有搜索任何内容,换个词试试</text>
 				</view>
 			</template>
@@ -114,27 +113,29 @@ export default {
 			tabIndex: 0,
 			activeId:'all',
 			categoryExpand: true,
+		    isSearch:false,
+			showClearIcon: false,
 			categoryIndex: 0,
 			categories: ['全部', '歌唱艺术', '太极养生', '防骗指南', '手机摄影', '棋牌益智', '用药指导', '膳食营养', '慢病管理'],
 			courseList: [],
 			recentList: [
-				{
-					date: '2026-02-08',
-					list: [
-						{ title: '歌唱家刘金的《0基础金曲演唱速练课》', progress: 87, cover: '' },
-						{ title: '资深编辑邹方斌讲《毛笔书法修心课》', progress: 56, cover: '' }
-					]
-				},
-				{
-					date: '2026-02-01',
-					list: [
-						{ title: '张斌《元气八段锦》系列课', progress: 56, cover: '' }
-					]
-				}
+				// {
+				// 	date: '2026-02-08',
+				// 	list: [
+				// 		{ title: '歌唱家刘金的《0基础金曲演唱速练课》', progress: 87, cover: '' },
+				// 		{ title: '资深编辑邹方斌讲《毛笔书法修心课》', progress: 56, cover: '' }
+				// 	]
+				// },
+				// {
+				// 	date: '2026-02-01',
+				// 	list: [
+				// 		{ title: '张斌《元气八段锦》系列课', progress: 56, cover: '' }
+				// 	]
+				// }
 			],
 			navList:[
-				{id: 37,categoryName: "健康食品"},
-				{id: 35,categoryName: "绿色有机"}
+				// {id: 37,categoryName: "健康食品"},
+				// {id: 35,categoryName: "绿色有机"}
 			],
 			recommendList: [
 				// { title: '刘金的《0基础金曲演唱速练课》', views: '9239', cover: '' },
@@ -150,9 +151,36 @@ export default {
 		this.getNewCourseList()
 	},
 	methods: {
+		courseViewsDisplay(views) {
+			const raw = views;
+			const n = Number(raw);
+			if (!Number.isFinite(n) || n < 0) {
+				return "0";
+			}
+			if (n < 100000) {
+				return String(Math.floor(n));
+			}
+			if (n < 1000000) {
+				return (n / 10000).toFixed(1) + "w";
+			}
+			return "100w+";
+		},
 		onSelectAll() {
 			this.$emit('select', { id: 'all', categoryName: '全部' });
 		},
+		 clearInput: function(event) {
+		            this.keyword = event.detail.value;
+		            if (event.detail.value.length > 0) {
+		                this.showClearIcon = true;
+		            } else {
+		                this.showClearIcon = false;
+		            }
+		        },
+		        clearIcon: function() {
+		            this.keyword = '';
+		            this.showClearIcon = false;
+					this.isSearch=false;
+		        },
 		async getCourseList(keyword) {
 			try {
 				const params = { pageNum: 1, pageSize: 10 }
@@ -173,7 +201,7 @@ export default {
 		},
 		async getNewCourseList() {
 			try {
-				const params = { pageNum: 1, pageSize: 10 }
+				const params = { pageNum: 1, pageSize: 6 }
 				const res = await listPublicCourse(params)
 				const list = (res && res.data && res.data.list) || []
 				this.recommendList = list.map(item => ({
@@ -187,6 +215,7 @@ export default {
 			}
 		},
 		goSearch() {
+			 this.isSearch=!this.isSearch
 			 if (!this.keyword.trim()) {
 			        uni.showToast({
 			          icon: 'none',
@@ -198,10 +227,9 @@ export default {
 		},
 		onCourseClick(course) {
 			if (course && course.courseId) {
-				uni.navigateTo({ url: '/pages_course/learn?courseId=' + course.courseId + '&type=1' })
+				uni.navigateTo({ url: '/pages_index/courseDetail?courseId=' + course.courseId + '&type=1' })
 				return
 			}
-			uni.showToast({ title: course.title || '立即观看', icon: 'none' })
 		}
 	}
 }
@@ -241,7 +269,7 @@ export default {
 			border-radius: 38rpx;
 			display: flex;
 			align-items: center;
-			padding: 0 20rpx;
+			padding-left:20rpx;
 			margin-right: 24rpx;
 			.icon-search{
 				width: 44rpx;
@@ -256,6 +284,11 @@ export default {
 				font-weight: 400;
 				font-size: 32rpx;
 			}
+			.close-circle{
+				position: relative;
+				z-index:999;
+				padding:0 20rpx;
+			}
 			
 		}
 		.sousuo{

+ 55 - 31
pages_index/video.vue

@@ -16,7 +16,7 @@
 					:class="{ active: tabIndex === 1 }"
 					@click="tabIndex = 1"
 				>
-					<text>最近观看</text>
+					<text>最近学习</text>
 					<view v-if="tabIndex === 1" class="nav-indicator"></view>
 				</view>
 			</view>
@@ -54,18 +54,17 @@
 					@click="onCourseClick(course)"
 				>
 					<view class="card-cover">
-						<image :src="course.cover || '/static/logo.jpg'" mode="aspectFill" class="cover-img"></image>
+						<image :src="course.imgUrl" mode="aspectFill" class="cover-img"></image>
 					</view>
 					<view class="course-info">
-						<text class="card-title">{{ course.title }}</text>
-						<view class="">
+						<text class="card-title">{{ course.courseName }}</text>
+					
 							<view class="course-meta">
-							{{ course.desc || '邀你一起看恩施美景,寻长寿秘密' }}
+							{{ course.courseDesc||'-' }}
 							</view>
 							<view class="y-end">
 								<view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
 							</view>
-						</view>
 					</view>
 					
 				</view>
@@ -89,14 +88,15 @@
 						@click="onCourseClick(item)"
 					>
 						<view class="recent-thumb">
-							<image :src="item.imgUrl || '/static/logo.jpg'" mode="aspectFill" class="thumb-img"></image>
+							<image :src="item.imgUrl" mode="aspectFill" class="thumb-img"></image>
 						</view>
 						<view class="recent-info">
 							<text class="recent-title">{{ item.courseName }}</text>
-							<text class="recent-meta">邀你一起看恩施美景,寻长寿秘密</text>
+							<text class="recent-progress">已学: {{ item.progress }}%</text>
+							<!-- <text class="recent-meta">{{item.courseDesc||'-' }}</text> -->
 							<!-- <text class="recent-meta">邀你一起看恩施美景,寻长寿秘密</text> -->
 							<view class="y-end">
-								<view class="btn-watch" @click.stop="onCourseClick(item)">看</view>
+								<view class="btn-watch" @click.stop="onCourseClick(item)">立即观看</view>
 							</view>
 						</view>
 					</view>
@@ -120,14 +120,14 @@
 							@click="onCourseClick(course)"
 						>
 							<view class="card-cover">
-								<image :src="course.cover || '/static/logo.jpg'" mode="aspectFill" class="cover-img"></image>
+								<image :src="course.cover" mode="aspectFill" class="cover-img"></image>
 							</view>
 							
 							<view class="card-footer">
 								<text class="card-title">{{ course.title }}</text>
 								<view class="y-b">
 									<view class="course-meta">
-									邀你一起看恩施美景,寻长寿秘密
+									{{course.courseDesc||'-' }}
 									</view>
 									<view class="y-end">
 										<view class="btn-watch" @click.stop="onCourseClick(course)">回看</view>
@@ -151,7 +151,7 @@ export default {
 		return {
 			statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
 			tabIndex: 0,
-			categoryExpand: true,
+			categoryExpand: false,
 			categoryIndex: 0,
 			categories: [],
 			activeCateId: null,
@@ -182,6 +182,7 @@ export default {
 	onLoad() {
 		this.initPublicVideoData();
 		this.getCourseStudyList();
+		this.getNewCourseList()
 	},
 	methods: {
 		onSelectCategory(cat, idx) {
@@ -206,15 +207,31 @@ export default {
 				this.courseList = [];
 			}
 		},
+		async getNewCourseList() {
+			try {
+				const params = { pageNum: 1, pageSize: 6 }
+				const res = await listPublicCourse(params)
+				const list = (res && res.data && res.data.list) || []
+				this.recommendList = list.map(item => ({
+					courseId: item.courseId,
+					title: item.courseTitle || item.courseName || '',
+					views: item.watchUserCount || 0,
+					cover: item.imgUrl || ''
+				}))
+			} catch (e) {
+				this.recommendList = []
+			}
+		},
 		async getCourseStudyList(subCateId) {
 			try {
 				const param={
 					pageNum: 1,
-					pageSize: 10
-				}
-				if(subCateId){
-					param.subCateId=subCateId
+					pageSize: 10,
+					courseType:1,
 				}
+				// if(subCateId){
+				// 	param.subCateId=subCateId
+				// }
 				const res = await getCourseStudyList(param);
 				const list = (res && res.data && res.data.list) || [];
 				this.recentList = list
@@ -234,12 +251,7 @@ export default {
 				}
 				const res = await listPublicCourse(param);
 				const list = (res && res.data && res.data.list) || [];
-				this.courseList = list.map(item => ({
-					courseId: item.courseId,
-					title: item.courseName || '',
-					desc: item.courseDesc || '',
-					cover: item.imgUrl || ''
-				}));
+				this.courseList = list
 			} catch (e) {
 				this.courseList = [];
 			}
@@ -249,7 +261,6 @@ export default {
 				uni.navigateTo({ url: '/pages_index/courseDetail?courseId=' + course.courseId + '&type=1' })
 				return;
 			}
-			uni.navigateTo({ url: '/pages_index/courseDetail' })
 		}
 	}
 }
@@ -340,8 +351,9 @@ export default {
 	flex-direction: row;
 	justify-content: flex-start;
 }
+/* 收起时固定展示约三行:单行约 20+56+20 padding+字高+padding,行间 gap 24rpx */
 .category-tags.collapsed {
-	max-height: 88rpx;
+	max-height: 336rpx;
 	overflow: hidden;
 }
 .tag-item {
@@ -351,18 +363,17 @@ export default {
 	border-radius: 20rpx;
 	background: #f0f0f0;
 }
-.tag-item {
-	width: 30%;
-	padding: 20rpx 0;
-	text-align: center;
-	border-radius: 20rpx;
-	background: #f0f0f0;
-}
+
 .tag-item text {
 	font-family: PingFangSC, PingFang SC;
 	font-weight: 400;
 	font-size: 40rpx;
 	color: rgba(0,0,0,0.85);
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 1;
+	-webkit-box-orient: vertical;
 }
 .tag-item.active {
 	background: linear-gradient( 135deg, #FF5267 0%, #FF233C 100%);
@@ -443,6 +454,19 @@ export default {
 	-webkit-line-clamp: 2;
 	-webkit-box-orient: vertical;
 }
+.recent-meta {
+	font-family: PingFangSC, PingFang SC;
+	font-weight: 400;
+	font-size: 32rpx;
+	color: rgba(0,0,0,0.65);
+	line-height: 44rpx;
+	text-align: justify;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 2;
+	-webkit-box-orient: vertical;
+}
 .meta-icon {
 	font-size: 24rpx;
 	margin-right: 6rpx;

+ 6 - 6
pages_user/user/integralGoodsDetails.vue

@@ -2,12 +2,12 @@
 	<view class="content">
 		<view class="cont-box">
 			<view class="goods-banner" @click="showImg()">
-				<view class="cartbox" @click.stop="goCart()">
+				<!-- <view class="cartbox" @click.stop="goCart()">
 					<view class="box">
 						<u-badge type="error" max="99" :value="cartNum" bgColor="#FF233C"></u-badge>
 					</view>
 					<u-icon name="shopping-cart" color="#FF233C" size="68rpx"></u-icon>
-				</view>
+				</view> -->
 				<swiper class="swiper" :indicator-dots="false" :circular="true" :autoplay="true" :interval="3000"
 					:duration="1000" indicator-color="rgba(255, 255, 255, 0.6)" indicator-active-color="#ffffff"
 					@change="swiperChange">
@@ -42,9 +42,9 @@
 						style="font-size: 20rpx;">元</text></view>
 			</view>
 			<view class="btn-box">
-				<view class="btn add" @click="openPop">
+				<!-- <view class="btn add" @click="openPop">
 					加入购物车
-				</view>
+				</view> -->
 				<view class="btn buy" @click="submit()">
 					立即兑换
 				</view>
@@ -73,9 +73,9 @@
 						<u-number-box v-model="num" integer :step="1" :min="1" :max="100000"></u-number-box>
 					</view>
 				</view>
-				<view class="es-max-btn x-c" @click="addCart">
+				<!-- <view class="es-max-btn x-c" @click="addCart">
 					加入购物车
-				</view>
+				</view> -->
 			</view>
 		</u-popup>
 	</view>

+ 1 - 1
pages_user/user/storeOrder.vue

@@ -808,7 +808,7 @@
 								font-weight: bold;
 								color: #FFFFFF;
 								line-height: 30upx;
-								float: left;
+								// float: left;
 								margin-top: 7upx;
 							}
 						}

+ 1 - 1
pages_user/user/storeOrderDetail.vue

@@ -700,7 +700,7 @@
 							font-weight: bold;
 							color: #FFFFFF;
 							line-height: 30upx;
-							float: left;
+							// float: left;
 							margin-top: 7upx;
 						}
 					}

binární
static/images/ai_right_icon.png


Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů