重构:重构个人中心前端代码

This commit is contained in:
Charles7c 2023-02-04 16:20:35 +08:00
parent 35e2964b49
commit 86c4350de4
11 changed files with 265 additions and 270 deletions

View File

@ -1,5 +1,7 @@
import axios from 'axios'; import axios from 'axios';
const BASE_URL = '/system/user/center';
export interface BasicInfoModel { export interface BasicInfoModel {
username: string; username: string;
nickname: string; nickname: string;
@ -9,24 +11,27 @@ export interface BasicInfoModel {
export interface AvatarRes { export interface AvatarRes {
avatar: string; avatar: string;
} }
export function uploadAvatar(data: FormData) { 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 { export interface UpdateBasicInfoReq {
nickname: string; nickname: string;
gender: number; gender: number;
} }
export function updateBasicInfo(req: UpdateBasicInfoReq) { 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 { export interface UpdatePasswordReq {
oldPassword: string; oldPassword: string;
newPassword: string; newPassword: string;
} }
export function updatePassword(req: UpdatePasswordReq) { export function updatePassword(req: UpdatePasswordReq) {
return axios.patch('/system/user/center/password', req); return axios.patch(`${BASE_URL}/password`, req);
} }
export interface UpdateEmailReq { export interface UpdateEmailReq {
@ -34,6 +39,7 @@ export interface UpdateEmailReq {
captcha: string; captcha: string;
currentPassword: string; currentPassword: string;
} }
export function updateEmail(req: UpdateEmailReq) { export function updateEmail(req: UpdateEmailReq) {
return axios.patch('/system/user/center/email', req); return axios.patch(`${BASE_URL}/email`, req);
} }

View File

@ -62,7 +62,7 @@
</template> </template>
<script lang="ts" setup> <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 { FieldRule, ValidatedError } from '@arco-design/web-vue';
import { LoginReq } from '@/api/auth/login'; import { LoginReq } from '@/api/auth/login';
import { useI18n } from 'vue-i18n'; 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') }], username: [{ required: true, message: t('login.form.error.required.username') }],
password: [{ required: true, message: t('login.form.error.required.password') }], password: [{ required: true, message: t('login.form.error.required.password') }],
captcha: [{ required: true, message: t('login.form.error.required.captcha') }], captcha: [{ required: true, message: t('login.form.error.required.captcha') }],
} };
}), }),
}); });
const { form, rules } = toRefs(data); const { form, rules } = toRefs(data);

View File

