From 2ca94de8ede18ac07ccfd8dec7b6f6a707adde9b Mon Sep 17 00:00:00 2001
From: 张含笑 <zhx18749296735@163.com>
Date: Mon, 01 Sep 2025 11:20:24 +0800
Subject: [PATCH] Merge branch 'refs/heads/feature/v5.0/5.0.5' into patch_management

---
 src/views/system/userinfo.vue |  640 ++++++++++++++++++++++++++++------------------------------
 1 files changed, 309 insertions(+), 331 deletions(-)

diff --git a/src/views/system/userinfo.vue b/src/views/system/userinfo.vue
index a73d22f..b1ea7d2 100644
--- a/src/views/system/userinfo.vue
+++ b/src/views/system/userinfo.vue
@@ -1,295 +1,297 @@
 <template>
-	
-		<div class="user-info-new">
-      <div class="titleBoxs">
-			<div
-				class="titleItem"
-				:class="index === checked ? 'activeItem' : ''"
-				v-for="(item, index) in titleList"
-				:key="index"
-				@click="titleClick(item, index)"
-			>
-				{{ item }}
-			</div>
-		</div>
-		<!-- 个人信息 -->
-		<div class="message" v-if="checked === 0">
-			<div class="info">
-				<div class="section">
-					<el-form label-width="120px">
-						<el-form-item label="头像:">
-							<el-upload
-								class="avatar-uploader"
-								:http-request="customUpload"
-								:show-file-list="false"
-								:before-upload="beforeAvatarUpload"
-								:disabled="uploadLoading"
-								action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
-							>
-								<img v-if="userInfo.avatar" :src="userInfo.avatar" class="avatar" />
-								<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
+  <div class="user-info-new">
+    <div class="titleBoxs">
+      <div
+        class="titleItem"
+        :class="index === checked ? 'activeItem' : ''"
+        v-for="(item, index) in titleList"
+        :key="index"
+        @click="titleClick(item, index)"
+      >
+        {{ item }}
+      </div>
+    </div>
+    <!-- 个人信息 -->
+    <div class="message" v-if="checked === 0">
+      <div class="info">
+        <div class="section">
+          <el-form label-width="120px">
+            <el-form-item label="头像:">
+              <el-upload
+                class="avatar-uploader"
+                :http-request="customUpload"
+                :show-file-list="false"
+                :before-upload="beforeAvatarUpload"
+                :disabled="uploadLoading"
+                action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
+              >
+                <img v-if="userInfo.avatar" :src="userInfo.avatar" class="avatar" />
+                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
 
-								<template #tip>
-									<div class="upload-tip">只能上传jpg/png用户头像,且不超过500kb</div>
-								</template>
-							</el-upload>
-							<!-- <el-dialog v-model="dialogVisible">
+                <template #tip>
+                  <div class="upload-tip">只能上传jpg/png用户头像,且不超过500kb</div>
+                </template>
+              </el-upload>
+              <!-- <el-dialog v-model="dialogVisible">
 								<img w-full :src="dialogImageUrl" alt="Preview Image" />
 							</el-dialog> -->
-						</el-form-item>
-					</el-form>
-				</div>
+            </el-form-item>
+          </el-form>
+        </div>
 
-				<div class="section">
-					<el-form :model="userInfo" label-width="120px">
-						<el-form-item label="姓名:">
-							<el-input class="ztzf-input" :style="{ width: pxToRem(230) }" v-model="userInfo.realName" disabled />
-						</el-form-item>
-						<!--						<el-form-item label="昵称:">
+        <div class="section">
+          <el-form :model="userInfo" label-width="120px">
+            <el-form-item label="姓名:">
+              <el-input
+                class="ztzf-input"
+                :style="{ width: pxToRem(230) }"
+                v-model="userInfo.realName"
+                disabled
+              />
+            </el-form-item>
+            <!--						<el-form-item label="昵称:">
 													<el-input class="ztzf-input" v-model="userInfo.name" />
 												</el-form-item>-->
