From e3c2cd23253f3501be7d31e03955fbb6f4aa3556 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 15 May 2026 16:30:04 +0800
Subject: [PATCH] Merge branch 'refs/heads/feature/v9.0/9.0.4' into prod

---
 src/subPackages/userDetail/infos/index.vue |  577 +++++++++++++++++++++++++++++---------------------------
 1 files changed, 299 insertions(+), 278 deletions(-)

diff --git a/src/subPackages/userDetail/infos/index.vue b/src/subPackages/userDetail/infos/index.vue
index 807446e..c1a6734 100644
--- a/src/subPackages/userDetail/infos/index.vue
+++ b/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>
\ No newline at end of file
+: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>

--
Gitblit v1.9.3