feat: R27-2 R27-5 优化企微入口与 Portal 体验
这个提交包含在:
@@ -0,0 +1,22 @@
|
||||
const WECOM_WEBVIEW_PATTERN = /(wxwork|wecom|wechatwork)/i;
|
||||
const ENTERPRISE_IM_PATTERN = /(wxwork|wecom|wechatwork|dingtalk|aliapp\(dingtalk\))/i;
|
||||
|
||||
export function canUseWindow() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
export function matchesMedia(query: string) {
|
||||
return canUseWindow() && typeof window.matchMedia === "function" && window.matchMedia(query).matches;
|
||||
}
|
||||
|
||||
export function readUserAgent() {
|
||||
return canUseWindow() ? window.navigator.userAgent : "";
|
||||
}
|
||||
|
||||
export function isWecomWebView(userAgent = readUserAgent()) {
|
||||
return WECOM_WEBVIEW_PATTERN.test(userAgent);
|
||||
}
|
||||
|
||||
export function isEnterpriseMessengerContainer(userAgent = readUserAgent()) {
|
||||
return ENTERPRISE_IM_PATTERN.test(userAgent);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import type { WecomEntryConfig } from "../api/auth";
|
||||
|
||||
export type WecomNoticeTone = "info" | "warning" | "success";
|
||||
|
||||
export type WecomNotice = {
|
||||
tone: WecomNoticeTone;
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
const STATUS_REASON_LABELS: Record<string, string> = {
|
||||
wecom_disabled: "管理员尚未启用企业微信接入",
|
||||
entry_disabled: "企业微信工作台入口尚未正式开放",
|
||||
oauth_disabled: "企业微信 OAuth 尚未启用",
|
||||
corp_id_missing: "未配置 CorpID",
|
||||
agent_id_missing: "未配置 AgentID",
|
||||
redirect_uri_missing: "未配置 OAuth 回调地址",
|
||||
};
|
||||
|
||||
export function resolveWecomStatusReasonLabels(statusReasons: string[]) {
|
||||
return statusReasons.map((reason) => STATUS_REASON_LABELS[reason] ?? reason);
|
||||
}
|
||||
|
||||
export function resolveWecomEntryStatus(config?: WecomEntryConfig | null) {
|
||||
if (!config) {
|
||||
return {
|
||||
label: "检测中",
|
||||
tone: "info" as const,
|
||||
description: "正在读取企业微信接入状态。",
|
||||
reasonLabels: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (config.status === "ready") {
|
||||
return {
|
||||
label: "已启用",
|
||||
tone: "success" as const,
|
||||
description: "员工可从企业微信工作台直接进入 OA,也可在个人设置里维护绑定。",
|
||||
reasonLabels: [],
|
||||
};
|
||||
}
|
||||
|
||||
const reasonLabels = resolveWecomStatusReasonLabels(config.statusReasons);
|
||||
|
||||
if (config.bindEnabled && !config.entryEnabled) {
|
||||
return {
|
||||
label: "入口未开放",
|
||||
tone: "warning" as const,
|
||||
description: "当前可先完成绑定,企业微信工作台直达入口尚未正式开放。",
|
||||
reasonLabels,
|
||||
};
|
||||
}
|
||||
|
||||
if (config.status === "misconfigured") {
|
||||
return {
|
||||
label: "配置不完整",
|
||||
tone: "warning" as const,
|
||||
description: "请管理员补齐 CorpID、AgentID 与回调地址后再开放企业微信入口。",
|
||||
reasonLabels,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
label: "未启用",
|
||||
tone: "info" as const,
|
||||
description: "当前未启用企业微信入口,仍可使用账号密码登录。",
|
||||
reasonLabels,
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveWecomLoginNotice(value: string | null): WecomNotice | null {
|
||||
if (value === "unbound") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "当前企业微信账号尚未绑定",
|
||||
description: "请先用账号密码登录,再到个人设置完成绑定。",
|
||||
};
|
||||
}
|
||||
|
||||
if (value === "invalid") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "企业微信登录状态已失效",
|
||||
description: "请重新从企业微信工作台进入,或改用账号密码登录。",
|
||||
};
|
||||
}
|
||||
|
||||
if (value === "expired") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "企业微信登录已超时",
|
||||
description: "请重新从企业微信工作台进入 OA。",
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resolveWecomBindNotice(value: string | null): WecomNotice | null {
|
||||
if (value === "success") {
|
||||
return {
|
||||
tone: "success",
|
||||
title: "企业微信绑定成功",
|
||||
description: "下次可直接从企业微信工作台进入 OA。",
|
||||
};
|
||||
}
|
||||
|
||||
if (value === "conflict") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "该企业微信账号已绑定其他员工",
|
||||
description: "请联系管理员核对后再处理。",
|
||||
};
|
||||
}
|
||||
|
||||
if (value === "employee_inactive") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "当前账号已停用",
|
||||
description: "停用账号无法绑定企业微信,请联系管理员。",
|
||||
};
|
||||
}
|
||||
|
||||
if (value === "invalid") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "本次绑定状态无效",
|
||||
description: "请回到个人设置后重新发起绑定。",
|
||||
};
|
||||
}
|
||||
|
||||
if (value === "expired") {
|
||||
return {
|
||||
tone: "warning",
|
||||
title: "本次绑定已超时",
|
||||
description: "请回到个人设置后重新发起绑定。",
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function buildWecomLoginUrl(loginUrl: string, returnTo: string) {
|
||||
const baseOrigin = typeof window !== "undefined" ? window.location.origin : "http://127.0.0.1";
|
||||
const url = new URL(loginUrl, baseOrigin);
|
||||
url.searchParams.set("returnTo", returnTo);
|
||||
return url.origin === baseOrigin ? `${url.pathname}${url.search}` : url.toString();
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户