-						<el-form-item label="所属单位:">
-							<el-input class="ztzf-input" v-model="userInfo.deptName" disabled />
-						</el-form-item>
-						<el-form-item label="手机号:">
-							<el-input class="ztzf-input" v-model="userInfo.phone" />
-						</el-form-item>
-						<el-form-item label="邮箱:">
-							<el-input class="ztzf-input" v-model="userInfo.email" />
-						</el-form-item>
-					</el-form>
-				</div>
-			</div>
-			<div class="butn">
-				<!-- <img @click="reset" :style="{ marginRight: pxToRem(23) }" :src="cancel1" alt="" />
+            <el-form-item label="所属单位:">
+              <el-input class="ztzf-input" v-model="userInfo.deptName" disabled />
+            </el-form-item>
+            <el-form-item label="手机号:">
+              <el-input class="ztzf-input" v-model="userInfo.phone" />
+            </el-form-item>
+            <el-form-item label="邮箱:">
+              <el-input class="ztzf-input" v-model="userInfo.email" />
+            </el-form-item>
+          </el-form>
+        </div>
+      </div>
+      <div class="butn">
+        <!-- <img @click="reset" :style="{ marginRight: pxToRem(23) }" :src="cancel1" alt="" />
 				<img @click="submit" :style="{ marginRight: pxToRem(23) }" :src="publish1" alt="" /> -->
-        <el-button type="primary" @click="submit" style="margin-right: 10px;">提交</el-button>
+        <el-button type="primary" @click="submit" style="margin-right: 10px">提交</el-button>
         <el-button @click="reset">重置</el-button>
-			</div>
-		</div>
-		<!-- 修改密码 -->
-		<div class="passwordBox" v-else-if="checked === 1">
-			<div class="password">
-				<el-form :model="passwordForm" label-width="120px">
-					<el-form-item label="原始密码:" prop="oldPassword">
-						<el-input class="ztzf-input" v-model="passwordForm.oldPassword" type="password" show-password />
-					</el-form-item>
-					<el-form-item label="新密码:" prop="newPassword">
-						<el-input class="ztzf-input" v-model="passwordForm.newPassword" type="password" show-password />
-					</el-form-item>
-					<el-form-item label="确认密码:" prop="newPassword1">
-						<el-input class="ztzf-input" v-model="passwordForm.newPassword1" type="password" show-password />
-					</el-form-item>
-				</el-form>
-			</div>
-			<div class="butn">
-				<!-- <img @click="reset" :style="{ marginRight: pxToRem(23) }" :src="cancel1" alt="" />
-				<img @click="submit" :style="{ marginRight: pxToRem(23) }" :src="publish1" alt="" /> -->
-      <el-button type="primary" @click="submit" style="margin-right: 10px;">提交</el-button>
-        <el-button @click="reset">重置</el-button>
-			</div>
-		</div>
-		<!-- 密钥上传 -->
-		<div class="upload-file" v-else-if="checked === 2">
-			<img v-if="isSuccess === 'success'" :src="uploadSuccess" alt="" />
-			<img v-if="isSuccess === 'error'" :src="uploadError" alt="" />
-			<el-upload action="/upload" accept=".lic" :show-file-list="false" :before-upload="handleUpload">
-				<div class="upload-btn">密钥上传</div>
-			</el-upload>
-			<div class="password-time">密钥有效期:{{ passwordTime || '永久有效' }}</div>
-		</div>
+      </div>
     </div>
+    <!-- 修改密码 -->
+    <div class="passwordBox" v-else-if="checked === 1">
+      <div class="password">
+        <el-form :model="passwordForm" label-width="120px">
+          <el-form-item label="原始密码:" prop="oldPassword">
+            <el-input
+              class="ztzf-input"
+              v-model="passwordForm.oldPassword"
+              type="password"
+              show-password
+            />
+          </el-form-item>
+          <el-form-item label="新密码:" prop="newPassword">
+            <el-input
+              class="ztzf-input"
+              v-model="passwordForm.newPassword"
+              type="password"
+              show-password
+            />
+          </el-form-item>
+          <el-form-item label="确认密码:" prop="newPassword1">
+            <el-input
+              class="ztzf-input"
+              v-model="passwordForm.newPassword1"
+              type="password"
+              show-password
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="butn">
+        <!-- <img @click="reset" :style="{ marginRight: pxToRem(23) }" :src="cancel1" alt="" />
+				<img @click="submit" :style="{ marginRight: pxToRem(23) }" :src="publish1" alt="" /> -->
+        <el-button type="primary" @click="submit" style="margin-right: 10px">提交</el-button>
+        <el-button @click="reset">重置</el-button>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script setup>
-import { pxToRem } from '@/utils/rem'
-import { useStore } from 'vuex'
-import { ElMessage } from 'element-plus'
-import { getToken } from '@/utils/auth'
-import md5 from 'js-md5'
-import request from '@/axios'
-import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user'
-import { findLicenseDate } from '@/api/system/dict'
-import { uploadLicense } from '@/api/license/uploadLicense';
-
+import { pxToRem } from '@/utils/rem';
+import { useStore } from 'vuex';
+import { ElMessage } from 'element-plus';
+import { getToken } from '@/utils/auth';
+import md5 from 'js-md5';
+import request from '@/axios';
+import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user';
+import { findLicenseDate } from '@/api/system/dict';
 import uploadSuccess from '@/assets/images/uoload-success.png';
 import uploadError from '@/assets/images/upload-error.png';
 import cancel1 from '@/assets/images/task/cancel1.png';
 import publish1 from '@/assets/images/task/publish1.png';
 
