R48 修复员工档案入口与合同新增按钮交互
这个提交包含在:
@@ -1006,7 +1006,12 @@ export function EmployeeProfilePage() {
|
||||
<h3 className="text-base font-semibold text-zinc-900">合同列表</h3>
|
||||
<div className="mt-1 text-sm text-zinc-500">状态由终止日期与结束日期自动推导,附件支持上传/下载,active 合同需先终止后删除。</div>
|
||||
</div>
|
||||
<div className="text-sm text-zinc-500">{contracts.length} 份合同</div>
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<div className="text-sm text-zinc-500">{contracts.length} 份合同</div>
|
||||
<Button type="button" variant="secondary" onClick={resetContractEditor}>
|
||||
新增合同
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
@@ -1157,7 +1162,7 @@ export function EmployeeProfilePage() {
|
||||
onClick={() => contractMutation.mutate()}
|
||||
disabled={contractMutation.isPending || !contractForm.contractNo.trim() || !contractForm.startDate || !contractForm.endDate}
|
||||
>
|
||||
{contractMutation.isPending ? "保存中..." : editingContractId ? "保存修改" : "新增合同"}
|
||||
{contractMutation.isPending ? "保存中..." : editingContractId ? "保存修改" : "保存合同"}
|
||||
</Button>
|
||||
{editingContractId ? (
|
||||
<Button type="button" variant="secondary" onClick={resetContractEditor}>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { fetchWecomConfig, startWecomBind, unbindWecom } from "../api/auth";
|
||||
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";
|
||||
@@ -35,8 +37,18 @@ function statusTone(status?: string) {
|
||||
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 } = useAuth();
|
||||
const { me, permissions, refreshMe } = useAuth();
|
||||
const [searchParams] = useSearchParams();
|
||||
const wecomConfigQuery = useQuery({
|
||||
queryKey: ["auth", "wecom-config"],
|
||||
@@ -57,6 +69,16 @@ export function ProfilePage() {
|
||||
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"));
|
||||
@@ -73,7 +95,17 @@ export function ProfilePage() {
|
||||
|
||||
<div className="page-shell-grid">
|
||||
<div className="space-y-6">
|
||||
<SectionPanel title="基本信息" description="员工可直接理解的个人资料与联系方式。">
|
||||
<SectionPanel
|
||||
title="基本信息"
|
||||
description="员工可直接理解的个人资料与联系方式。"
|
||||
actions={
|
||||
me?.id ? (
|
||||
<Button asChild type="button">
|
||||
<Link to={`/people/${me.id}`}>查看完整档案</Link>
|
||||
</Button>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<dl className="grid gap-4 text-sm text-zinc-700 md:grid-cols-2">
|
||||
<div>
|
||||
<dt className="text-zinc-500">姓名</dt>
|
||||
@@ -94,6 +126,33 @@ export function ProfilePage() {
|
||||
</dl>
|
||||
</SectionPanel>
|
||||
|
||||
{me?.id ? (
|
||||
<SectionPanel title="完整员工档案" description="办公地点、紧急联系人、绩效和薪资等员工档案信息在完整档案页维护或查看。">
|
||||
<div className="flex flex-col gap-3 text-sm text-zinc-600 md:flex-row md:items-center md:justify-between">
|
||||
<p>进入完整档案页后,可按当前权限查看本人绩效、已发放工资条,并编辑自助开放的档案字段。</p>
|
||||
<Button asChild type="button" variant="secondary">
|
||||
<Link to={`/people/${me.id}`}>进入完整员工档案</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</SectionPanel>
|
||||
) : null}
|
||||
|
||||
<SectionPanel title="外部通知推送" description="控制是否接收企微等外部渠道推送;关闭后仅保留站内通知,不影响企业微信绑定与工作台登录。">
|
||||
<div className="space-y-3 text-sm text-zinc-600">
|
||||
<label className="flex items-center gap-3 text-zinc-800">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="h-4 w-4 rounded border-zinc-300"
|
||||
checked={Boolean(me?.notificationPushEnabled ?? true)}
|
||||
disabled={!me || notificationPreferenceMutation.isPending}
|
||||
onChange={(event) => notificationPreferenceMutation.mutate(event.target.checked)}
|
||||
/>
|
||||
接收外部渠道推送
|
||||
</label>
|
||||
<p>适用于审批待办、报销付款、资产流转等业务提醒。关闭后不会停止站内通知,也不会移除你的业务权限。</p>
|
||||
</div>
|
||||
</SectionPanel>
|
||||
|
||||
<SectionPanel title="企业微信绑定" description="绑定后可从企业微信工作台直接进入海音达工作台;消息只做提醒与回流,不承接第二套业务录入。">
|
||||
<div className="space-y-4" data-testid="profile-wecom-card">
|
||||
{bindNotice ? (
|
||||
|
||||
在新工单中引用
屏蔽一个用户