多组织选择修复
This commit is contained in:
parent
d450bec1d7
commit
ebbab98a41
@ -248,11 +248,20 @@ export default function Page() {
|
||||
if (data.isGoogleEnabled) setIsGoogleEnabled(true);
|
||||
if (data.isGoogleConfigured) setIsGoogleConfigured(true);
|
||||
if (data.dingTalkAppKey) setDingTalkAppKey(data.dingTalkAppKey);
|
||||
if (Array.isArray(data.organizations)) {
|
||||
const rawOrganizations = Array.isArray(data.organizations)
|
||||
? data.organizations
|
||||
: Array.isArray(data.dingTalkOrganizations)
|
||||
? data.dingTalkOrganizations
|
||||
: [];
|
||||
|
||||
if (rawOrganizations.length > 0) {
|
||||
setDingTalkOrganizations(
|
||||
data.organizations
|
||||
.map((org: { name?: string }) => org.name)
|
||||
.filter((name: string | undefined): name is string => !!name),
|
||||
rawOrganizations
|
||||
.map((org: { name?: string } | string) =>
|
||||
typeof org === "string" ? org : org.name,
|
||||
)
|
||||
.filter((name: string | undefined): name is string => Boolean(name?.trim()))
|
||||
.map((name: string) => name.trim()),
|
||||
);
|
||||
}
|
||||
if (data.isRegistrationEnabled !== undefined) {
|
||||
@ -445,8 +454,10 @@ export default function Page() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 多组织:点击时展开/收起选择菜单(hover 时也会展开)
|
||||
setShowOrgMenu((prev) => !prev);
|
||||
// 多组织:直接打开弹窗中的组织列表,避免悬浮菜单被页面层级覆盖
|
||||
setDingTalkIframeSrc("");
|
||||
setShowDingTalkModal(true);
|
||||
setShowOrgMenu(false);
|
||||
};
|
||||
|
||||
// 关闭钉钉登录弹窗
|
||||
|
||||
@ -36,6 +36,7 @@ export async function GET() {
|
||||
dingTalkAppKey: "",
|
||||
dingTalkAppSecret: "", // 即使是空的,非管理员也不应该看到这个字段名,但因为是空字符串,问题不大
|
||||
dingTalkOrganizations: [],
|
||||
organizations: [],
|
||||
isDingTalkEnabled: false,
|
||||
isGoogleEnabled: false,
|
||||
googleClientId: "",
|
||||
@ -52,6 +53,11 @@ export async function GET() {
|
||||
}
|
||||
|
||||
if (isAdmin) {
|
||||
const organizations =
|
||||
settings.dingTalkOrganizations?.map((org) => ({
|
||||
name: org.name,
|
||||
})) ?? [];
|
||||
|
||||
return jsonNoStore({
|
||||
...settings,
|
||||
googleClientId: resolvedGoogleClientId,
|
||||
@ -59,6 +65,7 @@ export async function GET() {
|
||||
authUrl: resolvedAuthUrl,
|
||||
isGoogleConfigured,
|
||||
dingTalkOrganizations: settings.dingTalkOrganizations ?? [],
|
||||
organizations,
|
||||
isEmailVerificationEnabled: settings.isEmailVerificationEnabled,
|
||||
emailVerificationExpiresMinutes: settings.emailVerificationExpiresMinutes,
|
||||
resendApiKey: settings.resendApiKey || "",
|
||||
@ -87,6 +94,7 @@ export async function GET() {
|
||||
isEmailServiceConfigured: Boolean(
|
||||
(settings.resendApiKey || "").trim() && (settings.resendFromEmail || "").trim()
|
||||
),
|
||||
dingTalkOrganizations: organizations,
|
||||
organizations,
|
||||
// 不返回 dingTalkAppSecret 以及各组织的密钥
|
||||
});
|
||||
|
||||
@ -29,9 +29,9 @@ export async function GET(request: Request) {
|
||||
}
|
||||
|
||||
// 动态构建回调地址
|
||||
const host = request.headers.get("host");
|
||||
const protocol = request.headers.get("x-forwarded-proto") || "http";
|
||||
const baseUrl = `${protocol}://${host}`;
|
||||
// 优先使用 AUTH_URL 环境变量,确保使用正确的公网域名
|
||||
const requestUrl = new URL(request.url);
|
||||
const baseUrl = process.env.AUTH_URL || requestUrl.origin;
|
||||
const redirectUri = `${baseUrl}/dingtalk-callback.html`;
|
||||
|
||||
// 使用组织名称作为 state,便于回调时选择对应的配置
|
||||
|
||||
@ -139,6 +139,8 @@ type PublicAuthSettings = {
|
||||
isGoogleEnabled?: boolean;
|
||||
isGoogleConfigured?: boolean;
|
||||
isRegistrationEnabled?: boolean;
|
||||
organizations?: Array<{ name?: string } | string>;
|
||||
dingTalkOrganizations?: Array<{ name?: string } | string>;
|
||||
};
|
||||
|
||||
type ContactConfig = {
|
||||
@ -362,6 +364,7 @@ export function LovartHome({
|
||||
const [loginEmail, setLoginEmail] = useState("");
|
||||
const [loginPassword, setLoginPassword] = useState("");
|
||||
const [isLoggingIn, setIsLoggingIn] = useState(false);
|
||||
const [showDingTalkOrgMenu, setShowDingTalkOrgMenu] = useState(false);
|
||||
const [showImageEditor, setShowImageEditor] = useState(false);
|
||||
const [editorImageUrl, setEditorImageUrl] = useState("");
|
||||
const [tutorialDialogOpen, setTutorialDialogOpen] = useState(false);
|
||||
@ -663,6 +666,18 @@ export function LovartHome({
|
||||
const canUseGoogleLogin = Boolean(
|
||||
authSettingsData?.isGoogleEnabled && authSettingsData?.isGoogleConfigured
|
||||
);
|
||||
const dingTalkOrganizations = useMemo(() => {
|
||||
const raw = Array.isArray(authSettingsData?.organizations)
|
||||
? authSettingsData.organizations
|
||||
: Array.isArray(authSettingsData?.dingTalkOrganizations)
|
||||
? authSettingsData.dingTalkOrganizations
|
||||
: [];
|
||||
|
||||
return raw
|
||||
.map((org) => (typeof org === "string" ? org : org?.name || ""))
|
||||
.map((name) => name.trim())
|
||||
.filter(Boolean);
|
||||
}, [authSettingsData?.organizations, authSettingsData?.dingTalkOrganizations]);
|
||||
const canUseDingTalkLogin = Boolean(authSettingsData?.isDingTalkEnabled);
|
||||
const canUseRegistration = authSettingsData?.isRegistrationEnabled !== false;
|
||||
const hasThirdPartyLoginOptions = canUseGoogleLogin || canUseDingTalkLogin;
|
||||
@ -691,6 +706,7 @@ export function LovartHome({
|
||||
if (!loginDialogOpen) {
|
||||
setIsLoggingIn(false);
|
||||
setLoginPassword("");
|
||||
setShowDingTalkOrgMenu(false);
|
||||
}
|
||||
}, [loginDialogOpen]);
|
||||
|
||||
@ -903,11 +919,27 @@ export function LovartHome({
|
||||
await signIn("google", { callbackUrl: "/" });
|
||||
};
|
||||
|
||||
const startDingTalkLoginForOrg = (orgName: string) => {
|
||||
setLoginDialogOpen(false);
|
||||
window.location.href = `/api/auth/dingtalk/login?org=${encodeURIComponent(orgName)}`;
|
||||
};
|
||||
|
||||
const handleDingTalkLogin = () => {
|
||||
if (!canUseDingTalkLogin) {
|
||||
toast.error("钉钉登录未启用");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dingTalkOrganizations.length > 1) {
|
||||
setShowDingTalkOrgMenu((prev) => !prev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dingTalkOrganizations.length === 1) {
|
||||
startDingTalkLoginForOrg(dingTalkOrganizations[0] as string);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoginDialogOpen(false);
|
||||
window.location.href = "/api/auth/dingtalk/login";
|
||||
};
|
||||
@ -2122,13 +2154,29 @@ export function LovartHome({
|
||||
</button>
|
||||
) : null}
|
||||
{canUseDingTalkLogin ? (
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-black/10 text-[15px] font-medium text-black hover:bg-black/[0.03]"
|
||||
onClick={handleDingTalkLogin}
|
||||
>
|
||||
使用钉钉
|
||||
</button>
|
||||
<div className="relative">
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-black/10 text-[15px] font-medium text-black hover:bg-black/[0.03]"
|
||||
onClick={handleDingTalkLogin}
|
||||
>
|
||||
使用钉钉
|
||||
</button>
|
||||
{dingTalkOrganizations.length > 1 && showDingTalkOrgMenu ? (
|
||||
<div className="absolute left-0 right-0 top-full z-30 mt-2 max-h-60 overflow-auto rounded-xl border border-black/10 bg-white p-1.5 shadow-xl">
|
||||
{dingTalkOrganizations.map((org) => (
|
||||
<button
|
||||
key={org}
|
||||
type="button"
|
||||
className="flex w-full items-center justify-between rounded-lg px-3 py-2 text-left text-[14px] text-black hover:bg-black/[0.04]"
|
||||
onClick={() => startDingTalkLoginForOrg(org)}
|
||||
>
|
||||
<span>{org}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="my-2 border-t border-black/10" />
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user