feat: 飞书登录支持多租户和用户工号管理
后端改动: - FeishuService: 从飞书用户信息获取 tenant_key 和手机号 - FeishuService: 新增 user_sn 表工号分配机制 - FeishuService: 优先使用 enterprise_email,支持手机号 - AuthController: 飞书免登支持 company 参数 前端改动: - FeishuAutoLogin: 支持多租户 company 参数 - login/index: 支持 redirect 参数和已登录检测 - QRCodeLogin: 支持多租户参数传递 - router: 新增路由守卫和参数处理 - api.ts: 优化飞书登录 API 调用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -92,13 +92,37 @@ export default function QRCodeLogin({ visible, onClose }: QRCodeLoginProps) {
|
||||
|
||||
console.log('🔍 window.QRLogin:', !!window.QRLogin)
|
||||
|
||||
// 从 URL 获取 company 参数(支持两种方式:直接参数或从 redirect 中提取)
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
let companyParam = urlParams.get('company')
|
||||
|
||||
// 如果当前 URL 没有 company,尝试从 redirect 参数中获取
|
||||
if (!companyParam) {
|
||||
const redirect = urlParams.get('redirect')
|
||||
if (redirect) {
|
||||
try {
|
||||
const redirectUrl = new URL(redirect, window.location.origin)
|
||||
companyParam = redirectUrl.searchParams.get('company')
|
||||
console.log('🔍 从 redirect URL 中提取的 company 参数:', companyParam)
|
||||
} catch (e) {
|
||||
console.log('⚠️ 无法解析 redirect URL:', redirect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔍 最终使用的 company 参数:', companyParam)
|
||||
|
||||
// 生成登录会话
|
||||
const requestBody: any = {}
|
||||
if (companyParam) {
|
||||
// 如果有 company 参数,传递给后端
|
||||
requestBody.company = companyParam
|
||||
}
|
||||
|
||||
const response = await fetch('/api/v1/auth/qrcode-login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
tenant_key: '14e7bc0fe5985740',
|
||||
}),
|
||||
body: JSON.stringify(requestBody),
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
@@ -21,12 +21,38 @@ declare global {
|
||||
|
||||
export default function Login() {
|
||||
const navigate = useNavigate()
|
||||
const { login } = useUserStore()
|
||||
const { login, user } = useUserStore()
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [environment, setEnvironment] = useState<'feishu' | 'external' | null>(null)
|
||||
const [showQRCode, setShowQRCode] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
// 首先检查是否已登录
|
||||
const token = localStorage.getItem('token')
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const redirect = urlParams.get('redirect')
|
||||
|
||||
console.log('🔐 登录页检查:', { hasToken: !!token, hasUser: !!user, redirect })
|
||||
|
||||
// 如果有 token,说明已登录
|
||||
if (token) {
|
||||
console.log('✅ 检测到 token,用户已登录')
|
||||
// 如果有 redirect 参数,跳转到目标页面
|
||||
if (redirect) {
|
||||
console.log('✅ 跳转到 redirect 页面:', redirect)
|
||||
window.location.href = redirect
|
||||
return
|
||||
}
|
||||
// 否则跳转到 dashboard
|
||||
console.log('✅ 跳转到 dashboard')
|
||||
navigate('/dashboard')
|
||||
return
|
||||
}
|
||||
|
||||
// 没有token,继续登录流程
|
||||
console.log('⚠️ 未检测到 token,显示登录页面')
|
||||
setLoading(false)
|
||||
|
||||
// 监听飞书登录成功事件
|
||||
const handleFeishuLoginSuccess = ((e: any) => {
|
||||
console.log('🎉 收到飞书登录成功事件:', e.detail)
|
||||
@@ -39,7 +65,7 @@ export default function Login() {
|
||||
return () => {
|
||||
window.removeEventListener('feishu-login-success', handleFeishuLoginSuccess)
|
||||
}
|
||||
}, [])
|
||||
}, [user, login, navigate])
|
||||
|
||||
useEffect(() => {
|
||||
// 打印详细的环境信息
|
||||
@@ -103,7 +129,20 @@ export default function Login() {
|
||||
console.log('🔍 window.tt:', window.tt)
|
||||
console.log('🔍 window.tt 类型:', typeof window.tt)
|
||||
|
||||
const appId = 'cli_a8033d607cba500d'
|
||||
// 从 URL 获取 company 参数(可能来自当前 URL 或 redirect URL)
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
let companyParam = urlParams.get('company')
|
||||
console.log('🔍 URL 中的 company 参数:', companyParam)
|
||||
|
||||
// 如果当前 URL 没有 company,尝试从 redirect 参数中获取
|
||||
if (!companyParam) {
|
||||
const redirect = urlParams.get('redirect')
|
||||
if (redirect) {
|
||||
const redirectUrl = new URL(redirect, window.location.origin)
|
||||
companyParam = redirectUrl.searchParams.get('company')
|
||||
console.log('🔍 从 redirect URL 中提取的 company 参数:', companyParam)
|
||||
}
|
||||
}
|
||||
|
||||
// 详细检查 tt 对象
|
||||
if (window.tt) {
|
||||
@@ -137,10 +176,10 @@ export default function Login() {
|
||||
|
||||
// 尝试调用 requestAuthCode
|
||||
try {
|
||||
console.log('🔧 调用 tt.requestAuthCode,appId:', appId)
|
||||
console.log('🔧 调用 tt.requestAuthCode,company:', companyParam)
|
||||
|
||||
// 不传 appId,让飞书自动选择(后端会根据 company 参数处理)
|
||||
window.tt.requestAuthCode({
|
||||
appId: appId,
|
||||
success: (res: any) => {
|
||||
console.log('✅ 成功获取授权码:', res)
|
||||
console.log('✅ code:', res.code?.substring(0, 30))
|
||||
@@ -198,11 +237,28 @@ export default function Login() {
|
||||
// 处理飞书登录
|
||||
const handleFeishuLogin = async (authCode: string) => {
|
||||
try {
|
||||
// 从 URL 获取 app_id 参数
|
||||
// 从 URL 获取参数
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
let companyParam = urlParams.get('company')
|
||||
const urlAppId = urlParams.get('app_id')
|
||||
|
||||
console.log('🔍 URL 中的 app_id:', urlAppId)
|
||||
// 如果当前 URL 没有 company,尝试从 redirect 参数中获取
|
||||
if (!companyParam) {
|
||||
const redirect = urlParams.get('redirect')
|
||||
if (redirect) {
|
||||
try {
|
||||
const redirectUrl = new URL(redirect, window.location.origin)
|
||||
companyParam = redirectUrl.searchParams.get('company')
|
||||
console.log('🔍 从 redirect URL 中提取的 company 参数:', companyParam)
|
||||
} catch (e) {
|
||||
console.log('⚠️ 无法解析 redirect URL:', redirect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔍 URL 中的参数:')
|
||||
console.log(' - app_id:', urlAppId)
|
||||
console.log(' - company:', companyParam)
|
||||
|
||||
const response = await fetch('/api/v1/auth/feishu-login', {
|
||||
method: 'POST',
|
||||
@@ -210,6 +266,7 @@ export default function Login() {
|
||||
body: JSON.stringify({
|
||||
auth_code: authCode,
|
||||
app_id: urlAppId || undefined, // 如果 URL 有 app_id 就传递
|
||||
company: companyParam || undefined, // 传递 company 参数
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -224,6 +281,7 @@ export default function Login() {
|
||||
const redirect = urlParams.get('redirect')
|
||||
if (redirect) {
|
||||
console.log('🔗 登录成功,跳转到:', redirect)
|
||||
// redirect 参数可能包含 ?company=xxx,需要直接跳转
|
||||
window.location.href = redirect
|
||||
} else {
|
||||
navigate('/dashboard')
|
||||
|
||||
Reference in New Issue
Block a user