New file |
| | |
| | | <template> |
| | | <view class="map-selector-container"> |
| | | <view class="search-bar"> |
| | | <input |
| | | class="search-input" |
| | | placeholder="请输入地址" |
| | | v-model="searchKeyword" |
| | | @input="onSearchInput" |
| | | @focus="onSearchFocus" |
| | | /> |
| | | <button class="search-btn" @click="searchAddress">搜索</button> |
| | | </view> |
| | | |
| | | <!-- 微信小程序使用原生map组件 --> |
| | | <view class="map-container" id="mapContainer"> |
| | | <!-- #ifdef MP-WEIXIN --> |
| | | <map |
| | | id="map" |
| | | :longitude="longitude" |
| | | :latitude="latitude" |
| | | :markers="markers" |
| | | :polyline="polyline" |
| | | :circles="circles" |
| | | :controls="controls" |
| | | :include-points="includePoints" |
| | | :show-location="true" |
| | | @markertap="onMarkerTap" |
| | | @callouttap="onCalloutTap" |
| | | @controltap="onControlTap" |
| | | @regionchange="onRegionChange" |
| | | @tap="onMapTap" |
| | | class="map-webview" |
| | | ></map> |
| | | <!-- #endif --> |
| | | |
| | | <!-- H5平台使用web-view加载百度地图 --> |
| | | <!-- #ifdef H5 --> |
| | | <web-view |
| | | v-if="baiduMapUrl" |
| | | :src="baiduMapUrl" |
| | | class="map-webview" |
| | | @message="onWebviewMessage" |
| | | ></web-view> |
| | | <!-- #endif --> |
| | | |
| | | <view class="map-placeholder" v-if="!isMapLoaded"> |
| | | <text>地图加载中...</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="address-list" v-if="searchResults.length > 0"> |
| | | <view |
| | | class="address-item" |
| | | v-for="(item, index) in searchResults" |
| | | :key="index" |
| | | @click="selectAddress(item)" |
| | | > |
| | | <view class="address-title">{{ item.title }}</view> |
| | | <view class="address-detail">{{ item.address }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="selected-address" v-if="selectedAddress"> |
| | | <view class="address-title">选中地址:</view> |
| | | <view class="address-detail">{{ selectedAddress.title }}</view> |
| | | <view class="address-detail">{{ selectedAddress.address }}</view> |
| | | <button class="confirm-btn" @click="confirmAddress">确认选择</button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'MapSelector', |
| | | props: { |
| | | // 初始地址 |
| | | initialAddress: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | searchKeyword: '', |
| | | searchResults: [], |
| | | selectedAddress: null, |
| | | isMapLoaded: false, |
| | | // H5平台相关 |
| | | baiduMapUrl: '', |
| | | ak: '您的百度地图AK', |
| | | // 微信小程序相关 |
| | | longitude: 113.324520, |
| | | latitude: 23.099994, |
| | | markers: [], |
| | | polyline: [], |
| | | circles: [], |
| | | controls: [], |
| | | includePoints: [] |
| | | } |
| | | }, |
| | | mounted() { |
| | | // #ifdef H5 |
| | | // 初始化百度地图 |
| | | this.initBaiduMap() |
| | | // #endif |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // 初始化微信小程序地图 |
| | | this.initWechatMap() |
| | | // #endif |
| | | |
| | | if (this.initialAddress) { |
| | | this.searchKeyword = this.initialAddress |
| | | // 延迟设置焦点,避免跨域问题 |
| | | setTimeout(() => { |
| | | // 不自动聚焦,让用户手动点击 |
| | | }, 500) |
| | | } |
| | | }, |
| | | methods: { |
| | | // 搜索框获得焦点事件 |
| | | onSearchFocus() { |
| | | // 用户主动聚焦,不会触发跨域问题 |
| | | console.log('搜索框获得焦点') |
| | | }, |
| | | |
| | | // #ifdef H5 |
| | | // 处理web-view消息 |
| | | onWebviewMessage(e) { |
| | | // 处理来自web-view的消息 |
| | | console.log('收到来自web-view的消息:', e) |
| | | }, |
| | | |
| | | // 初始化百度地图(H5平台) |
| | | initBaiduMap() { |
| | | // 构造百度地图URL |
| | | this.baiduMapUrl = `https://api.map.baidu.com/mapjs?v=3.0&ak=${this.ak}&callback=initMap` |
| | | this.isMapLoaded = true |
| | | |
| | | // 延迟加载地图,避免阻塞 |
| | | setTimeout(() => { |
| | | this.isMapLoaded = true |
| | | }, 1000) |
| | | }, |
| | | // #endif |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // 初始化微信小程序地图 |
| | | initWechatMap() { |
| | | // 获取用户位置 |
| | | uni.getLocation({ |
| | | type: 'gcj02', |
| | | success: (res) => { |
| | | this.longitude = res.longitude |
| | | this.latitude = res.latitude |
| | | |
| | | // 设置默认标记 |
| | | this.markers = [{ |
| | | id: 0, |
| | | longitude: this.longitude, |
| | | latitude: this.latitude, |
| | | title: '当前位置', |
| | | iconPath: '/static/icons/location.png', |
| | | width: 30, |
| | | height: 30 |
| | | }] |
| | | |
| | | // 延迟设置加载状态,确保地图完全初始化 |
| | | setTimeout(() => { |
| | | this.isMapLoaded = true |
| | | }, 500) |
| | | }, |
| | | fail: () => { |
| | | // 延迟设置加载状态 |
| | | setTimeout(() => { |
| | | this.isMapLoaded = true |
| | | }, 500) |
| | | this.$modal.showToast('获取位置失败') |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | // 地图点击事件 |
| | | onMapTap(e) { |
| | | // 在点击位置添加标记 |
| | | const { longitude, latitude } = e.detail |
| | | this.markers = [{ |
| | | id: Date.now(), |
| | | longitude, |
| | | latitude, |
| | | title: '选中位置', |
| | | iconPath: '/static/icons/location-selected.png', |
| | | width: 30, |
| | | height: 30 |
| | | }] |
| | | |
| | | // 逆地址解析获取地址信息 |
| | | this.reverseGeocode(latitude, longitude) |
| | | }, |
| | | |
| | | // 逆地址解析 |
| | | reverseGeocode(lat, lng) { |
| | | // 这里应该调用后台API进行逆地址解析 |
| | | // 模拟数据 |
| | | this.selectedAddress = { |
| | | title: '选中位置', |
| | | address: `经纬度: ${lat.toFixed(6)}, ${lng.toFixed(6)}`, |
| | | lat: lat, |
| | | lng: lng |
| | | } |
| | | }, |
| | | // #endif |
| | | |
| | | // 搜索地址 |
| | | searchAddress() { |
| | | if (!this.searchKeyword) { |
| | | this.$modal.showToast('请输入地址') |
| | | return |
| | | } |
| | | |
| | | // 在实际项目中,这里应该调用对应平台的地图API |
| | | // 例如H5平台调用百度地图API,微信小程序调用微信地图API |
| | | |
| | | // 模拟搜索结果 |
| | | this.searchResults = [ |
| | | { |
| | | title: this.searchKeyword + '附近地点1', |
| | | address: '广东省广州市天河区' + this.searchKeyword + '123号', |
| | | lat: 23.123 + Math.random() * 0.1, |
| | | lng: 113.321 + Math.random() * 0.1 |
| | | }, |
| | | { |
| | | title: this.searchKeyword + '附近地点2', |
| | | address: '广东省广州市越秀区' + this.searchKeyword + '456号', |
| | | lat: 23.145 + Math.random() * 0.1, |
| | | lng: 113.289 + Math.random() * 0.1 |
| | | }, |
| | | { |
| | | title: this.searchKeyword + '附近地点3', |
| | | address: '广东省广州市白云区' + this.searchKeyword + '789号', |
| | | lat: 23.167 + Math.random() * 0.1, |
| | | lng: 113.345 + Math.random() * 0.1 |
| | | } |
| | | ] |
| | | }, |
| | | |
| | | // 输入框输入事件 |
| | | onSearchInput() { |
| | | // 防抖搜索 |
| | | }, |
| | | |
| | | // 选择地址 |
| | | selectAddress(item) { |
| | | this.selectedAddress = item |
| | | this.markLocation(item.lat, item.lng) |
| | | }, |
| | | |
| | | // 在地图上标记位置 |
| | | markLocation(lat, lng) { |
| | | // #ifdef H5 |
| | | // H5平台标记位置逻辑 |
| | | console.log(`H5平台标记位置: ${lat}, ${lng}`) |
| | | this.$modal.showToast(`已标记位置`) |
| | | // #endif |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // 微信小程序标记位置逻辑 |
| | | this.longitude = lng |
| | | this.latitude = lat |
| | | this.markers = [{ |
| | | id: Date.now(), |
| | | longitude: lng, |
| | | latitude: lat, |
| | | title: item.title, |
| | | iconPath: '/static/icons/location-selected.png', |
| | | width: 30, |
| | | height: 30 |
| | | }] |
| | | // #endif |
| | | }, |
| | | |
| | | // 确认选择地址 |
| | | confirmAddress() { |
| | | if (!this.selectedAddress) { |
| | | this.$modal.showToast('请先选择地址') |
| | | return |
| | | } |
| | | |
| | | // 触发事件,将选中的地址传递给父组件 |
| | | this.$emit('addressSelected', { |
| | | title: this.selectedAddress.title, |
| | | address: this.selectedAddress.address, |
| | | lat: this.selectedAddress.lat, |
| | | lng: this.selectedAddress.lng |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .map-selector-container { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | padding: 20rpx; |
| | | background-color: white; |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .search-btn { |
| | | width: 120rpx; |
| | | height: 70rpx; |
| | | margin-left: 20rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | |
| | | .map-container { |
| | | flex: 1; |
| | | height: 400rpx; |
| | | |
| | | .map-webview { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | // 微信小程序地图样式 |
| | | map { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .map-placeholder { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 100%; |
| | | background-color: #f5f5f5; |
| | | font-size: 28rpx; |
| | | color: #999; |
| | | } |
| | | } |
| | | |
| | | .address-list { |
| | | max-height: 300rpx; |
| | | overflow-y: auto; |
| | | background-color: white; |
| | | |
| | | .address-item { |
| | | padding: 20rpx 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .address-title { |
| | | font-size: 30rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 10rpx; |
| | | } |
| | | |
| | | .address-detail { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .selected-address { |
| | | padding: 20rpx 30rpx; |
| | | background-color: white; |
| | | border-top: 1rpx solid #f0f0f0; |
| | | |
| | | .address-title { |
| | | font-size: 30rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 10rpx; |
| | | } |
| | | |
| | | .address-detail { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | margin-bottom: 10rpx; |
| | | } |
| | | |
| | | .confirm-btn { |
| | | width: 100%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | margin-top: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | "optimization" : { |
| | | "subPackages" : true |
| | | }, |
| | | "usingComponents" : true |
| | | "usingComponents" : true, |
| | | "sdkConfigs" : { |
| | | "maps" : { |
| | | "baidu" : { |
| | | "appkey" : "n5z5pKfAnaP3fYMR4RJOAQsR1wQ2avAn" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | "vueVersion" : "2", |
| | | "h5" : { |
| | |
| | | "router" : { |
| | | "mode" : "hash", |
| | | "base" : "./" |
| | | }, |
| | | "sdkConfigs" : { |
| | | "maps" : { |
| | | "baidu" : { |
| | | "appkey" : "您的百度地图AK" |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | <view class="logo-content align-center justify-center flex"> |
| | | <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix"> |
| | | </image> |
| | | <text class="title">若依移动端登录</text> |
| | | <text class="title">民航调度系统</text> |
| | | </view> |
| | | <view class="login-form-content"> |
| | | <view class="input-item flex align-center"> |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 地图选择器弹窗 --> |
| | | <uni-popup ref="mapPopup" type="bottom" :mask-click="false"> |
| | | <view class="map-popup-container"> |
| | | <view class="popup-header"> |
| | | <view class="popup-title">选择地址</view> |
| | | <view class="close-btn" @click="closeMapSelector"> |
| | | <uni-icons type="closeempty" size="20" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | <map-selector |
| | | :initial-address="getInitialAddress()" |
| | | @addressSelected="onAddressSelected" |
| | | ></map-selector> |
| | | </view> |
| | | </uni-popup> |
| | | </scroll-view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue' |
| | | import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue' |
| | | import { getUserProfile } from "@/api/system/user" |
| | | import MapSelector from '@/components/map-selector.vue' |
| | | |
| | | export default { |
| | | components: { |
| | | uniDatetimePicker |
| | | uniDatetimePicker, |
| | | uniPopup, |
| | | MapSelector |
| | | }, |
| | | data() { |
| | | return { |
| | |
| | | selectedVehicle: '', |
| | | selectedOrganization: '', |
| | | selectedEmergencyTaskType: '', |
| | | boundVehicle: '', // 用户绑定的车辆 |
| | | // 地图选择相关 |
| | | showMapSelector: false, |
| | | mapSelectorType: '', // 标识当前选择的是哪个地址字段 |
| | | taskForm: { |
| | | description: '', |
| | | startLocation: '', |
| | |
| | | }) |
| | | }) |
| | | }, |
| | | onLoad() { |
| | | // 获取用户绑定的车辆信息 |
| | | this.getUserBoundVehicle() |
| | | }, |
| | | methods: { |
| | | // 获取用户绑定的车辆信息 |
| | | getUserBoundVehicle() { |
| | | getUserProfile().then(response => { |
| | | // 这里模拟从用户信息中获取绑定车辆,实际项目中应该从response.data中获取 |
| | | // 假设用户信息中有boundVehicle字段 |
| | | this.boundVehicle = '粤A12345' // 模拟值,实际应从response.data.boundVehicle获取 |
| | | |
| | | // 如果有绑定车辆,则默认选中 |
| | | if (this.boundVehicle) { |
| | | this.selectedVehicle = this.boundVehicle |
| | | } |
| | | }).catch(() => { |
| | | // 获取用户信息失败时使用默认值 |
| | | this.boundVehicle = '' |
| | | }) |
| | | }, |
| | | |
| | | selectTaskCategory(category) { |
| | | this.selectedTaskCategory = category |
| | | // 当选择任务类型时,如果是普通任务且用户有绑定车辆,则默认选中绑定车辆 |
| | | if (category.type === 'normal' && this.boundVehicle) { |
| | | this.selectedVehicle = this.boundVehicle |
| | | } |
| | | }, |
| | | |
| | | backToCategory() { |
| | |
| | | this.selectedEmergencyTaskType = this.emergencyTaskTypes[e.detail.value] |
| | | }, |
| | | |
| | | // 显示地图选择器 - 任务出发地 |
| | | selectStartLocation() { |
| | | this.$modal.showToast('选择出发地功能开发中') |
| | | this.mapSelectorType = 'startLocation' |
| | | this.$refs.mapPopup.open() |
| | | }, |
| | | |
| | | // 显示地图选择器 - 任务目的地 |
| | | selectEndLocation() { |
| | | this.$modal.showToast('选择目的地功能开发中') |
| | | this.mapSelectorType = 'endLocation' |
| | | this.$refs.mapPopup.open() |
| | | }, |
| | | |
| | | // 显示地图选择器 - 转出医院地址 |
| | | selectHospitalOutAddress() { |
| | | this.$modal.showToast('选择转出医院地址功能开发中') |
| | | this.mapSelectorType = 'hospitalOutAddress' |
| | | this.$refs.mapPopup.open() |
| | | }, |
| | | |
| | | // 显示地图选择器 - 转入医院地址 |
| | | selectHospitalInAddress() { |
| | | this.$modal.showToast('选择转入医院地址功能开发中') |
| | | this.mapSelectorType = 'hospitalInAddress' |
| | | this.$refs.mapPopup.open() |
| | | }, |
| | | |
| | | // 显示地图选择器 - 福祉车出发地址 |
| | | selectStartAddress() { |
| | | this.$modal.showToast('选择出发地址功能开发中') |
| | | this.mapSelectorType = 'startAddress' |
| | | this.$refs.mapPopup.open() |
| | | }, |
| | | |
| | | // 显示地图选择器 - 福祉车目的地址 |
| | | selectEndAddress() { |
| | | this.$modal.showToast('选择目的地址功能开发中') |
| | | this.mapSelectorType = 'endAddress' |
| | | this.$refs.mapPopup.open() |
| | | }, |
| | | |
| | | // 获取初始地址用于地图搜索 |
| | | getInitialAddress() { |
| | | switch (this.mapSelectorType) { |
| | | case 'startLocation': |
| | | return this.taskForm.startLocation |
| | | case 'endLocation': |
| | | return this.taskForm.endLocation |
| | | case 'hospitalOutAddress': |
| | | return this.taskForm.hospitalOut.address |
| | | case 'hospitalInAddress': |
| | | return this.taskForm.hospitalIn.address |
| | | case 'startAddress': |
| | | return this.taskForm.startAddress |
| | | case 'endAddress': |
| | | return this.taskForm.endAddress |
| | | default: |
| | | return '' |
| | | } |
| | | }, |
| | | |
| | | // 地图选择器地址选择回调 |
| | | onAddressSelected(address) { |
| | | // 根据不同的地址类型设置对应的表单字段 |
| | | switch (this.mapSelectorType) { |
| | | case 'startLocation': |
| | | this.taskForm.startLocation = address.title + ' - ' + address.address |
| | | break |
| | | case 'endLocation': |
| | | this.taskForm.endLocation = address.title + ' - ' + address.address |
| | | break |
| | | case 'hospitalOutAddress': |
| | | this.taskForm.hospitalOut.address = address.title + ' - ' + address.address |
| | | break |
| | | case 'hospitalInAddress': |
| | | this.taskForm.hospitalIn.address = address.title + ' - ' + address.address |
| | | break |
| | | case 'startAddress': |
| | | this.taskForm.startAddress = address.title + ' - ' + address.address |
| | | break |
| | | case 'endAddress': |
| | | this.taskForm.endAddress = address.title + ' - ' + address.address |
| | | break |
| | | } |
| | | |
| | | // 关闭地图选择器 |
| | | this.closeMapSelector() |
| | | }, |
| | | |
| | | // 关闭地图选择器 |
| | | closeMapSelector() { |
| | | this.$refs.mapPopup.close() |
| | | this.mapSelectorType = '' |
| | | }, |
| | | |
| | | addStaff() { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 地图选择器弹窗样式 |
| | | .map-popup-container { |
| | | height: 80vh; |
| | | background-color: white; |
| | | border-top-left-radius: 20rpx; |
| | | border-top-right-radius: 20rpx; |
| | | overflow: hidden; |
| | | |
| | | .popup-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .popup-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .close-btn { |
| | | width: 50rpx; |
| | | height: 50rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <el-select v-model="queryParams.status" placeholder="请选择关联状态" clearable> |
| | | <el-option |
| | | v-for="dict in dict.type.sys_task_vehicle_status" |
| | | :key="dict.value" |
| | | :key="'search-' + dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | |
| | | <el-select v-model="form.status" placeholder="请选择关联状态" style="width: 100%"> |
| | | <el-option |
| | | v-for="dict in dict.type.sys_task_vehicle_status" |
| | | :key="dict.value" |
| | | :key="'form-' + dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | ></el-option> |
| | |
| | | <el-select v-model="statusForm.newStatus" placeholder="请选择新状态"> |
| | | <el-option |
| | | v-for="dict in dict.type.sys_task_vehicle_status" |
| | | :key="dict.value" |
| | | :key="'status-' + dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | ></el-option> |