<template>
  <view class="page">
    <!-- 步骤头部 -->
    <view class="header">
      <view class="title-row">
        <text class="title">新增作业</text>
        <text class="device-id">设备：{{ jobState.machineCode || '未知设备' }}</text>
      </view>
      <view class="step-row">
        <view
          v-for="step in steps"
          :key="step.id"
          class="step-item"
        >
          <view
            class="step-index"
            :class="{
              active: currentStep === step.id,
              done: currentStep > step.id
            }"
          >
            <text v-if="currentStep > step.id">✓</text>
            <text v-else>{{ step.id }}</text>
          </view>
          <view class="step-texts">
            <text class="step-title">{{ step.title }}</text>
            <text class="step-sub">{{ step.sub }}</text>
          </view>
        </view>
      </view>
    </view>

    <!-- 主体内容 -->
    <view class="content">
      <!-- Step 1: 选择作业区域类型 & 路线类型 -->
      <view v-if="currentStep === 1" class="step-block">
        <view class="card select-card">
          <view class="select-title">选择作业区域类型</view>
          <view class="select-sub">
            不同区域形状将影响后续路线生成方式，请根据实际地块选择。
          </view>
          <view class="select-tabs">
            <view
              v-for="item in areaTypes"
              :key="item.value"
              class="select-tab"
              :class="{ active: selectedAreaType === item.value }"
              @click="selectAreaType(item.value)"
            >
              <text class="select-tab-label">{{ item.label }}</text>
              <text class="select-tab-sub" v-if="item.desc">
                {{ item.desc }}
              </text>
            </view>
          </view>
        </view>

        <view class="card select-card">
          <view class="select-title">选择路线类型</view>
          <view class="select-sub">
            依据区域形状推荐的路线类型，后端将按所选类型生成具体作业路线。
          </view>
          <view class="select-tabs">
            <view
              v-for="route in availableRouteTypes"
              :key="route.value"
              class="select-tab small"
              :class="{ active: selectedRouteType === route.value }"
              @click="selectRouteType(route.value)"
            >
              <text class="select-tab-label">{{ route.label }}</text>
              <text class="select-tab-sub" v-if="route.desc">
                {{ route.desc }}
              </text>
            </view>
          </view>
        </view>

        <view class="card tips-card">
          <view class="tips-title">说明</view>
          <view class="tips-content">
            <text>
              - 本步骤仅选择区域类型与路线类型，下一步将进入地图打点新增作业区域。
            </text>
            <text>
              - 当前选择会随作业一起提交至后端，用于指导路线生成策略。
            </text>
          </view>
        </view>
      </view>

      <!-- Step 2: 地图打点 -->
      <view v-else-if="currentStep === 2" class="step-block">
        <!-- 地图占位 -->
        <view class="map-card">
          <view class="map-header">
            <text class="map-title">地图预览</text>
            <view class="map-header-actions">
              <button class="btn-location" @click="manualLocation" :loading="locating">
                <text class="btn-location-text">{{ locating ? '定位中...' : '📍 定位' }}</text>
              </button>
            </view>
            <text class="map-sub">通过遥控器移动设备，在地图上逐点记录</text>
          </view>
          <view class="map-body">
            <!-- 始终渲染地图容器以避免渲染时序问题；未加载脚本时容器为空白 -->
            <view id="mapContainer"></view>
            <text v-if="!amapLoaded" class="map-placeholder">
              地图占位（H5 平台会加载高德地图 SDK）{{
                '\n'
              }}当前模式：{{ modeLabel }}
            </text>
          </view>
          <view class="map-footer">
            <text class="map-hint">
              提示：请使用遥控器移动设备到拐点位置，再点击“新增点”记录坐标。
            </text>
          </view>
        </view>

        <!-- 模式切换 -->
        <view class="mode-card">
          <view class="mode-title-row">
            <text class="mode-title">点位类型</text>
            <text class="mode-sub">在不同模式下分别记录作业区域、障碍物和返航点</text>
          </view>
          <view class="mode-tabs">
            <view
              v-for="item in modes"
              :key="item.value"
              class="mode-tab"
              :class="{ active: mode === item.value }"
              @click="switchMode(item.value)"
            >
              <text class="mode-tab-label">{{ item.label }}</text>
            </view>
          </view>
        </view>

        <!-- 控制面板 -->
        <view class="panel-card">
          <view class="panel-row">
            <button class="btn primary" @click="addPoint">新增点</button>
            <button class="btn ghost" @click="undoPoint" :disabled="!canUndo">
              撤销
            </button>
            <button
              class="btn ghost"
              v-if="mode === 'obstacle'"
              @click="finishCurrentObstacle"
              :disabled="!currentObstacle.length"
            >
              完成当前障碍物
            </button>
          </view>
          <view class="panel-desc">
            <text v-if="mode === 'area'">
              作业区域至少需要 3 个点，建议为近似矩形。
            </text>
            <text v-else-if="mode === 'obstacle'">
              每个障碍物可记录多个点，点击“完成当前障碍物”结束本组记录。
            </text>
            <text v-else>
              仅允许 1 个返航点，重复新增会覆盖已有点。
            </text>
          </view>
        </view>

        <!-- 已记录点列表 -->
        <view class="list-card">
          <view class="list-title-row">
            <text class="list-title">已记录点位</text>
          </view>

          <scroll-view scroll-y class="list-scroll">
            <!-- 作业区域点 -->
            <view class="list-group">
              <view class="list-group-header">
                <text class="list-group-title">作业区域点（{{ jobState.areaPoints.length }}）</text>
              </view>
              <view
                v-if="jobState.areaPoints.length"
                class="point-list"
              >
                <view
                  v-for="(p, index) in jobState.areaPoints"
                  :key="'area-' + index"
                  class="point-item"
                >
                  <text class="point-label">P{{ index + 1 }}</text>
                  <text class="point-coord">
                    {{ formatPoint(p) }}
                  </text>
                  <text class="point-time">{{ formatPointTime(p.timestamp) }}</text>
                </view>
              </view>
              <view v-else class="empty-row">
                <text>暂未记录作业区域点</text>
              </view>
            </view>

            <!-- 障碍物点 -->
            <view class="list-group">
              <view class="list-group-header">
                <text class="list-group-title">
                  障碍物（{{ jobState.obstacles.length + (currentObstacle.length ? 1 : 0) }} 组）
                </text>
              </view>
              <view
                v-if="jobState.obstacles.length || currentObstacle.length"
                class="obstacle-list"
              >
                <!-- 已完成的障碍物组 -->
                <view
                  v-for="(obs, oIdx) in jobState.obstacles"
                  :key="'obs-' + oIdx"
                  class="obstacle-item"
                >
                  <text class="obstacle-title">障碍物 {{ oIdx + 1 }}（{{ obs.length }} 点）</text>
                  <view
                    v-for="(p, pIdx) in obs"
                    :key="'obs-' + oIdx + '-' + pIdx"
                    class="point-item small"
                  >
                    <text class="point-label">O{{ oIdx + 1 }}-{{ pIdx + 1 }}</text>
                    <text class="point-coord">
                      {{ formatPoint(p) }}
                    </text>
                  </view>
                </view>

                <!-- 正在录入中的障碍物（未点击“完成当前障碍物”之前也要实时回显） -->
                <view
                  v-if="currentObstacle.length"
                  class="obstacle-item"
                >
                  <text class="obstacle-title">障碍物 {{ jobState.obstacles.length + 1 }}（录入中，{{ currentObstacle.length }} 点）</text>
                  <view
                    v-for="(p, pIdx) in currentObstacle"
                    :key="'obs-current-' + pIdx"
                    class="point-item small"
                  >
                    <text class="point-label">O{{ jobState.obstacles.length + 1 }}-{{ pIdx + 1 }}</text>
                    <text class="point-coord">
                      {{ formatPoint(p) }}
                    </text>
                  </view>
                </view>
              </view>
              <view v-else class="empty-row">
                <text>暂未记录障碍物点</text>
              </view>
            </view>

            <!-- 返航点 -->
            <view class="list-group">
              <view class="list-group-header">
                <text class="list-group-title">返航点</text>
              </view>
              <view v-if="jobState.returnPoint" class="point-item">
                <text class="point-label">R</text>
                <text class="point-coord">
                  {{ formatPoint(jobState.returnPoint) }}
                </text>
                <text class="point-time">
                  {{ formatPointTime(jobState.returnPoint.timestamp) }}
                </text>
              </view>
              <view v-else class="empty-row">
                <text>暂未设置返航点</text>
              </view>
            </view>
          </scroll-view>
        </view>
      </view>

      <!-- Step 3: 起点选择 -->
      <view v-else-if="currentStep === 3" class="step-block">
        <view class="map-card small">
          <view class="map-header">
            <text class="map-title">选择起点</text>
            <text class="map-sub">
              从已记录的作业区域点中选择作业起点，可通过左右切换预览。
            </text>
          </view>
          <view class="map-body">
            <text class="map-placeholder">
              这里显示作业区域示意图（占位）{{
                '\n'
              }}当前起点：P{{ currentStartDisplay }}
            </text>
          </view>
        </view>

        <view class="panel-card">
          <view class="panel-row center">
            <button class="btn ghost" @click="prevStart" :disabled="!canChangeStart">
              上一个
            </button>
            <view class="start-index">
              <text class="start-index-text">
                起点：P{{ currentStartDisplay }}
              </text>
            </view>
            <button class="btn ghost" @click="nextStart" :disabled="!canChangeStart">
              下一个
            </button>
          </view>
          <view class="panel-desc">
            <text>
              提示：起点将决定设备的初始行进方向与作业顺序，后端会基于该起点生成具体路线。
            </text>
          </view>
        </view>

        <view class="list-card">
          <view class="list-title-row">
            <text class="list-title">作业区域点列表</text>
          </view>
          <scroll-view scroll-y class="list-scroll">
            <view
              v-for="(p, index) in jobState.areaPoints"
              :key="'start-' + index"
              class="point-item"
              :class="{ active: index === jobState.startPointIndex }"
              @click="setStartIndex(index)"
            >
              <text class="point-label">P{{ index + 1 }}</text>
              <text class="point-coord">{{ formatPoint(p) }}</text>
            </view>
          </scroll-view>
        </view>
      </view>

      <!-- Step 4: 作业信息确认 -->
      <view v-else-if="currentStep === 4" class="step-block">
        <view class="card confirm-card">
          <view class="confirm-title">
            <text>作业基本信息</text>
          </view>

          <view class="form-item required">
            <text class="label">作业名称</text>
            <input
              class="input"
              v-model="jobState.jobName"
              placeholder="请输入作业名称，如“Test device - 北区作业”"
            />
          </view>

          <view class="form-item required">
            <text class="label">地块ID</text>
            <input
              class="input"
              v-model="jobState.fieldId"
              placeholder="请输入地块ID"
              type="text"
            />
          </view>

          <view class="form-item required">
            <text class="label">路径宽度（厘米）</text>
            <input
              class="input"
              v-model="jobState.pathWidth"
              placeholder="请输入路径宽度，单位：厘米"
              type="number"
            />
          </view>

          <view class="summary-row">
            <text class="summary-label">作业区域类型</text>
            <text class="summary-value">{{ areaTypeLabel }}</text>
          </view>
          <view class="summary-row">
            <text class="summary-label">路线类型</text>
            <text class="summary-value">{{ routeTypeLabel }}</text>
          </view>
          <view class="summary-row">
            <text class="summary-label">作业区域点</text>
            <text class="summary-value">{{ jobState.areaPoints.length }} 个</text>
          </view>
          <view class="summary-row">
            <text class="summary-label">障碍物</text>
            <text class="summary-value">
              {{ jobState.obstacles.length }} 组
            </text>
          </view>
          <view class="summary-row">
            <text class="summary-label">返航点</text>
            <text class="summary-value">
              {{ jobState.returnPoint ? '已设置' : '未设置' }}
            </text>
          </view>
          <view class="summary-row">
            <text class="summary-label">起点索引</text>
            <text class="summary-value">
              P{{ currentStartDisplay }}
            </text>
          </view>
        </view>

        <view class="card tips-card">
          <view class="tips-title">说明</view>
          <view class="tips-content">
            <text>
              - 前端仅负责记录点位与基本配置，并在本页面完成数据完整性校验。
            </text>
            <text>
              - 路线生成、几何合法性校验以及调度逻辑由后端 `/api/job/create` 负责处理。
            </text>
          </view>
        </view>
      </view>
    </view>

    <!-- 步骤导航 -->
    <view class="footer">
      <button class="btn ghost" @click="prevStep" :disabled="currentStep === 1">
        上一步
      </button>
      <button
        class="btn primary"
        v-if="currentStep < 4"
        @click="nextStep"
      >
        下一步
      </button>
      <button
        class="btn primary"
        v-else
        :loading="submitting"
        @click="submitJob"
      >
        完成并提交
      </button>
    </view>
  </view>
