fix: 全面优化安全、性能和代码质量

P0: 环境变量校验/事务保护/RBAC权限
P1: 花名册分页/密码重置验证码/ErrorBoundary/N+1查询优化
P2: 导出限制/自定义错误类/body大小限制/代码去重
P3: 自定义确认弹窗替换window.confirm
This commit is contained in:
freedakgmail
2026-07-24 22:28:58 +08:00
parent 9ec21fedea
commit 5c12f28ac7
23 changed files with 634 additions and 366 deletions
+15 -10
View File
@@ -1,6 +1,7 @@
import { useState, useRef } from 'react'
import { toast } from 'sonner'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useConfirm } from '../hooks/useConfirm'
import { Calculator, AlertCircle, Info, Check, Upload, Layers, Settings as SettingsIcon, Archive, Plus, Trash2, AlertTriangle, Download, FileText, X, ChevronLeft, Wallet, LayoutTemplate, Clock, Receipt, Users, TrendingDown, TrendingUp, BadgeCheck } from 'lucide-react'
import api from '../lib/api'
import Card from '../components/ui/Card'
@@ -62,6 +63,7 @@ export default function Money() {
function BatchManager() {
const queryClient = useQueryClient()
const confirm = useConfirm()
const [month, setMonth] = useState(new Date().toISOString().slice(0, 7))
const [monthFrom, setMonthFrom] = useState('')
const [monthTo, setMonthTo] = useState('')
@@ -336,8 +338,8 @@ function BatchManager() {
<SettingsIcon className="w-3.5 h-3.5" />
</button>
<button
onClick={() => {
if (window.confirm(`确认删除批次「${batch.name}」?此操作不可撤销。`)) {
onClick={async () => {
if (await confirm({ title: '删除批次', message: `确认删除批次「${batch.name}」?此操作不可撤销。` })) {
deleteBatchMutation.mutate(batch.id)
}
}}
@@ -366,6 +368,7 @@ function BatchManager() {
function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void }) {
const queryClient = useQueryClient()
const confirm = useConfirm()
const [editCell, setEditCell] = useState<{ employeeId: string; field: string } | null>(null)
const [editValue, setEditValue] = useState<string>('')
const [page, setPage] = useState(1)
@@ -554,8 +557,8 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
</Button>
<Button
size="sm"
onClick={() => {
if (window.confirm('确认归档?归档后批次将锁定不可编辑。工资条需在「工资条管理」中单独生成。')) {
onClick={async () => {
if (await confirm({ title: '归档确认', message: '确认归档?归档后批次将锁定不可编辑。工资条需在「工资条管理」中单独生成。', variant: 'primary' })) {
archiveMutation.mutate()
}
}}
@@ -567,8 +570,8 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
<Button
variant="danger"
size="sm"
onClick={() => {
if (window.confirm(`确认删除批次「${batch.name}」?此操作不可撤销。`)) {
onClick={async () => {
if (await confirm({ title: '删除批次', message: `确认删除批次「${batch.name}」?此操作不可撤销。` })) {
deleteBatchMutation.mutate()
}
}}
@@ -772,6 +775,7 @@ function AddEmployeeToBatch({ batchId, onClose }: { batchId: string; onClose: ()
function TemplateManager() {
const queryClient = useQueryClient()
const confirm = useConfirm()
const [showForm, setShowForm] = useState(false)
const [editingItem, setEditingItem] = useState<any>(null)
const [form, setForm] = useState({
@@ -917,8 +921,8 @@ function TemplateManager() {
</button>
{!item.isDefault && (
<button
onClick={() => {
if (window.confirm(`确认删除薪酬项「${item.name}」?`)) {
onClick={async () => {
if (await confirm({ title: '删除薪酬项', message: `确认删除薪酬项「${item.name}」?` })) {
deleteMutation.mutate(item.id)
}
}}
@@ -1447,6 +1451,7 @@ function OvertimeCalculator() {
function PayslipManager() {
const queryClient = useQueryClient()
const confirm = useConfirm()
const [month, setMonth] = useState(new Date().toISOString().slice(0, 7))
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
@@ -1517,8 +1522,8 @@ function PayslipManager() {
</Button>
<Button
onClick={() => {
if (window.confirm(`确认从 ${month} 已归档批次汇总生成工资条?这将覆盖已有的工资条数据。`)) {
onClick={async () => {
if (await confirm({ title: '生成工资条', message: `确认从 ${month} 已归档批次汇总生成工资条?这将覆盖已有的工资条数据。`, variant: 'primary' })) {
generateFromBatchMutation.mutate({ month })
}
}}