Procházet zdrojové kódy

修改省市区插件

1004749546@qq.com před 4 roky
rodič
revize
9f8bd87dfe
4 změnil soubory, kde provedl 492 přidání a 22 odebrání
  1. 21 0
      api/data.js
  2. 442 0
      components/address.vue
  3. 2 1
      pages.json
  4. 27 21
      pages/toOrder/editAddress.vue

+ 21 - 0
api/data.js

@@ -13,4 +13,25 @@ export const openDevice = (params) => {
     method: 'post',
 	data: params
   })
+}
+//查询省
+export const  getProvince = () => {
+  return axios.request({
+    url: `area/PROVINCE`,
+    method: 'get'
+  })
+}
+//查询市
+export const  getCityByPro = params => {
+  return axios.request({
+    url: `area/CITY/${params.id}`,
+    method: 'get'
+  })
+}
+//查询区
+export const  getDistrictByCity = params => {
+  return axios.request({
+    url: `area/DISTRICT/${params.id}`,
+    method: 'get'
+  })
 }

+ 442 - 0
components/address.vue

@@ -0,0 +1,442 @@
+<template>
+	<view class="simple-address" v-if="showPopup">
+		<!-- 遮罩层 -->
+		<view
+			class="simple-address-mask"
+			v-if="maskClick"
+			:class="[ani + '-mask', animation ? 'mask-ani' : '']"
+			:style="{
+				'background-color': maskBgColor
+			}"
+			@tap="hideMask(true)"
+		></view>
+		
+		<!-- 省市区 -->
+		<view class="simple-address-content simple-address--fixed" :class="[type, ani + '-content', animation ? 'content-ani' : '']">
+			<view class="simple-address__header">
+				<view class="simple-address__header-btn-box" @click="pickerCancel">
+					<text class="simple-address__header-text" :style="{ color: cancelColor, fontSize: btnFontSize }">取消</text>
+				</view>
+				<view class="simple-address__header-btn-box" @click="pickerConfirm">
+					<text class="simple-address__header-text" :style="{ color: confirmColor, fontSize: btnFontSize }">确定</text>
+				</view>
+			</view>
+			<view class="simple-address__box">
+				<picker-view indicator-style="height: 70rpx;" class="simple-address-view" :value="pickerValue" @change="pickerChange">
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+				</picker-view>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	import { getProvince, getCityByPro, getDistrictByCity } from '@/api/data.js'
+	export default{
+		name: 'Address',
+		props: {
+			// 是否允许点击遮罩层关闭
+			maskClick: {
+				type: Boolean,
+				default: true
+			},
+			// 是否开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			//  遮罩层背景颜色
+			maskBgColor: {
+				type: String,
+				default: 'rgba(0, 0, 0, 0.4)' //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss
+			},
+			/* 弹出层类型,可选值;  暂时只支持底部弹出
+					bottom:底部弹出层
+				*/
+			type: {
+				type: String,
+				default: 'bottom'
+			},
+			cancelColor: {
+				type: String,
+				default: '' // 取消按钮颜色
+			},
+			confirmColor: {
+				type: String,
+				default: '' // 确认按钮颜色
+			},
+			fontSize: {
+				type: String,
+				default: '28rpx' // picker-item字体大小
+			},
+			btnFontSize: {
+				type: String,
+				default: '' // 按钮的字体大小
+			},
+		},
+		data(){
+			return{
+				showPopup: false,  //  是否显示省市区选择
+				ani: '',
+				pickerValue: [0, 0, 0],  //  默认值下标
+				pickerId: [],  //  省市区默认值id
+				provinceDataList: [],  //  省数据列表
+				cityDataList: [],  //  市数据列表
+				areaDataList: [],  //  区数据列表
+				isFirst: false,  //  是否首次进入组件
+			}
+		},
+		methods: {
+			//  初始化
+			init(){
+				this.provinceDataList = []
+				this.cityDataList = []
+				this.areaDataList = []
+				this.isFirst = false
+			},
+			//  点击遮罩层关闭选择省市区
+			hideMask() {
+				this._$emit('onCancel')
+				this.close()
+			},
+			//  打开省市区picker
+			open(idArr) {
+				//  初始化数据
+				this.init()
+				this.pickerId = idArr
+				//  idArr 省市区默认id
+				if(this.pickerId && this.pickerId.length > 0){
+					//  获取省下拉
+					this.getProvinceList(idArr)
+				}else{
+					//  获取省下拉
+					this.getProvinceList()
+				}
+				this.showPopup = true
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.ani = 'simple-' + this.type
+					}, 100)
+				});
+			},
+			//  关闭省市区picker
+			close(type) {
+				if (!this.maskClick && type) return
+				this.ani = ''
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			//  取消按钮
+			pickerCancel() {
+				this._$emit('onCancel')
+				this.close()
+			},
+			//  确定按钮
+			pickerConfirm() {
+				this._$emit('onConfirm')
+				if(!this.isFirst){
+					//  首次
+					this.isFirst = true
+				}
+				this.close()
+			},
+			//  省市区  change
+			pickerChange(e) {
+				const _this = this
+				let changePickerValue = e.detail.value
+				
+				if (this.pickerValue[0] !== changePickerValue[0]) {
+					if(this.pickerId && this.pickerId.length > 0 && this.isFirst){
+						//  获取市下拉
+						this.getCityList(this.pickerId[0], this.pickerId)
+					}else{
+						// 第一级发生滚动,省 change重置市区下拉数据
+						this.getCityList(this.provinceDataList[changePickerValue[0]].id)
+						changePickerValue[1] = 0
+						changePickerValue[2] = 0
+					}
+				} else if (this.pickerValue[1] !== changePickerValue[1]) {
+					if(this.pickerId && this.pickerId.length > 0 && this.isFirst){
+						//  获取市下拉
+						this.getAreaList(this.pickerId[1], this.pickerId)
+					}else{
+						// 第二级滚动,市 change重置区县下拉数据
+						this.getAreaList(this.cityDataList[changePickerValue[1]].id)
+						changePickerValue[2] = 0
+					}
+				}
+				this.pickerValue = changePickerValue
+				//  setTimeout解决由于省市区接口请求数据有延缓导致获值报错
+				setTimeout(()=>{
+					_this._$emit('onChange')
+				},1000)
+			},
+			_$emit(emitName) {
+				let pickObj = {
+					label: this._getLabel(),
+					value: this.pickerValue,
+					cityCode: this._getCityCode(),
+					areaCode: this._getAreaCode(),
+					provinceCode: this._getProvinceCode(),
+					labelArr: this._getLabel().split('-')
+				}
+				this.$emit(emitName, pickObj)
+			},
+			_getLabel() {
+				//  name报错未发现页面影响(由于省市区接口请求数据延缓)
+				let pcikerLabel =
+					this.provinceDataList[this.pickerValue[0]].name + '-' + this.cityDataList[this.pickerValue[1]].name + '-' + this.areaDataList[this.pickerValue[2]].name
+				return pcikerLabel
+			},
+			_getCityCode() {
+				return this.cityDataList[this.pickerValue[1]].id
+			},
+			_getProvinceCode() {
+				return this.provinceDataList[this.pickerValue[0]].id
+			},
+			_getAreaCode() {
+				return this.areaDataList[this.pickerValue[2]].id
+			},
+			//  获取省下拉数据
+			getProvinceList(idArr){
+				const _this = this
+				getProvince().then(res => {
+				  if (res.code == 200 || res.status == 204 || res.status == 200) {
+				    _this.provinceDataList = res.data || []  //  省下拉数据
+					//  判断是否有默认值
+					if(idArr){
+						_this.getCityList(idArr[0], idArr)
+						_this.getAreaIndArr(idArr)
+					}else{
+						//  默认省数据第一条下的市下拉数据
+						_this.getCityList(_this.provinceDataList[0].id)
+					}
+					
+				  } else {
+				    _this.provinceDataList = []
+				  }
+				})
+			},
+			// 获取城市列表
+			getCityList (val, idArr) {
+				const _this = this
+				_this.cityDataList = []
+				_this.areaDataList = []
+				if (val != null && val != '') {
+					getCityByPro({id: val}).then(res => {
+						if (res.code == 200 || res.status == 204 || res.status == 200) {
+							_this.cityDataList = res.data || []  //  市下拉数据
+							//  判断是否有默认值
+							if(idArr){
+								_this.getAreaList(idArr[1], idArr)
+								_this.getAreaIndArr(idArr)
+							}else{
+								//  默认市数据第一条下的区县下拉数据
+								_this.getAreaList(_this.cityDataList[0].id)
+							}
+						} else {
+							_this.cityDataList = []
+						}
+					})
+				}
+			},
+			// 获取区县列表
+			getAreaList (val, idArr) {
+				const _this = this
+				this.areaDataList = []
+				if (val != null && val != '') {
+					getDistrictByCity({id: val}).then(res => {
+						if (res.code == 200 || res.status == 204 || res.status == 200) {
+							_this.areaDataList = res.data || []
+							//  判断是否有默认值
+							if(idArr){ _this.getAreaIndArr(idArr) }
+						} else {
+							_this.areaDataList = []
+						}
+					})
+				}
+			},
+			//  根据id 获取省市区 下标值
+			getAreaIndArr(idArr){
+				const _this = this
+				const provinceInd = _this.provinceDataList.findIndex(res => res['id'] == idArr[0])
+				const cityInd = _this.cityDataList.findIndex(res => res['id'] == idArr[1])
+				const districtInd = _this.areaDataList.findIndex(res => res['id'] == idArr[2])
+				setTimeout(()=>{
+					_this.pickerValue = [provinceInd, cityInd, districtInd]
+				},100)
+				// console.log(_this.pickerValue,'_this.pickerValue')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+.simple-address {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: column;
+}
+
+.simple-address-mask {
+	position: fixed;
+	bottom: 0;
+	top: 0;
+	left: 0;
+	right: 0;
+
+	transition-property: opacity;
+	transition-duration: 0.3s;
+	opacity: 0;
+	/* #ifndef APP-NVUE */
+	z-index: 99;
+	/* #endif */
+}
+
+.mask-ani {
+	transition-property: opacity;
+	transition-duration: 0.2s;
+}
+
+.simple-bottom-mask {
+	opacity: 1;
+}
+
+.simple-center-mask {
+	opacity: 1;
+}
+
+.simple-address--fixed {
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	transition-property: transform;
+	transition-duration: 0.3s;
+	transform: translateY(460rpx);
+	/* #ifndef APP-NVUE */
+	z-index: 99;
+	/* #endif */
+}
+
+.simple-address-content {
+	background-color: #ffffff;
+}
+
+.simple-content-bottom {
+	bottom: 0;
+	left: 0;
+	right: 0;
+	transform: translateY(500rpx);
+}
+
+.content-ani {
+	transition-property: transform, opacity;
+	transition-duration: 0.2s;
+}
+
+.simple-bottom-content {
+	transform: translateY(0);
+}
+
+.simple-center-content {
+	transform: scale(1);
+	opacity: 1;
+}
+
+.simple-address__header {
+	position: relative;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	flex-wrap: nowrap;
+	justify-content: space-between;
+	border-bottom-color: #f2f2f2;
+	border-bottom-style: solid;
+	border-bottom-width: 1rpx;
+}
+
+.simple-address--fixed-top {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	justify-content: space-between;
+	border-top-color: $uni-border-color;
+	border-top-style: solid;
+	border-top-width: 1rpx;
+}
+
+.simple-address__header-btn-box {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+	height: 70rpx;
+}
+
+.simple-address__header-text {
+	text-align: center;
+	font-size: $uni-font-size-base;
+	color: #1aad19;
+	line-height: 70rpx;
+	padding-left: 40rpx;
+	padding-right: 40rpx;
+}
+
+.simple-address__box {
+	position: relative;
+}
+
+.simple-address-view {
+	position: relative;
+	bottom: 0;
+	left: 0;
+	/* #ifndef APP-NVUE */
+	width: 100%;
+	/* #endif */
+	/* #ifdef APP-NVUE */
+	width: 750rpx;
+	/* #endif */
+	height: 408rpx;
+	background-color: rgba(255, 255, 255, 1);
+}
+
+.picker-item {
+	text-align: center;
+	line-height: 70rpx;
+	text-overflow: ellipsis;
+	font-size: 28rpx;
+}
+</style>

+ 2 - 1
pages.json

@@ -100,7 +100,8 @@
 		{
 			"path": "pages/order/order",
 			"style": {
-				"navigationBarTitleText": "我的订单"
+				"navigationBarTitleText": "我的订单",
+				"enablePullDownRefresh": true
 			}
 		}, {
 			"path": "pages/order/orderDetail",

+ 27 - 21
pages/toOrder/editAddress.vue

@@ -8,8 +8,8 @@
 				<u-input placeholder="请输入电话" :maxlength="11" type="number" v-model="form.receiverPhone" />
 			</u-form-item>
 			<u-form-item label="省市区" required prop="receiveAreasName">
-				<u-input v-model="form.receiveAreasName" placeholder="请选择省市区" @click="show = true" type="select" />
-				<u-picker v-model="show" @confirm="chooseArea" mode="region"></u-picker>
+				<u-input v-model="areaInfo.label" placeholder="请选择省市区" @click="openAddress" type="select" />
+				<Address ref="applyAddress" @onConfirm="areaConfirm"></Address>
 			</u-form-item>
 			<u-form-item label="详细地址" required prop="receiveAddress">
 				<u-input type="textarea" placeholder="请输入收货详细地址(最多500个字符)" :maxlength="500" v-model="form.receiveAddress" />
@@ -25,18 +25,23 @@
 	import {
 		saveAddress
 	} from '@/api/receiveAddress.js'
+	import Address from '@/components/address.vue'
 	export default {
+		components: {
+			Address
+		},
 		data() {
 			return {
 				show: false,
 				form: {
 					receiverName: '',
 					receiverPhone: '',
-					receiveAreasName: '', // 地址名称
 					receiveAddress: '' // 详细地址
 				},
 				receiveAreas: '', //地址编码
 				areaName: '', //地址
+				areaInfo: {},  //  省市区
+				areaIdArr: [],  //  省市区id数组
 				rules: {
 				}
 			};
@@ -44,9 +49,8 @@
 		onLoad(option) {
 			this.form = this.$store.state.vuex_OrderAddress
 			if (this.form.receiveAreasName) {
-				this.receiveAreas = this.form.receiveAreas
-				this.areaName = this.form.receiveAreasName
-				this.form.receiveAreasName = this.form.receiveAreasName.replace(/\,/g,'-')
+				this.areaIdArr = this.form.receiveAreas.split(',')
+				this.areaInfo.label = this.form.receiveAreasName.replace(/\,/g,'-')
 				uni.setNavigationBarTitle({
 					title: '修改地址'
 				})
@@ -78,12 +82,10 @@
 							})
 							return false
 						}
-						if (this.form.receiveAreasName ==='') {
-							uni.showToast({
-								title: '请选择省市区',
-								icon: 'none'
-							})
-							return false
+						//  省市区
+						if(this.areaIdArr.length == 0){
+							uni.showToast({icon: 'none',title: '请选择省市区'})
+							return
 						}
 						if (this.form.receiveAddress ==='') {
 							uni.showToast({
@@ -95,8 +97,8 @@
 						let params = {
 							receiverName: this.form.receiverName,
 							receiverPhone: this.form.receiverPhone,
-							receiveAreasName: this.areaName, // 地址名称
-							receiveAreas: this.receiveAreas, 
+							receiveAreasName: this.areaInfo.label.replace(/\-/g,','), // 地址名称
+							receiveAreas: this.areaIdArr.join(','), 
 							receiveAddress: this.form.receiveAddress // 详细地址
 						}
 						if(this.form.id) {
@@ -123,13 +125,17 @@
 					}
 				});
 			},
-			// 选择地址
-			chooseArea(e){
-				console.log(e)
-				this.form.receiveAreasName = e.province.label + '-' + e.city.label + '-' + e.area.label
-				this.areaName = e.province.label + ',' + e.city.label + ',' + e.area.label
-				this.receiveAreas = e.province.value + ',' + e.city.value + ',' + e.area.value
-			}
+			//  选择省区市
+			areaConfirm(e) {
+				console.log('已选择的省市区', e)
+				this.areaInfo = e
+				this.areaIdArr = [ e.provinceCode, e.cityCode, e.areaCode ]
+			},
+			openAddress(){
+				//  省市区  回显     参数为省市区id数组
+				// console.log(this.areaIdArr,'this.areaIdArr')
+				this.$refs.applyAddress.open(this.areaIdArr)
+			},
 		},
 		// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
 		onReady() {