feat: 添加飞书 JSBridge SDK 支持
问题: - 移动端飞书 WebView 中 tt 对象没有被注入 - 导致免登功能无法使用 修复: 1. index.html - 引入飞书 H5 JSBridge SDK 2. approval/detail.tsx - 添加对多种飞书 API 的支持 3. debug-feishu.tsx - 更新调试页面,检测所有可能的 API 对象 支持的飞书 API: - window.tt (标准 H5 应用) - window.h5sdk (JSBridge) - window.bridge (JSBridge) - window.ttjsBridge (旧版) 相关文件: - frontend/index.html - frontend/src/pages/approval/detail.tsx - frontend/src/pages/debug-feishu.tsx Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@
|
|||||||
<title>frontend</title>
|
<title>frontend</title>
|
||||||
<!-- 飞书扫码登录 SDK(飞书外扫码登录用) -->
|
<!-- 飞书扫码登录 SDK(飞书外扫码登录用) -->
|
||||||
<script src="https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js"></script>
|
<script src="https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js"></script>
|
||||||
|
<!-- 飞书 H5 JSBridge SDK(飞书内 WebView 免登用) -->
|
||||||
|
<script src="https://lf1-cdn-tos.bytegoofy.com/goofy/lark/op/h5-jsbridge-1.0.3.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -126,20 +126,22 @@ export default function ApprovalDetail() {
|
|||||||
console.log('🔍 tryFeishuLogin 开始')
|
console.log('🔍 tryFeishuLogin 开始')
|
||||||
console.log('📱 isInFeishu:', isInFeishu)
|
console.log('📱 isInFeishu:', isInFeishu)
|
||||||
console.log('🔧 window.tt:', window.tt)
|
console.log('🔧 window.tt:', window.tt)
|
||||||
|
console.log('🔧 window.h5sdk:', (window as any).h5sdk)
|
||||||
|
console.log('🔧 window.bridge:', (window as any).bridge)
|
||||||
|
|
||||||
if (!isInFeishu || !window.tt) {
|
if (!isInFeishu) {
|
||||||
console.log('❌ 不在飞书内或 tt 对象不可用,跳过免登')
|
console.log('❌ 不在飞书内,跳过免登')
|
||||||
resolve(false)
|
resolve(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('🚀 开始调用 tt.requestAuthCode')
|
|
||||||
const appId = 'cli_a8033d607cba500d'
|
const appId = 'cli_a8033d607cba500d'
|
||||||
|
const requestAuthCode = (apiObj: any, source: string) => {
|
||||||
window.tt.requestAuthCode({
|
console.log(`🚀 使用 ${source} 调用 requestAuthCode`)
|
||||||
|
apiObj.requestAuthCode({
|
||||||
appId: appId,
|
appId: appId,
|
||||||
success: async (res: any) => {
|
success: async (res: any) => {
|
||||||
console.log('✅ tt.requestAuthCode 成功:', res)
|
console.log(`✅ ${source}.requestAuthCode 成功:`, res)
|
||||||
console.log('🔑 authCode:', res.code?.substring(0, 30) + '...')
|
console.log('🔑 authCode:', res.code?.substring(0, 30) + '...')
|
||||||
try {
|
try {
|
||||||
console.log('📡 调用后端登录API...')
|
console.log('📡 调用后端登录API...')
|
||||||
@@ -155,12 +157,44 @@ export default function ApprovalDetail() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: (error: any) => {
|
fail: (error: any) => {
|
||||||
console.error('❌ tt.requestAuthCode 失败:', error)
|
console.error(`❌ ${source}.requestAuthCode 失败:`, error)
|
||||||
console.error('❌ 错误详情:', JSON.stringify(error))
|
console.error('❌ 错误详情:', JSON.stringify(error))
|
||||||
Toast.show('免登失败: ' + (error.errorMessage || error.errMsg || '未知错误'))
|
Toast.show('免登失败: ' + (error.errorMessage || error.errMsg || '未知错误'))
|
||||||
resolve(false)
|
resolve(false)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先使用 tt 对象
|
||||||
|
if (window.tt && typeof window.tt.requestAuthCode === 'function') {
|
||||||
|
requestAuthCode(window.tt, 'tt')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用 h5sdk
|
||||||
|
const h5sdk = (window as any).h5sdk
|
||||||
|
if (h5sdk && typeof h5sdk.requestAuthCode === 'function') {
|
||||||
|
requestAuthCode(h5sdk, 'h5sdk')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用 bridge
|
||||||
|
const bridge = (window as any).bridge
|
||||||
|
if (bridge && typeof bridge.requestAuthCode === 'function') {
|
||||||
|
requestAuthCode(bridge, 'bridge')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用 ttjsBridge
|
||||||
|
if (window.ttjsBridge && typeof window.ttjsBridge.requestAuthCode === 'function') {
|
||||||
|
requestAuthCode(window.ttjsBridge, 'ttjsBridge')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有方法都不可用
|
||||||
|
console.log('❌ 所有飞书 API 都不可用')
|
||||||
|
Toast.show('飞书API不可用,请使用其他方式登录')
|
||||||
|
resolve(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export default function DebugFeishuPage() {
|
|||||||
const [envInfo, setEnvInfo] = useState<EnvInfo | null>(null)
|
const [envInfo, setEnvInfo] = useState<EnvInfo | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// 延迟检测,等待 JSBridge 注入
|
||||||
|
setTimeout(() => {
|
||||||
const ua = navigator.userAgent
|
const ua = navigator.userAgent
|
||||||
const isInFeishu = ua.includes('Lark') || ua.includes('feishu') || ua.includes('lark')
|
const isInFeishu = ua.includes('Lark') || ua.includes('feishu') || ua.includes('lark')
|
||||||
|
|
||||||
@@ -45,17 +47,22 @@ export default function DebugFeishuPage() {
|
|||||||
console.log('User Agent:', ua)
|
console.log('User Agent:', ua)
|
||||||
console.log('在飞书中:', isInFeishu)
|
console.log('在飞书中:', isInFeishu)
|
||||||
console.log('window.tt:', window.tt)
|
console.log('window.tt:', window.tt)
|
||||||
|
console.log('window.h5sdk:', (window as any).h5sdk)
|
||||||
|
console.log('window.bridge:', (window as any).bridge)
|
||||||
|
console.log('window.ttjsBridge:', window.ttjsBridge)
|
||||||
console.log('tt 对象方法:', ttMethods)
|
console.log('tt 对象方法:', ttMethods)
|
||||||
|
|
||||||
|
// 检查所有全局对象
|
||||||
|
console.log('所有全局对象:', Object.keys(window).filter(k => k.includes('tt') || k.includes('h5') || k.includes('bridge') || k.includes('lark') || k.includes('feishu')))
|
||||||
|
}, 500)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const testFeishuLogin = async () => {
|
const testFeishuLogin = async () => {
|
||||||
if (!window.tt) {
|
|
||||||
alert('tt 对象不存在,无法测试')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const appId = 'cli_a8033d607cba500d'
|
const appId = 'cli_a8033d607cba500d'
|
||||||
|
|
||||||
|
// 优先使用 tt 对象
|
||||||
|
if (window.tt && typeof window.tt.requestAuthCode === 'function') {
|
||||||
|
console.log('🔧 使用 tt.requestAuthCode')
|
||||||
window.tt.requestAuthCode({
|
window.tt.requestAuthCode({
|
||||||
appId: appId,
|
appId: appId,
|
||||||
success: (res: any) => {
|
success: (res: any) => {
|
||||||
@@ -67,6 +74,64 @@ export default function DebugFeishuPage() {
|
|||||||
console.error('错误:', error)
|
console.error('错误:', error)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用 h5sdk
|
||||||
|
const h5sdk = (window as any).h5sdk
|
||||||
|
if (h5sdk) {
|
||||||
|
console.log('🔧 尝试使用 h5sdk')
|
||||||
|
try {
|
||||||
|
if (typeof h5sdk.requestAuthCode === 'function') {
|
||||||
|
h5sdk.requestAuthCode({
|
||||||
|
appId: appId,
|
||||||
|
success: (res: any) => {
|
||||||
|
alert('✅ h5sdk 获取授权码成功: ' + res.code?.substring(0, 30))
|
||||||
|
console.log('授权码:', res)
|
||||||
|
},
|
||||||
|
fail: (error: any) => {
|
||||||
|
alert('❌ h5sdk 获取授权码失败: ' + JSON.stringify(error))
|
||||||
|
console.error('错误:', error)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('h5sdk 调用失败:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用 bridge
|
||||||
|
const bridge = (window as any).bridge
|
||||||
|
if (bridge) {
|
||||||
|
console.log('🔧 尝试使用 bridge')
|
||||||
|
try {
|
||||||
|
if (typeof bridge.requestAuthCode === 'function') {
|
||||||
|
bridge.requestAuthCode({
|
||||||
|
appId: appId,
|
||||||
|
success: (res: any) => {
|
||||||
|
alert('✅ bridge 获取授权码成功: ' + res.code?.substring(0, 30))
|
||||||
|
console.log('授权码:', res)
|
||||||
|
},
|
||||||
|
fail: (error: any) => {
|
||||||
|
alert('❌ bridge 获取授权码失败: ' + JSON.stringify(error))
|
||||||
|
console.error('错误:', error)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('bridge 调用失败:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果都没有,显示详细错误
|
||||||
|
alert('❌ 未找到可用的飞书 API\n\n' +
|
||||||
|
'window.tt: ' + !!window.tt + '\n' +
|
||||||
|
'window.h5sdk: ' + !!(window as any).h5sdk + '\n' +
|
||||||
|
'window.bridge: ' + !!(window as any).bridge + '\n' +
|
||||||
|
'window.ttjsBridge: ' + !!window.ttjsBridge
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user