优化: 大文件拆分+代码分割+按需加载+console清理+any类型替换

- Money.tsx (2260行→54行): 拆分为 money/ 子目录4个组件, React.lazy二级分割
- AIAssistant.tsx (2038行→63行): 拆分为 ai-assistant/ 子目录6个组件, React.lazy二级分割
- xlsx改为动态导入, OvertimeTab从345KB降至12.7KB
- api-services.ts: 请求参数 any→Record<string,unknown>
- 移除前端3处console.log残留
- 后端console替换为pino logger
- 前后端未使用import/变量清理
- Zod schema验证: termination/platform/special-status/work-process
- 新增 leave.routes.ts, acceptance-test.routes.ts
- UI组件: PageGuide, QueryError, Stepper
This commit is contained in:
freedakgmail
2026-08-04 07:53:37 +08:00
parent 1da385cd5d
commit 2968484d2d
109 changed files with 8950 additions and 5926 deletions
+32 -2
View File
@@ -8,6 +8,7 @@ import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
import { Input, Label, Select } from '../components/ui/Input'
import Modal from '../components/ui/Modal'
import { useConfirm } from '../hooks/useConfirm'
export default function Settings() {
@@ -618,6 +619,7 @@ function handleAcceptanceExport() {
function PlanSettings({ orgData }: { orgData: any }) {
const queryClient = useQueryClient()
const confirm = useConfirm()
const plan = orgData?.plan || 'FREE'
const { data: usageData } = useQuery<any>({
@@ -683,8 +685,8 @@ function PlanSettings({ orgData }: { orgData: any }) {
variant="secondary"
className="w-full"
size="sm"
onClick={() => {
if (confirm(`确定切换到${p.label}`)) planMutation.mutate(p.key)
onClick={async () => {
if (await confirm({ title: '切换套餐', message: `确定切换到${p.label}`, variant: 'primary' })) planMutation.mutate(p.key)
}}
disabled={planMutation.isPending}
>
@@ -959,8 +961,14 @@ function InitImport() {
const data = await res.json()
if (!data.success) {
setError(data.error?.message || '导入失败')
toast.error(data.error?.message || '导入失败')
} else {
setResult(data.data)
if (data.data.errors?.length > 0) {
toast.warning(`导入完成,但有 ${data.data.errors.length} 条错误,请查看详情`)
} else {
toast.success(`成功导入员工 ${data.data.employees}`)
}
queryClient.invalidateQueries({ queryKey: ['roster'] })
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
}
@@ -1123,6 +1131,22 @@ function InitImport() {
{result.errors.length > 10 && <div className="text-amber-600">... {result.errors.length - 10} </div>}
</div>
)}
{/* 导入明细 */}
{result.details?.filter((d: any) => d.status === 'success').length > 0 && (
<div className="mt-2 pt-2 border-t border-green-200">
<div className="font-medium text-gray-600 mb-1"></div>
<div className="max-h-40 overflow-y-auto">
{result.details.filter((d: any) => d.status === 'success').map((d: any, i: number) => (
<div key={i} className="flex gap-3 text-xs text-gray-500">
<span>{d.row}</span>
<span>{d.name}</span>
{d.employeeId && <span className="text-gray-400">ID: {d.employeeId.slice(0, 8)}...</span>}
<span className="text-safe"> {d.message}</span>
</div>
))}
</div>
</div>
)}
</div>
)}
@@ -1175,8 +1199,14 @@ function MonthlyImport() {
const data = await res.json()
if (!data.success) {
setError(data.error?.message || '导入失败')
toast.error(data.error?.message || '导入失败')
} else {
setResult(data.data)
if (data.data.errors?.length > 0) {
toast.warning(`导入完成,但有 ${data.data.errors.length} 条错误,请查看详情`)
} else {
toast.success('月度数据导入成功')
}
queryClient.invalidateQueries({ queryKey: ['roster'] })
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
}