11
This commit is contained in:
parent
f175e5159a
commit
45f557c9cb
@ -10,3 +10,9 @@ export const login = (params:any) => request.post('/v1/auth/login', params)
|
||||
// export const updateRole = (id, params) => request.basic.put(`/api/v1/roles/${id}`, params)
|
||||
// // 删除role
|
||||
// export const delRole = (id) => request.basic.delete(`/api/v1/roles/${id}`)
|
||||
// 修改密码
|
||||
export const updatePassword = (newPassword:any) => request.put('/v1/auth/update_password',newPassword)
|
||||
// 获取用户信息
|
||||
export const fetchUserInfo = () => request.get('/v1/auth/info')
|
||||
// 修改手机号
|
||||
export const updatePhoneNumber = (params:any) => request.put('/v1/auth/update_phone', params)
|
||||
@ -1,6 +1,109 @@
|
||||
<!-- src/components/AccountSecurity.vue -->
|
||||
<template>
|
||||
<div class="account-security">
|
||||
<h2>账号安全</h2>
|
||||
<div v-for="(item, index) in securityItems" :key="index" class="security-item">
|
||||
<div class="item-header">
|
||||
<span class="title">{{ item.title }}</span>
|
||||
<div v-if="item.title == '登录密码'">
|
||||
<button class="action-btn" :class="`color-${getActionColor(item.status)}`" @click="item.actionHandler">
|
||||
{{ item.actionText }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="status" v-if="item.title !== '登录密码'">
|
||||
<component :is="getStatusIcon(item.status)" v-if="getStatusIcon(item.status)"
|
||||
:class="['icon', `color-${getStatusColor(item.status)}`]" />
|
||||
<span :class="['text', `color-${getStatusColor(item.status)}`]">
|
||||
{{ item.status === 'bound' ? '已绑定' : item.status === 'unverified' ? '未认证' : '未设置' }}
|
||||
</span>
|
||||
<span class="divider">|</span>
|
||||
<button class="action-btn" :class="`color-${getActionColor(item.status)}`" @click="item.actionHandler">
|
||||
{{ item.actionText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="description">{{ item.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 设置密码弹窗 -->
|
||||
<a-modal v-model:visible="setPasswordModalVisible" title="设置密码" width="500px" :footer="null"
|
||||
@cancel="closeSetPasswordModal">
|
||||
<div style="padding: 24px 0;">
|
||||
<div style="margin-bottom: 24px; font-size: 16px; color: #333;">
|
||||
手机号:<span>{{ userPhone }}</span>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">手机验证码:</label>
|
||||
<a-input v-model:value="passwordForm.smsCode" placeholder="请输入验证码" style="flex: 1;" />
|
||||
<a-button type="primary" :disabled="isSending || countdown > 0" @click="sendSmsCode('password')"
|
||||
style="width: 120px;">
|
||||
{{ isSending || countdown > 0 ? `${countdown}s后重发` : '发送验证码' }}
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">设置新密码:</label>
|
||||
<a-input v-model:value="passwordForm.newPassword" placeholder="请输入8~16位包含数字和字母的密码" type="password"
|
||||
style="flex: 1;" />
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">确认新密码:</label>
|
||||
<a-input v-model:value="passwordForm.confirmPassword" placeholder="请确认密码" type="password" style="flex: 1;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: right; padding: 16px 24px;">
|
||||
<a-button @click="closeSetPasswordModal" style="margin-right: 8px;">取消</a-button>
|
||||
<a-button type="primary" @click="savePassword">保存</a-button>
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
<!-- 修改手机号弹窗 -->
|
||||
<a-modal v-model:visible="editPhoneModalVisible" title="修改手机号" width="500px" :footer="null"
|
||||
@cancel="closeEditPhoneModal">
|
||||
<div style="padding: 24px 0;">
|
||||
<div style="margin-bottom: 24px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">输入新手机号:</label>
|
||||
<a-select v-model:value="phoneForm.countryCode" style="width: 80px;" placeholder="+86">
|
||||
<a-select-option value="+86">+86</a-select-option>
|
||||
<a-select-option value="+852">+852</a-select-option>
|
||||
<a-select-option value="+853">+853</a-select-option>
|
||||
</a-select>
|
||||
<a-input v-model:value="phoneForm.newPhoneNumber" placeholder="请输入新手机号" style="flex: 1;" />
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">手机验证码:</label>
|
||||
<a-input v-model:value="phoneForm.smsCode" placeholder="请输入验证码" style="flex: 1;" />
|
||||
<a-button type="primary" :disabled="isSending || countdown > 0" @click="sendSmsCode('phone')"
|
||||
style="width: 120px;">
|
||||
{{ isSending || countdown > 0 ? `${countdown}s后重发` : '发送验证码' }}
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">输入账号密码:</label>
|
||||
<a-input v-model:value="phoneForm.password" placeholder="请输入账号登录密码" type="password" style="flex: 1;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: right; padding: 16px 24px;">
|
||||
<a-button @click="closeEditPhoneModal" style="margin-right: 8px;">取消</a-button>
|
||||
<a-button type="primary" @click="savePhone">确定</a-button>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, onBeforeMount, computed } from 'vue';
|
||||
import {
|
||||
CheckCircleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
@ -10,9 +113,15 @@ import {
|
||||
import { Modal, message } from 'ant-design-vue';
|
||||
// 在 <script setup> 中引入 router
|
||||
import { useRouter } from 'vue-router';
|
||||
import { updatePassword, updatePhoneNumber } from '@/apis/login';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const userPhone = ref('')
|
||||
onBeforeMount(() => {
|
||||
// 模拟获取用户手机号
|
||||
console.log(1111)
|
||||
userPhone.value = JSON.parse(localStorage.getItem('userInfo') || '{}').phone
|
||||
})
|
||||
const getStatusIcon = (status: SecurityItem['status']) => {
|
||||
switch (status) {
|
||||
case 'bound':
|
||||
@ -46,24 +155,23 @@ const getActionColor = (status: SecurityItem['status']) => {
|
||||
interface SecurityItem {
|
||||
title: string;
|
||||
description: string;
|
||||
status: 'unset' | 'bound' | 'unverified' | 'verified';
|
||||
actionText: string;
|
||||
status?: 'unset' | 'bound' | 'unverified' | 'verified';
|
||||
actionText?: string;
|
||||
actionHandler: () => void;
|
||||
}
|
||||
|
||||
const securityItems = ref<SecurityItem[]>([
|
||||
const securityItems = computed<SecurityItem[]>(() => [
|
||||
{
|
||||
title: '登录密码',
|
||||
description: '安全性高的密码可以使账号更安全。建议您定期更换密码,设置一个包含字母和数字且长度超过8位的密码',
|
||||
status: 'unset',
|
||||
actionText: '设置',
|
||||
status: 'bound',
|
||||
actionText: '修改密码',
|
||||
actionHandler: () => openSetPasswordModal(),
|
||||
},
|
||||
{
|
||||
title: '手机绑定',
|
||||
description: '您已绑定了手机178****5075您的手机号可以直接用于登录、找回密码等',
|
||||
status: 'bound',
|
||||
actionText: '修改',
|
||||
title: '手机号',
|
||||
description: userPhone.value ? '您已绑定了手机178****5075您的手机号可以直接用于登录、找回密码等' : '未绑定手机',
|
||||
status: userPhone.value ? 'bound' : 'unset',
|
||||
actionText: userPhone.value ? '修改手机号' : '绑定手机号',
|
||||
actionHandler: () => openEditPhoneModal(),
|
||||
},
|
||||
{
|
||||
@ -75,21 +183,33 @@ const securityItems = ref<SecurityItem[]>([
|
||||
router.push('/layout/admin/realnameAuth');
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: '微信绑定',
|
||||
// description: '您已绑定微信,可快速扫码登录',
|
||||
// status: 'bound',
|
||||
// actionText: '解绑',
|
||||
// actionHandler: () => alert('确认解绑微信?'),
|
||||
// },
|
||||
{
|
||||
title: '邮箱绑定(即将上线)',
|
||||
description: '绑定邮箱后可接收系统消息,如余额不足、实例即将到期、实例即将释放等消息',
|
||||
status: 'unset',
|
||||
actionText: '绑定',
|
||||
actionHandler: () => alert('跳转到绑定邮箱页面'),
|
||||
},
|
||||
]);
|
||||
// const securityItems = ref<SecurityItem[]>([
|
||||
// {
|
||||
// title: '登录密码',
|
||||
// description: '安全性高的密码可以使账号更安全。建议您定期更换密码,设置一个包含字母和数字且长度超过8位的密码',
|
||||
// status: 'bound',
|
||||
// actionText: '修改密码',
|
||||
// actionHandler: () => openSetPasswordModal(),
|
||||
// },
|
||||
// {
|
||||
// title: '手机号',
|
||||
// description: userPhone.value?'您已绑定了手机178****5075您的手机号可以直接用于登录、找回密码等':'未绑定手机',
|
||||
// status: userPhone.value?'bound':'unset',
|
||||
// actionText: userPhone.value?'修改手机号':'绑定手机号',
|
||||
// actionHandler: () => openEditPhoneModal(),
|
||||
// },
|
||||
// {
|
||||
// title: '实名认证',
|
||||
// description: '实名认证后可以使用AutoDL更完整的功能,如打开实例的自定义服务等',
|
||||
// status: 'unverified',
|
||||
// actionText: '立即认证',
|
||||
// actionHandler: () => {
|
||||
// router.push('/layout/admin/realnameAuth');
|
||||
// },
|
||||
// },
|
||||
|
||||
// ]);
|
||||
|
||||
// 设置密码弹窗
|
||||
const setPasswordModalVisible = ref(false);
|
||||
@ -109,6 +229,7 @@ const closeRealNameAuthModal = () => {
|
||||
|
||||
// 表单数据
|
||||
const passwordForm = reactive({
|
||||
phone: userPhone.value,
|
||||
smsCode: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
@ -185,7 +306,7 @@ const resetPhoneForm = () => {
|
||||
|
||||
|
||||
// 保存密码
|
||||
const savePassword = () => {
|
||||
const savePassword = async () => {
|
||||
if (!passwordForm.smsCode) {
|
||||
message.error('请输入验证码');
|
||||
return;
|
||||
@ -206,13 +327,28 @@ const savePassword = () => {
|
||||
message.error('密码必须为8~16位,且包含字母和数字');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const passwordData = {
|
||||
phone: userPhone.value,
|
||||
code: passwordForm.smsCode,
|
||||
confirmPassword: passwordForm.confirmPassword,
|
||||
newPassword: passwordForm.newPassword
|
||||
};
|
||||
const res = await updatePassword(passwordData);
|
||||
message.success('密码设置成功!');
|
||||
setTimeout(() => {
|
||||
localStorage.clear();
|
||||
router.replace('/login');
|
||||
}, 1500);
|
||||
closeSetPasswordModal();
|
||||
} catch (error: any) {
|
||||
message.error(error);
|
||||
}
|
||||
|
||||
message.success('密码设置成功!');
|
||||
closeSetPasswordModal();
|
||||
};
|
||||
|
||||
// 保存手机号
|
||||
const savePhone = () => {
|
||||
const savePhone = async () => {
|
||||
if (!phoneForm.newPhoneNumber) {
|
||||
message.error('请输入新手机号');
|
||||
return;
|
||||
@ -229,166 +365,24 @@ const savePhone = () => {
|
||||
message.error('请输入账号登录密码');
|
||||
return;
|
||||
}
|
||||
|
||||
message.success('手机号修改成功!');
|
||||
closeEditPhoneModal();
|
||||
try {
|
||||
const phoneData = {
|
||||
newPhone: phoneForm.newPhoneNumber,
|
||||
code: phoneForm.smsCode,
|
||||
Password: phoneForm.password
|
||||
};
|
||||
await updatePhoneNumber(phoneData);
|
||||
message.success('手机号修改成功!');
|
||||
closeEditPhoneModal();
|
||||
setTimeout(() => {
|
||||
localStorage.clear();
|
||||
router.replace('/login');
|
||||
}, 1500);
|
||||
} catch (error: any) {
|
||||
message.error(error);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="account-security">
|
||||
<h2>账号安全</h2>
|
||||
<div v-for="(item, index) in securityItems" :key="index" class="security-item">
|
||||
<div class="item-header">
|
||||
<span class="title">{{ item.title }}</span>
|
||||
<div class="status">
|
||||
<component
|
||||
:is="getStatusIcon(item.status)"
|
||||
v-if="getStatusIcon(item.status)"
|
||||
:class="['icon', `color-${getStatusColor(item.status)}`]"
|
||||
/>
|
||||
<span :class="['text', `color-${getStatusColor(item.status)}`]">
|
||||
{{ item.status === 'bound' ? '已绑定' : item.status === 'unverified' ? '未认证' : '未设置' }}
|
||||
</span>
|
||||
<span class="divider">|</span>
|
||||
<button
|
||||
class="action-btn"
|
||||
:class="`color-${getActionColor(item.status)}`"
|
||||
@click="item.actionHandler"
|
||||
>
|
||||
{{ item.actionText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="description">{{ item.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 设置密码弹窗 -->
|
||||
<a-modal
|
||||
v-model:visible="setPasswordModalVisible"
|
||||
title="设置密码"
|
||||
width="500px"
|
||||
:footer="null"
|
||||
@cancel="closeSetPasswordModal"
|
||||
>
|
||||
<div style="padding: 24px 0;">
|
||||
<div style="margin-bottom: 24px; font-size: 16px; color: #333;">
|
||||
手机号:+86 178****5075
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">手机验证码:</label>
|
||||
<a-input
|
||||
v-model:value="passwordForm.smsCode"
|
||||
placeholder="请输入验证码"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="isSending || countdown > 0"
|
||||
@click="sendSmsCode('password')"
|
||||
style="width: 120px;"
|
||||
>
|
||||
{{ isSending || countdown > 0 ? `${countdown}s后重发` : '发送验证码' }}
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">设置新密码:</label>
|
||||
<a-input
|
||||
v-model:value="passwordForm.newPassword"
|
||||
placeholder="请输入8~16位包含数字和字母的密码"
|
||||
type="password"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">确认新密码:</label>
|
||||
<a-input
|
||||
v-model:value="passwordForm.confirmPassword"
|
||||
placeholder="请确认密码"
|
||||
type="password"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: right; padding: 16px 24px;">
|
||||
<a-button @click="closeSetPasswordModal" style="margin-right: 8px;">取消</a-button>
|
||||
<a-button type="primary" @click="savePassword">保存</a-button>
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
<!-- 修改手机号弹窗 -->
|
||||
<a-modal
|
||||
v-model:visible="editPhoneModalVisible"
|
||||
title="修改手机号"
|
||||
width="500px"
|
||||
:footer="null"
|
||||
@cancel="closeEditPhoneModal"
|
||||
>
|
||||
<div style="padding: 24px 0;">
|
||||
<div style="margin-bottom: 24px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">输入新手机号:</label>
|
||||
<a-select
|
||||
v-model:value="phoneForm.countryCode"
|
||||
style="width: 80px;"
|
||||
placeholder="+86"
|
||||
>
|
||||
<a-select-option value="+86">+86</a-select-option>
|
||||
<a-select-option value="+852">+852</a-select-option>
|
||||
<a-select-option value="+853">+853</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
v-model:value="phoneForm.newPhoneNumber"
|
||||
placeholder="请输入新手机号"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">手机验证码:</label>
|
||||
<a-input
|
||||
v-model:value="phoneForm.smsCode"
|
||||
placeholder="请输入验证码"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="isSending || countdown > 0"
|
||||
@click="sendSmsCode('phone')"
|
||||
style="width: 120px;"
|
||||
>
|
||||
{{ isSending || countdown > 0 ? `${countdown}s后重发` : '发送验证码' }}
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<span style="color: red;">*</span>
|
||||
<label style="font-size: 14px; color: #333;">输入账号密码:</label>
|
||||
<a-input
|
||||
v-model:value="phoneForm.password"
|
||||
placeholder="请输入账号登录密码"
|
||||
type="password"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: right; padding: 16px 24px;">
|
||||
<a-button @click="closeEditPhoneModal" style="margin-right: 8px;">取消</a-button>
|
||||
<a-button type="primary" @click="savePhone">确定</a-button>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.account-security {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
|
||||
@ -11,25 +11,26 @@
|
||||
<div class="user-info">
|
||||
<a-dropdown>
|
||||
<div style="display: flex;align-items: center;justify-content: flex-end;">
|
||||
<a-avatar :size="24" :src="avatar">
|
||||
<a-avatar :size="24" :src="userInfo.avatar">
|
||||
<!-- <template #icon>
|
||||
<UserOutlined />
|
||||
</template> -->
|
||||
</a-avatar>
|
||||
<span style="font-size: 14px;padding-left:5px;">管理员</span>
|
||||
<span style="font-size: 14px;padding-left:5px;">{{ userInfo.userName }}</span>
|
||||
</div>
|
||||
|
||||
<template #overlay>
|
||||
<a-card hoverable style="width: 300px">
|
||||
<template #cover>
|
||||
<div style="background:#f5f7fa;padding:10px;line-height: 30px">
|
||||
<div>管理员<a-tag style="margin-left: 10px;" color="red">未实名</a-tag></div>
|
||||
<div>ID:23455522</div>
|
||||
<div>{{ userInfo.userName }} <a-tag color="blue" style="margin-left: 10px;">{{ userInfo.accountType==='USER'?'个人认证':'企业认证' }}</a-tag></div>
|
||||
<div>ID:{{ userInfo.id }}</div>
|
||||
</div>
|
||||
<div style="padding: 10px;line-height: 45px;">
|
||||
<div style="display: flex;justify-content: space-between;align-items: center;"><div>可用余额:¥200.00</div> <a-button type="primary" danger ghost size="small">去充值</a-button></div>
|
||||
<div>冻结余额:¥100.00</div>
|
||||
<div>代金劵:¥100.00</div>
|
||||
<div>实例数量:¥{{ userInfo.caseNum }}</div>
|
||||
<div>冻结余额:¥{{ userInfo.freezeBalace }}</div>
|
||||
<div>未冻结余额:¥{{ userInfo.noFreezeBalace }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions>
|
||||
@ -56,6 +57,7 @@ import avatar from '@/assets/avator.png'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const isHome = ref(true)
|
||||
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
|
||||
// 根据当前路由初始化菜单选中项(去掉 /layout 前缀)
|
||||
const getActiveKeyFromRoute = () => {
|
||||
const path = route.path
|
||||
@ -100,6 +102,7 @@ const handleMenuClick = (key) => {
|
||||
}
|
||||
}
|
||||
const logout = () => {
|
||||
localStorage.clear()
|
||||
router.replace('/login')
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, shallowRef } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { login } from '@/apis/login';
|
||||
import { login, fetchUserInfo } from '@/apis/login';
|
||||
import { message, type FormInstance } from 'ant-design-vue';
|
||||
|
||||
const router = useRouter();
|
||||
@ -55,7 +55,7 @@ const onFinish = async (values: FormState) => {
|
||||
|
||||
const loginData = {
|
||||
...values,
|
||||
login_method: 'SMS'
|
||||
login_method: 'PWD'//PWD表示密码登录,SMS表示短信验证码登录
|
||||
};
|
||||
formRef.value?.validateFields().then(async () => {
|
||||
try {
|
||||
@ -67,6 +67,8 @@ const onFinish = async (values: FormState) => {
|
||||
throw new Error('登录失败:未返回有效凭证');
|
||||
}
|
||||
localStorage.setItem('token', token);
|
||||
const userRes=await fetchUserInfo();
|
||||
localStorage.setItem('userInfo', JSON.stringify(userRes));
|
||||
router.push('/layout/home');
|
||||
} catch (error: any) {
|
||||
console.error('登录请求失败:', error);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user