修改问题
This commit is contained in:
parent
264a10931b
commit
78eb7f9b87
@ -10,7 +10,7 @@
|
||||
<!-- 左侧:背景图区域 -->
|
||||
<div class="left-section">
|
||||
<div class="slogan">
|
||||
<p>{{ $t('login.titleSjtb') }}</p>
|
||||
<p>{{ $t("login.titleSjtb") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,6 +49,7 @@
|
||||
v-model:value="forgotPasswordForm.captcha"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
autocomplete="current-captcha"
|
||||
class="captcha-input"
|
||||
>
|
||||
<template #prefix>
|
||||
@ -63,9 +64,7 @@
|
||||
:loading="loading"
|
||||
>
|
||||
{{
|
||||
smsCountdown > 0
|
||||
? `${smsCountdown}秒后重新获取`
|
||||
: '获取验证码'
|
||||
smsCountdown > 0 ? `${smsCountdown}秒后重新获取` : "获取验证码"
|
||||
}}
|
||||
</a-button>
|
||||
</template>
|
||||
@ -76,6 +75,7 @@
|
||||
<a-form-item label="" name="newPassword">
|
||||
<a-input-password
|
||||
v-model:value="forgotPasswordForm.newPassword"
|
||||
autocomplete="current-password"
|
||||
placeholder="请输入新密码"
|
||||
size="large"
|
||||
>
|
||||
@ -88,6 +88,7 @@
|
||||
<a-form-item label="" name="confirmPassword">
|
||||
<a-input-password
|
||||
v-model:value="forgotPasswordForm.confirmPassword"
|
||||
autocomplete="current-confirmPassword"
|
||||
placeholder="请再次输入密码"
|
||||
size="large"
|
||||
>
|
||||
@ -130,6 +131,7 @@
|
||||
type="text"
|
||||
placeholder="请输入用户账号/手机号"
|
||||
size="large"
|
||||
autocomplete="current-username"
|
||||
>
|
||||
<template #prefix>
|
||||
<UserOutlined />
|
||||
@ -144,6 +146,7 @@
|
||||
v-model:value="loginData.password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
autocomplete="current-password"
|
||||
>
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
@ -158,6 +161,7 @@
|
||||
><a-input
|
||||
v-model:value="loginData.code"
|
||||
placeholder="请输入验证码"
|
||||
autocomplete="current-captcha"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
/></a-col>
|
||||
@ -185,9 +189,7 @@
|
||||
justify-content: space-between;
|
||||
"
|
||||
>
|
||||
<a-checkbox
|
||||
v-model:checked="remember"
|
||||
style="margin-top: 10px"
|
||||
<a-checkbox v-model:checked="remember" style="margin-top: 10px"
|
||||
>记住密码</a-checkbox
|
||||
>
|
||||
<a-button
|
||||
@ -254,7 +256,7 @@
|
||||
{{
|
||||
smsCountdown > 0
|
||||
? `${smsCountdown}秒后重新获取`
|
||||
: '获取验证码'
|
||||
: "获取验证码"
|
||||
}}
|
||||
</a-button>
|
||||
</template>
|
||||
@ -307,43 +309,34 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs, watch } from 'vue';
|
||||
import loginImg from '@/assets/images/logo.png';
|
||||
import {
|
||||
UserOutlined,
|
||||
LockOutlined,
|
||||
MobileOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import {
|
||||
getCaptcha,
|
||||
sendSmsCode,
|
||||
smsLoginApi,
|
||||
resetPassword
|
||||
} from '@/api/auth';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { setToken } from '@/utils/auth';
|
||||
import Cookies from 'js-cookie';
|
||||
import { onMounted, reactive, ref, toRefs, watch } from "vue";
|
||||
import loginImg from "@/assets/images/logo.png";
|
||||
import { UserOutlined, LockOutlined, MobileOutlined } from "@ant-design/icons-vue";
|
||||
import { getCaptcha, sendSmsCode, smsLoginApi, resetPassword } from "@/api/auth";
|
||||
import { message } from "ant-design-vue";
|
||||
import { setToken } from "@/utils/auth";
|
||||
import Cookies from "js-cookie";
|
||||
// 组件依赖
|
||||
|
||||
import router from '@/router';
|
||||
import router from "@/router";
|
||||
// API依赖
|
||||
import { useRoute } from 'vue-router';
|
||||
import { LoginData } from '@/api/auth/types';
|
||||
import { useRoute } from "vue-router";
|
||||
import { LoginData } from "@/api/auth/types";
|
||||
|
||||
//密码加密
|
||||
import { encrypt, decrypt } from '@/utils/rsaEncrypt';
|
||||
import { encrypt, decrypt } from "@/utils/rsaEncrypt";
|
||||
|
||||
// 状态管理依赖
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { usePermissionStoreHook } from '@/store/modules/permission';
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
|
||||
// 国际化
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const route = useRoute();
|
||||
// 图片验证码
|
||||
const codeUrl = ref('');
|
||||
const codeUrl = ref("");
|
||||
|
||||
const smsCountdown = ref(0); // 短信验证码倒计时
|
||||
const smsButtonDisabled = ref(false); // 短信按钮禁用状态
|
||||
@ -352,59 +345,55 @@ let remember = ref(false);
|
||||
|
||||
// 忘记密码表单数据
|
||||
const forgotPasswordForm = ref({
|
||||
phone: '',
|
||||
captcha: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
phone: "",
|
||||
captcha: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
// 忘记密码
|
||||
const showForgotPassword = ref(false);
|
||||
// 登录方式
|
||||
const activeTab = ref('account');
|
||||
const activeTab = ref("account");
|
||||
|
||||
const state = reactive({
|
||||
redirect: '',
|
||||
redirect: "",
|
||||
loginData: {
|
||||
uuid: '',
|
||||
username: '',
|
||||
password: '',
|
||||
code: ''
|
||||
uuid: "",
|
||||
username: "",
|
||||
password: "",
|
||||
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: '请输入验证码' }]
|
||||
username: [{ required: true, trigger: "blur", message: t("login.rulesUsername") }],
|
||||
password: [{ required: true, trigger: "blur", message: t("login.rulesPassword") }],
|
||||
code: [{ required: true, trigger: "blur", message: "请输入验证码" }],
|
||||
},
|
||||
smsLoginRules: {
|
||||
username: [{ required: true, trigger: 'blur', message: '请输入手机号' }],
|
||||
code: [{ required: true, trigger: 'blur', message: '请输入验证码' }]
|
||||
username: [{ required: true, trigger: "blur", message: "请输入手机号" }],
|
||||
code: [{ required: true, trigger: "blur", message: "请输入验证码" }],
|
||||
},
|
||||
loginImg: loginImg[0],
|
||||
loading: false,
|
||||
passwordType: 'password',
|
||||
passwordType: "password",
|
||||
// 大写提示禁用
|
||||
capslockTooltipDisabled: true,
|
||||
otherQuery: {},
|
||||
clientHeight: document.documentElement.clientHeight,
|
||||
showDialog: false,
|
||||
|
||||
cookiePass: ''
|
||||
cookiePass: "",
|
||||
});
|
||||
|
||||
// 忘记密码表单校验规则
|
||||
const forgotPasswordRules = ref({
|
||||
phone: [
|
||||
{ required: true, message: '手机号不能为空', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号", trigger: "blur" },
|
||||
],
|
||||
captcha: [{ required: true, message: '验证码不能为空', trigger: 'blur' }],
|
||||
captcha: [{ required: true, message: "验证码不能为空", trigger: "blur" }],
|
||||
newPassword: [
|
||||
{ required: true, message: '新密码不能为空', trigger: 'blur' },
|
||||
{ min: 10, message: '密码长度不能少于10位', trigger: 'blur' },
|
||||
{ required: true, message: "新密码不能为空", trigger: "blur" },
|
||||
{ min: 10, message: "密码长度不能少于10位", trigger: "blur" },
|
||||
{
|
||||
validator: (rule: any, value: string) => {
|
||||
if (!value) return Promise.resolve();
|
||||
@ -413,28 +402,21 @@ const forgotPasswordRules = ref({
|
||||
const hasUpperCase = /[A-Z]/.test(value);
|
||||
const hasLowerCase = /[a-z]/.test(value);
|
||||
const hasNumber = /\d/.test(value);
|
||||
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
|
||||
value
|
||||
);
|
||||
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value);
|
||||
|
||||
const typeCount = [
|
||||
hasUpperCase,
|
||||
hasLowerCase,
|
||||
hasNumber,
|
||||
hasSpecialChar
|
||||
].filter(Boolean).length;
|
||||
const typeCount = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(
|
||||
Boolean
|
||||
).length;
|
||||
|
||||
if (typeCount < 3) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种'
|
||||
)
|
||||
new Error("密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种")
|
||||
);
|
||||
}
|
||||
|
||||
// 检查连续重复字符
|
||||
if (/(.)\1{1,}/.test(value)) {
|
||||
return Promise.reject(new Error('密码不能包含连续重复字符'));
|
||||
return Promise.reject(new Error("密码不能包含连续重复字符"));
|
||||
}
|
||||
|
||||
// 检查连续递增/递减数字
|
||||
@ -442,9 +424,7 @@ const forgotPasswordRules = ref({
|
||||
if (/\d/.test(value[i]) && /\d/.test(value[i + 1])) {
|
||||
const diff = value.charCodeAt(i + 1) - value.charCodeAt(i);
|
||||
if (Math.abs(diff) === 1) {
|
||||
return Promise.reject(
|
||||
new Error('密码不能包含连续递增或递减的数字')
|
||||
);
|
||||
return Promise.reject(new Error("密码不能包含连续递增或递减的数字"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -454,39 +434,37 @@ const forgotPasswordRules = ref({
|
||||
if (/[a-zA-Z]/.test(value[i]) && /[a-zA-Z]/.test(value[i + 1])) {
|
||||
const diff = value.charCodeAt(i + 1) - value.charCodeAt(i);
|
||||
if (Math.abs(diff) === 1) {
|
||||
return Promise.reject(
|
||||
new Error('密码不能包含连续递增或递减的字母')
|
||||
);
|
||||
return Promise.reject(new Error("密码不能包含连续递增或递减的字母"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
confirmPassword: [
|
||||
// { required: true, message: "请再次输入密码", trigger: "blur" },
|
||||
{
|
||||
validator: (rule: any, value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject(new Error('请再次输入密码'));
|
||||
return Promise.reject(new Error("请再次输入密码"));
|
||||
}
|
||||
if (value !== forgotPasswordForm.value.newPassword) {
|
||||
return Promise.reject(new Error('两次输入的密码不一致'));
|
||||
return Promise.reject(new Error("两次输入的密码不一致"));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const {
|
||||
loginData,
|
||||
loginRules,
|
||||
loading
|
||||
loading,
|
||||
// passwordType, capslockTooltipDisabled
|
||||
} = toRefs(state);
|
||||
|
||||
@ -516,7 +494,7 @@ function onFinish() {
|
||||
password: state.loginData.password,
|
||||
// rememberMe: state.loginData.rememberMe,
|
||||
code: state.loginData.code,
|
||||
uuid: state.loginData.uuid
|
||||
uuid: state.loginData.uuid,
|
||||
};
|
||||
if (user.password !== state.cookiePass) {
|
||||
user.password = encrypt(user.password);
|
||||
@ -525,18 +503,18 @@ function onFinish() {
|
||||
.login(user)
|
||||
.then(() => {
|
||||
if (remember.value == true) {
|
||||
Cookies.set('username', user.username, { expires: 30 });
|
||||
Cookies.set('password', user.password, { expires: 30 });
|
||||
Cookies.set('rememberMe', String(remember.value), { expires: 30 });
|
||||
Cookies.set("username", user.username, { expires: 30 });
|
||||
Cookies.set("password", user.password, { expires: 30 });
|
||||
Cookies.set("rememberMe", String(remember.value), { expires: 30 });
|
||||
} else {
|
||||
// 如果用户取消勾选记住密码,应该移除 cookie
|
||||
Cookies.remove('username');
|
||||
Cookies.remove('password');
|
||||
Cookies.remove('rememberMe');
|
||||
Cookies.remove("username");
|
||||
Cookies.remove("password");
|
||||
Cookies.remove("rememberMe");
|
||||
}
|
||||
router.push({ path: '/' });
|
||||
router.push({ path: "/" });
|
||||
state.loading = false;
|
||||
message.success('登录成功');
|
||||
message.success("登录成功");
|
||||
})
|
||||
.catch(() => {
|
||||
getCode();
|
||||
@ -551,16 +529,13 @@ const onSmsLogin = async () => {
|
||||
try {
|
||||
// ========== 第一部分:表单验证 ==========
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (
|
||||
!loginData.value.username ||
|
||||
!phoneRegex.test(loginData.value.username)
|
||||
) {
|
||||
message.error('请输入正确的手机号');
|
||||
if (!loginData.value.username || !phoneRegex.test(loginData.value.username)) {
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loginData.value.code || loginData.value.code.trim() === '') {
|
||||
message.error('请输入验证码');
|
||||
if (!loginData.value.code || loginData.value.code.trim() === "") {
|
||||
message.error("请输入验证码");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -568,53 +543,53 @@ const onSmsLogin = async () => {
|
||||
state.loading = true;
|
||||
|
||||
// ========== 第三部分:调用短信登录 API ==========
|
||||
console.log('开始调用短信登录API, 手机号:', loginData.value.username);
|
||||
console.log("开始调用短信登录API, 手机号:", loginData.value.username);
|
||||
const res: any = await smsLoginApi(
|
||||
loginData.value.username, // 手机号
|
||||
loginData.value.code // 短信验证码
|
||||
);
|
||||
console.log('短信登录API响应:', res);
|
||||
console.log("短信登录API响应:", res);
|
||||
|
||||
// ========== 第四部分:检查响应结果 ==========
|
||||
console.log('检查响应结果, res.code:', res.code, '类型:', typeof res.code);
|
||||
console.log("检查响应结果, res.code:", res.code, "类型:", typeof res.code);
|
||||
|
||||
// 注意:code 可能是字符串 "0" 或数字 0,需要兼容处理
|
||||
if (res.code !== 0 && res.code !== '0') {
|
||||
console.error('短信登录失败, 错误码:', res.code, '错误信息:', res.msg);
|
||||
message.error(res.msg || '登录失败');
|
||||
if (res.code !== 0 && res.code !== "0") {
|
||||
console.error("短信登录失败, 错误码:", res.code, "错误信息:", res.msg);
|
||||
message.error(res.msg || "登录失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== 第五部分:提取并存储 Token ==========
|
||||
console.log('开始提取Token, res.data:', res.data);
|
||||
console.log("开始提取Token, res.data:", res.data);
|
||||
const token = res.data?.token || res.data; // 兼容两种结构
|
||||
|
||||
if (!token) {
|
||||
console.error('Token为空, res.data结构:', JSON.stringify(res.data));
|
||||
message.error('登录失败:未获取到Token');
|
||||
console.error("Token为空, res.data结构:", JSON.stringify(res.data));
|
||||
message.error("登录失败:未获取到Token");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Token获取成功:', token);
|
||||
console.log("Token获取成功:", token);
|
||||
// 存储到 Cookie
|
||||
setToken(token);
|
||||
|
||||
// 更新 Store 状态(注意是大写 Token)
|
||||
userStore.Token = token;
|
||||
console.log('Token已存储到Store');
|
||||
console.log("Token已存储到Store");
|
||||
|
||||
// ========== 第六部分:获取用户信息和角色 ==========
|
||||
console.log('开始获取用户信息...');
|
||||
console.log("开始获取用户信息...");
|
||||
const userInfo = await userStore.getInfo();
|
||||
console.log('用户信息获取成功:', userInfo);
|
||||
console.log("用户信息获取成功:", userInfo);
|
||||
const roles = userInfo.roles;
|
||||
console.log('用户角色:', roles);
|
||||
console.log("用户角色:", roles);
|
||||
|
||||
// ========== 第七部分:生成路由(获取菜单)==========
|
||||
console.log('开始生成路由...');
|
||||
console.log("开始生成路由...");
|
||||
const permissionStore = usePermissionStoreHook();
|
||||
const accessRoutes: any = await permissionStore.generateRoutes(roles);
|
||||
console.log('路由生成成功, 路由数量:', accessRoutes.length);
|
||||
console.log("路由生成成功, 路由数量:", accessRoutes.length);
|
||||
|
||||
// ========== 第八部分:动态添加路由 ==========
|
||||
accessRoutes.forEach((route: any) => {
|
||||
@ -623,11 +598,11 @@ const onSmsLogin = async () => {
|
||||
|
||||
// ========== 第九部分:设置路径并跳转 ==========
|
||||
router.push({ path: accessRoutes[0].children[0].opturl });
|
||||
message.success('登录成功');
|
||||
message.success("登录成功");
|
||||
} catch (error: any) {
|
||||
// ========== 第十部分:错误处理 ==========
|
||||
console.error('短信登录失败', error);
|
||||
message.error(error.message || '登录失败,请重试');
|
||||
console.error("短信登录失败", error);
|
||||
message.error(error.message || "登录失败,请重试");
|
||||
} finally {
|
||||
// ========== 第十一部分:关闭加载状态 ==========
|
||||
state.loading = false;
|
||||
@ -644,31 +619,31 @@ watch(
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
function getOtherQuery(query: any) {
|
||||
return Object.keys(query).reduce((acc: any, cur: any) => {
|
||||
if (cur !== 'redirect') {
|
||||
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;
|
||||
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;
|
||||
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: ''
|
||||
code: "",
|
||||
uuid: "",
|
||||
};
|
||||
remember.value = rememberMe === undefined ? false : Boolean(rememberMe);
|
||||
}
|
||||
@ -699,17 +674,17 @@ const showForgotPasswordPage = () => {
|
||||
};
|
||||
//注册用户页面
|
||||
const goRegister = () => {
|
||||
router.push({ path: '/register' });
|
||||
router.push({ path: "/register" });
|
||||
};
|
||||
// 返回登录页面
|
||||
const backToLogin = () => {
|
||||
showForgotPassword.value = false;
|
||||
// 重置忘记密码表单
|
||||
forgotPasswordForm.value = {
|
||||
phone: '',
|
||||
captcha: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
phone: "",
|
||||
captcha: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
};
|
||||
|
||||
@ -717,14 +692,14 @@ const backToLogin = () => {
|
||||
const sendSms = async () => {
|
||||
// 检查手机号是否为空
|
||||
if (!loginData.value.username) {
|
||||
message.error('请输入手机号');
|
||||
message.error("请输入手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(loginData.value.username)) {
|
||||
message.error('请输入正确的手机号');
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -744,13 +719,13 @@ const sendSms = async () => {
|
||||
return;
|
||||
}
|
||||
// 发送成功
|
||||
message.success('验证码发送成功');
|
||||
message.success("验证码发送成功");
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown();
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败', error);
|
||||
message.error('验证码发送失败,请重试');
|
||||
console.error("发送验证码失败", error);
|
||||
message.error("验证码发送失败,请重试");
|
||||
smsButtonDisabled.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
@ -760,14 +735,14 @@ const sendSms = async () => {
|
||||
const sendForgotPasswordSms = async () => {
|
||||
// 检查手机号是否为空
|
||||
if (!forgotPasswordForm.value.phone) {
|
||||
message.error('请输入手机号');
|
||||
message.error("请输入手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(forgotPasswordForm.value.phone)) {
|
||||
message.error('请输入正确的手机号');
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -790,7 +765,7 @@ const sendForgotPasswordSms = async () => {
|
||||
}
|
||||
|
||||
// 发送成功
|
||||
message.success('验证码发送成功');
|
||||
message.success("验证码发送成功");
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown();
|
||||
@ -812,65 +787,57 @@ const handleResetPassword = async () => {
|
||||
!forgotPasswordForm.value.phone ||
|
||||
!phoneRegex.test(forgotPasswordForm.value.phone)
|
||||
) {
|
||||
message.error('请输入正确的手机号');
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!forgotPasswordForm.value.captcha) {
|
||||
message.error('请输入验证码');
|
||||
message.error("请输入验证码");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!forgotPasswordForm.value.newPassword) {
|
||||
message.error('请输入新密码');
|
||||
message.error("请输入新密码");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证确认密码
|
||||
if (!forgotPasswordForm.value.confirmPassword) {
|
||||
message.error('请再次输入密码');
|
||||
message.error("请再次输入密码");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证两次密码是否一致
|
||||
if (
|
||||
forgotPasswordForm.value.newPassword !==
|
||||
forgotPasswordForm.value.confirmPassword
|
||||
forgotPasswordForm.value.newPassword !== forgotPasswordForm.value.confirmPassword
|
||||
) {
|
||||
message.error('两次输入的密码不一致');
|
||||
message.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
|
||||
// 密码复杂度校验
|
||||
const password = forgotPasswordForm.value.newPassword;
|
||||
if (password.length < 10) {
|
||||
message.error('密码长度不能少于10位');
|
||||
message.error("密码长度不能少于10位");
|
||||
return;
|
||||
}
|
||||
|
||||
const hasUpperCase = /[A-Z]/.test(password);
|
||||
const hasLowerCase = /[a-z]/.test(password);
|
||||
const hasNumber = /\d/.test(password);
|
||||
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
|
||||
password
|
||||
);
|
||||
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password);
|
||||
|
||||
const typeCount = [
|
||||
hasUpperCase,
|
||||
hasLowerCase,
|
||||
hasNumber,
|
||||
hasSpecialChar
|
||||
].filter(Boolean).length;
|
||||
const typeCount = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(
|
||||
Boolean
|
||||
).length;
|
||||
if (typeCount < 3) {
|
||||
message.error(
|
||||
'密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种'
|
||||
);
|
||||
message.error("密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查连续重复字符
|
||||
if (/(.)\1{1,}/.test(password)) {
|
||||
message.error('密码不能包含连续重复字符');
|
||||
message.error("密码不能包含连续重复字符");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -879,7 +846,7 @@ const handleResetPassword = async () => {
|
||||
if (/\d/.test(password[i]) && /\d/.test(password[i + 1])) {
|
||||
const diff = password.charCodeAt(i + 1) - password.charCodeAt(i);
|
||||
if (Math.abs(diff) === 1) {
|
||||
message.error('密码不能包含连续递增或递减的数字');
|
||||
message.error("密码不能包含连续递增或递减的数字");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -890,13 +857,13 @@ const handleResetPassword = async () => {
|
||||
if (/[a-zA-Z]/.test(password[i]) && /[a-zA-Z]/.test(password[i + 1])) {
|
||||
const diff = password.charCodeAt(i + 1) - password.charCodeAt(i);
|
||||
if (Math.abs(diff) === 1) {
|
||||
message.error('密码不能包含连续递增或递减的字母');
|
||||
message.error("密码不能包含连续递增或递减的字母");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('表单验证失败', error);
|
||||
console.error("表单验证失败", error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -914,11 +881,11 @@ const handleResetPassword = async () => {
|
||||
);
|
||||
|
||||
if (res.code == 0) {
|
||||
message.success('密码重置成功');
|
||||
message.success("密码重置成功");
|
||||
// 返回登录页面
|
||||
backToLogin();
|
||||
} else {
|
||||
message.error(res.msg || '密码重置失败');
|
||||
message.error(res.msg || "密码重置失败");
|
||||
}
|
||||
} catch (error: any) {
|
||||
// console.error("密码重置失败", error);
|
||||
@ -989,7 +956,7 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 600px;
|
||||
background: url('@/assets/images/bg_sjtb.png');
|
||||
background: url("@/assets/images/bg_sjtb.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
<a-form-item name="username" label="账 号">
|
||||
<a-input
|
||||
v-model:value="registerData.username"
|
||||
autocomplete="current-username"
|
||||
placeholder="请输入登录账号(4-20个字符)"
|
||||
/>
|
||||
</a-form-item>
|
||||
@ -41,6 +42,7 @@
|
||||
>
|
||||
<a-input-password
|
||||
v-model:value="registerData.password"
|
||||
autocomplete="current-password"
|
||||
placeholder="请设置密码(6-20个字符)"
|
||||
/>
|
||||
</a-form-item>
|
||||
@ -49,6 +51,7 @@
|
||||
<a-form-item name="confirmPassword" label="确认密码">
|
||||
<a-input-password
|
||||
v-model:value="registerData.confirmPassword"
|
||||
autocomplete="current-confirmPassword"
|
||||
placeholder="请再次输入密码"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
36
frontend/docs/问题.md
Normal file
36
frontend/docs/问题.md
Normal file
@ -0,0 +1,36 @@
|
||||
# 问题汇总
|
||||
|
||||
> 本记录用于跟踪项目开发过程中发现的问题,按日期倒序排列,并标注每项问题的发现人及处理状态。
|
||||
|
||||
---
|
||||
|
||||
## 问题列表(2026-06-26)
|
||||
|
||||
| 发现日期 | 解决人 | 编号 | 问题描述 | 状态 | 备注 |
|
||||
|----------|--------|------|----------|------|------|
|
||||
| 2026-06-26 | 扈 | 1 | 基础信息图片展示是什么逻辑 | ✅ | |
|
||||
| 2026-06-26 | 扈 | 2 | 电站专题展示逻辑 | ✅ | |
|
||||
| 2026-06-26 | | 3 | 实时视频回放 少接口 | ⚠ | 缺少接口 |
|
||||
| 2026-06-26 | | 4 | 预警提示 少接口 | ⚠ | 缺少接口 |
|
||||
| 2026-06-26 | 扈 | 5 | 生态流量 达标率查询不对 | ✅ | |
|
||||
| 2026-06-26 | 王 | 6 | 鱼类适应性繁殖同期对比NAN | ⚠ | |
|
||||
| 2026-06-26 | | 7 | 出库水温 综合分析 导出没做 | ⚠ | |
|
||||
| 2026-06-26 | | 8 | 栖息地-流量监测 没有水位视频和流量视频 字段没数据 | ⚠ | |
|
||||
| 2026-06-26 | | 9 | 栖息地 水温、水质、流量没有数据没法测 | ⚠ | |
|
||||
| 2026-06-26 | | 10 | 鱼类增殖站 - 运行数据 要添加字典 | ⚠ | |
|
||||
| 2026-06-26 | 扈 | 11 | 珍惜植物园 - 种植要求字段不知道 | ✅ | |
|
||||
| 2026-06-26 | 扈 | 12 | 水生调查断面 - 监测数据 不知道电导率,性腺发育期,早期资源量和种类 | ✅ | |
|
||||
| 2026-06-26 | 扈 | 13 | 水电告警情况 生态流量 不知道字段 接口传参有问题 | ✅ | |
|
||||
| 2026-06-26 | | 14 | 地图抽吸 碰撞检测 放大到具体层级锚点抽吸了但是popup弹框还在显示 | ⚠ | |
|
||||
| 2026-06-26 | | 15 | 地图比如积石峡 放大到层级被公伯峡隐藏掉了,然后在放大才显示 抽吸的问题 | ⚠ | |
|
||||
| 2026-06-26 | | 16 | 运行情况 计划开始运行时间 接口没接 | ⚠ | |
|
||||
|
||||
---
|
||||
|
||||
## 状态说明
|
||||
- ✅ – 已解决 / 已确认
|
||||
- ⚠ – 处理中 / 待解决
|
||||
- ❌ – 阻塞 / 未开始
|
||||
|
||||
---
|
||||
、
|
||||
@ -9,26 +9,6 @@
|
||||
:destroyOnClose="true"
|
||||
class="map-modal"
|
||||
>
|
||||
<!-- 问题:
|
||||
1.基础信息图片展示是什么逻辑✅️
|
||||
2. 电站专题展示逻辑✅️
|
||||
3. 实时视频回放 少接口✅️
|
||||
4. 预警提示 少接口
|
||||
5. 生态流量 达标率查询不对(✅️)
|
||||
6. 鱼类适应性繁殖同期对比NAN (王)
|
||||
7. 出库水温 综合分析 导出没做
|
||||
8. 栖息地-流量监测 没有水位视频和流量视频 字段没数据
|
||||
9. 栖息地 水温、水质、流量没有数据没法测
|
||||
10.鱼类增殖站 - 运行数据 要添加字典
|
||||
11.珍惜植物园 - 种植要求字段不知道✅️
|
||||
12.水生调查断面 - 监测数据 不知道电导率 ,性腺发育期,早期资源量和种类 ✅️
|
||||
13.水电告警情况 生态流量 不知道字段 ✅️ 接口传参有问题
|
||||
14. 地图抽吸 碰撞检测 放大到具体层级锚点抽吸了但是popup弹框还在显示;
|
||||
15.地图比如积石峡 放大到层级被公伯峡隐藏掉了,然后在放大才显示 抽吸的问题
|
||||
15.运行情况 计划开始运行时间 接口没接
|
||||
|
||||
|
||||
-->
|
||||
<div v-if="modelStore.showStcdSelector" class="stcd-selector-wrapper">
|
||||
<a-select
|
||||
v-model:value="modelStore.params.stcd"
|
||||
@ -267,7 +247,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, reactive, computed } from 'vue';
|
||||
import { ref, watch, computed } from 'vue';
|
||||
// 导入预定义的 Tab 内容组件
|
||||
import BasicInfo from './components/BasicInfo.vue'; // 基本信息
|
||||
import VideoInfo from './components/videoInfo.vue'; // 实时视频
|
||||
|
||||
@ -112,6 +112,7 @@
|
||||
type="text"
|
||||
placeholder="请输入用户账号/手机号"
|
||||
size="large"
|
||||
autocomplete="current-username"
|
||||
>
|
||||
<template #prefix>
|
||||
<UserOutlined />
|
||||
@ -126,6 +127,7 @@
|
||||
v-model:value="loginData.password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
autocomplete="current-password"
|
||||
>
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
@ -140,6 +142,7 @@
|
||||
><a-input
|
||||
v-model:value="loginData.code"
|
||||
placeholder="请输入验证码"
|
||||
autocomplete="current-captcha"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
/></a-col>
|
||||
@ -184,6 +187,7 @@
|
||||
<a-form-item label="" name="username">
|
||||
<a-input
|
||||
v-model:value="loginData.username"
|
||||
autocomplete="current-username"
|
||||
placeholder="请输入手机号"
|
||||
size="large"
|
||||
>
|
||||
@ -197,6 +201,7 @@
|
||||
<a-input
|
||||
v-model="loginData.code"
|
||||
placeholder="请输入验证码"
|
||||
autocomplete="current-captcha"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user