</template>
<script setup>
import { ref, reactive, computed, nextTick } from 'vue'
import { onLoad, onReady, onUnload } from '@dcloudio/uni-app'
import { createJob, getRealtimeData } from '@/api/services/job.js'
import coordinateUtils from '@/utils/coordinateUtils.js'

// ==================== Reactive State ====================

// Simple values
const currentStep = ref(1)
const selectedAreaType = ref('loopArea')
const selectedRouteType = ref('loop')
const mode = ref('area')
const submitting = ref(false)
const locating = ref(false)
const map = ref(null)
const amapLoaded = ref(false)
const geolocation = ref(null)
const realtimeMarker = ref(null)
const realtimeTimer = ref(null)
const lastReportTime = ref(null)
const latestRealtimeLngLat = ref(null)
const polling = ref(false)
const loopPolygon = ref(null)
const loopReplaceIndex = ref(null)
const areaPolygon = ref(null)
const returnMarker = ref(null)
const amapKey = ref('9f2cac7ea18905dd3830cf7360a43a35')
const jscode = ref('41af52e416d1fd1b15020dac066cec86')

// Arrays
const currentObstacle = ref([])
const markers = ref([])
const obstacleMarkers = ref([])
const loopMarkers = ref([])

// Complex state object
const jobState = reactive({
  machineCode: '',
  machineId: '',
  areaType: 'loopArea',
  routeType: 'loop',
  areaPoints: [],
  obstacles: [],
  returnPoint: null,
  startPointIndex: 0,
  jobName: '',
  fieldId: '',
  pathWidth: 100
})

