2026-02-26 19:16:33 +08:00
|
|
|
import { useEffect, useState } from 'react'
|
|
|
|
|
import { Card, List, NoticeBar } from 'antd-mobile'
|
|
|
|
|
import { useNavigate } from 'react-router-dom'
|
|
|
|
|
|
|
|
|
|
declare global {
|
|
|
|
|
interface Window {
|
|
|
|
|
tt?: any
|
|
|
|
|
ttjsBridge?: any
|
|
|
|
|
h5sdk?: any
|
|
|
|
|
bridge?: any
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface EnvInfo {
|
|
|
|
|
ua: string
|
|
|
|
|
isInFeishu: boolean
|
|
|
|
|
hasTT: boolean
|
|
|
|
|
hasTTJSBridge: boolean
|
|
|
|
|
hasH5SDK: boolean
|
|
|
|
|
hasBridge: boolean
|
|
|
|
|
ttMethods: string[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function DebugFeishuPage() {
|
|
|
|
|
const navigate = useNavigate()
|
|
|
|
|
const [envInfo, setEnvInfo] = useState<EnvInfo | null>(null)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-26 19:21:01 +08:00
|
|
|
// 延迟检测,等待 JSBridge 注入
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
const ua = navigator.userAgent
|
|
|
|
|
const isInFeishu = ua.includes('Lark') || ua.includes('feishu') || ua.includes('lark')
|
2026-02-26 19:16:33 +08:00
|
|
|
|
2026-02-26 19:21:01 +08:00
|
|
|
const ttMethods = window.tt ? Object.keys(window.tt) : []
|
2026-02-26 19:16:33 +08:00
|
|
|
|
2026-02-26 19:21:01 +08:00
|
|
|
setEnvInfo({
|
|
|
|
|
ua,
|
|
|
|
|
isInFeishu,
|
|
|
|
|
hasTT: !!window.tt,
|
|
|
|
|
hasTTJSBridge: !!window.ttjsBridge,
|
|
|
|
|
hasH5SDK: !!(window as any).h5sdk,
|
|
|
|
|
hasBridge: !!(window as any).bridge,
|
|
|
|
|
ttMethods,
|
|
|
|
|
})
|
2026-02-26 19:16:33 +08:00
|
|
|
|
2026-02-26 19:21:01 +08:00
|
|
|
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)
|
2026-02-26 19:16:33 +08:00
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
const testFeishuLogin = async () => {
|
2026-02-26 19:21:01 +08:00
|
|
|
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)
|
|
|
|
|
},
|
|
|
|
|
})
|
2026-02-26 19:16:33 +08:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 19:21:01 +08:00
|
|
|
// 尝试使用 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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-26 19:16:33 +08:00
|
|
|
|
2026-02-26 19:21:01 +08:00
|
|
|
// 如果都没有,显示详细错误
|
|
|
|
|
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
|
|
|
|
|
)
|
2026-02-26 19:16:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div style={{ padding: '16px', background: '#f5f5f5', minHeight: '100vh' }}>
|
|
|
|
|
<h2>飞书环境调试页面</h2>
|
|
|
|
|
|
|
|
|
|
{envInfo && (
|
|
|
|
|
<List header="环境信息">
|
|
|
|
|
<List.Item extra={envInfo.isInFeishu ? '✅ 是' : '❌ 否'}>
|
|
|
|
|
在飞书客户端内
|
|
|
|
|
</List.Item>
|
|
|
|
|
<List.Item extra={envInfo.hasTT ? '✅ 存在' : '❌ 不存在'}>
|
|
|
|
|
window.tt 对象
|
|
|
|
|
</List.Item>
|
|
|
|
|
<List.Item extra={envInfo.hasTTJSBridge ? '✅ 存在' : '❌ 不存在'}>
|
|
|
|
|
window.ttjsBridge 对象
|
|
|
|
|
</List.Item>
|
|
|
|
|
<List.Item
|
|
|
|
|
extraStyle={{ maxWidth: '200px', fontSize: '12px', wordBreak: 'break-all' }}
|
|
|
|
|
>
|
|
|
|
|
User Agent
|
|
|
|
|
<div style={{ fontSize: '10px', color: '#999' }}>
|
|
|
|
|
{envInfo.ua}
|
|
|
|
|
</div>
|
|
|
|
|
</List.Item>
|
|
|
|
|
<List.Item>
|
|
|
|
|
tt 对象方法 ({envInfo.ttMethods.length} 个)
|
|
|
|
|
<div style={{ fontSize: '10px', color: '#999', textAlign: 'right' }}>
|
|
|
|
|
{envInfo.ttMethods.length > 0 ? envInfo.ttMethods.join(', ') : '(无)'}
|
|
|
|
|
</div>
|
|
|
|
|
</List.Item>
|
|
|
|
|
</List>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<List header="操作">
|
|
|
|
|
<List.Item
|
|
|
|
|
onClick={testFeishuLogin}
|
|
|
|
|
clickable
|
|
|
|
|
arrow
|
|
|
|
|
>
|
|
|
|
|
测试飞书免登
|
|
|
|
|
</List.Item>
|
|
|
|
|
<List.Item
|
|
|
|
|
onClick={() => navigate(-1)}
|
|
|
|
|
clickable
|
|
|
|
|
arrow
|
|
|
|
|
>
|
|
|
|
|
返回
|
|
|
|
|
</List.Item>
|
|
|
|
|
</List>
|
|
|
|
|
|
|
|
|
|
<NoticeBar content="请在飞书客户端中打开此页面进行测试" color="info" />
|
|
|
|
|
|
|
|
|
|
<Card title="使用说明">
|
|
|
|
|
<p>1. 在飞书客户端中发送此链接给自己</p>
|
|
|
|
|
<p>2. 点击链接打开此调试页面</p>
|
|
|
|
|
<p>3. 查看环境信息</p>
|
|
|
|
|
<p>4. 点击"测试飞书免登"按钮</p>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|