Răsfoiți Sursa

自动定位问题

shish 2 luni în urmă
părinte
comite
e6b51aef45

+ 0 - 5
ghsApp/src/admin/home/workbench.vue

@@ -1323,9 +1323,4 @@ export default {
 	color: #d8dee8;
 	font-size: 24upx;
 }
-
-.guest-footer-link--accent {
-	color: #3385ff;
-	font-weight: 600;
-}
 </style>

+ 5 - 1
ghsApp/src/api/map/index.js

@@ -1,10 +1,14 @@
 import https from '@/plugins/luch-request_0.0.7/request'
 
-//经纬度解析地址  jiangfneg  2021-06-26
+// 经纬度解析地址(高德逆地理) lat, long, locationType(gcj02|wgs84)
 export const mapResolve = data => {
 	return https.get('/map/resolve', data)
 }
 
+export const mapNearby = data => {
+	return https.get('/map/nearby', data)
+}
+
 //是否已经导航过
 export const hasHitNavigate = data => {
 	return https.get('/map/has-hit-navigate', data)

+ 288 - 39
ghsApp/src/pagesClient/official/apply.vue

@@ -3,8 +3,10 @@
     <form @submit="formSubmit">
       <view class="apply-body">
         <view class="apply-alert apply-alert--warning">
-          <text class="apply-alert-text">零售花店和个人请勿注册,注册了也不会审核通过。零售花店需要系统请加微信:</text>
-          <text class="apply-alert-link" @click="copyWechat('18559200768')">18559200768</text>
+          <text class="apply-alert-line">
+            <text class="apply-alert-text">零售花店和个人请勿注册,注册了也不会审核通过。零售花店需要系统请加微信:</text>
+            <text class="apply-alert-link" @click="copyWechat('18559200768')">18559200768</text>
+          </text>
         </view>
 
         <!-- #ifdef MP-WEIXIN -->
@@ -26,24 +28,29 @@
               <view class="tui-title">门店名称</view>
               <input v-model="form.name" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="name" placeholder="请输入名称" />
             </tui-list-cell>
-            <tui-list-cell class="line-cell" :hover="false" :arrow="true" @click="openAddres">
+            <tui-list-cell class="line-cell line-cell--city" :hover="false">
               <view class="tui-title">所在城市</view>
-              <view class="tui-input" v-if="form.province">{{ form.province + '-' + form.city }}</view>
-              <view class="tui-placeholder" v-else>请选择</view>
+              <view class="city-row-main" @click="openAddres">
+                <view class="tui-input" v-if="form.province">{{ form.province + '-' + form.city }}</view>
+                <view class="tui-placeholder" v-else>请选择城市</view>
+              </view>
+              <view class="city-locate-btn" @click.stop="openNearbyAddress">
+                <image class="city-locate-icon" src="/static/images/common/localposition.png" mode="aspectFit"></image>
+              </view>
             </tui-list-cell>
             <tui-list-cell v-if="hasMap == 0" class="line-cell" :hover="false">
               <view class="tui-title">所在地址</view>
-              <input v-model="form.address" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="address" placeholder="请填写" />
+              <input v-model="form.address" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="address" @input="modifyShow" placeholder="请填写地址" />
             </tui-list-cell>
             <tui-list-cell v-else class="line-cell" :hover="false" :arrow="true" @click="selectRegion">
               <view class="tui-title">所在地址</view>
               <view v-if="form.address" class="tui-input">{{ form.address }}</view>
-              <view v-else class="tui-placeholder">请填写地址</view>
+              <view v-else class="tui-placeholder">请搜索选择地址</view>
               <input v-model="form.address" name="address" hidden />
             </tui-list-cell>
             <tui-list-cell class="line-cell" :hover="false">
               <view class="tui-title">楼号门牌</view>
-              <input v-model="form.floor" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="floor" placeholder="选填" />
+              <input v-model="form.floor" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="floor" placeholder="选填" @input="modifyShow" />
             </tui-list-cell>
           </view>
         </view>
@@ -99,6 +106,27 @@
 
       <simple-address ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onCityConfirm"></simple-address>
       <app-area-sel :show.sync="showRegion" :city="form.city" @change="changeAreaFn" />
+
+      <bottom-popup class="nearby-popup-wrap" :show="showNearbyPopup" @close="closeNearbyPopup">
+        <view class="nearby-popup">
+          <view class="nearby-popup-head">
+            <text class="nearby-popup-title">选择附近地址</text>
+            <app-close icon="iconguanbi" @close="closeNearbyPopup" />
+          </view>
+          <scroll-view class="nearby-list" scroll-y>
+            <view
+              v-for="(item, index) in nearbyList"
+              :key="index"
+              class="nearby-item"
+              @click="selectNearbyAddress(item)"
+            >
+              <view class="nearby-item-name">{{ item.name }}</view>
+              <view class="nearby-item-address">{{ item.address }}</view>
+            </view>
+            <view v-if="nearbyList.length === 0" class="nearby-empty">暂无附近地址,请手动填写</view>
+          </scroll-view>
+        </view>
+      </bottom-popup>
     </form>
   </view>
 </template>
@@ -107,22 +135,29 @@
 import TuiListCell from "@/components/plugin/list-cell";
 import AppAreaSel from "@/components/app-area-sel";
 import SimpleAddress from "@/components/plugin/simple-address";
+import BottomPopup from '@/components/plugin/bottom-popup'
+import AppClose from '@/components/module/app-close'
 import AppAvatarModule from "@/components/module/app-avatar";
 import AppUploader from "@/components/app-uploader";
 const form = require("@/utils/formValidation.js");
 import {getIntroduce,applyRegister} from "@/api/official";
 import {getAuthCode} from "@/api/apply";
 import { mapGetters } from "vuex"
-//图片上传插件来源:https://ext.dcloud.net.cn/plugin?id=2922 已改造,不能再升级 shish 20211228
 import htzImageUpload from '@/components/htz-image-upload/htz-image-upload.vue'
 import { APIHOST } from '@/config'
-import {getHasMap} from "@/api/express"
+import { getHasMap } from "@/api/express"
+import { mapNearby } from '@/api/map/index'
+// #ifdef APP-PLUS
+import permision from "@/utils/wa-permission_1.1/permission.js";
+// #endif
 export default {
   name: "apply-data",
   components: {
     TuiListCell,
     AppAreaSel,
     SimpleAddress,
+    BottomPopup,
+    AppClose,
     AppAvatarModule,
     AppUploader,
     htzImageUpload
@@ -150,8 +185,12 @@ export default {
         cover:'',
         inviteCode:''
       },
-      showRegion: false,
       cityPickerValueDefault: [0, 0],
+      showRegion: false,
+      showNearbyPopup: false,
+      nearbyList: [],
+      locating: false,
+      hasMap: 0,
       adminName: "",
       logo: '',
       hasGet:false,
@@ -160,7 +199,6 @@ export default {
       headers:{token:''},
       currentImgData: [],
       uploadImgUrl:APIHOST+'/upload/save-file',
-      hasMap:0
     };
   },
 	computed:{
@@ -168,8 +206,8 @@ export default {
 	},
   onLoad () {
     const token = uni.getStorageSync('token')
-    this.headers.token = token,
-    getHasMap().then(res=>{
+    this.headers.token = token
+    getHasMap().then(res => {
       this.hasMap = res.data.hasMap
     })
   },
@@ -177,6 +215,122 @@ export default {
     clearInterval(this.INT)
   },
   methods: {
+    ensureAppLocationPermission() {
+      return new Promise(async (resolve, reject) => {
+        // #ifdef APP-PLUS
+        if (plus.os.name === 'Android') {
+          const permissionRes = await permision.requestAndroidPermission('android.permission.ACCESS_FINE_LOCATION')
+          if (permissionRes !== 1) {
+            if (permissionRes === -1) {
+              permision.gotoAppPermissionSetting()
+            }
+            reject(new Error('请开启定位权限'))
+            return
+          }
+        }
+        if (!permision.checkSystemEnableLocation()) {
+          reject(new Error('请先开启系统定位服务'))
+          return
+        }
+        // #endif
+        resolve()
+      })
+    },
+    getDeviceLocation() {
+      return new Promise((resolve, reject) => {
+        const requestLocation = (locationType) => {
+          uni.getLocation({
+            type: locationType,
+            success: (res) => resolve({ ...res, locationType }),
+            fail: (err) => {
+              if (locationType === 'gcj02' && (
+                err.code == 18 ||
+                err.errCode == 18 ||
+                (err.errMsg && (
+                  err.errMsg.indexOf('not support gcj02') > -1 ||
+                  err.errMsg.indexOf('Not Support CoordsType') > -1
+                ))
+              )) {
+                requestLocation('wgs84')
+                return
+              }
+              reject(err)
+            }
+          })
+        }
+        // #ifdef APP-PLUS
+        if (plus.os.name === 'iOS') {
+          requestLocation('wgs84')
+          return
+        }
+        // #endif
+        requestLocation('gcj02')
+      })
+    },
+    closeNearbyPopup() {
+      this.showNearbyPopup = false
+    },
+    modifyShow() {
+      this.form.showAddress = (this.form.city || '') + (this.form.address || '') + (this.form.floor || '')
+    },
+    applyNearbyAddress(item) {
+      if (!item) {
+        return false
+      }
+      if (item.province) {
+        this.form.province = item.province
+      }
+      if (item.city) {
+        this.form.city = item.city
+      }
+      if (item.district) {
+        this.form.dist = item.district
+      }
+      this.form.address = item.name || item.address || ''
+      this.form.showAddress = item.showAddress || item.address || ''
+      if (item.location) {
+        const parts = String(item.location).split(',').map(v => v.trim())
+        if (parts.length >= 2) {
+          this.form.longitude = parts[0]
+          this.form.latitude = parts[1]
+        }
+      }
+      this.modifyShow()
+    },
+    selectNearbyAddress(item) {
+      this.applyNearbyAddress(item)
+      this.closeNearbyPopup()
+    },
+    async openNearbyAddress() {
+      if (this.locating) {
+        return false
+      }
+      this.locating = true
+      uni.showLoading({ title: '定位中', mask: true })
+      try {
+        await this.ensureAppLocationPermission()
+        const location = await this.getDeviceLocation()
+        const res = await mapNearby({
+          lat: location.latitude,
+          long: location.longitude,
+          locationType: location.locationType || 'gcj02'
+        })
+        if (res.code != 1 || !res.data || !res.data.list || res.data.list.length === 0) {
+          this.$msg('未获取到附近地址,请手动填写')
+          return false
+        }
+        this.nearbyList = res.data.list
+        this.showNearbyPopup = true
+        return true
+      } catch (err) {
+        console.log('openNearbyAddress fail', err)
+        this.$msg((err && err.message) ? err.message : '定位失败,请手动填写')
+        return false
+      } finally {
+        this.locating = false
+        uni.hideLoading()
+      }
+    },
     suggest(){
       let that = this
       that.$util.confirmModal({content:'请添加微信号:1528025347',okText:'复制'},() => {
@@ -247,6 +401,7 @@ export default {
     onCityConfirm (e) {
       this.form.province = e.provinceName;
       this.form.city = e.cityName;
+      this.modifyShow()
     },
     imgUploadSuccess(res) {
       var _res = JSON.parse(res.data)
@@ -259,26 +414,26 @@ export default {
       this.form.cover =''
     },
     selectRegion() {
-			if (!this.form.city) {
-				this.$msg('请先选择城市!')
-				return false
-			}
-			this.showRegion = true
-		},
+      if (!this.form.city) {
+        this.$msg('请先选择城市!')
+        return false
+      }
+      this.showRegion = true
+    },
     changeAreaFn(e) {
-			let locationStr = e.location
-			let fruits = locationStr.split(",").map(fruit => fruit.trim())
-
-			this.form.latitude = fruits[1]
-			this.form.longitude = fruits[0]
-			this.form.showAddress = e.address
-			this.form.address = e.name
-
-      		// 提取地区信息,按遇到第一个"市"字后,把"市"后面的字符串作为地区
-			const districtStr = e.district || '';
-			const cityIndex = districtStr.indexOf('市');
-			this.form.dist = cityIndex !== -1 ? districtStr.substring(cityIndex + 1) : districtStr;
-		},
+      let locationStr = e.location
+      let fruits = locationStr.split(',').map(fruit => fruit.trim())
+
+      this.form.latitude = fruits[1]
+      this.form.longitude = fruits[0]
+      this.form.showAddress = e.address
+      this.form.address = e.name
+
+      const districtStr = e.district || ''
+      const cityIndex = districtStr.indexOf('市')
+      this.form.dist = cityIndex !== -1 ? districtStr.substring(cityIndex + 1) : districtStr
+      this.modifyShow()
+    },
     formSubmit (e) {
       let rules = [
         { name: "name", rule: ["required"], msg: ["请填写名称"] },
@@ -393,10 +548,16 @@ export default {
 }
 
 .apply-alert-text {
-  display: block;
   color: #5c656d;
-  font-size: 26upx;
-  line-height: 40upx;
+  font-size: 30upx;
+  line-height: 44upx;
+}
+
+.apply-alert-line {
+  display: inline;
+  color: #c0392b;
+  font-size: 30upx;
+  line-height: 44upx;
 }
 
 .apply-alert--warning .apply-alert-text {
@@ -404,16 +565,19 @@ export default {
 }
 
 .apply-alert--info .apply-alert-text {
+  display: block;
   color: #3385ff;
   font-weight: 600;
   text-align: center;
+  font-size: 30upx;
+  line-height: 44upx;
 }
 
 .apply-alert-link {
   color: #3385ff;
-  font-size: 28upx;
+  font-size: 32upx;
   font-weight: 700;
-  line-height: 40upx;
+  line-height: 44upx;
 }
 
 .apply-section {
@@ -456,11 +620,15 @@ export default {
     font-size: 28upx;
   }
   .tui-input {
-    width: calc(100% - 180upx);
+    flex: 1;
+    min-width: 0;
+    width: auto;
     font-size: 28upx;
     color: #161819;
   }
   .tui-placeholder {
+    flex: 1;
+    min-width: 0;
     color: #ccc;
   }
   .phcolor {
@@ -468,6 +636,87 @@ export default {
   }
 }
 
+.line-cell--city {
+  .city-row-main {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .city-locate-btn {
+    flex-shrink: 0;
+    width: 72upx;
+    height: 72upx;
+    margin-left: 12upx;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 50%;
+    background: #e8f0ff;
+  }
+
+  .city-locate-icon {
+    width: 40upx;
+    height: 40upx;
+    display: block;
+  }
+}
+
+.nearby-popup-wrap {
+  ::v-deep .tui-popup-class {
+    border-top-left-radius: 20upx;
+    border-top-right-radius: 20upx;
+  }
+}
+
+.nearby-popup {
+  background: #fff;
+}
+
+.nearby-popup-head {
+  position: relative;
+  padding: 30upx 80upx 24upx;
+  text-align: center;
+}
+
+.nearby-popup-title {
+  color: #161819;
+  font-size: 34upx;
+  font-weight: 700;
+  line-height: 48upx;
+}
+
+.nearby-list {
+  max-height: 60vh;
+  padding: 0 24upx 40upx;
+  box-sizing: border-box;
+}
+
+.nearby-item {
+  padding: 24upx 8upx;
+  border-bottom: 1upx solid #f0f2f5;
+}
+
+.nearby-item-name {
+  color: #161819;
+  font-size: 30upx;
+  font-weight: 600;
+  line-height: 42upx;
+}
+
+.nearby-item-address {
+  margin-top: 8upx;
+  color: #8a9199;
+  font-size: 26upx;
+  line-height: 38upx;
+}
+
+.nearby-empty {
+  padding: 60upx 0;
+  text-align: center;
+  color: #8a9199;
+  font-size: 28upx;
+}
+
 .code-wrap {
   .tui-input--code {
     flex: 1;

+ 6 - 1
hdApp/src/api/map/index.js

@@ -1,9 +1,14 @@
 import https from '@/plugins/luch-request_0.0.7/request'
 
 /** *
- * 经纬度解析地址  jiangfneg  2021-06-26
+ * 经纬度解析地址(高德逆地理) jiangfneg  2021-06-26
+ * @param {Object} data lat, long, locationType(gcj02|wgs84)
  */
 export const mapResolve = data => {
 	return https.get('/map/resolve', data)
 }
 
+export const mapNearby = data => {
+	return https.get('/map/nearby', data)
+}
+

+ 535 - 172
hdApp/src/pagesClient/official/apply.vue

@@ -1,130 +1,162 @@
 <template>
-  <div class="app-content">
+  <view class="apply-page app-content">
     <form @submit="formSubmit">
+      <view class="apply-body">
+        <view class="apply-section">
+          <view class="apply-section-title">手机号</view>
+          <view class="module-com apply-card">
+            <!-- #ifdef MP-WEIXIN -->
+            <tui-list-cell class="line-cell" :hover="false">
+              <view class="tui-title">填手机号</view>
+              <view class="apply-mode-btns">
+                <view class="apply-mode-btn" :class="{ 'apply-mode-btn--active': fillMobile == 0 }" @click="oneGet">一键获取</view>
+                <view class="apply-mode-btn" :class="{ 'apply-mode-btn--active': fillMobile == 1 }" @click="manFill">手动填写</view>
+              </view>
+            </tui-list-cell>
+            <!-- #endif -->
+            <block v-if="fillMobile == 1">
+              <tui-list-cell class="line-cell" :hover="false">
+                <view class="tui-title required">手机号</view>
+                <input v-model="form.mobile" type="number" placeholder-class="phcolor" @blur="checkShopFn" placeholder-style="color:#CCCCCC" class="tui-input" name="mobile" placeholder="请填写手机号" />
+              </tui-list-cell>
+              <tui-list-cell class="line-cell code-wrap" :hover="false">
+                <view class="tui-title required">验证码</view>
+                <input v-model="form.authCode" type="number" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input tui-input--code" name="authCode" placeholder="请填写验证码" />
+                <button v-if="hasGet == false" class="apply-code-btn" @click="requestAuthCode()">获取</button>
+                <button v-else class="apply-code-btn apply-code-btn--disabled">{{ count }}</button>
+              </tui-list-cell>
+            </block>
+            <block v-else>
+              <tui-list-cell class="line-cell code-wrap" :hover="false">
+                <view class="tui-title required">手机号</view>
+                <input v-model="form.mobile" type="number" placeholder-class="phcolor" :disabled="true" placeholder-style="color:#CCCCCC" class="tui-input tui-input--code" name="mobile" placeholder="请点右边按钮获取" />
+                <button v-if="hasGet == false" class="apply-code-btn" open-type="getPhoneNumber" @getphonenumber="getSj">点击获取</button>
+              </tui-list-cell>
+            </block>
+          </view>
+        </view>
 
-      <view class="module-com">
-		<!-- #ifdef MP-WEIXIN -->
-			<tui-list-cell class="line-cell" :hover="false" >
-			  <div class="tui-title">填手机号</div>
-			  <div>
-			    <button class="admin-button-com middle" :class="[fillMobile == 0 ? 'blue' : 'default']" @click="oneGet">一键获取</button>
-			    <button class="admin-button-com middle" :class="[fillMobile == 1 ? 'blue' : 'default']" style="margin-left:30upx;" @click="manFill">无法一键获取</button>
-			  </div>
-			</tui-list-cell>
-		<!-- #endif -->
-        <block v-if="fillMobile ==1">
-          <tui-list-cell class="line-cell" :hover="false">
-              <div class="tui-title required">手机号</div>
-              <input v-model="form.mobile" type="number" placeholder-class="phcolor" @blur="checkShopFn"
-             placeholder-style="color:#CCCCCC" class="tui-input" name="mobile" placeholder="请填写手机号" />
-          </tui-list-cell>
-          <tui-list-cell class="line-cell" :hover="false">
-              <div class="tui-title required">验证码</div>
-              <input v-model="form.authCode" type="number" style="width:330upx;" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="authCode" placeholder="请填写验证码" />
-              <button v-if="hasGet == false" class="admin-button-com blue middle" @click="requestAuthCode()">获取</button>
-              <button v-else class="admin-button-com default middle" >{{count}}</button>
-          </tui-list-cell>
-        </block>
-        <block v-else>
-          <tui-list-cell class="line-cell" :hover="false">
-              <div class="tui-title required">手机号</div>
-              <input v-model="form.mobile" type="number" style="width:300upx;" placeholder-class="phcolor" :disabled="true"
-             placeholder-style="color:#CCCCCC" class="tui-input" name="mobile" placeholder="请点右边按钮获取" />
-             <button v-if="hasGet == false" class="admin-button-com blue middle" open-type="getPhoneNumber" @getphonenumber="getSj">点击获取</button>
-          </tui-list-cell>
-        </block>
-      </view>
-
-      <view class="module-com">
-        <tui-list-cell class="line-cell" :hover="false">
-              <div class="tui-title required">姓名</div>
+        <view class="apply-section">
+          <view class="apply-section-title">基本信息</view>
+          <view class="module-com apply-card">
+            <tui-list-cell class="line-cell" :hover="false">
+              <view class="tui-title required">姓名</view>
               <input v-model="form.adminName" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="adminName" placeholder="请填写姓名" />
-        </tui-list-cell>
-      </view>
+            </tui-list-cell>
+          </view>
+        </view>
 
-      <view class="module-com">
-        <tui-list-cell class="line-cell" :hover="false" >
-          <div class="tui-title">类型</div>
-          <div>
-            <button class="admin-button-com middle" :class="[isHd == 1 ? 'blue' : 'default']" @click="isHd=1">我有店</button>
-            <button class="admin-button-com middle" :class="[isHd == 0 ? 'blue' : 'default']" style="margin-left:30upx;" @click="isHd=0">我没店</button>
-          </div>
-        </tui-list-cell>
-        <tui-list-cell class="line-cell" :hover="false" >
-          <div class="tui-title">{{isHd==1?'你的店名':'收货姓名'}}</div>
-          <input v-model="form.name" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="name" placeholder="请填写名称" />
-        </tui-list-cell>
-        <tui-list-cell class="line-cell" :hover="false" :arrow="true" @click="openAddres" >
-          <div class="tui-title">所在城市</div>
-          <div class="tui-input" v-if="form.province">{{ form.province + '-' + form.city }}</div>
-          <div class="tui-placeholder" v-else>请选择城市</div>
-        </tui-list-cell>
-        <!-- <tui-list-cell class="line-cell" :hover="false">
-          <div class="tui-title">所在地址</div>
-          <input v-model="form.address" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="address" placeholder="请填写地址" />
-        </tui-list-cell> -->
-        <tui-list-cell v-if="hasMap == 0" class="line-cell" :hover="false">
-					<view class="tui-title">所在地址</view>
-					<input v-model="form.address" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="address" @input="modifyShow" placeholder="请填写地址" />
-				</tui-list-cell>
-				<tui-list-cell v-else class="line-cell" :hover="false" :arrow="true" @click="selectRegion">
-					<view class="tui-title">所在地址</view>
-					<view v-if="form.address" class="tui-input">{{ form.address }}</view>
-					<view v-else class="tui-placeholder">请填写地址</view>
-					<input v-model="form.address" name="address" hidden />
-				</tui-list-cell>
-        <tui-list-cell class="line-cell" :hover="false" >
-          <div class="tui-title">楼号门牌</div>
-          <input v-model="form.floor" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="floor" placeholder="选填" @input="modifyShow" />
-        </tui-list-cell>
-      </view>
+        <view class="apply-section">
+          <view class="apply-section-title">门店信息</view>
+          <view class="module-com apply-card">
+            <tui-list-cell class="line-cell" :hover="false">
+              <view class="tui-title">类型</view>
+              <view class="apply-mode-btns">
+                <view class="apply-mode-btn" :class="{ 'apply-mode-btn--active': isHd == 1 }" @click="isHd = 1">我有店</view>
+                <view class="apply-mode-btn apply-mode-btn--last" :class="{ 'apply-mode-btn--active': isHd == 0 }" @click="isHd = 0">我没店</view>
+              </view>
+            </tui-list-cell>
+            <tui-list-cell class="line-cell" :hover="false">
+              <view class="tui-title">{{ isHd == 1 ? '你的店名' : '收货姓名' }}</view>
+              <input v-model="form.name" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="name" placeholder="请填写名称" />
+            </tui-list-cell>
 
-      <view class="module-com recommend-wrap" v-if="!$util.isEmpty(merchantData)" >
-        <div class="recommend-tag">推荐人</div>
-        <div class="recommend-det">
-          <image style="width:90upx;height:90upx;border-radius:42upx;" mode="scaleToFill" :src="merchantData.logoUrl" @error="imageError" />
-          <div class="recommend-info">
-            <div class="app-size-32">{{ merchantData.name }}</div>
-            <div class="app-color-2"></div>
-          </div>
-        </div>
-      </view>
-      <view style="color:#999999;font-size:25upx;margin-top:30upx;">
-        <checkbox-group @change="agreeItem">
-          <label style="display:flex;align-items:center;justify-content:center;">
-            <checkbox value="1" style="width:6upx;transform:scale(0.8)" :checked="agree == 1" />
-            <text style="margin-left:42upx;font-size:30upx;">
-              我已阅读并同意
-              <text style="font-weight:bold;color:#666666;" @click.stop="goToService()">《服务协议》</text>
-              和
-              <text style="font-weight:bold;color:#666666;" @click.stop="goToPrivacy()">《隐私政策》</text>
-            </text>
-          </label>
-        </checkbox-group>
+            <tui-list-cell class="line-cell line-cell--city" :hover="false">
+              <view class="tui-title">所在城市</view>
+              <view class="city-row-main" @click="openAddres">
+                <view class="tui-input" v-if="form.province">{{ form.province + '-' + form.city }}</view>
+                <view class="tui-placeholder" v-else>请选择城市</view>
+              </view>
+              <view class="city-locate-btn" @click.stop="openNearbyAddress">
+                <image class="city-locate-icon" :src="iconSrc('general-location')" mode="aspectFit"></image>
+              </view>
+            </tui-list-cell>
+            <tui-list-cell v-if="hasMap == 0" class="line-cell" :hover="false">
+              <view class="tui-title">所在地址</view>
+              <input v-model="form.address" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="address" @input="modifyShow" placeholder="请填写地址" />
+            </tui-list-cell>
+            <tui-list-cell v-else class="line-cell" :hover="false" :arrow="true" @click="selectRegion">
+              <view class="tui-title">所在地址</view>
+              <view v-if="form.address" class="tui-input">{{ form.address }}</view>
+              <view v-else class="tui-placeholder">请搜索选择地址</view>
+              <input v-model="form.address" name="address" hidden />
+            </tui-list-cell>
+
+            <tui-list-cell class="line-cell" :hover="false">
+              <view class="tui-title">楼号门牌</view>
+              <input v-model="form.floor" type="text" placeholder-class="phcolor" placeholder-style="color:#CCCCCC" class="tui-input" name="floor" placeholder="选填" @input="modifyShow" />
+            </tui-list-cell>
+          </view>
+        </view>
+
+        <view class="module-com apply-card recommend-wrap" v-if="!$util.isEmpty(merchantData)">
+          <view class="recommend-tag">推荐人</view>
+          <view class="recommend-det">
+            <image class="recommend-avatar" mode="scaleToFill" :src="merchantData.logoUrl" @error="imageError" />
+            <view class="recommend-info">
+              <view class="app-size-32">{{ merchantData.name }}</view>
+            </view>
+          </view>
+        </view>
+
+        <view class="apply-agreement">
+          <checkbox-group @change="agreeItem">
+            <label class="apply-agreement-label">
+              <checkbox value="1" class="apply-checkbox" :checked="agree == 1" />
+              <text class="apply-agreement-text">
+                我已阅读并同意
+                <text class="apply-agreement-link" @click.stop="goToService()">《服务协议》</text>
+                和
+                <text class="apply-agreement-link" @click.stop="goToPrivacy()">《隐私政策》</text>
+              </text>
+            </label>
+          </checkbox-group>
+        </view>
+
+        <view class="apply-submit-wrap">
+          <button class="apply-submit-btn" formType="submit">确认注册</button>
+        </view>
       </view>
-      <div class="btn-wrap">
-        <button class="admin-button-com blue big" formType="submit" >确认</button>
-      </div>
-
-      <!-- 省市联动 -->
-      <simple-address ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onCityConfirm" ></simple-address>
-      <!-- 选择地区 -->
-		  <app-area-sel :show.sync="showRegion" :city="form.city" @change="changeAreaFn" />
+
+      <simple-address ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onCityConfirm"></simple-address>
+      <app-area-sel :show.sync="showRegion" :city="form.city" @change="changeAreaFn" />
+
+      <bottom-popup class="nearby-popup-wrap" :show="showNearbyPopup" @close="closeNearbyPopup">
+        <view class="nearby-popup">
+          <view class="nearby-popup-head">
+            <text class="nearby-popup-title">选择附近地址</text>
+            <app-close icon="iconguanbi" @close="closeNearbyPopup" />
+          </view>
+          <scroll-view class="nearby-list" scroll-y>
+            <view
+              v-for="(item, index) in nearbyList"
+              :key="index"
+              class="nearby-item"
+              @click="selectNearbyAddress(item)"
+            >
+              <view class="nearby-item-name">{{ item.name }}</view>
+              <view class="nearby-item-address">{{ item.address }}</view>
+            </view>
+            <view v-if="nearbyList.length === 0" class="nearby-empty">暂无附近地址,请手动填写</view>
+          </scroll-view>
+        </view>
+      </bottom-popup>
     </form>
-  </div>
+  </view>
 </template>
 
 <script>
 import TuiListCell from "@/components/plugin/list-cell";
 import AppAreaSel from "@/components/app-area-sel";
 import SimpleAddress from "@/components/plugin/simple-address";
+import BottomPopup from '@/components/plugin/bottom-popup'
+import AppClose from '@/components/module/app-close'
 import AppAvatarModule from "@/components/module/app-avatar";
 import AppUploader from "@/components/app-uploader";
 const form = require("@/utils/formValidation.js");
 import {getIntroduce,applyRegister} from "@/api/official";
 import {getAuthCode} from "@/api/apply";
 import { mapGetters,mapActions } from "vuex"
-//图片上传插件来源:https://ext.dcloud.net.cn/plugin?id=2922 已改造,不能再升级 shish 20211228
 import htzImageUpload from '@/components/htz-image-upload/htz-image-upload.vue'
 import { APIHOST } from '@/config'
 import { getShopInfo} from "@/utils/auth";
@@ -132,14 +164,21 @@ import { getDictionaries } from '@/api/mini'
 import { checkShop } from '@/api/shop'
 import { ghsInfo } from "@/api/ghs/index";
 import { getMobile } from "@/api/auth";
-import {getHasMap} from "@/api/express"
+import { getHasMap } from "@/api/express"
+import { mapNearby } from '@/api/map/index'
+import { iconSrc } from '@/utils/iconSrc'
 import { persistInviteContext, tryBindPendingInvite, optionHasInviteContext, clearPendingInvite, restorePendingInviteFromLegacy, getRegisterInviteParams, expireInviteIfNeeded, getGhsProductQueryFromPending } from "@/utils/pendingGhsInvite";
+// #ifdef APP-PLUS
+import permision from "@/utils/wa-permission_1.1/permission.js";
+// #endif
 export default {
   name: "apply-data",
   components: {
     TuiListCell,
     AppAreaSel,
     SimpleAddress,
+    BottomPopup,
+    AppClose,
     AppAvatarModule,
     AppUploader,
     htzImageUpload
@@ -166,8 +205,12 @@ export default {
         authCode:"",
         cover:''
       },
-      showRegion: false,
       cityPickerValueDefault: [0, 0],
+      showRegion: false,
+      showNearbyPopup: false,
+      nearbyList: [],
+      locating: false,
+      hasMap: 0,
       adminName: "",
       logo: '',
       hasGet:false,
@@ -178,7 +221,6 @@ export default {
       isHd:1,
       uploadImgUrl:APIHOST+'/upload/save-file',
       fillMobile:0,
-      hasMap:0
     };
   },
 	computed:{
@@ -202,7 +244,7 @@ export default {
     // #ifdef APP-PLUS
     this.fillMobile = 1
     // #endif
-    getHasMap().then(res=>{
+    getHasMap().then(res => {
       this.hasMap = res.data.hasMap
     })
   },
@@ -213,6 +255,120 @@ export default {
 	},
   methods: {
     ...mapActions(['setUserShopAll']),
+    iconSrc,
+    ensureAppLocationPermission() {
+      return new Promise(async (resolve, reject) => {
+        // #ifdef APP-PLUS
+        if (plus.os.name === 'Android') {
+          const permissionRes = await permision.requestAndroidPermission('android.permission.ACCESS_FINE_LOCATION')
+          if (permissionRes !== 1) {
+            if (permissionRes === -1) {
+              permision.gotoAppPermissionSetting()
+            }
+            reject(new Error('请开启定位权限'))
+            return
+          }
+        }
+        if (!permision.checkSystemEnableLocation()) {
+          reject(new Error('请先开启系统定位服务'))
+          return
+        }
+        // #endif
+        resolve()
+      })
+    },
+    getDeviceLocation() {
+      return new Promise((resolve, reject) => {
+        const requestLocation = (locationType) => {
+          uni.getLocation({
+            type: locationType,
+            success: (res) => resolve({ ...res, locationType }),
+            fail: (err) => {
+              if (locationType === 'gcj02' && (
+                err.code == 18 ||
+                err.errCode == 18 ||
+                (err.errMsg && (
+                  err.errMsg.indexOf('not support gcj02') > -1 ||
+                  err.errMsg.indexOf('Not Support CoordsType') > -1
+                ))
+              )) {
+                requestLocation('wgs84')
+                return
+              }
+              reject(err)
+            }
+          })
+        }
+        // #ifdef APP-PLUS
+        if (plus.os.name === 'iOS') {
+          requestLocation('wgs84')
+          return
+        }
+        // #endif
+        requestLocation('gcj02')
+      })
+    },
+    closeNearbyPopup() {
+      this.showNearbyPopup = false
+    },
+    applyNearbyAddress(item) {
+      if (!item) {
+        return false
+      }
+      if (item.province) {
+        this.form.province = item.province
+      }
+      if (item.city) {
+        this.form.city = item.city
+      }
+      if (item.district) {
+        this.form.dist = item.district
+      }
+      this.form.address = item.name || item.address || ''
+      this.form.showAddress = item.showAddress || item.address || ''
+      if (item.location) {
+        const parts = String(item.location).split(',').map(v => v.trim())
+        if (parts.length >= 2) {
+          this.form.longitude = parts[0]
+          this.form.latitude = parts[1]
+        }
+      }
+      this.modifyShow()
+    },
+    selectNearbyAddress(item) {
+      this.applyNearbyAddress(item)
+      this.closeNearbyPopup()
+    },
+    async openNearbyAddress() {
+      if (this.locating) {
+        return false
+      }
+      this.locating = true
+      uni.showLoading({ title: '定位中', mask: true })
+      try {
+        await this.ensureAppLocationPermission()
+        const location = await this.getDeviceLocation()
+        const res = await mapNearby({
+          lat: location.latitude,
+          long: location.longitude,
+          locationType: location.locationType || 'gcj02'
+        })
+        if (res.code != 1 || !res.data || !res.data.list || res.data.list.length === 0) {
+          this.$msg('未获取到附近地址,请手动填写')
+          return false
+        }
+        this.nearbyList = res.data.list
+        this.showNearbyPopup = true
+        return true
+      } catch (err) {
+        console.log('openNearbyAddress fail', err)
+        this.$msg((err && err.message) ? err.message : '定位失败,请手动填写')
+        return false
+      } finally {
+        this.locating = false
+        uni.hideLoading()
+      }
+    },
     onHere(){
       this.form.province = '云南省'
       this.form.city = '昆明市'
@@ -235,7 +391,7 @@ export default {
             this.form.mobile = subRes.data.mobile
             this.checkShopFn({detail:{value:this.form.mobile}})
           }else{
-            this.$msg("没获取到手机号")    
+            this.$msg("没获取到手机号")
           }
 				});
 			} else {
@@ -315,6 +471,7 @@ export default {
     onCityConfirm (e) {
       this.form.province = e.provinceName;
       this.form.city = e.cityName;
+      this.modifyShow()
     },
     imgUploadSuccess(res) {
       var _res = JSON.parse(res.data)
@@ -327,28 +484,28 @@ export default {
       this.form.cover=''
     },
     selectRegion() {
-			if (!this.form.city) {
-				this.$msg('请先选择城市!')
-				return false
-			}
-			this.showRegion = true
-		},
-    modifyShow(){
-			this.form.showAddress = this.form.city+this.form.address+this.form.floor
-		},
+      if (!this.form.city) {
+        this.$msg('请先选择城市!')
+        return false
+      }
+      this.showRegion = true
+    },
     changeAreaFn(e) {
-			let locationStr = e.location
-			let fruits = locationStr.split(",").map(fruit => fruit.trim())
+      let locationStr = e.location
+      let fruits = locationStr.split(',').map(fruit => fruit.trim())
 
-			this.form.latitude = fruits[1]
-			this.form.longitude = fruits[0]
-			this.form.showAddress = e.address
+      this.form.latitude = fruits[1]
+      this.form.longitude = fruits[0]
+      this.form.showAddress = e.address
       this.form.address = e.name
 
-      // 提取地区信息,按遇到第一个"市"字后,把"市"后面的字符串作为地区
-			const districtStr = e.district || '';
-			const cityIndex = districtStr.indexOf('市');
-			this.form.dist = cityIndex !== -1 ? districtStr.substring(cityIndex + 1) : districtStr;
+      const districtStr = e.district || ''
+      const cityIndex = districtStr.indexOf('市')
+      this.form.dist = cityIndex !== -1 ? districtStr.substring(cityIndex + 1) : districtStr
+      this.modifyShow()
+    },
+    modifyShow(){
+			this.form.showAddress = this.form.city + this.form.address + this.form.floor
 		},
     formSubmit (e) {
       let rules = [
@@ -361,14 +518,12 @@ export default {
       let formData = this.form;
       let checkRes = form.validation(formData, rules)
 
-      // 检查是否同意服务协议和隐私政策
       if(this.agree == 0){
         this.$util.confirmModal({
           content:'请阅读并同意服务协议和隐私政策',
           okText:'同意',
           cancelText:'不同意'
         },() => {
-          // 点击同意时,直接执行下一步
           this.agree = 1
           if (!checkRes) {
             uni.showLoading({mask:true})
@@ -401,7 +556,7 @@ export default {
       let style = this.option.style || 0
       let from = this.option.from || 0
       let that = this
-      this.form.showAddress = this.form.city+this.form.address+this.form.floor
+      this.form.showAddress = this.form.city + this.form.address + this.form.floor
       uni.showLoading({mask:true})
       let appRegister = 0
       // #ifdef APP-PLUS
@@ -425,7 +580,6 @@ export default {
           that.$msg('出错了')
           return false
         }
-        //有几个地方涉及登陆,需要统一方法,请搜索关键词 uni_login
         if(subRes.code == 1){
           if (that.$util.isEmpty(subRes)) {
             that.$msg('出错了')
@@ -441,8 +595,8 @@ export default {
             that.$store.commit('setMyShopInfo', { ...res.data.shop, ...res.data })
           })
           that.$store.commit('setLoginInfo', { ...subRes.data.admin, ...subRes.data })
-          getShopInfo(true).then(res => { 
-            uni.setNavigationBarTitle({ title: res.name }) 
+          getShopInfo(true).then(res => {
+            uni.setNavigationBarTitle({ title: res.name })
           })
           that.setUserShopAll()
 
@@ -451,7 +605,6 @@ export default {
         const registerInviteQuery = getGhsProductQueryFromPending()
 
         const goAfterRegister = () => {
-          //去失信人员列表
           if(this.option.fromType && this.option.fromType == 2){
             this.$util.pageTo({url: "/admin/ll/list", type:2})
             return
@@ -482,73 +635,283 @@ export default {
 };
 </script>
 <style lang="scss" scoped>
+.apply-page {
+  min-height: 100vh;
+  background: #f2f7f4;
+}
+
+.apply-body {
+  padding: 24upx 24upx 48upx;
+}
+
+.apply-section {
+  margin-bottom: 24upx;
+}
+
+.apply-section-title {
+  margin-bottom: 16upx;
+  padding-left: 8upx;
+  color: #161819;
+  font-size: 30upx;
+  font-weight: 700;
+  line-height: 42upx;
+}
+
+.apply-card {
+  margin-bottom: 0;
+  border-radius: 20upx;
+  overflow: hidden;
+  box-shadow: 0 8upx 24upx rgba(9, 197, 103, 0.08);
+}
+
 .module-com {
-  margin-bottom: 20upx;
   background-color: #fff;
-  .module-tit {
-    padding: 20upx 18upx;
-    font-size: 28upx;
-    font-weight: 600;
-    border-bottom: 1upx solid $borderColor;
+}
+
+.apply-mode-btns {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  flex: 1;
+  min-width: 0;
+}
+
+.apply-mode-btn {
+  flex: 1;
+  min-width: 0;
+  height: 64upx;
+  line-height: 64upx;
+  text-align: center;
+  color: #6b737c;
+  font-size: 26upx;
+  border-radius: 999upx;
+  background: #f2f7f4;
+  border: 1upx solid #e3ebe6;
+}
+
+.apply-mode-btn--last {
+  margin-left: 16upx;
+}
+
+.apply-mode-btn--active {
+  color: #fff;
+  background: #09c567;
+  border-color: #09c567;
+  font-weight: 600;
+}
+
+.line-cell--city {
+  .city-row-main {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .city-locate-btn {
+    flex-shrink: 0;
+    width: 72upx;
+    height: 72upx;
+    margin-left: 12upx;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 50%;
+    background: #e8f8f0;
   }
-  .module-det {
-    padding: 0 30upx;
+
+  .city-locate-icon {
+    width: 40upx;
+    height: 40upx;
+    display: block;
+  }
+}
+
+.nearby-popup-wrap {
+  ::v-deep .tui-popup-class {
+    border-top-left-radius: 20upx;
+    border-top-right-radius: 20upx;
   }
 }
-// 公共
+
+.nearby-popup {
+  background: #fff;
+}
+
+.nearby-popup-head {
+  position: relative;
+  padding: 30upx 80upx 24upx;
+  text-align: center;
+}
+
+.nearby-popup-title {
+  color: #161819;
+  font-size: 34upx;
+  font-weight: 700;
+  line-height: 48upx;
+}
+
+.nearby-list {
+  max-height: 60vh;
+  padding: 0 24upx 40upx;
+  box-sizing: border-box;
+}
+
+.nearby-item {
+  padding: 24upx 8upx;
+  border-bottom: 1upx solid #f0f2f1;
+}
+
+.nearby-item-name {
+  color: #161819;
+  font-size: 30upx;
+  font-weight: 600;
+  line-height: 42upx;
+}
+
+.nearby-item-address {
+  margin-top: 8upx;
+  color: #8a9199;
+  font-size: 26upx;
+  line-height: 38upx;
+}
+
+.nearby-empty {
+  padding: 60upx 0;
+  text-align: center;
+  color: #8a9199;
+  font-size: 28upx;
+}
+
 .line-cell {
   .tui-title {
-    width: 210upx;
-    color: $fontColor2;
+    width: 180upx;
+    color: #5c6673;
+    font-size: 28upx;
   }
   .tui-input {
-    width: calc(100% - 210upx);
+    flex: 1;
+    min-width: 0;
+    width: auto;
     font-size: 28upx;
+    color: #161819;
   }
   .tui-placeholder {
+    flex: 1;
+    min-width: 0;
     color: #ccc;
   }
   .phcolor {
     color: #ccc;
   }
 }
-.btn-wrap {
-  width: 90%;
-  margin: 60upx auto;
-  .admin-button-com {
-    width: 100%;
-    margin: 0 auto;
-  }
-}
-// 验证码
+
 .code-wrap {
-  .tui-input {
-    width: calc(100% - 410upx);
-    font-size: 28upx;
-  }
-  .tui-code {
-    width: 200upx;
-    text-align: center;
-    border-left: 1upx solid $borderColor;
-    color: $mainColor;
+  .tui-input--code {
+    margin-right: 16upx;
   }
 }
-// 推荐人
+
+.apply-code-btn {
+  flex-shrink: 0;
+  min-width: 140upx;
+  height: 64upx;
+  margin: 0;
+  padding: 0 24upx;
+  line-height: 64upx;
+  border: none;
+  border-radius: 999upx;
+  color: #fff;
+  font-size: 26upx;
+  font-weight: 600;
+  background: #09c567;
+}
+
+.apply-code-btn::after {
+  border: none;
+}
+
+.apply-code-btn--disabled {
+  color: #8a9199;
+  background: #eef1f5;
+}
+
+.apply-agreement {
+  margin-top: 8upx;
+  padding: 0 8upx;
+}
+
+.apply-agreement-label {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+
+.apply-checkbox {
+  transform: scale(0.82);
+  flex-shrink: 0;
+}
+
+.apply-agreement-text {
+  flex: 1;
+  margin-left: 8upx;
+  color: #8a9199;
+  font-size: 24upx;
+  line-height: 36upx;
+}
+
+.apply-agreement-link {
+  color: #09c567;
+  font-weight: 600;
+}
+
+.apply-submit-wrap {
+  margin-top: 40upx;
+  padding: 0 8upx;
+}
+
+.apply-submit-btn {
+  width: 100%;
+  height: 96upx;
+  margin: 0;
+  padding: 0;
+  line-height: 96upx;
+  border: none;
+  border-radius: 999upx;
+  color: #fff;
+  font-size: 32upx;
+  font-weight: 600;
+  text-align: center;
+  background: #09c567;
+  box-shadow: 0 10upx 24upx rgba(9, 197, 103, 0.24);
+}
+
+.apply-submit-btn::after {
+  border: none;
+}
+
 .recommend-wrap {
-  padding: 30upx 45upx;
+  padding: 28upx 32upx;
+  margin-bottom: 24upx;
   .recommend-tag {
     font-size: 28upx;
-    color: $fontColor2;
-    margin-bottom: 24upx;
+    color: #5c6673;
+    font-weight: 600;
+    margin-bottom: 20upx;
   }
   .recommend-det {
     @include disFlex(center, flex-start);
+    .recommend-avatar {
+      width: 90upx;
+      height: 90upx;
+      border-radius: 45upx;
+      flex-shrink: 0;
+    }
     .recommend-info {
       margin-left: 20upx;
       .app-size-32 {
         margin-bottom: 4upx;
+        color: #161819;
       }
     }
   }
 }
-</style>
+</style>