fix: portal端token过期后自动跳转登录页,避免显示空数据

- portalAxios 401 响应拦截器:清除 token 并跳转 /portal/login
- PortalLayoutWrapper:检查 token 是否存在,不存在则跳转登录页
- 排除 /portal/login 和 /portal/auto-login 页面避免重复跳转

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-17 15:06:46 +08:00
parent c66ea290eb
commit 5196d7c80a
23 changed files with 812 additions and 74 deletions
+23 -2
View File
@@ -89,6 +89,8 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
phone: profile.phone || '',
hireDate: profile.hireDate?.toString().slice(0, 10) || '',
monthlySalary: profile.monthlySalary || '',
baseSalary: profile.baseSalary != null ? profile.baseSalary : '',
performanceSalary: profile.performanceSalary != null ? profile.performanceSalary : '0',
emergencyContact: profile.emergencyContact || '',
emergencyPhone: profile.emergencyPhone || '',
address: profile.address || '',
@@ -171,6 +173,8 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
phone: form.phone || undefined,
hireDate: new Date(form.hireDate).toISOString(),
monthlySalary: String(form.monthlySalary),
baseSalary: String(form.baseSalary),
performanceSalary: String(form.performanceSalary || '0'),
emergencyContact: form.emergencyContact || undefined,
emergencyPhone: form.emergencyPhone || undefined,
address: form.address || undefined,
@@ -235,7 +239,9 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
: []),
]
const salaryFields = [
{ label: '月工资', value: `¥${fmt(profile.monthlySalary)}` },
{ label: '月工资', value: profile.baseSalary != null || profile.performanceSalary != null
? `¥${fmt(profile.monthlySalary)}(基本 ¥${fmt(profile.baseSalary || 0)} + 绩效 ¥${fmt(profile.performanceSalary || 0)}`
: `¥${fmt(profile.monthlySalary)}` },
{ label: '紧急联系人', value: profile.emergencyContact || '未填写' },
{ label: '紧急联系电话', value: profile.emergencyPhone || '未填写' },
{ label: '住址', value: profile.address || '未填写' },
@@ -378,7 +384,22 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
<div><Label></Label><Select value={form.education} onChange={(e) => setForm({ ...form, education: e.target.value })}><option value=""></option><option value="博士"></option><option value="硕士"></option><option value="本科"></option><option value="大专"></option><option value="高中"></option><option value="其他"></option></Select></div>
<div><Label>/</Label><Input value={form.position} onChange={(e) => setForm({ ...form, position: e.target.value })} placeholder="如:前端工程师" /></div>
<div><Label></Label><Input type="date" value={form.hireDate} onChange={(e) => setForm({ ...form, hireDate: e.target.value })} /></div>
<div><Label></Label><Input type="number" value={form.monthlySalary} onChange={(e) => setForm({ ...form, monthlySalary: Number(e.target.value) })} /></div>
<div>
<Label></Label>
<Input type="number" value={form.baseSalary} onChange={(e) => {
const base = parseFloat(e.target.value) || 0
const perf = parseFloat(form.performanceSalary) || 0
setForm({ ...form, baseSalary: e.target.value, monthlySalary: base + perf })
}} placeholder="元" />
</div>
<div>
<Label></Label>
<Input type="number" value={form.performanceSalary} onChange={(e) => {
const perf = parseFloat(e.target.value) || 0
const base = parseFloat(form.baseSalary) || 0
setForm({ ...form, performanceSalary: e.target.value, monthlySalary: base + perf })
}} placeholder="可为0" />
</div>
<div><Label></Label><Input value={form.emergencyContact} onChange={(e) => setForm({ ...form, emergencyContact: e.target.value })} placeholder="选填" /></div>
<div><Label></Label><Input value={form.emergencyPhone} onChange={(e) => setForm({ ...form, emergencyPhone: e.target.value })} placeholder="选填" /></div>
<div className="md:col-span-2"><Label></Label><Input value={form.address} onChange={(e) => setForm({ ...form, address: e.target.value })} placeholder="选填" /></div>