-const store = useStore()
-const token = getToken()
-const userinforShow = defineModel('show')
-const userInfoAs = computed(() => store.state.user.userInfo)
-const titleList = ref(['个人信息', '修改密码', '密钥上传'])
-const checked = ref(0)
-const uploadUrl = computed(() => `${import.meta.env.VITE_APP_API_URL}/blade-resource/oss/endpoint/put-file`)
+const store = useStore();
+const token = getToken();
+const userinforShow = defineModel('show');
+const userInfoAs = computed(() => store.state.user.userInfo);
+const titleList = ref(['个人信息', '修改密码']);
+const checked = ref(0);
+const uploadUrl = computed(
+  () => `${import.meta.env.VITE_APP_API_URL}/blade-resource/oss/endpoint/put-file`
+);
 // 表单数据
 const userInfo = ref({
-	id: '',
-	avatar: '',
-	realName: '',
-	name: '',
-	phone: '',
-	email: '',
-	deptName: '',
-})
+  id: '',
+  avatar: '',
+  realName: '',
+  name: '',
+  phone: '',
+  email: '',
+  deptName: '',
+});
 // 校验手机号
 const validatePhone = () => {
-	const phoneRegex = /^1[3-9]\d{9}$/
-	if (!phoneRegex.test(userInfo.value.phone)) {
-		ElMessage.error('请输入正确的手机号码')
+  const phoneRegex = /^1[3-9]\d{9}$/;
+  if (!phoneRegex.test(userInfo.value.phone)) {
+    ElMessage.error('请输入正确的手机号码');
+    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)) {
+		ElMessage.error('请输入正确的邮箱地址')
 		return false
 	}
 	return true
 }
 const passwordForm = ref({
-	oldPassword: '',
-	newPassword: '',
-	newPassword1: '',
-})
+  oldPassword: '',
+  newPassword: '',
+  newPassword1: '',
+});
 // 头像
 const beforeAvatarUpload = file => {
-	const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
-	const isLt500KB = file.size / 1024 < 500
-	if (!isJpgOrPng) {
-		ElMessage.error('头像图片只能是 JPG/PNG 格式!')
-		return false
-	}
-	if (!isLt500KB) {
-		ElMessage.error('头像图片大小不能超过 500KB!')
-		return false
-	}
-	return true
-}
-const uploadLoading = ref(false)
+  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
+  const isLt500KB = file.size / 1024 < 500;
+  if (!isJpgOrPng) {
+    ElMessage.error('头像图片只能是 JPG/PNG 格式!');
+    return false;
+  }
+  if (!isLt500KB) {
+    ElMessage.error('头像图片大小不能超过 500KB!');
+    return false;
+  }
+  return true;
+};
+const uploadLoading = ref(false);
 
 const customUpload = async options => {
-	const { file } = options
-	uploadLoading.value = true
+  const { file } = options;
+  uploadLoading.value = true;
 
-	const formData = new FormData()
-	formData.append('file', file) // 根据后端API调整字段名
-	try {
-		const res = await request.post('/blade-resource/oss/endpoint/put-file', formData, {
-			headers: {
-				'Content-Type': 'multipart/form-data',
-			},
-		})
+  const formData = new FormData();
+  formData.append('file', file); // 根据后端API调整字段名
+  try {
+    const res = await request.post('/blade-resource/oss/endpoint/put-file', formData, {
+      headers: {
+        'Content-Type': 'multipart/form-data',
+      },
+    });
 
-		if (res.data.code === 200) {
-			ElMessage.success('头像上传成功')
-			userInfo.value.avatar = res.data.data.link
-			return res.data
-		} else {
-			throw new Error(res.data.msg || '上传失败')
-		}
-	} catch (error) {
-		ElMessage.error(error.response?.data?.msg || error.message || '上传失败')
-		return Promise.reject(error)
-	} finally {
-		uploadLoading.value = false
-	}
-}
+    if (res.data.code === 200) {
+      ElMessage.success('头像上传成功');
+      userInfo.value.avatar = res.data.data.link;
+      return res.data;
+    } else {
+      throw new Error(res.data.msg || '上传失败');
+    }
+  } catch (error) {
+    ElMessage.error(error.response?.data?.msg || error.message || '上传失败');
+    return Promise.reject(error);
+  } finally {
+    uploadLoading.value = false;
+  }
+};
 
 const titleClick = (item, index) => {
-	checked.value = index
-	if (index === 2) {
-		getFindLicenseDate()
-	}
-}
+  checked.value = index;
+};
 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 emit = defineEmits(['logout'])
