import { useMutation, useQuery } from "@tanstack/react-query"; import { toast } from "sonner"; import { Link, useSearchParams } from "react-router-dom"; import { fetchWecomConfig, startWecomBind, unbindWecom, updateNotificationPreferences } from "../api/auth"; import { isApiError } from "../api/types"; import { useAuth } from "../auth/AuthContext"; import { PageHeader } from "../components/common/PageHeader"; import { SectionPanel } from "../components/patterns/SectionPanel"; import { PageScaffold } from "../components/patterns/PageScaffold"; import { Button } from "../components/ui/button"; import { resolveWecomBindNotice, resolveWecomEntryStatus, type WecomNotice, } from "../lib/wecomEntry"; function noticeClasses(tone: WecomNotice["tone"]) { if (tone === "success") { return "border-emerald-200 bg-emerald-50 text-emerald-700"; } if (tone === "warning") { return "border-amber-200 bg-amber-50 text-amber-700"; } return "border-zinc-200 bg-zinc-50 text-zinc-700"; } function maskExternalUserId(value: string) { if (value.length <= 8) { return value; } return `${value.slice(0, 4)}****${value.slice(-4)}`; } function statusTone(status?: string) { if (status === "active") return "badge-success"; if (status === "inactive") return "badge-warning"; return "badge-neutral"; } function resolveProfileError(error: unknown) { if (isApiError(error)) { return `${error.code}: ${error.message}`; } if (error instanceof Error) { return error.message; } return "请求失败,请稍后重试。"; } export function ProfilePage() { const { me, permissions, refreshMe } = useAuth(); const [searchParams] = useSearchParams(); const wecomConfigQuery = useQuery({ queryKey: ["auth", "wecom-config"], queryFn: () => fetchWecomConfig(), staleTime: 60_000, }); const bindMutation = useMutation({ mutationFn: async () => startWecomBind("/settings/profile"), onSuccess: (payload) => { window.location.assign(payload.loginUrl); }, }); const unbindMutation = useMutation({ mutationFn: () => unbindWecom(), onSuccess: () => { window.location.reload(); }, }); const notificationPreferenceMutation = useMutation({ mutationFn: (notificationPushEnabled: boolean) => updateNotificationPreferences({ notificationPushEnabled }), onSuccess: async () => { await refreshMe(); toast.success("外部推送偏好已更新"); }, onError: (error) => { toast.error(resolveProfileError(error)); }, }); const wecomStatus = resolveWecomEntryStatus(wecomConfigQuery.data); const bindNotice = resolveWecomBindNotice(searchParams.get("wecomBind")); const isBound = Boolean(me?.wecomBinding?.externalUserId); return ( {me?.status === "active" ? "账号正常" : "账号状态待确认"}} />
查看完整档案 ) : null } >
姓名
{me?.name ?? "-"}
员工号
{me?.employeeNo ?? "-"}
邮箱
{me?.email ?? "-"}
手机号
{me?.phone ?? "-"}
{me?.id ? (

进入完整档案页后,可按当前权限查看本人绩效、已发放工资条,并编辑自助开放的档案字段。

) : null}

适用于审批待办、报销付款、资产流转等业务提醒。关闭后不会停止站内通知,也不会移除你的业务权限。

{bindNotice ? (
{bindNotice.title}
{bindNotice.description}
) : null}
接入状态
{wecomStatus.label}
{wecomStatus.description}
{wecomStatus.reasonLabels.length ? (
    {wecomStatus.reasonLabels.map((label) => (
  • {label}
  • ))}
) : null}
当前绑定状态
{isBound ? "已绑定" : "未绑定"}
{isBound ? "下次可直接从企业微信工作台进入海音达工作台。" : "未绑定时,企业微信登录会自动回退到账号密码登录。"}
{isBound ? (
绑定标识:{maskExternalUserId(me?.wecomBinding?.externalUserId ?? "")}
绑定时间:{me?.wecomBinding?.createdAt ? new Date(me.wecomBinding.createdAt).toLocaleString() : "-"}
) : null}
组织归属
部门与直属汇报关系由管理员统一维护,当前个人页只展示员工可理解的设置入口,避免把内部 ID 直接暴露给员工。
部门维护状态
{me?.departmentId ? "已关联组织" : "待管理员维护"}
直属汇报关系
{me?.directManagerId ? "已维护" : "待管理员维护"}
{me?.status === "active" ? "active" : me?.status ?? "unknown"} {(me?.roleCodes ?? []).map((role) => ( {role} ))}
权限摘要
{permissions.map((permission) => ( {permission} ))}
); }