fix: 修复前端代码质量问题

- 创建 Toast 通知组件,替换所有 alert() 调用
- 修复 useReview hook 内存泄漏(setInterval 清理)
- 移除所有 console.error 和 console.log 语句
- 为复制操作失败添加用户友好的 toast 提示

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-02-09 12:48:22 +08:00
co-authored by Claude Opus 4.5
parent a5a005db0c
commit 37ac749071
33 changed files with 519 additions and 91 deletions
+4 -2
View File
@@ -2,6 +2,7 @@
import { useState } from 'react'
import { useRouter, useParams } from 'next/navigation'
import { useToast } from '@/components/ui/Toast'
import { ArrowLeft, Play, Pause, AlertTriangle, Shield, Radio } from 'lucide-react'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
@@ -85,6 +86,7 @@ function formatTimestamp(seconds: number): string {
export default function ReviewPage() {
const router = useRouter()
const params = useParams()
const toast = useToast()
const [isPlaying, setIsPlaying] = useState(false)
const [showApproveModal, setShowApproveModal] = useState(false)
const [showRejectModal, setShowRejectModal] = useState(false)
@@ -103,7 +105,7 @@ export default function ReviewPage() {
const handleReject = () => {
if (!rejectReason.trim()) {
alert('请填写驳回原因')
toast.error('请填写驳回原因')
return
}
setShowRejectModal(false)
@@ -112,7 +114,7 @@ export default function ReviewPage() {
const handleForcePass = () => {
if (!forcePassReason.trim()) {
alert('请填写强制通过原因')
toast.error('请填写强制通过原因')
return
}
setShowForcePassModal(false)
+10 -8
View File
@@ -2,6 +2,7 @@
import { useState } from 'react'
import Link from 'next/link'
import { useToast } from '@/components/ui/Toast'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { SuccessTag, PendingTag, WarningTag, ErrorTag } from '@/components/ui/Tag'
@@ -165,13 +166,13 @@ function ScoreTag({ score }: { score: number }) {
type ScriptTask = typeof mockScriptTasks[0]
type VideoTask = typeof mockVideoTasks[0]
function ScriptTaskCard({ task, onPreview }: { task: ScriptTask; onPreview: (task: ScriptTask) => void }) {
function ScriptTaskCard({ task, onPreview, toast }: { task: ScriptTask; onPreview: (task: ScriptTask) => void; toast: ReturnType<typeof useToast> }) {
const riskConfig = riskLevelConfig[task.riskLevel]
const platform = getPlatformInfo(task.platform)
const handleDownload = (e: React.MouseEvent) => {
e.stopPropagation()
alert(`下载文件: ${task.fileName}`)
toast.info(`下载文件: ${task.fileName}`)
}
const handlePreview = (e: React.MouseEvent) => {
@@ -261,13 +262,13 @@ function ScriptTaskCard({ task, onPreview }: { task: ScriptTask; onPreview: (tas
)
}
function VideoTaskCard({ task, onPreview }: { task: VideoTask; onPreview: (task: VideoTask) => void }) {
function VideoTaskCard({ task, onPreview, toast }: { task: VideoTask; onPreview: (task: VideoTask) => void; toast: ReturnType<typeof useToast> }) {
const riskConfig = riskLevelConfig[task.riskLevel]
const platform = getPlatformInfo(task.platform)
const handleDownload = (e: React.MouseEvent) => {
e.stopPropagation()
alert(`下载文件: ${task.fileName}`)
toast.info(`下载文件: ${task.fileName}`)
}
const handlePreview = (e: React.MouseEvent) => {
@@ -362,6 +363,7 @@ export default function AgencyReviewListPage() {
const [activeTab, setActiveTab] = useState<'all' | 'script' | 'video'>('all')
const [previewScript, setPreviewScript] = useState<ScriptTask | null>(null)
const [previewVideo, setPreviewVideo] = useState<VideoTask | null>(null)
const toast = useToast()
const filteredScripts = mockScriptTasks.filter(task =>
task.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
@@ -462,7 +464,7 @@ export default function AgencyReviewListPage() {
<CardContent className="space-y-3">
{filteredScripts.length > 0 ? (
filteredScripts.map((task) => (
<ScriptTaskCard key={task.id} task={task} onPreview={setPreviewScript} />
<ScriptTaskCard key={task.id} task={task} onPreview={setPreviewScript} toast={toast} />
))
) : (
<div className="text-center py-8 text-text-tertiary">
@@ -489,7 +491,7 @@ export default function AgencyReviewListPage() {
<CardContent className="space-y-3">
{filteredVideos.length > 0 ? (
filteredVideos.map((task) => (
<VideoTaskCard key={task.id} task={task} onPreview={setPreviewVideo} />
<VideoTaskCard key={task.id} task={task} onPreview={setPreviewVideo} toast={toast} />
))
) : (
<div className="text-center py-8 text-text-tertiary">
@@ -536,7 +538,7 @@ export default function AgencyReviewListPage() {
<Button variant="secondary" onClick={() => setPreviewScript(null)}>
</Button>
<Button onClick={() => alert(`下载文件: ${previewScript?.fileName}`)}>
<Button onClick={() => toast.info(`下载文件: ${previewScript?.fileName}`)}>
<Download size={16} />
</Button>
@@ -581,7 +583,7 @@ export default function AgencyReviewListPage() {
<Button variant="secondary" onClick={() => setPreviewVideo(null)}>
</Button>
<Button onClick={() => alert(`下载文件: ${previewVideo?.fileName}`)}>
<Button onClick={() => toast.info(`下载文件: ${previewVideo?.fileName}`)}>
<Download size={16} />
</Button>
@@ -2,6 +2,7 @@
import { useState } from 'react'
import { useRouter, useParams } from 'next/navigation'
import { useToast } from '@/components/ui/Toast'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { Modal, ConfirmModal } from '@/components/ui/Modal'
@@ -90,6 +91,7 @@ function ReviewProgressBar({ taskStatus }: { taskStatus: string }) {
export default function AgencyScriptReviewPage() {
const router = useRouter()
const toast = useToast()
const params = useParams()
const [showApproveModal, setShowApproveModal] = useState(false)
const [showRejectModal, setShowRejectModal] = useState(false)
@@ -103,27 +105,27 @@ export default function AgencyScriptReviewPage() {
const handleApprove = () => {
setShowApproveModal(false)
alert('已提交品牌方终审')
toast.success('已提交品牌方终审')
router.push('/agency/review')
}
const handleReject = () => {
if (!rejectReason.trim()) {
alert('请填写驳回原因')
toast.error('请填写驳回原因')
return
}
setShowRejectModal(false)
alert('已驳回')
toast.success('已驳回')
router.push('/agency/review')
}
const handleForcePass = () => {
if (!forcePassReason.trim()) {
alert('请填写强制通过原因')
toast.error('请填写强制通过原因')
return
}
setShowForcePassModal(false)
alert('已强制通过并提交品牌方终审')
toast.success('已强制通过并提交品牌方终审')
router.push('/agency/review')
}
@@ -2,6 +2,7 @@
import { useState } from 'react'
import { useRouter, useParams } from 'next/navigation'
import { useToast } from '@/components/ui/Toast'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { Modal, ConfirmModal } from '@/components/ui/Modal'
@@ -114,6 +115,7 @@ function RiskLevelTag({ level }: { level: string }) {
export default function AgencyVideoReviewPage() {
const router = useRouter()
const toast = useToast()
const params = useParams()
const [isPlaying, setIsPlaying] = useState(false)
const [showApproveModal, setShowApproveModal] = useState(false)
@@ -130,27 +132,27 @@ export default function AgencyVideoReviewPage() {
const handleApprove = () => {
setShowApproveModal(false)
alert('已提交品牌方终审')
toast.success('已提交品牌方终审')
router.push('/agency/review')
}
const handleReject = () => {
if (!rejectReason.trim()) {
alert('请填写驳回原因')
toast.error('请填写驳回原因')
return
}
setShowRejectModal(false)
alert('已驳回')
toast.success('已驳回')
router.push('/agency/review')
}
const handleForcePass = () => {
if (!forcePassReason.trim()) {
alert('请填写强制通过原因')
toast.error('请填写强制通过原因')
return
}
setShowForcePassModal(false)
alert('已强制通过并提交品牌方终审')
toast.success('已强制通过并提交品牌方终审')
router.push('/agency/review')
}