MrShi
2026-04-17 f39ca3c49d26abd10f76fc67506b9c603a13547c
small-program/pages/settings/settings.vue
@@ -1,132 +1,309 @@
<template>
   <view class="settings-page">
      <view class="avatar-section">
         <image class="avatar-image" src="/static/image/tx@2x.png" mode="aspectFill"></image>
         <view class="change-avatar-btn">更换头像</view>
   <view class="box">
      <view class="box-tx">
         <view class="box-tx-image">
            <image :src="form.imgFullUrl || '/static/image/tx@2x.png'" mode="widthFix"></image>
         </view>
         <button open-type="chooseAvatar" @chooseavatar="getAvatar">更换头像</button>
      </view>
      <view class="settings-list">
         <view v-for="item in settingsList" :key="item.label" class="settings-row">
            <text class="row-label">{{ item.label }}</text>
            <view class="row-right">
               <text class="row-value" :class="{ placeholder: !item.value }">{{ item.value || item.placeholder }}</text>
               <u-icon name="arrow-right" size="18" color="#B8BDC6"></u-icon>
      <view class="list">
         <view class="list-item">
            <view class="list-item-label">昵称</view>
            <view class="list-item-val">
               <input type="text" v-model="form.nickname" @blur="updateUserInfo" placeholder="请输入" />
            </view>
         </view>
         <view class="list-item">
            <view class="list-item-label">真实姓名</view>
            <view class="list-item-val">
               <input type="text" v-model="form.name" @blur="updateUserInfo" placeholder="请输入" />
            </view>
         </view>
         <view class="list-item">
            <view class="list-item-label">绑定手机</view>
            <view class="list-item-val" @click="show = true">
               <text>{{form.phone1}}</text>
               <image src="/static/icon/ar_next@2x.png" mode="widthFix"></image>
            </view>
         </view>
         <view class="list-item" @click="jumpAddr">
            <view class="list-item-label">收货地址</view>
            <view class="list-item-val">
               <image src="/static/icon/ar_next@2x.png" mode="widthFix"></image>
            </view>
         </view>
         <view class="list-item" @click="jumpxy">
            <view class="list-item-label">协议与说明</view>
            <view class="list-item-val">
               <image src="/static/icon/ar_next@2x.png" mode="widthFix"></image>
            </view>
         </view>
      </view>
      <view class="logout-wrap">
         <view class="logout-btn">退出登录</view>
      </view>
      <view class="loginOut" @click="tuichu">退出登录</view>
      <!-- 更换手机号 -->
      <u-popup :show="show" round="15" :safeAreaInsetBottom="false" mode="center">
         <view class="tc">
            <view class="tc-contemt">
               <view class="tc-contemt-title">更换绑定手机号?</view>
               <view class="tc-contemt-nr">
                  更换后现手机号{{returnPhone(form.phone)}}将不能用于登录,180天内只可更换一次
               </view>
            </view>
            <view class="tc-btn">
               <view class="tc-btn-item" @click="show = false">我再想想</view>
               <view class="tc-btn-item" style="color: #004096;" @click="jumpPhone">确认更换</view>
            </view>
         </view>
      </u-popup>
   </view>
</template>
<script>
   import { mapState } from 'vuex'
   import { formatPhoneStar } from '@/utils/utils.js'
   export default {
      computed: {
         ...mapState(['userInfo', 'token'])
      },
      data() {
         return {
            settingsList: [
               { label: '昵称', value: '', placeholder: '请输入' },
               { label: '真实姓名', value: '', placeholder: '请输入' },
               { label: '绑定手机', value: '181****9990', placeholder: '' },
               { label: '收货地址', value: '', placeholder: '' },
               { label: '协议与说明', value: '', placeholder: '' }
            ]
            show: false,
            form: {
               nickname: '',
               name: '',
               phone: '',
               phone1: '',
               imgFullUrl: '',
               imgurl: ''
            }
         };
      },
      onLoad() {
         this.form.nickname = this.userInfo.nickname
         this.form.name = this.userInfo.name
         this.form.phone = this.userInfo.phone
         this.form.phone1 = this.returnPhone(this.userInfo.phone)
         this.form.imgFullUrl = this.userInfo.imgFullUrl
         this.form.imgurl = this.userInfo.imgurl
         uni.$on('phone', () => {
            this.form.phone = this.userInfo.phone
            this.form.phone1 = this.returnPhone(this.userInfo.phone)
         })
      },
      methods: {
         jumpxy() {
            uni.navigateTo({
               url: '/pages/agreement-description/agreement-description'
            })
         },
         returnPhone(phone) {
            return formatPhoneStar(phone)
         },
         jumpPhone() {
            this.show = false
            uni.navigateTo({
               url: '/pages/change-binding/change-binding'
            })
         },
         jumpAddr() {
            uni.navigateTo({
               url: '/pages/address/address'
            })
         },
         // 上传头像
         getAvatar(e) {
            var that = this;
            uni.uploadFile({
               url: `${this.$baseUrl}public/upload`,
               filePath: e.detail.avatarUrl,
               name: 'file',
               fileType: 'image',
               header: { 'token': this.token },
               formData: { folder: 'member' },
               success: (uploadFileRes) => {
                  let result = JSON.parse(uploadFileRes.data)
                  that.form.imgurl = result.data.imgaddr
                  that.form.imgFullUrl = result.data.url
                  that.updateUserInfo()
               }
            });
         },
         // 更新用户信息
         updateUserInfo() {
            this.$u.api.updateMember(this.form)
               .then(res => {
                  if (res.code === 200) {
                     this.setUserInfo()
                  }
               })
         },
         // 缓存最新用户信息
         async setUserInfo() {
            let res = await this.$u.api.getUserInfo()
            if (res.code === 200) {
               await this.$store.commit('setUserInfo', res.data)
               await this.$store.commit('setOpenId', res.data.openId)
            }
         },
         // 退出登录
         tuichu() {
            this.$u.api.logOut()
               .then(res => {
                  if (res.code === 200) {
                     this.$store.commit('clear')
                     uni.$emit('loginOut')
                     uni.switchTab({
                        url: '/pages/index/index'
                     })
                  }
               })
         }
      }
   }