// Constants
const steps = ref([
  { id: 1, title: '区域与路线', sub: '选择作业区域类型与路线类型' },
  { id: 2, title: '打点建模', sub: '作业区域 / 障碍物 / 返航点' },
  { id: 3, title: '选择起点', sub: '确定作业起点位置' },
  { id: 4, title: '信息确认', sub: '填写作业名称并提交' }
])

const areaTypes = ref([
  {
    value: 'loopArea',
    label: '回字形区域',
    desc: '规则四边形地块，适合标准往返或回字形路线',
    routes: [{ value: 'loop', label: '回字形路线（loop）' }]
  },
  {
    value: 'bowArea',
    label: '弓子形区域',
    desc: '一侧为弧形或不规则，适合弓字形或自适应路线',
    routes: [{ value: 'bow', label: '弓子形路线（bow）' }]
  },
  {
    value: 'customArea',
    label: '自定义区域',
    desc: '任意多边形地块，路线由后端自适应规划',
    routes: [{ value: 'custom', label: '自定义路线（custom）' }]
  },
  {
    value: 'ridgeArea',
    label: '垄沟区域',
    desc: '存在大量垄沟或等距行的地块',
    routes: [{ value: 'ridge', label: '垄沟路线（ridge）' }]
  }
])

const modes = ref([
  { value: 'area', label: '作业区域点' },
  { value: 'obstacle', label: '障碍物点' },
  { value: 'return', label: '返航点' }
])

// ==================== Computed Properties ====================

const modeLabel = computed(() => {
  const m = modes.value.find(m => m.value === mode.value)
  return m ? m.label : ''
})

const canUndo = computed(() => {
  if (mode.value === 'area') {
    return jobState.areaPoints.length > 0
  }
  if (mode.value === 'obstacle') {
    return currentObstacle.value.length > 0
  }
  if (mode.value === 'return') {
    return !!jobState.returnPoint
  }
  return false
})

const canChangeStart = computed(() => {
  return jobState.areaPoints.length > 0
})

const currentStartDisplay = computed(() => {
  if (!jobState.areaPoints.length) return '-'
  return jobState.startPointIndex + 1
})

const areaTypeLabel = computed(() => {
  const a = areaTypes.value.find(a => a.value === jobState.areaType)
  return a ? a.label : ''
})

const availableRouteTypes = computed(() => {
  const a = areaTypes.value.find(a => a.value === selectedAreaType.value)
  return a ? a.routes : []
})

const routeTypeLabel = computed(() => {
  const list = areaTypes.value.reduce((acc, cur) => {
    if (cur.routes && cur.routes.length) {
      acc.push(...cur.routes)
    }
    return acc
  }, [])
  const r = list.find(r => r.value === jobState.routeType)
  return r ? r.label : jobState.routeType
})

// ==================== Helper Functions ====================

// Simple mock function for current point
function mockCurrentPoint(baseIndex = 0) {
  const now = Date.now()
  const lng = 120.0 + (baseIndex % 10) * 0.0001
  const lat = 30.0 + (baseIndex % 10) * 0.0001
  return {
    lng,
    lat,
    timestamp: now
  }
}

// ==================== Lifecycle Hooks ====================

onLoad((options) => {
  const { machineCode, id } = options || {}
  if (machineCode) {
    jobState.machineCode = machineCode 
    jobState.machineId = id
  }
})

onReady(() => {
  if (typeof window !== 'undefined' && typeof document !== 'undefined') {
    console.log('[job-create] onReady - loading AMap script')
    loadScript()
  }
})

onUnload(() => {
  clearRealtimePolling()
  clearAllMarkers()
})

// ==================== Map Functions ====================

const loadScript = () => {
  // #ifdef H5
  window.mapInit = () => {
    _createMapWhenReady()
  }

  const script = document.createElement('script')
  script.src = `https://webapi.amap.com/maps?v=2.0&key=${amapKey.value}&callback=mapInit`
  document.body.appendChild(script)
  amapLoaded.value = true
  // #endif
  // #ifndef H5
  console.warn('当前平台不支持动态加载高德地图脚本，请使用 uni-app 地图组件')
  // #endif
}

const _createMapWhenReady = () => {
  const createWhenReady = () => {
    // #ifdef H5
    const container = document.getElementById('mapContainer')
    if (!container) {
      setTimeout(createWhenReady, 200)
      return
    }
    // #endif

    const defaultCenter = [113.382, 22.5211]

    const createMapWithCenter = centerArr => {
      try {
        map.value = new AMap.Map('mapContainer', {
          center: centerArr || defaultCenter,
          zoom: 16
        })
      } catch (err) {
        console.error('[job-create] create map failed', err)
        return
      }

      try {
        if (AMap.TileLayer && typeof AMap.TileLayer.Satellite === 'function') {
          const sat = new AMap.TileLayer.Satellite()
          map.value.add(sat)
        }
      } catch (layerErr) {
        console.warn('[job-create] satellite layer failed', layerErr)
      }

      try {
        AMap.plugin('AMap.ToolBar', () => {
          const toolbar = new AMap.ToolBar()
          if (map.value && typeof map.value.addControl === 'function') {
            map.value.addControl(toolbar)
          }
        })
      } catch (pluginErr) {
        console.warn('[job-create] toolbar plugin failed', pluginErr)
      }

      AMap.plugin('AMap.Geolocation', () => {
        geolocation.value = new AMap.Geolocation({
          enableHighAccuracy: true,
          timeout: 10000,
          maximumAge: 0,
          convert: true,
          showButton: false,
          showMarker: false,
          showCircle: false,
          panToLocation: false,
          zoomToAccuracy: false,
          noIpLocate: 0,
          GeoLocationFirst: true
        })
        console.log('[job-create] 高德定位插件加载完成')
        
        tryAutoLocation()
      })

      if (map.value && typeof map.value.on === 'function') {
        map.value.on('click', e => {
          const lng = e.lnglat && (e.lnglat.lng || (e.lnglat.getLng && e.lnglat.getLng()))
          const lat = e.lnglat && (e.lnglat.lat || (e.lnglat.getLat && e.lnglat.getLat()))
          if (lng == null || lat == null) return
          onMapClick({ lng, lat })
        })
      }

      setupRealtimePolling()
    }

    console.log('[job-create] 创建地图使用默认中心点:', defaultCenter)
    createMapWithCenter(defaultCenter)
  }

  createWhenReady()
}

const tryAutoLocation = () => {
  console.log('[job-create] 开始自动定位...')
  
  _getCurrentLocation(
    res => {
      console.log('[job-create] 自动定位成功:', res)
      const { longitude, latitude } = res || {}
      if (longitude != null && latitude != null) {
        console.log('[job-create] 使用定位坐标:', [longitude, latitude])
        _centerMapToLngLat(longitude, latitude, 16)
        uni.showToast({
          title: '已定位到您的位置',
          icon: 'success',
          duration: 2000
        })
      } else {
        console.warn('[job-create] 定位返回坐标无效')
      }
    },
    err => {
      console.warn('[job-create] 自动定位失败:', err)
    }
  )
}