@ -1,39 +1,30 @@
<template> <template>
<a-form <a-form
ref="formRef" ref="formRef"
:model="formData" :model="form"
:rules="rules" :rules="rules"
class="form"
:label-col-props="{ span: 8 }" :label-col-props="{ span: 8 }"
:wrapper-col-props="{ span: 16 }" :wrapper-col-props="{ span: 16 }"
class="form"
> >
<a-form-item <a-form-item :label="$t('userCenter.basicInfo.form.label.username')" disabled>
:label="$t('userCenter.basicInfo.form.label.username')"
disabled
>
<a-input <a-input
v-model="formData.username" v-model="form.username"
:placeholder="$t('userCenter.basicInfo.form.placeholder.username')" :placeholder="$t('userCenter.basicInfo.form.placeholder.username')"
size="large"
max-length="50" max-length="50"
size="large"
/> />
</a-form-item> </a-form-item>
<a-form-item <a-form-item :label="$t('userCenter.basicInfo.form.label.nickname')" field="nickname">
field="nickname"
:label="$t('userCenter.basicInfo.form.label.nickname')"
>
<a-input <a-input
v-model="formData.nickname" v-model="form.nickname"
:placeholder="$t('userCenter.basicInfo.form.placeholder.nickname')" :placeholder="$t('userCenter.basicInfo.form.placeholder.nickname')"
size="large" size="large"
max-length="32" max-length="32"
/> />
</a-form-item> </a-form-item>
<a-form-item <a-form-item :label="$t('userCenter.basicInfo.form.label.gender')" field="gender">
field="gender" <a-radio-group v-model="form.gender">
:label="$t('userCenter.basicInfo.form.label.gender')"
>
<a-radio-group v-model="formData.gender">
<a-radio :value="1"></a-radio> <a-radio :value="1"></a-radio>
<a-radio :value="2"></a-radio> <a-radio :value="2"></a-radio>
<a-radio :value="0" disabled>未知</a-radio> <a-radio :value="0" disabled>未知</a-radio>
@ -41,10 +32,10 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-space> <a-space>
<a-button type="primary" :loading="loading" @click="save"> <a-button :loading="loading" type="primary" @click="handleSave">
{{ $t('userCenter.basicInfo.form.save') }} {{ $t('userCenter.basicInfo.form.save') }}
</a-button> </a-button>
<a-button type="secondary" @click="reset"> <a-button @click="handleReset">
{{ $t('userCenter.basicInfo.form.reset') }} {{ $t('userCenter.basicInfo.form.reset') }}
</a-button> </a-button>
</a-space> </a-space>
@ -53,57 +44,61 @@
</template> </template>
<script lang="ts" setup> <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 { useI18n } from 'vue-i18n';
import { useLoginStore } from '@/store'; import { useLoginStore } from '@/store';
import { updateBasicInfo } from '@/api/system/user-center';
import useLoading from '@/hooks/loading'; const { proxy } = getCurrentInstance() as any;
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 { t } = useI18n(); const { t } = useI18n();
const { loading, setLoading } = useLoading();
const loginStore = useLoginStore(); const loginStore = useLoginStore();
const formRef = ref<FormInstance>(); const loading = ref(false);
const formData = ref<BasicInfoModel>({
const data = reactive({
//
form: {
username: loginStore.username, username: loginStore.username,
nickname: loginStore.nickname, nickname: loginStore.nickname,
gender: loginStore.gender, gender: loginStore.gender,
}); } as BasicInfoModel,
const rules = computed((): Record<string, FieldRule[]> => { //
rules: computed((): Record<string, FieldRule[]> => {
return { return {
username: [ username: [{ required: true, message: t('userCenter.basicInfo.form.error.required.username') }],
{ required: true, message: t('userCenter.basicInfo.form.error.required.username') } nickname: [{ required: true, message: t('userCenter.basicInfo.form.error.required.nickname') }],
], };
nickname: [ }),
{ required: true, message: t('userCenter.basicInfo.form.error.required.nickname') }
],
}
}); });
const { form, rules } = toRefs(data);
// /**
const save = async () => { * 保存
*/
const handleSave = () => {
if (loading.value) return; if (loading.value) return;
const errors = await formRef.value?.validate(); proxy.$refs.formRef.validate((valid: any) => {
if (!errors) { if (!valid) {
setLoading(true); loading.value = true;
try { updateBasicInfo({
const res = await updateBasicInfo({ nickname: form.value.nickname,
nickname: formData.value.nickname, gender: form.value.gender,
gender: formData.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> </script>

View File

@ -88,6 +88,7 @@
listOperationLog(params).then((res) => { listOperationLog(params).then((res) => {
operationLogList.value = res.data.list; operationLogList.value = res.data.list;
total.value = res.data.total; total.value = res.data.total;
}).finally(() => {
loading.value = false; loading.value = false;
}); });
}; };
@ -125,6 +126,7 @@
.container { .container {
padding: 0 20px 20px 20px; padding: 0 20px 20px 20px;
} }
:deep(.arco-table-th) { :deep(.arco-table-th) {
&:last-child { &:last-child {
.arco-table-th-item-title { .arco-table-th-item-title {
@ -132,10 +134,12 @@
} }
} }
} }
.action-icon { .action-icon {
cursor: pointer; cursor: pointer;
margin-right: 10px; margin-right: 10px;
} }
.action-icon:hover { .action-icon:hover {
color: #0960bd; color: #0960bd;
} }

View File

@ -21,16 +21,20 @@
<style scoped lang="less"> <style scoped lang="less">
:deep(.arco-list-item) { :deep(.arco-list-item) {
border-bottom: none !important; border-bottom: none !important;
.arco-typography { .arco-typography {
margin-bottom: 20px; margin-bottom: 20px;
} }
.arco-list-item-meta-avatar { .arco-list-item-meta-avatar {
margin-bottom: 1px; margin-bottom: 1px;
} }
.arco-list-item-meta { .arco-list-item-meta {
padding: 0; padding: 0;
} }
} }
:deep(.arco-list-item-meta-content) { :deep(.arco-list-item-meta-content) {
flex: 1; flex: 1;
border-bottom: 1px solid var(--color-neutral-3); border-bottom: 1px solid var(--color-neutral-3);
@ -43,6 +47,7 @@
.tip { .tip {
color: rgb(var(--gray-6)); color: rgb(var(--gray-6));
} }
.operation { .operation {
margin-right: 6px; margin-right: 6px;
} }

View File

@ -15,7 +15,7 @@
</a-typography-paragraph> </a-typography-paragraph>
</div> </div>
<div class="operation"> <div class="operation">
<a-link @click="toUpdate"> <a-link :title="$t('userCenter.securitySettings.button.update')" @click="toUpdate">
{{ $t('userCenter.securitySettings.button.update') }} {{ $t('userCenter.securitySettings.button.update') }}
</a-link> </a-link>
</div> </div>
@ -23,96 +23,82 @@
</a-list-item-meta> </a-list-item-meta>
<a-modal <a-modal
v-model:visible="visible"
:title="$t('userCenter.securitySettings.updateEmail.modal.title')" :title="$t('userCenter.securitySettings.updateEmail.modal.title')"
:visible="visible"
:mask-closable="false" :mask-closable="false"
@ok="handleUpdate"
@cancel="handleCancel" @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 <a-input
v-model="formData.newEmail" v-model="form.newEmail"
:placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.newEmail')" :placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.newEmail')"
size="large"
allow-clear allow-clear
> size="large"
</a-input> />
</a-form-item> </a-form-item>
<a-form-item <a-form-item :label="$t('userCenter.securitySettings.updateEmail.form.label.captcha')" field="captcha">
field="captcha"
:validate-trigger="['change', 'blur']"
:label="$t('userCenter.securitySettings.updateEmail.form.label.captcha')"
>
<a-input <a-input
v-model="formData.captcha" v-model="form.captcha"
:placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.captcha')" :placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.captcha')"
max-length="6"
allow-clear
size="large" size="large"
style="width: 80%" style="width: 80%"
allow-clear />
max-length="6"
>
</a-input>
<a-button <a-button
class="captcha-btn" :loading="captchaLoading"
type="primary" type="primary"
size="large" size="large"
:loading="captchaLoading"
:disabled="captchaDisable" :disabled="captchaDisable"
@click="sendCaptcha" class="captcha-btn"
@click="handleSendCaptcha"
> >
{{ captchaBtnName }} {{ captchaBtnName }}
</a-button> </a-button>
</a-form-item> </a-form-item>
<a-form-item <a-form-item :label="$t('userCenter.securitySettings.updateEmail.form.label.currentPassword')" field="currentPassword">
field="currentPassword"
:validate-trigger="['change', 'blur']"
:label="$t('userCenter.securitySettings.updateEmail.form.label.currentPassword')"
>
<a-input-password <a-input-password
v-model="formData.currentPassword" v-model="form.currentPassword"
:placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.currentPassword')" :placeholder="$t('userCenter.securitySettings.updateEmail.form.placeholder.currentPassword')"
size="large"
allow-clear
max-length="32" max-length="32"
> allow-clear
</a-input-password> size="large"
/>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, computed } from 'vue'; import { getCurrentInstance, ref, reactive, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { FieldRule } from '@arco-design/web-vue';
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 { getMailCaptcha } from '@/api/common/captcha'; import { getMailCaptcha } from '@/api/common/captcha';
import { updateEmail } from '@/api/system/user-center'; import { updateEmail } from '@/api/system/user-center';
import { useI18n } from 'vue-i18n';
import { useLoginStore } from '@/store';
import { encryptByRsa } from '@/utils/encrypt'; import { encryptByRsa } from '@/utils/encrypt';
const { proxy } = getCurrentInstance() as any;
const { t } = useI18n(); const { t } = useI18n();
const { loading, setLoading } = useLoading();
const loginStore = useLoginStore(); const loginStore = useLoginStore();
const captchaTime = ref(60);
const captchaTimer = ref();
const captchaLoading = ref(false);
const captchaDisable = ref(false);
const visible = ref(false); const visible = ref(false);
const captchaBtnNameKey = ref('userCenter.securitySettings.updateEmail.form.sendCaptcha'); const captchaBtnNameKey = ref('userCenter.securitySettings.updateEmail.form.sendCaptcha');
const captchaBtnName = computed(() => t(captchaBtnNameKey.value)); const captchaBtnName = computed(() => t(captchaBtnNameKey.value));
const captchaLoading = ref(false);
const captchaDisable = ref(false); //
const captchaTime = ref(60); const form = reactive({
const captchaTimer = ref();
const formRef = ref<FormInstance>();
const formData = reactive({
newEmail: '', newEmail: '',
captcha: '', captcha: '',
currentPassword: '', currentPassword: '',
}); });
//
const rules = computed((): Record<string, FieldRule[]> => { const rules = computed((): Record<string, FieldRule[]> => {
return { return {
newEmail: [ newEmail: [
@ -134,10 +120,12 @@
currentPassword: [ currentPassword: [
{ required: true, message: t('userCenter.securitySettings.updateEmail.form.error.required.currentPassword') } { required: true, message: t('userCenter.securitySettings.updateEmail.form.error.required.currentPassword') }
] ]
} };
}); });
// /**
* 重置验证码
*/
const resetCaptcha = () => { const resetCaptcha = () => {
window.clearInterval(captchaTimer.value); window.clearInterval(captchaTimer.value);
captchaTime.value = 60; captchaTime.value = 60;
@ -145,23 +133,21 @@
captchaDisable.value = false; captchaDisable.value = false;
} }
// /**
const sendCaptcha = async () => { * 发送验证码
*/
const handleSendCaptcha = () => {
if (captchaLoading.value) return; if (captchaLoading.value) return;
const errors = await formRef.value?.validateField('newEmail'); proxy.$refs.formRef.validateField('newEmail', (valid: any) => {
if (errors) return; if (!valid) {
captchaLoading.value = true; captchaLoading.value = true;
captchaBtnNameKey.value = 'userCenter.securitySettings.updateEmail.form.loading.sendCaptcha'; captchaBtnNameKey.value = 'userCenter.securitySettings.updateEmail.form.loading.sendCaptcha';
try { getMailCaptcha({
const res = await getMailCaptcha({ email: form.newEmail
email: formData.newEmail }).then((res) => {
});
if (res.success) {
captchaLoading.value = false; captchaLoading.value = false;
captchaDisable.value = true; captchaDisable.value = true;
captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value -= 1}s)`; captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value -= 1}s)`;
Message.success(res.msg);
captchaTimer.value = window.setInterval(function() { captchaTimer.value = window.setInterval(function() {
captchaTime.value -= 1; captchaTime.value -= 1;
captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value}s)`; captchaBtnNameKey.value = `${t('userCenter.securitySettings.updateEmail.form.reSendCaptcha')}(${captchaTime.value}s)`;
@ -172,42 +158,46 @@
captchaDisable.value = false; captchaDisable.value = false;
} }
}, 1000); }, 1000);
} proxy.$message.success(res.msg);
} catch (err) { }).catch(() => {
resetCaptcha(); resetCaptcha();
captchaLoading.value = false; 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 = () => { const handleCancel = () => {
visible.value = false; visible.value = false;
formRef.value?.resetFields(); proxy.$refs.formRef.resetFields();
resetCaptcha(); 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 = () => { const toUpdate = () => {
visible.value = true; visible.value = true;
}; };

View File

@ -15,7 +15,7 @@
</a-typography-paragraph> </a-typography-paragraph>
</div> </div>
<div class="operation"> <div class="operation">
<a-link> <a-link :title="$t('userCenter.securitySettings.button.update')">
{{ $t('userCenter.securitySettings.button.update') }} {{ $t('userCenter.securitySettings.button.update') }}
</a-link> </a-link>
</div> </div>

View File

@ -15,7 +15,7 @@
</a-typography-paragraph> </a-typography-paragraph>
</div> </div>
<div class="operation"> <div class="operation">
<a-link @click="toUpdate"> <a-link :title="$t('userCenter.securitySettings.button.update')" @click="toUpdate">
{{ $t('userCenter.securitySettings.button.update') }} {{ $t('userCenter.securitySettings.button.update') }}
</a-link> </a-link>
</div> </div>
@ -23,90 +23,74 @@
</a-list-item-meta> </a-list-item-meta>
<a-modal <a-modal
v-model:visible="visible"
:title="$t('userCenter.securitySettings.updatePwd.modal.title')" :title="$t('userCenter.securitySettings.updatePwd.modal.title')"
:visible="visible"
:mask-closable="false" :mask-closable="false"
@ok="handleUpdate"
@cancel="handleCancel" @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 <a-input-password
v-model="formData.oldPassword" v-model="form.oldPassword"
:placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.oldPassword')" :placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.oldPassword')"
size="large"
allow-clear
max-length="32" max-length="32"
> allow-clear
</a-input-password> size="large"
/>
</a-form-item> </a-form-item>
<a-form-item <a-form-item :label="$t('userCenter.securitySettings.updatePwd.form.label.newPassword')" field="newPassword">
field="newPassword"
:validate-trigger="['change', 'blur']"
:label="$t('userCenter.securitySettings.updatePwd.form.label.newPassword')"
>
<a-input-password <a-input-password
v-model="formData.newPassword" v-model="form.newPassword"
:placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.newPassword')" :placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.newPassword')"
size="large"
allow-clear
max-length="32" max-length="32"
> allow-clear
</a-input-password> size="large"
/>
</a-form-item> </a-form-item>
<a-form-item <a-form-item :label="$t('userCenter.securitySettings.updatePwd.form.label.rePassword')" field="rePassword">
field="rePassword"
:validate-trigger="['change', 'blur']"
:label="$t('userCenter.securitySettings.updatePwd.form.label.rePassword')"
>
<a-input-password <a-input-password
v-model="formData.rePassword" v-model="form.rePassword"
:placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.rePassword')" :placeholder="$t('userCenter.securitySettings.updatePwd.form.placeholder.rePassword')"
size="large"
allow-clear
max-length="32" max-length="32"
> allow-clear
</a-input-password> size="large"
/>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <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 { useI18n } from 'vue-i18n';
import { useLoginStore } from '@/store'; 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'; import { encryptByRsa } from '@/utils/encrypt';
const { proxy } = getCurrentInstance() as any;
const { t } = useI18n(); const { t } = useI18n();
const { loading, setLoading } = useLoading();
const loginStore = useLoginStore(); const loginStore = useLoginStore();
const visible = ref(false); const visible = ref(false);
const formRef = ref<FormInstance>();
const formData = reactive({ //
const form = reactive({
oldPassword: '', oldPassword: '',
newPassword: '', newPassword: '',
rePassword: '', rePassword: '',
}); });
//
const rules = computed((): Record<string, FieldRule[]> => { const rules = computed((): Record<string, FieldRule[]> => {
return { return {
oldPassword: [ oldPassword: [{ required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.oldPassword') }],
{ required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.oldPassword') }
],
newPassword: [ newPassword: [
{ required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.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') }, { match: /^(?=.*\d)(?=.*[a-z]).{6,32}$/, message: t('userCenter.securitySettings.updatePwd.form.error.match.newPassword') },
{ {
validator: (value, callback) => { validator: (value, callback) => {
if (value === formData.oldPassword) { if (value === form.oldPassword) {
callback(t('userCenter.securitySettings.updatePwd.form.error.validator.newPassword')) callback(t('userCenter.securitySettings.updatePwd.form.error.validator.newPassword'))
} else { } else {
callback() callback()
@ -118,7 +102,7 @@
{ required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.rePassword') }, { required: true, message: t('userCenter.securitySettings.updatePwd.form.error.required.rePassword') },
{ {
validator: (value, callback) => { validator: (value, callback) => {
if (value !== formData.newPassword) { if (value !== form.newPassword) {
callback(t('userCenter.securitySettings.updatePwd.form.error.validator.rePassword')) callback(t('userCenter.securitySettings.updatePwd.form.error.validator.rePassword'))
} else { } else {
callback() 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 = () => { const handleCancel = () => {
visible.value = false; 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 = () => { const toUpdate = () => {
visible.value = true; visible.value = true;
}; };

View File

@ -2,26 +2,23 @@
<a-card :bordered="false"> <a-card :bordered="false">
<a-space :size="54"> <a-space :size="54">
<a-upload <a-upload
:custom-request="handleUpload"
list-type="picture-card"
:file-list="avatarList" :file-list="avatarList"
:show-upload-button="true"
:show-file-list="false" :show-file-list="false"
@change="changeAvatar" list-type="picture-card"
:show-upload-button="true"
:custom-request="handleUpload"
@change="handleAvatarChange"
> >
<template #upload-button> <template #upload-button>
<a-avatar :size="100" class="info-avatar"> <a-avatar :size="100" class="info-avatar">
<template #trigger-icon> <template #trigger-icon><icon-camera /></template>
<icon-camera /> <img v-if="avatarList.length" :src="avatarList[0].url" :alt="$t('userCenter.panel.avatar')" />
</template>
<img v-if="avatarList.length" :src="avatarList[0].url" :alt="$t('userCenter.panel.avatar')"/>
</a-avatar> </a-avatar>
</template> </template>
</a-upload> </a-upload>
<a-descriptions <a-descriptions
:column="2" :column="2"
align="right"
layout="inline-horizontal"
:label-style="{ :label-style="{
width: '140px', width: '140px',
fontWeight: 'normal', fontWeight: 'normal',
@ -32,6 +29,8 @@
paddingLeft: '8px', paddingLeft: '8px',
textAlign: 'left', 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.nickname')">{{ loginStore.nickname }}</a-descriptions-item>
<a-descriptions-item :label="$t('userCenter.panel.label.gender')"> <a-descriptions-item :label="$t('userCenter.panel.label.gender')">
@ -54,15 +53,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { getCurrentInstance, ref } from 'vue';
import type { import { FileItem, RequestOption } from '@arco-design/web-vue';
FileItem,
RequestOption,
} from '@arco-design/web-vue/es/upload/interfaces';
import { useLoginStore } from '@/store';
import { uploadAvatar } from '@/api/system/user-center'; import { uploadAvatar } from '@/api/system/user-center';
import { useLoginStore } from '@/store';
import getAvatar from '@/utils/avatar'; import getAvatar from '@/utils/avatar';
import { Message } from '@arco-design/web-vue';
const { proxy } = getCurrentInstance() as any;
const loginStore = useLoginStore(); const loginStore = useLoginStore();
const avatar = { const avatar = {
@ -72,12 +69,11 @@
}; };
const avatarList = ref<FileItem[]>([avatar]); const avatarList = ref<FileItem[]>([avatar]);
// /**
const changeAvatar = (fileItemList: FileItem[], currentFile: FileItem) => { * 上传头像
avatarList.value = [currentFile]; *
}; * @param options 选项
*/
//
const handleUpload = (options: RequestOption) => { const handleUpload = (options: RequestOption) => {
const controller = new AbortController(); const controller = new AbortController();
(async function requestWrap() { (async function requestWrap() {
@ -91,15 +87,13 @@
onProgress(20); onProgress(20);
const formData = new FormData(); const formData = new FormData();
formData.append(name as string, fileItem.file as Blob); formData.append(name as string, fileItem.file as Blob);
try { uploadAvatar(formData).then((res) => {
const res = await uploadAvatar(formData);
onSuccess(res); onSuccess(res);
if (res.success) Message.success(res.msg);
//
loginStore.avatar = res.data.avatar; loginStore.avatar = res.data.avatar;
} catch (error) { proxy.$message.success(res.msg);
}).catch((error) => {
onError(error); onError(error);
} });
})(); })();
return { return {
abort() { abort() {
@ -107,6 +101,16 @@
}, },
}; };
}; };
/**
* 切换头像
*
* @param fileItemList 文件列表
* @param currentFile 当前文件
*/
const handleAvatarChange = (fileItemList: FileItem[], currentFile: FileItem) => {
avatarList.value = [currentFile];
};
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@ -114,11 +118,13 @@
padding: 14px 0 4px 4px; padding: 14px 0 4px 4px;
border-radius: 4px; border-radius: 4px;
} }
:deep(.arco-avatar-trigger-icon-button) { :deep(.arco-avatar-trigger-icon-button) {
width: 32px; width: 32px;
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
background-color: #e8f3ff; background-color: #e8f3ff;
.arco-icon-camera { .arco-icon-camera {
margin-top: 8px; margin-top: 8px;
color: rgb(var(--arcoblue-6)); color: rgb(var(--arcoblue-6));

View File

@ -27,6 +27,7 @@ export default {
'userCenter.basicInfo.form.error.required.nickname': 'Please enter nickname', 'userCenter.basicInfo.form.error.required.nickname': 'Please enter nickname',
'userCenter.basicInfo.form.save': 'Save', 'userCenter.basicInfo.form.save': 'Save',
'userCenter.basicInfo.form.save.success': 'Save success',
'userCenter.basicInfo.form.reset': 'Reset', 'userCenter.basicInfo.form.reset': 'Reset',
// security-settings // security-settings

View File

@ -27,6 +27,7 @@ export default {
'userCenter.basicInfo.form.error.required.nickname': '请输入昵称', 'userCenter.basicInfo.form.error.required.nickname': '请输入昵称',
'userCenter.basicInfo.form.save': '保存', 'userCenter.basicInfo.form.save': '保存',
'userCenter.basicInfo.form.save.success': '保存成功',
'userCenter.basicInfo.form.reset': '重置', 'userCenter.basicInfo.form.reset': '重置',
// security-settings // security-settings