liujie
2026-09-11 4f6f15b818704079ff2e4e4719b798f48d68a335
mingdaojingjiang_guide_app/pages/receiving/index.vue
@@ -5,15 +5,6 @@
    <scroll-view scroll-y class="content-scroll">
      <view class="form-wrap">
        <view class="select-field">
          <text class="field-label">&#25509;&#21333;&#27169;&#24335;</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">
@@ -105,6 +96,39 @@
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
@@ -114,7 +138,6 @@
      scenics: [],
      scenicId: '',
      meetingPointId: '',
      receivingMode: 'GROUP',
      premiumEnabled: false,
      requiredOrderCount: 0,
      requiredRating: 0,
@@ -147,12 +170,6 @@
    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) || {}
    },
@@ -176,7 +193,8 @@
    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) {
@@ -203,10 +221,6 @@
      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) {
@@ -229,29 +243,37 @@
      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]]
@@ -271,15 +293,26 @@
        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(() => {