const _getDeviceLocationAndCenter = () => {
  const doCenter = (lng, lat) => {
    if (!lng && lng !== 0) return
    if (!lat && lat !== 0) return
    _centerMapToLngLat(lng, lat, 18)
    try {
      if (map.value && typeof AMap !== 'undefined' && AMap.Marker) {
        new AMap.Marker({
          position: [lng, lat],
          map: map.value
        })
      }
    } catch (err) {
      console.warn('[job-create] add marker failed', err)
    }
  }

  _getCurrentLocation(
    res => {
      console.log("当前定位", res)
      const { longitude, latitude } = res || {}
      if (longitude != null && latitude != null) {
        doCenter(longitude, latitude)
      } else {
        const p = getMapCenterPoint() || mockCurrentPoint(0)
        doCenter(p.lng, p.lat)
      }
    },
    () => {
      const p = getMapCenterPoint() || mockCurrentPoint(0)
      doCenter(p.lng, p.lat)
    }
  )

  const p = getMapCenterPoint() || mockCurrentPoint(0)
  doCenter(p.lng, p.lat)
}

const _centerMapToLngLat = (lng, lat, zoom = 18) => {
  if (!map.value) return
  try {
    if (typeof map.value.setCenter === 'function') {
      map.value.setCenter([lng, lat])
    }
    if (typeof map.value.setZoom === 'function' && typeof zoom === 'number') {
      map.value.setZoom(zoom)
    }
  } catch (err) {
    console.warn('[job-create] center map failed', err)
  }
}

const _getCurrentLocation = (successCallback, failCallback, retryCount = 0) => {
  if (!geolocation.value) {
    if (retryCount < 5) {
      console.log(`[job-create] 高德定位未初始化，${retryCount + 1}秒后重试...`)
      setTimeout(() => {
        _getCurrentLocation(successCallback, failCallback, retryCount + 1)
      }, 1000)
      return
    } else {
      console.warn('[job-create] 高德定位未初始化，重试失败')
      if (failCallback) failCallback(new Error('高德定位未初始化'))
      return
    }
  }

  console.log('[job-create] 开始调用高德定位 getCurrentPosition...')
  
  geolocation.value.getCurrentPosition((status, result) => {
    console.log('[job-create] 定位回调 status:', status, 'result:', result)
    
    if (status === 'complete') {
      const { lng, lat } = result.position
      console.log('[job-create] 高德定位成功:', { lng, lat })
      if (successCallback) {
        successCallback({
          longitude: lng,
          latitude: lat
        })
      }
    } else {
      console.error('[job-create] 高德定位失败:', result)
      let errorMsg = '定位失败'
      let errorDetail = ''
      
      switch(result.info) {
        case 'FAILED':
          errorMsg = '定位失败，请检查网络连接'
          errorDetail = '可能原因：网络问题或GPS信号弱'
          break
        case 'NOT_SUPPORTED':
          errorMsg = '浏览器不支持定位功能'
          errorDetail = '请使用支持地理定位的现代浏览器'
          break
        case 'PERMISSION_DENIED':
          errorMsg = '定位权限被拒绝'
          errorDetail = 'HTTPS环境下需要用户授权定位权限，HTTP环境下浏览器会直接拒绝'
          break
        case 'PERMISSION_GRANTED':
          errorMsg = '定位权限已获取但定位失败'
          errorDetail = '可能是GPS信号问题'
          break
        case 'TIMEOUT':
          errorMsg = '定位请求超时'
          errorDetail = '请检查网络连接或GPS信号'
          break
        default:
          errorMsg = `定位失败: ${result.info}`
          errorDetail = result.message || ''
      }
      
      console.warn('[job-create] 定位失败详情:', errorMsg, errorDetail)
      
      if (failCallback) {
        failCallback({ 
          code: result.info, 
          message: errorMsg,
          detail: errorDetail
        })
      }
    }
  })
}

const getMapCenterPoint = () => {
  if (map.value && typeof map.value.getCenter === 'function') {
    const c = map.value.getCenter()
    return {
      lng: c.lng || (c.lng === 0 ? 0 : c.getLng && c.getLng()),
      lat: c.lat || (c.lat === 0 ? 0 : c.getLat && c.getLat()),
      timestamp: Date.now()
    }
  }
  return null
}

// ==================== UI Interaction Functions ====================

const selectAreaType = (val) => {
  selectedAreaType.value = val
  const a = areaTypes.value.find(item => item.value === val)
  if (a && a.routes && a.routes.length) {
    selectedRouteType.value = a.routes[0].value
  }
  jobState.areaType = selectedAreaType.value
  jobState.routeType = selectedRouteType.value
}

const selectRouteType = (val) => {
  selectedRouteType.value = val
  jobState.routeType = val
}

const switchMode = (val) => {
  mode.value = val
}

// ==================== Real-time Polling Functions ====================

const setupRealtimePolling = () => {
  if (currentStep.value !== 2) return

  const deviceId = jobState.machineId || jobState.machineCode
  if (!deviceId) return
  if (!amapLoaded.value || !map.value) return

  if (realtimeTimer.value) return

  fetchRealtimeAndUpdate()

  realtimeTimer.value = setInterval(() => {
    fetchRealtimeAndUpdate()
  }, 3000)
}

const clearRealtimePolling = () => {
  if (realtimeTimer.value) {
    clearInterval(realtimeTimer.value)
    realtimeTimer.value = null
  }
  polling.value = false
}

const fetchRealtimeAndUpdate = async () => {
  try {
    const deviceId = jobState.machineCode
    if (!deviceId) return

    polling.value = true
    const res = await getRealtimeData(deviceId)
    const payload = res && res.data && (res.data.data || res.data)
    if (!payload) return

    const reportTime = payload.reportTime
    if (reportTime && lastReportTime.value && reportTime < lastReportTime.value) {
      return
    }
    if (reportTime) lastReportTime.value = reportTime

    const pt = payload.currentPoint
    if (!pt || pt.x == null || pt.y == null) return

    const lngLat = [pt.x, pt.y]
    latestRealtimeLngLat.value = lngLat

    updateRealtimeMarker(lngLat)

    try {
      if (map.value && typeof map.value.setCenter === 'function') {
        map.value.setCenter(lngLat)
      }
    } catch (e) {}
  } catch (e) {
    console.warn('[job-create] fetchRealtimeAndUpdate failed', e)
  } finally {
    polling.value = false
  }
}

const updateRealtimeMarker = (lngLat) => {
  if (!map.value || !amapLoaded.value) return
  if (!lngLat || lngLat.length !== 2) return

  if (!realtimeMarker.value) {
    realtimeMarker.value = new AMap.Marker({
      map: map.value,
      position: lngLat
    })
  } else {
    realtimeMarker.value.setPosition(lngLat)
  }
}

// ==================== Point Management Functions ====================

