fix: 修复前后端编译警告 — 移除未使用变量/导入/函数

前端:
- 移除未使用导入: FileText, AlertCircle, RefreshCw, Signal, QrCode, Upload, Save, Bell, History, useMemo, Select
- 移除未使用变量/函数: scope, cfg, org, paged, salaryNum, ackColor, resultColor, maxEmployees, compareVersions, showRenewPreview, showEvidence, handleStartDateChange, ResultRow, previewEmployeeId, updateMutation
- 修复 vite.config.ts: 安装 @types/node 并配置 tsconfig.node.json
- 将未使用参数 req/s 改为 _req/_s

后端:
- 移除未使用导入: Request, Response, NextFunction, decrypt, ContractType, ensureDefaultTemplate
- 移除未使用变量/常量: scope, cfg, org, orgId(preview), monthNum, TAX_BRACKETS, months, daysBetween
- 将未使用参数 req 改为 _req
This commit is contained in:
freedakgmail
2026-07-24 08:25:31 +08:00
parent e01bad4815
commit 951a3abac5
28 changed files with 61 additions and 100 deletions
-1
View File
@@ -207,7 +207,6 @@ async function main() {
console.log('\n生成 1-6 月历史工资条...')
const socialConfig = await prisma.socialInsuranceConfig.findFirst({ where: { orgId: org.id, isCurrent: true } })
const allEmployees = await prisma.employee.findMany({ where: { orgId: org.id } })
const months = ['2026-01', '2026-02', '2026-03', '2026-04', '2026-05', '2026-06']
for (const emp of allEmployees) {
// 跳过 2026 年之后入职的员工
+1 -2
View File
@@ -188,7 +188,6 @@ router.post('/case-to-todo', authMiddleware, async (req: AuthRequest, res, next)
router.get('/predict', authMiddleware, async (req: AuthRequest, res, next) => {
try {
const scope = (req.query.scope as string) || 'all'
const department = req.query.department as string
const employeeId = req.query.employeeId as string
const riskType = req.query.riskType as string
@@ -339,7 +338,7 @@ router.get('/review/employee/:employeeId', authMiddleware, async (req: AuthReque
})
// RAG 知识库管理
router.post('/rag/seed', authMiddleware, async (req: AuthRequest, res, next) => {
router.post('/rag/seed', authMiddleware, async (_req: AuthRequest, res, next) => {
try {
await seedKnowledgeBase()
res.json({ success: true, data: { message: '知识库初始化完成' } })
+2 -3
View File
@@ -88,7 +88,6 @@ function num(v: any): number {
router.post('/excel/preview', authMiddleware, upload.single('file'), async (req: AuthRequest, res: Response, next) => {
try {
if (!req.file) return res.status(400).json({ success: false, error: { code: 'BAD_REQUEST', message: '请上传文件' } })
const orgId = req.user!.orgId
const wb = XLSX.read(req.file.buffer, { type: 'buffer', cellDates: true })
const preview: any = { employees: [], contracts: [], overtime: [], disciplinary: [], attendance: [], errors: [] as any[] }
@@ -385,7 +384,7 @@ router.post('/excel', authMiddleware, upload.single('file'), async (req: AuthReq
}
})
router.get('/template', authMiddleware, async (req: AuthRequest, res: Response) => {
router.get('/template', authMiddleware, async (_req: AuthRequest, res: Response) => {
const wb = XLSX.utils.book_new()
const empData = [
@@ -582,7 +581,7 @@ router.post('/monthly', authMiddleware, upload.single('file'), async (req: AuthR
}
})
router.get('/monthly-template', authMiddleware, async (req: AuthRequest, res: Response) => {
router.get('/monthly-template', authMiddleware, async (_req: AuthRequest, res: Response) => {
const wb = XLSX.utils.book_new()
const attData = [{ '姓名': '张三', '身份证号': '110101199001011234', '日期': '2024-06-01', '考勤状态': '正常', '上班时间': '09:00', '下班时间': '18:00', '备注': '' }]
-1
View File
@@ -427,7 +427,6 @@ router.post('/overtime/import-to-batch/:batchId', async (req: AuthRequest, res:
// 获取加班费计算规则
let config = await prisma.overtimeConfig.findUnique({ where: { orgId } })
if (!config) config = await prisma.overtimeConfig.create({ data: { orgId } })
const cfg = config
// 获取该月未关联批次的加班记录
const overtimeRecords = await prisma.overtimeRecord.findMany({
-4
View File
@@ -4,7 +4,6 @@ import { authMiddleware, AuthRequest } from '../middleware/auth'
import { z } from 'zod'
import { decrypt } from '../lib/crypto'
import {
ensureDefaultTemplate,
getTemplate,
calcBatchEntry,
getPayrollRiskWarnings,
@@ -228,9 +227,6 @@ router.post('/batches', async (req: AuthRequest, res: Response, next: NextFuncti
})
const batchNo = existingBatches + 1
// 获取组织发薪频率
const org = await prisma.organization.findUnique({ where: { id: orgId } })
// 获取在职员工 + 本月离职员工
const monthStart = new Date(`${month}-01`)
const monthEnd = new Date(monthStart.getFullYear(), monthStart.getMonth() + 1, 0, 23, 59, 59)
+1 -1
View File
@@ -1,4 +1,4 @@
import { Router, Request, Response, NextFunction } from 'express'
import { Router } from 'express'
import { authMiddleware, AuthRequest } from '../middleware/auth'
import { auditLog } from '../middleware/auditLog'
import prisma from '../lib/prisma'
+1 -1
View File
@@ -1,4 +1,4 @@
import { Router, Request, Response, NextFunction } from 'express'
import { Router } from 'express'
import bcrypt from 'bcryptjs'
import prisma from '../lib/prisma'
import { authMiddleware, AuthRequest } from '../middleware/auth'
-1
View File
@@ -4,7 +4,6 @@ import { auditLog } from '../middleware/auditLog'
import { terminationChecklistSchema } from '../schemas/termination.schema'
import { createTermination, createResignation, revokeTermination, getTerminations, getChecklistForReason, assessRisk, batchTerminatePreview, batchTerminate } from '../services/termination.service'
import prisma from '../lib/prisma'
import { decrypt } from '../lib/crypto'
const router = Router()
-12
View File
@@ -1,5 +1,4 @@
import prisma from '../lib/prisma'
import { decrypt } from '../lib/crypto'
// ========== 薪酬模版 ==========
@@ -51,16 +50,6 @@ export function calcHousingFund(base: number, config: any) {
// ========== 累计预扣个税 ==========
const TAX_BRACKETS = [
{ rate: 0.03, quickDeduction: 0 },
{ rate: 0.10, quickDeduction: 2520 },
{ rate: 0.20, quickDeduction: 16920 },
{ rate: 0.25, quickDeduction: 31920 },
{ rate: 0.30, quickDeduction: 52920 },
{ rate: 0.35, quickDeduction: 85920 },
{ rate: 0.45, quickDeduction: 181920 },
]
export function calcTax(taxableIncome: number): number {
if (taxableIncome <= 0) return 0
let tax = 0
@@ -291,7 +280,6 @@ export async function generatePayslipFromBatches(orgId: string, month: string) {
// 计算累计数据
const year = month.slice(0, 4)
const monthNum = Number(month.slice(5, 7))
let generated = 0
for (const [employeeId, summary] of employeeMap) {
+1 -2
View File
@@ -1,6 +1,5 @@
import prisma from '../lib/prisma'
import { decrypt } from '../lib/crypto'
import type { ContractType, RiskLevel, RiskType } from '@prisma/client'
import type { RiskLevel, RiskType } from '@prisma/client'
function daysBetween(a: Date, b: Date): number {
return Math.floor((a.getTime() - b.getTime()) / (1000 * 60 * 60 * 24))
@@ -1,11 +1,6 @@
import prisma from '../lib/prisma'
import { decrypt } from '../lib/crypto'
import { RiskAssessment, TerminationReason } from '@prisma/client'
function daysBetween(a: Date, b: Date): number {
return Math.floor((a.getTime() - b.getTime()) / (1000 * 60 * 60 * 24))
}
function dateToMonth(date: Date): string {
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
+18
View File
@@ -24,6 +24,7 @@
"zustand": "^4.5.0"
},
"devDependencies": {
"@types/node": "^26.1.1",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
@@ -1309,6 +1310,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "26.1.1",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz",
"integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~8.3.0"
}
},
"node_modules/@types/pako": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/@types/pako/-/pako-2.0.4.tgz",
@@ -3303,6 +3314,13 @@
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "8.3.0",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz",
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
"dev": true,
"license": "MIT"
},
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+1
View File
@@ -25,6 +25,7 @@
"zustand": "^4.5.0"
},
"devDependencies": {
"@types/node": "^26.1.1",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
@@ -1,5 +1,5 @@
import { Link, useLocation } from 'react-router-dom'
import { Home, FileText, Users, Calculator, UserX, Bot, Shield } from 'lucide-react'
import { Home, Users, Calculator, UserX, Bot, Shield } from 'lucide-react'
import clsx from 'clsx'
const tabs = [
+1 -1
View File
@@ -1,5 +1,5 @@
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { Building2, AlertCircle, ChevronDown } from 'lucide-react'
import { Building2, ChevronDown } from 'lucide-react'
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { useAuthStore } from '../../store/authStore'
+1 -2
View File
@@ -1,12 +1,11 @@
import { useState, useRef } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Plus, Search, RefreshCw, Paperclip, Trash2, X } from 'lucide-react'
import { Plus, Search, Paperclip, Trash2, X } from 'lucide-react'
import api from '../lib/api'
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 Signal from '../components/ui/Signal'
import EmptyState from '../components/ui/EmptyState'
interface EmployeeItem {
+1 -1
View File
@@ -21,7 +21,7 @@ const TODO_ICON_CONFIG: Record<string, { icon: typeof FileText; color: string; b
ONBOARDING: { icon: UserPlus, color: 'text-cyan-600', bg: 'bg-cyan-50' },
}
function TodoIcon({ type, level }: { type: string; level: string }) {
function TodoIcon({ type }: { type: string; level: string }) {
const config = TODO_ICON_CONFIG[type] || TODO_ICON_CONFIG.MONTHLY
const Icon = config.icon
return (
+2 -17
View File
@@ -1,6 +1,6 @@
import { useState, useMemo, useRef } from 'react'
import { useState, useRef } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Calculator, AlertCircle, Info, Save, Check, Upload, Bell, Layers, Settings as SettingsIcon, Archive, Plus, Trash2, AlertTriangle, Download, FileText, History, X } from 'lucide-react'
import { Calculator, AlertCircle, Info, Check, Upload, Layers, Settings as SettingsIcon, Archive, Plus, Trash2, AlertTriangle, Download, FileText, X } from 'lucide-react'
import api from '../lib/api'
import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
@@ -703,11 +703,6 @@ function TemplateManager() {
},
})
const updateMutation = useMutation({
mutationFn: ({ id, data }: { id: string; data: any }) => api.put(`/payroll2/template/${id}`, data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['payslip-template'] }),
})
const deleteMutation = useMutation({
mutationFn: (id: string) => api.delete(`/payroll2/template/${id}`),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['payslip-template'] }),
@@ -1184,22 +1179,12 @@ function OvertimeCalculator() {
)
}
function ResultRow({ label, value }: { label: string; value: number }) {
return (
<div className="flex items-center justify-between text-xs">
<span className="text-gray-600">{label}</span>
<span className="font-medium">¥{fmt(value)}</span>
</div>
)
}
function PayslipManager() {
const queryClient = useQueryClient()
const [month, setMonth] = useState(new Date().toISOString().slice(0, 7))
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
const [showTaxPreview, setShowTaxPreview] = useState(false)
const [previewEmployeeId, setPreviewEmployeeId] = useState('')
const [previewData, setPreviewData] = useState({
baseSalary: 0,
overtimePay: 0,
+1 -36
View File
@@ -1,13 +1,12 @@
import { useState, useRef } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Users, FileText, AlertTriangle, Calendar, GraduationCap, TrendingUp, Scale, X, Plus, Paperclip, Trash2, Printer, Calculator, Shield, Info, Check, Eye, Download, UserX, UserPlus, QrCode } from 'lucide-react'
import { Users, FileText, AlertTriangle, Calendar, GraduationCap, TrendingUp, Scale, X, Plus, Paperclip, Trash2, Printer, Calculator, Shield, Info, Check, Eye, Download, UserX, UserPlus } from 'lucide-react'
import { QRCodeSVG } from 'qrcode.react'
import api from '../lib/api'
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 Signal from '../components/ui/Signal'
import Pagination from '../components/ui/Pagination'
// 金额格式化:保留两位小数 + 千分位
@@ -41,7 +40,6 @@ export default function Roster() {
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
const [showBatchRenewModal, setShowBatchRenewModal] = useState(false)
const [batchRenewYears, setBatchRenewYears] = useState(3)
const [showRenewPreview, setShowRenewPreview] = useState(false)
const [previewData, setPreviewData] = useState<any>(null)
const [filterStatus, setFilterStatus] = useState('')
const [filterContractStatus, setFilterContractStatus] = useState('')
@@ -128,7 +126,6 @@ export default function Roster() {
queryClient.invalidateQueries({ queryKey: ['roster'] })
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
setShowBatchRenewModal(false)
setShowRenewPreview(false)
setSelectedIds(new Set())
setPreviewData(null)
},
@@ -138,7 +135,6 @@ export default function Roster() {
mutationFn: (contractIds: string[]) => api.post('/employees/contracts/preview-renew', { contractIds }),
onSuccess: (data: any) => {
setPreviewData(data.data)
setShowRenewPreview(true)
},
})
@@ -191,7 +187,6 @@ export default function Roster() {
const filtered = employees?.filter((e: any) =>
!search || e.name.includes(search) || e.department.includes(search)
) || []
const paged = filtered.slice((page - 1) * pageSize, page * pageSize)
if (selectedId) {
return <EmployeeProfile employeeId={selectedId} onBack={() => setSelectedId(null)} />
@@ -681,7 +676,6 @@ export default function Roster() {
function EmployeeProfile({ employeeId, onBack }: { employeeId: string; onBack: () => void }) {
const [tab, setTab] = useState<DetailTab>('basic')
const [showEvidence, setShowEvidence] = useState(false)
const { data: profile, isLoading } = useQuery<any>({
queryKey: ['roster-profile', employeeId],
@@ -1521,19 +1515,6 @@ function RehireModal({ employee, onClose, onSubmit, loading, error }: {
}
}
// 开始日期变更 → 重新计算结束日期
const handleStartDateChange = (startDate: string) => {
if (form.contractType === 'FIXED' && form.contractYears > 0 && startDate) {
const start = new Date(startDate)
const end = new Date(start)
end.setFullYear(end.getFullYear() + form.contractYears)
end.setDate(end.getDate() - 1)
setForm({ ...form, startDate, endDate: end.toISOString().slice(0, 10) })
} else {
setForm({ ...form, startDate })
}
}
const handleSubmit = () => {
const data: any = {
hireDate: new Date(form.hireDate).toISOString(),
@@ -1702,7 +1683,6 @@ function AddEmployeeModal({ onClose, onSubmit, loading, error }: {
})
const hireMonth = form.hireDate ? form.hireDate.slice(0, 7) : ''
const salaryNum = parseFloat(form.monthlySalary) || 0
// 入职日期变更 → 同步合同开始日期 + 重算结束日期
const handleHireDateChange = (hireDate: string) => {
@@ -1788,19 +1768,6 @@ function AddEmployeeModal({ onClose, onSubmit, loading, error }: {
setForm({ ...form, endDate, contractYears: Math.max(1, Math.round(months / 12)) })
}
// 开始日期变更 → 重新计算结束日期
const handleStartDateChange = (startDate: string) => {
if (form.contractType === 'FIXED' && form.contractYears > 0 && startDate) {
const start = new Date(startDate)
const end = new Date(start)
end.setFullYear(end.getFullYear() + form.contractYears)
end.setDate(end.getDate() - 1)
setForm({ ...form, startDate, endDate: end.toISOString().slice(0, 10) })
} else {
setForm({ ...form, startDate })
}
}
const handleSubmit = () => {
const data: any = {
name: form.name, department: form.department,
@@ -2531,7 +2498,6 @@ function TrainingInfo({ employeeId, records }: { employeeId: string; records: an
})
const ackMap: Record<string, string> = { PENDING: '待签收', SIGNED: '已签收', REFUSED: '拒绝签收' }
const ackColor: Record<string, string> = { PENDING: 'bg-amber-50 text-warning', SIGNED: 'bg-green-50 text-safe', REFUSED: 'bg-red-50 text-danger' }
return (
<div className="space-y-3">
@@ -2607,7 +2573,6 @@ function PerformanceInfo({ employeeId, records }: { employeeId: string; records:
})
const resultMap: Record<string, string> = { EXCELLENT: '优秀', QUALIFIED: '合格', NEED_IMPROVE: '需改进', UNQUALIFIED: '不胜任' }
const resultColor: Record<string, string> = { EXCELLENT: 'bg-green-50 text-safe', QUALIFIED: 'bg-blue-50 text-blue-600', NEED_IMPROVE: 'bg-amber-50 text-warning', UNQUALIFIED: 'bg-red-50 text-danger' }
return (
<div className="space-y-3">
-1
View File
@@ -404,7 +404,6 @@ function ExportSettings() {
function PlanSettings({ orgData }: { orgData: any }) {
const queryClient = useQueryClient()
const plan = orgData?.data?.plan || 'FREE'
const maxEmployees = orgData?.data?.maxEmployees || 10
const { data: usageData } = useQuery<any>({
queryKey: ['usage'],
+1 -1
View File
@@ -4,7 +4,7 @@ import { Calculator, Info, Check, Settings as SettingsIcon, Plus, History, Downl
import api from '../lib/api'
import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
import { Input, Label, Select } from '../components/ui/Input'
import { Input, Label } from '../components/ui/Input'
// 金额格式化:保留两位小数 + 千分位
const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
+1 -5
View File
@@ -6,7 +6,6 @@ import api from '../lib/api'
import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
import { Input, Label, Select } from '../components/ui/Input'
import Signal from '../components/ui/Signal'
// 金额格式化:保留两位小数 + 千分位
const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
@@ -81,8 +80,6 @@ export default function Termination() {
isSimulated: boolean
createdAt: string
}>>([])
// 对比模式:选中的版本ID列表
const [compareVersions, setCompareVersions] = useState<string[]>([])
// 是否展开对比
const [showCompare, setShowCompare] = useState(false)
@@ -405,7 +402,7 @@ export default function Termination() {
{/* 进度条 */}
<div className="flex items-center gap-1">
{STEPS.map((s, i) => (
{STEPS.map((_s, i) => (
<div key={i} className="flex items-center">
<div className={`w-2.5 h-2.5 rounded-full ${i <= step ? 'bg-primary' : 'bg-gray-300'}`} />
{i < STEPS.length - 1 && <div className={`w-8 h-0.5 ${i < step ? 'bg-primary' : 'bg-gray-300'}`} />}
@@ -955,7 +952,6 @@ export default function Termination() {
size="sm"
onClick={() => {
setShowCompare(!showCompare)
if (!showCompare) setCompareVersions([])
}}
>
<List className="w-3.5 h-3.5 mr-1" />
+1 -1
View File
@@ -1,6 +1,6 @@
import { useState, useRef } from 'react'
import { useSearchParams } from 'react-router-dom'
import { ClipboardList, Check, Upload, FileText, X } from 'lucide-react'
import { ClipboardList, Check, FileText, X } from 'lucide-react'
import api from '../../lib/api'
import Card from '../../components/ui/Card'
import Button from '../../components/ui/Button'
+2 -1
View File
@@ -5,7 +5,8 @@
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
"strict": true,
"types": ["node"]
},
"include": ["vite.config.ts"]
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"root":["./src/app.tsx","./src/main.tsx","./src/components/onboardingguide.tsx","./src/components/layout/mobiletabbar.tsx","./src/components/layout/pagecontainer.tsx","./src/components/layout/topnav.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/emptystate.tsx","./src/components/ui/input.tsx","./src/components/ui/modal.tsx","./src/components/ui/pagination.tsx","./src/components/ui/signal.tsx","./src/lib/api.ts","./src/pages/aiassistant.tsx","./src/pages/compensation.tsx","./src/pages/contracts.tsx","./src/pages/dashboard.tsx","./src/pages/money.tsx","./src/pages/roster.tsx","./src/pages/settings.tsx","./src/pages/socialinsurance.tsx","./src/pages/termination.tsx","./src/pages/auth/forgotpassword.tsx","./src/pages/auth/login.tsx","./src/pages/auth/register.tsx","./src/pages/portal/contractconfirm.tsx","./src/pages/portal/mycontract.tsx","./src/pages/portal/onboarding.tsx","./src/pages/portal/payslip.tsx","./src/pages/portal/portallogin.tsx","./src/store/authstore.ts","./src/types/index.ts"],"version":"5.9.3"}
+2
View File
@@ -0,0 +1,2 @@
declare const _default: import("vite").UserConfig;
export default _default;
+20
View File
@@ -0,0 +1,20 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
},
},
},
});