1
This commit is contained in:
113
new-soul/miniprogram/pages/mentor-detail/mentor-detail.js
Normal file
113
new-soul/miniprogram/pages/mentor-detail/mentor-detail.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Soul创业派对 - 导师详情(stitch_soul)
|
||||
* 联系导师按钮 → 弹出 v2 弹窗(选择咨询项目)
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
mentor: null,
|
||||
loading: true,
|
||||
showConsultModal: false,
|
||||
consultOptions: [],
|
||||
selectedType: '',
|
||||
selectedAmount: 0,
|
||||
creating: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 })
|
||||
if (options.id) this.loadDetail(options.id)
|
||||
},
|
||||
|
||||
async loadDetail(id) {
|
||||
this.setData({ loading: true })
|
||||
try {
|
||||
const res = await app.request({ url: `/api/miniprogram/mentors/${id}`, silent: true })
|
||||
if (res?.success && res.data) {
|
||||
const d = res.data
|
||||
if (d.judgmentStyle && typeof d.judgmentStyle === 'string') {
|
||||
d.judgmentStyleArr = d.judgmentStyle.split(/[,,]/).map(s => s.trim()).filter(Boolean)
|
||||
} else {
|
||||
d.judgmentStyleArr = []
|
||||
}
|
||||
const fmt = v => v != null ? String(Math.floor(v)).replace(/\B(?=(\d{3})+(?!\d))/g, ',') : ''
|
||||
d.priceSingleFmt = fmt(d.priceSingle)
|
||||
d.priceHalfYearFmt = fmt(d.priceHalfYear)
|
||||
d.priceYearFmt = fmt(d.priceYear)
|
||||
const options = []
|
||||
if (d.priceSingle != null) options.push({ type: 'single', label: '单次咨询', desc: '1小时深度沟通', price: d.priceSingle, priceFmt: fmt(d.priceSingle), original: null })
|
||||
if (d.priceHalfYear != null) options.push({ type: 'half_year', label: '半年咨询', desc: '不限次数 · 关键节点陪伴', price: d.priceHalfYear, priceFmt: fmt(d.priceHalfYear), original: '98,000' })
|
||||
if (d.priceYear != null) options.push({ type: 'year', label: '年度咨询', desc: '全年度战略顾问', price: d.priceYear, priceFmt: fmt(d.priceYear), original: '196,000', recommend: true })
|
||||
this.setData({
|
||||
mentor: d,
|
||||
consultOptions: options,
|
||||
loading: false,
|
||||
})
|
||||
} else {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
onContactTap() {
|
||||
if (!this.data.mentor || this.data.consultOptions.length === 0) {
|
||||
wx.showToast({ title: '暂无咨询项目', icon: 'none' })
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
showConsultModal: true,
|
||||
selectedType: this.data.consultOptions[0].type,
|
||||
selectedAmount: this.data.consultOptions[0].price,
|
||||
})
|
||||
},
|
||||
|
||||
closeConsultModal() {
|
||||
this.setData({ showConsultModal: false })
|
||||
},
|
||||
|
||||
onSelectOption(e) {
|
||||
const item = e.currentTarget.dataset.item
|
||||
this.setData({ selectedType: item.type, selectedAmount: item.price })
|
||||
},
|
||||
|
||||
async onConfirmConsult() {
|
||||
const { mentor, selectedType } = this.data
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) {
|
||||
wx.showToast({ title: '请先登录', icon: 'none' })
|
||||
wx.navigateTo({ url: '/pages/my/my' })
|
||||
return
|
||||
}
|
||||
this.setData({ creating: true })
|
||||
try {
|
||||
const res = await app.request({
|
||||
url: `/api/miniprogram/mentors/${mentor.id}/book`,
|
||||
method: 'POST',
|
||||
data: { userId, consultationType: selectedType },
|
||||
})
|
||||
if (res?.success && res.data) {
|
||||
this.setData({ showConsultModal: false, creating: false })
|
||||
wx.showToast({ title: '预约创建成功', icon: 'success' })
|
||||
// TODO: 调起支付 productType: mentor_consultation, productId: res.data.id
|
||||
wx.showModal({
|
||||
title: '预约成功',
|
||||
content: '请联系客服完成后续对接',
|
||||
showCancel: false,
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: res?.error || '创建失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '创建失败', icon: 'none' })
|
||||
}
|
||||
this.setData({ creating: false })
|
||||
},
|
||||
|
||||
goBack() {
|
||||
getApp().goBackOrToHome()
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
{"usingComponents":{},"navigationStyle":"custom"}
|
||||
118
new-soul/miniprogram/pages/mentor-detail/mentor-detail.wxml
Normal file
118
new-soul/miniprogram/pages/mentor-detail/mentor-detail.wxml
Normal file
@@ -0,0 +1,118 @@
|
||||
<!-- 导师详情 -->
|
||||
<view class="page">
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-back" bindtap="goBack"><text class="back-icon">‹</text></view>
|
||||
<text class="nav-title">导师详情</text>
|
||||
<view class="nav-placeholder-r"></view>
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="loading" wx:if="{{loading}}">加载中...</view>
|
||||
<block wx:else>
|
||||
<view class="mentor-header" wx:if="{{mentor}}">
|
||||
<view class="mentor-avatar-wrap">
|
||||
<image wx:if="{{mentor.avatar}}" class="mentor-avatar" src="{{mentor.avatar}}" mode="aspectFill"></image>
|
||||
<view wx:else class="mentor-avatar-placeholder">{{mentor.name ? mentor.name[0] : '?'}}</view>
|
||||
</view>
|
||||
<text class="mentor-name">{{mentor.name}}</text>
|
||||
<text class="mentor-intro">{{mentor.intro}}</text>
|
||||
<view class="mentor-quote" wx:if="{{mentor.quote}}">{{mentor.quote}}</view>
|
||||
</view>
|
||||
|
||||
<view class="block" wx:if="{{mentor.whyFind}}">
|
||||
<view class="block-header"><text class="block-num">01</text><text class="block-title">为什么找{{mentor.name}}?</text></view>
|
||||
<text class="block-text">{{mentor.whyFind}}</text>
|
||||
</view>
|
||||
|
||||
<view class="block" wx:if="{{mentor.offering}}">
|
||||
<view class="block-header"><text class="block-num">02</text><text class="block-title">提供什么?</text></view>
|
||||
<text class="block-text">{{mentor.offering}}</text>
|
||||
</view>
|
||||
|
||||
<view class="block" wx:if="{{mentor.priceSingle || mentor.priceHalfYear || mentor.priceYear}}">
|
||||
<view class="block-header"><text class="block-num">03</text><text class="block-title">收费标准</text></view>
|
||||
<view class="price-table">
|
||||
<view class="price-thead">
|
||||
<text class="p-col-2">咨询项目</text>
|
||||
<text class="p-col-center">时长</text>
|
||||
<text class="p-col-right">价格</text>
|
||||
</view>
|
||||
<view class="price-row" wx:if="{{mentor.priceSingle}}">
|
||||
<text class="p-col-2">单次咨询</text>
|
||||
<text class="p-col-center">1小时</text>
|
||||
<text class="p-col-right price-num">¥{{mentor.priceSingleFmt || mentor.priceSingle}}</text>
|
||||
</view>
|
||||
<view class="price-row price-row-alt" wx:if="{{mentor.priceHalfYear}}">
|
||||
<text class="p-col-2">半年咨询</text>
|
||||
<text class="p-col-center">-</text>
|
||||
<view class="p-col-right">
|
||||
<text class="price-original">98,000</text>
|
||||
<text class="price-num">¥{{mentor.priceHalfYearFmt || mentor.priceHalfYear}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="price-row" wx:if="{{mentor.priceYear}}">
|
||||
<text class="p-col-2">年度咨询</text>
|
||||
<text class="p-col-center">-</text>
|
||||
<view class="p-col-right">
|
||||
<text class="price-original">196,000</text>
|
||||
<text class="price-num">¥{{mentor.priceYearFmt || mentor.priceYear}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="block" wx:if="{{mentor.judgmentStyle}}">
|
||||
<view class="block-header"><text class="block-num">04</text><text class="block-title">判断风格</text></view>
|
||||
<view class="style-tags">
|
||||
<text class="style-tag" wx:for="{{mentor.judgmentStyleArr}}" wx:key="*this">{{item}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom-btn-area">
|
||||
<view class="contact-btn" bindtap="onContactTap">
|
||||
<icon name="message-circle" size="40" color="#00CED1" customClass="contact-icon"></icon>
|
||||
<text>联系导师</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- v2 弹窗:选择咨询项目 -->
|
||||
<view class="modal-overlay" wx:if="{{showConsultModal}}" bindtap="closeConsultModal">
|
||||
<view class="modal-content" catchtap="">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">选择咨询项目</text>
|
||||
<view class="modal-close" bindtap="closeConsultModal"><icon name="x" size="36" color="#8e8e93"></icon></view>
|
||||
</view>
|
||||
<view class="consult-options">
|
||||
<view
|
||||
wx:for="{{consultOptions}}"
|
||||
wx:key="type"
|
||||
class="consult-option {{selectedType === item.type ? 'option-selected' : ''}}"
|
||||
data-item="{{item}}"
|
||||
bindtap="onSelectOption"
|
||||
>
|
||||
<view class="option-row1">
|
||||
<text class="option-label">{{item.label}}</text>
|
||||
<text class="option-rec" wx:if="{{item.recommend}}">推荐</text>
|
||||
<view class="option-radio {{selectedType === item.type ? 'radio-selected' : ''}}"></view>
|
||||
</view>
|
||||
<view class="option-row2">
|
||||
<text class="option-desc">{{item.desc}}</text>
|
||||
<view class="option-price-wrap">
|
||||
<text class="option-price-old" wx:if="{{item.original}}">¥{{item.original}}</text>
|
||||
<text class="option-price">¥{{item.priceFmt || item.price}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-footer">
|
||||
<view class="confirm-btn" bindtap="onConfirmConsult" disabled="{{creating}}">
|
||||
{{creating ? '处理中...' : '确认选择 →'}}
|
||||
</view>
|
||||
<text class="footer-hint">点击确认即代表同意 <text class="footer-link">服务协议</text></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom-space"></view>
|
||||
</view>
|
||||
70
new-soul/miniprogram/pages/mentor-detail/mentor-detail.wxss
Normal file
70
new-soul/miniprogram/pages/mentor-detail/mentor-detail.wxss
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 按 mentor_detail_profile_1 + mentor_detail_profile_2 设计稿 */
|
||||
.page { background: #000; min-height: 100vh; color: #fff; }
|
||||
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; height: 44px; padding: 0 24rpx; background: rgba(0,0,0,0.9); border-bottom: 1rpx solid #27272a; }
|
||||
.nav-back { width: 60rpx; }
|
||||
.back-icon { font-size: 44rpx; color: #fff; }
|
||||
.nav-title { font-size: 36rpx; font-weight: 500; }
|
||||
.nav-placeholder-r { width: 60rpx; }
|
||||
|
||||
.loading { padding: 96rpx; text-align: center; color: #71717a; }
|
||||
.mentor-header { display: flex; flex-direction: column; align-items: center; padding: 48rpx 24rpx; text-align: center; }
|
||||
.mentor-avatar-wrap { margin-bottom: 24rpx; }
|
||||
.mentor-avatar { width: 192rpx; height: 192rpx; border-radius: 50%; border: 4rpx solid #4FD1C5; display: block; background: rgba(255,255,255,0.1); }
|
||||
.mentor-avatar-placeholder { width: 192rpx; height: 192rpx; border-radius: 50%; border: 4rpx solid #4FD1C5; background: rgba(79,209,197,0.2); display: flex; align-items: center; justify-content: center; font-size: 72rpx; font-weight: bold; color: #4FD1C5; }
|
||||
.mentor-name { font-size: 48rpx; font-weight: bold; margin-bottom: 8rpx; }
|
||||
.mentor-intro { font-size: 28rpx; color: #4FD1C5; font-weight: 500; margin-bottom: 24rpx; }
|
||||
.mentor-quote { padding: 32rpx; background: #1E1E1E; border-left: 8rpx solid #4FD1C5; border-radius: 24rpx; font-size: 28rpx; color: #d4d4d8; text-align: left; width: 100%; max-width: 600rpx; box-sizing: border-box; }
|
||||
|
||||
.block { padding: 0 24rpx 64rpx; }
|
||||
.block-header { display: flex; align-items: center; margin-bottom: 24rpx; }
|
||||
.block-num { background: #4FD1C5; color: #000; font-size: 24rpx; font-weight: bold; padding: 8rpx 20rpx; border-radius: 999rpx; margin-right: 16rpx; }
|
||||
.block-title { font-size: 36rpx; font-weight: bold; }
|
||||
.block-text { font-size: 26rpx; color: #A0AEC0; line-height: 1.7; display: block; }
|
||||
|
||||
/* 03 收费标准 - 表头青色 */
|
||||
.price-table { background: #1E1E1E; border-radius: 24rpx; overflow: hidden; }
|
||||
.price-thead { display: flex; align-items: center; padding: 24rpx 32rpx; background: #4FD1C5; color: #000; font-size: 24rpx; font-weight: bold; }
|
||||
.p-col-2 { flex: 2; }
|
||||
.p-col-center { flex: 1; text-align: center; }
|
||||
.p-col-right { flex: 1; text-align: right; min-width: 160rpx; }
|
||||
.price-row { display: flex; align-items: center; padding: 32rpx; border-bottom: 1rpx solid #27272a; }
|
||||
.price-row:last-child { border-bottom: none; }
|
||||
.price-row-alt { background: rgba(255,255,255,0.02); }
|
||||
.price-row .p-col-2 { font-size: 28rpx; font-weight: 500; }
|
||||
.price-row .p-col-center { font-size: 24rpx; color: #71717a; }
|
||||
.price-num { font-size: 28rpx; font-weight: bold; color: #4FD1C5; }
|
||||
.price-original { font-size: 20rpx; color: #71717a; text-decoration: line-through; display: block; margin-bottom: 4rpx; }
|
||||
.price-row .p-col-right { display: flex; flex-direction: column; align-items: flex-end; }
|
||||
|
||||
.style-tags { display: flex; flex-wrap: wrap; gap: 24rpx; }
|
||||
.style-tag { padding: 16rpx 32rpx; background: #1E1E1E; border: 1rpx solid #3f3f46; border-radius: 999rpx; font-size: 28rpx; font-weight: 500; }
|
||||
|
||||
.bottom-btn-area { position: fixed; bottom: 0; left: 0; right: 0; padding: 24rpx 32rpx; padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); background: rgba(0,0,0,0.95); border-top: 1rpx solid #27272a; z-index: 50; }
|
||||
.contact-btn { display: flex; align-items: center; justify-content: center; gap: 16rpx; width: 100%; height: 96rpx; background: #4FD1C5; color: #000; font-size: 32rpx; font-weight: bold; border-radius: 24rpx; box-shadow: 0 8rpx 32rpx rgba(79,209,197,0.25); }
|
||||
.contact-icon { font-size: 36rpx; }
|
||||
|
||||
/* v2 弹窗 - mentor_detail_profile_2 */
|
||||
.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7); backdrop-filter: blur(4px); z-index: 200; display: flex; align-items: flex-end; justify-content: center; }
|
||||
.modal-content { width: 100%; max-height: 85vh; background: #121212; border-radius: 32rpx 32rpx 0 0; padding: 32rpx; padding-bottom: calc(48rpx + env(safe-area-inset-bottom)); border: 1rpx solid rgba(255,255,255,0.08); }
|
||||
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 32rpx; padding-bottom: 24rpx; border-bottom: 1rpx solid #27272a; }
|
||||
.modal-title { font-size: 40rpx; font-weight: bold; }
|
||||
.modal-close { font-size: 40rpx; color: #71717a; padding: 16rpx; }
|
||||
.consult-options { margin-bottom: 32rpx; }
|
||||
.consult-option { padding: 32rpx; margin-bottom: 24rpx; background: #1E1E1E; border-radius: 24rpx; border: 2rpx solid #3f3f46; }
|
||||
.option-selected { border-color: #4FD1C5; background: rgba(79,209,197,0.08); }
|
||||
.option-row1 { display: flex; align-items: center; margin-bottom: 16rpx; }
|
||||
.option-label { font-size: 32rpx; font-weight: bold; flex: 1; }
|
||||
.option-rec { font-size: 20rpx; padding: 6rpx 16rpx; background: #ED8936; color: #fff; border-radius: 8rpx; margin-right: 16rpx; }
|
||||
.option-radio { width: 40rpx; height: 40rpx; border-radius: 50%; border: 2rpx solid #71717a; flex-shrink: 0; }
|
||||
.radio-selected { border-color: #4FD1C5; background: #4FD1C5; }
|
||||
.option-row2 { display: flex; justify-content: space-between; align-items: flex-end; }
|
||||
.option-desc { font-size: 24rpx; color: #71717a; }
|
||||
.option-price-wrap { display: flex; flex-direction: column; align-items: flex-end; }
|
||||
.option-price-old { font-size: 22rpx; color: #71717a; text-decoration: line-through; margin-bottom: 4rpx; }
|
||||
.option-price { font-size: 36rpx; font-weight: bold; color: #4FD1C5; }
|
||||
.confirm-btn { width: 100%; height: 100rpx; line-height: 100rpx; text-align: center; background: #4FD1C5; color: #000; font-size: 32rpx; font-weight: bold; border-radius: 24rpx; box-shadow: 0 8rpx 32rpx rgba(79,209,197,0.25); }
|
||||
.confirm-btn[disabled] { opacity: 0.6; }
|
||||
.footer-hint { display: block; font-size: 22rpx; color: #71717a; text-align: center; margin-top: 24rpx; }
|
||||
.footer-link { color: #4FD1C5; }
|
||||
|
||||
.bottom-space { height: 180rpx; }
|
||||
Reference in New Issue
Block a user