mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	重构:重构个人中心前端代码
This commit is contained in:
		| @@ -1,5 +1,7 @@ | ||||
| import axios from 'axios'; | ||||
|  | ||||
| const BASE_URL = '/system/user/center'; | ||||
|  | ||||
| export interface BasicInfoModel { | ||||
|   username: string; | ||||
|   nickname: string; | ||||
| @@ -9,24 +11,27 @@ export interface BasicInfoModel { | ||||
| export interface AvatarRes { | ||||
|   avatar: string; | ||||
| } | ||||
|  | ||||
| export function uploadAvatar(data: FormData) { | ||||
|   return axios.post<AvatarRes>('/system/user/center/avatar', data); | ||||
|   return axios.post<AvatarRes>(`${BASE_URL}/avatar`, data); | ||||
| } | ||||
|  | ||||
| export interface UpdateBasicInfoReq { | ||||
|   nickname: string; | ||||
|   gender: number; | ||||
| } | ||||
|  | ||||
| export function updateBasicInfo(req: UpdateBasicInfoReq) { | ||||
|   return axios.patch('/system/user/center/basic/info', req); | ||||
|   return axios.patch(`${BASE_URL}/basic/info`, req); | ||||
| } | ||||
|  | ||||
| export interface UpdatePasswordReq { | ||||
|   oldPassword: string; | ||||
|   newPassword: string; | ||||
| } | ||||
|  | ||||
| export function updatePassword(req: UpdatePasswordReq) { | ||||
|   return axios.patch('/system/user/center/password', req); | ||||
|   return axios.patch(`${BASE_URL}/password`, req); | ||||
| } | ||||
|  | ||||
| export interface UpdateEmailReq { | ||||
| @@ -34,6 +39,7 @@ export interface UpdateEmailReq { | ||||
|   captcha: string; | ||||
|   currentPassword: string; | ||||
| } | ||||
|  | ||||
| export function updateEmail(req: UpdateEmailReq) { | ||||
|   return axios.patch('/system/user/center/email', req); | ||||
|   return axios.patch(`${BASE_URL}/email`, req); | ||||
| } | ||||
| @@ -62,7 +62,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { getCurrentInstance, ref, toRefs, reactive, computed } from "vue"; | ||||
|   import { getCurrentInstance, ref, toRefs, reactive, computed } from 'vue'; | ||||
|   import { FieldRule, ValidatedError } from '@arco-design/web-vue'; | ||||
|   import { LoginReq } from '@/api/auth/login'; | ||||
|   import { useI18n } from 'vue-i18n'; | ||||
| @@ -101,7 +101,7 @@ import { getCurrentInstance, ref, toRefs, reactive, computed } from "vue"; | ||||
|         username: [{ required: true, message: t('login.form.error.required.username') }], | ||||
|         password: [{ required: true, message: t('login.form.error.required.password') }], | ||||
|         captcha: [{ required: true, message: t('login.form.error.required.captcha') }], | ||||
|       } | ||||
|       }; | ||||
|     }), | ||||
|   }); | ||||
|   const { form, rules } = toRefs(data); | ||||
|   | ||||
| @@ -1,39 +1,30 @@ | ||||
| <template> | ||||
|   <a-form | ||||
|     ref="formRef" | ||||
|     :model="formData" | ||||
|     :model="form" | ||||
|     :rules="rules" | ||||
|     class="form" | ||||
|     :label-col-props="{ span: 8 }" | ||||
|     :wrapper-col-props="{ span: 16 }" | ||||
|     class="form" | ||||
|   > | ||||
|     <a-form-item | ||||
|       :label="$t('userCenter.basicInfo.form.label.username')" | ||||
|       disabled | ||||
|     > | ||||
|     <a-form-item :label="$t('userCenter.basicInfo.form.label.username')" disabled> | ||||
|       <a-input | ||||
|         v-model="formData.username" | ||||
|         v-model="form.username" | ||||
|         :placeholder="$t('userCenter.basicInfo.form.placeholder.username')" | ||||
|         size="large" | ||||
|         max-length="50" | ||||
|         size="large" | ||||
|       /> | ||||
|     </a-form-item> | ||||
|     <a-form-item | ||||
|       field="nickname" | ||||
|       :label="$t('userCenter.basicInfo.form.label.nickname')" | ||||
|     > | ||||
|     <a-form-item :label="$t('userCenter.basicInfo.form.label.nickname')" field="nickname"> | ||||
|       <a-input | ||||
|         v-model="formData.nickname" | ||||
|         v-model="form.nickname" | ||||
|         :placeholder="$t('userCenter.basicInfo.form.placeholder.nickname')" | ||||
|         size="large" | ||||
|         max-length="32" | ||||
|       /> | ||||
|     </a-form-item> | ||||
|     <a-form-item | ||||
|       field="gender" | ||||
|       :label="$t('userCenter.basicInfo.form.label.gender')" | ||||
|     > | ||||
|       <a-radio-group v-model="formData.gender"> | ||||
|     <a-form-item :label="$t('userCenter.basicInfo.form.label.gender')" field="gender"> | ||||
|       <a-radio-group v-model="form.gender"> | ||||
|         <a-radio :value="1">男</a-radio> | ||||
|         <a-radio :value="2">女</a-radio> | ||||
|         <a-radio :value="0" disabled>未知</a-radio> | ||||
| @@ -41,10 +32,10 @@ | ||||
|     </a-form-item> | ||||
|     <a-form-item> | ||||
|       <a-space> | ||||
|         <a-button type="primary" :loading="loading" @click="save"> | ||||
|         <a-button :loading="loading" type="primary" @click="handleSave"> | ||||
|           {{ $t('userCenter.basicInfo.form.save') }} | ||||
|         </a-button> | ||||
|         <a-button type="secondary" @click="reset"> | ||||
|         <a-button @click="handleReset"> | ||||
|           {{ $t('userCenter.basicInfo.form.reset') }} | ||||
|         </a-button> | ||||
|       </a-space> | ||||
| @@ -53,57 +44,61 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
|   import { ref, computed } from 'vue'; | ||||
|   import { getCurrentInstance, ref, toRefs, reactive, computed } from 'vue'; | ||||
|   import { FieldRule } from '@arco-design/web-vue'; | ||||
|   import { BasicInfoModel, updateBasicInfo } from "@/api/system/user-center"; | ||||
|   import { useI18n } from 'vue-i18n'; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import { updateBasicInfo } from '@/api/system/user-center'; | ||||
|   import useLoading from '@/hooks/loading'; | ||||
|   import { FormInstance } from '@arco-design/web-vue/es/form'; | ||||
|   import { BasicInfoModel } from '@/api/system/user-center'; | ||||
|   import { FieldRule, Message } from '@arco-design/web-vue'; | ||||
|  | ||||
|   const { proxy } = getCurrentInstance() as any; | ||||
|  | ||||
|   const { t } = useI18n(); | ||||
|   const { loading, setLoading } = useLoading(); | ||||
|   const loginStore = useLoginStore(); | ||||
|   const formRef = ref<FormInstance>(); | ||||
|   const formData = ref<BasicInfoModel>({ | ||||
|     username: loginStore.username, | ||||
|     nickname: loginStore.nickname, | ||||
|     gender: loginStore.gender, | ||||
|   }); | ||||
|   const rules = computed((): Record<string, FieldRule[]> => { | ||||
|     return { | ||||
|       username: [ | ||||
|         { required: true, message: t('userCenter.basicInfo.form.error.required.username') } | ||||
|       ], | ||||
|       nickname: [ | ||||
|         { required: true, message: t('userCenter.basicInfo.form.error.required.nickname') } | ||||
|       ], | ||||
|     } | ||||
|   }); | ||||
|   const loading = ref(false); | ||||
|  | ||||
|   // 保存 | ||||
|   const save = async () => { | ||||
|   const data = reactive({ | ||||
|     // 表单数据 | ||||
|     form: { | ||||
|       username: loginStore.username, | ||||
|       nickname: loginStore.nickname, | ||||
|       gender: loginStore.gender, | ||||
|     } as BasicInfoModel, | ||||
|     // 表单验证规则 | ||||
|     rules: computed((): Record<string, FieldRule[]> => { | ||||
|       return { | ||||
|         username: [{ required: true, message: t('userCenter.basicInfo.form.error.required.username') }], | ||||
|         nickname: [{ required: true, message: t('userCenter.basicInfo.form.error.required.nickname') }], | ||||
|       }; | ||||
|     }), | ||||
|   }); | ||||
|   const { form, rules } = toRefs(data); | ||||
|  | ||||
|   /** | ||||
|    * 保存 | ||||
|    */ | ||||
|   const handleSave = () => { | ||||
|     if (loading.value) return; | ||||
|     const errors = await formRef.value?.validate(); | ||||
|     if (!errors) { | ||||
|       setLoading(true); | ||||
|       try { | ||||
|         const res = await updateBasicInfo({ | ||||
|           nickname: formData.value.nickname, | ||||
|           gender: formData.value.gender, | ||||
|     proxy.$refs.formRef.validate((valid: any) => { | ||||
|       if (!valid) { | ||||
|         loading.value = true; | ||||
|         updateBasicInfo({ | ||||
|           nickname: form.value.nickname, | ||||
|           gender: form.value.gender, | ||||
|         }).then((res) => { | ||||
|           loginStore.getInfo(); | ||||
|           proxy.$message.success(t('userCenter.basicInfo.form.save.success')); | ||||
|         }).finally(() => { | ||||
|           loading.value = false; | ||||
|         }); | ||||
|         await loginStore.getInfo(); | ||||
|         if (res.success) Message.success(res.msg); | ||||
|       } finally { | ||||
|         setLoading(false); | ||||
|       } | ||||
|     } | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   // 重置 | ||||
|   const reset = async () => { | ||||
|     await formRef.value?.resetFields(); | ||||
|   /** | ||||
|    * 重置 | ||||
|    */ | ||||
|   const handleReset = () => { | ||||
|     proxy.$refs.formRef.resetFields(); | ||||
|   }; | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -88,6 +88,7 @@ | ||||
|     listOperationLog(params).then((res) => { | ||||
|       operationLogList.value = res.data.list; | ||||
|       total.value = res.data.total; | ||||
|     }).finally(() => { | ||||
|       loading.value = false; | ||||
|     }); | ||||
|   }; | ||||
| @@ -125,6 +126,7 @@ | ||||
|   .container { | ||||
|     padding: 0 20px 20px 20px; | ||||
|   } | ||||
|  | ||||
|   :deep(.arco-table-th) { | ||||
|     &:last-child { | ||||
|       .arco-table-th-item-title { | ||||
| @@ -132,10 +134,12 @@ | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .action-icon { | ||||
|     cursor: pointer; | ||||
|     margin-right: 10px; | ||||
|   } | ||||
|  | ||||
|   .action-icon:hover { | ||||
|     color: #0960bd; | ||||
|   } | ||||
|   | ||||
| @@ -21,16 +21,20 @@ | ||||
| <style scoped lang="less"> | ||||
|   :deep(.arco-list-item) { | ||||
|     border-bottom: none !important; | ||||
|  | ||||
|     .arco-typography { | ||||
|       margin-bottom: 20px; | ||||
|     } | ||||
|  | ||||
|     .arco-list-item-meta-avatar { | ||||
|       margin-bottom: 1px; | ||||
|     } | ||||
|  | ||||
|     .arco-list-item-meta { | ||||
|       padding: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep(.arco-list-item-meta-content) { | ||||
|     flex: 1; | ||||
|     border-bottom: 1px solid var(--color-neutral-3); | ||||
| @@ -43,6 +47,7 @@ | ||||
|       .tip { | ||||
|         color: rgb(var(--gray-6)); | ||||
|       } | ||||
|  | ||||
|       .operation { | ||||
|         margin-right: 6px; | ||||
|       } | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|         </a-typography-paragraph> | ||||
|       </div> | ||||
|       <div class="operation"> | ||||
|         <a-link @click="toUpdate"> | ||||
|         <a-link :title="$t('userCenter.securitySettings.button.update')" @click="toUpdate"> | ||||
|           {{ $t('userCenter.securitySettings.button.update') }} | ||||
|         </a-link> | ||||
|       </div> | ||||
| @@ -23,96 +23,82 @@ | ||||
|   </a-list-item-meta> | ||||
|  | ||||
|   <a-modal | ||||
|     v-model:visible="visible" | ||||
|     :title="$t('userCenter.securitySettings.updateEmail.modal.title')" | ||||
|     :visible="visible" | ||||
|     :mask-closable="false" | ||||
|     @ok="handleUpdate" | ||||
|     @cancel="handleCancel" | ||||
|     @before-ok="handleUpdate" | ||||
|   > | ||||
|     <a-form ref="formRef" :model="formData" :rules="rules"> | ||||
|       <a-form-item | ||||
|         field="newEmail" | ||||
|         :validate-trigger="['change', 'blur']" | ||||
|         :label="$t('userCenter.securitySettings.updateEmail.form.label.newEmail')" | ||||
|       > | ||||
|     <a-form ref="formRef" :model="form" :rules="rules"> | ||||
|       <a-form-item :label="$t('userCenter.securitySettings.updateEmail.form.label.newEmail')" field="newEmail"> | ||||
|         <a-input | ||||
|           v-model="formData.newEmail" | ||||
|           v-model="form.newEmail" | ||||
|           :placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.newEmail')" | ||||
|           size="large" | ||||
|           allow-clear | ||||
|         > | ||||
|         </a-input> | ||||
|           size="large" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item | ||||
|         field="captcha" | ||||
|         :validate-trigger="['change', 'blur']" | ||||
|         :label="$t('userCenter.securitySettings.updateEmail.form.label.captcha')" | ||||
|       > | ||||
|       <a-form-item :label="$t('userCenter.securitySettings.updateEmail.form.label.captcha')" field="captcha"> | ||||
|         <a-input | ||||
|           v-model="formData.captcha" | ||||
|           v-model="form.captcha" | ||||
|           :placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.captcha')" | ||||
|           max-length="6" | ||||
|           allow-clear | ||||
|           size="large" | ||||
|           style="width: 80%" | ||||
|           allow-clear | ||||
|           max-length="6" | ||||
|         > | ||||
|         </a-input> | ||||
|         /> | ||||
|         <a-button | ||||
|           class="captcha-btn" | ||||
|           :loading="captchaLoading" | ||||
|           type="primary" | ||||
|           size="large" | ||||
|           :loading="captchaLoading" | ||||
|           :disabled="captchaDisable" | ||||
|           @click="sendCaptcha" | ||||
|           class="captcha-btn" | ||||
|           @click="handleSendCaptcha" | ||||
|         > | ||||
|           {{ captchaBtnName }} | ||||
|         </a-button> | ||||
|       </a-form-item> | ||||
|       <a-form-item | ||||
|         field="currentPassword" | ||||
|         :validate-trigger="['change', 'blur']" | ||||
|         :label="$t('userCenter.securitySettings.updateEmail.form.label.currentPassword')" | ||||
|       > | ||||
|       <a-form-item :label="$t('userCenter.securitySettings.updateEmail.form.label.currentPassword')" field="currentPassword"> | ||||
|         <a-input-password | ||||
|           v-model="formData.currentPassword" | ||||
|           v-model="form.currentPassword" | ||||
|           :placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.currentPassword')" | ||||
|           size="large" | ||||
|           allow-clear | ||||
|           max-length="32" | ||||
|         > | ||||
|         </a-input-password> | ||||
|           allow-clear | ||||
|           size="large" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|     </a-form> | ||||
|   </a-modal> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
|   import { ref, reactive, computed } from 'vue'; | ||||
|   import { useI18n } from 'vue-i18n'; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import { FormInstance } from '@arco-design/web-vue/es/form'; | ||||
|   import useLoading from '@/hooks/loading'; | ||||
|   import { FieldRule, Message } from '@arco-design/web-vue'; | ||||
|   import { getCurrentInstance, ref, reactive, computed } from 'vue'; | ||||
|   import { FieldRule } from '@arco-design/web-vue'; | ||||
|   import { getMailCaptcha } from '@/api/common/captcha'; | ||||
|   import { updateEmail } from '@/api/system/user-center'; | ||||
|   import { useI18n } from 'vue-i18n'; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import { encryptByRsa } from '@/utils/encrypt'; | ||||
|  | ||||
|   const { proxy } = getCurrentInstance() as any; | ||||
|  | ||||
|   const { t } = useI18n(); | ||||
|   const { loading, setLoading } = useLoading(); | ||||
|   const loginStore = useLoginStore(); | ||||
|   const captchaTime = ref(60); | ||||
|   const captchaTimer = ref(); | ||||
|   const captchaLoading = ref(false); | ||||
|   const captchaDisable = ref(false); | ||||
|   const visible = ref(false); | ||||
|   const captchaBtnNameKey = ref('userCenter.securitySettings.updateEmail.form.sendCaptcha'); | ||||
|   const captchaBtnName = computed(() => t(captchaBtnNameKey.value)); | ||||
|   const captchaLoading = ref(false); | ||||
|   const captchaDisable = ref(false); | ||||
|   const captchaTime = ref(60); | ||||
|   const captchaTimer = ref(); | ||||
|   const formRef = ref<FormInstance>(); | ||||
|   const formData = reactive({ | ||||
|  | ||||
|   // 表单数据 | ||||
|   const form = reactive({ | ||||
|     newEmail: '', | ||||
|     captcha: '', | ||||
|     currentPassword: '', | ||||
|   }); | ||||
|   // 表单验证规则 | ||||
|   const rules = computed((): Record<string, FieldRule[]> => { | ||||
|     return { | ||||
|       newEmail: [ | ||||
| @@ -134,10 +120,12 @@ | ||||
|       currentPassword: [ | ||||
|         { required: true, message: t('userCenter.securitySettings.updateEmail.form.error.required.currentPassword') } | ||||
|       ] | ||||
|     } | ||||
|     }; | ||||
|   }); | ||||
|  | ||||
|   // 重置验证码相关 | ||||
|   /** | ||||
|    * 重置验证码 | ||||
|    */ | ||||
|   const resetCaptcha = () => { | ||||
|     window.clearInterval(captchaTimer.value); | ||||
|     captchaTime.value = 60; | ||||
| @@ -145,69 +133,71 @@ | ||||
|     captchaDisable.value = false; | ||||
|   } | ||||
|  | ||||
|   // 发送验证码 | ||||
|   const sendCaptcha = async () => { | ||||
|   /** | ||||
|    * 发送验证码 | ||||
|    */ | ||||
|   const handleSendCaptcha = () => { | ||||
|     if (captchaLoading.value) return; | ||||
|     const errors = await formRef.value?.validateField('newEmail'); | ||||
|     if (errors) return; | ||||
|     captchaLoading.value = true; | ||||
|     captchaBtnNameKey.value = 'userCenter.securitySettings.updateEmail.form.loading.sendCaptcha'; | ||||
|     try { | ||||
|       const res = await getMailCaptcha({ | ||||
|         email: formData.newEmail | ||||
|       }); | ||||
|       if (res.success) { | ||||
|         captchaLoading.value = false; | ||||
|         captchaDisable.value = true; | ||||
|         captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value -= 1}s)`; | ||||
|         Message.success(res.msg); | ||||
|  | ||||
|         captchaTimer.value = window.setInterval(function() { | ||||
|           captchaTime.value -= 1; | ||||
|           captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value}s)`; | ||||
|           if (captchaTime.value < 0) { | ||||
|             window.clearInterval(captchaTimer.value); | ||||
|             captchaTime.value = 60; | ||||
|             captchaBtnNameKey.value = t('userCenter.securitySettings.updateEmail.form.reSendCaptcha'); | ||||
|             captchaDisable.value = false; | ||||
|           } | ||||
|         }, 1000); | ||||
|     proxy.$refs.formRef.validateField('newEmail', (valid: any) => { | ||||
|       if (!valid) { | ||||
|         captchaLoading.value = true; | ||||
|         captchaBtnNameKey.value = 'userCenter.securitySettings.updateEmail.form.loading.sendCaptcha'; | ||||
|         getMailCaptcha({ | ||||
|           email: form.newEmail | ||||
|         }).then((res) => { | ||||
|           captchaLoading.value = false; | ||||
|           captchaDisable.value = true; | ||||
|           captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value -= 1}s)`; | ||||
|           captchaTimer.value = window.setInterval(function() { | ||||
|             captchaTime.value -= 1; | ||||
|             captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value}s)`; | ||||
|             if (captchaTime.value < 0) { | ||||
|               window.clearInterval(captchaTimer.value); | ||||
|               captchaTime.value = 60; | ||||
|               captchaBtnNameKey.value = t('userCenter.securitySettings.updateEmail.form.reSendCaptcha'); | ||||
|               captchaDisable.value = false; | ||||
|             } | ||||
|           }, 1000); | ||||
|           proxy.$message.success(res.msg); | ||||
|         }).catch(() => { | ||||
|           resetCaptcha(); | ||||
|           captchaLoading.value = false; | ||||
|         }); | ||||
|       } | ||||
|     } catch (err) { | ||||
|       resetCaptcha(); | ||||
|       captchaLoading.value = false; | ||||
|       console.log((err as Error)); | ||||
|     } | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   // 确定修改 | ||||
|   const handleUpdate = async () => { | ||||
|     if (loading.value) return false; | ||||
|     const errors = await formRef.value?.validate(); | ||||
|     if (errors) return false; | ||||
|     setLoading(true); | ||||
|     try { | ||||
|       const res = await updateEmail({ | ||||
|         newEmail: formData.newEmail, | ||||
|         captcha: formData.captcha, | ||||
|         currentPassword: encryptByRsa(formData.currentPassword) || '', | ||||
|       }); | ||||
|       await loginStore.getInfo(); | ||||
|       if (res.success) Message.success(res.msg); | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|     } | ||||
|     return true; | ||||
|   }; | ||||
|  | ||||
|   // 取消修改 | ||||
|   /** | ||||
|    * 取消 | ||||
|    */ | ||||
|   const handleCancel = () => { | ||||
|     visible.value = false; | ||||
|     formRef.value?.resetFields(); | ||||
|     proxy.$refs.formRef.resetFields(); | ||||
|     resetCaptcha(); | ||||
|   }; | ||||
|  | ||||
|   // 打开修改窗口 | ||||
|   /** | ||||
|    * 修改 | ||||
|    */ | ||||
|   const handleUpdate = () => { | ||||
|     proxy.$refs.formRef.validate((valid: any) => { | ||||
|       if (!valid) { | ||||
|         updateEmail({ | ||||
|           newEmail: form.newEmail, | ||||
|           captcha: form.captcha, | ||||
|           currentPassword: encryptByRsa(form.currentPassword) || '', | ||||
|         }).then((res) => { | ||||
|           handleCancel(); | ||||
|           loginStore.getInfo(); | ||||
|           proxy.$message.success(res.msg); | ||||
|         }); | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 打开修改对话框 | ||||
|    */ | ||||
|   const toUpdate = () => { | ||||
|     visible.value = true; | ||||
|   }; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|         </a-typography-paragraph> | ||||
|       </div> | ||||
|       <div class="operation"> | ||||
|         <a-link> | ||||
|         <a-link :title="$t('userCenter.securitySettings.button.update')"> | ||||
|           {{ $t('userCenter.securitySettings.button.update') }} | ||||
|         </a-link> | ||||
|       </div> | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|         </a-typography-paragraph> | ||||
|       </div> | ||||
|       <div class="operation"> | ||||
|         <a-link @click="toUpdate"> | ||||
|         <a-link :title="$t('userCenter.securitySettings.button.update')" @click="toUpdate"> | ||||
|           {{ $t('userCenter.securitySettings.button.update') }} | ||||
|         </a-link> | ||||
|       </div> | ||||
| @@ -23,90 +23,74 @@ | ||||
|   </a-list-item-meta> | ||||
|  | ||||
|   <a-modal | ||||
|     v-model:visible="visible" | ||||
|     :title="$t('userCenter.securitySettings.updatePwd.modal.title')" | ||||
|     :visible="visible" | ||||
|     :mask-closable="false" | ||||
|     @ok="handleUpdate" | ||||
|     @cancel="handleCancel" | ||||
|     @before-ok="handleUpdate" | ||||
|   > | ||||
|     <a-form ref="formRef" :model="formData" :rules="rules"> | ||||
|       <a-form-item | ||||
|         field="oldPassword" | ||||
|         :validate-trigger="['change', 'blur']" | ||||
|         :label="$t('userCenter.securitySettings.updatePwd.form.label.oldPassword')" | ||||
|       > | ||||
|     <a-form ref="formRef" :model="form" :rules="rules"> | ||||
|       <a-form-item :label="$t('userCenter.securitySettings.updatePwd.form.label.oldPassword')" field="oldPassword"> | ||||
|         <a-input-password | ||||
|           v-model="formData.oldPassword" | ||||
|           v-model="form.oldPassword" | ||||
|           :placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.oldPassword')" | ||||
|           size="large" | ||||
|           allow-clear | ||||
|           max-length="32" | ||||
|         > | ||||
|         </a-input-password> | ||||
|           allow-clear | ||||
|           size="large" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item | ||||
|         field="newPassword" | ||||
|         :validate-trigger="['change', 'blur']" | ||||
|         :label="$t('userCenter.securitySettings.updatePwd.form.label.newPassword')" | ||||
|       > | ||||
|       <a-form-item :label="$t('userCenter.securitySettings.updatePwd.form.label.newPassword')" field="newPassword"> | ||||
|         <a-input-password | ||||
|           v-model="formData.newPassword" | ||||
|           v-model="form.newPassword" | ||||
|           :placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.newPassword')" | ||||
|           size="large" | ||||
|           allow-clear | ||||
|           max-length="32" | ||||
|         > | ||||
|         </a-input-password> | ||||
|           allow-clear | ||||
|           size="large" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item | ||||
|         field="rePassword" | ||||
|         :validate-trigger="['change', 'blur']" | ||||
|         :label="$t('userCenter.securitySettings.updatePwd.form.label.rePassword')" | ||||
|       > | ||||
|       <a-form-item :label="$t('userCenter.securitySettings.updatePwd.form.label.rePassword')" field="rePassword"> | ||||
|         <a-input-password | ||||
|           v-model="formData.rePassword" | ||||
|           v-model="form.rePassword" | ||||
|           :placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.rePassword')" | ||||
|           size="large" | ||||
|           allow-clear | ||||
|           max-length="32" | ||||
|         > | ||||
|         </a-input-password> | ||||
|           allow-clear | ||||
|           size="large" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|     </a-form> | ||||
|   </a-modal> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
|   import { ref, reactive, computed } from 'vue'; | ||||
|   import { getCurrentInstance, ref, reactive, computed } from 'vue'; | ||||
|   import { FieldRule } from '@arco-design/web-vue'; | ||||
|   import { updatePassword } from '@/api/system/user-center'; | ||||
|   import { useI18n } from 'vue-i18n'; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import { FormInstance } from '@arco-design/web-vue/es/form'; | ||||
|   import useLoading from '@/hooks/loading'; | ||||
|   import { FieldRule, Message } from '@arco-design/web-vue'; | ||||
|   import { updatePassword } from '@/api/system/user-center'; | ||||
|   import { encryptByRsa } from '@/utils/encrypt'; | ||||
|  | ||||
|   const { proxy } = getCurrentInstance() as any; | ||||
|  | ||||
|   const { t } = useI18n(); | ||||
|   const { loading, setLoading } = useLoading(); | ||||
|   const loginStore = useLoginStore(); | ||||
|   const visible = ref(false); | ||||
|   const formRef = ref<FormInstance>(); | ||||
|   const formData = reactive({ | ||||
|  | ||||
|   // 表单数据 | ||||
|   const form = reactive({ | ||||
|     oldPassword: '', | ||||
|     newPassword: '', | ||||
|     rePassword: '', | ||||
|   }); | ||||
|   // 表单验证规则 | ||||
|   const rules = computed((): Record<string, FieldRule[]> => { | ||||
|     return { | ||||
|       oldPassword: [ | ||||
|         { required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.oldPassword') } | ||||
|       ], | ||||
|       oldPassword: [{ required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.oldPassword') }], | ||||
|       newPassword: [ | ||||
|         { required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.newPassword') }, | ||||
|         { match: /^(?=.*\d)(?=.*[a-z]).{6,32}$/, message: t('userCenter.securitySettings.updatePwd.form.error.match.newPassword') }, | ||||
|         { | ||||
|           validator: (value, callback) => { | ||||
|             if (value === formData.oldPassword) { | ||||
|             if (value === form.oldPassword) { | ||||
|               callback(t('userCenter.securitySettings.updatePwd.form.error.validator.newPassword')) | ||||
|             } else { | ||||
|               callback() | ||||
| @@ -118,7 +102,7 @@ | ||||
|         { required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.rePassword') }, | ||||
|         { | ||||
|           validator: (value, callback) => { | ||||
|             if (value !== formData.newPassword) { | ||||
|             if (value !== form.newPassword) { | ||||
|               callback(t('userCenter.securitySettings.updatePwd.form.error.validator.rePassword')) | ||||
|             } else { | ||||
|               callback() | ||||
| @@ -126,34 +110,37 @@ | ||||
|           } | ||||
|         } | ||||
|       ], | ||||
|     } | ||||
|     }; | ||||
|   }); | ||||
|  | ||||
|   // 确定修改 | ||||
|   const handleUpdate = async () => { | ||||
|     if (loading.value) return false; | ||||
|     const errors = await formRef.value?.validate(); | ||||
|     if (errors) return false; | ||||
|     setLoading(true); | ||||
|     try { | ||||
|       const res = await updatePassword({ | ||||
|         oldPassword: encryptByRsa(formData.oldPassword) || '', | ||||
|         newPassword: encryptByRsa(formData.newPassword) || '', | ||||
|       }); | ||||
|       if (res.success) Message.success(res.msg); | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|     } | ||||
|     return true; | ||||
|   }; | ||||
|  | ||||
|   // 取消修改 | ||||
|   /** | ||||
|    * 取消 | ||||
|    */ | ||||
|   const handleCancel = () => { | ||||
|     visible.value = false; | ||||
|     formRef.value?.resetFields() | ||||
|     proxy.$refs.formRef.resetFields(); | ||||
|   }; | ||||
|  | ||||
|   // 打开修改窗口 | ||||
|   /** | ||||
|    * 修改 | ||||
|    */ | ||||
|   const handleUpdate = () => { | ||||
|     proxy.$refs.formRef.validate((valid: any) => { | ||||
|       if (!valid) { | ||||
|         updatePassword({ | ||||
|           oldPassword: encryptByRsa(form.oldPassword) || '', | ||||
|           newPassword: encryptByRsa(form.newPassword) || '', | ||||
|         }).then((res) => { | ||||
|           handleCancel(); | ||||
|           proxy.$message.success(res.msg); | ||||
|         }); | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 打开修改对话框 | ||||
|    */ | ||||
|   const toUpdate = () => { | ||||
|     visible.value = true; | ||||
|   }; | ||||
|   | ||||
| @@ -2,26 +2,23 @@ | ||||
|   <a-card :bordered="false"> | ||||
|     <a-space :size="54"> | ||||
|       <a-upload | ||||
|         :custom-request="handleUpload" | ||||
|         list-type="picture-card" | ||||
|         :file-list="avatarList" | ||||
|         :show-upload-button="true" | ||||
|         :show-file-list="false" | ||||
|         @change="changeAvatar" | ||||
|         list-type="picture-card" | ||||
|         :show-upload-button="true" | ||||
|         :custom-request="handleUpload" | ||||
|         @change="handleAvatarChange" | ||||
|       > | ||||
|         <template #upload-button> | ||||
|           <a-avatar :size="100" class="info-avatar"> | ||||
|             <template #trigger-icon> | ||||
|               <icon-camera /> | ||||
|             </template> | ||||
|             <img v-if="avatarList.length" :src="avatarList[0].url"  :alt="$t('userCenter.panel.avatar')"/> | ||||
|             <template #trigger-icon><icon-camera /></template> | ||||
|             <img v-if="avatarList.length" :src="avatarList[0].url" :alt="$t('userCenter.panel.avatar')" /> | ||||
|           </a-avatar> | ||||
|         </template> | ||||
|       </a-upload> | ||||
|  | ||||
|       <a-descriptions | ||||
|         :column="2" | ||||
|         align="right" | ||||
|         layout="inline-horizontal" | ||||
|         :label-style="{ | ||||
|           width: '140px', | ||||
|           fontWeight: 'normal', | ||||
| @@ -32,6 +29,8 @@ | ||||
|           paddingLeft: '8px', | ||||
|           textAlign: 'left', | ||||
|         }" | ||||
|         align="right" | ||||
|         layout="inline-horizontal" | ||||
|       > | ||||
|         <a-descriptions-item :label="$t('userCenter.panel.label.nickname')">{{ loginStore.nickname }}</a-descriptions-item> | ||||
|         <a-descriptions-item :label="$t('userCenter.panel.label.gender')"> | ||||
| @@ -54,15 +53,13 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
|   import { ref } from 'vue'; | ||||
|   import type { | ||||
|     FileItem, | ||||
|     RequestOption, | ||||
|   } from '@arco-design/web-vue/es/upload/interfaces'; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import { getCurrentInstance, ref } from 'vue'; | ||||
|   import { FileItem, RequestOption } from '@arco-design/web-vue'; | ||||
|   import { uploadAvatar } from '@/api/system/user-center'; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import getAvatar from '@/utils/avatar'; | ||||
|   import { Message } from '@arco-design/web-vue'; | ||||
|  | ||||
|   const { proxy } = getCurrentInstance() as any; | ||||
|  | ||||
|   const loginStore = useLoginStore(); | ||||
|   const avatar = { | ||||
| @@ -72,12 +69,11 @@ | ||||
|   }; | ||||
|   const avatarList = ref<FileItem[]>([avatar]); | ||||
|  | ||||
|   // 切换头像 | ||||
|   const changeAvatar = (fileItemList: FileItem[], currentFile: FileItem) => { | ||||
|     avatarList.value = [currentFile]; | ||||
|   }; | ||||
|  | ||||
|   // 上传头像 | ||||
|   /** | ||||
|    * 上传头像 | ||||
|    * | ||||
|    * @param options 选项 | ||||
|    */ | ||||
|   const handleUpload = (options: RequestOption) => { | ||||
|     const controller = new AbortController(); | ||||
|     (async function requestWrap() { | ||||
| @@ -91,15 +87,13 @@ | ||||
|       onProgress(20); | ||||
|       const formData = new FormData(); | ||||
|       formData.append(name as string, fileItem.file as Blob); | ||||
|       try { | ||||
|         const res = await uploadAvatar(formData); | ||||
|       uploadAvatar(formData).then((res) => { | ||||
|         onSuccess(res); | ||||
|         if (res.success) Message.success(res.msg); | ||||
|         // 更换头像 | ||||
|         loginStore.avatar = res.data.avatar; | ||||
|       } catch (error) { | ||||
|         proxy.$message.success(res.msg); | ||||
|       }).catch((error) => { | ||||
|         onError(error); | ||||
|       } | ||||
|       }); | ||||
|     })(); | ||||
|     return { | ||||
|       abort() { | ||||
| @@ -107,6 +101,16 @@ | ||||
|       }, | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 切换头像 | ||||
|    * | ||||
|    * @param fileItemList 文件列表 | ||||
|    * @param currentFile 当前文件 | ||||
|    */ | ||||
|   const handleAvatarChange = (fileItemList: FileItem[], currentFile: FileItem) => { | ||||
|     avatarList.value = [currentFile]; | ||||
|   }; | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
| @@ -114,11 +118,13 @@ | ||||
|     padding: 14px 0 4px 4px; | ||||
|     border-radius: 4px; | ||||
|   } | ||||
|  | ||||
|   :deep(.arco-avatar-trigger-icon-button) { | ||||
|     width: 32px; | ||||
|     height: 32px; | ||||
|     line-height: 32px; | ||||
|     background-color: #e8f3ff; | ||||
|  | ||||
|     .arco-icon-camera { | ||||
|       margin-top: 8px; | ||||
|       color: rgb(var(--arcoblue-6)); | ||||
|   | ||||
| @@ -27,6 +27,7 @@ export default { | ||||
|   'userCenter.basicInfo.form.error.required.nickname': 'Please enter nickname', | ||||
|  | ||||
|   'userCenter.basicInfo.form.save': 'Save', | ||||
|   'userCenter.basicInfo.form.save.success': 'Save success', | ||||
|   'userCenter.basicInfo.form.reset': 'Reset', | ||||
|  | ||||
|   // security-settings | ||||
|   | ||||
| @@ -27,6 +27,7 @@ export default { | ||||
|   'userCenter.basicInfo.form.error.required.nickname': '请输入昵称', | ||||
|  | ||||
|   'userCenter.basicInfo.form.save': '保存', | ||||
|   'userCenter.basicInfo.form.save.success': '保存成功', | ||||
|   'userCenter.basicInfo.form.reset': '重置', | ||||
|  | ||||
|   // security-settings | ||||
|   | ||||
		Reference in New Issue
	
	Block a user