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:
root
2026-02-26 19:21:01 +08:00
parent f31abf2c68
commit 7e57e8720b
3 changed files with 160 additions and 59 deletions
+96 -31
View File
@@ -26,47 +26,112 @@ export default function DebugFeishuPage() {
const [envInfo, setEnvInfo] = useState<EnvInfo | null>(null)
useEffect(() => {
const ua = navigator.userAgent
const isInFeishu = ua.includes('Lark') || ua.includes('feishu') || ua.includes('lark')
// 延迟检测,等待 JSBridge 注入
setTimeout(() => {
const ua = navigator.userAgent
const isInFeishu = ua.includes('Lark') || ua.includes('feishu') || ua.includes('lark')
const ttMethods = window.tt ? Object.keys(window.tt) : []
const ttMethods = window.tt ? Object.keys(window.tt) : []
setEnvInfo({
ua,
isInFeishu,
hasTT: !!window.tt,
hasTTJSBridge: !!window.ttjsBridge,
hasH5SDK: !!(window as any).h5sdk,
hasBridge: !!(window as any).bridge,
ttMethods,
})
setEnvInfo({
ua,
isInFeishu,
hasTT: !!window.tt,
hasTTJSBridge: !!window.ttjsBridge,
hasH5SDK: !!(window as any).h5sdk,
hasBridge: !!(window as any).bridge,
ttMethods,
})
console.log('=== 飞书环境调试 ===')
console.log('User Agent:', ua)
console.log('在飞书中:', isInFeishu)
console.log('window.tt:', window.tt)
console.log('tt 对象方法:', ttMethods)
console.log('=== 飞书环境调试 ===')
console.log('User Agent:', ua)
console.log('在飞书中:', isInFeishu)
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('所有全局对象:', Object.keys(window).filter(k => k.includes('tt') || k.includes('h5') || k.includes('bridge') || k.includes('lark') || k.includes('feishu')))
}, 500)
}, [])
const testFeishuLogin = async () => {
if (!window.tt) {
alert('tt 对象不存在,无法测试')
const appId = 'cli_a8033d607cba500d'
// 优先使用 tt 对象
if (window.tt && typeof window.tt.requestAuthCode === 'function') {
console.log('🔧 使用 tt.requestAuthCode')
window.tt.requestAuthCode({
appId: appId,
success: (res: any) => {
alert('✅ 获取授权码成功: ' + res.code?.substring(0, 30))
console.log('授权码:', res)
},
fail: (error: any) => {
alert('❌ 获取授权码失败: ' + JSON.stringify(error))
console.error('错误:', error)
},
})
return
}
const appId = 'cli_a8033d607cba500d'
// 尝试使用 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)
}
}
window.tt.requestAuthCode({
appId: appId,
success: (res: any) => {
alert('✅ 获取授权码成功: ' + res.code?.substring(0, 30))
console.log('授权码:', res)
},
fail: (error: any) => {
alert('❌ 获取授权码失败: ' + JSON.stringify(error))
console.error('错误:', error)
},
})
// 尝试使用 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 (