const addPoint = () => {
  const realtimeLngLat = latestRealtimeLngLat.value
  const realtimePoint = realtimeLngLat && realtimeLngLat.length === 2
    ? { lng: realtimeLngLat[0], lat: realtimeLngLat[1], timestamp: Date.now() }
    : null

  let centerPoint = null
  if (amapLoaded.value && map.value) {
    centerPoint = getMapCenterPoint()
  }

  const fallbackPoint = centerPoint || mockCurrentPoint(0)
  const point = realtimePoint || fallbackPoint

  if (mode.value === 'area') {
    onMapClick({ lng: point.lng, lat: point.lat })
  } else if (mode.value === 'obstacle') {
    currentObstacle.value.push(point)
    addObstacleMarker(point, jobState.obstacles.length, currentObstacle.value.length - 1)
  } else if (mode.value === 'return') {
    if (jobState.returnPoint) {
      uni.showModal({
        title: '覆盖返航点',
        content: '已存在返航点，是否覆盖为当前设备位置？',
        success: res => {
          if (res.confirm) {
            jobState.returnPoint = point
            updateReturnMarker(point)
          }
        }
      })
    } else {
      jobState.returnPoint = point
      updateReturnMarker(point)
    }
  }
}

const undoPoint = () => {
  if (!canUndo.value) return
  if (mode.value === 'area') {
    const lastIdx = jobState.areaPoints.length - 1
    if (lastIdx >= 0) {
      jobState.areaPoints.pop()
      const m = loopMarkers.value.pop()
      if (m && typeof m.setMap === 'function') {
        try { m.setMap(null) } catch (e) {}
      }
      if (jobState.areaPoints.length >= 3) {
        recomputeLoopPolygon()
      } else {
        if (loopPolygon.value && typeof loopPolygon.value.setMap === 'function') {
          try { loopPolygon.value.setMap(null) } catch (e) {}
        }
        loopPolygon.value = null
      }
    }
  } else if (mode.value === 'obstacle') {
    currentObstacle.value.pop()
    removeLastObstacleMarker()
  } else if (mode.value === 'return') {
    jobState.returnPoint = null
    clearReturnMarker()
  }
}

const finishCurrentObstacle = () => {
  if (!currentObstacle.value.length) return
  jobState.obstacles.push([...currentObstacle.value])
  currentObstacle.value = []
  uni.showToast({
    title: '已保存一组障碍物',
    icon: 'success'
  })
}

const flushCurrentObstacle = () => {
  if (currentObstacle.value && currentObstacle.value.length) {
    jobState.obstacles.push([...currentObstacle.value])
    currentObstacle.value = []
  }
}

// ==================== Step Navigation Functions ====================

const prevStep = () => {
  if (currentStep.value === 1) return
  currentStep.value -= 1

  if (currentStep.value !== 2) {
    clearRealtimePolling()
  }
}

const nextStep = () => {
  if (currentStep.value === 1) {
    if (!selectedAreaType.value || !selectedRouteType.value) {
      uni.showToast({
        title: '请选择作业区域类型和路线类型',
        icon: 'none'
      })
      return
    }
    jobState.areaType = selectedAreaType.value
    jobState.routeType = selectedRouteType.value
  }
  
  if (currentStep.value === 2) {
    if (jobState.areaPoints.length < 3) {
      uni.showToast({
        title: '作业区域点至少需要 3 个',
        icon: 'none'
      })
      return
    }

    flushCurrentObstacle()

    if (!jobState.returnPoint) {
      uni.showToast({
        title: '请先设置返航点',
        icon: 'none'
      })
      return
    }
  }
  
  if (currentStep.value === 3) {
    if (!jobState.areaPoints.length) {
      uni.showToast({
        title: '请先在上一步记录作业区域点',
        icon: 'none'
      })
      return
    }
  }
  
  if (currentStep.value < 4) {
    currentStep.value += 1

    if (currentStep.value === 2) {
      setupRealtimePolling()
    } else {
      clearRealtimePolling()
    }
  }
}

// ==================== Start Point Selection Functions ====================

const setStartIndex = (index) => {
  if (!jobState.areaPoints.length) return
  jobState.startPointIndex = index
}

const prevStart = () => {
  if (!canChangeStart.value) return
  const total = jobState.areaPoints.length
  jobState.startPointIndex =
    (jobState.startPointIndex - 1 + total) % total
}

const nextStart = () => {
  if (!canChangeStart.value) return
  const total = jobState.areaPoints.length
  jobState.startPointIndex =
    (jobState.startPointIndex + 1) % total
}

// ==================== Manual Location Function ====================

const manualLocation = async () => {
  if (locating.value) return
  locating.value = true

  const doCenter = (lng, lat) => {
    if (!lng && lng !== 0) return
    if (!lat && lat !== 0) return
    _centerMapToLngLat(lng, lat, 18)
    uni.showToast({
      title: '已定位到您的位置',
      icon: 'success',
      duration: 2000
    })
  }

  try {
    const isSecureContext = window.isSecureContext || window.location.protocol === 'https:'
    if (!isSecureContext) {
      console.warn('[job-create] 非HTTPS环境，浏览器可能拒绝定位请求')
      uni.showModal({
        title: '定位提示',
        content: '当前为HTTP环境，浏览器可能拒绝定位请求。建议使用HTTPS访问或使用IP定位。',
        showCancel: false
      })
    }

    await new Promise((resolve, reject) => {
      _getCurrentLocation(
        res => {
          const { longitude, latitude } = res || {}
          if (longitude != null && latitude != null) {
            doCenter(longitude, latitude)
            resolve()
          } else {
            reject(new Error('无效坐标'))
          }
        },
        reject
      )
    })
  } catch (err) {
    console.error('[job-create] 手动定位失败:', err)
    let errorMsg = '定位失败'
    let showDetail = false
    
    if (err.message) {
      errorMsg = err.message
    }
    if (err.detail) {
      showDetail = true
    }
    
    if (showDetail) {
      uni.showModal({
        title: errorMsg,
        content: err.detail || '请检查浏览器定位权限设置，或确保使用HTTPS访问',
        showCancel: false
      })
    } else {
      uni.showToast({
        title: errorMsg,
        icon: 'none',
        duration: 3000
      })
    }
  } finally {
    locating.value = false
  }
}

// ==================== Submit Job Function ====================

