55 lines
1.9 KiB
TypeScript

import dd from "dingtalk-jsapi";
import { getDingTalkConfig, loginWithDingTalk } from "@/api/auth";
import type { AuthTokenData } from "@/types/auth";
declare global {
interface Window {
dingtalk?: { platform?: { invokeAPI?: unknown } };
DingTalkJSBridge?: unknown;
}
}
export function isDingTalkContainer() {
if (typeof window === "undefined" || typeof navigator === "undefined")
return false;
const userAgent =
navigator.userAgent ||
(navigator as Navigator & { swuserAgent?: string }).swuserAgent ||
"";
return Boolean(
/DingTalk|dingtalk-win|dd-web/i.test(userAgent) ||
window.DingTalkJSBridge ||
window.dingtalk?.platform?.invokeAPI ||
// DingTalk desktop can expose its container identity through window.name
// even when the embedded browser omits DingTalk from userAgent.
/dingtalk/i.test(window.name || ""),
);
}
export async function waitForDingTalkContainer(timeoutMs = 5000) {
if (isDingTalkContainer()) return true;
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
await new Promise((resolve) => window.setTimeout(resolve, 100));
if (isDingTalkContainer()) return true;
}
return false;
}
export async function authenticateWithDingTalk(): Promise<AuthTokenData> {
if (!(await waitForDingTalkContainer()))
throw new Error("请从钉钉工作台打开此应用");
const configResponse = await getDingTalkConfig();
const config = configResponse.data.data;
if (!config) throw new Error("钉钉免登配置不完整");
const result = await dd.runtime.permission.requestAuthCode({
corpId: config.corpId,
});
const authCode = result?.code;
if (!authCode) throw new Error("钉钉未返回免登授权码");
const response = await loginWithDingTalk(authCode);
if (!response.data.data) throw new Error("钉钉登录响应为空");
return response.data.data;
}