课程详情:静态页面+数据对接已完成、底部的分享和客服功能未完成

This commit is contained in:
wangzimeng 2025-07-26 16:27:53 +08:00
parent 01776e495b
commit d939d93686
5 changed files with 589 additions and 6 deletions

View File

@ -134,8 +134,18 @@
"auth": true, "auth": true,
"title": "平台学院" "title": "平台学院"
} }
} },
{
"path": "classesDetail",
"style": {
"navigationBarTitleText": "课程详情"
},
"meta": {
"sync": true,
"title": "课程详情",
"group": "平台学院"
}
}
] ]
}, },
{ {

View File

@ -180,9 +180,9 @@
onLoad((options) => { onLoad((options) => {
console.log('onload', options.id); console.log('onload', options.id);
rentId.value = options.id rentId.value = options.id
if (options.id) { // if (options.id) {
getDetail(); // getDetail();
} // }
}) })
onShow(() => { onShow(() => {

View File

@ -0,0 +1,555 @@
<template>
<s-layout title="课程详情">
<view class="container">
<!-- 顶部视频 -->
<view class="swiper-box" v-if="detailClass.status == 2">
<view class="swiper_s">
<!-- 视频播放器 :poster="currentVideo.image"-->
<video
id="mainVideo"
:src="detailClass.video_file"
:controls="true"
:autoplay="false"
:loop="false"
:muted="false"
:show-center-play-btn="true"
:enable-play-gesture="true"
:playsinline="false"
style="width: 100%; height: 400rpx;"
@play="handlePlay"
@pause="handlePause"
@ended="handleEnded"
@error="handleError"
></video>
</view>
</view>
<!-- 招租基本信息 -->
<view class="listItem-contents">
<view class="title2" style="margin-bottom: 20rpx;">{{detailClass.title}}</view>
<view class="cons-third">
<view class="title5" style="">发布时间 {{detailClass.release_time_text}}</view>
<view style="display: flex;">
<image style="width: 26rpx;height: 20rpx;" src="https://jiangxiaoxian.0rui.cn/eye.png"></image>
<view class="title3" style="margin-left: 10rpx;">{{detailClass.views}}</view>
</view>
</view>
</view>
<view class="description">
<view class="desTi">
<view style="width: 6rpx;height: 36rpx;background-color: #fcc74e;margin-right: 20rpx;"></view>
<view class="cs bold" style="font-size: 36rpx;line-height: 38rpx;">课程介绍</view>
</view>
<view class="desCon">
<rich-text :nodes="detailClass.content"></rich-text>
</view>
<!-- {{detailClass.content}} -->
</view>
<view style="width: 100%;height: 180rpx;"></view>
<!-- 底部按钮 -->
<view class="footer-box">
<view class="icon-box flex ml40">
<view @click="backHome">
<image class="btnIcon" src="https://jiangxiaoxian.0rui.cn/backHome.png" mode=""></image>
<view class="btnText" style="margin-top: 10rpx;">首页</view>
</view>
<view style="margin-left: 40rpx;" @click="showShareModal">
<image class="btnIcon" src="https://jiangxiaoxian.0rui.cn/rentShare.png" mode=""></image>
<view class="btnText" style="margin-top: 10rpx;">分享</view>
</view>
<view style="margin-left: 40rpx;" @click="toPage('/pages/chat/index')">
<image class="btnIcon" src="https://jiangxiaoxian.0rui.cn/service.png" mode=""></image>
<view class="btnText" style="margin-top: 10rpx;">客服</view>
</view>
</view>
<view class="button-box" @click="handleColect" v-if="detailClass.is_collect == 0">
<image class="btnIcon" src="https://jiangxiaoxian.0rui.cn/unCollect.png" mode=""></image>
<view style="margin-left: 20rpx;">收藏课程</view>
</view>
<view class="button-box2" @click="handleColect" v-else>
<image class="btnIcon" src="https://jiangxiaoxian.0rui.cn/classColoected.png" mode=""></image>
<view style="margin-left: 20rpx;">已收藏</view>
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import {
computed,
ref,
reactive,
} from 'vue';
import {
onLoad,
onShow,
onPageScroll,
onPullDownRefresh,
onReachBottom
} from '@dcloudio/uni-app';
import {
consignee,
mobile,
address,
region
} from '@/sheep/validate/form';
import rent from '../../sheep/api/rent';
import sheep from '@/sheep';
import {
showShareModal
} from '@/sheep/hooks/useModal';
const classId = ref('');
const detailClass = ref('')
const imagesNum = ref(0);
const currentImgIndex = ref(1)
const showContacted = ref(false)
const showContactNo = ref(false)
onLoad((options) => {
console.log('onload', options.id);
classId.value = options.id
// if (options.id) {
// getDetail();
// }
})
onShow(() => {
if (classId.value) {
getDetail();
}
})
async function getDetail() {
const res = await sheep.$api.school.classInfo(classId.value)
console.log('获取课程详情', res);
if (res.code == 1) {
detailClass.value = res.data.detail
detailClass.value.release_time_text = detailClass.value.release_time_text.substring(0, 10);
//
detailClass.value.content = formatRichText(detailClass.value.content);
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}
const newContent = ref('')
//
function formatRichText(html) {
if (!html) return html;
// 1.
newContent.value = html.replace(/<img[^>]*>/gi, function(match) {
if (!/style=/gi.test(match)) {
return match.replace(/<img/, '<img style="max-width:100%;height:auto;display:block;" ');
}
return match;
});
// 2.
newContent.value = newContent.value.replace(/style="[^"]+"/gi, function(match) {
match = match.replace(/width[^;]+;/gi, 'max-width:100%;');
match = match.replace(/height[^;]+;/gi, 'height:auto;');
return match;
});
// 3.
newContent.value = newContent.value.replace(/<table/gi, '<table style="width:100%!important;"');
newContent.value = newContent.value.replace(/<td/gi, '<td style="word-break:break-all;"');
return newContent.value;
}
//
function backHome() {
uni.switchTab({
url: '/pages/index/index'
})
}
//
const toPage = (e) => {
uni.navigateTo({
url: e
})
}
//
function handleColect() {
console.log('收藏', detailClass.value.is_collect);
if (detailClass.value.is_collect == 1) {
detailClass.value.is_collect = 0
uni.showToast({
title: '已取消收藏',
icon: 'none'
})
} else {
detailClass.value.is_collect = 1
uni.showToast({
title: '已收藏',
icon: 'none'
})
}
}
</script>
<style lang="scss" scoped>
.btnIcon {
width: 40rpx;
height: 40rpx;
}
.btnText {
font-size: 20rpx;
font-weight: 400;
line-height: 20rpx;
color: #3d3d3d;
}
.title1 {
font-size: 24rpx;
font-weight: 400;
color: #9c9c9c;
line-height: 26rpx;
}
.title2 {
color: #3d3d3d;
font-size: 30rpx;
font-weight: 800;
line-height: 42rpx;
}
.title3 {
font-size: 24rpx;
font-weight: 400;
color: #999999;
line-height: 26rpx;
}
.title4 {
font-size: 26rpx;
font-weight: 400;
color: #9b9b9b;
line-height: 36rpx;
}
.title5 {
font-size: 26rpx;
font-weight: 400;
color: #9b9b9b;
line-height: 36rpx;
}
.flex {
display: flex;
}
.flex-start {
align-items: flex-start;
}
.justify-center {
justify-content: center;
}
.align-items {
align-items: center;
}
.flex-column {
flex-flow: column;
}
.fs24 {
font-size: 24rpx;
}
.Regular {
font-weight: 400;
}
.bold {
font-weight: bold;
}
.c3 {
color: #333333;
}
.c9 {
color: #999999;
}
.container {
width: 100%;
.swiper-box {
width: 100%;
// padding: 0 30rpx;
// display: grid;
// justify-content: center;
height: 421rpx;
position: relative;
.swiper_s {
width: 100%;
height: 100%;
// display: grid;
// justify-content: center;
.bannerNum {
z-index: 100;
width: 85rpx;
height: 40rpx;
background-color: rgba(0, 0, 0, 0.5);
color: #ffffff;
font-weight: 400;
font-size: 26rpx;
line-height: 20rpx;
border-radius: 30rpx;
position: relative;
left: 628rpx;
bottom: 64rpx;
display: flex;
justify-content: center;
align-items: center;
}
.swiper-image {
width: 100%;
height: 100%;
// border-radius: 36rpx;
object-fit: contain;
}
}
}
.listItem-contents {
background-color: #ffffff;
padding: 30rpx;
// margin-left: 20rpx;
// padding: 30rpx;
.score-box {
display: flex;
.cate {
display: flex;
justify-content: flex-start;
align-items: center;
.cate-e {
.status-tag {
padding: 5rpx 15rpx;
border-radius: 5rpx;
font-size: 22rpx;
font-weight: 400;
line-height: 22rpx;
background-color: rgba(247, 97, 0, 0.2);
// opacity: 0.2;
color: #F76100;
//flex-shrink: 0
}
}
}
}
.cons-third {
margin-top: 20rpx;
// padding: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.phoneNumBox {
margin-top: 10rpx;
background-color: #ffffff;
padding: 40rpx 30rpx;
.line-row {
width: 100%;
height: 1rpx;
background: #F0F0F0;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
}
.description {
background-color: #ffffff;
padding: 40rpx 30rpx;
margin-top: 10rpx;
.desTi {
display: flex;
justify-content: flex-start;
align-items: center;
}
.desCon {
width: 100%;
margin-top: 30rpx;
color: #3d3d3d;
font-weight: 400;
line-height: 42rpx;
font-size: 28rpx;
overflow: hidden;
word-wrap: break-word;
word-break: break-all;
/* 处理表格 */
table {
width: 100% !important;
border-collapse: collapse;
}
img {
max-width: 100% !important;
height: auto !important;
display: block;
}
}
}
.footer-box {
width: 100%;
height: 98rpx;
padding-bottom: 0rpx;
box-sizing: border-box;
position: fixed;
bottom: 0;
display: flex;
align-items: center;
justify-content: space-between;
// box-shadow: 0 -4rpx 6rpx 6rpx #f6f6f6;
background-color: #fff;
// padding-left: 30rpx;
.icon-box {
width: 36%;
height: 98rpx;
display: flex;
justify-content: space-around;
align-items: center;
padding: 14rpx 30rpx;
}
.button-box {
background-color: #fcc74e;
color: #333333;
width: 64%;
height: 98rpx;
display: flex;
align-items: center;
justify-content: center;
}
.button-box2 {
background-color: #999999;
color: #ffffff;
width: 64%;
height: 98rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.popupContacted {
width: 660rpx;
height: 477rpx;
background-color: #fff;
display: grid;
border-radius: 18rpx;
.contactedBox {
width: 660rpx;
height: 325rpx;
padding: 30rpx 0;
// margin-top: 40rpx;
display: grid;
justify-content: center;
align-items: center;
}
.contactBtn {
width: 660rpx;
height: 92rpx;
border-top: 1rpx solid #eeeeee;
display: flex;
border-radius: 0 0 18rpx 18rpx;
// margin-top: 40rpx;
.tactBtnBox {
width: 330rpx;
height: 92rpx;
border-right: 1rpx solid #eeeeee;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.popupContactNo {
width: 660rpx;
height: 477rpx;
background-color: #fff;
display: grid;
border-radius: 18rpx;
.contactNoBox {
width: 660rpx;
height: 325rpx;
padding: 30rpx 0;
display: grid;
justify-content: center;
align-items: center;
}
.contactBtn {
width: 660rpx;
height: 92rpx;
border-top: 1rpx solid #eeeeee;
display: flex;
border-radius: 0 0 18rpx 18rpx;
.tactBtnBox {
width: 330rpx;
height: 92rpx;
border-right: 1rpx solid #eeeeee;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>

View File

@ -24,7 +24,7 @@
@refresherrefresh="onS" scroll-y="true" class="flex align-items" @refresherrefresh="onS" scroll-y="true" class="flex align-items"
style="height: 1250rpx;box-sizing: border-box;"> style="height: 1250rpx;box-sizing: border-box;">
<view class="couponsList"> <view class="couponsList">
<view class="list-item" v-for="(item,index) in classesList" :key="index"> <view class="list-item" v-for="(item,index) in classesList" :key="index" @click="toDetail(item)">
<image style="width: 100%;height: 200rpx;border-radius: 30rpx 30rpx 0 0;" :src="item.image"> <image style="width: 100%;height: 200rpx;border-radius: 30rpx 30rpx 0 0;" :src="item.image">
</image> </image>
<image v-if="item.status == 1" style="width: 77rpx;height: 36rpx;z-index: 100;position: relative;bottom: 190rpx;left: 20rpx;" <image v-if="item.status == 1" style="width: 77rpx;height: 36rpx;z-index: 100;position: relative;bottom: 190rpx;left: 20rpx;"
@ -146,6 +146,15 @@
classesList.value = []; classesList.value = [];
// loadStatus.value = "loading"; // loadStatus.value = "loading";
} }
function toDetail(e){
console.log('跳转详情',e);
uni.navigateTo({
url:'/pages/school/classesDetail?id=' + e.id
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -11,6 +11,15 @@ export default {
showLoading: false, showLoading: false,
}, },
}), }),
//课程详情
classInfo: (id) =>
request({
url: 'meal.classes/detail',
method: 'GET',
params: {
id: id,
},
}),
// detail: (id, user_coupon_id) => // detail: (id, user_coupon_id) =>
// request({ // request({
// url: 'coupon/detail', // url: 'coupon/detail',