</script>
<style lang="scss" scoped>
   .settings-page {
      background: #ffffff;
      padding: 0 30rpx;
   .box {
      width: 100%;
      padding-top: 40rpx;
      box-sizing: border-box;
      .tc {
         width: calc(100vw - 148rpx);
         .tc-btn {
            width: 100%;
            height: 102rpx;
            display: flex;
            align-items: center;
            justify-content: space-between;
            border-top: 1rpx solid #EEEEEE;
            .tc-btn-item {
               flex: 1;
               height: 100%;
               display: flex;
               align-items: center;
               justify-content: center;
               font-weight: 400;
               font-size: 32rpx;
               color: #666666;
               border-right: 1rpx solid #EEEEEE;
               &:last-child {
                  border: none !important;
               }
            }
         }
         .tc-contemt {
            width: 100%;
            padding: 40rpx 0;
            box-sizing: border-box;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            .tc-contemt-title {
               width: 100%;
               text-align: center;
               font-weight: 600;
               font-size: 32rpx;
               color: #111111;
            }
            .tc-contemt-nr {
               width: 472rpx;
               text-align: center;
               font-weight: 400;
               font-size: 28rpx;
               color: #333333;
               margin-top: 40rpx;
            }
         }
      }
      .loginOut {
         position: fixed;
         left: 50%;
         bottom: calc(40rpx + env(safe-area-inset-bottom));
         transform: translate(-50%, 0);
         width: 200rpx;
         height: 72rpx;
         line-height: 72rpx;
         text-align: center;
         border-radius: 36rpx;
         font-weight: 400;
         font-size: 28rpx;
         color: #333333;
         border: 1rpx solid #999999;
      }
      .box-tx {
         width: 100%;
         display: flex;
         align-items: center;
         flex-direction: column;
         justify-content: center;
         .box-tx-image {
            width: 160rpx;
            height: 160rpx;
            border-radius: 50%;
            overflow: hidden;
            image {
               width: 100%;
            }
         }
         button {
            width: 136rpx;
            padding: 0;
            height: 48rpx;
            line-height: 48rpx;
            text-align: center;
            border-radius: 32rpx;
            border: 1rpx solid #004096;
            font-weight: 400;
            font-size: 24rpx;
            color: #004096;
            margin-top: 24rpx;
         }
      }
      .list {
         width: 100%;
         padding: 0 30rpx;
         box-sizing: border-box;
         display: flex;
         flex-direction: column;
         margin-top: 60rpx;
         .list-item {
            width: 100%;
            height: 98rpx;
            display: flex;
            align-items: center;
            justify-content: space-between;
            border-bottom: 1rpx solid #E5E5E5;
            .list-item-label {
               flex-shrink: 0;
               font-weight: 400;
               font-size: 30rpx;
               color: #111111;
               width: 200rpx;
            }
            .list-item-val {
               flex: 1;
               display: flex;
               align-items: center;
               justify-content: flex-end;
               text {
                  font-weight: 400;
                  font-size: 28rpx;
                  color: #333333;
               }
               input {
                  width: 100%;
                  text-align: right;
                  font-weight: 400;
                  font-size: 28rpx;
                  color: #111111;
               }
               image {
                  width: 40rpx;
                  height: 40rpx;
               }
            }
         }
      }
   }
   .avatar-section {
      margin-top: 40rpx;
      display: flex;
      flex-direction: column;
      align-items: center;
   }
   .avatar-image {
      width: 160rpx;
      height: 160rpx;
      border-radius: 50%;
      overflow: hidden;
   }
   .change-avatar-btn {
      width: 136rpx;
      height: 48rpx;
      border-radius: 32rpx;
      border: 1rpx solid #10B2FA;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 26rpx;
      color: #10B2FA;
      margin-top: 24rpx;
   }
   .settings-list {
      margin-top: 56rpx;
   }
   .settings-row {
      height: 98rpx;
      border-bottom: 1rpx solid #E5E5E5;
      display: flex;
      align-items: center;
      justify-content: space-between;
   }
   .row-label {
      font-weight: 400;
      font-size: 30rpx;
      color: #111111;
   }
   .row-right {
      display: flex;
      align-items: center;
      gap: 8rpx;
   }
   .row-value {
      font-weight: 400;
      font-size: 28rpx;
      color: #111111;
   }
   .row-value.placeholder {
      font-weight: 400;
      font-size: 28rpx;
      color: #999999;
   }
   .logout-wrap {
      position: fixed;
      bottom: calc(40rpx + env(safe-area-inset-bottom));
      left: 30rpx;
      width: calc(100% - 60rpx);
      display: flex;
      justify-content: center;
   }
   .logout-btn {
      width: 200rpx;
      height: 72rpx;
      border-radius: 36rpx;
      border: 1rpx solid #999999;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: 400;
      font-size: 28rpx;
      color: #333333;
      box-sizing: border-box;
   }
</style>
</style>