const submitJob = async () => {
  if (!jobState.jobName) {
    uni.showToast({
      title: '请填写作业名称',
      icon: 'none'
    })
    return
  }
  if (!jobState.fieldId) {
    uni.showToast({
      title: '请填写地块ID',
      icon: 'none'
    })
    return
  }
  if (!jobState.pathWidth) {
    uni.showToast({
      title: '请填写路径宽度',
      icon: 'none'
    })
    return
  }
  if (jobState.areaPoints.length < 3) {
    uni.showToast({
      title: '作业区域点至少需要 3 个',
      icon: 'none'
    })
    return
  }

  flushCurrentObstacle()

  const convertedAreaPoints = coordinateUtils.convertPointsToWgs84(jobState.areaPoints)
  const convertedObstacles = jobState.obstacles.map(obstacleGroup =>
    coordinateUtils.convertPointsToWgs84(obstacleGroup)
  )
  const convertedReturnPoint = jobState.returnPoint ?
    coordinateUtils.convertPointToWgs84(jobState.returnPoint) : undefined

  const areaTypeMap = {
    'loopArea': 1,
    'bowArea': 2,
    'customArea': 3,
    'ridgeArea': 4
  }
  
  console.log("jobState", jobState)
  
  const payload = {
    deviceId: jobState.machineId,
    fieldId: parseInt(jobState.fieldId),
    taskName: jobState.jobName,
    areaType: areaTypeMap[jobState.areaType] || 1,
    waypoints: convertedAreaPoints.map(p => ({ lng: p.lng, lat: p.lat })),
    obstacles: convertedObstacles.flat().map(p => ({ lng: p.lng, lat: p.lat })),
    returnPoint: convertedReturnPoint ? { lng: convertedReturnPoint.lng, lat: convertedReturnPoint.lat } : undefined,
    pathWidth: parseInt(jobState.pathWidth)
  }
  
  console.log("payload", payload)

  submitting.value = true
  uni.showLoading({ title: '提交中...' })
  try {
    const res = await createJob(payload)
    console.log("res收到尽快发货", res)
    
    const { data } = res || {}
    if (data && data.code === 200) {
      uni.showToast({
        title: '作业创建成功',
        icon: 'success'
      })
      setTimeout(() => {
        uni.navigateBack()
      }, 800)
    } else {
      uni.showToast({
        title: (data && data.msg) || '提交失败',
        icon: 'none'
      })
    }
  } catch (err) {
    console.error('创建作业失败', err)
    uni.showToast({
      title: '网络异常或接口未就绪',
      icon: 'none'
    })
  } finally {
    submitting.value = false
    uni.hideLoading()
  }
}

// ==================== Map Click Handler ====================

const onMapClick = ({ lng, lat } = {}) => {
  if (!lng && lng !== 0) return
  if (!lat && lat !== 0) return
  
  if (mode.value !== 'area') return

  const newPoint = { lng, lat, timestamp: Date.now() }

  if (loopReplaceIndex.value != null && loopReplaceIndex.value >= 0 && loopReplaceIndex.value < jobState.areaPoints.length) {
    jobState.areaPoints.splice(loopReplaceIndex.value, 1, newPoint)
    const m = loopMarkers.value[loopReplaceIndex.value]
    if (m && typeof m.setPosition === 'function') {
      try { m.setPosition([lng, lat]) } catch (e) {}
    }
    loopReplaceIndex.value = null
    if (jobState.areaPoints.length >= 3) recomputeLoopPolygon()
    return
  }
  
  jobState.areaPoints.push(newPoint)
  const idx = jobState.areaPoints.length - 1
  createOrUpdateLoopMarker(idx, newPoint)
  if (jobState.areaPoints.length >= 3) {
    recomputeLoopPolygon()
  }
}

const createOrUpdateLoopMarker = (index, point) => {
  if (!map.value || typeof AMap === 'undefined') return
  const pos = [point.lng, point.lat]
  let marker = loopMarkers.value[index]
  if (marker) {
    try { marker.setPosition(pos) } catch (e) {}
    return
  }
  
  let icon = null
  try {
    icon = new AMap.Icon({
      image: "static/icons/poi-marker-default.png",
      size: new AMap.Size(20, 28),
      imageSize: new AMap.Size(20, 28)
    })
  } catch (e) {
    icon = "static/icons/poi-marker-default.png"
  }
  
  marker = new AMap.Marker({
    position: pos,
    map: map.value,
    draggable: true,
    icon,
    offset: new AMap.Pixel(-10, -28)
  })
  
  try {
    const labelContent = `<div class="p-marker-label">P${index + 1}</div>`
    if (typeof marker.setLabel === 'function') {
      marker.setLabel({
        content: labelContent,
        offset: new AMap.Pixel(10, -36)
      })
    } else {
      marker.label = { content: labelContent }
    }
  } catch (e) {}
  
  marker.on('dragend', e => {
    const p = marker.getPosition()
    const lngv = p.lng || (p.getLng && p.getLng())
    const latv = p.lat || (p.getLat && p.getLat())
    if (lngv == null || latv == null) return
    jobState.areaPoints[index] = { lng: lngv, lat: latv, timestamp: Date.now() }
    if (jobState.areaPoints.length >= 3) recomputeLoopPolygon()
  })
  
  marker.on('click', () => {
    loopReplaceIndex.value = index
    uni.showToast({ title: `已选中 P${index + 1}，下一次点击将替换该点`, icon: 'none' })
  })
  
  loopMarkers.value[index] = marker
  refreshLoopMarkerLabels()
}

const recomputeLoopPolygon = () => {
  if (!map.value) return
  if (!jobState.areaPoints || jobState.areaPoints.length < 3) {
    if (loopPolygon.value && typeof loopPolygon.value.setMap === 'function') {
      try { loopPolygon.value.setMap(null) } catch (e) {}
    }
    loopPolygon.value = null
    return
  }

  const outer = jobState.areaPoints.map(p => [p.lng, p.lat])

  try {
    if (loopPolygon.value) {
      loopPolygon.value.setPath(outer)
    } else {
      loopPolygon.value = new AMap.Polygon({
        map: map.value,
        path: outer,
        strokeColor: '#3bb44a',
        strokeWeight: 2,
        fillColor: '#3bb44a',
        fillOpacity: 0.15
      })
    }
  } catch (err) {
    console.warn('[job-create] recompute loop polygon failed', err)
  }
}

const refreshLoopMarkerLabels = () => {
  if (!loopMarkers.value || !loopMarkers.value.length) return
  loopMarkers.value.forEach((m, i) => {
    try {
      const content = `<div class="p-marker-label">P${i + 1}</div>`
      if (typeof m.setLabel === 'function') {
        m.setLabel({ content, offset: new AMap.Pixel(10, -36) })
      } else if (m.label) {
        m.label.content = content
      }
    } catch (e) {}
  })
}

const clearLoopGraphics = () => {
  if (loopMarkers.value && loopMarkers.value.length) {
    loopMarkers.value.forEach(m => {
      try { m.setMap(null) } catch (e) {}
    })
  }
  loopMarkers.value = []
  if (loopPolygon.value && typeof loopPolygon.value.setMap === 'function') {
    try { loopPolygon.value.setMap(null) } catch (e) {}
  }
  loopPolygon.value = null
  loopReplaceIndex.value = null
}

const deleteAreaPoints = () => {
  jobState.areaPoints = []
  clearLoopGraphics()
}

// ==================== Formatting Functions ====================

const formatPoint = (p) => {
  if (!p) return '--'
  return `${p.lng.toFixed(5)}, ${p.lat.toFixed(5)}`
}

const formatPointTime = (ts) => {
  if (!ts) return ''
  const d = new Date(ts)
  const h = `${d.getHours()}`.padStart(2, '0')
  const m = `${d.getMinutes()}`.padStart(2, '0')
  const s = `${d.getSeconds()}`.padStart(2, '0')
  return `${h}:${m}:${s}`
}

// ==================== Obstacle Marker Functions ====================

