| | |
| | | </template> |
| | | </view> |
| | | <view class="receiving-right"> |
| | | <view>{{ receivingMeetingPoint }}</view> |
| | | <view class="meeting-point-name">{{ receivingMeetingPoint }}</view> |
| | | <view class="meeting-link" @tap="viewMeetingPoint">查看汇合点</view> |
| | | </view> |
| | | </view> |
| | |
| | | meetingPointLongitude: meetingPoint.longitude ?? fallback.meetingPointLongitude ?? fallback.longitude, |
| | | latitude: meetingPoint.latitude ?? fallback.latitude, |
| | | longitude: meetingPoint.longitude ?? fallback.longitude, |
| | | serviceStartAt: session.serviceStartAt || fallback.serviceStartAt || '' |
| | | receivingMode: session.receivingMode || fallback.receivingMode || '', |
| | | serviceStartAt: session.serviceStartAt || fallback.serviceStartAt || '', |
| | | firstOrderLeadMinutes: resolvePositiveMinutes( |
| | | scenic.firstOrderLeadMinutes ?? fallback.firstOrderLeadMinutes, |
| | | 15 |
| | | ) |
| | | } |
| | | } |
| | | |
| | |
| | | return NaN |
| | | } |
| | | return new Date(String(value).trim().replace(' ', 'T')).getTime() |
| | | } |
| | | |
| | | function resolvePositiveMinutes(value, fallback = 15) { |
| | | const minutes = Number(value) |
| | | return Number.isFinite(minutes) && minutes > 0 ? minutes : fallback |
| | | } |
| | | |
| | | export default { |
| | |
| | | unreadMessageCount: 0, |
| | | unreadMessageInitialized: false, |
| | | countdownSeconds: 0, |
| | | countdownFallbackEndAt: null, |
| | | countdownTimer: null, |
| | | refreshTimer: null, |
| | | refreshing: false, |
| | |
| | | const order = this.activeReceivingOrder |
| | | const serving = this.isServing |
| | | const durationMinutes = Number(order.durationMinutes || 30) |
| | | const startAt = parseApiDateTime(serving |
| | | ? order.lectureStartTime |
| | | : this.guide.receivingConfig && this.guide.receivingConfig.serviceStartAt) |
| | | const receivingConfig = this.guide.receivingConfig || {} |
| | | const leadMinutes = resolvePositiveMinutes(receivingConfig.firstOrderLeadMinutes, 15) |
| | | const receiveStartAt = parseApiDateTime( |
| | | order.receiveStartTime || order.receiveTime || order.acceptedAt |
| | | ) |
| | | const configuredStartAt = parseApiDateTime(receivingConfig.serviceStartAt) |
| | | let startAt = parseApiDateTime(serving ? order.lectureStartTime : receivingConfig.serviceStartAt) |
| | | if (!serving && receivingConfig.receivingMode === 'PRIVATE' |
| | | && Number.isFinite(receiveStartAt) |
| | | && (!Number.isFinite(configuredStartAt) || configuredStartAt <= receiveStartAt)) { |
| | | startAt = receiveStartAt + leadMinutes * 60 * 1000 |
| | | } |
| | | if (!Number.isFinite(startAt)) { |
| | | this.countdownSeconds = 0 |
| | | if (serving) { |
| | | this.countdownSeconds = 0 |
| | | return |
| | | } |
| | | if (!Number.isFinite(this.countdownFallbackEndAt)) { |
| | | this.countdownFallbackEndAt = Date.now() + leadMinutes * 60 * 1000 |
| | | } |
| | | this.countdownSeconds = Math.max( |
| | | 0, |
| | | Math.ceil((this.countdownFallbackEndAt - Date.now()) / 1000) |
| | | ) |
| | | return |
| | | } |
| | | this.countdownFallbackEndAt = null |
| | | const endAt = serving ? startAt + durationMinutes * 60 * 1000 : startAt |
| | | this.countdownSeconds = Math.max(0, Math.ceil((endAt - Date.now()) / 1000)) |
| | | }, |
| | |
| | | clearInterval(this.countdownTimer) |
| | | this.countdownTimer = null |
| | | } |
| | | this.countdownFallbackEndAt = null |
| | | }, |
| | | finishLectureWhenCountdownEnds() { |
| | | if (!this.isServing || this.finishingLecture) { |
| | |
| | | } |
| | | |
| | | .receiving-summary { |
| | | display: flex; |
| | | display: grid; |
| | | grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); |
| | | column-gap: 24rpx; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | height: 160rpx; |
| | | padding: 0 58rpx; |
| | | border-bottom: 1rpx solid #d8d8d8; |
| | |
| | | } |
| | | |
| | | .receiving-left { |
| | | min-width: 0; |
| | | color: #1f2937; |
| | | font-size: 30rpx; |
| | | font-weight: 500; |
| | |
| | | |
| | | .service-line { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 16rpx; |
| | | min-width: 0; |
| | | overflow: hidden; |
| | | color: #1f2937; |
| | | font-size: 29rpx; |
| | | line-height: 1.3; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .service-line > text:first-child { |
| | | min-width: 0; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .service-line > text:last-child { |
| | | flex-shrink: 0; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .start-line { |
| | | min-width: 0; |
| | | margin-top: 34rpx; |
| | | overflow: hidden; |
| | | color: #1f2937; |
| | | font-size: 29rpx; |
| | | line-height: 1.3; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .receiving-right { |
| | | min-width: 0; |
| | | overflow: hidden; |
| | | color: #111827; |
| | | text-align: right; |
| | | font-size: 25rpx; |
| | | line-height: 1.8; |
| | | } |
| | | |
| | | .meeting-point-name, |
| | | .meeting-link { |
| | | display: block; |
| | | min-width: 0; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .meeting-point-name { |
| | | color: #111827; |
| | | } |
| | | |
| | | .meeting-link { |
| | | color: #1685ff; |
| | | } |