+  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 emit = defineEmits(['logout']);
 const submit = () => {
-	if (checked.value === 0) {
-		// if (!validatePhone()) return
-		userInfo.value.name = userInfo.value.realName
-		updateInfo(userInfo.value).then(res => {
-			if (res.data.code === 200) {
-				ElMessage.success('修改信息成功!')
-				userinforShow.value = false
-			} else {
-				ElMessage.error(res.msg)
-			}
-		})
-	} else if (checked.value === 1) {
-		updatePassword(
-			md5(passwordForm.value.oldPassword),
-			md5(passwordForm.value.newPassword),
-			md5(passwordForm.value.newPassword1)
-		).then(res => {
-			if (res.data.code === 200) {
-				ElMessage.success('修改密码成功!')
-				// 调用父组件方法
-				userinforShow.value = false
-				emit('logout')
-			} else {
-				ElMessage.error(res.msg)
-			}
-		})
-	}
-}
+  if (checked.value === 0) {
+   if (!validatePhone() || !validateEmail()) return
+    userInfo.value.name = userInfo.value.realName;
+    updateInfo(userInfo.value).then(res => {
+      if (res.data.code === 200) {
+        ElMessage.success('修改信息成功!');
+        userinforShow.value = false;
+      } else {
+        ElMessage.error(res.msg);
+      }
+    });
+  } else if (checked.value === 1) {
+    updatePassword(
+      md5(passwordForm.value.oldPassword),
+      md5(passwordForm.value.newPassword),
+      md5(passwordForm.value.newPassword1)
+    ).then(res => {
+      if (res.data.code === 200) {
+        ElMessage.success('修改密码成功!');
+        // 调用父组件方法
+        userinforShow.value = false;
+        emit('logout');
+      } else {
+        ElMessage.error(res.msg);
+      }
+    });
+  }
+};
 const reset = () => {
-	if (checked.value === 0) {
-		getUserInfoData()
-		userinforShow.value = false
-	} else if (checked.value === 1) {
-		passwordForm.value = {
-			id: userInfoAs.value.userId,
-			oldPassword: '',
-			newPassword: '',
-			newPassword1: '',
-		}
-		userinforShow.value = false
-	}
-}
-const isSuccess = ref('')
-const passwordTime = ref('')
-const handleUpload = file => {
-	const formData = new FormData()
-	formData.append('file', file)
-	uploadLicense(formData)
-		.then(res => {
-			if (res.data.code !== 200) return ElMessage.error('上传失败')
-			ElMessage.success('上传成功')
-			isSuccess.value = 'success'
-			getFindLicenseDate()
-		})
-		.catch(err => {
-			isSuccess.value = 'error'
-			ElMessage.error('上传失败')
-		})
-}
+  if (checked.value === 0) {
+    getUserInfoData();
+    userinforShow.value = false;
+  } else if (checked.value === 1) {
+    passwordForm.value = {
+      id: userInfoAs.value.userId,
+      oldPassword: '',
+      newPassword: '',
+      newPassword1: '',
+    };
+    userinforShow.value = false;
+  }
+};
+const isSuccess = ref('');
+const passwordTime = ref('');
 const getFindLicenseDate = () => {
-	findLicenseDate()
-		.then(res => {
-			if (res.data.code !== 0) return ElMessage.error('获取失败')
-			passwordTime.value = res.data.data
-		})
-		.catch(err => {
-			ElMessage.error('获取失败')
-		})
-}
+  findLicenseDate()
+    .then(res => {
+      if (res.data.code !== 0) return ElMessage.error('获取失败');
+      passwordTime.value = res.data.data;
+    })
+    .catch(err => {
+      ElMessage.error('获取失败');
+    });
+};
 // const dialogImageUrl = ref('')
 // const dialogVisible = ref(false)
 // const handlePictureCardPreview = () => {}
 // const handleRemove = () => {}
 onMounted(() => {
-	getUserInfoData()
-})
+  getUserInfoData();
+});
 </script>
 <style scoped lang="scss">
 .user-info-new {
@@ -298,119 +300,95 @@
   background-color: #ffffff;
 }
 .titleBoxs {
-	margin: 0 24px;
-	margin-bottom: 10px;
-	// background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
-	// background-size: 100% 100%;
-	p {
-		display: inline-block;
-		margin-left: 30px;
-		font-size: 16px;
-		color: #000;
-		line-height: 20px;
-		text-align: left;
-		margin-bottom: 8px;
-	}
+  margin: 0 24px;
+  margin-bottom: 10px;
+  // background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
+  // background-size: 100% 100%;
+  p {
+    display: inline-block;
+    margin-left: 30px;
+    font-size: 16px;
+    color: #000;
+    line-height: 20px;
+    text-align: left;
+    margin-bottom: 8px;
+  }
 }
 :deep(.el-form-item__label) {
-	color: #000 !important;
+  color: #000 !important;
 }
 :deep(.el-button) {
-	width: 150px !important;
+  width: 150px !important;
 }
 .info {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	padding: 0 80px 0 50px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0 80px 0 50px;
 }
 .password {
-	padding: 0 120px 0 50px;
+  padding: 0 120px 0 50px;
 }
 .butn {
-	// position: absolute;
-	// bottom: 20px;
-	// left: 50%;
-	// transform: translate(-50%);
+  // position: absolute;
+  // bottom: 20px;
+  // left: 50%;
+  // transform: translate(-50%);
   display: flex;
   justify-content: center;
-	cursor: pointer;
-	img {
-		width: 96px;
-		height: 32px;
-	}
+  cursor: pointer;
+  img {
+    width: 96px;
+    height: 32px;
+  }
 }
 .titleBoxs {
-	display: flex;
-	padding: 0 20px;
+  display: flex;
+  padding: 0 20px;
 }
 .titleItem {
-	color: #61809c;
-	font-size: 16px;
-	margin-right: 50px;
-	cursor: pointer;
+  color: #61809c;
+  font-size: 16px;
+  margin-right: 50px;
+  cursor: pointer;
 }
 .activeItem {
-	border-radius: 0px 0px 0px 0px;
-	color: #51abff;
-	border-bottom: 2px solid #198cff;
+  border-radius: 0px 0px 0px 0px;
+  color: #51abff;
+  border-bottom: 2px solid #198cff;
 }
 .avatar-uploader .el-upload {
-	border: 1px dashed #d9d9d9;
-	border-radius: 6px;
-	cursor: pointer;
-	position: relative;
-	overflow: hidden;
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
 }
 .avatar-uploader .el-upload:hover {
-	border-color: #409eff;
+  border-color: #409eff;
 }
 .avatar-uploader-icon {
-	font-size: 28px;
-	color: #8c939d;
-	width: 178px;
-	height: 178px;
-	line-height: 178px;
-	text-align: center;
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
 }
 .avatar {
-	width: 178px;
-	height: 178px;
-	display: block;
+  width: 178px;
+  height: 178px;
+  display: block;
 }
 .upload-tip {
-	margin-top: 10px;
-	color: #999;
-	font-size: 12px;
-	text-align: center;
+  margin-top: 10px;
+  color: #999;
+  font-size: 12px;
+  text-align: center;
 }
 .message,
 .passwordBox {
-	margin-top: 40px;
+  margin-top: 40px;
 }
-.upload-file {
-	text-align: center;
-	margin-top: 60px;
-	.upload-btn {
-		width: 93px;
-		height: 38px;
-		line-height: 38px;
-		background: #1b3e6c;
-		border-radius: 8px 8px 8px 8px;
-		border: 1px solid #ffffff;
-		color: #fff;
-		text-align: center;
-	}
-	.password-time {
-		margin-top: 50px;
-		width: 100%;
-		height: 16px;
-		font-family: Source Han Sans CN, Source Han Sans CN;
-		font-weight: 400;
-		font-size: 14px;
-		color: #2d9dff;
-		line-height: 16px;
-		// text-align: left;
-	}
-}
+
 </style>

--
Gitblit v1.9.3