feat: 工作台概览优化 - 人力成本展示、解聘记录完善、数据准确性修复
- 解聘列表显示所有状态记录(含已撤销/已完成) - 月度解聘人数排除CANCELLED和DRAFT状态 - 工作台新增当月人力成本和年度累计成本卡片 - 年度累计成本包含当前月未归档数据 - 企业总成本公式加入加班费 - 统计卡片月加班费改为工资条数量,避免与动态区重复 - 本月工作动态与风险分布改为左右两列布局 - 人力成本区域优化:2列网格+突出总成本
This commit is contained in:
@@ -116,15 +116,36 @@ export default function Dashboard() {
|
||||
|
||||
if (!data) return null
|
||||
|
||||
const payroll = data.payrollSummary
|
||||
const activities = data.monthlyActivities
|
||||
const yearCost = data.yearCostSummary
|
||||
|
||||
const stats = [
|
||||
{ label: '在管员工', value: data.stats.employeeCount, icon: Users, color: 'text-primary' },
|
||||
{ label: '高风险', value: data.stats.highRiskCount, icon: AlertTriangle, color: 'text-danger' },
|
||||
{ label: '待办事项', value: data.stats.todoCount, icon: CheckSquare, color: 'text-warning' },
|
||||
{ label: '月加班费', value: fmt(data.stats.monthlyOvertimePay), icon: DollarSign, color: 'text-safe' },
|
||||
{ label: '工资条', value: payroll?.payslipCount ?? 0, icon: Receipt, color: 'text-safe' },
|
||||
]
|
||||
|
||||
const payroll = data.payrollSummary
|
||||
const activities = data.monthlyActivities
|
||||
// 当月人力成本
|
||||
const monthCostItems = [
|
||||
{ label: '工资总额', value: payroll?.totalPay ?? 0, color: 'text-primary' },
|
||||
{ label: '企业社保', value: payroll?.socialOrg ?? 0, color: 'text-blue-600' },
|
||||
{ label: '企业公积金', value: payroll?.housingOrg ?? 0, color: 'text-purple-600' },
|
||||
{ label: '加班费', value: payroll?.overtimePay ?? 0, color: 'text-safe' },
|
||||
{ label: '补偿金', value: payroll?.severancePay ?? 0, color: 'text-orange-600' },
|
||||
]
|
||||
const monthTotalCost = payroll?.orgTotalCost ?? 0
|
||||
|
||||
// 年度累计人力成本
|
||||
const yearCostItems = [
|
||||
{ label: '工资总额', value: yearCost?.totalPay ?? 0, color: 'text-primary' },
|
||||
{ label: '企业社保', value: yearCost?.socialOrg ?? 0, color: 'text-blue-600' },
|
||||
{ label: '企业公积金', value: yearCost?.housingOrg ?? 0, color: 'text-purple-600' },
|
||||
{ label: '加班费', value: yearCost?.overtimePay ?? 0, color: 'text-safe' },
|
||||
{ label: '补偿金', value: yearCost?.severancePay ?? 0, color: 'text-orange-600' },
|
||||
]
|
||||
const yearTotalCost = yearCost?.orgTotalCost ?? 0
|
||||
|
||||
const activityItems = [
|
||||
{ label: '新签合同', value: activities?.newContracts ?? 0, icon: FileText, color: 'text-primary' },
|
||||
@@ -213,6 +234,49 @@ export default function Dashboard() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 人力成本概览:当月 + 年度累计 */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
|
||||
{/* 当月人力成本 */}
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h2 className="font-medium flex items-center gap-1.5"><Wallet className="w-4 h-4 text-primary" />当月人力成本</h2>
|
||||
<span className="text-xs text-gray-400">{payroll?.month}</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||
{monthCostItems.map((item) => (
|
||||
<div key={item.label} className="flex items-center justify-between">
|
||||
<span className="text-xs text-gray-500">{item.label}</span>
|
||||
<span className={`text-xs font-semibold ${item.color}`}>{fmt(item.value)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-3 pt-2 border-t flex items-center justify-between bg-danger/5 -mx-4 -mb-4 px-4 py-2.5 rounded-b-lg">
|
||||
<span className="text-sm font-medium text-gray-700">企业总成本</span>
|
||||
<span className="text-lg font-bold text-danger">{fmt(monthTotalCost)}</span>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* 年度累计人力成本 */}
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h2 className="font-medium flex items-center gap-1.5"><TrendingUp className="w-4 h-4 text-primary" />年度累计成本</h2>
|
||||
<span className="text-xs text-gray-400">{yearCost?.year}年</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||
{yearCostItems.map((item) => (
|
||||
<div key={item.label} className="flex items-center justify-between">
|
||||
<span className="text-xs text-gray-500">{item.label}</span>
|
||||
<span className={`text-xs font-semibold ${item.color}`}>{fmt(item.value)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-3 pt-2 border-t flex items-center justify-between bg-danger/5 -mx-4 -mb-4 px-4 py-2.5 rounded-b-lg">
|
||||
<span className="text-sm font-medium text-gray-700">年度企业总成本</span>
|
||||
<span className="text-lg font-bold text-danger">{fmt(yearTotalCost)}</span>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 合同到期预警 */}
|
||||
{expiringContracts && expiringContracts.length > 0 && (
|
||||
<Link to="/roster?contractStatus=expiring">
|
||||
@@ -240,13 +304,15 @@ export default function Dashboard() {
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{/* 本月工作动态 + 风险分布 左右两列 */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
|
||||
{/* 本月工作动态 */}
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h2 className="font-medium flex items-center gap-1.5"><Briefcase className="w-4 h-4" />本月工作动态</h2>
|
||||
<span className="text-xs text-gray-500">{activities?.month}</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
|
||||
{activityItems.map((item) => {
|
||||
const Icon = item.icon
|
||||
return (
|
||||
@@ -353,6 +419,7 @@ export default function Dashboard() {
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user