修改问题

This commit is contained in:
扈兆增 2026-06-26 18:16:16 +08:00
parent 264a10931b
commit 78eb7f9b87
5 changed files with 181 additions and 190 deletions

View File

@ -10,7 +10,7 @@
<!-- 左侧背景图区域 --> <!-- 左侧背景图区域 -->
<div class="left-section"> <div class="left-section">
<div class="slogan"> <div class="slogan">
<p>{{ $t('login.titleSjtb') }}</p> <p>{{ $t("login.titleSjtb") }}</p>
</div> </div>
</div> </div>
@ -49,6 +49,7 @@
v-model:value="forgotPasswordForm.captcha" v-model:value="forgotPasswordForm.captcha"
placeholder="请输入验证码" placeholder="请输入验证码"
size="large" size="large"
autocomplete="current-captcha"
class="captcha-input" class="captcha-input"
> >
<template #prefix> <template #prefix>
@ -63,9 +64,7 @@
:loading="loading" :loading="loading"
> >
{{ {{
smsCountdown > 0 smsCountdown > 0 ? `${smsCountdown}秒后重新获取` : "获取验证码"
? `${smsCountdown}秒后重新获取`
: '获取验证码'
}} }}
</a-button> </a-button>
</template> </template>
@ -76,6 +75,7 @@
<a-form-item label="" name="newPassword"> <a-form-item label="" name="newPassword">
<a-input-password <a-input-password
v-model:value="forgotPasswordForm.newPassword" v-model:value="forgotPasswordForm.newPassword"
autocomplete="current-password"
placeholder="请输入新密码" placeholder="请输入新密码"
size="large" size="large"
> >
@ -88,6 +88,7 @@
<a-form-item label="" name="confirmPassword"> <a-form-item label="" name="confirmPassword">
<a-input-password <a-input-password
v-model:value="forgotPasswordForm.confirmPassword" v-model:value="forgotPasswordForm.confirmPassword"
autocomplete="current-confirmPassword"
placeholder="请再次输入密码" placeholder="请再次输入密码"
size="large" size="large"
> >
@ -130,6 +131,7 @@
type="text" type="text"
placeholder="请输入用户账号/手机号" placeholder="请输入用户账号/手机号"
size="large" size="large"
autocomplete="current-username"
> >
<template #prefix> <template #prefix>
<UserOutlined /> <UserOutlined />
@ -144,6 +146,7 @@
v-model:value="loginData.password" v-model:value="loginData.password"
placeholder="请输入密码" placeholder="请输入密码"
size="large" size="large"
autocomplete="current-password"
> >
<template #prefix> <template #prefix>
<LockOutlined /> <LockOutlined />
@ -158,6 +161,7 @@
><a-input ><a-input
v-model:value="loginData.code" v-model:value="loginData.code"
placeholder="请输入验证码" placeholder="请输入验证码"
autocomplete="current-captcha"
size="large" size="large"
class="captcha-input" class="captcha-input"
/></a-col> /></a-col>
@ -185,9 +189,7 @@
justify-content: space-between; justify-content: space-between;
" "
> >
<a-checkbox <a-checkbox v-model:checked="remember" style="margin-top: 10px"
v-model:checked="remember"
style="margin-top: 10px"
>记住密码</a-checkbox >记住密码</a-checkbox
> >
<a-button <a-button
@ -254,7 +256,7 @@
{{ {{
smsCountdown > 0 smsCountdown > 0
? `${smsCountdown}秒后重新获取` ? `${smsCountdown}秒后重新获取`
: '获取验证码' : "获取验证码"
}} }}
</a-button> </a-button>
</template> </template>
@ -307,43 +309,34 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, reactive, ref, toRefs, watch } from 'vue'; import { onMounted, reactive, ref, toRefs, watch } from "vue";
import loginImg from '@/assets/images/logo.png'; import loginImg from "@/assets/images/logo.png";
import { import { UserOutlined, LockOutlined, MobileOutlined } from "@ant-design/icons-vue";
UserOutlined, import { getCaptcha, sendSmsCode, smsLoginApi, resetPassword } from "@/api/auth";
LockOutlined, import { message } from "ant-design-vue";
MobileOutlined import { setToken } from "@/utils/auth";
} from '@ant-design/icons-vue'; import Cookies from "js-cookie";
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 // API
import { useRoute } from 'vue-router'; import { useRoute } from "vue-router";
import { LoginData } from '@/api/auth/types'; 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 { useUserStore } from "@/store/modules/user";
import { usePermissionStoreHook } from '@/store/modules/permission'; import { usePermissionStoreHook } from "@/store/modules/permission";
// //
import { useI18n } from 'vue-i18n'; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const userStore = useUserStore(); const userStore = useUserStore();
const route = useRoute(); const route = useRoute();
// //
const codeUrl = ref(''); const codeUrl = ref("");
const smsCountdown = ref(0); // const smsCountdown = ref(0); //
const smsButtonDisabled = ref(false); // const smsButtonDisabled = ref(false); //
@ -352,59 +345,55 @@ let remember = ref(false);
// //
const forgotPasswordForm = ref({ const forgotPasswordForm = ref({
phone: '', phone: "",
captcha: '', captcha: "",
newPassword: '', newPassword: "",
confirmPassword: '' confirmPassword: "",
}); });
// //
const showForgotPassword = ref(false); const showForgotPassword = ref(false);
// //
const activeTab = ref('account'); const activeTab = ref("account");
const state = reactive({ const state = reactive({
redirect: '', redirect: "",
loginData: { loginData: {
uuid: '', uuid: "",
username: '', username: "",
password: '', password: "",
code: '' code: "",
} as LoginData, } as LoginData,
loginRules: { loginRules: {
username: [ username: [{ required: true, trigger: "blur", message: t("login.rulesUsername") }],
{ required: true, trigger: 'blur', message: t('login.rulesUsername') } password: [{ required: true, trigger: "blur", message: t("login.rulesPassword") }],
], code: [{ required: true, trigger: "blur", message: "请输入验证码" }],
password: [
{ required: true, trigger: 'blur', message: t('login.rulesPassword') }
],
code: [{ required: true, trigger: 'blur', message: '请输入验证码' }]
}, },
smsLoginRules: { smsLoginRules: {
username: [{ required: true, trigger: 'blur', message: '请输入手机号' }], username: [{ required: true, trigger: "blur", message: "请输入手机号" }],
code: [{ required: true, trigger: 'blur', message: '请输入验证码' }] code: [{ required: true, trigger: "blur", message: "请输入验证码" }],
}, },
loginImg: loginImg[0], loginImg: loginImg[0],
loading: false, loading: false,
passwordType: 'password', passwordType: "password",
// //
capslockTooltipDisabled: true, capslockTooltipDisabled: true,
otherQuery: {}, otherQuery: {},
clientHeight: document.documentElement.clientHeight, clientHeight: document.documentElement.clientHeight,
showDialog: false, showDialog: false,
cookiePass: '' cookiePass: "",
}); });
// //
const forgotPasswordRules = ref({ const forgotPasswordRules = ref({
phone: [ phone: [
{ required: true, message: '手机号不能为空', trigger: 'blur' }, { required: true, message: "手机号不能为空", trigger: "blur" },
{ pattern: /^1[3-9]\d{9}$/, 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: [ newPassword: [
{ required: true, message: '新密码不能为空', trigger: 'blur' }, { required: true, message: "新密码不能为空", trigger: "blur" },
{ min: 10, message: '密码长度不能少于10位', trigger: 'blur' }, { min: 10, message: "密码长度不能少于10位", trigger: "blur" },
{ {
validator: (rule: any, value: string) => { validator: (rule: any, value: string) => {
if (!value) return Promise.resolve(); if (!value) return Promise.resolve();
@ -413,28 +402,21 @@ const forgotPasswordRules = ref({
const hasUpperCase = /[A-Z]/.test(value); const hasUpperCase = /[A-Z]/.test(value);
const hasLowerCase = /[a-z]/.test(value); const hasLowerCase = /[a-z]/.test(value);
const hasNumber = /\d/.test(value); const hasNumber = /\d/.test(value);
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test( const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value);
value
);
const typeCount = [ const typeCount = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(
hasUpperCase, Boolean
hasLowerCase, ).length;
hasNumber,
hasSpecialChar
].filter(Boolean).length;
if (typeCount < 3) { if (typeCount < 3) {
return Promise.reject( return Promise.reject(
new Error( new Error("密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种")
'密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种'
)
); );
} }
// //
if (/(.)\1{1,}/.test(value)) { 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])) { if (/\d/.test(value[i]) && /\d/.test(value[i + 1])) {
const diff = value.charCodeAt(i + 1) - value.charCodeAt(i); const diff = value.charCodeAt(i + 1) - value.charCodeAt(i);
if (Math.abs(diff) === 1) { if (Math.abs(diff) === 1) {
return Promise.reject( return Promise.reject(new Error("密码不能包含连续递增或递减的数字"));
new Error('密码不能包含连续递增或递减的数字')
);
} }
} }
} }
@ -454,39 +434,37 @@ const forgotPasswordRules = ref({
if (/[a-zA-Z]/.test(value[i]) && /[a-zA-Z]/.test(value[i + 1])) { if (/[a-zA-Z]/.test(value[i]) && /[a-zA-Z]/.test(value[i + 1])) {
const diff = value.charCodeAt(i + 1) - value.charCodeAt(i); const diff = value.charCodeAt(i + 1) - value.charCodeAt(i);
if (Math.abs(diff) === 1) { if (Math.abs(diff) === 1) {
return Promise.reject( return Promise.reject(new Error("密码不能包含连续递增或递减的字母"));
new Error('密码不能包含连续递增或递减的字母')
);
} }
} }
} }
return Promise.resolve(); return Promise.resolve();
}, },
trigger: 'blur' trigger: "blur",
} },
], ],
confirmPassword: [ confirmPassword: [
// { required: true, message: "", trigger: "blur" }, // { required: true, message: "", trigger: "blur" },
{ {
validator: (rule: any, value: string) => { validator: (rule: any, value: string) => {
if (!value) { if (!value) {
return Promise.reject(new Error('请再次输入密码')); return Promise.reject(new Error("请再次输入密码"));
} }
if (value !== forgotPasswordForm.value.newPassword) { if (value !== forgotPasswordForm.value.newPassword) {
return Promise.reject(new Error('两次输入的密码不一致')); return Promise.reject(new Error("两次输入的密码不一致"));
} }
return Promise.resolve(); return Promise.resolve();
}, },
trigger: 'blur' trigger: "blur",
} },
] ],
}); });
const { const {
loginData, loginData,
loginRules, loginRules,
loading loading,
// passwordType, capslockTooltipDisabled // passwordType, capslockTooltipDisabled
} = toRefs(state); } = toRefs(state);
@ -516,7 +494,7 @@ function onFinish() {
password: state.loginData.password, password: state.loginData.password,
// rememberMe: state.loginData.rememberMe, // rememberMe: state.loginData.rememberMe,
code: state.loginData.code, code: state.loginData.code,
uuid: state.loginData.uuid uuid: state.loginData.uuid,
}; };
if (user.password !== state.cookiePass) { if (user.password !== state.cookiePass) {
user.password = encrypt(user.password); user.password = encrypt(user.password);
@ -525,18 +503,18 @@ function onFinish() {
.login(user) .login(user)
.then(() => { .then(() => {
if (remember.value == true) { if (remember.value == true) {
Cookies.set('username', user.username, { expires: 30 }); Cookies.set("username", user.username, { expires: 30 });
Cookies.set('password', user.password, { expires: 30 }); Cookies.set("password", user.password, { expires: 30 });
Cookies.set('rememberMe', String(remember.value), { expires: 30 }); Cookies.set("rememberMe", String(remember.value), { expires: 30 });
} else { } else {
// cookie // cookie
Cookies.remove('username'); Cookies.remove("username");
Cookies.remove('password'); Cookies.remove("password");
Cookies.remove('rememberMe'); Cookies.remove("rememberMe");
} }
router.push({ path: '/' }); router.push({ path: "/" });
state.loading = false; state.loading = false;
message.success('登录成功'); message.success("登录成功");
}) })
.catch(() => { .catch(() => {
getCode(); getCode();
@ -551,16 +529,13 @@ const onSmsLogin = async () => {
try { try {
// ========== ========== // ========== ==========
const phoneRegex = /^1[3-9]\d{9}$/; const phoneRegex = /^1[3-9]\d{9}$/;
if ( if (!loginData.value.username || !phoneRegex.test(loginData.value.username)) {
!loginData.value.username || message.error("请输入正确的手机号");
!phoneRegex.test(loginData.value.username)
) {
message.error('请输入正确的手机号');
return; return;
} }
if (!loginData.value.code || loginData.value.code.trim() === '') { if (!loginData.value.code || loginData.value.code.trim() === "") {
message.error('请输入验证码'); message.error("请输入验证码");
return; return;
} }
@ -568,53 +543,53 @@ const onSmsLogin = async () => {
state.loading = true; state.loading = true;
// ========== API ========== // ========== API ==========
console.log('开始调用短信登录API, 手机号:', loginData.value.username); console.log("开始调用短信登录API, 手机号:", loginData.value.username);
const res: any = await smsLoginApi( const res: any = await smsLoginApi(
loginData.value.username, // loginData.value.username, //
loginData.value.code // 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 // code "0" 0
if (res.code !== 0 && res.code !== '0') { if (res.code !== 0 && res.code !== "0") {
console.error('短信登录失败, 错误码:', res.code, '错误信息:', res.msg); console.error("短信登录失败, 错误码:", res.code, "错误信息:", res.msg);
message.error(res.msg || '登录失败'); message.error(res.msg || "登录失败");
return; return;
} }
// ========== Token ========== // ========== Token ==========
console.log('开始提取Token, res.data:', res.data); console.log("开始提取Token, res.data:", res.data);
const token = res.data?.token || res.data; // const token = res.data?.token || res.data; //
if (!token) { if (!token) {
console.error('Token为空, res.data结构:', JSON.stringify(res.data)); console.error("Token为空, res.data结构:", JSON.stringify(res.data));
message.error('登录失败:未获取到Token'); message.error("登录失败:未获取到Token");
return; return;
} }
console.log('Token获取成功:', token); console.log("Token获取成功:", token);
// Cookie // Cookie
setToken(token); setToken(token);
// Store Token // Store Token
userStore.Token = token; userStore.Token = token;
console.log('Token已存储到Store'); console.log("Token已存储到Store");
// ========== ========== // ========== ==========
console.log('开始获取用户信息...'); console.log("开始获取用户信息...");
const userInfo = await userStore.getInfo(); const userInfo = await userStore.getInfo();
console.log('用户信息获取成功:', userInfo); console.log("用户信息获取成功:", userInfo);
const roles = userInfo.roles; const roles = userInfo.roles;
console.log('用户角色:', roles); console.log("用户角色:", roles);
// ========== ========== // ========== ==========
console.log('开始生成路由...'); console.log("开始生成路由...");
const permissionStore = usePermissionStoreHook(); const permissionStore = usePermissionStoreHook();
const accessRoutes: any = await permissionStore.generateRoutes(roles); const accessRoutes: any = await permissionStore.generateRoutes(roles);
console.log('路由生成成功, 路由数量:', accessRoutes.length); console.log("路由生成成功, 路由数量:", accessRoutes.length);
// ========== ========== // ========== ==========
accessRoutes.forEach((route: any) => { accessRoutes.forEach((route: any) => {
@ -623,11 +598,11 @@ const onSmsLogin = async () => {
// ========== ========== // ========== ==========
router.push({ path: accessRoutes[0].children[0].opturl }); router.push({ path: accessRoutes[0].children[0].opturl });
message.success('登录成功'); message.success("登录成功");
} catch (error: any) { } catch (error: any) {
// ========== ========== // ========== ==========
console.error('短信登录失败', error); console.error("短信登录失败", error);
message.error(error.message || '登录失败,请重试'); message.error(error.message || "登录失败,请重试");
} finally { } finally {
// ========== ========== // ========== ==========
state.loading = false; state.loading = false;
@ -644,31 +619,31 @@ watch(
} }
}, },
{ {
immediate: true immediate: true,
} }
); );
function getOtherQuery(query: any) { function getOtherQuery(query: any) {
return Object.keys(query).reduce((acc: any, cur: any) => { return Object.keys(query).reduce((acc: any, cur: any) => {
if (cur !== 'redirect') { if (cur !== "redirect") {
acc[cur] = query[cur]; acc[cur] = query[cur];
} }
return acc; return acc;
}, {}); }, {});
} }
function getCookie() { function getCookie() {
const username = Cookies.get('username'); const username = Cookies.get("username");
let password = Cookies.get('password'); let password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe'); const rememberMe = Cookies.get("rememberMe");
rememberMe == 'true' ? (remember.value = Boolean(rememberMe)) : false; rememberMe == "true" ? (remember.value = Boolean(rememberMe)) : false;
// cookie // cookie
state.cookiePass = password === undefined ? '' : password; state.cookiePass = password === undefined ? "" : password;
password = password === undefined ? state.loginData.password : password; password = password === undefined ? state.loginData.password : password;
state.loginData = { state.loginData = {
username: username === undefined ? state.loginData.username : username, username: username === undefined ? state.loginData.username : username,
password: decrypt(password), password: decrypt(password),
code: '', code: "",
uuid: '' uuid: "",
}; };
remember.value = rememberMe === undefined ? false : Boolean(rememberMe); remember.value = rememberMe === undefined ? false : Boolean(rememberMe);
} }
@ -699,17 +674,17 @@ const showForgotPasswordPage = () => {
}; };
// //
const goRegister = () => { const goRegister = () => {
router.push({ path: '/register' }); router.push({ path: "/register" });
}; };
// //
const backToLogin = () => { const backToLogin = () => {
showForgotPassword.value = false; showForgotPassword.value = false;
// //
forgotPasswordForm.value = { forgotPasswordForm.value = {
phone: '', phone: "",
captcha: '', captcha: "",
newPassword: '', newPassword: "",
confirmPassword: '' confirmPassword: "",
}; };
}; };
@ -717,14 +692,14 @@ const backToLogin = () => {
const sendSms = async () => { const sendSms = async () => {
// //
if (!loginData.value.username) { if (!loginData.value.username) {
message.error('请输入手机号'); message.error("请输入手机号");
return; return;
} }
// //
const phoneRegex = /^1[3-9]\d{9}$/; const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(loginData.value.username)) { if (!phoneRegex.test(loginData.value.username)) {
message.error('请输入正确的手机号'); message.error("请输入正确的手机号");
return; return;
} }
@ -744,13 +719,13 @@ const sendSms = async () => {
return; return;
} }
// //
message.success('验证码发送成功'); message.success("验证码发送成功");
// //
startCountdown(); startCountdown();
} catch (error) { } catch (error) {
console.error('发送验证码失败', error); console.error("发送验证码失败", error);
message.error('验证码发送失败,请重试'); message.error("验证码发送失败,请重试");
smsButtonDisabled.value = false; smsButtonDisabled.value = false;
} finally { } finally {
loading.value = false; loading.value = false;
@ -760,14 +735,14 @@ const sendSms = async () => {
const sendForgotPasswordSms = async () => { const sendForgotPasswordSms = async () => {
// //
if (!forgotPasswordForm.value.phone) { if (!forgotPasswordForm.value.phone) {
message.error('请输入手机号'); message.error("请输入手机号");
return; return;
} }
// //
const phoneRegex = /^1[3-9]\d{9}$/; const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(forgotPasswordForm.value.phone)) { if (!phoneRegex.test(forgotPasswordForm.value.phone)) {
message.error('请输入正确的手机号'); message.error("请输入正确的手机号");
return; return;
} }
@ -790,7 +765,7 @@ const sendForgotPasswordSms = async () => {
} }
// //
message.success('验证码发送成功'); message.success("验证码发送成功");
// //
startCountdown(); startCountdown();
@ -812,65 +787,57 @@ const handleResetPassword = async () => {
!forgotPasswordForm.value.phone || !forgotPasswordForm.value.phone ||
!phoneRegex.test(forgotPasswordForm.value.phone) !phoneRegex.test(forgotPasswordForm.value.phone)
) { ) {
message.error('请输入正确的手机号'); message.error("请输入正确的手机号");
return; return;
} }
if (!forgotPasswordForm.value.captcha) { if (!forgotPasswordForm.value.captcha) {
message.error('请输入验证码'); message.error("请输入验证码");
return; return;
} }
if (!forgotPasswordForm.value.newPassword) { if (!forgotPasswordForm.value.newPassword) {
message.error('请输入新密码'); message.error("请输入新密码");
return; return;
} }
// //
if (!forgotPasswordForm.value.confirmPassword) { if (!forgotPasswordForm.value.confirmPassword) {
message.error('请再次输入密码'); message.error("请再次输入密码");
return; return;
} }
// //
if ( if (
forgotPasswordForm.value.newPassword !== forgotPasswordForm.value.newPassword !== forgotPasswordForm.value.confirmPassword
forgotPasswordForm.value.confirmPassword
) { ) {
message.error('两次输入的密码不一致'); message.error("两次输入的密码不一致");
return; return;
} }
// //
const password = forgotPasswordForm.value.newPassword; const password = forgotPasswordForm.value.newPassword;
if (password.length < 10) { if (password.length < 10) {
message.error('密码长度不能少于10位'); message.error("密码长度不能少于10位");
return; return;
} }
const hasUpperCase = /[A-Z]/.test(password); const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password); const hasLowerCase = /[a-z]/.test(password);
const hasNumber = /\d/.test(password); const hasNumber = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test( const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password);
password
);
const typeCount = [ const typeCount = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(
hasUpperCase, Boolean
hasLowerCase, ).length;
hasNumber,
hasSpecialChar
].filter(Boolean).length;
if (typeCount < 3) { if (typeCount < 3) {
message.error( message.error("密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种");
'密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种'
);
return; return;
} }
// //
if (/(.)\1{1,}/.test(password)) { if (/(.)\1{1,}/.test(password)) {
message.error('密码不能包含连续重复字符'); message.error("密码不能包含连续重复字符");
return; return;
} }
@ -879,7 +846,7 @@ const handleResetPassword = async () => {
if (/\d/.test(password[i]) && /\d/.test(password[i + 1])) { if (/\d/.test(password[i]) && /\d/.test(password[i + 1])) {
const diff = password.charCodeAt(i + 1) - password.charCodeAt(i); const diff = password.charCodeAt(i + 1) - password.charCodeAt(i);
if (Math.abs(diff) === 1) { if (Math.abs(diff) === 1) {
message.error('密码不能包含连续递增或递减的数字'); message.error("密码不能包含连续递增或递减的数字");
return; return;
} }
} }
@ -890,13 +857,13 @@ const handleResetPassword = async () => {
if (/[a-zA-Z]/.test(password[i]) && /[a-zA-Z]/.test(password[i + 1])) { if (/[a-zA-Z]/.test(password[i]) && /[a-zA-Z]/.test(password[i + 1])) {
const diff = password.charCodeAt(i + 1) - password.charCodeAt(i); const diff = password.charCodeAt(i + 1) - password.charCodeAt(i);
if (Math.abs(diff) === 1) { if (Math.abs(diff) === 1) {
message.error('密码不能包含连续递增或递减的字母'); message.error("密码不能包含连续递增或递减的字母");
return; return;
} }
} }
} }
} catch (error) { } catch (error) {
console.error('表单验证失败', error); console.error("表单验证失败", error);
return; return;
} }
@ -914,11 +881,11 @@ const handleResetPassword = async () => {
); );
if (res.code == 0) { if (res.code == 0) {
message.success('密码重置成功'); message.success("密码重置成功");
// //
backToLogin(); backToLogin();
} else { } else {
message.error(res.msg || '密码重置失败'); message.error(res.msg || "密码重置失败");
} }
} catch (error: any) { } catch (error: any) {
// console.error("", error); // console.error("", error);
@ -989,7 +956,7 @@ onMounted(() => {
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 600px; min-height: 600px;
background: url('@/assets/images/bg_sjtb.png'); background: url("@/assets/images/bg_sjtb.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
} }

View File

@ -29,6 +29,7 @@
<a-form-item name="username" label="账&nbsp;&nbsp;号"> <a-form-item name="username" label="账&nbsp;&nbsp;号">
<a-input <a-input
v-model:value="registerData.username" v-model:value="registerData.username"
autocomplete="current-username"
placeholder="请输入登录账号4-20个字符" placeholder="请输入登录账号4-20个字符"
/> />
</a-form-item> </a-form-item>
@ -41,6 +42,7 @@
> >
<a-input-password <a-input-password
v-model:value="registerData.password" v-model:value="registerData.password"
autocomplete="current-password"
placeholder="请设置密码6-20个字符" placeholder="请设置密码6-20个字符"
/> />
</a-form-item> </a-form-item>
@ -49,6 +51,7 @@
<a-form-item name="confirmPassword" label="确认密码"> <a-form-item name="confirmPassword" label="确认密码">
<a-input-password <a-input-password
v-model:value="registerData.confirmPassword" v-model:value="registerData.confirmPassword"
autocomplete="current-confirmPassword"
placeholder="请再次输入密码" placeholder="请再次输入密码"
/> />
</a-form-item> </a-form-item>

36
frontend/docs/问题.md Normal file
View 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 | 运行情况 计划开始运行时间 接口没接 | ⚠ | |
---
## 状态说明
- ✅ 已解决 / 已确认
- ⚠ 处理中 / 待解决
- ❌ 阻塞 / 未开始
---

View File

@ -9,26 +9,6 @@
:destroyOnClose="true" :destroyOnClose="true"
class="map-modal" 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"> <div v-if="modelStore.showStcdSelector" class="stcd-selector-wrapper">
<a-select <a-select
v-model:value="modelStore.params.stcd" v-model:value="modelStore.params.stcd"
@ -267,7 +247,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch, reactive, computed } from 'vue'; import { ref, watch, computed } from 'vue';
// Tab // Tab
import BasicInfo from './components/BasicInfo.vue'; // import BasicInfo from './components/BasicInfo.vue'; //
import VideoInfo from './components/videoInfo.vue'; // import VideoInfo from './components/videoInfo.vue'; //

View File

@ -112,6 +112,7 @@
type="text" type="text"
placeholder="请输入用户账号/手机号" placeholder="请输入用户账号/手机号"
size="large" size="large"
autocomplete="current-username"
> >
<template #prefix> <template #prefix>
<UserOutlined /> <UserOutlined />
@ -126,6 +127,7 @@
v-model:value="loginData.password" v-model:value="loginData.password"
placeholder="请输入密码" placeholder="请输入密码"
size="large" size="large"
autocomplete="current-password"
> >
<template #prefix> <template #prefix>
<LockOutlined /> <LockOutlined />
@ -140,6 +142,7 @@
><a-input ><a-input
v-model:value="loginData.code" v-model:value="loginData.code"
placeholder="请输入验证码" placeholder="请输入验证码"
autocomplete="current-captcha"
size="large" size="large"
class="captcha-input" class="captcha-input"
/></a-col> /></a-col>
@ -184,6 +187,7 @@
<a-form-item label="" name="username"> <a-form-item label="" name="username">
<a-input <a-input
v-model:value="loginData.username" v-model:value="loginData.username"
autocomplete="current-username"
placeholder="请输入手机号" placeholder="请输入手机号"
size="large" size="large"
> >
@ -197,6 +201,7 @@
<a-input <a-input
v-model="loginData.code" v-model="loginData.code"
placeholder="请输入验证码" placeholder="请输入验证码"
autocomplete="current-captcha"
size="large" size="large"
class="captcha-input" class="captcha-input"
> >