fix: HR系统优化批次1 - P0/P1问题修复
P0-3: 修复合同状态判断逻辑,有合同记录但signDate为null时不再误判未签 P0-5: 修复参保城市默认北京问题,导入和预览均改为null P0-11: 添加全局ErrorBoundary防止白屏,三处布局均包裹 P1-2: 合同附件改为可选,允许先保存再补充上传 P1-7.2: 排班弹窗增加员工搜索(姓名/部门) P1-8.2: 加班费导入支持Excel(xlsx/xls)格式,兼容中英文列名 P1-9: 社保/公积金基数月度办理支持逐人修改,后端返回recordId
This commit is contained in:
@@ -1048,9 +1048,9 @@ export default function SocialInsurance() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{add.map((i: any) => <MonthlyRow key={`sa-${city}-${i.employeeId}`} item={i} type="add" />)}
|
||||
{sub.map((i: any) => <MonthlyRow key={`ss-${city}-${i.employeeId}`} item={i} type="sub" />)}
|
||||
{normal.map((i: any) => <MonthlyRow key={`sn-${city}-${i.employeeId}`} item={i} type="normal" />)}
|
||||
{add.map((i: any) => <MonthlyRow key={`sa-${city}-${i.employeeId}`} item={i} type="add" onCorrected={handleMonthlyProcess} />)}
|
||||
{sub.map((i: any) => <MonthlyRow key={`ss-${city}-${i.employeeId}`} item={i} type="sub" onCorrected={handleMonthlyProcess} />)}
|
||||
{normal.map((i: any) => <MonthlyRow key={`sn-${city}-${i.employeeId}`} item={i} type="normal" onCorrected={handleMonthlyProcess} />)}
|
||||
</tbody>
|
||||
{(add.length > 0 || normal.length > 0) && (
|
||||
<tfoot>
|
||||
@@ -1090,9 +1090,9 @@ export default function SocialInsurance() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{add.map((i: any) => <MonthlyHousingRow key={`ha-${city}-${i.employeeId}`} item={i} type="add" />)}
|
||||
{sub.map((i: any) => <MonthlyHousingRow key={`hs-${city}-${i.employeeId}`} item={i} type="sub" />)}
|
||||
{normal.map((i: any) => <MonthlyHousingRow key={`hn-${city}-${i.employeeId}`} item={i} type="normal" />)}
|
||||
{add.map((i: any) => <MonthlyHousingRow key={`ha-${city}-${i.employeeId}`} item={i} type="add" onCorrected={handleMonthlyProcess} />)}
|
||||
{sub.map((i: any) => <MonthlyHousingRow key={`hs-${city}-${i.employeeId}`} item={i} type="sub" onCorrected={handleMonthlyProcess} />)}
|
||||
{normal.map((i: any) => <MonthlyHousingRow key={`hn-${city}-${i.employeeId}`} item={i} type="normal" onCorrected={handleMonthlyProcess} />)}
|
||||
</tbody>
|
||||
{(add.length > 0 || normal.length > 0) && (
|
||||
<tfoot>
|
||||
@@ -1146,19 +1146,58 @@ export default function SocialInsurance() {
|
||||
)
|
||||
}
|
||||
|
||||
/** 月度办理社保行组件(可展开查看各险种明细) */
|
||||
function MonthlyRow({ item: i, type }: { item: any; type: 'add' | 'sub' | 'normal' }) {
|
||||
/** 月度办理社保行组件(可展开查看各险种明细,支持修改基数) */
|
||||
function MonthlyRow({ item: i, type, onCorrected }: { item: any; type: 'add' | 'sub' | 'normal'; onCorrected?: () => void }) {
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const [editing, setEditing] = useState(false)
|
||||
const [editBase, setEditBase] = useState(i.base?.toString() || '')
|
||||
const typeLabel = type === 'add' ? (i.changeType === 'CITY_CHANGE' ? '新增(城市变更)' : '新增') : type === 'sub' ? (i.changeType === 'CITY_CHANGE' ? '减员(城市变更)' : '减员') : '正常'
|
||||
const typeClass = type === 'add' ? 'bg-green-50 text-safe' : type === 'sub' ? 'bg-red-50 text-danger' : 'bg-gray-100 text-gray-500'
|
||||
const d = i.detail
|
||||
|
||||
const correctMutation = useMutation({
|
||||
mutationFn: (data: { base: number }) => api.put(`/social/records/social/${i.recordId}/correct`, data),
|
||||
onSuccess: () => {
|
||||
setEditing(false)
|
||||
toast.success('基数已修改')
|
||||
onCorrected?.()
|
||||
},
|
||||
onError: () => toast.error('修改失败'),
|
||||
})
|
||||
|
||||
const handleSaveBase = () => {
|
||||
const val = Number(editBase) || 0
|
||||
if (val <= 0) { toast.error('基数必须大于0'); return }
|
||||
correctMutation.mutate({ base: val })
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<tr className="border-b last:border-0 hover:bg-gray-50 cursor-pointer" onClick={() => setExpanded(!expanded)}>
|
||||
<td className="py-1.5">{i.name} {d && <span className="text-gray-300 text-xs">{expanded ? '▾' : '▸'}</span>}</td>
|
||||
<td className="py-1.5 text-gray-500">{i.department}</td>
|
||||
<td className="py-1.5"><span className={`px-2 py-0.5 rounded text-xs ${typeClass}`}>{typeLabel}</span></td>
|
||||
<td className="py-1.5 text-right">¥{fmt(i.base)}</td>
|
||||
<td className="py-1.5 text-right">
|
||||
{editing ? (
|
||||
<span onClick={(e) => e.stopPropagation()} className="inline-flex items-center gap-1">
|
||||
<Input type="number" step="0.01" min="0" className="!w-24 text-right text-xs" value={editBase}
|
||||
onChange={(e) => setEditBase(e.target.value)} autoFocus />
|
||||
<button className="text-xs text-primary hover:underline" onClick={handleSaveBase} disabled={correctMutation.isPending}>
|
||||
{correctMutation.isPending ? '...' : '保存'}
|
||||
</button>
|
||||
<button className="text-xs text-gray-400 hover:underline" onClick={() => { setEditing(false); setEditBase(i.base?.toString() || '') }}>取消</button>
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1">
|
||||
¥{fmt(i.base)}
|
||||
{i.recordId && type !== 'sub' && (
|
||||
<button className="text-xs text-gray-400 hover:text-primary" onClick={(e) => { e.stopPropagation(); setEditing(true); setEditBase(i.base?.toString() || '') }}>
|
||||
修改
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-1.5 text-right text-danger">{d ? `¥${fmt(d.totalOrg)}` : '-'}</td>
|
||||
<td className="py-1.5 text-right text-warning">{d ? `¥${fmt(d.totalEmp)}` : '-'}</td>
|
||||
<td className="py-1.5 text-right font-medium text-primary">{d ? `¥${fmt(d.total)}` : '-'}</td>
|
||||
@@ -1196,17 +1235,56 @@ function MonthlyRow({ item: i, type }: { item: any; type: 'add' | 'sub' | 'norma
|
||||
)
|
||||
}
|
||||
|
||||
/** 月度办理公积金行组件 */
|
||||
function MonthlyHousingRow({ item: i, type }: { item: any; type: 'add' | 'sub' | 'normal' }) {
|
||||
/** 月度办理公积金行组件(支持修改基数) */
|
||||
function MonthlyHousingRow({ item: i, type, onCorrected }: { item: any; type: 'add' | 'sub' | 'normal'; onCorrected?: () => void }) {
|
||||
const [editing, setEditing] = useState(false)
|
||||
const [editBase, setEditBase] = useState(i.base?.toString() || '')
|
||||
const typeLabel = type === 'add' ? (i.changeType === 'CITY_CHANGE' ? '新增(城市变更)' : '新增') : type === 'sub' ? (i.changeType === 'CITY_CHANGE' ? '减员(城市变更)' : '减员') : '正常'
|
||||
const typeClass = type === 'add' ? 'bg-green-50 text-safe' : type === 'sub' ? 'bg-red-50 text-danger' : 'bg-gray-100 text-gray-500'
|
||||
const d = i.detail
|
||||
|
||||
const correctMutation = useMutation({
|
||||
mutationFn: (data: { base: number }) => api.put(`/social/records/housing/${i.recordId}/correct`, data),
|
||||
onSuccess: () => {
|
||||
setEditing(false)
|
||||
toast.success('基数已修改')
|
||||
onCorrected?.()
|
||||
},
|
||||
onError: () => toast.error('修改失败'),
|
||||
})
|
||||
|
||||
const handleSaveBase = () => {
|
||||
const val = Number(editBase) || 0
|
||||
if (val <= 0) { toast.error('基数必须大于0'); return }
|
||||
correctMutation.mutate({ base: val })
|
||||
}
|
||||
|
||||
return (
|
||||
<tr className="border-b last:border-0 hover:bg-gray-50">
|
||||
<td className="py-1.5">{i.name}</td>
|
||||
<td className="py-1.5 text-gray-500">{i.department}</td>
|
||||
<td className="py-1.5"><span className={`px-2 py-0.5 rounded text-xs ${typeClass}`}>{typeLabel}</span></td>
|
||||
<td className="py-1.5 text-right">¥{fmt(i.base)}</td>
|
||||
<td className="py-1.5 text-right">
|
||||
{editing ? (
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<Input type="number" step="0.01" min="0" className="!w-24 text-right text-xs" value={editBase}
|
||||
onChange={(e) => setEditBase(e.target.value)} autoFocus />
|
||||
<button className="text-xs text-primary hover:underline" onClick={handleSaveBase} disabled={correctMutation.isPending}>
|
||||
{correctMutation.isPending ? '...' : '保存'}
|
||||
</button>
|
||||
<button className="text-xs text-gray-400 hover:underline" onClick={() => { setEditing(false); setEditBase(i.base?.toString() || '') }}>取消</button>
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1">
|
||||
¥{fmt(i.base)}
|
||||
{i.recordId && type !== 'sub' && (
|
||||
<button className="text-xs text-gray-400 hover:text-primary" onClick={() => { setEditing(true); setEditBase(i.base?.toString() || '') }}>
|
||||
修改
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-1.5 text-right text-danger">{d ? `¥${fmt(d.orgAmount)}` : '-'}</td>
|
||||
<td className="py-1.5 text-right text-warning">{d ? `¥${fmt(d.empAmount)}` : '-'}</td>
|
||||
<td className="py-1.5 text-right font-medium text-primary">{d ? `¥${fmt(d.total)}` : '-'}</td>
|
||||
|
||||
Reference in New Issue
Block a user