Files
inquiry_robot/inquiry-backend/src/views/inquiry/login/index.vue
T

130 lines
4.2 KiB
Vue

<script lang="ts" setup>
/**
* 询价后台登录页:视觉 1:1 对齐 admin/LoginView(居中白卡片 + 品牌区,无验证码)。
* 鉴权走 Jeecg loginApi;主账 inquiry 配置关闭图形验证码(jeecg.loginCaptchaEnabled=false)。
*
* 禁止写死 admin/123456:退出后再进登录页会误显示测试账号。
* 仅记住上次成功登录的账号(不存密码),方便换人登录时改账号。
*/
import { reactive, ref, toRaw } from 'vue';
import { ConfigProvider, message } from 'ant-design-vue';
import { useUserStore } from '/@/store/modules/user';
import ProtoIcon from '/@/views/inquiry/components/ProtoIcon.vue';
import '/@/views/inquiry/styles/admin-prototype.css';
import '/@/views/inquiry/styles/admin-fidelity.css';
const LAST_USERNAME_KEY = 'inquiry_admin_last_username';
function readLastUsername(): string {
try {
return String(localStorage.getItem(LAST_USERNAME_KEY) || '').trim();
} catch {
return '';
}
}
function rememberUsername(username: string) {
try {
localStorage.setItem(LAST_USERNAME_KEY, username);
} catch {
/* 隐私模式等写失败时忽略 */
}
}
const userStore = useUserStore();
const loading = ref(false);
const form = reactive({
username: readLastUsername(),
password: '',
});
const themeToken = {
colorPrimary: '#155eef',
borderRadius: 8,
fontFamily: 'Inter, PingFang SC, Microsoft YaHei, Noto Sans SC, system-ui, sans-serif',
fontSize: 11,
controlHeight: 34,
controlHeightLG: 40,
colorText: '#172033',
colorTextSecondary: '#667085',
colorBorder: '#d9e2ef',
};
async function onSubmit() {
if (!form.username.trim() || !form.password.trim()) {
message.warning('请输入账号和密码');
return;
}
loading.value = true;
try {
const username = form.username.trim();
const { userInfo } = await userStore.login(
toRaw({
username,
password: form.password,
// 主账已关验证码;仍传空字段以兼容 LoginParams 类型
captcha: '',
checkKey: '',
mode: 'none',
goHome: true,
})
);
if (userInfo) {
rememberUsername(username);
// 成功后清空密码,避免浏览器后退/再进登录页时残留明文
form.password = '';
message.success(`登录成功,欢迎 ${userInfo.realname || userInfo.username}`);
}
} catch (e: any) {
message.error(e?.message || '登录失败');
} finally {
loading.value = false;
}
}
</script>
<template>
<ConfigProvider :theme="{ token: themeToken }">
<div class="login-page inquiry-login-page">
<div class="login-card">
<div class="login-brand">
<div class="login-brand-mark">
<ProtoIcon name="bot" :size="22" />
</div>
<h1>友通达智能体运营后台</h1>
<p>管理询价工单、人员配置与系统权限</p>
</div>
<a-form :model="form" layout="vertical" @finish="onSubmit">
<a-form-item label="账号" name="username" :rules="[{ required: true, message: '请输入账号' }]">
<a-input v-model:value="form.username" size="large" placeholder="请输入账号" allow-clear autocomplete="username" />
</a-form-item>
<a-form-item label="密码" name="password" :rules="[{ required: true, message: '请输入密码' }]">
<a-input-password v-model:value="form.password" size="large" placeholder="请输入密码" autocomplete="current-password" />
</a-form-item>
<a-button type="primary" html-type="submit" size="large" block :loading="loading"> 登录 </a-button>
</a-form>
</div>
</div>
</ConfigProvider>
</template>
<style scoped>
.inquiry-login-page :deep(.ant-form-item-label > label) {
font-size: 11px;
font-weight: 700;
color: #344054;
}
.login-brand-mark {
width: 56px;
height: 56px;
border-radius: 14px;
display: grid;
place-items: center;
color: #fff;
background: linear-gradient(145deg, #1d4ed8, #0f172a);
box-shadow: 0 10px 24px rgba(21, 94, 239, 0.28);
}
</style>