You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
14 KiB

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
  1. <template>
  2. <view class="container">
  3. <view class="address-info ">
  4. <u--form labelPosition="left" ref="uForm">
  5. <u-form-item required label="联系人" prop="addressInfo.name" labelWidth="120" borderBottom>
  6. <u--input v-model="addressInfo.name" placeholder="请输入联系人姓名" placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right"></u--input>
  7. </u-form-item>
  8. <u-form-item required label="手机号码" prop="addressInfo.phone" labelWidth="120" borderBottom>
  9. <u--input v-model="addressInfo.phone" placeholder="请输入手机号码" placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right"></u--input>
  10. </u-form-item>
  11. <u-form-item label="应急联络" prop="addressInfo.emergencyPhone" labelWidth="120" borderBottom>
  12. <u--input v-model="addressInfo.emergencyPhone" placeholder="请输入应急联络号码" placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right"></u--input>
  13. </u-form-item>
  14. <!-- <u-form-item label="所在城市" prop="addressInfo.city" labelWidth="120" borderBottom>
  15. <picker mode="multiSelector" @columnchange="columnchange" @change="bindMultiPickerColumnChange" :value="multiIndex"
  16. :range="multiArray">
  17. <view style="display: flex;justify-content: space-between;">
  18. <u--input :value="addressInfo.city? (addressInfo.city +' '+ addressInfo.district):''"
  19. disabled disabledColor="#ffffff" placeholder="请选择所在城市"
  20. placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right">
  21. </u--input>
  22. <u-icon slot="right" name="arrow-right" color="#AAA"></u-icon>
  23. </view>
  24. </picker>
  25. </u-form-item> -->
  26. <u-form-item label="所在地区" prop="addressInfo.city" labelWidth="120" borderBottom>
  27. <view style="display: flex;justify-content: space-between;" @click="selectAddress">
  28. <u--input :value="addressInfo.selectAddress"
  29. disabled disabledColor="#ffffff" placeholder="请选择所在地区"
  30. placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right">
  31. </u--input>
  32. <u-icon slot="right" name="arrow-right" color="#AAA"></u-icon>
  33. </view>
  34. </u-form-item>
  35. <u-form-item label="详细地址" prop="addressInfo.detailAddress" labelWidth="120" borderBottom>
  36. <u--input v-model="addressInfo.detailAddress" placeholder="如楼栋、门牌号" placeholderStyle="text-align:right;color:#AAA;" border="none" inputAlign="right"></u--input>
  37. </u-form-item>
  38. <u-form-item label="设为默认地址" prop="addressInfo.isDefault" labelWidth="120">
  39. <view>
  40. <u-radio-group :value="addressInfo.isDefault?'默认':''" placement="column" @change="groupChange">
  41. <u-radio name="默认" activeColor="#ffbf60" labelColor="#ffbf60" label="默认"></u-radio>
  42. </u-radio-group>
  43. </view>
  44. </u-form-item>
  45. </u--form>
  46. </view>
  47. <view class="address-save">
  48. <button class="address-save-btn" @click="save" :loading="loading">保存并使用</button>
  49. </view>
  50. </view>
  51. </template>
  52. <script>
  53. import {
  54. getCity
  55. } from '@/api/system/user.js'
  56. import {
  57. getAddressDetails,addAddress,updateAddress
  58. } from '@/api/system/address.js'
  59. export default{
  60. data(){
  61. return{
  62. loading:false,
  63. needRelocate: false, // 是否需要重新定位
  64. addressInfo:{
  65. name:"",
  66. phone:"",
  67. emergencyPhone:"",
  68. province:"",
  69. city:"",
  70. district:'',
  71. detailAddress:"",
  72. openId:"",
  73. isDefault:0,
  74. latitude:"",
  75. longitude:"",
  76. selectAddress:""
  77. },
  78. multiArray: [],
  79. cityList:[],
  80. multiIndex: [0, 0],
  81. addressId:'',
  82. }
  83. },
  84. onLoad(option) {
  85. this.optionType=option.optionType;
  86. this.needRelocate = option.needRelocate === 'true'; // 是否需要重新定位
  87. if(this.optionType=='edit'){
  88. this.addressId=option.addressId;
  89. this.getAddressDetails(option.addressId);
  90. }
  91. },
  92. mounted() {
  93. this.getCityList()
  94. },
  95. methods:{
  96. getAddressDetails(id){
  97. getAddressDetails(id).then(res=>{
  98. if(res&& res.id){
  99. const {
  100. name,
  101. phone,
  102. emergencyPhone,
  103. province,
  104. city,
  105. district,
  106. detailAddress,
  107. openId,
  108. isDefault,
  109. latitude,
  110. longitude,
  111. } = res;
  112. // 检查是否需要重新定位或缺少经纬度信息
  113. const needClearLocation = this.needRelocate || !latitude || !longitude;
  114. this.addressInfo = {
  115. name,
  116. phone,
  117. emergencyPhone,
  118. province: needClearLocation ? '' : province,
  119. city: needClearLocation ? '' : city,
  120. district: needClearLocation ? '' : district,
  121. detailAddress,
  122. openId,
  123. isDefault,
  124. latitude: needClearLocation ? '' : latitude,
  125. longitude: needClearLocation ? '' : longitude,
  126. selectAddress: needClearLocation ? '' : `${province}${city}${district}`,
  127. };
  128. // 如果需要重新定位,提示用户
  129. if(needClearLocation) {
  130. setTimeout(() => {
  131. this.$modal.showToast('请重新选择所在地区进行定位');
  132. }, 500);
  133. }
  134. }else{
  135. this.$modal.showToast('获取地址详情失败')
  136. }
  137. })
  138. },
  139. // 选择地区
  140. selectAddress(){
  141. uni.chooseLocation({
  142. success: res => {
  143. console.log(res);
  144. this.addressInfo.latitude = res.latitude
  145. this.addressInfo.longitude = res.longitude
  146. // 获取完整地址
  147. let address = ''
  148. if (!res.address && res.name) {
  149. address = res.name
  150. } else if (res.address || res.name) {
  151. address = (res.address || '') + (res.name || '')
  152. }
  153. if(!address){
  154. return
  155. }
  156. // 解析地址信息
  157. const addressInfo = this.parseAddress(address);
  158. this.addressInfo.province = addressInfo.province
  159. this.addressInfo.city = addressInfo.city
  160. this.addressInfo.district = addressInfo.district
  161. this.addressInfo.detailAddress = addressInfo.detailAddress
  162. this.addressInfo.selectAddress = addressInfo.selectAddress
  163. },
  164. fail(e) {
  165. console.log("获取位置信息失败!", e)
  166. }
  167. })
  168. },
  169. save(){
  170. let params = this.addressInfo
  171. if(params.phone){
  172. if(!(/^1[3456789]\d{9}$/.test(params.phone))){
  173. this.$modal.showToast('手机号码有误')
  174. return false;
  175. }
  176. } else {
  177. this.$modal.showToast('请输入手机号')
  178. return false;
  179. }
  180. if(params.emergencyPhone){
  181. if(!(/^1[3456789]\d{9}$/.test(params.emergencyPhone))){
  182. this.$modal.showToast('手机号码有误')
  183. return false;
  184. }
  185. }
  186. if(!params.name){
  187. this.$modal.showToast('请输入联系人')
  188. return false;
  189. }
  190. // 所在地区与详细地址必填校验
  191. if(!params.province && !params.city && !params.district){
  192. this.$modal.showToast('请选择所在地区')
  193. return false;
  194. }
  195. // 需具备定位信息(经纬度)
  196. if(!params.latitude || !params.longitude){
  197. this.$modal.showToast('定位信息缺失,请重新选择所在地区')
  198. this.addressInfo.province = ''
  199. this.addressInfo.city = ''
  200. this.addressInfo.district = ''
  201. this.addressInfo.selectAddress = ''
  202. return false;
  203. }
  204. if(!params.detailAddress){
  205. this.$modal.showToast('请输入详细地址')
  206. return false;
  207. }
  208. this.loading=true
  209. if(this.optionType=='edit'){
  210. params.id = this.addressId;
  211. updateAddress(params).then(res=>{
  212. if(res&&res==1){
  213. this.$globalData.newOrderData.currentAddress={
  214. id:params.id,
  215. name:params.name,
  216. phone:params.phone,
  217. province:params.province,
  218. city:params.city,
  219. district:params.district,
  220. detailAddress:params.detailAddress,
  221. latitude:params.latitude,
  222. longitude:params.longitude,
  223. }
  224. this.loading=false
  225. uni.redirectTo({
  226. url: `/pages/newOrder/serviceNew`
  227. });
  228. }else {
  229. this.loading=false
  230. this.$modal.showToast('更新地址失败')
  231. }
  232. })
  233. } else if(this.optionType=='add'){
  234. addAddress(params).then(res=>{
  235. if(res&&res>0){
  236. this.$globalData.newOrderData.currentAddress={
  237. id:res,
  238. name:params.name,
  239. phone:params.phone,
  240. province:params.province,
  241. city:params.city,
  242. district:params.district,
  243. detailAddress:params.detailAddress,
  244. latitude:params.latitude,
  245. longitude:params.longitude,
  246. }
  247. this.loading=false
  248. uni.redirectTo({
  249. url: `/pages/newOrder/serviceNew`
  250. });
  251. }else {
  252. this.loading=false
  253. this.$modal.showToast('新增地址失败')
  254. }
  255. })
  256. }
  257. },
  258. getCityList() {
  259. getCity().then(res => {
  260. if (res.code == 200) {
  261. console.log('city', JSON.parse(res.msg));
  262. this.cityList = JSON.parse(res.msg)
  263. const cityLabels = this.cityList.map(item =>item.city)
  264. this.multiArray[0] = cityLabels
  265. this.multiArray[1] = this.cityList[0].region.map(e=> e.region)
  266. } else {
  267. this.$modal.showToast('获取城市失败,请联系系统管理员!');
  268. }
  269. })
  270. },
  271. columnchange(e){
  272. console.log(e)
  273. // 当滚动切换一级分类时,为当前的一级分类添加它的子类
  274. if (e.detail.column == 0) {
  275. const currentCity = this.cityList[e.detail.value]
  276. // #ifdef H5
  277. // 在小程序中直接赋值无效 H5 可直接赋值
  278. this.multiArray[1] = currentCity.region.map(e=>e.region)
  279. // #endif
  280. // #ifdef MP-WEIXIN
  281. // 在 H5 环境下 $set 会导致一级分类无法滚动, 小程序正常运行
  282. this.$set(this.multiArray, 1, currentCity.region.map(e=>e.region))
  283. // #endif
  284. this.multiIndex=[e.detail.value,0]
  285. }
  286. },
  287. bindMultiPickerColumnChange(e) {
  288. console.log('值为:' + e.detail.value)
  289. this.multiIndex = e.detail.value
  290. this.addressInfo.province = this.multiArray[0][this.multiIndex[0]]
  291. this.addressInfo.city = this.multiArray[0][this.multiIndex[0]]
  292. this.addressInfo.district = this.multiArray[1][this.multiIndex[1]]
  293. this.isSelected = true
  294. this.$forceUpdate()
  295. },
  296. groupChange(n) {
  297. console.log('groupChange', n);
  298. this.addressInfo.isDefault=+(!this.addressInfo.isDefault)
  299. },
  300. // 智能解析地址信息
  301. parseAddress(address) {
  302. if (!address) {
  303. return {
  304. province: '',
  305. city: '',
  306. district: '',
  307. detailAddress: '',
  308. selectAddress: ''
  309. };
  310. }
  311. console.log(address);
  312. // 直辖市列表
  313. const municipalities = ['北京市', '上海市', '天津市', '重庆市'];
  314. // 省级行政区正则
  315. const provinceReg = /(.*?(?:省|自治区|特别行政区))/;
  316. // 市级行政区正则
  317. const cityReg = /(.*?(?:市|自治州|地区|盟))/;
  318. // 区县级行政区正则
  319. const districtReg = /(.*?(?:区|县|市|旗|自治县|自治旗))/;
  320. let province = '';
  321. let city = '';
  322. let district = '';
  323. let detailAddress = '';
  324. let remainingAddress = address;
  325. // 检查是否为直辖市
  326. const municipality = municipalities.find(m => address.includes(m));
  327. if (municipality) {
  328. province = municipality;
  329. city = municipality;
  330. remainingAddress = address.substring(address.indexOf(municipality) + municipality.length);
  331. // 对于直辖市,需要特殊处理区县解析
  332. // 先尝试匹配区县名称
  333. const districtMatch = remainingAddress.match(/^(.*?(?:区|县|市|旗|自治县|自治旗))/);
  334. if (districtMatch) {
  335. district = districtMatch[1];
  336. detailAddress = remainingAddress.substring(districtMatch[0].length).trim();
  337. } else {
  338. // 如果没有匹配到区县,整个剩余部分作为详细地址
  339. detailAddress = remainingAddress.trim();
  340. }
  341. } else {
  342. // 非直辖市,按省市区县顺序解析
  343. // 解析省份
  344. const provinceMatch = remainingAddress.match(provinceReg);
  345. if (provinceMatch) {
  346. province = provinceMatch[1];
  347. remainingAddress = remainingAddress.substring(provinceMatch[0].length);
  348. }
  349. // 解析城市
  350. const cityMatch = remainingAddress.match(cityReg);
  351. if (cityMatch) {
  352. city = cityMatch[1];
  353. remainingAddress = remainingAddress.substring(cityMatch[0].length);
  354. }
  355. // 解析区县
  356. const districtMatch = remainingAddress.match(districtReg);
  357. if (districtMatch) {
  358. district = districtMatch[1];
  359. remainingAddress = remainingAddress.substring(districtMatch[0].length);
  360. }
  361. detailAddress = remainingAddress.trim();
  362. }
  363. // 如果没有解析到省份,但有城市,可能是省级市
  364. if (!province && city) {
  365. province = city;
  366. }
  367. const selectAddress = `${province}${city !== province ? city : ''}${district}`;
  368. return {
  369. province,
  370. city,
  371. district,
  372. detailAddress,
  373. selectAddress
  374. };
  375. }
  376. }
  377. }
  378. </script>
  379. <style lang="scss">
  380. .container {
  381. position: relative;
  382. height: 100%;
  383. padding-bottom: 90px;
  384. .address-save {
  385. background-color: #FFFFFF;
  386. padding: 10px 20px 40px;
  387. width: 100%;
  388. height: 90px;
  389. position: fixed;
  390. bottom: 0;
  391. z-index: 100;
  392. .address-save-btn {
  393. width: 100%;
  394. border-radius: 6px;
  395. background: #FFB13F;
  396. font-size: 16px;
  397. color: #FFFFFF;
  398. }
  399. }
  400. }
  401. .address-info{
  402. background-color: #fff;
  403. padding: 10px 20px;
  404. .u-radio-group{
  405. float: right;
  406. }
  407. }
  408. </style>