罗广辉
2026-05-15 e3c2cd23253f3501be7d31e03955fbb6f4aa3556
src/subPackages/userDetail/infos/index.vue
@@ -1,307 +1,328 @@
<template>
   <view class="container">
      <div class="avatarBox">
         <u-avatar @click="uploadAvatar" :src="userInfo.avatar" size="114" mode="aspectFill" />
      </div>
      <view class="detailBox">
         <div class="detailCon">
            <div class="orderRow">
               <div class="rowTitle">姓名</div>
               <div>{{userInfo.realName}}</div>
            </div>
            <div class="orderRow">
               <div class="rowTitle">所属单位</div>
               <div>{{userInfo.deptName}}</div>
            </div>
            <div class="orderRow">
               <div class="rowTitle">手机号</div>
               <u-input input-align="right" v-model="userInfo.phone" type="number" placeholder="请输入手机号"
                  class="input-item" />
  <view class="container">
    <div class="avatarBox">
            </div>
            <div class="orderRow">
               <div class="rowTitle">邮箱</div>
               <u-input input-align="right" v-model="userInfo.email" type="email" placeholder="请输入邮箱"
                  class="input-item" />
            </div>
         </div>
      </view>
      <view class="btngroup">
         <u-button color="#AEAEAE" class="custom-style" shape="circle" @click="reset">重置</u-button>
         <u-button color="#1D6FE9" class="custom-style" shape="circle" @click="submit">提交</u-button>
      </view>
   </view>
      <u-avatar @click="uploadAvatar" :src="userInfo.avatar" size="114" mode="aspectFill"/>
    </div>
    <view class="detailBox">
      <div class="detailCon">
        <div class="orderRow">
          <div class="rowTitle">姓名</div>
          <div>{{ userInfo.realName }}</div>
        </div>
        <div class="orderRow">
          <div class="rowTitle">所属单位</div>
          <div>{{ userInfo.deptName }}</div>
        </div>
        <div class="orderRow">
          <div class="rowTitle">手机号</div>
          <u-input input-align="right" v-model="userInfo.phone" type="number" placeholder="请输入手机号"
                   class="input-item"/>
        </div>
        <div class="orderRow">
          <div class="rowTitle">邮箱</div>
          <u-input input-align="right" v-model="userInfo.email" type="email" placeholder="请输入邮箱"
                   class="input-item"/>
        </div>
      </div>
    </view>
    <view class="btngroup">
      <u-button color="#AEAEAE" class="custom-style" shape="circle" @click="reset">重置</u-button>
      <u-button
        :color="submitLoading ? '#AEAEAE' : '#1D6FE9'"
        class="custom-style"
        shape="circle"
        text="提交"
        :loading="submitLoading"
        loading-text="提交中"
        loading-mode="circle"
        :loading-size="13"
        @click="submit"
      />
    </view>
  </view>
</template>
<script setup>
   import {
      getEnvObj,
      getWebViewUrl
   } from "@/utils/index.js";
   import {
      getUserInfo,
      updateInfo,
      updatePassword
   } from '@/api/user/index.js';
   import {
      useUserStore
   } from "@/store/index.js";
   const userInfo = ref({
      id: '',
      avatar: '',
      realName: '',
      name: '',
      phone: '',
      email: '',
      deptName: '',
   });
   // 校验手机号
   const validatePhone = () => {
      const phone = userInfo.value.phone
      if (!phone) return true
      const phoneRegex = /^1[3-9]\d{9}$/
      if (!phoneRegex.test(phone)) {
import {getEnvObj} from "@/utils/index.js";
import {getUserInfo, updateInfo} from '@/api/user/index.js';
import {useUserStore} from "@/store/index.js";
import {ref} from "vue";
import {onShow} from "@dcloudio/uni-app";
         uni.showToast({
            title: '请输入正确的手机号码',
            icon: 'none',
            duration: 2000
         });
         return false
      }
      return true
   }
   // 校验邮箱
   const validateEmail = () => {
      if (!userInfo.value.email) return true
      const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
      if (!emailRegex.test(userInfo.value.email)) {
const userInfo = ref({
  id: '',
  avatar: '',
  realName: '',
  name: '',
  phone: '',
  email: '',
  deptName: '',
});
const submitLoading = ref(false);
         uni.showToast({
            title: '请输入正确的邮箱地址',
            icon: 'none',
            duration: 2000
         });
         return false
      }
      return true
   }
   const getUserInfoData = () => {
      getUserInfo().then(res => {
         const user = res.data.data;
         userInfo.value = {
            id: user.id,
            avatar: user.avatar,
            name: user.name,
            realName: user.realName,
            phone: user.phone,
            email: user.email,
            deptName: user.deptName,
         };
// 校验手机号
const validatePhone = () => {
  const phone = userInfo.value.phone
  if (!phone) return true
  const phoneRegex = /^1[3-9]\d{9}$/
  if (!phoneRegex.test(phone)) {
    uni.showToast({
      title: '请输入正确的手机号码',
      icon: 'none',
      duration: 2000
    });
    return false
  }
  return true
}
      });
   };
   const reset = () => {
      getUserInfoData();
   };
