| | |
| | | <scroll-view scroll-y class="content-scroll"> |
| | | <view class="form-wrap"> |
| | | <view class="select-field"> |
| | | <text class="field-label">接单模式</text> |
| | | <picker class="field-control" :range="modeNames" @change="handleModeChange"> |
| | | <view class="select-box"> |
| | | <text>{{ currentModeName }}</text> |
| | | <image class="select-icon" src="/static/icons/chevron-down.svg" mode="aspectFit" /> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | <view class="select-field"> |
| | | <text class="field-label">接单景区</text> |
| | | <picker class="field-control" :range="scenicNames" @change="handleScenicChange"> |
| | | <view class="select-box"> |
| | |
| | | import { buildMeetingPointCircles, hasMeetingPointLocation, openMeetingPointPage } from '../../services/map' |
| | | import { routeTo } from '../../utils/router' |
| | | |
| | | function formatPriceAmount(value) { |
| | | if (value === null || value === undefined || value === '') { |
| | | return '' |
| | | } |
| | | const amount = Number(value) |
| | | if (!Number.isFinite(amount)) { |
| | | return '' |
| | | } |
| | | return amount.toFixed(2).replace(/\.?0+$/, '') |
| | | } |
| | | |
| | | function formatServicePrice(option, unit) { |
| | | if (!option) { |
| | | return '' |
| | | } |
| | | const amount = formatPriceAmount(option.discountPrice ?? option.originalPrice) |
| | | return amount ? `¥${amount}/${unit}` : '' |
| | | } |
| | | |
| | | function formatParticipants(option, group) { |
| | | if (!option || option.minParticipants === null || option.minParticipants === undefined) { |
| | | return '-' |
| | | } |
| | | const min = Number(option.minParticipants) |
| | | const max = option.maxParticipants === null || option.maxParticipants === undefined |
| | | ? min |
| | | : Number(option.maxParticipants) |
| | | if (!Number.isFinite(min) || !Number.isFinite(max)) { |
| | | return '-' |
| | | } |
| | | return group ? `${min}-${max}人` : `${max}人(含)内` |
| | | } |
| | | |
| | | export default { |
| | | components: { |
| | | GuideNavBar |
| | |
| | | scenics: [], |
| | | scenicId: '', |
| | | meetingPointId: '', |
| | | receivingMode: 'GROUP', |
| | | premiumEnabled: false, |
| | | requiredOrderCount: 0, |
| | | requiredRating: 0, |
| | |
| | | scenicNames() { |
| | | return this.scenics.map((item) => item.name) |
| | | }, |
| | | modeNames() { |
| | | return ['\u62fc\u56e2', '\u5305\u56e2'] |
| | | }, |
| | | currentModeName() { |
| | | return this.receivingMode === 'GROUP' ? '\u62fc\u56e2' : '\u5305\u56e2' |
| | | }, |
| | | currentScenic() { |
| | | return this.scenics.find((item) => item.id === this.scenicId) || {} |
| | | }, |
| | |
| | | getGuideReceivingOptions().then((result) => { |
| | | const list = result.scenics || [] |
| | | this.scenics = list |
| | | this.premiumEnabled = Boolean(result.premiumEnabled) |
| | | this.premiumEnabled = result.premiumEnabled === true || result.premiumEnabled === 1 |
| | | || result.premiumEnabled === 'true' || result.premiumEnabled === '1' |
| | | this.requiredOrderCount = Number(result.requiredOrderCount || 0) |
| | | this.requiredRating = Number(result.requiredRating || 0) |
| | | if (list.length) { |
| | |
| | | this.meetingPointId = (item.meetingPoints && item.meetingPoints[0] && item.meetingPoints[0].id) || '' |
| | | this.refreshServices() |
| | | }, |
| | | handleModeChange(event) { |
| | | this.receivingMode = Number(event.detail.value) === 0 ? 'GROUP' : 'PRIVATE' |
| | | this.refreshServices() |
| | | }, |
| | | handleMeetingPointChange(event) { |
| | | const item = this.currentMeetingPoints[event.detail.value] |
| | | if (item) { |
| | |
| | | this.selectedServiceIds.push(service.id) |
| | | }, |
| | | refreshServices() { |
| | | const prefix = `${this.receivingMode}_` |
| | | this.services = (this.currentScenic.services || []) |
| | | .filter((item) => item.serviceType && item.serviceType.startsWith(prefix)) |
| | | .map((item) => { |
| | | const premium = item.serviceType.endsWith('_PREMIUM') |
| | | const peopleText = this.receivingMode === 'GROUP' |
| | | ? `${item.minParticipants || 1}-${item.maxParticipants || item.minParticipants || 1}\u4eba` |
| | | : `${item.maxParticipants || item.minParticipants || 1}\u4eba\u4ee5\u5185` |
| | | return { |
| | | id: premium ? 'deep' : 'quick', |
| | | serviceType: item.serviceType, |
| | | title: premium ? '\u7cbe\u8bb2' : '\u5feb\u8bb2', |
| | | duration: `${item.durationMinutes || 0}\u5206\u949f`, |
| | | groupPeople: this.receivingMode === 'GROUP' ? peopleText : '-', |
| | | groupPrice: '', |
| | | privatePeople: this.receivingMode === 'PRIVATE' ? peopleText : '-', |
| | | privatePrice: '', |
| | | disabled: premium && !this.premiumEnabled, |
| | | note: premium && !this.premiumEnabled |
| | | ? `\u7d2f\u8ba1\u63a5\u5355\u6570\u2265${this.requiredOrderCount}\uff0c\u8bc4\u5206\u2265${this.requiredRating}\u53ef\u5f00\u542f\u7cbe\u8bb2` |
| | | : '' |
| | | } |
| | | }) |
| | | const configuredServices = this.currentScenic.services || [] |
| | | const serviceDefinitions = [ |
| | | { id: 'quick', code: 'QUICK', title: '\u5feb\u8bb2' }, |
| | | { id: 'deep', code: 'PREMIUM', title: '\u7cbe\u8bb2' } |
| | | ] |
| | | this.services = serviceDefinitions.map((definition) => { |
| | | const groupOption = configuredServices.find((item) => item.serviceType === `GROUP_${definition.code}`) |
| | | const privateOption = configuredServices.find((item) => item.serviceType === `PRIVATE_${definition.code}`) |
| | | const serviceTypes = [groupOption && groupOption.serviceType, privateOption && privateOption.serviceType] |
| | | .filter(Boolean) |
| | | if (!serviceTypes.length) { |
| | | return null |
| | | } |
| | | const durationMinutes = (groupOption && groupOption.durationMinutes) |
| | | || (privateOption && privateOption.durationMinutes) || 0 |
| | | const disabled = definition.id === 'deep' && !this.premiumEnabled |
| | | return { |
| | | id: definition.id, |
| | | serviceTypes, |
| | | title: definition.title, |
| | | duration: `${durationMinutes}分钟`, |
| | | groupPeople: formatParticipants(groupOption, true), |
| | | groupPrice: formatServicePrice(groupOption, '人'), |
| | | privatePeople: formatParticipants(privateOption, false), |
| | | privatePrice: formatServicePrice(privateOption, '团'), |
| | | disabled, |
| | | note: disabled |
| | | ? `累计接单数≥${this.requiredOrderCount},评分≥${this.requiredRating}可开启精讲` |
| | | : '' |
| | | } |
| | | }).filter(Boolean) |
| | | const available = this.services.filter((item) => !item.disabled).map((item) => item.id) |
| | | this.selectedServiceIds = this.selectedServiceIds.filter((id) => available.includes(id)) |
| | | if (!this.selectedServiceIds.length && available.length) this.selectedServiceIds = [available[0]] |
| | |
| | | uni.showToast({ title: '请选择景区和汇合点', icon: 'none' }) |
| | | return |
| | | } |
| | | const selectedServices = this.services.filter((item) => this.selectedServiceIds.includes(item.id)) |
| | | if (!selectedServices.length) { |
| | | uni.showToast({ title: '至少选择一种接单类型', icon: 'none' }) |
| | | return |
| | | } |
| | | if (selectedServices.some((item) => !Array.isArray(item.serviceTypes) || !item.serviceTypes.length)) { |
| | | uni.showToast({ title: '接单配置加载中,请稍后重试', icon: 'none' }) |
| | | return |
| | | } |
| | | if (selectedServices.some((item) => item.serviceTypes.some((type) => type.endsWith('_PREMIUM')) && !this.premiumEnabled)) { |
| | | uni.showToast({ title: '当前未开通精讲接单权限', icon: 'none' }) |
| | | return |
| | | } |
| | | updateGuideOnlineStatus('online', { |
| | | scenicSpotId: this.scenicId, |
| | | meetingPointId: this.meetingPointId, |
| | | receivingMode: this.receivingMode, |
| | | receivingMode: 'ALL', |
| | | latitude: this.currentMeetingPoint.latitude, |
| | | longitude: this.currentMeetingPoint.longitude, |
| | | serviceTypes: this.services |
| | | .filter((item) => this.selectedServiceIds.includes(item.id)) |
| | | .map((item) => item.serviceType) |
| | | serviceTypes: selectedServices.reduce((types, item) => types.concat(item.serviceTypes), []) |
| | | }).then(() => { |
| | | uni.showToast({ title: '已开始接单', icon: 'success' }) |
| | | setTimeout(() => { |