const addObstacleMarker = (point, obstacleGroupIndex, pointIndex) => {
  if (!map.value || !amapLoaded.value || typeof AMap === 'undefined') return
  
  try {
    const pos = [point.lng, point.lat]
    
    let icon = null
    try {
      icon = new AMap.Icon({
        image: "static/icons/poi-marker-default.png",
        size: new AMap.Size(16, 22),
        imageSize: new AMap.Size(16, 22)
      })
    } catch (e) {
      icon = "static/icons/poi-marker-default.png"
    }

    const marker = new AMap.Marker({
      position: pos,
      map: map.value,
      icon,
      offset: new AMap.Pixel(-8, -22)
    })

    try {
      const labelContent = `<div class="obstacle-marker-label">O${obstacleGroupIndex + 1}-${pointIndex + 1}</div>`
      if (typeof marker.setLabel === 'function') {
        marker.setLabel({
          content: labelContent,
          offset: new AMap.Pixel(8, -28)
        })
      }
    } catch (e) {}

    if (!obstacleMarkers.value[obstacleGroupIndex]) {
      obstacleMarkers.value[obstacleGroupIndex] = []
    }
    obstacleMarkers.value[obstacleGroupIndex].push(marker)
  } catch (err) {
    console.warn('[job-create] add obstacle marker failed', err)
  }
}

const removeLastObstacleMarker = () => {
  const currentGroupIndex = jobState.obstacles.length
  if (obstacleMarkers.value[currentGroupIndex] && obstacleMarkers.value[currentGroupIndex].length > 0) {
    const marker = obstacleMarkers.value[currentGroupIndex].pop()
    if (marker && typeof marker.setMap === 'function') {
      try {
        marker.setMap(null)
      } catch (e) {}
    }
  }
}

// ==================== Return Marker Functions ====================

const updateReturnMarker = (point) => {
  if (!map.value || !amapLoaded.value || typeof AMap === 'undefined') return
  
  try {
    const pos = [point.lng, point.lat]
    
    clearReturnMarker()

    let icon = null
    try {
      icon = new AMap.Icon({
        image: "static/icons/poi-marker-default.png",
        size: new AMap.Size(20, 28),
        imageSize: new AMap.Size(20, 28)
      })
    } catch (e) {
      icon = "static/icons/poi-marker-default.png"
    }

    returnMarker.value = new AMap.Marker({
      position: pos,
      map: map.value,
      icon,
      offset: new AMap.Pixel(-10, -28)
    })

    try {
      const labelContent = '<div class="return-marker-label">返航点</div>'
      if (typeof returnMarker.value.setLabel === 'function') {
        returnMarker.value.setLabel({
          content: labelContent,
          offset: new AMap.Pixel(10, -36)
        })
      }
    } catch (e) {}
  } catch (err) {
    console.warn('[job-create] update return marker failed', err)
  }
}

const clearReturnMarker = () => {
  if (returnMarker.value && typeof returnMarker.value.setMap === 'function') {
    try {
      returnMarker.value.setMap(null)
    } catch (e) {}
  }
  returnMarker.value = null
}

// ==================== Cleanup Functions ====================

const clearAllMarkers = () => {
  if (loopMarkers.value && loopMarkers.value.length) {
    loopMarkers.value.forEach(m => {
      try {
        if (m && typeof m.setMap === 'function') {
          m.setMap(null)
        }
      } catch (e) {}
    })
    loopMarkers.value = []
  }

  if (obstacleMarkers.value && obstacleMarkers.value.length) {
    obstacleMarkers.value.forEach(group => {
      if (group && group.length) {
        group.forEach(m => {
          try {
            if (m && typeof m.setMap === 'function') {
              m.setMap(null)
            }
          } catch (e) {}
        })
      }
    })
    obstacleMarkers.value = []
  }

  clearReturnMarker()

  if (realtimeMarker.value && typeof realtimeMarker.value.setMap === 'function') {
    try {
      realtimeMarker.value.setMap(null)
    } catch (e) {}
    realtimeMarker.value = null
  }

  if (loopPolygon.value && typeof loopPolygon.value.setMap === 'function') {
    try {
      loopPolygon.value.setMap(null)
    } catch (e) {}
    loopPolygon.value = null
  }
}
</script>
<style scoped>
.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background-color: #f6f9f7;
}

.header {
  padding: 24rpx 28rpx 12rpx;
}

.title-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 12rpx;
}

.title {
  font-size: 34rpx;
  font-weight: 600;
  color: #2c3e50;
}

.device-id {
  font-size: 24rpx;
  color: #8c9396;
}

.step-row {
  display: flex;
  padding: 10rpx 8rpx;
  border-radius: 16rpx;
  background-color: #eef6f0;
}

.step-item {
  flex: 1;
  display: flex;
  align-items: center;
}

.step-index {
  width: 36rpx;
  height: 36rpx;
  border-radius: 18rpx;
  border: 2rpx solid #b0c4b8;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22rpx;
  color: #7f8c8d;
  margin-right: 10rpx;
}

