update
This commit is contained in:
parent
54be0f58f2
commit
cdd46d912e
@ -45,4 +45,22 @@ export function submitUserAuth(data) {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
export function sendCode(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/user/send-code',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改密码
|
||||||
|
export function changePassword(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/user/change-password',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@ -11,6 +11,9 @@
|
|||||||
v-model:openKeys="openKeys"
|
v-model:openKeys="openKeys"
|
||||||
theme="dark"
|
theme="dark"
|
||||||
mode="inline"
|
mode="inline"
|
||||||
|
:inline-collapsed="collapsed"
|
||||||
|
:defaultOpenKeys="['finance']"
|
||||||
|
:defaultSelectedKeys="['dashboard']"
|
||||||
style="background: #1a1a1a;"
|
style="background: #1a1a1a;"
|
||||||
>
|
>
|
||||||
<a-menu-item key="dashboard" @click="() => $router.push('/dashboard')">
|
<a-menu-item key="dashboard" @click="() => $router.push('/dashboard')">
|
||||||
@ -72,6 +75,9 @@
|
|||||||
</a>
|
</a>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
|
<a-menu-item key="1">
|
||||||
|
<a href="javascript:;" @click="changePasswordVisible = true">修改密码</a>
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="0">
|
<a-menu-item key="0">
|
||||||
<a href="javascript:;" @click="handleLogout">退出登录</a>
|
<a href="javascript:;" @click="handleLogout">退出登录</a>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@ -93,6 +99,7 @@
|
|||||||
蜂快 · 运营商平台 ©2025
|
蜂快 · 运营商平台 ©2025
|
||||||
</a-layout-footer> -->
|
</a-layout-footer> -->
|
||||||
</a-layout>
|
</a-layout>
|
||||||
|
<change-password v-model:visible="changePasswordVisible" />
|
||||||
</a-layout>
|
</a-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -109,6 +116,7 @@ import {
|
|||||||
UserOutlined,
|
UserOutlined,
|
||||||
ProfileOutlined
|
ProfileOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
|
import ChangePassword from '../views/ChangePassword.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AdminLayout',
|
name: 'AdminLayout',
|
||||||
@ -119,12 +127,14 @@ export default {
|
|||||||
CreditCardOutlined,
|
CreditCardOutlined,
|
||||||
WalletOutlined,
|
WalletOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
ProfileOutlined
|
ProfileOutlined,
|
||||||
|
ChangePassword
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const changePasswordVisible = ref(false);
|
||||||
|
|
||||||
const collapsed = computed({
|
const collapsed = computed({
|
||||||
get: () => store.getters.sidebarCollapsed,
|
get: () => store.getters.sidebarCollapsed,
|
||||||
@ -132,7 +142,7 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const userInfo = computed(() => store.getters.userInfo);
|
const userInfo = computed(() => store.getters.userInfo);
|
||||||
const selectedKeys = ref([]);
|
const selectedKeys = ref(['dashboard']);
|
||||||
const openKeys = ref(['finance']);
|
const openKeys = ref(['finance']);
|
||||||
|
|
||||||
// 获取当前页面标题
|
// 获取当前页面标题
|
||||||
@ -176,7 +186,8 @@ export default {
|
|||||||
userInfo,
|
userInfo,
|
||||||
handleLogout,
|
handleLogout,
|
||||||
currentPageTitle,
|
currentPageTitle,
|
||||||
route
|
route,
|
||||||
|
changePasswordVisible
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -65,6 +65,12 @@ const routes = [
|
|||||||
name: 'UserAuth',
|
name: 'UserAuth',
|
||||||
component: () => import('../views/UserAuth.vue'),
|
component: () => import('../views/UserAuth.vue'),
|
||||||
meta: { title: '实名认证', icon: 'user' }
|
meta: { title: '实名认证', icon: 'user' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'user/change-password',
|
||||||
|
name: 'ChangePassword',
|
||||||
|
component: () => import('../views/ChangePassword.vue'),
|
||||||
|
meta: { title: '修改密码', icon: 'lock' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
249
src/views/ChangePassword.vue
Normal file
249
src/views/ChangePassword.vue
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:visible="visible"
|
||||||
|
@update:visible="$emit('update:visible', $event)"
|
||||||
|
title="修改密码"
|
||||||
|
:confirm-loading="loading"
|
||||||
|
@ok="handleSubmit"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:maskClosable="false"
|
||||||
|
:keyboard="false"
|
||||||
|
width="400px"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formState"
|
||||||
|
name="changePassword"
|
||||||
|
:rules="rules"
|
||||||
|
class="password-form"
|
||||||
|
>
|
||||||
|
<a-form-item name="phone">
|
||||||
|
<a-input
|
||||||
|
v-model:value="formState.phone"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
:maxLength="11"
|
||||||
|
class="input-item"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<mobile-outlined />
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="verify_code">
|
||||||
|
<div class="verify-code-input">
|
||||||
|
<a-input
|
||||||
|
v-model:value="formState.verify_code"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
:maxLength="6"
|
||||||
|
class="input-item"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<safety-certificate-outlined />
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
:disabled="!!countdown"
|
||||||
|
@click="handleSendCode"
|
||||||
|
class="send-code-btn"
|
||||||
|
>
|
||||||
|
{{ countdown ? `${countdown}s后重试` : '获取验证码' }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="new_password">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="formState.new_password"
|
||||||
|
placeholder="请输入新密码"
|
||||||
|
class="input-item"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<lock-outlined />
|
||||||
|
</template>
|
||||||
|
</a-input-password>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="confirm_password">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="formState.confirm_password"
|
||||||
|
placeholder="请确认新密码"
|
||||||
|
class="input-item"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<lock-outlined />
|
||||||
|
</template>
|
||||||
|
</a-input-password>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, reactive, watch, onMounted, onBeforeUnmount } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
import {
|
||||||
|
LockOutlined,
|
||||||
|
MobileOutlined,
|
||||||
|
SafetyCertificateOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
import { sendCode, changePassword } from '../api/user';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ChangePassword',
|
||||||
|
components: {
|
||||||
|
LockOutlined,
|
||||||
|
MobileOutlined,
|
||||||
|
SafetyCertificateOutlined
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:visible'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const store = useStore();
|
||||||
|
const loading = ref(false);
|
||||||
|
const countdown = ref(0);
|
||||||
|
const formRef = ref(null);
|
||||||
|
let countdownTimer = null;
|
||||||
|
|
||||||
|
const formState = reactive({
|
||||||
|
phone: '',
|
||||||
|
verify_code: '',
|
||||||
|
new_password: '',
|
||||||
|
confirm_password: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const validateConfirmPassword = async (rule, value) => {
|
||||||
|
if (!value) {
|
||||||
|
return Promise.reject('请确认新密码');
|
||||||
|
}
|
||||||
|
if (value !== formState.new_password) {
|
||||||
|
return Promise.reject('两次输入的密码不一致');
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
verify_code: [{ required: true, message: '请输入验证码' }],
|
||||||
|
new_password: [
|
||||||
|
{ required: true, message: '请输入新密码' },
|
||||||
|
{ min: 6, message: '密码长度不能小于6位' }
|
||||||
|
],
|
||||||
|
confirm_password: [{ required: true, validator: validateConfirmPassword }]
|
||||||
|
};
|
||||||
|
|
||||||
|
const startCountdown = () => {
|
||||||
|
countdown.value = 60;
|
||||||
|
countdownTimer = setInterval(() => {
|
||||||
|
countdown.value--;
|
||||||
|
if (countdown.value <= 0) {
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
countdownTimer = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSendCode = async () => {
|
||||||
|
try {
|
||||||
|
await sendCode({ phone: formState.phone });
|
||||||
|
message.success('验证码已发送');
|
||||||
|
startCountdown();
|
||||||
|
} catch (error) {
|
||||||
|
message.error(error.message || '发送验证码失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value.validate();
|
||||||
|
loading.value = true;
|
||||||
|
await changePassword({
|
||||||
|
phone: formState.phone,
|
||||||
|
verify_code: formState.verify_code,
|
||||||
|
new_password: formState.new_password
|
||||||
|
});
|
||||||
|
message.success('密码修改成功');
|
||||||
|
handleCancel();
|
||||||
|
} catch (error) {
|
||||||
|
if (error.message) {
|
||||||
|
message.error(error.message);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
// 清空表单
|
||||||
|
if (formRef.value) {
|
||||||
|
formRef.value.resetFields();
|
||||||
|
}
|
||||||
|
// 重置倒计时
|
||||||
|
countdown.value = 0;
|
||||||
|
if (countdownTimer) {
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
countdownTimer = null;
|
||||||
|
}
|
||||||
|
// 关闭模态框
|
||||||
|
emit('update:visible', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听visible变化,当显示时设置手机号
|
||||||
|
watch(() => props.visible, (val) => {
|
||||||
|
if (val) {
|
||||||
|
const userInfo = store.getters.userInfo;
|
||||||
|
if (userInfo && userInfo.phone) {
|
||||||
|
formState.phone = userInfo.phone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 组件卸载前清理
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (countdownTimer) {
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
countdownTimer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
formRef,
|
||||||
|
formState,
|
||||||
|
rules,
|
||||||
|
loading,
|
||||||
|
countdown,
|
||||||
|
handleSubmit,
|
||||||
|
handleSendCode,
|
||||||
|
handleCancel
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.password-form {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-code-input {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-code-btn {
|
||||||
|
white-space: nowrap;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user