注册相关内容
This commit is contained in:
parent
10c3c33ad0
commit
1963dbbba1
@ -34,3 +34,113 @@ export function getCaptcha(): AxiosPromise<VerifyCode> {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
export function registerUser(data: any): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/sms/register',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流域列表
|
||||
* @param companyId 公司ID(可选),如果传入则根据公司获取流域列表
|
||||
*/
|
||||
export function getBasinList(): AxiosPromise<any[]> {
|
||||
return request({
|
||||
url: '/env/hbrv/regDropdown',
|
||||
method: 'get',
|
||||
// params: baseid ? { baseid } : {}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取集团列表(无参数,获取全量集团)
|
||||
*/
|
||||
export function getGroupList(): AxiosPromise<any[]> {
|
||||
return request({
|
||||
url: '/env/hycd/regDropdown',
|
||||
method: 'get',
|
||||
params:{lx:1}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据集团获取公司列表
|
||||
*/
|
||||
export function getCompanyList(): AxiosPromise<any[]> {
|
||||
return request({
|
||||
url: '/env/hycd/regDropdown',
|
||||
method: 'get',
|
||||
params: { lx:2 }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流域获取电站列表
|
||||
*/
|
||||
export function getStationList(params:any): AxiosPromise<any[]> {
|
||||
return request({
|
||||
url: '/env/engInfo/regDropdown',
|
||||
method: 'post',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
* @param phone 手机号
|
||||
* @param type 验证码类型:1-注册 2-找回密码
|
||||
*/
|
||||
export function sendSmsCode(phone: string, type: number = 1): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/sms/sendCode',
|
||||
method: 'post',
|
||||
data: { phone, type }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证短信验证码
|
||||
* @param phone 手机号
|
||||
* @param code 验证码
|
||||
* @param type 验证码类型:1-注册 2-找回密码
|
||||
*/
|
||||
export function verifySmsCode(phone: string, code: string, type: number = 1): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/sms/verifyCode',
|
||||
method: 'post',
|
||||
data: { phone, code, type }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信验证码登录
|
||||
* @param phone 手机号
|
||||
* @param code 验证码
|
||||
*/
|
||||
export function smsLoginApi(phone: string, code: string): AxiosPromise<TokenResult> {
|
||||
return request({
|
||||
url: '/sms/login',
|
||||
method: 'post',
|
||||
data: { phone, code }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
* @param phone 手机号
|
||||
* @param code 验证码
|
||||
* @param password 新密码
|
||||
*/
|
||||
export function resetPassword(phone: string, code: string, password: string): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/sms/resetPassword',
|
||||
method: 'post',
|
||||
data: { phone, code, password }
|
||||
});
|
||||
}
|
||||
|
||||
@ -17,6 +17,14 @@ export function gettableData(queryParams:any) {
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
// 审核用户列表
|
||||
export function queryPendingAuditUsers(queryParams:any) {
|
||||
return request({
|
||||
url: '/system/user/queryPendingAuditUsers',
|
||||
method: 'get',
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
//用户-禁用,启用
|
||||
export function DataStatus (queryParams:any) {
|
||||
return request({
|
||||
@ -105,7 +113,7 @@ export function updatePassword (queryParams:any) {
|
||||
//获取过鱼设施权限树
|
||||
export function getFishtree(queryParams:any) {
|
||||
return request({
|
||||
url: '/env/tree/rvcdEng',
|
||||
url: '/env/tree/hbrvEng',
|
||||
method: 'get',
|
||||
params: queryParams
|
||||
});
|
||||
@ -127,6 +135,15 @@ export function getuserdata(queryParams:any) {
|
||||
});
|
||||
}
|
||||
|
||||
// 审计用户(审批通过/驳回)
|
||||
export function auditUser(data: any) {
|
||||
return request({
|
||||
url: '/system/user/auditUser',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)
|
||||
*/
|
||||
|
||||
BIN
frontend/src/assets/components/shenpibohui.png
Normal file
BIN
frontend/src/assets/components/shenpibohui.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 440 B |
BIN
frontend/src/assets/components/shenpitongguo.png
Normal file
BIN
frontend/src/assets/components/shenpitongguo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 431 B |
BIN
frontend/src/assets/components/审批通过.png
Normal file
BIN
frontend/src/assets/components/审批通过.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 553 B |
@ -12,7 +12,7 @@ const routeKey = computed(() => router.path + Math.random());
|
||||
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<GisView />
|
||||
<!-- <GisView /> -->
|
||||
<div class="gi-panels">
|
||||
<router-view v-slot="{ Component, route }" :key="routeKey">
|
||||
<transition name="router-fade" mode="out-in">
|
||||
|
||||
@ -9,7 +9,7 @@ NProgress.configure({ showSpinner: false });
|
||||
const permissionStore = usePermissionStoreHook();
|
||||
|
||||
// 白名单路由
|
||||
const whiteList = ['/login']; //login
|
||||
const whiteList = ['/login','/register']; //login
|
||||
|
||||
// 查找第一个可用路由
|
||||
function findFirstAvailableRoute(routes: any[]): string | undefined {
|
||||
|
||||
@ -26,6 +26,11 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
component: () => import('@/views/login-sjtb/index.vue'),
|
||||
meta: { hidden: true }
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
component: () => import('@/views/register/index.vue'),
|
||||
meta: { hidden: true }
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/error-page/404.vue'),
|
||||
|
||||
@ -25,14 +25,9 @@
|
||||
<!-- <h3 class="forgot-password-title">忘记密码</h3> -->
|
||||
</div>
|
||||
|
||||
<a-form
|
||||
:model="forgotPasswordForm"
|
||||
:rules="forgotPasswordRules"
|
||||
layout="vertical"
|
||||
class="form-container"
|
||||
>
|
||||
<a-form :model="forgotPasswordForm" :rules="forgotPasswordRules" layout="vertical" class="form-container">
|
||||
<a-form-item label="" name="phone">
|
||||
<a-input placeholder="请输入手机号" size="large">
|
||||
<a-input v-model:value="forgotPasswordForm.phone" placeholder="请输入手机号" size="large">
|
||||
<template #prefix>
|
||||
<MobileOutlined />
|
||||
</template>
|
||||
@ -41,23 +36,13 @@
|
||||
|
||||
<a-form-item label="" name="captcha">
|
||||
<div class="captcha-row">
|
||||
<a-input
|
||||
v-model="forgotPasswordForm.captcha"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
class="captcha-input"
|
||||
>
|
||||
<a-input v-model:value="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"
|
||||
>
|
||||
<a-button type="text" size="small" @click="sendForgotPasswordSms" :disabled="smsButtonDisabled"
|
||||
:loading="loading">
|
||||
{{
|
||||
smsCountdown > 0 ? `${smsCountdown}秒后重新获取` : "获取验证码"
|
||||
}}
|
||||
@ -68,24 +53,22 @@
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="" name="newPassword">
|
||||
<a-input-password
|
||||
v-model="forgotPasswordForm.newPassword"
|
||||
placeholder="请输入新密码"
|
||||
size="large"
|
||||
>
|
||||
<a-input-password v-model:value="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"
|
||||
>
|
||||
<a-form-item label="" name="confirmPassword">
|
||||
<a-input-password v-model:value="forgotPasswordForm.confirmPassword" 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>
|
||||
@ -96,23 +79,12 @@
|
||||
<!-- 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 :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"
|
||||
>
|
||||
<a-input ref="username" v-model:value="loginData.username" clearable type="text"
|
||||
placeholder="请输入用户账号/身份证号/手机号" size="large">
|
||||
<template #prefix>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
@ -121,12 +93,7 @@
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<a-form-item label="" name="password">
|
||||
<a-input-password
|
||||
type="password"
|
||||
v-model:value="loginData.password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
>
|
||||
<a-input-password type="password" v-model:value="loginData.password" placeholder="请输入密码" size="large">
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
</template>
|
||||
@ -136,65 +103,38 @@
|
||||
<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="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"
|
||||
>
|
||||
<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-button
|
||||
type="link"
|
||||
size="mini"
|
||||
block
|
||||
:style="{ marginTop: '10px', border: 'none' }"
|
||||
>
|
||||
注册
|
||||
</a-button>
|
||||
<div style="width: 100%;display: flex;align-items: center;justify-content: space-between;">
|
||||
<a-button type="link" size="mini" block @click="showForgotPasswordPage"
|
||||
:style="{ marginTop: '10px', border: 'none' }">
|
||||
忘记密码
|
||||
</a-button>
|
||||
<a-button type="link" size="mini" block @click="goRegister"
|
||||
:style="{ marginTop: '10px', border: 'none' }">
|
||||
注册
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 忘记密码 -->
|
||||
</a-form>
|
||||
</a-tab-pane>
|
||||
|
||||
<!-- 短信登录 Tab (占位) -->
|
||||
<!-- <a-tab-pane key="sms" tab="短信登录">
|
||||
<a-form
|
||||
:model="loginData"
|
||||
:rules="loginRules"
|
||||
layout="vertical"
|
||||
class="form-container"
|
||||
>
|
||||
<a-tab-pane key="sms" tab="短信登录">
|
||||
<a-form :model="loginData" :rules="state.smsLoginRules" layout="vertical" class="form-container"
|
||||
@finish="onSmsLogin">
|
||||
<a-form-item label="" name="username">
|
||||
<a-input
|
||||
v-model:value="loginData.username"
|
||||
placeholder="请输入手机号"
|
||||
size="large"
|
||||
>
|
||||
<a-input v-model:value="loginData.username" placeholder="请输入手机号" size="large">
|
||||
<template #prefix>
|
||||
<MobileOutlined />
|
||||
</template>
|
||||
@ -202,23 +142,13 @@
|
||||
</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"
|
||||
>
|
||||
<a-input v-model:value="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"
|
||||
>
|
||||
<a-button type="text" size="small" @click="sendSms" :disabled="smsButtonDisabled"
|
||||
:loading="loading">
|
||||
{{
|
||||
smsCountdown > 0
|
||||
? `${smsCountdown}秒后重新获取`
|
||||
@ -229,17 +159,21 @@
|
||||
</a-input>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
htmlType="submit"
|
||||
:loading="loading"
|
||||
>
|
||||
<a-button type="primary" size="large" block htmlType="submit" :loading="loading">
|
||||
<span>登录</span>
|
||||
</a-button>
|
||||
<div style="width: 100%;display: flex;align-items: center;justify-content: space-between;">
|
||||
<a-button type="link" size="mini" block @click="showForgotPasswordPage"
|
||||
:style="{ marginTop: '10px', border: 'none' }">
|
||||
忘记密码
|
||||
</a-button>
|
||||
<a-button type="link" size="mini" block @click="goRegister"
|
||||
:style="{ marginTop: '10px', border: 'none' }">
|
||||
注册
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-tab-pane> -->
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
@ -251,7 +185,7 @@
|
||||
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 } from "@/api/auth";
|
||||
import { getCaptcha, sendSmsCode, smsLoginApi, resetPassword } from "@/api/auth";
|
||||
import { message } from "ant-design-vue";
|
||||
import { setPath } from "@/utils/auth";
|
||||
// 组件依赖
|
||||
@ -285,6 +219,7 @@ const forgotPasswordForm = ref({
|
||||
phone: "",
|
||||
captcha: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
// 忘记密码
|
||||
const showForgotPassword = ref(false);
|
||||
@ -304,6 +239,10 @@ const state = reactive({
|
||||
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: "请输入验证码" }]
|
||||
},
|
||||
loginImg: loginImg[0],
|
||||
loading: false,
|
||||
passwordType: "password",
|
||||
@ -325,7 +264,67 @@ const forgotPasswordRules = ref({
|
||||
captcha: [{ required: true, message: "验证码不能为空", trigger: "blur" }],
|
||||
newPassword: [
|
||||
{ required: true, message: "新密码不能为空", trigger: "blur" },
|
||||
{ min: 6, message: "密码长度不能少于6位", trigger: "blur" },
|
||||
{ min: 10, message: "密码长度不能少于10位", trigger: "blur" },
|
||||
{
|
||||
validator: (rule: any, value: string) => {
|
||||
if (!value) return Promise.resolve();
|
||||
|
||||
// 检查密码复杂度:至少包含四类字符中的三类
|
||||
const hasUpperCase = /[A-Z]/.test(value);
|
||||
const hasLowerCase = /[a-z]/.test(value);
|
||||
const hasNumber = /\d/.test(value);
|
||||
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value);
|
||||
|
||||
const typeCount = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(Boolean).length;
|
||||
|
||||
if (typeCount < 3) {
|
||||
return Promise.reject(new Error('密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种'));
|
||||
}
|
||||
|
||||
// 检查连续重复字符
|
||||
if (/(.)\1{1,}/.test(value)) {
|
||||
return Promise.reject(new Error('密码不能包含连续重复字符'));
|
||||
}
|
||||
|
||||
// 检查连续递增/递减数字
|
||||
for (let i = 0; i < value.length - 1; i++) {
|
||||
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('密码不能包含连续递增或递减的数字'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查连续递增/递减字母
|
||||
for (let i = 0; i < value.length - 1; i++) {
|
||||
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.resolve();
|
||||
},
|
||||
trigger: "blur"
|
||||
}
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, message: "请再次输入密码", trigger: "blur" },
|
||||
{
|
||||
validator: (rule: any, value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject(new Error('请再次输入密码'));
|
||||
}
|
||||
if (value !== forgotPasswordForm.value.newPassword) {
|
||||
return Promise.reject(new Error('两次输入的密码不一致'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: "blur"
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
@ -382,6 +381,50 @@ function onFinish() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信验证码登录
|
||||
*/
|
||||
const onSmsLogin = async () => {
|
||||
// 对短信登录表单进行验证
|
||||
try {
|
||||
// 验证手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!loginData.value.username || !phoneRegex.test(loginData.value.username)) {
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证验证码
|
||||
if (!loginData.value.code || loginData.value.code.trim() === '') {
|
||||
message.error("请输入验证码");
|
||||
return;
|
||||
}
|
||||
// console.log()
|
||||
// debugger
|
||||
state.loading = true;
|
||||
|
||||
// 调用短信登录接口
|
||||
await smsLoginApi(
|
||||
loginData.value.username, // 手机号
|
||||
loginData.value.code // 验证码
|
||||
);
|
||||
|
||||
// 登录成功处理
|
||||
const res: any = setPath("/login-sjtb");
|
||||
if (res.code == 0) {
|
||||
message.success("登录成功");
|
||||
|
||||
// 跳转到首页
|
||||
router.push({ path: "/" });
|
||||
}
|
||||
} catch (error: any) {
|
||||
// console.error("短信登录失败", error);
|
||||
// message.error(error.message || "登录失败,请重试");
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
route,
|
||||
() => {
|
||||
@ -426,9 +469,9 @@ const startCountdown = () => {
|
||||
};
|
||||
|
||||
// 显示忘记密码页面
|
||||
// const showForgotPasswordPage = () => {
|
||||
// showForgotPassword.value = true;
|
||||
// };
|
||||
const showForgotPasswordPage = () => {
|
||||
showForgotPassword.value = true;
|
||||
};
|
||||
//注册用户页面
|
||||
const goRegister = () => {
|
||||
router.push({ path: "/register" });
|
||||
@ -441,49 +484,53 @@ const backToLogin = () => {
|
||||
phone: "",
|
||||
captcha: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
};
|
||||
|
||||
// 发送短信验证码
|
||||
// const sendSms = async () => {
|
||||
// // 检查手机号是否为空
|
||||
// if (!loginData.value.username) {
|
||||
// message.error("请输入手机号");
|
||||
// return;
|
||||
// }
|
||||
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;
|
||||
// }
|
||||
// 检查手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(loginData.value.username)) {
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// // 如果正在倒计时,不允许重复发送
|
||||
// if (smsCountdown.value > 0) {
|
||||
// return;
|
||||
// }
|
||||
// 如果正在倒计时,不允许重复发送
|
||||
if (smsCountdown.value > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// loading.value = true;
|
||||
// smsButtonDisabled.value = true;
|
||||
loading.value = true;
|
||||
smsButtonDisabled.value = true;
|
||||
|
||||
// try {
|
||||
// // 模拟发送短信验证码接口
|
||||
// // await axios.post('/sms/send', { phone: loginForm.value.username })
|
||||
try {
|
||||
// 调用发送短信验证码接口,type默认为1(注册类型)
|
||||
const res: any = await sendSmsCode(loginData.value.username, 3);
|
||||
if (res.code == 1) {
|
||||
message.success(res.msg);
|
||||
return
|
||||
}
|
||||
// 发送成功
|
||||
message.success("验证码发送成功");
|
||||
|
||||
// // 模拟发送成功
|
||||
// message.success("验证码发送成功");
|
||||
|
||||
// // 开始倒计时
|
||||
// startCountdown();
|
||||
// } catch (error) {
|
||||
// console.error("发送验证码失败", error);
|
||||
// message.error("验证码发送失败,请重试");
|
||||
// smsButtonDisabled.value = false;
|
||||
// } finally {
|
||||
// loading.value = false;
|
||||
// }
|
||||
// };
|
||||
// 开始倒计时
|
||||
startCountdown();
|
||||
} catch (error) {
|
||||
console.error("发送验证码失败", error);
|
||||
message.error("验证码发送失败,请重试");
|
||||
smsButtonDisabled.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
// 发送忘记密码短信验证码
|
||||
const sendForgotPasswordSms = async () => {
|
||||
// 检查手机号是否为空
|
||||
@ -508,17 +555,23 @@ const sendForgotPasswordSms = async () => {
|
||||
smsButtonDisabled.value = true;
|
||||
|
||||
try {
|
||||
// 模拟发送短信验证码接口
|
||||
// await axios.post('/sms/forgot-password', { phone: forgotPasswordForm.value.phone })
|
||||
// 调用发送短信验证码接口,type=3表示找回密码类型
|
||||
const res: any = await sendSmsCode(forgotPasswordForm.value.phone, 2);
|
||||
|
||||
// 模拟发送成功
|
||||
if (res.code == 1) {
|
||||
message.error(res.msg);
|
||||
smsButtonDisabled.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送成功
|
||||
message.success("验证码发送成功");
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown();
|
||||
} catch (error) {
|
||||
console.error("发送验证码失败", error);
|
||||
message.error("验证码发送失败,请重试");
|
||||
} catch (error: any) {
|
||||
// console.error("发送验证码失败", error);
|
||||
// message.error(error.message || "验证码发送失败,请重试");
|
||||
smsButtonDisabled.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
@ -526,23 +579,111 @@ const sendForgotPasswordSms = async () => {
|
||||
};
|
||||
// 处理密码重置
|
||||
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
|
||||
// })
|
||||
// 手动验证各个字段
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!forgotPasswordForm.value.phone || !phoneRegex.test(forgotPasswordForm.value.phone)) {
|
||||
message.error("请输入正确的手机号");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 模拟重置成功
|
||||
message.success("密码重置成功");
|
||||
if (!forgotPasswordForm.value.captcha) {
|
||||
message.error("请输入验证码");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!forgotPasswordForm.value.newPassword) {
|
||||
message.error("请输入新密码");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证确认密码
|
||||
if (!forgotPasswordForm.value.confirmPassword) {
|
||||
message.error("请再次输入密码");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证两次密码是否一致
|
||||
if (forgotPasswordForm.value.newPassword !== forgotPasswordForm.value.confirmPassword) {
|
||||
message.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
|
||||
// 密码复杂度校验
|
||||
const password = forgotPasswordForm.value.newPassword;
|
||||
if (password.length < 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 typeCount = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(Boolean).length;
|
||||
if (typeCount < 3) {
|
||||
message.error('密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查连续重复字符
|
||||
if (/(.)\1{1,}/.test(password)) {
|
||||
message.error('密码不能包含连续重复字符');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查连续递增/递减数字
|
||||
for (let i = 0; i < password.length - 1; i++) {
|
||||
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('密码不能包含连续递增或递减的数字');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查连续递增/递减字母
|
||||
for (let i = 0; i < password.length - 1; i++) {
|
||||
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('密码不能包含连续递增或递减的字母');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 返回登录页面
|
||||
backToLogin();
|
||||
} catch (error) {
|
||||
console.error("密码重置失败", error);
|
||||
message.error("密码重置失败,请重试");
|
||||
console.error("表单验证失败", error);
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// 对密码进行 RSA 加密
|
||||
const encryptedPassword = encrypt(forgotPasswordForm.value.newPassword);
|
||||
|
||||
// 调用重置密码接口,使用加密后的密码
|
||||
const res: any = await resetPassword(
|
||||
forgotPasswordForm.value.phone,
|
||||
forgotPasswordForm.value.captcha,
|
||||
encryptedPassword
|
||||
);
|
||||
|
||||
if (res.code == 0 ) {
|
||||
message.success("密码重置成功");
|
||||
// 返回登录页面
|
||||
backToLogin();
|
||||
} else {
|
||||
message.error(res.msg || "密码重置失败");
|
||||
}
|
||||
} catch (error: any) {
|
||||
// console.error("密码重置失败", error);
|
||||
// message.error(error.message || "密码重置失败,请重试");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@ -632,7 +773,7 @@ onMounted(() => {
|
||||
left: 74%;
|
||||
top: 30%;
|
||||
width: 20%;
|
||||
max-height: 402px;
|
||||
max-height: 420px;
|
||||
max-width: 400px;
|
||||
min-height: 362px;
|
||||
border-radius: 3px;
|
||||
@ -647,10 +788,12 @@ onMounted(() => {
|
||||
/* 验证码布局 */
|
||||
.captcha-row {
|
||||
display: flex;
|
||||
|
||||
.ant-row {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* gap: 12px;
|
||||
align-items: center; */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1209
frontend/src/views/system/review/index.vue
Normal file
1209
frontend/src/views/system/review/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -282,57 +282,80 @@ const userId = ref('')
|
||||
// 回显的权限ID数组
|
||||
const fishhui = ref<any[]>([])
|
||||
const fishTreeDialog = ref(false)
|
||||
function openFishway(row: any) {
|
||||
|
||||
// 添加标志位,标识数据是否已加载完成
|
||||
const isFishDataLoaded = ref(false)
|
||||
|
||||
async function openFishway(row: any) {
|
||||
fishway.value = true
|
||||
userId.value = row.id
|
||||
// 临时模拟数据
|
||||
getFishTree()
|
||||
// 打开对话框,watch 会处理回显逻辑
|
||||
|
||||
// 重置状态
|
||||
fishhui.value = []
|
||||
tableDatafish.value = []
|
||||
getuserdata({ userId: userId.value }).then((res: any) => {
|
||||
console.log(res)
|
||||
if (res.code == 0) {
|
||||
res.data.forEach((item: any) => {
|
||||
fishhui.value.push(item.orgId)
|
||||
tableDatafish.value.push({
|
||||
name: item.orgName,
|
||||
type: item.orgType, // 默认类型为'站点'
|
||||
id: item.orgId.toString(), // 使用code作为id
|
||||
code: item.orgId,
|
||||
path: item.path,
|
||||
userId: item.userId,
|
||||
parentId: item.parentId,
|
||||
orgLevel: item.orgLevel,
|
||||
permissionType: item.permissionType // 默认选择读权限
|
||||
})
|
||||
isFishDataLoaded.value = false
|
||||
|
||||
try {
|
||||
// 使用 Promise.all 并行等待两个请求都完成
|
||||
await Promise.all([
|
||||
getFishTree(), // 获取树形数据
|
||||
getuserdata({ userId: userId.value }).then((res: any) => {
|
||||
console.log('用户权限数据:', res)
|
||||
if (res.code == 0) {
|
||||
res.data.forEach((item: any) => {
|
||||
fishhui.value.push(item.orgId)
|
||||
tableDatafish.value.push({
|
||||
name: item.orgName,
|
||||
type: item.orgType,
|
||||
id: item.orgId.toString(),
|
||||
code: item.orgId,
|
||||
path: item.path,
|
||||
userId: item.userId,
|
||||
parentId: item.parentId,
|
||||
orgLevel: item.orgLevel,
|
||||
permissionType: item.permissionType
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
])
|
||||
|
||||
}
|
||||
})
|
||||
// 两个请求都完成后,标记数据已加载
|
||||
isFishDataLoaded.value = true
|
||||
console.log('所有数据加载完成,准备回显')
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
ElMessage.error('加载数据失败,请重试')
|
||||
}
|
||||
}
|
||||
|
||||
// 监听fishway对话框打开,延迟回显
|
||||
watch(fishway, (newVal) => {
|
||||
if (newVal) {
|
||||
// dialog打开后,延迟回显确保tree组件完全渲染
|
||||
setTimeout(() => {
|
||||
console.log('开始回显, fishTreeRef:', fishTreeRef.value);
|
||||
console.log('回显ID:', fishhui.value);
|
||||
watch([fishway, isFishDataLoaded], ([newFishway, newDataLoaded]) => {
|
||||
if (newFishway && newDataLoaded) {
|
||||
// 确保两个数据都已加载完成后再执行回显
|
||||
console.log('开始回显, fishTreeRef:', fishTreeRef.value);
|
||||
console.log('回显ID:', fishhui.value);
|
||||
console.log('树数据:', fishData.value);
|
||||
|
||||
// 使用 nextTick 确保 DOM 已更新
|
||||
nextTick(() => {
|
||||
if (fishTreeRef.value && fishhui.value.length > 0) {
|
||||
// 清除所有选中状态
|
||||
fishTreeRef.value.setCheckedKeys([], false);
|
||||
|
||||
// 延迟一点再设置,确保清除生效
|
||||
// 再设置新的选中状态
|
||||
setTimeout(() => {
|
||||
fishTreeRef.value.setCheckedKeys(fishhui.value, false);
|
||||
|
||||
// 验证回显结果
|
||||
const checkedKeys = fishTreeRef.value.getCheckedKeys();
|
||||
const halfCheckedKeys = fishTreeRef.value.getHalfCheckedKeys();
|
||||
console.log('回显完成 - 全选节点:', checkedKeys);
|
||||
console.log('回显完成 - 半选节点:', halfCheckedKeys);
|
||||
|
||||
// 同步表格数据
|
||||
fishTableData.value = tableDatafish.value
|
||||
}, 100);
|
||||
} else if (fishTreeRef.value) {
|
||||
// 如果fishhui.value为空,也需要清空表格数据
|
||||
@ -341,20 +364,12 @@ watch(fishway, (newVal) => {
|
||||
fishTableData.value = [];
|
||||
}, 100);
|
||||
}
|
||||
fishTableData.value = tableDatafish.value
|
||||
// if (fishhui.value.length > 0 && activeName.value == '1') {
|
||||
// isCompanyDisabled.value = true
|
||||
// } else if (fishhui.value.length > 0 && activeName.value == '2') {
|
||||
// isBaseDisabled.value = true
|
||||
// } else {
|
||||
// isCompanyDisabled.value = false
|
||||
// isBaseDisabled.value = false
|
||||
// }
|
||||
}, 500);
|
||||
} else {
|
||||
});
|
||||
} else if (!newFishway) {
|
||||
// 关闭时清空回显数据
|
||||
console.log('关闭对话框,清理数据');
|
||||
fishhui.value = [];
|
||||
isFishDataLoaded.value = false;
|
||||
// 清除tree选中状态
|
||||
setTimeout(() => {
|
||||
if (fishTreeRef.value) {
|
||||
@ -367,6 +382,7 @@ watch(fishway, (newVal) => {
|
||||
|
||||
function fishHandleClose() {
|
||||
fishway.value = false
|
||||
isFishDataLoaded.value = false
|
||||
fishTableData.value = []
|
||||
fishData.value = []
|
||||
}
|
||||
@ -406,19 +422,21 @@ const fishData: any = ref([])
|
||||
//获取左侧树的数据
|
||||
// const huixiandata = ref([])
|
||||
let tableDatafish: any = []
|
||||
// 修改为返回 Promise,便于外部等待
|
||||
function getFishTree() {
|
||||
fishTreeDialog.value = true
|
||||
const params = {
|
||||
// type:'1',
|
||||
engName: treeInput.value
|
||||
}
|
||||
getFishtree(params).then((res: any) => {
|
||||
return getFishtree(params).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
fishData.value = res.data
|
||||
fishTreeDialog.value = false
|
||||
}
|
||||
}).catch(() => {
|
||||
fishTreeDialog.value = false
|
||||
})
|
||||
fishTreeDialog.value = false
|
||||
|
||||
}
|
||||
|
||||
// 过鱼设施权限维护 - 获取所有子节点ID的辅助函数
|
||||
@ -1000,7 +1018,7 @@ function handleClearSelection() {
|
||||
<!-- 过鱼设施权限维护 -->
|
||||
<el-dialog v-model="fishway" :close-on-click-modal="false" :before-close="fishHandleClose" title="过鱼设施权限维护"
|
||||
append-to-body width="1600px" draggable>
|
||||
<el-scrollbar height="610px">
|
||||
<!-- <el-scrollbar height="610px"> -->
|
||||
<!-- <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="基地" name="1" :disabled="isBaseDisabled"></el-tab-pane>
|
||||
<el-tab-pane label="公司" name="2" :disabled="isCompanyDisabled"></el-tab-pane>
|
||||
@ -1021,9 +1039,9 @@ function handleClearSelection() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-scrollbar height="460px">
|
||||
<el-scrollbar height="450px" style="margin-top: 10px;">
|
||||
<el-tree ref="fishTreeRef" style="max-width: 300px" :data="fishData" show-checkbox default-expand-all
|
||||
:v-loading="fishTreeDialog" node-key="code" highlight-current :props="fishProps"
|
||||
v-loading="fishTreeDialog" node-key="code" highlight-current :props="fishProps"
|
||||
@check="handleFishCheckChange" />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
@ -1053,7 +1071,7 @@ function handleClearSelection() {
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<!-- </el-scrollbar> -->
|
||||
<span class="dialog-footer"
|
||||
style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;margin-top: 20px;">
|
||||
<el-button @click="fishHandleClose">取 消</el-button>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user