mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 10:57:10 +08:00 
			
		
		
		
	feat: 新增修改手机号、修改邮箱、修改密码、修改基本信息
This commit is contained in:
		| @@ -7,6 +7,7 @@ export interface UserInfo { | ||||
|   email: string | ||||
|   phone: string | ||||
|   avatar: string | ||||
|   pwdResetTime: string | ||||
|   registrationDate: string | ||||
|   deptName: string | ||||
|   roles: string[] | ||||
|   | ||||
| @@ -2,9 +2,9 @@ export * from './user' | ||||
| export * from './role' | ||||
| export * from './menu' | ||||
| export * from './dept' | ||||
| export * from '../monitor/log' | ||||
| export * from './announcement' | ||||
| export * from './dict' | ||||
| export * from './file' | ||||
| export * from './storage' | ||||
| export * from './option' | ||||
| export * from './announcement' | ||||
| export * from './user-center' | ||||
|   | ||||
							
								
								
									
										39
									
								
								src/apis/system/user-center.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/apis/system/user-center.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import http from '@/utils/http' | ||||
| import type * as System from '@/apis/system/type' | ||||
|  | ||||
| const BASE_URL = '/system/user' | ||||
|  | ||||
| /** @desc 修改用户基本信息 */ | ||||
| export function updateUserBaseInfo(data: { nickname: string; gender: number }) { | ||||
|   return http.patch(`${BASE_URL}/basic/info`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 修改密码 */ | ||||
| export function updateUserPassword(data: { oldPassword: string; newPassword: string }) { | ||||
|   return http.patch(`${BASE_URL}/password`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 修改手机号 */ | ||||
| export function updateUserPhone(data: { newPhone: string; captcha: string; currentPassword: string }) { | ||||
|   return http.patch(`${BASE_URL}/phone`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 修改邮箱 */ | ||||
| export function updateUserEmail(data: { newEmail: string; captcha: string; currentPassword: string }) { | ||||
|   return http.patch(`${BASE_URL}/email`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 获取绑定的三方账号 */ | ||||
| export function listUserSocial() { | ||||
|   return http.get<System.BindSocialAccountRes[]>(`${BASE_URL}/social`) | ||||
| } | ||||
|  | ||||
| /** @desc 绑定三方账号 */ | ||||
| export function bindSocialAccount(source: string, data: any) { | ||||
|   return http.post(`${BASE_URL}/social/${source}`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 解绑三方账号 */ | ||||
| export function unbindSocialAccount(source: string) { | ||||
|   return http.del(`${BASE_URL}/social/${source}`) | ||||
| } | ||||
| @@ -37,25 +37,3 @@ export function exportUser(query: System.UserQuery) { | ||||
| export function resetUserPwd(data: any, id: string) { | ||||
|   return http.patch(`${BASE_URL}/${id}/password`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 修改用户基础信息 */ | ||||
| export function updateUserBaseInfo(data: { nickname?: string; gender?: number }) { | ||||
|   return http.patch(`${BASE_URL}/basic/info`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 修改邮箱 */ | ||||
| export function updateUserEmail(data: { newEmail: string; captcha: string; currentPassword: string }) { | ||||
|   return http.patch(`${BASE_URL}/email`, data) | ||||
| } | ||||
| /**@desc 绑定三方账号 */ | ||||
| export function bindSocialAccount(source: string, data: any) { | ||||
|   return http.post(`${BASE_URL}/social/${source}`, data) | ||||
| } | ||||
| /**@desc 获取绑定的三方账号 */ | ||||
| export function getSocialAccount() { | ||||
|   return http.get<System.BindSocialAccountRes[]>(`${BASE_URL}/social`) | ||||
| } | ||||
| /**@desc 解绑三方账号 */ | ||||
| export function unbindSocialAccount(source: string) { | ||||
|   return http.del(`${BASE_URL}/social/${source}`) | ||||
| } | ||||
|   | ||||
| @@ -26,6 +26,7 @@ const storeSetup = () => { | ||||
|     email: '', | ||||
|     phone: '', | ||||
|     avatar: '', | ||||
|     pwdResetTime: '', | ||||
|     registrationDate: '', | ||||
|     deptName: '', | ||||
|     roles: [], | ||||
|   | ||||
| @@ -313,6 +313,12 @@ | ||||
|       .btn { | ||||
|         height: 28px; | ||||
|         width: 56px; | ||||
|         &:hover { | ||||
|           -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, .15); | ||||
|           box-shadow: 0 2px 3px rgba(0, 0, 0, .15); | ||||
|           border-color: rgb(var(--primary-5)); | ||||
|           color: var(--color-text-2); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -74,8 +74,10 @@ const handleLogin = async () => { | ||||
|   } | ||||
| } | ||||
|  | ||||
| const captchaTime = ref(60) | ||||
| const captchaTimer = ref() | ||||
| const captchaTime = ref(60) | ||||
| const captchaBtnName = ref('获取验证码') | ||||
| const captchaDisable = ref(false) | ||||
| // 重置验证码 | ||||
| const resetCaptcha = () => { | ||||
|   window.clearInterval(captchaTimer.value) | ||||
| @@ -84,15 +86,13 @@ const resetCaptcha = () => { | ||||
|   captchaDisable.value = false | ||||
| } | ||||
|  | ||||
| const captchaBtnName = ref('获取验证码') | ||||
| const captchaLoading = ref(false) | ||||
| const captchaDisable = ref(false) | ||||
| // 获取验证码 | ||||
| const onCaptcha = async () => { | ||||
|   if (captchaLoading.value) return | ||||
|   const isInvalid = await formRef.value?.validateField('email') | ||||
|   if (isInvalid) return | ||||
|   try { | ||||
|     if (captchaLoading.value) return | ||||
|     const isInvalid = await formRef.value?.validateField('email') | ||||
|     if (isInvalid) return | ||||
|     captchaLoading.value = true | ||||
|     captchaBtnName.value = '发送中...' | ||||
|     // await getEmailCaptcha({ | ||||
|   | ||||
| @@ -77,8 +77,10 @@ const handleLogin = async () => { | ||||
|   } | ||||
| } | ||||
|  | ||||
| const captchaTime = ref(60) | ||||
| const captchaTimer = ref() | ||||
| const captchaTime = ref(60) | ||||
| const captchaBtnName = ref('获取验证码') | ||||
| const captchaDisable = ref(false) | ||||
| // 重置验证码 | ||||
| const resetCaptcha = () => { | ||||
|   window.clearInterval(captchaTimer.value) | ||||
| @@ -87,15 +89,13 @@ const resetCaptcha = () => { | ||||
|   captchaDisable.value = false | ||||
| } | ||||
|  | ||||
| const captchaBtnName = ref('获取验证码') | ||||
| const captchaLoading = ref(false) | ||||
| const captchaDisable = ref(false) | ||||
| // 获取验证码 | ||||
| const onCaptcha = async () => { | ||||
|   if (captchaLoading.value) return | ||||
|   const isInvalid = await formRef.value?.validateField('phone') | ||||
|   if (isInvalid) return | ||||
|   try { | ||||
|     if (captchaLoading.value) return | ||||
|     const isInvalid = await formRef.value?.validateField('phone') | ||||
|     if (isInvalid) return | ||||
|     captchaLoading.value = true | ||||
|     captchaBtnName.value = '发送中...' | ||||
|     // await getSmsCaptcha({ | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| <template> | ||||
|   <div class="card"> | ||||
|     <div class="card_header"> | ||||
|       <slot name="header"></slot> | ||||
|     </div> | ||||
|     <div class="card_body"> | ||||
|       <slot name="body"> </slot> | ||||
|     </div> | ||||
|     <slot name="footer"></slot> | ||||
|   </div> | ||||
| </template> | ||||
| <style scoped lang="scss"> | ||||
| .card { | ||||
|   width: 100%; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   border-radius: 8px; | ||||
|   background: var(--color-bg-1); | ||||
|   border: 1px solid var(--color-neutral-2); | ||||
|   .card_header { | ||||
|     padding: 18px 20px; | ||||
|     background: -webkit-gradient( | ||||
|       linear, | ||||
|       left top, | ||||
|       left bottom, | ||||
|       from(rgba(232, 244, 255, 0.5)), | ||||
|       to(hsla(0, 0%, 100%, 0)) | ||||
|     ); | ||||
|     font-size: 16px; | ||||
|     font-weight: 500; | ||||
|     line-height: 24px; | ||||
|     background: linear-gradient(180deg, rgba(232, 244, 255, 0.5), hsla(0, 0%, 100%, 0)); | ||||
|   } | ||||
|   .card_body { | ||||
|     flex: 1; | ||||
|     padding: 15px 28px; | ||||
|   } | ||||
|   .card_footer { | ||||
|     padding: 15px 28px; | ||||
|     border-top: 1px solid var(--color-neutral-2); | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -1,107 +1,184 @@ | ||||
| <template> | ||||
|   <a-modal v-model:visible="visible" :title="title" @before-ok="save" @cancel="handleCancel"> | ||||
|     <a-form :model="form" ref="formRef"> | ||||
|       <a-form-item | ||||
|         field="newPhone" | ||||
|         label="新手机号" | ||||
|         :rules="[{ required: true, match: Regexp.Phone, message: '请输入正确的手机号' }]" | ||||
|         v-if="verifyType === 'phone'" | ||||
|       > | ||||
|         <a-input v-model="form.newPhone" /> | ||||
|       </a-form-item> | ||||
|       <a-form-item | ||||
|         field="email" | ||||
|         label="邮箱" | ||||
|         v-if="verifyType === 'email'" | ||||
|         :rules="[{ required: true, match: Regexp.Email, message: '请输入正确的邮箱' }]" | ||||
|       > | ||||
|         <a-input v-model="form.email" /> | ||||
|       </a-form-item> | ||||
|       <a-form-item field="verifyCode" label="验证码" :rules="[{ required: true, message: '请输入正确的验证码' }]"> | ||||
|         <a-input v-model="form.captcha" /> | ||||
|         <a-button type="outline" @click="onSendCaptcha">发送验证码</a-button> | ||||
|       </a-form-item> | ||||
|       <a-form-item | ||||
|         field="currentPassword" | ||||
|         label="当前密码" | ||||
|         :rules="[ | ||||
|           { required: true, message: '请输入当前密码' }, | ||||
|           { match: Regexp.Password, message: '请输入格式的密码' } | ||||
|         ]" | ||||
|       > | ||||
|         <a-input v-model="form.currentPassword" /> | ||||
|       </a-form-item> | ||||
|     </a-form> | ||||
|   <a-modal v-model:visible="visible" :title="title" @before-ok="save" @close="reset"> | ||||
|     <GiForm ref="formRef" v-model="form" :options="options" :columns="columns"> | ||||
|       <template #captcha> | ||||
|         <a-input v-model="form.captcha" placeholder="请输入验证码" :max-length="4" allow-clear style="flex: 1 1" /> | ||||
|         <a-button | ||||
|           class="captcha-btn" | ||||
|           :loading="captchaLoading" | ||||
|           :disabled="captchaDisable" | ||||
|           size="large" | ||||
|           @click="onCaptcha" | ||||
|         > | ||||
|           {{ captchaBtnName }} | ||||
|         </a-button> | ||||
|       </template> | ||||
|     </GiForm> | ||||
|   </a-modal> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { computed, ref } from 'vue' | ||||
| import { getSmsCaptcha, getEmailCaptcha, updateUserEmail } from '@/apis' | ||||
| import { encryptByRsa } from '@/utils/encrypt' | ||||
| // import { getSmsCaptcha, getEmailCaptcha, updateUserEmail, updateUserPhone } from '@/apis' | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| // import { encryptByRsa } from '@/utils/encrypt' | ||||
| import * as Regexp from '@/utils/regexp' | ||||
| import { Message, type Modal } from '@arco-design/web-vue' | ||||
| import { useUserStore } from '@/stores' | ||||
| const userStore = useUserStore() | ||||
| const visible = ref<boolean>(false) | ||||
| const form = reactive({ | ||||
| import { type Columns, GiForm } from '@/components/GiForm' | ||||
| import { useForm } from '@/hooks' | ||||
|  | ||||
| const verifyType = ref() | ||||
| const title = computed(() => (verifyType.value === 'phone' ? '修改手机号' : '修改邮箱')) | ||||
| const formRef = ref<InstanceType<typeof GiForm>>() | ||||
|  | ||||
| const options: Options = { | ||||
|   form: {}, | ||||
|   col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 }, | ||||
|   btns: { hide: true } | ||||
| } | ||||
|  | ||||
| const columns: Columns = [ | ||||
|   { | ||||
|     label: '手机号', | ||||
|     field: 'newPhone', | ||||
|     type: 'input', | ||||
|     rules: [ | ||||
|       { required: true, message: '请输入手机号' }, | ||||
|       { match: Regexp.Phone, message: '请输入正确的手机号' } | ||||
|     ], | ||||
|     hide: () => { | ||||
|       return verifyType.value !== 'phone' | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     label: '邮箱', | ||||
|     field: 'email', | ||||
|     type: 'input', | ||||
|     rules: [ | ||||
|       { required: true, message: '请输入邮箱' }, | ||||
|       { match: Regexp.Email, message: '请输入正确的邮箱' } | ||||
|     ], | ||||
|     hide: () => { | ||||
|       return verifyType.value !== 'email' | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     label: '验证码', | ||||
|     field: 'captcha', | ||||
|     type: 'input', | ||||
|     rules: [{ required: true, message: '请输入验证码' }] | ||||
|   }, | ||||
|   { | ||||
|     label: '当前密码', | ||||
|     field: 'currentPassword', | ||||
|     type: 'input', | ||||
|     rules: [{ required: true, message: '请输入当前密码' }] | ||||
|   } | ||||
| ] | ||||
|  | ||||
| const { form, resetForm } = useForm({ | ||||
|   newPhone: '', | ||||
|   captcha: '', | ||||
|   currentPassword: '', | ||||
|   email: '' | ||||
| }) | ||||
| const formRef = ref() | ||||
| const verifyType = ref() | ||||
| const title = computed(() => { | ||||
|   return verifyType.value === 'phone' ? '修改手机号' : '修改邮箱' | ||||
| }) | ||||
| const onSendCaptcha = () => { | ||||
|   formRef.value.validateField(verifyType.value === 'phone' ? 'newPhone' : 'email', (validate) => { | ||||
|     if (!validate) { | ||||
|       // 发送验证码 | ||||
|       if (verifyType.value === 'phone') { | ||||
|         //手机号 | ||||
|         getSmsCaptcha({ phone: form.newPhone }).then((res) => { | ||||
|           console.log(res) | ||||
|         }) | ||||
|       } else if (verifyType.value === 'email') { | ||||
|         //邮箱 | ||||
|         getEmailCaptcha({ email: form.email }).then((res) => { | ||||
|           console.log(res) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
|  | ||||
| // 重置 | ||||
| const reset = () => { | ||||
|   formRef.value?.formRef?.resetFields() | ||||
|   resetForm() | ||||
|   resetCaptcha() | ||||
| } | ||||
| const save: InstanceType<typeof Modal>['onBeforeOk'] = async () => { | ||||
|   const flag = await formRef.value?.validate() | ||||
|   if (flag) return false | ||||
|  | ||||
| const captchaTimer = ref() | ||||
| const captchaTime = ref(60) | ||||
| const captchaBtnName = ref('获取验证码') | ||||
| const captchaDisable = ref(false) | ||||
| // 重置验证码 | ||||
| const resetCaptcha = () => { | ||||
|   window.clearInterval(captchaTimer.value) | ||||
|   captchaTime.value = 60 | ||||
|   captchaBtnName.value = '获取验证码' | ||||
|   captchaDisable.value = false | ||||
| } | ||||
|  | ||||
| const captchaLoading = ref(false) | ||||
| // 获取验证码 | ||||
| const onCaptcha = async () => { | ||||
|   const isInvalid = await formRef.value?.formRef?.validateField(verifyType.value === 'phone' ? 'newPhone' : 'email') | ||||
|   if (isInvalid) return false | ||||
|   // 发送验证码 | ||||
|   try { | ||||
|     const res = await updateUserEmail({ | ||||
|       newEmail: form.email, | ||||
|       captcha: form.captcha, | ||||
|       currentPassword: encryptByRsa(form.currentPassword) as string | ||||
|     }) | ||||
|     if (res.code === 200) { | ||||
|       Message.success('修改成功') | ||||
|       visible.value = false | ||||
|       // 修改成功后,重新获取用户信息 | ||||
|       userStore.getInfo() | ||||
|       return true | ||||
|     captchaLoading.value = true | ||||
|     captchaBtnName.value = '发送中...' | ||||
|     if (verifyType.value === 'phone') { | ||||
|       // await getSmsCaptcha({ | ||||
|       //   phone: form.newPhone | ||||
|       // }) | ||||
|     } else if (verifyType.value === 'email') { | ||||
|       // await getEmailCaptcha({ | ||||
|       //   email: form.email | ||||
|       // }) | ||||
|     } | ||||
|     captchaLoading.value = false | ||||
|     captchaDisable.value = true | ||||
|     captchaBtnName.value = `获取验证码(${(captchaTime.value -= 1)}s)` | ||||
|     // Message.success('发送成功') | ||||
|     Message.success('仅提供效果演示,实际使用请查看代码取消相关注释') | ||||
|     captchaTimer.value = window.setInterval(() => { | ||||
|       captchaTime.value -= 1 | ||||
|       captchaBtnName.value = `获取验证码(${captchaTime.value}s)` | ||||
|       if (captchaTime.value <= 0) { | ||||
|         resetCaptcha() | ||||
|       } | ||||
|     }, 1000) | ||||
|   } catch (error) { | ||||
|     resetCaptcha() | ||||
|   } finally { | ||||
|     captchaLoading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| // 保存 | ||||
| const save = async () => { | ||||
|   const isInvalid = await formRef.value?.formRef?.validate() | ||||
|   if (isInvalid) return false | ||||
|   try { | ||||
|     if (verifyType.value === 'phone') { | ||||
|       // await updateUserEmail({ | ||||
|       //   newEmail: form.email, | ||||
|       //   captcha: form.captcha, | ||||
|       //   currentPassword: encryptByRsa(form.currentPassword) as string | ||||
|       // }) | ||||
|     } else if (verifyType.value === 'email') { | ||||
|       // await updateUserPhone({ | ||||
|       //   newPhone: form.email, | ||||
|       //   captcha: form.captcha, | ||||
|       //   currentPassword: encryptByRsa(form.currentPassword) as string | ||||
|       // }) | ||||
|     } | ||||
|     Message.success('修改成功') | ||||
|     // 修改成功后,重新获取用户信息 | ||||
|     await userStore.getInfo() | ||||
|     return true | ||||
|   } catch (error) { | ||||
|     return false | ||||
|   } | ||||
|   // return await saveApi() | ||||
| } | ||||
| const handleCancel = () => { | ||||
|   formRef.value?.resetFields() | ||||
|   visible.value = false | ||||
| } | ||||
|  | ||||
| const visible = ref(false) | ||||
| // 打开弹框 | ||||
| const open = (type: string) => { | ||||
|   verifyType.value = type | ||||
|   visible.value = true | ||||
| } | ||||
| defineExpose({ | ||||
|   open | ||||
| }) | ||||
|  | ||||
| defineExpose({ open }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .captcha-btn { | ||||
|   margin-left: 12px; | ||||
|   min-width: 98px; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|         </div> | ||||
|         <div class="name"> | ||||
|           <span style="margin-right: 10px">{{ userInfo.nickname }}</span> | ||||
|           <icon-edit :size="16" class="btn" @click="onEditNickName" /> | ||||
|           <icon-edit :size="16" class="btn" @click="onUpdate" /> | ||||
|         </div> | ||||
|         <div class="id"> | ||||
|           <GiSvgIcon name="id" :size="16" /> | ||||
| @@ -43,22 +43,81 @@ | ||||
|     </div> | ||||
|     <div class="footer">注册于 {{ userInfo.registrationDate }}</div> | ||||
|   </a-card> | ||||
|   <VerifyModel ref="verifyModelRef" /> | ||||
|  | ||||
|   <a-modal v-model:visible="visible" title="修改基本信息" @before-ok="save" @close="reset"> | ||||
|     <GiForm ref="formRef" v-model="form" :options="options" :columns="columns" /> | ||||
|   </a-modal> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { updateUserBaseInfo } from '@/apis' | ||||
| import VerifyModel from '../components/VerifyModel.vue' | ||||
| import { updateUserBaseInfo, updateUserPassword } from '@/apis' | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| import { type Columns, GiForm } from '@/components/GiForm' | ||||
| import { useForm } from '@/hooks' | ||||
| import { useUserStore } from '@/stores' | ||||
| import { encryptByRsa } from '@/utils/encrypt' | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| const userInfo = computed(() => userStore.userInfo) | ||||
| const verifyModelRef = ref<InstanceType<typeof VerifyModel>>() | ||||
| const onEditNickName = () => { | ||||
|   userStore.editNickNameVisible = true | ||||
| const formRef = ref<InstanceType<typeof GiForm>>() | ||||
|  | ||||
| const options: Options = { | ||||
|   form: {}, | ||||
|   col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 }, | ||||
|   btns: { hide: true } | ||||
| } | ||||
| const openVerifyModel = (type: 'phone' | 'email') => { | ||||
|   verifyModelRef.value?.open(type) | ||||
|  | ||||
| const columns: Columns = [ | ||||
|   { | ||||
|     label: '昵称', | ||||
|     field: 'nickname', | ||||
|     type: 'input', | ||||
|     rules: [{ required: true, message: '请输入昵称' }] | ||||
|   }, | ||||
|   { | ||||
|     label: '性别', | ||||
|     field: 'gender', | ||||
|     type: 'radio-group', | ||||
|     options: [ | ||||
|       { label: '男', value: 1 }, | ||||
|       { label: '女', value: 2 }, | ||||
|       { label: '未知', value: 0, disabled: true } | ||||
|     ], | ||||
|     rules: [{ required: true, message: '请选择性别' }] | ||||
|   } | ||||
| ] | ||||
|  | ||||
| const { form, resetForm } = useForm({ | ||||
|   nickname: userInfo.value.nickname, | ||||
|   gender: userInfo.value.gender | ||||
| }) | ||||
|  | ||||
| // 重置 | ||||
| const reset = () => { | ||||
|   formRef.value?.formRef?.resetFields() | ||||
|   resetForm() | ||||
| } | ||||
|  | ||||
| const visible = ref(false) | ||||
| // 修改 | ||||
| const onUpdate = async () => { | ||||
|   reset() | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| // 保存 | ||||
| const save = async () => { | ||||
|   const isInvalid = await formRef.value?.formRef?.validate() | ||||
|   if (isInvalid) return false | ||||
|   try { | ||||
|     await updateUserBaseInfo(form) | ||||
|     Message.success('修改成功') | ||||
|     // 修改成功后,重新获取用户信息 | ||||
|     await userStore.getInfo() | ||||
|     return true | ||||
|   } catch (error) { | ||||
|     return false | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
|             v-if="item.jumpMode == 'modal'" | ||||
|             class="btn" | ||||
|             :type="item.status ? 'secondary' : 'primary'" | ||||
|             @click="openVerifyModel(item.type, item.status)" | ||||
|             @click="onUpdate(item.type, item.status)" | ||||
|           > | ||||
|             {{ item.status ? '修改' : '绑定' }} | ||||
|           </a-button> | ||||
| @@ -44,19 +44,15 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { socialAuth, getSocialAccount, unbindSocialAccount } from '@/apis' | ||||
| import { socialAuth, listUserSocial, unbindSocialAccount } from '@/apis' | ||||
| import type { ModeItem } from '../type' | ||||
| import { useUserStore } from '@/stores' | ||||
| import VerifyModel from '../components/VerifyModel.vue' | ||||
| import { useUserStore } from '@/stores' | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| const userInfo = computed(() => userStore.userInfo) | ||||
| const verifyModelRef = ref<InstanceType<typeof VerifyModel>>() | ||||
| const openVerifyModel = (type: 'phone' | 'email') => { | ||||
|   verifyModelRef.value?.open(type) | ||||
| } | ||||
| const socialList = ref<any>([]) | ||||
|  | ||||
| const socialList = ref<any>([]) | ||||
| const modeList = ref<ModeItem[]>([]) | ||||
| modeList.value = [ | ||||
|   { | ||||
| @@ -94,12 +90,8 @@ modeList.value = [ | ||||
|     status: socialList.value.some((el) => el == 'github') | ||||
|   } | ||||
| ] | ||||
| const initData = () => { | ||||
|   getSocialAccount().then((res) => { | ||||
|     socialList.value = res.data.map((el) => el.source) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| // 绑定 | ||||
| const onBinding = (type: string, status: boolean) => { | ||||
|   if (!status) { | ||||
|     socialAuth(type).then((res) => { | ||||
| @@ -114,6 +106,19 @@ const onBinding = (type: string, status: boolean) => { | ||||
|   } | ||||
| } | ||||
|  | ||||
| const verifyModelRef = ref<InstanceType<typeof VerifyModel>>() | ||||
| // 修改 | ||||
| const onUpdate = (type: string) => { | ||||
|   verifyModelRef.value?.open(type) | ||||
| } | ||||
|  | ||||
| // 初始化数据 | ||||
| const initData = () => { | ||||
|   listUserSocial().then((res) => { | ||||
|     socialList.value = res.data.map((el) => el.source) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
|   initData() | ||||
| }) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="btn-wrapper"> | ||||
|           <a-switch disabled /> | ||||
|           <a-switch disabled title="未开放" /> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|         <div class="info-desc">为了您的账号安全,建议定期修改密码</div> | ||||
|       </div> | ||||
|       <div class="btn-wrapper"> | ||||
|         <a-button class="btn">修改</a-button> | ||||
|         <a-button class="btn" @click="onUpdate">修改</a-button> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="detail"> | ||||
| @@ -31,8 +31,91 @@ | ||||
|       </div> | ||||
|     </div> | ||||
|   </a-card> | ||||
|  | ||||
|   <a-modal v-model:visible="visible" title="修改密码" @before-ok="save" @close="reset"> | ||||
|     <GiForm ref="formRef" v-model="form" :options="options" :columns="columns" /> | ||||
|   </a-modal> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup></script> | ||||
| <script lang="ts" setup> | ||||
| import { updateUserPassword } from '@/apis' | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| import { encryptByRsa } from '@/utils/encrypt' | ||||
| import { type Columns, GiForm } from '@/components/GiForm' | ||||
| import { useForm } from '@/hooks' | ||||
| import { useUserStore } from '@/stores' | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| const userInfo = computed(() => userStore.userInfo) | ||||
| const formRef = ref<InstanceType<typeof GiForm>>() | ||||
|  | ||||
| const options: Options = { | ||||
|   form: {}, | ||||
|   col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 }, | ||||
|   btns: { hide: true } | ||||
| } | ||||
|  | ||||
| const columns: Columns = [ | ||||
|   { | ||||
|     label: '当前密码', | ||||
|     field: 'oldPassword', | ||||
|     type: 'input-password', | ||||
|     rules: [{ required: true, message: '请输入当前密码' }], | ||||
|     hide: () => { | ||||
|       return userInfo.pwdResetTime | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     label: '新密码', | ||||
|     field: 'newPassword', | ||||
|     type: 'input-password', | ||||
|     rules: [{ required: true, message: '请输入新密码' }] | ||||
|   }, | ||||
|   { | ||||
|     label: '确认新密码', | ||||
|     field: 'rePassword', | ||||
|     type: 'input-password', | ||||
|     rules: [{ required: true, message: '请再次输入新密码' }], | ||||
|     props: { | ||||
|       placeholder: '请再次输入新密码' | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|  | ||||
| const { form, resetForm } = useForm({ | ||||
|   oldPassword: '', | ||||
|   newPassword: '', | ||||
|   rePassword: '' | ||||
| }) | ||||
|  | ||||
| // 重置 | ||||
| const reset = () => { | ||||
|   formRef.value?.formRef?.resetFields() | ||||
|   resetForm() | ||||
| } | ||||
|  | ||||
| const visible = ref(false) | ||||
| // 修改 | ||||
| const onUpdate = async () => { | ||||
|   reset() | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| // 保存 | ||||
| const save = async () => { | ||||
|   const isInvalid = await formRef.value?.formRef?.validate() | ||||
|   if (isInvalid) return false | ||||
|   try { | ||||
|     await updateUserPassword({ | ||||
|       oldPassword: encryptByRsa(form.oldPassword) || '', | ||||
|       newPassword: encryptByRsa(form.newPassword) || '' | ||||
|     }) | ||||
|     Message.success('修改成功') | ||||
|     return true | ||||
|   } catch (error) { | ||||
|     return false | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped></style> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user