diff --git a/app/dingtalk-entry/route.ts b/app/dingtalk-entry/route.ts index eab7c47..79fe7eb 100644 --- a/app/dingtalk-entry/route.ts +++ b/app/dingtalk-entry/route.ts @@ -4,7 +4,11 @@ import { getAuthSessionCookieCandidates, resolveSecureAuthCookieFromRequest, } from '@/lib/auth-cookie' -import { DINGTALK_DIRECT_LOGIN_SOURCE, buildDingtalkOAuthUrl } from '@/lib/dingtalk-oauth' +import { + DINGTALK_DIRECT_LOGIN_SOURCE, + buildDingtalkOAuthUrl, + getDingtalkOAuthClientId, +} from '@/lib/dingtalk-oauth' import { getConfiguredDingtalkCorpId, normalizeDingtalkCorpId, @@ -83,18 +87,58 @@ function createH5LoginPage({ if (status) status.textContent = text; } - function showError(message) { + function stringifyError(error) { + if (!error) return ''; + if (typeof error === 'string') return error; + if (error.message) return String(error.message); + if (error.errorMessage) return String(error.errorMessage); + if (error.errMsg) return String(error.errMsg); + if (error.errmsg) return String(error.errmsg); + try { + return JSON.stringify(error); + } catch (e) { + return String(error); + } + } + + function appendFallbackLink() { + if (!status) return; + status.appendChild(document.createElement('br')); + status.appendChild(document.createElement('br')); + var link = document.createElement('a'); + link.href = fallbackOAuthUrl; + link.textContent = '改用网页授权登录'; + status.appendChild(link); + } + + function showError(message, detail) { if (status) { status.textContent = message + '。请返回钉钉重新打开通知,或联系管理员检查钉钉免登配置。'; - status.appendChild(document.createElement('br')); - status.appendChild(document.createElement('br')); - var link = document.createElement('a'); - link.href = fallbackOAuthUrl; - link.textContent = '改用网页授权登录'; - status.appendChild(link); + if (detail) { + status.appendChild(document.createElement('br')); + status.appendChild(document.createTextNode('错误详情:' + String(detail).slice(0, 180))); + } + appendFallbackLink(); } } + function fallbackToOAuth(message, error) { + var detail = stringifyError(error); + console.log('DingTalk H5 login fallback:', message, detail || error || ''); + if (status) { + status.textContent = message + ',正在改用网页授权登录...'; + if (detail) { + status.appendChild(document.createElement('br')); + status.appendChild(document.createTextNode('错误详情:' + detail.slice(0, 180))); + } + appendFallbackLink(); + } + + setTimeout(function () { + window.location.replace(fallbackOAuthUrl); + }, 900); + } + window.__failDingtalkLogin = showError; function completeProfile(user) { @@ -136,6 +180,70 @@ function createH5LoginPage({ }); } + function resolveAuthCode(result) { + return result && (result.code || result.authCode || result.auth_code); + } + + function requestAuthCodeWithFallback(dd, previousError) { + if (dd.getAuthCode) { + setStatus('正在尝试钉钉新版免登接口...'); + try { + var promiseResult = dd.getAuthCode({ corpId: corpId }); + if (promiseResult && typeof promiseResult.then === 'function') { + promiseResult + .then(function (result) { + var code = resolveAuthCode(result); + if (!code) { + fallbackToOAuth('钉钉新版免登接口未返回授权码', result || previousError); + return; + } + submitCode(code); + }) + .catch(function (error) { + fallbackToOAuth('钉钉免登授权失败', error || previousError); + }); + return; + } + + var directCode = resolveAuthCode(promiseResult); + if (directCode) { + submitCode(directCode); + return; + } + } catch (error) { + fallbackToOAuth('钉钉免登授权失败', error || previousError); + return; + } + } + + if (dd.requestAuthCode) { + setStatus('正在尝试钉钉备用免登接口...'); + try { + dd.requestAuthCode({ + corpId: corpId, + clientId: ${stringifyForInlineScript(getDingtalkOAuthClientId())}, + onSuccess: function (result) { + var code = resolveAuthCode(result); + if (!code) { + fallbackToOAuth('钉钉备用免登接口未返回授权码', result || previousError); + return; + } + submitCode(code); + }, + onFail: function (error) { + fallbackToOAuth('钉钉免登授权失败', error || previousError); + } + }); + return; + } catch (error) { + fallbackToOAuth('钉钉免登授权失败', error || previousError); + return; + } + } + + fallbackToOAuth('钉钉免登授权失败', previousError); + } + window.__startDingtalkLogin = function () { if (started) return; started = true; @@ -143,19 +251,19 @@ function createH5LoginPage({ var dd = window.dd; if (!dd || !dd.ready || !dd.runtime || !dd.runtime.permission) { - showError('当前页面未检测到钉钉客户端环境'); + fallbackToOAuth('当前页面未检测到钉钉客户端环境'); return; } var readyTimer = setTimeout(function () { - showError('钉钉免登初始化超时'); + fallbackToOAuth('钉钉免登初始化超时'); }, 15000); if (dd.error) { dd.error(function (error) { console.log('DingTalk JSAPI error:', error); clearTimeout(readyTimer); - showError('钉钉免登初始化失败'); + fallbackToOAuth('钉钉免登初始化失败', error); }); } @@ -173,7 +281,7 @@ function createH5LoginPage({ }, onFail: function (error) { console.log('requestAuthCode failed:', error); - showError('钉钉免登授权失败'); + requestAuthCodeWithFallback(dd, error); } }); }); @@ -187,7 +295,7 @@ function createH5LoginPage({ ]; var scriptIndex = 0; var loadTimer = setTimeout(function () { - if (!started) showError('钉钉免登组件加载超时'); + if (!started) fallbackToOAuth('钉钉免登组件加载超时'); }, 15000); function loadDingtalkScript() { @@ -206,7 +314,7 @@ function createH5LoginPage({ } clearTimeout(loadTimer); - showError('钉钉 JSAPI 加载失败'); + fallbackToOAuth('钉钉 JSAPI 加载失败'); }; document.head.appendChild(script); }