| @ -0,0 +1,139 @@ | |||
| <template> | |||
| <view class="card"> | |||
| <view class="top" @click="$emit('click')"> | |||
| <addressView :data="data"></addressView> | |||
| </view> | |||
| <view class="flex bottom"> | |||
| <view class="flex col"> | |||
| <view> | |||
| <uv-radio-group | |||
| v-model="radiovalue" | |||
| shape="circle" | |||
| size="36rpx" | |||
| iconSize="36rpx" | |||
| labelSize="24rpx" | |||
| labelColor="#9B9B9B" | |||
| activeColor="#7451DE" | |||
| @change="onRadioChange" | |||
| > | |||
| <uv-radio :name="1"> | |||
| <view>默认地址</view> | |||
| </uv-radio> | |||
| </uv-radio-group> | |||
| </view> | |||
| </view> | |||
| <button class="flex col btn" @click="onEdit"> | |||
| <image class="icon" src="@/pages_order/static/address/icon-edit.png" mode="scaleToFill"></image> | |||
| <view>编辑</view> | |||
| </button> | |||
| <button class="flex col btn" @click="onDelete"> | |||
| <image class="icon" src="@/pages_order/static/address/icon-delete.png" mode="scaleToFill"></image> | |||
| <view>删除</view> | |||
| </button> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import addressView from './addressView.vue'; | |||
| export default { | |||
| components: { | |||
| addressView, | |||
| }, | |||
| props: { | |||
| data: { | |||
| type: Object, | |||
| default() { | |||
| return {} | |||
| } | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| radiovalue: null, | |||
| } | |||
| }, | |||
| computed: { | |||
| isDefault: { | |||
| set(val) { | |||
| this.radiovalue = val ? 1 : null | |||
| if (this.data.default == val) { | |||
| return | |||
| } | |||
| // todo: set this address as default | |||
| this.$emit('defaultChange', val) | |||
| }, | |||
| get() { | |||
| return this.radiovalue == 1 ? true : false | |||
| } | |||
| }, | |||
| }, | |||
| watch: { | |||
| data: { | |||
| handler(val) { | |||
| this.isDefault = val.default | |||
| }, | |||
| immediate: true, | |||
| deep: true, | |||
| } | |||
| }, | |||
| methods: { | |||
| onRadioChange() { | |||
| this.isDefault = true | |||
| }, | |||
| onEdit() { | |||
| // todo | |||
| this.$emit('edit') | |||
| }, | |||
| onDelete() { | |||
| uni.showModal({ | |||
| title: '确认删除?', | |||
| success : e => { | |||
| if(e.confirm){ | |||
| // todo | |||
| this.$emit('delete') | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .card { | |||
| padding: 24rpx 32rpx; | |||
| background: #FFFFFF; | |||
| border-radius: 24rpx; | |||
| .top { | |||
| padding-bottom: 24rpx; | |||
| } | |||
| .bottom { | |||
| padding-top: 24rpx; | |||
| column-gap: 24rpx; | |||
| border-top: 2rpx dashed #DADADA; | |||
| .col { | |||
| flex: 1; | |||
| column-gap: 8rpx; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 24rpx; | |||
| line-height: 1.4; | |||
| color: #9B9B9B; | |||
| .icon { | |||
| width: 36rpx; | |||
| height: 36rpx; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,208 @@ | |||
| <template> | |||
| <view class="page__view"> | |||
| <navbar title="选择地址" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" /> | |||
| <view class="main"> | |||
| <view class="card" v-for="(item, index) in list" :key="item.id"> | |||
| <addressCard | |||
| :data="item" | |||
| @defaultChange="onDefaultChange(index, $event)" | |||
| @click="onSelect(item)" | |||
| @edit="onEdit(item)" | |||
| @delete="onDelete(item.id)" | |||
| ></addressCard> | |||
| </view> | |||
| </view> | |||
| <view class="flex bottom"> | |||
| <button class="btn" @click="onAdd">新建地址</button> | |||
| </view> | |||
| <addressPopup ref="addressPopup" @submitted="getData"></addressPopup> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import mixinsList from '@/mixins/list.js' | |||
| import addressCard from './addressCard.vue' | |||
| import addressPopup from '@/pages_order/address/addressPopup.vue' | |||
| export default { | |||
| mixins: [mixinsList], | |||
| components: { | |||
| addressCard, | |||
| addressPopup, | |||
| }, | |||
| data() { | |||
| return { | |||
| // todo | |||
| mixinsListApi: '', | |||
| } | |||
| }, | |||
| methods: { | |||
| getData() { | |||
| this.list = [ | |||
| { | |||
| id: '001', | |||
| name: '郑文锦', | |||
| phone: '18108341643', | |||
| area: ['海南省', '海口市', '秀英区'], | |||
| address: '秀英街道5单元183室', | |||
| default: true, | |||
| }, | |||
| { | |||
| id: '002', | |||
| name: '周俊', | |||
| phone: '13293992217', | |||
| area: ['贵州省', '遵义市', '道真仡佬族苗族自治县'], | |||
| address: '洛龙镇5幢172室', | |||
| default: false, | |||
| }, | |||
| { | |||
| id: '003', | |||
| name: '何炜', | |||
| phone: '18108341643', | |||
| area: ['新疆维吾尔自治区', '乌鲁木齐市', '沙依巴克区'], | |||
| address: '仓房沟片区街道4单元50室', | |||
| default: false, | |||
| }, | |||
| { | |||
| id: '004', | |||
| name: '赵萸艳', | |||
| phone: '15022123314', | |||
| area: ['海南省', '海口市', '秀英区'], | |||
| address: '海南省海口市秀英区秀英街道5单元183室', | |||
| default: false, | |||
| }, | |||
| { | |||
| id: '005', | |||
| name: '周俊', | |||
| phone: '13293992217', | |||
| area: ['贵州省', '遵义市', '道真仡佬族苗族自治县'], | |||
| address: '贵州省遵义市道真仡佬族苗族自治县洛龙镇5幢172室', | |||
| default: false, | |||
| }, | |||
| { | |||
| id: '006', | |||
| name: '何炜', | |||
| phone: '18108341643', | |||
| area: ['新疆维吾尔自治区', '乌鲁木齐市', '沙依巴克区'], | |||
| address: '新疆维吾尔自治区乌鲁木齐市沙依巴克区仓房沟片区街道4单元50室', | |||
| default: false, | |||
| }, | |||
| { | |||
| id: '007', | |||
| name: '赵萸艳', | |||
| phone: '15022123314', | |||
| area: ['海南省', '海口市', '秀英区'], | |||
| address: '海南省海口市秀英区秀英街道5单元183室', | |||
| default: false, | |||
| }, | |||
| ] | |||
| this.total = this.list.length | |||
| }, | |||
| onDefaultChange(index) { | |||
| console.log('onDefaultChange', index) | |||
| this.list.forEach((item, idx) => { | |||
| if (idx === index) { | |||
| item.default = true | |||
| } else { | |||
| item.default = false | |||
| } | |||
| }) | |||
| }, | |||
| onSelect(data) { | |||
| this.$store.commit('setAddressInfo', data) | |||
| this.$utils.navigateBack() | |||
| }, | |||
| onDelete(id) { | |||
| uni.showToast({ | |||
| icon: 'loading', | |||
| title: '正在删除', | |||
| }); | |||
| setTimeout(() => { | |||
| this.list = this.list.filter(item => item.id !== id) | |||
| this.total = this.list.length | |||
| uni.showToast({ | |||
| icon: 'success', | |||
| title: '删除成功', | |||
| }); | |||
| // uni.showToast({ | |||
| // icon: 'error', | |||
| // title: '删除失败', | |||
| // }); | |||
| }, 1000) | |||
| }, | |||
| onEdit(data) { | |||
| this.$refs.addressPopup.open(data) | |||
| }, | |||
| onAdd() { | |||
| this.$refs.addressPopup.open() | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .page__view { | |||
| width: 100vw; | |||
| min-height: 100vh; | |||
| background-color: $uni-bg-color; | |||
| position: relative; | |||
| /deep/ .nav-bar__view { | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| } | |||
| } | |||
| .main { | |||
| padding: calc(var(--status-bar-height) + 160rpx) 40rpx 254rpx 40rpx; | |||
| } | |||
| .card { | |||
| & + & { | |||
| margin-top: 40rpx; | |||
| } | |||
| } | |||
| .bottom { | |||
| position: fixed; | |||
| left: 0; | |||
| bottom: 0; | |||
| align-items: flex-start; | |||
| width: 100vw; | |||
| height: 214rpx; | |||
| padding: 32rpx 40rpx; | |||
| background: #FFFFFF; | |||
| box-sizing: border-box; | |||
| .btn { | |||
| width: 100%; | |||
| padding: 16rpx 0; | |||
| box-sizing: border-box; | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 36rpx; | |||
| line-height: 1; | |||
| color: #FFFFFF; | |||
| background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
| border-radius: 41rpx; | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,249 @@ | |||
| <template> | |||
| <view> | |||
| <uv-popup ref="popup" mode="bottom" bgColor="none" > | |||
| <view class="popup__view"> | |||
| <view class="flex header"> | |||
| <view class="title">新建地址</view> | |||
| <button class="btn" @click="close">关闭</button> | |||
| </view> | |||
| <view class="form"> | |||
| <uv-form | |||
| ref="form" | |||
| :model="form" | |||
| :rules="rules" | |||
| errorType="toast" | |||
| > | |||
| <view class="form-item"> | |||
| <uv-form-item prop="name" :customStyle="formItemStyle"> | |||
| <view class="form-item-label">联系人</view> | |||
| <view class="form-item-content"> | |||
| <formInput v-model="form.name"></formInput> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="phone" :customStyle="formItemStyle"> | |||
| <view class="form-item-label">手机号</view> | |||
| <view class="form-item-content"> | |||
| <formInput v-model="form.phone"></formInput> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="phone" :customStyle="formItemStyle"> | |||
| <view class="form-item-label">所在地区</view> | |||
| <view class="form-item-content"> | |||
| <picker mode="region" @change="onAreaChange" :value="form.area"> | |||
| <view class="flex region"> | |||
| <view v-if="form.area">{{ form.area.join('') }}</view> | |||
| <view v-else class="placeholder">选择省市区街道</view> | |||
| </view> | |||
| </picker> | |||
| <!-- <formInput v-model="form.phone"></formInput> --> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="address" :customStyle="formItemStyle"> | |||
| <view class="form-item-label">详细地址</view> | |||
| <view class="form-item-content"> | |||
| <formInput v-model="form.address" placeholder="小区楼栋、门牌号、村等"></formInput> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| </uv-form> | |||
| </view> | |||
| <view class="footer"> | |||
| <button class="flex btn" @click="onSave">保存</button> | |||
| </view> | |||
| </view> | |||
| </uv-popup> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import formInput from '@/pages_order/components/formInput.vue' | |||
| export default { | |||
| components: { | |||
| formInput, | |||
| }, | |||
| data() { | |||
| return { | |||
| form: { | |||
| name: null, | |||
| phone: null, | |||
| area: null, | |||
| address: null, | |||
| }, | |||
| rules: { | |||
| 'name': { | |||
| type: 'string', | |||
| required: true, | |||
| message: '请输入联系人', | |||
| }, | |||
| 'phone': { | |||
| type: 'string', | |||
| required: true, | |||
| message: '请输入手机号', | |||
| }, | |||
| 'area': { | |||
| type: 'array', | |||
| required: true, | |||
| message: '请选择省市区', | |||
| }, | |||
| 'address': { | |||
| type: 'string', | |||
| required: true, | |||
| message: '请输入详细地址', | |||
| }, | |||
| }, | |||
| formItemStyle: { padding: 0 }, | |||
| } | |||
| }, | |||
| methods: { | |||
| open(data) { | |||
| if (data) { | |||
| const { | |||
| name, | |||
| phone, | |||
| area, | |||
| address, | |||
| } = data | |||
| this.form = { | |||
| name, | |||
| phone, | |||
| area, | |||
| address, | |||
| } | |||
| } | |||
| this.$refs.popup.open() | |||
| }, | |||
| close() { | |||
| this.$refs.popup.close() | |||
| }, | |||
| onAreaChange(e) { | |||
| this.form.area = e.detail.value | |||
| }, | |||
| async onSave() { | |||
| try { | |||
| const res = await this.$refs.form.validate() | |||
| console.log('onSave res', res) | |||
| // todo: save | |||
| this.$emit('submitted') | |||
| this.close() | |||
| } catch (err) { | |||
| console.log('onSave err', err) | |||
| } | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .popup__view { | |||
| width: 100vw; | |||
| display: flex; | |||
| flex-direction: column; | |||
| box-sizing: border-box; | |||
| background: #FFFFFF; | |||
| border-top-left-radius: 32rpx; | |||
| border-top-right-radius: 32rpx; | |||
| } | |||
| .header { | |||
| position: relative; | |||
| width: 100%; | |||
| padding: 24rpx 0; | |||
| box-sizing: border-box; | |||
| border-bottom: 2rpx solid #EEEEEE; | |||
| .title { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 34rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| } | |||
| .btn { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| color: #8B8B8B; | |||
| position: absolute; | |||
| top: 26rpx; | |||
| left: 40rpx; | |||
| } | |||
| } | |||
| .form { | |||
| padding: 32rpx 40rpx; | |||
| &-item { | |||
| padding: 8rpx 0 6rpx 0; | |||
| & + & { | |||
| padding-top: 24rpx; | |||
| border-top: 2rpx solid #EEEEEE; | |||
| } | |||
| &-label { | |||
| margin-bottom: 14rpx; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 26rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| } | |||
| &-content { | |||
| .placeholder { | |||
| color: #C6C6C6; | |||
| font-size: 32rpx; | |||
| font-weight: 400; | |||
| } | |||
| .region { | |||
| min-height: 44rpx; | |||
| justify-content: flex-start; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .footer { | |||
| width: 100%; | |||
| // todo:check | |||
| // height: 214rpx; | |||
| padding: 32rpx 40rpx; | |||
| box-sizing: border-box; | |||
| border-top: 2rpx solid #F1F1F1; | |||
| .btn { | |||
| width: 100%; | |||
| padding: 16rpx 0; | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 36rpx; | |||
| line-height: 1.4; | |||
| color: #FFFFFF; | |||
| background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
| border-radius: 41rpx; | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,79 @@ | |||
| <template> | |||
| <view> | |||
| <template v-if="data"> | |||
| <view class="flex user"> | |||
| <view>{{ data.name }}</view> | |||
| <view>{{ data.phone }}</view> | |||
| <view class="tag" v-if="data.default">默认</view> | |||
| </view> | |||
| <view class="flex address"> | |||
| <image v-if="showIcon" class="icon" src="@/pages_order/static/address/icon-address.png" mode="scaleToFill"></image> | |||
| <view>{{ `${data.area.join('')}${data.address}` }}</view> | |||
| </view> | |||
| </template> | |||
| <template v-else> | |||
| <view>请选择地址</view> | |||
| </template> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| data: { | |||
| type: Object, | |||
| default() { | |||
| return null | |||
| } | |||
| }, | |||
| showIcon: { | |||
| type: Boolean, | |||
| default: false, | |||
| } | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .user { | |||
| justify-content: flex-start; | |||
| column-gap: 24rpx; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| .tag { | |||
| padding: 2rpx 14rpx; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 24rpx; | |||
| line-height: 1.4; | |||
| color: #7451DE; | |||
| background: #EFEAFF; | |||
| border: 2rpx solid #7451DE; | |||
| border-radius: 8rpx; | |||
| } | |||
| } | |||
| .address { | |||
| margin-top: 16rpx; | |||
| align-items: flex-start; | |||
| justify-content: flex-start; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 28rpx; | |||
| line-height: 1.4; | |||
| color: #9B9B9B; | |||
| .icon { | |||
| margin: 3px 8rpx 0 0; | |||
| width: 32rpx; | |||
| height: 32rpx; | |||
| } | |||
| } | |||
| </style> | |||