态势感知平台-账号密码登录及验证码接口对接治理平台登录接口
This commit is contained in:
@@ -40,7 +40,8 @@
|
||||
<!-- <li><router-link to="/intro" class="LNK">关于我们</router-link></li>-->
|
||||
<!-- </ul>-->
|
||||
|
||||
<a class="login-btn" @click="handleLogin('login')">登录</a>
|
||||
<a v-if="!isLogin" class="login-btn" @click="handleLogin('login')">登录</a>
|
||||
<UserAvatar v-else/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,7 +49,12 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, reactive} from 'vue';
|
||||
import UserAvatar from './UserAvatar.vue';
|
||||
import {emitEvent} from "@/utils/eventBus";
|
||||
import { useAccountStore } from '@/stores/user';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const userInfo = useAccountStore();
|
||||
const { isLogin } = storeToRefs(userInfo);
|
||||
|
||||
const dataSubMenus = [
|
||||
{
|
||||
|
||||
@@ -34,17 +34,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="login-form" @submit.prevent="handleLogin">
|
||||
|
||||
<d-form
|
||||
ref="loginFormRef"
|
||||
:data="loginForm"
|
||||
:rules="loginRules"
|
||||
layout="vertical"
|
||||
class="login-form-container"
|
||||
>
|
||||
<template v-if="loginType === 'account'">
|
||||
<div class="form-item">
|
||||
<d-form-item field="username" label="账号">
|
||||
<d-input
|
||||
v-model="loginForm.account"
|
||||
v-model="loginForm.username"
|
||||
placeholder="账户(邮箱或手机号)"
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
</d-form-item>
|
||||
<d-form-item field="password" label="密码">
|
||||
<d-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
@@ -52,45 +57,49 @@
|
||||
show-password
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-item verify-row">
|
||||
<d-input
|
||||
v-model="loginForm.verifyCode"
|
||||
placeholder="请输入验证码"
|
||||
size="lg"
|
||||
class="verify-input"
|
||||
/>
|
||||
<div class="captcha-box">
|
||||
<span>x j 7 2</span>
|
||||
<!-- <img class="code" :src="codeDir" alt="验证码图片" @click="getCaptchaUrl" />-->
|
||||
</d-form-item>
|
||||
<d-form-item field="code" label="验证码">
|
||||
<div class="verify-row">
|
||||
<d-input
|
||||
v-model="loginForm.code"
|
||||
placeholder="请输入验证码"
|
||||
size="lg"
|
||||
class="verify-input"
|
||||
/>
|
||||
<div class="captcha-box" @click="getCaptchaUrl">
|
||||
<img v-if="codeDir" :src="codeDir" alt="验证码" class="captcha-img" />
|
||||
<span v-else class="loading-text">加载中</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</d-form-item>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="form-item">
|
||||
<d-form-item field="mobile">
|
||||
<d-input
|
||||
v-model="loginForm.mobile"
|
||||
placeholder="请输入手机号"
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-item verify-row">
|
||||
<d-input
|
||||
v-model="loginForm.smsCode"
|
||||
placeholder="请输入验证码"
|
||||
size="lg"
|
||||
class="verify-input"
|
||||
/>
|
||||
<d-button
|
||||
variant="text"
|
||||
class="get-code-btn"
|
||||
:disabled="isCounting"
|
||||
@click="getSmsCode"
|
||||
>
|
||||
{{ isCounting ? `${count}s后重试` : '获取验证码' }}
|
||||
</d-button>
|
||||
</div>
|
||||
</d-form-item>
|
||||
<d-form-item field="smsCode">
|
||||
<div class="verify-row">
|
||||
<d-input
|
||||
v-model="loginForm.smsCode"
|
||||
placeholder="请输入验证码"
|
||||
size="lg"
|
||||
class="verify-input"
|
||||
/>
|
||||
<d-button
|
||||
variant="text"
|
||||
class="get-code-btn"
|
||||
:disabled="isCounting"
|
||||
@click="getSmsCode"
|
||||
>
|
||||
{{ isCounting ? `${count}s后重试` : '获取验证码' }}
|
||||
</d-button>
|
||||
</div>
|
||||
</d-form-item>
|
||||
</template>
|
||||
|
||||
<div class="extra-row">
|
||||
@@ -112,8 +121,7 @@
|
||||
>
|
||||
登录
|
||||
</d-button>
|
||||
|
||||
</form>
|
||||
</d-form>
|
||||
|
||||
<div class="footer-links">
|
||||
<a href="#">隐私政策</a>
|
||||
@@ -124,18 +132,21 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive,onMounted } from 'vue';
|
||||
import { ref, reactive, onMounted,defineProps } from 'vue';
|
||||
import { useModel } from '@/utils/hooks/useModel';
|
||||
// 引入 DevUI 组件 (确保已安装)
|
||||
import { Modal as DModal } from 'vue-devui/modal';
|
||||
import { Input as DInput } from 'vue-devui/input';
|
||||
import { Button as DButton } from 'vue-devui/button';
|
||||
import { Checkbox as DCheckbox } from 'vue-devui/checkbox';
|
||||
import { Message } from 'vue-devui/message';
|
||||
import {useRouter} from "vue-router";
|
||||
import {getCaptcha} from "@/api/jyh/auth";
|
||||
import {
|
||||
Modal as DModal,
|
||||
Input as DInput,
|
||||
Button as DButton,
|
||||
Checkbox as DCheckbox,
|
||||
Form as DForm,
|
||||
FormItem as DFormItem,
|
||||
Message
|
||||
} from 'vue-devui';
|
||||
import { useRouter } from "vue-router";
|
||||
// 引入页面2风格的接口逻辑
|
||||
import { getCaptcha, login } from "@/api/jyh/auth";
|
||||
|
||||
// 定义 Props 和 Emits
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue: boolean;
|
||||
showClose?: boolean;
|
||||
@@ -154,35 +165,48 @@ const { vModels } = useModel(props, emits);
|
||||
const router = useRouter();
|
||||
|
||||
// --- 状态管理 ---
|
||||
const loginType = ref<'account' | 'mobile'>('account'); // 当前登录方式
|
||||
const loginType = ref<'account' | 'mobile'>('account');
|
||||
const loading = ref(false);
|
||||
const rememberMe = ref(false);
|
||||
const loginFormRef = ref();
|
||||
const codeDir = ref(''); // 验证码图片路径
|
||||
|
||||
// 表单数据
|
||||
const loginForm = reactive({
|
||||
account: '',
|
||||
username: '',
|
||||
password: '',
|
||||
verifyCode: '', // 图形验证码
|
||||
code: '',
|
||||
uuid: '',
|
||||
mobile: '',
|
||||
smsCode: '' // 短信验证码
|
||||
smsCode: ''
|
||||
});
|
||||
|
||||
const loginRules = {
|
||||
username: [{ required: true, message: '请输入账户', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
||||
mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
||||
smsCode: [{ required: true, message: '请输入短信验证码', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
// 短信倒计时
|
||||
const count = ref(60);
|
||||
const isCounting = ref(false);
|
||||
let timer: any = null;
|
||||
|
||||
const codeDir = ref('');
|
||||
|
||||
|
||||
const getCaptchaUrl = () => {
|
||||
getCaptcha().then((res) => {
|
||||
const imageUrl = URL.createObjectURL(res.data);
|
||||
codeDir.value = imageUrl;
|
||||
getCaptcha().then((res: any) => {
|
||||
// 页面2通常返回的是包含 img (base64) 和 uuid 的对象
|
||||
if (res.data && res.data.img) {
|
||||
codeDir.value = res.data.img;
|
||||
loginForm.uuid = res.data.uuid;
|
||||
} else {
|
||||
// 兼容页面1原本的 Blob 模式
|
||||
const imageUrl = URL.createObjectURL(res.data);
|
||||
codeDir.value = imageUrl;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const handleClose = (close: Function) => {
|
||||
emits('close');
|
||||
close();
|
||||
@@ -193,10 +217,7 @@ const getSmsCode = async () => {
|
||||
Message.warning('请输入手机号');
|
||||
return;
|
||||
}
|
||||
// TODO: 调用发送短信接口
|
||||
Message.success('验证码已发送');
|
||||
|
||||
// 开始倒计时
|
||||
isCounting.value = true;
|
||||
count.value = 60;
|
||||
timer = setInterval(() => {
|
||||
@@ -209,245 +230,125 @@ const getSmsCode = async () => {
|
||||
};
|
||||
|
||||
const handleLogin = async () => {
|
||||
// 简单校验
|
||||
if (loginType.value === 'account') {
|
||||
if (!loginForm.account || !loginForm.password) {
|
||||
Message.warning('请输入账户和密码');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!loginForm.mobile || !loginForm.smsCode) {
|
||||
Message.warning('请输入手机号和验证码');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const validate = await loginFormRef.value.validate();
|
||||
if (!validate) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
// TODO: 调用实际登录接口
|
||||
// const res = await api.login(...)
|
||||
const loginParams = loginType.value === 'account'
|
||||
? { username: loginForm.username, password: loginForm.password, code: loginForm.code, uuid: loginForm.uuid }
|
||||
: { mobile: loginForm.mobile, smsCode: loginForm.smsCode };
|
||||
|
||||
// 模拟登录延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
// const res = await login(loginParams);
|
||||
|
||||
login(loginParams.username, loginParams.code, getRsaCode(loginParams.password))
|
||||
.then(async (res) => {
|
||||
if (res.data.code === 200) {
|
||||
Message.success('登录成功');
|
||||
const { access_token } = res.data.data;
|
||||
const account = useAccountStore();
|
||||
await account.checkIsLogin(access_token, res.data.data);
|
||||
emits('close');
|
||||
return;
|
||||
}
|
||||
Message.error(res.data.msg);
|
||||
formModel.code = '';
|
||||
getCaptchaUrl();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
formModel.code = '';
|
||||
getCaptchaUrl();
|
||||
});
|
||||
|
||||
Message.success('登录成功');
|
||||
// router.push({ name: `Pricing` });
|
||||
window.open(`${import.meta.env.VITE_BASE_URL}Dashboard`, '_blank');
|
||||
emits('close', true); // 关闭弹窗
|
||||
emits('close', true);
|
||||
emits('login-success', { user: 'test' });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
getCaptchaUrl(); // 失败刷新验证码
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const switchToRegister = () => {
|
||||
// 切换到注册模式或跳转
|
||||
emits('go-register');
|
||||
};
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
getCaptchaUrl();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
/* 使用全局样式或穿透样式覆盖 DevUI 默认 Modal 样式 */
|
||||
.tcode-login-modal {
|
||||
:deep(.devui-modal) {
|
||||
width: 600px !important;
|
||||
}
|
||||
.devui-modal__header {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
.devui-modal__body {
|
||||
padding: 0; /* 移除默认内边距,由内部控制 */
|
||||
}
|
||||
.btn-close {
|
||||
z-index: 10; /* 确保关闭按钮在最上层 */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* --- 布局样式 --- */
|
||||
.login-header {
|
||||
text-align: center;
|
||||
padding: 40px 0 20px;
|
||||
|
||||
.logo-img {
|
||||
height: 48px; /* 根据实际 Logo 调整 */
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
.logo-img { height: 48px; width: auto; display: inline-block; }
|
||||
}
|
||||
|
||||
.login-body {
|
||||
padding: 0 50px 40px; /* 两侧留白 */
|
||||
}
|
||||
.login-body { padding: 0 50px 40px; }
|
||||
|
||||
/* --- Tabs 样式 --- */
|
||||
.login-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
.tab-item {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
padding: 10px 30px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: color 0.3s;
|
||||
|
||||
font-size: 16px; color: #666; padding: 10px 30px; cursor: pointer; position: relative;
|
||||
&.active {
|
||||
color: #d12323; /* 红色高亮 */
|
||||
font-weight: 500;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -1px; /* 盖住底边框 */
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background-color: #d12323;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #d12323;
|
||||
color: #d12323; font-weight: 500;
|
||||
&::after { content: ''; position: absolute; bottom: -1px; left: 0; width: 100%; height: 2px; background-color: #d12323; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 表单样式 --- */
|
||||
.login-form {
|
||||
.form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 覆盖 DevUI Input 样式以匹配设计 */
|
||||
:deep(.devui-input__wrapper) {
|
||||
border-radius: 4px;
|
||||
border-color: #ddd;
|
||||
box-shadow: none;
|
||||
|
||||
//&:hover, &.is-focus {
|
||||
// border-color: #d12323; /* 聚焦时红色边框 */
|
||||
//}
|
||||
}
|
||||
|
||||
:deep(.devui-input__inner) {
|
||||
height: 44px; /* 增加输入框高度 */
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 验证码行 */
|
||||
.verify-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.verify-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 图形验证码 */
|
||||
display: flex; gap: 10px; align-items: center;
|
||||
.verify-input { flex: 1; }
|
||||
.captcha-box {
|
||||
width: 100px;
|
||||
height: 44px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
background-color: #f9f9f9;
|
||||
font-size: 18px;
|
||||
letter-spacing: 4px;
|
||||
color: #333;
|
||||
/* 实际使用 img 标签 */
|
||||
}
|
||||
width: 100px; height: 44px; border: 1px solid #ddd; border-radius: 4px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
cursor: pointer; background-color: #f9f9f9; overflow: hidden;
|
||||
|
||||
/* 获取验证码按钮 */
|
||||
.get-code-btn {
|
||||
//color: #d12323 !important;
|
||||
font-size: 14px;
|
||||
padding: 0 10px;
|
||||
|
||||
&:disabled {
|
||||
color: #999 !important;
|
||||
}
|
||||
.captcha-img { width: 100%; height: 30px; object-fit: cover; }
|
||||
.loading-text { font-size: 12px; color: #999; }
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 辅助功能行 --- */
|
||||
.extra-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
|
||||
:deep(.devui-checkbox-label) {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.right-links {
|
||||
.link-btn {
|
||||
//color: #d12323;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 0 8px;
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
margin-top: 10px; margin-bottom: 30px; font-size: 14px; color: #666;
|
||||
}
|
||||
|
||||
///* --- 登录按钮 --- */
|
||||
//.submit-btn {
|
||||
// background-color: #d12323 !important; /* 强制红色背景 */
|
||||
// border-color: #d12323 !important;
|
||||
// color: #fff !important;
|
||||
// font-size: 16px;
|
||||
// height: 48px;
|
||||
// border-radius: 4px;
|
||||
//
|
||||
// &:hover {
|
||||
// background-color: #b01d1d !important;
|
||||
// border-color: #b01d1d !important;
|
||||
// }
|
||||
//}
|
||||
|
||||
/* --- 底部链接 --- */
|
||||
.footer-links {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
|
||||
|
||||
a {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
margin: 0 10px;
|
||||
|
||||
&:hover {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-links {
|
||||
.link-btn {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.divider {
|
||||
margin: 0 8px;
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
/* 覆盖 DevUI FormItem 间距 */
|
||||
:deep(.devui-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
11
src/utils/jsencrypt.ts
Normal file
11
src/utils/jsencrypt.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import JSEncrypt from 'jsencrypt';
|
||||
|
||||
const PUBLIC_KEY =
|
||||
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcXz5g5hNGAOgFOVhiYY8pYlrH3gXmHkYRBqqEHsVaKqjdY9PQbkfSb9VkD78VYwFyTSzMZn5e1A5XXXDTUL3PezflMc/GjvseB87OQ3a6XDHw5tVXiJruc72oN9GKEvh5TjQUzi2S1sTHXg8vdD/niXw+K/icrQFdzSpy1PWc6QIDAQAB';
|
||||
const pubKey = `-----BEGIN PUBLIC KEY-----${PUBLIC_KEY}-----END PUBLIC KEY-----`;
|
||||
|
||||
export default (str: string) => {
|
||||
const encryptStr = new JSEncrypt();
|
||||
encryptStr.setPublicKey(pubKey);
|
||||
return encryptStr.encrypt(str.toString());
|
||||
};
|
||||
@@ -38,12 +38,12 @@ export default (config: any) => {
|
||||
},
|
||||
proxy: {
|
||||
// 配置跨域代理
|
||||
'/gateway/official/u-auth/index/getCaptcha': {
|
||||
// target: 'http://223.76.236.155:20011', // 目标服务器地址
|
||||
target: 'http://222.20.126.217:9700', // 目标服务器地址
|
||||
changeOrigin: true, // 允许跨域
|
||||
rewrite: (path) => path.replace('/gateway/official/u-auth', '/gateway/u-auth') // 重写路径
|
||||
},
|
||||
// '/gateway/official/u-auth/index/getCaptcha': {
|
||||
// // target: 'http://223.76.236.155:20011', // 目标服务器地址
|
||||
// target: 'http://222.20.126.217:9700', // 目标服务器地址
|
||||
// changeOrigin: true, // 允许跨域
|
||||
// rewrite: (path) => path.replace('/gateway/official/u-auth', '/gateway/u-auth') // 重写路径
|
||||
// },
|
||||
'/gateway': {
|
||||
// target: 'http://223.76.236.155:20011', // 目标服务器地址
|
||||
target: 'http://222.20.126.217:10010', // 目标服务器地址
|
||||
|
||||
Reference in New Issue
Block a user