数据填报首页
This commit is contained in:
commit
37ff31c231
1170
frontend-process/package-lock.json
generated
Normal file
1170
frontend-process/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
frontend/src/assets/components/bg_sjtb.png
Normal file
BIN
frontend/src/assets/components/bg_sjtb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
frontend/src/assets/images/bg_sjtb.png
Normal file
BIN
frontend/src/assets/images/bg_sjtb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
@ -14,6 +14,7 @@ import { useTagsViewStore } from "@/store/modules/tagsView";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import Cookies from "js-cookie";
|
||||
import { storeToRefs } from "pinia";
|
||||
import {getPath,removePath } from '@/utils/auth';
|
||||
|
||||
const url = import.meta.env.VITE_APP_BASE_API;
|
||||
const username = Cookies.get("username");
|
||||
@ -35,7 +36,9 @@ function logout() {
|
||||
tagsViewStore.delAllViews();
|
||||
})
|
||||
.then(() => {
|
||||
router.push(`/login?redirect=${route.fullPath}`);
|
||||
// router.push(`/login?redirect=${route.fullPath}`);
|
||||
router.push(`${getPath()}?redirect=${route.fullPath}`);
|
||||
removePath()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import router from '@/router';
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { usePermissionStoreHook } from '@/store/modules/permission';
|
||||
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
NProgress.configure({ showSpinner: false });
|
||||
@ -10,20 +9,20 @@ NProgress.configure({ showSpinner: false });
|
||||
const permissionStore = usePermissionStoreHook();
|
||||
|
||||
// 白名单路由
|
||||
const whiteList = ['/login'];
|
||||
const whiteList = ['/login', '/login-sjtb']; //login
|
||||
|
||||
// 查找第一个可用路由
|
||||
function findFirstAvailableRoute(routes: RouteRecordRaw[]): string | undefined {
|
||||
for (const route of routes) {
|
||||
if (route.meta?.hidden) continue;
|
||||
|
||||
|
||||
if (route.children?.length > 0) {
|
||||
const child = route.children[0];
|
||||
// 优先使用 opturl 或 path
|
||||
const targetPath = child.opturl || child.path;
|
||||
return targetPath?.startsWith('/') ? targetPath : `/${targetPath}`;
|
||||
}
|
||||
|
||||
|
||||
const targetPath = route.opturl || route.path;
|
||||
return targetPath;
|
||||
}
|
||||
@ -33,15 +32,15 @@ function findFirstAvailableRoute(routes: RouteRecordRaw[]): string | undefined {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
const userStore = useUserStoreHook();
|
||||
|
||||
|
||||
if (userStore.Token) {
|
||||
// 登录成功,跳转到首页
|
||||
if (to.path === '/login') {
|
||||
if (to.path === '/login-sjtb' || to.path === '/login') {//login
|
||||
next({ path: '/' });
|
||||
NProgress.done();
|
||||
} else {
|
||||
|
||||
const hasGetUserInfo = userStore.roles.length > 0;
|
||||
|
||||
if (hasGetUserInfo) {
|
||||
// 已获取用户信息,检查路由匹配
|
||||
if (to.matched.length === 0) {
|
||||
@ -62,11 +61,11 @@ router.beforeEach(async (to, from, next) => {
|
||||
try {
|
||||
const { roles } = await userStore.getInfo();
|
||||
const accessRoutes: RouteRecordRaw[] = await permissionStore.generateRoutes(roles);
|
||||
|
||||
|
||||
accessRoutes.forEach((route: any) => {
|
||||
router.addRoute(route);
|
||||
});
|
||||
|
||||
|
||||
// 关键:如果是根路径,加载完路由后跳转到第一个可用路由
|
||||
if (to.path === '/') {
|
||||
const firstRoute = findFirstAvailableRoute(accessRoutes);
|
||||
@ -76,22 +75,23 @@ router.beforeEach(async (to, from, next) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
next({ ...to, replace: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
await userStore.resetToken();
|
||||
next(`/login?redirect=${to.path}`);
|
||||
to.path === '/login-sjtb' ? next(`/login-sjtb?redirect=${to.path}`) : next(`/login?redirect=${to.path}`);
|
||||
NProgress.done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 未登录可以访问白名单页面
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
next();
|
||||
} else {
|
||||
next(`/login?redirect=${to.path}`);
|
||||
to.path === '/login-sjtb' ? next(`/login-sjtb?redirect=${to.path}`) : next(`/login?redirect=${to.path}`);
|
||||
NProgress.done();
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,11 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
path: '/login',
|
||||
component: () => import('@/views/login/index.vue'),
|
||||
meta: { hidden: true }
|
||||
},
|
||||
{
|
||||
path: '/login-sjtb',
|
||||
component: () => import('@/views/login-sjtb/index.vue'),
|
||||
meta: { hidden: true }
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
const TokenKey = 'token';
|
||||
|
||||
const PathKey = 'path';
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey);
|
||||
}
|
||||
@ -13,3 +13,12 @@ export function setToken(token: any) {
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey);
|
||||
}
|
||||
export function setPath(path:any) {
|
||||
Cookies.set(PathKey,path);
|
||||
}
|
||||
export function getPath() {
|
||||
return Cookies.get(PathKey);
|
||||
}
|
||||
export function removePath() {
|
||||
return Cookies.remove(PathKey);
|
||||
}
|
||||
724
frontend/src/views/login-sjtb/index.vue
Normal file
724
frontend/src/views/login-sjtb/index.vue
Normal file
@ -0,0 +1,724 @@
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<!-- <h1>
|
||||
<div>
|
||||
<img :src="loginImg" alt="Logo" class="logo-img" />
|
||||
<a class="system-title">{{ $t("login.title") }}</a>
|
||||
</div>
|
||||
</h1> -->
|
||||
<div class="login-wrapper">
|
||||
<!-- 左侧:背景图区域 -->
|
||||
<div class="left-section">
|
||||
<div class="slogan">
|
||||
<p>采集网站及数据管理子系统</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:登录表单区域 -->
|
||||
<div class="right-section">
|
||||
<!-- 忘记密码页面 -->
|
||||
<div v-if="showForgotPassword" class="forgot-password-container">
|
||||
<div class="forgot-password-header">
|
||||
<a-button type="link" @click="backToLogin" class="back-button">
|
||||
<span>← 返回</span>
|
||||
</a-button>
|
||||
<!-- <h3 class="forgot-password-title">忘记密码</h3> -->
|
||||
</div>
|
||||
|
||||
<a-form
|
||||
:model="forgotPasswordForm"
|
||||
:rules="forgotPasswordRules"
|
||||
layout="vertical"
|
||||
class="form-container"
|
||||
>
|
||||
<a-form-item label="" name="phone">
|
||||
<a-input placeholder="请输入手机号" size="large">
|
||||
<template #prefix>
|
||||
<MobileOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="" name="captcha">
|
||||
<div class="captcha-row">
|
||||
<a-input
|
||||
v-model="forgotPasswordForm.captcha"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<a-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="sendForgotPasswordSms"
|
||||
:disabled="smsButtonDisabled"
|
||||
:loading="loading"
|
||||
>
|
||||
{{
|
||||
smsCountdown > 0 ? `${smsCountdown}秒后重新获取` : "获取验证码"
|
||||
}}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="" name="newPassword">
|
||||
<a-input-password
|
||||
v-model="forgotPasswordForm.newPassword"
|
||||
placeholder="请输入新密码"
|
||||
size="large"
|
||||
>
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
</template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
|
||||
<a-button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
@click="handleResetPassword"
|
||||
:loading="loading"
|
||||
>
|
||||
<span>提交</span>
|
||||
</a-button>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<!-- 登录页面 -->
|
||||
<div v-else>
|
||||
<!-- Tabs 切换:账号登录 / 短信登录 -->
|
||||
<a-tabs v-model:activeKey="activeTab" class="login-tabs">
|
||||
<a-tab-pane key="account" tab="账号登录">
|
||||
<a-form
|
||||
:model="loginData"
|
||||
:rules="loginRules"
|
||||
layout="vertical"
|
||||
class="form-container"
|
||||
@finish="onFinish"
|
||||
>
|
||||
<!-- 用户名/账号/手机号输入框 -->
|
||||
<a-form-item label="" name="username">
|
||||
<a-input
|
||||
ref="username"
|
||||
v-model:value="loginData.username"
|
||||
clearable
|
||||
type="text"
|
||||
placeholder="请输入用户账号/身份证号/手机号"
|
||||
size="large"
|
||||
>
|
||||
<template #prefix>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<a-form-item label="" name="password">
|
||||
<a-input-password
|
||||
type="password"
|
||||
v-model:value="loginData.password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
>
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
</template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
<!-- 验证码区域 -->
|
||||
<a-form-item label="" name="captcha">
|
||||
<div class="captcha-row">
|
||||
<a-row :gutter="24" align="middle">
|
||||
<a-col :span="10"
|
||||
><a-input
|
||||
v-model:value="loginData.code"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
/></a-col>
|
||||
<a-col :span="10"
|
||||
><img :src="codeUrl" alt="验证码" class="captcha-img"
|
||||
/></a-col>
|
||||
<a-col :span="4"> <a @click="getCode">换一张</a></a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
htmlType="submit"
|
||||
:loading="loading"
|
||||
>
|
||||
<span>登录</span>
|
||||
</a-button>
|
||||
<!-- <a-button
|
||||
type="link"
|
||||
size="mini"
|
||||
block
|
||||
@click="showForgotPasswordPage"
|
||||
:style="{ marginTop: '10px', border: 'none' }"
|
||||
>
|
||||
忘记密码
|
||||
</a-button> -->
|
||||
|
||||
<!-- 忘记密码 -->
|
||||
</a-form>
|
||||
</a-tab-pane>
|
||||
|
||||
<!-- 短信登录 Tab (占位) -->
|
||||
<!-- <a-tab-pane key="sms" tab="短信登录">
|
||||
<a-form
|
||||
:model="loginData"
|
||||
:rules="loginRules"
|
||||
layout="vertical"
|
||||
class="form-container"
|
||||
>
|
||||
<a-form-item label="" name="username">
|
||||
<a-input
|
||||
v-model:value="loginData.username"
|
||||
placeholder="请输入手机号"
|
||||
size="large"
|
||||
>
|
||||
<template #prefix>
|
||||
<MobileOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="" name="captcha">
|
||||
<div class="captcha-row">
|
||||
<a-input
|
||||
v-model="loginData.code"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<a-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="sendSms"
|
||||
:disabled="smsButtonDisabled"
|
||||
:loading="loading"
|
||||
>
|
||||
{{
|
||||
smsCountdown > 0
|
||||
? `${smsCountdown}秒后重新获取`
|
||||
: "获取验证码"
|
||||
}}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
htmlType="submit"
|
||||
:loading="loading"
|
||||
>
|
||||
<span>登录</span>
|
||||
</a-button>
|
||||
</a-form>
|
||||
</a-tab-pane> -->
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs, watch, nextTick } from "vue";
|
||||
import loginImg from "@/assets/images/logo.png";
|
||||
import { UserOutlined, LockOutlined, MobileOutlined } from "@ant-design/icons-vue";
|
||||
import { getCaptcha } from "@/api/auth";
|
||||
import { message } from "ant-design-vue";
|
||||
import { setPath } from '@/utils/auth';
|
||||
// 组件依赖
|
||||
|
||||
import router from "@/router";
|
||||
import Cookies from "js-cookie";
|
||||
// API依赖
|
||||
import { useRoute } from "vue-router";
|
||||
import { LoginData } from "@/api/auth/types";
|
||||
|
||||
//密码加密
|
||||
import { encrypt, decrypt } from "@/utils/rsaEncrypt";
|
||||
|
||||
// 状态管理依赖
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
// 国际化
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const route = useRoute();
|
||||
// 图片验证码
|
||||
const codeUrl = ref("");
|
||||
|
||||
const smsCountdown = ref(0); // 短信验证码倒计时
|
||||
const smsButtonDisabled = ref(false); // 短信按钮禁用状态
|
||||
// 记住密码
|
||||
let remember = ref(false);
|
||||
|
||||
// 忘记密码表单数据
|
||||
const forgotPasswordForm = ref({
|
||||
phone: "",
|
||||
captcha: "",
|
||||
newPassword: "",
|
||||
});
|
||||
// 忘记密码
|
||||
const showForgotPassword = ref(false);
|
||||
// 登录方式
|
||||
const activeTab = ref("account");
|
||||
|
||||
const state = reactive({
|
||||
redirect: "",
|
||||
loginData: {
|
||||
uuid: "",
|
||||
username: "admin",
|
||||
password: "123456",
|
||||
code: "",
|
||||
} as LoginData,
|
||||
loginRules: {
|
||||
username: [{ required: true, trigger: "blur", message: t("login.rulesUsername") }],
|
||||
password: [{ required: true, trigger: "blur", message: t("login.rulesPassword") }],
|
||||
code: [{ required: true, trigger: "blur", message: "请输入验证码" }],
|
||||
},
|
||||
loginImg: loginImg[0],
|
||||
loading: false,
|
||||
passwordType: "password",
|
||||
// 大写提示禁用
|
||||
capslockTooltipDisabled: true,
|
||||
otherQuery: {},
|
||||
clientHeight: document.documentElement.clientHeight,
|
||||
showDialog: false,
|
||||
|
||||
cookiePass: "",
|
||||
});
|
||||
|
||||
// 忘记密码表单校验规则
|
||||
const forgotPasswordRules = ref({
|
||||
phone: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号", trigger: "blur" },
|
||||
],
|
||||
captcha: [{ required: true, message: "验证码不能为空", trigger: "blur" }],
|
||||
newPassword: [
|
||||
{ required: true, message: "新密码不能为空", trigger: "blur" },
|
||||
{ min: 6, message: "密码长度不能少于6位", trigger: "blur" },
|
||||
],
|
||||
});
|
||||
|
||||
const { loginData, loginRules, loading, passwordType, capslockTooltipDisabled } = toRefs(
|
||||
state
|
||||
);
|
||||
|
||||
function checkCapslock(e: any) {
|
||||
const { key } = e;
|
||||
state.capslockTooltipDisabled = key && key.length === 1 && key >= "A" && key <= "Z";
|
||||
}
|
||||
|
||||
function showPwd() {
|
||||
if (passwordType.value === "password") {
|
||||
passwordType.value = "";
|
||||
} else {
|
||||
passwordType.value = "password";
|
||||
}
|
||||
nextTick(() => {
|
||||
passwordRef.value.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
function onFinish() {
|
||||
state.loading = true;
|
||||
const user = {
|
||||
username: state.loginData.username,
|
||||
password: state.loginData.password,
|
||||
// rememberMe: state.loginData.rememberMe,
|
||||
code: state.loginData.code,
|
||||
uuid: state.loginData.uuid,
|
||||
};
|
||||
if (user.password !== state.cookiePass) {
|
||||
user.password = encrypt(user.password);
|
||||
}
|
||||
console.log(user);
|
||||
userStore
|
||||
.login(user)
|
||||
.then(() => {
|
||||
Cookies.set("username", user.username);
|
||||
setPath('/login-sjtb')
|
||||
router.push({ path: "/" });
|
||||
state.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
getCode();
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
route,
|
||||
() => {
|
||||
const query = route.query;
|
||||
if (query) {
|
||||
state.redirect = query.redirect as string;
|
||||
state.otherQuery = getOtherQuery(query);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
function getOtherQuery(query: any) {
|
||||
return Object.keys(query).reduce((acc: any, cur: any) => {
|
||||
if (cur !== "redirect") {
|
||||
acc[cur] = query[cur];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
function getCookie() {
|
||||
const username = Cookies.get("username");
|
||||
let password = Cookies.get("password");
|
||||
const rememberMe = Cookies.get("rememberMe");
|
||||
rememberMe == "true" ? (remember.value = Boolean(rememberMe)) : false;
|
||||
// 保存cookie里面的加密后的密码
|
||||
state.cookiePass = password === undefined ? "" : password;
|
||||
password = password === undefined ? state.loginData.password : password;
|
||||
state.loginData = {
|
||||
username: username === undefined ? state.loginData.username : username,
|
||||
password: decrypt(password),
|
||||
code: "",
|
||||
uuid: "",
|
||||
};
|
||||
remember.value = rememberMe === undefined ? false : Boolean(rememberMe);
|
||||
}
|
||||
function getCode() {
|
||||
getCaptcha().then((result: any) => {
|
||||
codeUrl.value = result.data.img;
|
||||
state.loginData.uuid = result.data.uuid;
|
||||
});
|
||||
}
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
smsCountdown.value = 60;
|
||||
|
||||
const timer = setInterval(() => {
|
||||
smsCountdown.value--;
|
||||
|
||||
if (smsCountdown.value <= 0) {
|
||||
clearInterval(timer);
|
||||
smsButtonDisabled.value = false;
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// 显示忘记密码页面
|
||||
const showForgotPasswordPage = () => {
|
||||
showForgotPassword.value = true;
|
||||
};
|
||||
|
||||
// 返回登录页面
|
||||
const backToLogin = () => {
|
||||
showForgotPassword.value = false;
|
||||
// 重置忘记密码表单
|
||||
forgotPasswordForm.value = {
|
||||
phone: "",
|
||||
captcha: "",
|
||||
newPassword: "",
|
||||
};
|
||||
};
|
||||
|
||||
// 发送短信验证码
|
||||
const sendSms = async () => {
|
||||
// 检查手机号是否为空
|
||||
if (!loginData.value.username) {
|
||||
message.error("请输入手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(loginData.value.username)) {
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果正在倒计时,不允许重复发送
|
||||
if (smsCountdown.value > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
smsButtonDisabled.value = true;
|
||||
|
||||
try {
|
||||
// 模拟发送短信验证码接口
|
||||
// await axios.post('/sms/send', { phone: loginForm.value.username })
|
||||
|
||||
// 模拟发送成功
|
||||
message.success("验证码发送成功");
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown();
|
||||
} catch (error) {
|
||||
console.error("发送验证码失败", error);
|
||||
message.error("验证码发送失败,请重试");
|
||||
smsButtonDisabled.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
// 发送忘记密码短信验证码
|
||||
const sendForgotPasswordSms = async () => {
|
||||
// 检查手机号是否为空
|
||||
if (!forgotPasswordForm.value.phone) {
|
||||
message.error("请输入手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(forgotPasswordForm.value.phone)) {
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果正在倒计时,不允许重复发送
|
||||
if (smsCountdown.value > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
smsButtonDisabled.value = true;
|
||||
|
||||
try {
|
||||
// 模拟发送短信验证码接口
|
||||
// await axios.post('/sms/forgot-password', { phone: forgotPasswordForm.value.phone })
|
||||
|
||||
// 模拟发送成功
|
||||
message.success("验证码发送成功");
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown();
|
||||
} catch (error) {
|
||||
console.error("发送验证码失败", error);
|
||||
message.error("验证码发送失败,请重试");
|
||||
smsButtonDisabled.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
// 处理密码重置
|
||||
const handleResetPassword = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
// 2. 模拟接口请求 (实际替换为真实重置密码接口)
|
||||
// await axios.post('/user/reset-password', {
|
||||
// phone: forgotPasswordForm.value.phone,
|
||||
// captcha: forgotPasswordForm.value.captcha,
|
||||
// newPassword: forgotPasswordForm.value.newPassword
|
||||
// })
|
||||
|
||||
// 3. 模拟重置成功
|
||||
message.success("密码重置成功");
|
||||
|
||||
// 4. 返回登录页面
|
||||
backToLogin();
|
||||
} catch (error) {
|
||||
console.error("密码重置失败", error);
|
||||
message.error("密码重置失败,请重试");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getCookie();
|
||||
getCode();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.login-container {
|
||||
margin: 0px auto;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 1500px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
|
||||
h1 {
|
||||
position: relative;
|
||||
padding: 66px 0px 2px 80px;
|
||||
margin-bottom: 0px;
|
||||
height: 155px;
|
||||
|
||||
div {
|
||||
position: relative;
|
||||
line-height: 71px;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 10px;
|
||||
width: 55px;
|
||||
}
|
||||
|
||||
.system-title {
|
||||
margin-left: 71px;
|
||||
font-weight: 700;
|
||||
font-size: 35px;
|
||||
color: rgb(47, 107, 152);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-tab) {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
:deep(.ant-input-prefix) {
|
||||
display: flex;
|
||||
width: 26px;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 600px;
|
||||
background: url("@/assets/images/bg_sjtb.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
// 左侧背景区域
|
||||
.left-section {
|
||||
.slogan {
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
left: 18%;
|
||||
width: 490px;
|
||||
height: 112px;
|
||||
color: #040504;
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧登录卡片区域
|
||||
.right-section {
|
||||
position: absolute;
|
||||
left: 74%;
|
||||
top: 30%;
|
||||
width: 20%;
|
||||
max-height: 402px;
|
||||
max-width: 400px;
|
||||
min-height: 362px;
|
||||
border-radius: 3px;
|
||||
padding: 15px 24px 24px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
|
||||
.ant-tabs-nav {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 验证码布局 */
|
||||
.captcha-row {
|
||||
display: flex;
|
||||
.ant-row {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
}
|
||||
/* gap: 12px;
|
||||
align-items: center; */
|
||||
|
||||
.captcha-img {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
a {
|
||||
line-height: 50px;
|
||||
float: right;
|
||||
color: #1890ff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
// 忘记密码样式
|
||||
.forgot-link {
|
||||
float: right;
|
||||
color: #1677ff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
// 短信登录占位提示
|
||||
.sms-login-tip {
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
// 忘记密码页面样式
|
||||
.forgot-password-container {
|
||||
.forgot-password-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.back-button {
|
||||
padding: 0;
|
||||
margin-right: 12px;
|
||||
color: #1677ff;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
color: #4096ff;
|
||||
}
|
||||
}
|
||||
|
||||
.forgot-password-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -240,6 +240,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { setPath } from '@/utils/auth';
|
||||
import { onMounted, reactive, ref, toRefs, watch, nextTick } from "vue";
|
||||
import loginImg from "@/assets/images/logo.png";
|
||||
import { UserOutlined, LockOutlined, MobileOutlined } from "@ant-design/icons-vue";
|
||||
@ -362,6 +363,7 @@ function onFinish() {
|
||||
.then(() => {
|
||||
Cookies.set("username", user.username);
|
||||
router.push({ path: "/" });
|
||||
setPath('/login')
|
||||
state.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "WholeProcessPlatform",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user