@@ -0,0 +1,908 @@
< template >
< view class = "course-detail-page" >
<!-- 顶部导航 -- >
< MemberInfoSubNav : title = "course.courseName || '课程详情'" @back ="goBack" / >
<!-- 骨架屏 -- >
< view v-if = "loading" class="skeleton" >
< view class = "skeleton-header" >
< view class = "skeleton-cover skeleton-block" > < / view >
< / view >
< view class = "skeleton-content" >
< view class = "skeleton-name skeleton-block" > < / view >
< view class = "skeleton-meta" >
< view class = "skeleton-meta-item skeleton-block" > < / view >
< view class = "skeleton-meta-item skeleton-block" > < / view >
< view class = "skeleton-meta-item skeleton-block" > < / view >
< / view >
< view class = "skeleton-card" >
< view class = "skeleton-card-title skeleton-block" > < / view >
< view class = "skeleton-card-content" >
< view class = "skeleton-text-line skeleton-block" > < / view >
< view class = "skeleton-text-line skeleton-block" > < / view >
< view class = "skeleton-text-line skeleton-block short" > < / view >
< / view >
< / view >
< view class = "skeleton-card" >
< view class = "skeleton-info-row" >
< view class = "skeleton-info-label skeleton-block" > < / view >
< view class = "skeleton-info-value skeleton-block" > < / view >
< / view >
< view class = "skeleton-info-row" >
< view class = "skeleton-info-label skeleton-block" > < / view >
< view class = "skeleton-info-value skeleton-block" > < / view >
< / view >
< view class = "skeleton-info-row" >
< view class = "skeleton-info-label skeleton-block" > < / view >
< view class = "skeleton-info-value skeleton-block" > < / view >
< / view >
< view class = "skeleton-info-row" >
< view class = "skeleton-info-label skeleton-block" > < / view >
< view class = "skeleton-payment" >
< view class = "skeleton-payment-item skeleton-block" > < / view >
< view class = "skeleton-payment-item skeleton-block" > < / view >
< / view >
< / view >
< / view >
< view class = "skeleton-card" >
< view class = "skeleton-card-title skeleton-block" > < / view >
< view class = "skeleton-notice" >
< view class = "skeleton-notice-item skeleton-block" > < / view >
< view class = "skeleton-notice-item skeleton-block" > < / view >
< view class = "skeleton-notice-item skeleton-block" > < / view >
< view class = "skeleton-notice-item skeleton-block" > < / view >
< / view >
< / view >
< / view >
< / view >
<!-- 内容区域 -- >
< view v-else >
< ! - - 顶部图片区域 - - >
< view class = "header-section" >
<!-- 课程封面图 -- >
< view class = "cover-image-wrapper" >
< image
v-if = "course.coverImage"
:src = "course.coverImage"
mode = "aspectFill"
class = "cover-image"
/ >
< view v-else class = "cover-image-placeholder" >
< uni-icons type = "image" size = "80" color = "#CCCCCC" / >
< text class = "placeholder-text" > 暂无封面 < / text >
< / view >
< / view >
< / view >
<!-- 课程基本信息 -- >
< view class = "basic-info-section" >
< view class = "course-name-wrapper" >
< text class = "course-name" > { { course . courseName } } < / text >
<!-- 课程状态标签 -- >
< view : class = "['status-tag', statusClass]" >
{ { statusText } }
< / view >
< view : class = "['course-type-badge', courseTypeClass]" >
{ { courseTypeText } }
< / view >
< / view >
< view class = "course-meta" >
< view class = "meta-item" >
< uni-icons type = "calendar" size = "24" color = "#8A99B4" / >
< text class = "meta-text" > { { formatDate ( course . startTime ) } } < / text >
< / view >
< view class = "meta-item" >
< uni-icons type = "clock" size = "24" color = "#8A99B4" / >
< text class = "meta-text" > { { formatTime ( course . startTime ) } } - { { formatTime ( course . endTime ) } } < / text >
< / view >
< view class = "meta-item" >
< uni-icons type = "map-pin" size = "24" color = "#8A99B4" / >
< text class = "meta-text" > { { course . location } } < / text >
< / view >
< / view >
< / view >
<!-- 课程详情卡片 -- >
< view class = "detail-card" >
< view class = "card-header" >
< uni-icons type = "info" size = "24" color = "#FF6B35" / >
< text class = "card-title" > 课程详情 < / text >
< / view >
< view class = "card-content" >
< text class = "description-text" > { { course . description } } < / text >
< / view >
< / view >
<!-- 课程信息卡片 -- >
< view class = "info-card" >
< view class = "info-row" >
< view class = "info-label" >
< uni-icons type = "users" size = "24" color = "#5E6F8D" / >
< text > 课程容量 < / text >
< / view >
< text class = "info-value" > { { course . currentMembers } } / { { course . maxMembers } } 人 < / text >
< / view >
< view class = "info-row" >
< view class = "info-label" >
< uni-icons type = "time" size = "24" color = "#5E6F8D" / >
< text > 课程时长 < / text >
< / view >
< text class = "info-value" > { { formatDuration ( course . startTime , course . endTime ) } } < / text >
< / view >
< view class = "info-row" >
< view class = "info-label" >
< uni-icons type = "star" size = "24" color = "#5E6F8D" / >
< text > 教练 < / text >
< / view >
< text class = "info-value" > ID : { { course . coachId } } < / text >
< / view >
< view class = "info-row" >
< view class = "info-label" >
< uni-icons type = "credit-card" size = "24" color = "#5E6F8D" / >
< text > 支付方式 < / text >
< / view >
< view class = "payment-options" >
< view
v-if = "course.storedValueAmount > 0"
: class = "['payment-item', { active: selectedPayment === 'storedValue' || (!selectedPayment && course.pointCardAmount === 0) }]"
@click ="selectPayment('storedValue')"
>
< text class = "payment-label" > 储值卡 < / text >
< text class = "payment-value" > ¥ { { course . storedValueAmount } } < / text >
< view v-if = "selectedPayment === 'storedValue' || (!selectedPayment && course.pointCardAmount === 0)" class="payment-check" >
< uni -icons type = "checkmark" size = "20" color = "#ffffff" / >
< / view >
< / view >
< view
v-if = "course.pointCardAmount > 0"
: class = "['payment-item', { active: selectedPayment === 'pointCard' || (!selectedPayment && course.storedValueAmount === 0) }]"
@click ="selectPayment('pointCard')"
>
< text class = "payment-label" > 次卡 < / text >
< text class = "payment-value" > { { course . pointCardAmount } } 次 < / text >
< view v-if = "selectedPayment === 'pointCard' || (!selectedPayment && course.storedValueAmount === 0)" class="payment-check" >
< uni -icons type = "checkmark" size = "20" color = "#ffffff" / >
< / view >
< / view >
< view v-if = "course.storedValueAmount === 0 && course.pointCardAmount === 0" class="payment-item free" >
< text class = "payment-value" > 免费 < / text >
< / view >
< / view >
< / view >
< / view >
<!-- 预约须知 -- >
< view class = "notice-card" >
< view class = "card-header" >
< uni-icons type = "alert-circle" size = "24" color = "#F39C12" / >
< text class = "card-title" > 预约须知 < / text >
< / view >
< view class = "notice-list" >
< view class = "notice-item" >
< text class = "notice-dot" > ● < / text >
< text > 请在课程开始前30分钟到达教室 < / text >
< / view >
< view class = "notice-item" >
< text class = "notice-dot" > ● < / text >
< text > 如需取消预约 , 请提前2小时操作 < / text >
< / view >
< view class = "notice-item" >
< text class = "notice-dot" > ● < / text >
< text > 课程开始后将无法取消预约 < / text >
< / view >
< view class = "notice-item" >
< text class = "notice-dot" > ● < / text >
< text > 迟到超过15分钟将无法入场 < / text >
< / view >
< / view >
< / view >
<!-- 底部操作栏 -- >
< view class = "bottom-bar" >
< view class = "price-display" >
< text v-if = "selectedPrice.type === 'storedValue'" class="price" >
< text class = "currency" > ¥ < / text > { { selectedPrice . amount } }
< / text >
< text v-else-if = "selectedPrice.type === 'pointCard'" class="price points" >
< uni -icons type = "shop" size = "20" color = "#FF6B35" / >
< text > { { selectedPrice . amount } } 次 < / text >
< / text >
< text v-else class = "price free" > 免费 < / text >
< / view >
< view : class = "['booking-btn', { disabled: !canBook }]" @click ="handleBooking" >
< text > { { canBook ? '立即预约' : ( course . currentMembers >= course . maxMembers ? '已满员' : statusText ) } } < / text >
< / view >
< / view >
< / view >
< / view >
< / template >
< script setup >
import { ref , computed , onMounted } from 'vue'
import { groupCourseService } from '@/request_api/groupCourse.mock.js'
import MemberInfoSubNav from '@/components/memberInfo/MemberInfoSubNav.vue'
// 加载状态
const loading = ref ( true )
// 课程详情数据
const course = ref ( {
id : '' ,
courseName : '' ,
courseType : '' ,
startTime : '' ,
endTime : '' ,
maxMembers : 0 ,
currentMembers : 0 ,
status : '' ,
location : '' ,
coverImage : '' ,
description : '' ,
coachId : '' ,
pointCardAmount : 0 ,
storedValueAmount : 0
} )
// 选中的支付方式 ('storedValue' | 'pointCard' | 'free')
const selectedPayment = ref ( '' )
// 课程状态文本
const statusText = computed ( ( ) => {
const status = course . value . status
if ( status === '0' ) return '进行中'
if ( status === '1' ) return '已取消'
if ( status === '2' ) return '已结束'
return '未知'
} )
// 课程状态样式
const statusClass = computed ( ( ) => {
const status = course . value . status
if ( status === '0' ) return 'active'
if ( status === '1' ) return 'canceled'
if ( status === '2' ) return 'ended'
return ''
} )
// 课程类型文本
const courseTypeText = computed ( ( ) => {
const type = course . value . courseType
if ( type === '1' ) return '瑜伽/普拉提'
if ( type === '2' ) return '有氧训练'
if ( type === '3' ) return '力量训练'
return '其他'
} )
// 课程类型样式
const courseTypeClass = computed ( ( ) => {
const type = course . value . courseType
if ( type === '1' ) return 'yoga'
if ( type === '2' ) return 'cardio'
if ( type === '3' ) return 'strength'
return ''
} )
// 是否可以预约
const canBook = computed ( ( ) => {
const status = course . value . status
const isFull = course . value . currentMembers >= course . value . maxMembers
return status === '0' && ! isFull
} )
// 是否有多种支付方式
const hasMultiplePayment = computed ( ( ) => {
return course . value . storedValueAmount > 0 && course . value . pointCardAmount > 0
} )
// 当前选中的支付方式价格显示
const selectedPrice = computed ( ( ) => {
if ( selectedPayment . value === 'storedValue' ) {
return { type : 'storedValue' , amount : course . value . storedValueAmount }
} else if ( selectedPayment . value === 'pointCard' ) {
return { type : 'pointCard' , amount : course . value . pointCardAmount }
} else if ( course . value . storedValueAmount > 0 && course . value . pointCardAmount > 0 ) {
// 默认优先显示储值卡
return { type : 'storedValue' , amount : course . value . storedValueAmount }
} else if ( course . value . storedValueAmount > 0 ) {
return { type : 'storedValue' , amount : course . value . storedValueAmount }
} else if ( course . value . pointCardAmount > 0 ) {
return { type : 'pointCard' , amount : course . value . pointCardAmount }
}
return { type : 'free' , amount : 0 }
} )
// 选择支付方式
const selectPayment = ( type ) => {
selectedPayment . value = type
}
// 格式化日期
const formatDate = ( dateStr ) => {
if ( ! dateStr ) return ''
const date = new Date ( dateStr )
const year = date . getFullYear ( )
const month = ( date . getMonth ( ) + 1 ) . toString ( ) . padStart ( 2 , '0' )
const day = date . getDate ( ) . toString ( ) . padStart ( 2 , '0' )
const weekDays = [ '周日' , '周一' , '周二' , '周三' , '周四' , '周五' , '周六' ]
const weekDay = weekDays [ date . getDay ( ) ]
return ` ${ year } 年 ${ month } 月 ${ day } 日 ${ weekDay } `
}
// 格式化时间
const formatTime = ( dateStr ) => {
if ( ! dateStr ) return ''
const date = new Date ( dateStr )
const hours = date . getHours ( ) . toString ( ) . padStart ( 2 , '0' )
const minutes = date . getMinutes ( ) . toString ( ) . padStart ( 2 , '0' )
return ` ${ hours } : ${ minutes } `
}
// 格式化时长
const formatDuration = ( startStr , endStr ) => {
if ( ! startStr || ! endStr ) return ''
const start = new Date ( startStr )
const end = new Date ( endStr )
const minutes = Math . floor ( ( end . getTime ( ) - start . getTime ( ) ) / 60000 )
return ` ${ minutes } 分钟 `
}
// 返回上一页
const goBack = ( ) => {
uni . navigateBack ( )
}
// 预约处理
const handleBooking = ( ) => {
if ( ! canBook . value ) return
uni . showModal ( {
title : '确认预约' ,
content : ` 确定要预约「 ${ course . value . courseName } 」吗? ` ,
success : ( res ) => {
if ( res . confirm ) {
uni . showLoading ( { title : '预约中...' } )
groupCourseService . book ( {
courseId : course . value . id ,
memberId : '1' // 模拟会员ID
} ) . then ( ( ) => {
uni . hideLoading ( )
uni . showToast ( {
title : '预约成功' ,
icon : 'success'
} )
setTimeout ( ( ) => {
uni . navigateBack ( )
} , 1500 )
} ) . catch ( ( ) => {
uni . hideLoading ( )
uni . showToast ( {
title : '预约失败' ,
icon : 'none'
} )
} )
}
}
} )
}
// 获取课程详情
const fetchCourseDetail = async ( id ) => {
try {
const result = await groupCourseService . getDetail ( id )
course . value = result
console . log ( '[detail.vue] 课程详情获取成功:' , course . value )
} catch ( error ) {
console . error ( '[detail.vue] 获取课程详情失败:' , error )
uni . showToast ( {
title : '获取课程详情失败' ,
icon : 'none'
} )
} finally {
loading . value = false
}
}
// 页面挂载时获取课程详情
onMounted ( ( ) => {
const pages = getCurrentPages ( )
const currentPage = pages [ pages . length - 1 ]
const options = currentPage . options || { }
const courseId = options . id || '1'
console . log ( '[detail.vue] 页面挂载,课程ID:' , courseId )
fetchCourseDetail ( courseId )
} )
< / script >
< style lang = "scss" scoped >
. course - detail - page {
min - height : 100 vh ;
background : # F5F7FA ;
padding - bottom : calc ( 140 rpx + constant ( safe - area - inset - bottom ) ) ;
padding - bottom : calc ( 140 rpx + env ( safe - area - inset - bottom ) ) ;
}
/* 顶部图片区域 */
. header - section {
width : 100 % ;
background : # FFFFFF ;
position : relative ;
}
. cover - image - wrapper {
width : 100 % ;
height : 480 rpx ;
background : # F5F7FA ;
}
. cover - image {
width : 100 % ;
height : 100 % ;
}
. cover - image - placeholder {
width : 100 % ;
height : 100 % ;
background : linear - gradient ( 135 deg , # F3F4F6 0 % , # E5E7EB 100 % ) ;
display : flex ;
flex - direction : column ;
align - items : center ;
justify - content : center ;
gap : 16 rpx ;
}
. placeholder - text {
font - size : 28 rpx ;
color : # 9 CA3AF ;
}
/* 课程基本信息 */
. basic - info - section {
background : # ffffff ;
padding : 32 rpx ;
margin - top : - 40 rpx ;
border - radius : 32 rpx 32 rpx 0 0 ;
position : relative ;
z - index : 10 ;
box - shadow : 0 - 4 rpx 20 rpx rgba ( 0 , 0 , 0 , 0.05 ) ;
}
. course - name - wrapper {
display : flex ;
align - items : center ;
gap : 20 rpx ;
margin - bottom : 24 rpx ;
}
. course - name {
font - size : 40 rpx ;
font - weight : 700 ;
color : # 1 E2A3A ;
flex : 1 ;
line - height : 1.4 ;
}
/* 课程基本信息区域的状态标签 */
. status - tag {
padding : 8 rpx 20 rpx ;
border - radius : 16 rpx ;
font - size : 22 rpx ;
font - weight : 500 ;
& . active {
background : linear - gradient ( 135 deg , # 10 B981 0 % , # 059669 100 % ) ;
color : # ffffff ;
}
& . canceled {
background : linear - gradient ( 135 deg , # 9 CA3AF 0 % , # 6 B7280 100 % ) ;
color : # ffffff ;
}
& . ended {
background : linear - gradient ( 135 deg , # D1D5DB 0 % , # 9 CA3AF 100 % ) ;
color : # ffffff ;
}
}
. course - type - badge {
padding : 8 rpx 20 rpx ;
border - radius : 16 rpx ;
font - size : 22 rpx ;
font - weight : 500 ;
& . yoga {
background : linear - gradient ( 135 deg , # D1FAE5 0 % , # A7F3D0 100 % ) ;
color : # 065 F46 ;
}
& . cardio {
background : linear - gradient ( 135 deg , # FEF3C7 0 % , # FDE68A 100 % ) ;
color : # 92400 E ;
}
& . strength {
background : linear - gradient ( 135 deg , # DBEAFE 0 % , # 93 C5FD 100 % ) ;
color : # 1 E40AF ;
}
}
. course - meta {
display : flex ;
flex - direction : column ;
gap : 16 rpx ;
}
. meta - item {
display : flex ;
align - items : center ;
gap : 12 rpx ;
padding : 16 rpx 20 rpx ;
background : linear - gradient ( 135 deg , # F9FAFB 0 % , # F3F4F6 100 % ) ;
border - radius : 16 rpx ;
}
. meta - text {
font - size : 28 rpx ;
color : # 4 B5563 ;
flex : 1 ;
}
/* 详情卡片 */
. detail - card {
background : # ffffff ;
margin : 24 rpx ;
border - radius : 24 rpx ;
padding : 28 rpx ;
box - shadow : 0 4 rpx 16 rpx rgba ( 0 , 0 , 0 , 0.04 ) ;
}
. card - header {
display : flex ;
align - items : center ;
gap : 12 rpx ;
margin - bottom : 20 rpx ;
}
. card - title {
font - size : 32 rpx ;
font - weight : 600 ;
color : # 1 E2A3A ;
}
. card - content {
padding - top : 8 rpx ;
}
. description - text {
font - size : 28 rpx ;
color : # 5 E6F8D ;
line - height : 1.8 ;
text - align : justify ;
}
/* 信息卡片 */
. info - card {
background : # ffffff ;
margin : 0 24 rpx 24 rpx ;
border - radius : 24 rpx ;
padding : 28 rpx ;
box - shadow : 0 4 rpx 16 rpx rgba ( 0 , 0 , 0 , 0.04 ) ;
}
. info - row {
display : flex ;
align - items : center ;
padding : 20 rpx 0 ;
border - bottom : 1 rpx solid # F3F4F6 ;
& : last - child {
border - bottom : none ;
}
}
. info - label {
display : flex ;
align - items : center ;
gap : 12 rpx ;
width : 200 rpx ;
font - size : 28 rpx ;
color : # 5 E6F8D ;
}
. info - value {
font - size : 28 rpx ;
color : # 1 E2A3A ;
font - weight : 500 ;
flex : 1 ;
text - align : right ;
}
. payment - options {
display : flex ;
gap : 20 rpx ;
flex : 1 ;
justify - content : flex - end ;
}
. payment - item {
display : flex ;
flex - direction : column ;
align - items : center ;
padding : 16 rpx 28 rpx ;
background : linear - gradient ( 135 deg , # F9FAFB 0 % , # F3F4F6 100 % ) ;
border - radius : 16 rpx ;
border : 2 rpx solid transparent ;
position : relative ;
transition : all 0.3 s cubic - bezier ( 0.4 , 0 , 0.2 , 1 ) ;
& : active {
transform : scale ( 0.97 ) ;
}
& . active {
background : linear - gradient ( 135 deg , # FF6B35 0 % , # FF8C5A 100 % ) ;
border - color : # FF6B35 ;
. payment - label ,
. payment - value {
color : # ffffff ;
}
}
& . free {
background : linear - gradient ( 135 deg , # ECFDF5 0 % , # D1FAE5 100 % ) ;
}
}
. payment - label {
font - size : 20 rpx ;
color : # 6 B7280 ;
}
. payment - value {
font - size : 28 rpx ;
font - weight : 600 ;
color : # FF6B35 ;
. free & {
color : # 059669 ;
}
}
. payment - check {
position : absolute ;
top : - 8 rpx ;
right : - 8 rpx ;
width : 36 rpx ;
height : 36 rpx ;
background : # 059669 ;
border - radius : 50 % ;
display : flex ;
align - items : center ;
justify - content : center ;
}
/* 预约须知 */
. notice - card {
background : # ffffff ;
margin : 0 24 rpx 24 rpx ;
border - radius : 24 rpx ;
padding : 28 rpx ;
box - shadow : 0 4 rpx 16 rpx rgba ( 0 , 0 , 0 , 0.04 ) ;
}
. notice - list {
padding - top : 8 rpx ;
}
. notice - item {
display : flex ;
gap : 12 rpx ;
padding : 12 rpx 0 ;
font - size : 26 rpx ;
color : # 5 E6F8D ;
line - height : 1.6 ;
}
. notice - dot {
color : # F39C12 ;
font - size : 24 rpx ;
}
/* 底部操作栏 */
. bottom - bar {
position : fixed ;
bottom : 0 ;
left : 0 ;
right : 0 ;
background : # ffffff ;
padding : 20 rpx 24 rpx ;
padding - bottom : calc ( 20 rpx + constant ( safe - area - inset - bottom ) ) ;
padding - bottom : calc ( 20 rpx + env ( safe - area - inset - bottom ) ) ;
display : flex ;
align - items : center ;
gap : 24 rpx ;
box - shadow : 0 - 4 rpx 20 rpx rgba ( 0 , 0 , 0 , 0.08 ) ;
z - index : 100 ;
}
. price - display {
flex : 1 ;
padding - left : 20 rpx ;
. price {
font - size : 40 rpx ;
font - weight : 700 ;
color : # FF6B35 ;
display : flex ;
align - items : baseline ;
gap : 4 rpx ;
. currency {
font - size : 26 rpx ;
font - weight : 600 ;
}
& . points {
gap : 8 rpx ;
}
& . free {
color : # 10 B981 ;
}
}
}
. booking - btn {
padding : 24 rpx 64 rpx ;
background : linear - gradient ( 135 deg , # FF6B35 0 % , # FF8C5A 100 % ) ;
border - radius : 52 rpx ;
font - size : 32 rpx ;
font - weight : 600 ;
color : # ffffff ;
box - shadow : 0 8 rpx 24 rpx rgba ( 255 , 107 , 53 , 0.3 ) ;
transition : all 0.3 s cubic - bezier ( 0.4 , 0 , 0.2 , 1 ) ;
& : active {
transform : scale ( 0.97 ) ;
box - shadow : 0 4 rpx 12 rpx rgba ( 255 , 107 , 53 , 0.2 ) ;
}
& . disabled {
background : linear - gradient ( 135 deg , # F3F4F6 0 % , # E5E7EB 100 % ) ;
color : # 9 CA3AF ;
box - shadow : none ;
}
}
/* 骨架屏样式 */
. skeleton {
padding - bottom : calc ( 140 rpx + constant ( safe - area - inset - bottom ) ) ;
padding - bottom : calc ( 140 rpx + env ( safe - area - inset - bottom ) ) ;
}
. skeleton - header {
background : # ffffff ;
padding - top : 20 rpx ;
}
. skeleton - cover {
width : 100 % ;
height : 480 rpx ;
border - radius : 0 ;
}
. skeleton - content {
margin - top : - 40 rpx ;
padding : 0 24 rpx ;
}
. skeleton - block {
background : linear - gradient ( 90 deg , # F0F0F0 25 % , # E0E0E0 50 % , # F0F0F0 75 % ) ;
background - size : 200 % 100 % ;
animation : skeleton - loading 1.5 s ease - in - out infinite ;
border - radius : 16 rpx ;
}
@ keyframes skeleton - loading {
0 % {
background - position : 200 % 0 ;
}
100 % {
background - position : - 200 % 0 ;
}
}
. skeleton - name {
width : 50 % ;
height : 48 rpx ;
margin - bottom : 20 rpx ;
}
. skeleton - meta {
display : flex ;
flex - direction : column ;
gap : 16 rpx ;
margin - bottom : 24 rpx ;
}
. skeleton - meta - item {
width : 70 % ;
height : 48 rpx ;
}
. skeleton - card {
background : # ffffff ;
border - radius : 24 rpx ;
padding : 28 rpx ;
margin - bottom : 24 rpx ;
box - shadow : 0 4 rpx 16 rpx rgba ( 0 , 0 , 0 , 0.04 ) ;
}
. skeleton - card - title {
width : 30 % ;
height : 36 rpx ;
margin - bottom : 20 rpx ;
}
. skeleton - card - content {
display : flex ;
flex - direction : column ;
gap : 12 rpx ;
}
. skeleton - text - line {
height : 32 rpx ;
& . short {
width : 60 % ;
}
}
. skeleton - info - row {
display : flex ;
justify - content : space - between ;
align - items : center ;
padding : 20 rpx 0 ;
border - bottom : 1 rpx solid # F3F4F6 ;
& : last - child {
border - bottom : none ;
}
}
. skeleton - info - label {
width : 160 rpx ;
height : 32 rpx ;
}
. skeleton - info - value {
width : 120 rpx ;
height : 32 rpx ;
}
. skeleton - payment {
display : flex ;
gap : 16 rpx ;
}
. skeleton - payment - item {
width : 100 rpx ;
height : 60 rpx ;
}
. skeleton - notice {
display : flex ;
flex - direction : column ;
gap : 16 rpx ;
padding - top : 8 rpx ;
}
. skeleton - notice - item {
height : 32 rpx ;
width : 90 % ;
}
< / style >