// 校验邮箱
const validateEmail = () => {
  if (!userInfo.value.email) return true
  const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
  if (!emailRegex.test(userInfo.value.email)) {
   const {
      VITE_API_BASE_URL
   } = getEnvObj()
    uni.showToast({
      title: '请输入正确的邮箱地址',
      icon: 'none',
      duration: 2000
    });
    return false
  }
  return true
}
   function uploadUtil(options) {
      const {
         formData,
         filePath,
         url
      } = options;
const getUserInfoData = () => {
  getUserInfo().then(res => {
    const user = res.data.data;
    userInfo.value = {
      id: user.id,
      avatar: user.avatar,
      name: user.name,
      realName: user.realName,
      phone: user.phone,
      email: user.email,
      deptName: user.deptName,
    };
      return new Promise((resolve, reject) => {
         let accessToken = useUserStore()?.$state?.userInfo?.access_token;
  });
};
const reset = () => {
  getUserInfoData();
};
         uni.uploadFile({
            url: `${VITE_API_BASE_URL}${url}`,
            name: 'file',
            header: {
               'Blade-Auth': 'bearer ' + accessToken
            },
            filePath: filePath,
            formData,
            success: (res) => {
               const resData = JSON.parse(res.data)
               if (resData.code === 200 || resData.code === 0) {
                  resolve(res)
               } else {
                  showToast(resData.message)
const {
  VITE_API_BASE_URL
} = getEnvObj()
                  reject(res)
               }
            },
            fail: (err) => {
               reject(err)
            }
         });
      })
   }
   const uploadAvatar = () => {
      uni.chooseImage({
         count: 1,
         success: (res) => {
            const tempFile = res.tempFiles[0]; // 获取文件对象
            const filePath = tempFile.path || tempFile.tempFilePath;
            if (!filePath) {
               uni.showToast({
                  title: '获取文件路径失败',
                  icon: 'none'
               });
               return;
            }
            let fileName = tempFile.name;
            if (!fileName) {
               const pathWithoutProtocol = filePath.replace(/^file:\/\//, '');
               fileName = pathWithoutProtocol.split('/').pop() || 'unknown.png';
            }
            // 显示加载中
            uni.showLoading({
               title: '上传中...'
            });
// 头像上传到服务器
function uploadUtil(options) {
  const {formData, filePath, url} = options;
  uni.showLoading({title: '上传中...'})
  return new Promise((resolve, reject) => {
    let accessToken = useUserStore()?.$state?.userInfo?.access_token;
    uni.uploadFile({
      url: `${VITE_API_BASE_URL}${url}`,
      name: 'file',
      header: {
        'Blade-Auth': 'bearer ' + accessToken
      },
      filePath: filePath,
      formData,
      success: (res) => {
        const resData = JSON.parse(res.data)
        if (resData.code === 200 || resData.code === 0) {
          resolve(res)
        } else {
          uni.showToast(resData.message)
          reject(res)
        }
      },
      fail: (err) => {
        reject(err)
      },
      complete: () => {
        uni.hideLoading()
      }
    });
  })
}
            // 上传文件
            uploadUtil({
               filePath: filePath,
               formData: {
                  fileName: fileName,
                  sn: 'avatar_upload'
               },
               url: '/blade-resource/oss/endpoint/put-file'
            }).then(res => {
               const resData = JSON.parse(res.data);
               if (resData.code === 200 || resData.code === 0) {
                  // 更新头像显示
                  userInfo.value.avatar = resData.data.link || resData.data.url;
                  uni.hideLoading();
                  uni.showToast({
                     title: '头像上传成功',
                     icon: 'success'
                  });
               } else {
                  throw new Error(resData.message || '上传失败');
const handleUploadResult = (filePath, fileName) => {
  uploadUtil({
    filePath: filePath,
    formData: {
      fileName: fileName,
      sn: 'avatar_upload'
    },
    url: '/blade-resource/oss/endpoint/put-file'
  }).then(res => {
    const resData = JSON.parse(res.data);
    if (resData.code === 200 || resData.code === 0) {
      // 更新头像显示
      userInfo.value.avatar = resData.data.link || resData.data.url;
      uni.showToast({title: '头像上传成功', icon: 'success'});
    } else {
      throw new Error(resData.message || '上传失败');
    }
  }).catch(err => {
    uni.showToast({title: err.message || '上传失败', icon: 'none'});
  });
};
               }
            }).catch(err => {
               uni.hideLoading();
               uni.showToast({
                  title: err.message || '上传失败',
                  icon: 'none'
               });
            });
         }
      });
   }
   const submit = () => {
      if (!validatePhone() || !validateEmail()) return
      userInfo.value.name = userInfo.value.realName;
      updateInfo(userInfo.value).then(res => {
         if (res.data.code === 200) {
            uni.showToast({
               title: '修改信息成功',
               icon: 'none',
               duration: 2000
            });
               getUserInfoData()
// 上传头像功能
const uploadAvatar = () => {
  // #ifdef MP-WEIXIN
  uni.chooseMedia({
    count: 1,
    mediaType: ['image'],
    sourceType: ['album', 'camera'],
    maxDuration: 30,
    camera: 'back',
    success(res) {
      const filePath = res.tempFiles[0].tempFilePath;
      handleUploadResult(filePath, filePath);
    }
  })
  // #endif
         } else {
            uni.showToast({
               title: res.msg,
               icon: 'none',
               duration: 2000
            });
               getUserInfoData()
         }
  // #ifndef MP-WEIXIN
  uni.chooseImage({
    count: 1,
    success: (res) => {
      const tempFile = res.tempFiles[0]; // 获取文件对象
      const filePath = tempFile.path || tempFile.tempFilePath;
      if (!filePath) {
        uni.showToast({title: '获取文件路径失败', icon: 'none'});
        return;
      }
      let fileName = tempFile.name;
      if (!fileName) {
        const pathWithoutProtocol = filePath.replace(/^file:\/\//, '');
        fileName = pathWithoutProtocol.split('/').pop() || 'unknown.png';
      }
      // 上传文件
      handleUploadResult(filePath, fileName);
    }
  });
  // #endif
}
const submit = () => {
  if (submitLoading.value) return
  if (!validatePhone() || !validateEmail()) return
  submitLoading.value = true
  userInfo.value.name = userInfo.value.realName;
  updateInfo(userInfo.value).then(res => {
    if (res.data.code === 200) {
      uni.showToast({
        title: '修改信息成功',
        icon: 'none',
        duration: 1500
      });
      setTimeout(() => {
        uni.switchTab({
          url: '/pages/user/index'
        });
      }, 1500);
      return
      });
   };
   onShow(async () => {
      getUserInfoData()
   });
    } else {
      uni.showToast({
        title: res.msg,
        icon: 'none',
        duration: 2000
      });
      getUserInfoData()
    }
    submitLoading.value = false
  }).catch(() => {
    getUserInfoData()
    submitLoading.value = false
  });
};
onShow(async () => {
  getUserInfoData()
});
</script>
<style lang="scss" scoped>
   .container {
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
   }
   .avatarBox {
      width: 228rpx;
      height: 228rpx;
      margin: 76rpx 0;
   }
.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}
   .detailBox {
      width: 702rpx;
      min-height: 430rpx;
      background: #FFFFFF;
      border-radius: 12rpx;
      box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
.avatarBox {
  width: 228rpx;
  height: 228rpx;
  margin: 76rpx 0;
}
      .detailCon {
         padding: 0 24rpx;
      }
.detailBox {
  width: 702rpx;
  min-height: 430rpx;
  background: #FFFFFF;
  border-radius: 12rpx;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
      .orderRow {
         display: flex;
         justify-content: space-between;
         align-items: center;
         height: 96rpx;
         border-bottom: 2rpx solid #f5f5f5;
         color: #7b7b7b;
  .detailCon {
    padding: 0 24rpx;
  }
         .rowTitle {
            font-family: Source Han Sans CN, Source Han Sans CN;
            font-weight: 400;
            font-size: 30rpx;
            color: #222324;
            white-space: nowrap;
         }
  .orderRow {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 96rpx;
    border-bottom: 2rpx solid #f5f5f5;
    color: #7b7b7b;
         ::v-deep .u-input {
            border: none !important;
            background: transparent !important;
            padding: 0 !important;
         }
    .rowTitle {
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-weight: 400;
      font-size: 30rpx;
      color: #222324;
      white-space: nowrap;
    }
         ::v-deep .u-input__input {
            border: none !important;
            box-shadow: none !important;
            background: transparent !important;
            padding: 0 !important;
            margin: 0 !important;
            height: auto !important;
         }
      }
   }
    ::v-deep .u-input {
      border: none !important;
      background: transparent !important;
      padding: 0 !important;
    }
   .btngroup {
      display: flex;
      position: absolute;
      bottom: 150rpx;
   }
    ::v-deep .u-input__input {
      border: none !important;
      box-shadow: none !important;
      background: transparent !important;
      padding: 0 !important;
      margin: 0 !important;
      height: auto !important;
    }
  }
}
   :deep(.u-button:first-child) {
      margin-right: 30rpx !important;
   }
.btngroup {
  display: flex;
  position: absolute;
  bottom: 150rpx;
}
   .custom-style {
      width: 276rpx;
      height: 76rpx;
   }
   :deep(.u-button){
      width: 276rpx !important;
      height: 76rpx !important;
   }
</style>
:deep(.u-button:first-child) {
  margin-right: 30rpx !important;
}
.custom-style {
  width: 276rpx;
  height: 76rpx;
}
:deep(.u-button) {
  width: 276rpx !important;
  height: 76rpx !important;
}
</style>