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
+3 -1
View File
@@ -5,6 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { Modal } from '@/components/ui/Modal'
import { SuccessTag, PendingTag, WarningTag } from '@/components/ui/Tag'
import { useToast } from '@/components/ui/Toast'
import {
Search,
Plus,
@@ -110,6 +111,7 @@ function StatusTag({ status }: { status: string }) {
}
export default function AgenciesManagePage() {
const toast = useToast()
const [searchQuery, setSearchQuery] = useState('')
const [agencies, setAgencies] = useState<Agency[]>(initialAgencies)
const [copiedId, setCopiedId] = useState<string | null>(null)
@@ -231,7 +233,7 @@ export default function AgenciesManagePage() {
.filter(p => selectedProjects.includes(p.id))
.map(p => p.name)
.join('、')
alert(`已将代理商「${assignModal.agency.name}」分配到项目「${projectNames}`)
toast.success(`已将代理商「${assignModal.agency.name}」分配到项目「${projectNames}`)
}
setAssignModal({ open: false, agency: null })
setSelectedProjects([])
+3 -1
View File
@@ -6,6 +6,7 @@ import { Button } from '@/components/ui/Button'
import { Input } from '@/components/ui/Input'
import { Select } from '@/components/ui/Select'
import { SuccessTag, ErrorTag, PendingTag } from '@/components/ui/Tag'
import { useToast } from '@/components/ui/Toast'
import {
Bot,
Eye,
@@ -68,6 +69,7 @@ type TestResult = {
}
export default function AIConfigPage() {
const toast = useToast()
const [provider, setProvider] = useState('oneapi')
const [baseUrl, setBaseUrl] = useState('https://oneapi.intelligrow.cn')
const [apiKey, setApiKey] = useState('')
@@ -133,7 +135,7 @@ export default function AIConfigPage() {
}
const handleSave = () => {
alert('配置已保存')
toast.success('配置已保存')
}
const getTestStatusIcon = (status: string) => {
+5 -3
View File
@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation'
import { ArrowLeft, Check, X, CheckSquare, Video, Clock } from 'lucide-react'
import { cn } from '@/lib/utils'
import { getPlatformInfo } from '@/lib/platforms'
import { useToast } from '@/components/ui/Toast'
// 模拟待审核内容列表
const mockReviewItems = [
@@ -99,6 +100,7 @@ function ReviewProgressBar({ currentStep }: { currentStep: number }) {
export default function FinalReviewPage() {
const router = useRouter()
const toast = useToast()
const [selectedItem, setSelectedItem] = useState(mockReviewItems[0])
const [feedback, setFeedback] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
@@ -108,19 +110,19 @@ export default function FinalReviewPage() {
setIsSubmitting(true)
// 模拟提交
await new Promise(resolve => setTimeout(resolve, 1000))
alert('已通过审核')
toast.success('已通过审核')
setIsSubmitting(false)
}
const handleReject = async () => {
if (!feedback.trim()) {
alert('请填写驳回原因')
toast.error('请填写驳回原因')
return
}
setIsSubmitting(true)
// 模拟提交
await new Promise(resolve => setTimeout(resolve, 1000))
alert('已驳回')
toast.success('已驳回')
setIsSubmitting(false)
setFeedback('')
}
@@ -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 { Input } from '@/components/ui/Input'
@@ -82,6 +83,7 @@ const strictnessOptions = [
export default function ProjectConfigPage() {
const router = useRouter()
const params = useParams()
const toast = useToast()
const projectId = params.id as string
const [brief, setBrief] = useState(mockData.brief)
@@ -100,7 +102,7 @@ export default function ProjectConfigPage() {
setIsSaving(true)
await new Promise(resolve => setTimeout(resolve, 1000))
setIsSaving(false)
alert('配置已保存')
toast.success('配置已保存')
}
const addRequirement = () => {
+4 -2
View File
@@ -2,6 +2,7 @@
import { useState } from 'react'
import { useRouter } 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 { Input } from '@/components/ui/Input'
@@ -40,6 +41,7 @@ const mockAgencies = [
export default function CreateProjectPage() {
const router = useRouter()
const toast = useToast()
const [projectName, setProjectName] = useState('')
const [deadline, setDeadline] = useState('')
const [briefFile, setBriefFile] = useState<File | null>(null)
@@ -73,14 +75,14 @@ export default function CreateProjectPage() {
const handleSubmit = async () => {
if (!projectName.trim() || !deadline || !briefFile || selectedAgencies.length === 0 || !selectedPlatform) {
alert('请填写完整信息')
toast.error('请填写完整信息')
return
}
setIsSubmitting(true)
// 模拟提交
await new Promise(resolve => setTimeout(resolve, 1500))
alert('项目创建成功!')
toast.success('项目创建成功!')
router.push('/brand')
}
+5 -2
View File
@@ -5,6 +5,7 @@ import Link from 'next/link'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { SuccessTag, PendingTag, WarningTag, ErrorTag } from '@/components/ui/Tag'
import { useToast } from '@/components/ui/Toast'
import {
FileText,
Video,
@@ -129,6 +130,7 @@ function TaskCard({
type: 'script' | 'video'
onPreview: (task: ScriptTask | VideoTask, type: 'script' | 'video') => void
}) {
const toast = useToast()
const href = type === 'script' ? `/brand/review/script/${task.id}` : `/brand/review/video/${task.id}`
const platform = getPlatformInfo(task.platform)
@@ -141,7 +143,7 @@ function TaskCard({
const handleDownload = (e: React.MouseEvent) => {
e.preventDefault()
e.stopPropagation()
alert(`下载文件: ${task.fileName}`)
toast.info(`下载文件: ${task.fileName}`)
}
return (
@@ -243,6 +245,7 @@ function TaskCard({
}
export default function BrandReviewListPage() {
const toast = useToast()
const [searchQuery, setSearchQuery] = useState('')
const [activeTab, setActiveTab] = useState<'all' | 'script' | 'video'>('all')
const [previewTask, setPreviewTask] = useState<{ task: ScriptTask | VideoTask; type: 'script' | 'video' } | null>(null)
@@ -445,7 +448,7 @@ export default function BrandReviewListPage() {
<Button variant="secondary" onClick={() => setPreviewTask(null)}>
</Button>
<Button onClick={() => alert(`下载文件: ${previewTask?.task.fileName}`)}>
<Button onClick={() => toast.info(`下载文件: ${previewTask?.task.fileName}`)}>
<Download size={16} />
</Button>
@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/Button'
import { Modal, ConfirmModal } from '@/components/ui/Modal'
import { SuccessTag, WarningTag, ErrorTag, PendingTag } from '@/components/ui/Tag'
import { ReviewSteps, getBrandReviewSteps } from '@/components/ui/ReviewSteps'
import { useToast } from '@/components/ui/Toast'
import {
ArrowLeft,
FileText,
@@ -99,6 +100,7 @@ function ReviewProgressBar({ taskStatus }: { taskStatus: string }) {
export default function BrandScriptReviewPage() {
const router = useRouter()
const params = useParams()
const toast = useToast()
const [showApproveModal, setShowApproveModal] = useState(false)
const [showRejectModal, setShowRejectModal] = useState(false)
const [rejectReason, setRejectReason] = useState('')
@@ -109,17 +111,17 @@ export default function BrandScriptReviewPage() {
const handleApprove = () => {
setShowApproveModal(false)
alert('审核通过')
toast.success('审核通过')
router.push('/brand/review')
}
const handleReject = () => {
if (!rejectReason.trim()) {
alert('请填写驳回原因')
toast.error('请填写驳回原因')
return
}
setShowRejectModal(false)
alert('已驳回')
toast.success('已驳回')
router.push('/brand/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'
@@ -123,6 +124,7 @@ function RiskLevelTag({ level }: { level: string }) {
export default function BrandVideoReviewPage() {
const router = useRouter()
const params = useParams()
const toast = useToast()
const [isPlaying, setIsPlaying] = useState(false)
const [showApproveModal, setShowApproveModal] = useState(false)
const [showRejectModal, setShowRejectModal] = useState(false)
@@ -135,17 +137,17 @@ export default function BrandVideoReviewPage() {
const handleApprove = () => {
setShowApproveModal(false)
alert('审核通过!')
toast.success('审核通过!')
router.push('/brand/review')
}
const handleReject = () => {
if (!rejectReason.trim()) {
alert('请填写驳回原因')
toast.error('请填写驳回原因')
return
}
setShowRejectModal(false)
alert('已驳回')
toast.success('已驳回')
router.push('/brand/review')
}
+10 -8
View File
@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { Modal } from '@/components/ui/Modal'
import { useToast } from '@/components/ui/Toast'
import {
Bell,
Shield,
@@ -32,6 +33,7 @@ import {
export default function BrandSettingsPage() {
const router = useRouter()
const toast = useToast()
const [notifications, setNotifications] = useState({
email: true,
push: true,
@@ -95,7 +97,7 @@ export default function BrandSettingsPage() {
]
const handleSave = () => {
alert('设置已保存')
toast.success('设置已保存')
}
const handleLogout = () => {
@@ -105,10 +107,10 @@ export default function BrandSettingsPage() {
const handleChangePassword = () => {
if (passwordForm.new !== passwordForm.confirm) {
alert('两次输入的密码不一致')
toast.error('两次输入的密码不一致')
return
}
alert('密码修改成功')
toast.success('密码修改成功')
setShowPasswordModal(false)
setPasswordForm({ current: '', new: '', confirm: '' })
}
@@ -116,18 +118,18 @@ export default function BrandSettingsPage() {
const handleEnable2FA = () => {
setTwoFAEnabled(true)
setShow2FAModal(false)
alert('双因素认证已启用')
toast.success('双因素认证已启用')
}
const handleChangeEmail = () => {
alert(`邮箱已更新为 ${newEmail}`)
toast.success(`邮箱已更新为 ${newEmail}`)
setShowEmailModal(false)
setNewEmail('')
setEmailCode('')
}
const handleChangePhone = () => {
alert(`手机号已更新为 ${newPhone}`)
toast.success(`手机号已更新为 ${newPhone}`)
setShowPhoneModal(false)
setNewPhone('')
setPhoneCode('')
@@ -139,11 +141,11 @@ export default function BrandSettingsPage() {
await new Promise(resolve => setTimeout(resolve, 2000))
setIsExporting(false)
setShowExportModal(false)
alert('导出任务已创建,完成后将通知您下载')
toast.info('导出任务已创建,完成后将通知您下载')
}
const handleRemoveDevice = (deviceId: string) => {
alert('已移除该设备的登录状态')
toast.success('已移除该设备的登录状态')
}
return (