.step-index.active {
  background: linear-gradient(135deg, #3bb44a, #66cc6a);
  color: #ffffff;
  border-color: transparent;
}

.step-index.done {
  background-color: #ffffff;
  color: #3bb44a;
  border-color: #3bb44a;
}

.step-texts {
  display: flex;
  flex-direction: column;
}

.step-title {
  font-size: 24rpx;
  color: #2c3e50;
}

.step-sub {
  font-size: 20rpx;
  color: #8c9396;
}

.content {
  flex: 1;
  padding: 10rpx 24rpx 130rpx;
  box-sizing: border-box;
}

.step-block {
  display: flex;
  flex-direction: column;
  gap: 18rpx;
}

/* 区域类型 & 路线类型选择卡片 */
.card.select-card {
  background-color: #ffffff;
  border-radius: 20rpx;
  padding: 20rpx 22rpx 16rpx;
  box-shadow: 0 4rpx 14rpx rgba(0, 0, 0, 0.03);
}

.select-title {
  font-size: 26rpx;
  font-weight: 600;
  color: #2c3e50;
}

.select-sub {
  margin-top: 6rpx;
  font-size: 22rpx;
  color: #8c9396;
  line-height: 1.5;
}

.select-tabs {
  margin-top: 14rpx;
  display: flex;
  flex-wrap: wrap;
  gap: 12rpx;
}

.select-tab {
  min-width: 46%;
  padding: 14rpx 16rpx;
  border-radius: 16rpx;
  background-color: #f3f5f7;
  box-sizing: border-box;
}

.select-tab.small {
  min-width: 30%;
}

.select-tab-label {
  font-size: 24rpx;
  color: #2c3e50;
}

.select-tab-sub {
  margin-top: 4rpx;
  font-size: 20rpx;
  color: #8c9396;
}

.select-tab.active {
  background: linear-gradient(135deg, #3bb44a, #66cc6a);
  box-shadow: 0 4rpx 12rpx rgba(59, 180, 74, 0.26);
}

.select-tab.active .select-tab-label,
.select-tab.active .select-tab-sub {
  color: #ffffff;
}

.map-card {
  background-color: #ffffff;
  border-radius: 20rpx;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
  overflow: hidden;
}

.map-card.small .map-body {
  height: 260rpx;
}

.map-header {
  padding: 20rpx 22rpx 10rpx;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.map-header-actions {
  margin-left: 20rpx;
}

.map-title {
  font-size: 28rpx;
  font-weight: 600;
  color: #2c3e50;
}

.map-sub {
  margin-top: 4rpx;
  font-size: 22rpx;
  color: #8c9396;
}

.map-body {
  height: 320rpx;
  background-color: #d3dce6;
  display: flex;
  align-items: center;
  justify-content: center;
}

.map-placeholder {
  font-size: 24rpx;
  color: #ffffff;
  text-align: center;
  white-space: pre-line;
  width: 100%;
}

/* AMap 容器样式（确保占满 map-body） */
#mapContainer {
  width: 100%;
  height: 100%;
}

.map-footer {
  padding: 12rpx 18rpx 16rpx;
  background-color: #f7faf8;
}

.map-hint {
  font-size: 22rpx;
  color: #8c9396;
}

.mode-card {
  background-color: #ffffff;
  border-radius: 20rpx;
  padding: 18rpx 20rpx 14rpx;
  box-shadow: 0 4rpx 14rpx rgba(0, 0, 0, 0.03);
}

.mode-title-row {
  margin-bottom: 10rpx;
}

.mode-title {
  font-size: 26rpx;
  font-weight: 600;
  color: #2c3e50;
}

.mode-sub {
  margin-top: 4rpx;
  font-size: 22rpx;
  color: #8c9396;
}

.mode-tabs {
  display: flex;
  gap: 12rpx;
}

.mode-tab {
  flex: 1;
  padding: 12rpx 0;
  border-radius: 30rpx;
  background-color: #f3f5f7;
  text-align: center;
  font-size: 24rpx;
  color: #666;
}

.mode-tab.active {
  background: linear-gradient(135deg, #3bb44a, #66cc6a);
  color: #ffffff;
  box-shadow: 0 4rpx 12rpx rgba(59, 180, 74, 0.3);
}

.panel-card {
  background-color: #ffffff;
  border-radius: 20rpx;
  padding: 18rpx 20rpx 14rpx;
  box-shadow: 0 4rpx 14rpx rgba(0, 0, 0, 0.03);
}

.panel-row {
  display: flex;
  gap: 12rpx;
}

.panel-row.center {
  justify-content: space-between;
  align-items: center;
}

.panel-desc {
  margin-top: 8rpx;
  font-size: 22rpx;
  color: #8c9396;
}

.list-card {
  background-color: #ffffff;
  border-radius: 20rpx;
  padding: 18rpx 20rpx 10rpx;
  box-shadow: 0 4rpx 14rpx rgba(0, 0, 0, 0.03);
  max-height: 420rpx;
}

.list-title-row {
  margin-bottom: 6rpx;
}

.list-title {
  font-size: 26rpx;
  font-weight: 600;
  color: #2c3e50;
}

.list-scroll {
  max-height: 360rpx;
}

.list-group {
  margin-top: 10rpx;
}

.list-group-header {
  margin-bottom: 4rpx;
}

.list-group-title {
  font-size: 24rpx;
  color: #555;
}

.point-list {
  margin-top: 4rpx;
}

.point-item {
  padding: 8rpx 4rpx;
  border-bottom: 1rpx solid #f0f0f0;
  display: flex;
  align-items: center;
}

.point-item.small {
  padding-left: 20rpx;
}

.point-item.active {
  background-color: #f0f9f2;
}

.point-label {
  font-size: 22rpx;
  color: #3bb44a;
  margin-right: 8rpx;
}

.point-coord {
  flex: 1;
  font-size: 22rpx;
  color: #333;
}

.point-time {
  font-size: 20rpx;
  color: #999;
}

.obstacle-item {
  margin-top: 6rpx;
}

.obstacle-title {
  font-size: 22rpx;
  color: #666;
  margin-bottom: 2rpx;
}

.empty-row {
  padding: 12rpx 0;
  font-size: 22rpx;
  color: #999;
}

.start-index {
  flex: 1;
  align-items: center;
  justify-content: center;
  display: flex;
}

.start-index-text {
  font-size: 26rpx;
  color: #2c3e50;
}

.card.confirm-card {
  padding: 22rpx 24rpx 10rpx;
}

.confirm-title {
  font-size: 28rpx;
  font-weight: 600;
  color: #2c3e50;
  margin-bottom: 12rpx;
}

.form-item {
  margin-bottom: 16rpx;
}

.form-item.required .label::after {
  content: '*';
  color: #ff4d4f;
  margin-left: 4rpx;
}

.label {
  display: block;
  font-size: 26rpx;
  color: #555;
  margin-bottom: 8rpx;
}

.input {
  width: 100%;
  height: 80rpx;
  line-height: 80rpx;
  padding: 14rpx 18rpx;
  border-radius: 12rpx;
  background-color: #f7f7f7;
  font-size: 26rpx;
  color: #333;
  box-sizing: border-box;
}

.summary-row {
  display: flex;
  justify-content: space-between;
  padding: 8rpx 0;
  border-bottom: 1rpx solid #f0f0f0;
}

.summary-label {
  font-size: 24rpx;
  color: #777;
}

.summary-value {
  font-size: 24rpx;
  color: #333;
}

.tips-card {
  padding: 20rpx 22rpx 16rpx;
}

.tips-title {
  font-size: 26rpx;
  color: #2c3e50;
  font-weight: 600;
  margin-bottom: 6rpx;
}

.tips-content text {
  display: block;
  font-size: 22rpx;
  color: #666;
  margin-top: 4rpx;
}

.footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 12rpx 26rpx 24rpx;
  background-color: #ffffff;
  box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
  display: flex;
  gap: 12rpx;
  box-sizing: border-box;
}

.btn {
  flex: 1;
  height: 84rpx;
  line-height: 84rpx;
  border-radius: 42rpx;
  font-size: 28rpx;
}

.btn.primary {
  background: linear-gradient(135deg, #3bb44a, #66cc6a);
  color: #ffffff;
}

.btn.ghost {
  background-color: #f4f5f7;
  color: #555;
}

.btn:disabled {
  opacity: 0.5;
}

.btn-location {
  padding: 8rpx 16rpx;
  border-radius: 20rpx;
  background-color: #f0f9f2;
  border: 1rpx solid #3bb44a;
  font-size: 24rpx;
  color: #3bb44a;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 120rpx;
  height: 56rpx;
  box-sizing: border-box;
}

.btn-location-text {
  font-size: 24rpx;
  color: #3bb44a;
}

/* 任务标题行新增作业按钮样式（与详情页保持风格一致） */
.task-title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.task-title-left {
  display: flex;
  flex-direction: column;
}

.task-title-text {
  font-size: 32rpx;
  font-weight: 600;
  color: #2c3e50;
}

.task-title-sub {
  margin-top: 4rpx;
  font-size: 22rpx;
  color: #8c9396;
}

.task-add-btn {
  width: 60rpx;
  height: 60rpx;
  border-radius: 30rpx;
  background: linear-gradient(135deg, #3bb44a, #66cc6a);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4rpx 12rpx rgba(59, 180, 74, 0.3);
}

.task-add-plus {
  font-size: 40rpx;
  color: #ffffff;
  line-height: 1;
}

.p-marker-label {
  background: rgba(59,180,74,0.95);
  color: #fff;
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 18rpx;
  line-height: 1;
}

.obstacle-marker-label {
  background: rgba(255, 152, 0, 0.95);
  color: #fff;
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 16rpx;
  line-height: 1;
}

.return-marker-label {
  background: rgba(33, 150, 243, 0.95);
  color: #fff;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 18rpx;
  line-height: 1;
  font-weight: 600;
}
</style>