datai-vue/src/views/auth/register/index.vue

741 lines
23 KiB
Vue
Raw Normal View History

<template>
<div class="salesforce-login-container">
<div class="login-header">
<h2>Salesforce 认证中心</h2>
<p class="login-description">选择适合您的登录方式连接到 Salesforce</p>
</div>
<!-- 登录表单 -->
<div class="login-section" v-if="!isLoggedIn">
<el-card class="login-card" shadow="hover">
<el-tabs v-model="activeTab" @tab-change="handleTabChange" class="login-tabs">
<!-- OAuth 2.0 登录 -->
<el-tab-pane label="OAuth 2.0" name="oauth2">
<div class="tab-content">
<div class="tab-description">
<h3>OAuth 2.0 认证</h3>
<p>使用标准的 OAuth 2.0 协议进行安全认证</p>
</div>
<el-form
ref="oauth2FormRef"
:model="oauth2Form"
:rules="oauth2Rules"
label-width="120px"
class="login-form"
>
<el-form-item label="授权类型" prop="grantType">
<el-select v-model="oauth2Form.grantType" placeholder="请选择授权类型" style="width: 100%">
<el-option label="密码模式" value="password"></el-option>
<el-option label="客户端凭证模式" value="client_credentials"></el-option>
<el-option label="授权码模式" value="authorization_code"></el-option>
</el-select>
</el-form-item>
<el-form-item label="客户端ID" prop="clientId">
<el-input v-model="oauth2Form.clientId" placeholder="请输入客户端ID"></el-input>
</el-form-item>
<el-form-item label="客户端密钥" prop="clientSecret">
<el-input v-model="oauth2Form.clientSecret" type="password" placeholder="请输入客户端密钥" show-password></el-input>
</el-form-item>
<el-form-item label="用户名" prop="username" v-show="oauth2Form.grantType === 'password'">
<el-input v-model="oauth2Form.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password" v-show="oauth2Form.grantType === 'password'">
<el-input v-model="oauth2Form.password" type="password" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<el-form-item label="安全令牌" prop="securityToken" v-show="oauth2Form.grantType === 'password'">
<el-input v-model="oauth2Form.securityToken" placeholder="请输入安全令牌(可选)"></el-input>
</el-form-item>
<el-form-item label="授权码" prop="code" v-show="oauth2Form.grantType === 'authorization_code'">
<el-input v-model="oauth2Form.code" placeholder="请输入授权码"></el-input>
</el-form-item>
<el-form-item label="State" prop="state" v-show="oauth2Form.grantType === 'authorization_code'">
<el-input v-model="oauth2Form.state" placeholder="请输入state参数"></el-input>
</el-form-item>
<el-form-item class="form-actions">
<el-button type="primary" @click="handleOAuth2Login" :loading="loading" size="large">
<el-icon><Connection /></el-icon>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
<!-- 传统凭据登录 -->
<el-tab-pane label="传统凭据" name="legacy_credential">
<div class="tab-content">
<div class="tab-description">
<h3>传统凭据认证</h3>
<p>使用用户名和密码进行传统登录</p>
</div>
<el-form
ref="legacyFormRef"
:model="legacyForm"
:rules="legacyRules"
label-width="120px"
class="login-form"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="legacyForm.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="legacyForm.password" type="password" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<el-form-item label="安全令牌" prop="securityToken">
<el-input v-model="legacyForm.securityToken" placeholder="请输入安全令牌(可选)"></el-input>
</el-form-item>
<el-form-item class="form-actions">
<el-button type="primary" @click="handleLegacyLogin" :loading="loading" size="large">
<el-icon><User /></el-icon>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
<!-- Session ID 登录 -->
<el-tab-pane label="Session ID" name="session_id">
<div class="tab-content">
<div class="tab-description">
<h3>Session ID 认证</h3>
<p>使用现有的 Session ID 直接登录</p>
</div>
<el-form
ref="sessionIdFormRef"
:model="sessionIdForm"
:rules="sessionIdRules"
label-width="120px"
class="login-form"
>
<el-form-item label="Session ID" prop="sessionId">
<el-input v-model="sessionIdForm.sessionId" placeholder="请输入Session ID" type="textarea" :rows="3"></el-input>
</el-form-item>
<el-form-item class="form-actions">
<el-button type="primary" @click="handleSessionIdLogin" :loading="loading" size="large">
<el-icon><Key /></el-icon>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
<!-- Salesforce CLI 登录 -->
<el-tab-pane label="Salesforce CLI" name="salesforce_cli">
<div class="tab-content">
<div class="tab-description">
<h3>Salesforce CLI 认证</h3>
<p>使用已配置的 Salesforce CLI 凭据登录</p>
</div>
<el-form
ref="cliFormRef"
:model="cliForm"
label-width="120px"
class="login-form"
>
<el-form-item label="组织别名" prop="orgAlias">
<el-input v-model="cliForm.orgAlias" placeholder="请输入组织别名(可选)"></el-input>
</el-form-item>
<el-form-item class="form-actions">
<el-button type="primary" @click="handleCliLogin" :loading="loading" size="large">
<el-icon><Monitor /></el-icon>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
</el-tabs>
</el-card>
</div>
<!-- 登录成功后的会话信息展示 -->
<div v-if="isLoggedIn && sessionInfo" class="session-info-section">
<el-card class="session-card" shadow="hover">
<template #header>
<div class="card-header">
<h3>会话信息</h3>
<el-tag :type="sessionInfo.status === 'active' ? 'success' : 'danger'" size="large">
{{ sessionInfo.status === 'active' ? '活跃' : '非活跃' }}
</el-tag>
</div>
</template>
<el-descriptions :column="2" border class="session-descriptions">
<el-descriptions-item label="会话ID" span="2">
<el-text class="session-id" copyable>{{ sessionInfo.sessionId }}</el-text>
</el-descriptions-item>
<el-descriptions-item label="租户编号">{{ sessionInfo.tenantId }}</el-descriptions-item>
<el-descriptions-item label="用户名">{{ sessionInfo.username }}</el-descriptions-item>
<el-descriptions-item label="登录类型">{{ sessionInfo.loginType }}</el-descriptions-item>
<el-descriptions-item label="会话状态">
<el-tag :type="sessionInfo.status === 'active' ? 'success' : 'danger'">
{{ sessionInfo.status }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="登录时间">{{ sessionInfo.loginTime }}</el-descriptions-item>
<el-descriptions-item label="过期时间">{{ sessionInfo.expireTime }}</el-descriptions-item>
<el-descriptions-item label="最后活动时间">{{ sessionInfo.lastActivityTime }}</el-descriptions-item>
<el-descriptions-item label="登录IP" span="2">{{ sessionInfo.loginIp }}</el-descriptions-item>
<el-descriptions-item label="设备信息" span="2">{{ sessionInfo.deviceInfo }}</el-descriptions-item>
<el-descriptions-item label="浏览器信息" span="2">{{ sessionInfo.browserInfo }}</el-descriptions-item>
<el-descriptions-item label="令牌ID" span="2">
<el-text class="token-id" copyable>{{ sessionInfo.tokenId }}</el-text>
</el-descriptions-item>
</el-descriptions>
<div class="session-actions">
<el-button type="primary" @click="fetchSessionInfo" :loading="loading">
<el-icon><Refresh /></el-icon>
刷新会话信息
</el-button>
<el-button type="danger" @click="logout">
<el-icon><SwitchButton /></el-icon>
退出登录
</el-button>
</div>
</el-card>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { executeLogin as salesforceLogin, getLoginSession as getCurrentSession } from '@/api/auth/register'
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
import { Connection, User, Key, Monitor, Refresh, SwitchButton } from '@element-plus/icons-vue'
// 表单引用
const oauth2FormRef = ref<FormInstance>()
const legacyFormRef = ref<FormInstance>()
const sessionIdFormRef = ref<FormInstance>()
const cliFormRef = ref<FormInstance>()
// 当前激活的标签页
const activeTab = ref('oauth2')
// 加载状态
const loading = ref(false)
// 登录状态
const isLoggedIn = ref(false)
// 会话信息
const sessionInfo = ref<any>(null)
// OAuth2 表单数据
const oauth2Form = reactive({
loginType: 'oauth2',
grantType: 'password',
username: '',
password: '',
securityToken: '',
clientId: '',
clientSecret: '',
code: '',
state: ''
})
// 传统凭据表单数据
const legacyForm = reactive({
loginType: 'legacy_credential',
username: '',
password: '',
securityToken: ''
})
// Session ID 表单数据
const sessionIdForm = reactive({
loginType: 'session_id',
sessionId: ''
})
// CLI 表单数据
const cliForm = reactive({
loginType: 'salesforce_cli',
orgAlias: ''
})
// OAuth2 表单校验规则
const oauth2Rules = reactive<FormRules>({
grantType: [{ required: true, message: '请选择授权类型', trigger: 'change' }],
clientId: [{ required: true, message: '请输入客户端ID', trigger: 'blur' }],
clientSecret: [{ required: true, message: '请输入客户端密钥', trigger: 'blur' }],
username: [{
required: false,
message: '请输入用户名',
trigger: 'blur',
validator: (rule, value, callback) => {
if (oauth2Form.grantType === 'password' && !value) {
callback(new Error('密码模式下用户名为必填项'))
} else {
callback()
}
}
}],
password: [{
required: false,
message: '请输入密码',
trigger: 'blur',
validator: (rule, value, callback) => {
if (oauth2Form.grantType === 'password' && !value) {
callback(new Error('密码模式下密码为必填项'))
} else {
callback()
}
}
}],
code: [{
required: false,
message: '请输入授权码',
trigger: 'blur',
validator: (rule, value, callback) => {
if (oauth2Form.grantType === 'authorization_code' && !value) {
callback(new Error('授权码模式下授权码为必填项'))
} else {
callback()
}
}
}],
state: [{
required: false,
message: '请输入state参数',
trigger: 'blur',
validator: (rule, value, callback) => {
if (oauth2Form.grantType === 'authorization_code' && !value) {
callback(new Error('授权码模式下state参数为必填项'))
} else {
callback()
}
}
}]
})
// 传统凭据表单校验规则
const legacyRules = reactive<FormRules>({
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
})
// Session ID 表单校验规则
const sessionIdRules = reactive<FormRules>({
sessionId: [{ required: true, message: '请输入Session ID', trigger: 'blur' }]
})
// 标签页切换处理
const handleTabChange = () => {
// 清空表单校验状态
oauth2FormRef.value?.clearValidate()
legacyFormRef.value?.clearValidate()
sessionIdFormRef.value?.clearValidate()
cliFormRef.value?.clearValidate()
}
// 通用登录处理函数
const handleLogin = async (formRef: FormInstance | undefined, formData: any, loginType: string) => {
if (!formRef) return
await formRef.validate(async (valid) => {
if (valid) {
loading.value = true
try {
// 处理CLI登录的特殊情况
let loginParams = { ...formData }
if (loginType === 'salesforce_cli' && !loginParams.orgAlias) {
delete loginParams.orgAlias
}
await salesforceLogin(loginParams)
ElMessage.success('登录成功')
await fetchSessionInfo()
} catch (error: any) {
console.error(`${loginType}登录失败:`, error)
const errorMessage = error.response?.data?.message || error.message || '登录失败,请检查您的凭据'
ElMessage.error(errorMessage)
} finally {
loading.value = false
}
}
})
}
// OAuth2 登录处理
const handleOAuth2Login = async () => {
if (!oauth2FormRef.value) return
await oauth2FormRef.value.validate(async (valid) => {
if (valid) {
loading.value = true
try {
// 构造登录参数 - 所有OAuth2模式都需要客户端ID和密钥
const loginParams: any = {
loginType: oauth2Form.loginType,
grantType: oauth2Form.grantType,
clientId: oauth2Form.clientId,
clientSecret: oauth2Form.clientSecret
}
// 根据不同授权类型添加特定参数
if (oauth2Form.grantType === 'password') {
loginParams.username = oauth2Form.username
loginParams.password = oauth2Form.password
// 仅在有值时添加安全令牌
if (oauth2Form.securityToken) {
loginParams.securityToken = oauth2Form.securityToken
}
} else if (oauth2Form.grantType === 'authorization_code') {
loginParams.code = oauth2Form.code
loginParams.state = oauth2Form.state
}
// client_credentials 类型需要 clientId 和 clientSecret已在基础参数中
await salesforceLogin(loginParams)
ElMessage.success('登录成功')
await fetchSessionInfo()
} catch (error: any) {
console.error('OAuth2登录失败:', error)
const errorMessage = error.response?.data?.message || error.message || '登录失败,请检查您的凭据'
ElMessage.error(errorMessage)
} finally {
loading.value = false
}
}
})
}
// 传统凭据登录处理
const handleLegacyLogin = () => handleLogin(legacyFormRef.value, legacyForm, '传统凭据')
// Session ID 登录处理
const handleSessionIdLogin = () => handleLogin(sessionIdFormRef.value, sessionIdForm, 'Session ID')
// CLI 登录处理
const handleCliLogin = () => {
if (!cliFormRef.value) return
loading.value = true
try {
// 如果没有填写组织别名,则删除该字段
const loginParams = { ...cliForm }
if (!loginParams.orgAlias) {
delete loginParams.orgAlias
}
salesforceLogin(loginParams).then(() => {
ElMessage.success('登录成功')
fetchSessionInfo()
}).catch((error: any) => {
console.error('CLI登录失败:', error)
const errorMessage = error.response?.data?.message || error.message || '登录失败请检查您的CLI配置'
ElMessage.error(errorMessage)
}).finally(() => {
loading.value = false
})
} catch (error: any) {
console.error('CLI登录失败:', error)
const errorMessage = error.response?.data?.message || error.message || '登录失败请检查您的CLI配置'
ElMessage.error(errorMessage)
loading.value = false
}
}
// 获取会话信息
const fetchSessionInfo = async () => {
try {
const response = await getCurrentSession()
if (response.code === 200) {
sessionInfo.value = response.data
isLoggedIn.value = true
} else {
ElMessage.error(response.msg || '获取会话信息失败')
isLoggedIn.value = false
sessionInfo.value = null
}
} catch (error: any) {
console.error('获取会话信息失败:', error)
const errorMessage = error.response?.data?.message || error.message || '获取会话信息失败'
ElMessage.error(errorMessage)
isLoggedIn.value = false
sessionInfo.value = null
}
}
// 页面加载时尝试获取会话信息
onMounted(() => {
fetchSessionInfo()
})
// 退出登录
const logout = () => {
ElMessageBox.confirm('确定要退出登录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
isLoggedIn.value = false
sessionInfo.value = null
ElMessage.success('已退出登录')
}).catch(() => {
// 取消退出
})
}
</script>
<style scoped lang="scss">
.salesforce-login-container {
padding: 24px;
max-width: 900px;
margin: 0 auto;
min-height: 100vh;
display: flex;
flex-direction: column;
.login-header {
text-align: center;
margin-bottom: 32px;
h2 {
font-size: 28px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
}
.login-description {
font-size: 16px;
color: #606266;
max-width: 600px;
margin: 0 auto;
}
}
.login-section {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.login-card {
border-radius: 12px;
overflow: hidden;
.login-tabs {
:deep(.el-tabs__header) {
margin-bottom: 24px;
}
:deep(.el-tabs__nav-wrap) {
&::after {
height: 1px;
}
}
:deep(.el-tabs__item) {
font-size: 16px;
font-weight: 500;
padding: 0 24px;
}
}
.tab-content {
padding: 0 8px;
.tab-description {
margin-bottom: 24px;
text-align: center;
h3 {
font-size: 20px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
}
p {
font-size: 14px;
color: #909399;
}
}
.login-form {
max-width: 500px;
margin: 0 auto;
:deep(.el-form-item__label) {
font-weight: 500;
color: #606266;
}
:deep(.el-input__wrapper) {
border-radius: 6px;
}
:deep(.el-select .el-input .el-input__wrapper) {
border-radius: 6px;
}
.form-actions {
margin-top: 32px;
text-align: center;
.el-button {
padding: 12px 32px;
font-size: 16px;
border-radius: 6px;
.el-icon {
margin-right: 8px;
}
}
}
}
}
}
}
.session-info-section {
margin-top: 32px;
.session-card {
border-radius: 12px;
overflow: hidden;
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
h3 {
font-size: 20px;
font-weight: 600;
color: #303133;
margin: 0;
}
}
.session-descriptions {
margin: 24px 0;
:deep(.el-descriptions__label) {
font-weight: 500;
color: #606266;
}
:deep(.el-descriptions__content) {
color: #303133;
}
.session-id, .token-id {
font-family: monospace;
font-size: 13px;
word-break: break-all;
}
}
.session-actions {
display: flex;
justify-content: center;
gap: 16px;
margin-top: 24px;
.el-button {
padding: 10px 24px;
border-radius: 6px;
.el-icon {
margin-right: 8px;
}
}
}
}
}
}
@media (max-width: 768px) {
.salesforce-login-container {
padding: 16px;
.login-header {
h2 {
font-size: 24px;
}
.login-description {
font-size: 14px;
}
}
.login-section {
.login-card {
.login-tabs {
:deep(.el-tabs__item) {
font-size: 14px;
padding: 0 16px;
}
}
.tab-content {
.tab-description {
h3 {
font-size: 18px;
}
p {
font-size: 13px;
}
}
.login-form {
max-width: 100%;
.form-actions {
.el-button {
padding: 10px 24px;
font-size: 14px;
}
}
}
}
}
}
.session-info-section {
.session-card {
.session-descriptions {
:deep(.el-descriptions__label) {
font-size: 13px;
}
:deep(.el-descriptions__content) {
font-size: 13px;
}
}
.session-actions {
flex-direction: column;
align-items: center;
.el-button {
width: 100%;
max-width: 200px;
}
}
}
}
}
}
</style>