From 88e027bcdaf708f93dd8c30a3edb5ea5d6b95f4a Mon Sep 17 00:00:00 2001 From: selfrelease Date: Sat, 1 Aug 2026 08:15:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BE=85=E5=8A=9E=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E2=80=94=201)actionUrl=E4=BB=8E/contracts?= =?UTF-8?q?=E6=94=B9=E4=B8=BA/roster(=E6=97=A0=E6=AD=A4=E8=B7=AF=E7=94=B1)?= =?UTF-8?q?=202)Roster=E9=A1=B5=E9=9D=A2=E8=AF=BB=E5=8F=96employee?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=87=AA=E5=8A=A8=E6=90=9C=E7=B4=A2=E5=B9=B6?= =?UTF-8?q?=E6=89=93=E5=BC=80=E5=91=98=E5=B7=A5=E8=AF=A6=E6=83=85=203)?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=95=B0=E6=8D=AE=E5=BA=93281=E6=9D=A1?= =?UTF-8?q?=E5=B7=B2=E6=9C=89riskItem=E7=9A=84actionUrl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/services/risk.service.ts | 12 ++++++------ frontend/src/pages/Roster.tsx | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/backend/src/services/risk.service.ts b/backend/src/services/risk.service.ts index 8400f5d..1e8da3f 100644 --- a/backend/src/services/risk.service.ts +++ b/backend/src/services/risk.service.ts @@ -167,7 +167,7 @@ export async function detectContractRisks(orgId: string) { level: 'HIGH', title: `${emp.name}入职${Math.round(days / 30)}个月未签合同,已视为无固定期限`, description: `入职日期 ${emp.hireDate.toISOString().slice(0, 10)},超过1年未签订书面合同,法律上已视为无固定期限劳动合同。`, - actionUrl: `/contracts?employee=${encodeURIComponent(emp.name)}`, + actionUrl: `/roster?employee=${encodeURIComponent(emp.name)}`, }) } else if (days > 30) { risks.push({ @@ -176,7 +176,7 @@ export async function detectContractRisks(orgId: string) { level: 'HIGH', title: `${emp.name}入职${Math.round(days / 30)}个月未签合同`, description: `入职日期 ${emp.hireDate.toISOString().slice(0, 10)},超过30天未签订书面合同,需尽快补签。`, - actionUrl: `/contracts?employee=${encodeURIComponent(emp.name)}`, + actionUrl: `/roster?employee=${encodeURIComponent(emp.name)}`, }) } else { risks.push({ @@ -185,7 +185,7 @@ export async function detectContractRisks(orgId: string) { level: 'LOW', title: `${emp.name}入职${Math.round(days / 30)}个月,尚未签合同`, description: `入职日期 ${emp.hireDate.toISOString().slice(0, 10)},30天内需签订书面合同。`, - actionUrl: `/contracts?employee=${encodeURIComponent(emp.name)}`, + actionUrl: `/roster?employee=${encodeURIComponent(emp.name)}`, }) } continue @@ -200,7 +200,7 @@ export async function detectContractRisks(orgId: string) { level: 'HIGH', title: `${emp.name}的合同已到期${Math.abs(daysToExpire)}天未续签`, description: `合同到期日 ${latestContract.endDate.toISOString().slice(0, 10)},已过期未续签。`, - actionUrl: `/contracts?employee=${encodeURIComponent(emp.name)}`, + actionUrl: `/roster?employee=${encodeURIComponent(emp.name)}`, }) } else if (daysToExpire <= 30) { risks.push({ @@ -209,7 +209,7 @@ export async function detectContractRisks(orgId: string) { level: 'MEDIUM', title: `${emp.name}的合同即将到期(${daysToExpire}天)`, description: `合同到期日 ${latestContract.endDate.toISOString().slice(0, 10)},需提前准备续签或终止。`, - actionUrl: `/contracts?employee=${encodeURIComponent(emp.name)}`, + actionUrl: `/roster?employee=${encodeURIComponent(emp.name)}`, }) } } @@ -230,7 +230,7 @@ export async function detectContractRisks(orgId: string) { level: 'MEDIUM', title: `${emp.name}试用期${latestContract.probationMonths}个月可能不合法`, description: `${contractMonths}个月合同试用期最多${maxProbation}个月,当前${latestContract.probationMonths}个月超出法定上限。`, - actionUrl: `/contracts?employee=${encodeURIComponent(emp.name)}`, + actionUrl: `/roster?employee=${encodeURIComponent(emp.name)}`, }) } } diff --git a/frontend/src/pages/Roster.tsx b/frontend/src/pages/Roster.tsx index 048dac1..8b299da 100644 --- a/frontend/src/pages/Roster.tsx +++ b/frontend/src/pages/Roster.tsx @@ -1,4 +1,5 @@ -import { useState, useMemo } from 'react' +import { useState, useMemo, useEffect } from 'react' +import { useSearchParams } from 'react-router-dom' import { toast } from 'sonner' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { useConfirm } from '../hooks/useConfirm' @@ -20,6 +21,7 @@ import { ImportSettings } from './Settings' export default function Roster() { const queryClient = useQueryClient() const confirm = useConfirm() + const [searchParams, setSearchParams] = useSearchParams() const [selectedId, setSelectedId] = useState(null) const [search, setSearch] = useState('') const debouncedSearch = useDebouncedValue(search, 300) @@ -67,6 +69,18 @@ export default function Roster() { }) const pagination = rosterData?.pagination || { page, pageSize, total: 0, totalPages: 0 } + // 从 URL query 参数自动定位员工(从待办跳转时) + useEffect(() => { + const emp = searchParams.get('employee') + if (emp) { + setSearch(emp) + // 搜索结果加载后自动打开第一个匹配的员工 + if (!isLoading && employees.length > 0 && !selectedId) { + setSelectedId(employees[0].id) + } + } + }, [searchParams, isLoading, employees, selectedId]) + const addMutation = useMutation({ mutationFn: (data: any) => api.post('/employees', data), onSuccess: () => {