| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import { AlertTriangle, Loader2, Trash2, X } from 'lucide-react'
- import { FormEvent, useEffect, useState } from 'react'
- import { api } from '../api'
- import type { Course } from '../types'
- interface DeleteCourseModalProps {
- isOpen: boolean
- onClose: () => void
- course: Course
- onSuccess: () => void
- }
- export function DeleteCourseModal({
- isOpen,
- onClose,
- course,
- onSuccess
- }: DeleteCourseModalProps) {
- const [confirmName, setConfirmName] = useState('')
- const [busy, setBusy] = useState(false)
- const [error, setError] = useState('')
- useEffect(() => {
- if (isOpen) {
- setConfirmName('')
- setError('')
- setBusy(false)
- }
- }, [isOpen])
- // 监听 ESC 键关闭
- useEffect(() => {
- function handleKeyDown(e: KeyboardEvent) {
- if (e.key === 'Escape' && isOpen && !busy) {
- onClose()
- }
- }
- window.addEventListener('keydown', handleKeyDown)
- return () => window.removeEventListener('keydown', handleKeyDown)
- }, [isOpen, busy, onClose])
- if (!isOpen) return null
- const isMatch = confirmName.trim() === course.name.trim()
- async function handleSubmit(e: FormEvent) {
- e.preventDefault()
- if (!isMatch) {
- setError('输入的课程名称不一致,请核对后重试')
- return
- }
- setBusy(true)
- setError('')
- try {
- await api.deleteCourse(course.id)
- onSuccess()
- } catch (err) {
- setError((err as Error).message || '删除课程失败,请稍后重试')
- setBusy(false)
- }
- }
- return (
- <div
- className="modal-backdrop"
- onClick={(e) => {
- if (e.target === e.currentTarget && !busy) {
- onClose()
- }
- }}
- >
- <div className="modal-dialog delete-course-modal" role="dialog" aria-modal="true">
- <div className="modal-header">
- <div className="modal-header-simple-title">
- <h3>删除课程</h3>
- </div>
- <button
- type="button"
- className="close-modal-btn"
- onClick={onClose}
- disabled={busy}
- aria-label="关闭"
- >
- <X size={18} />
- </button>
- </div>
- <form onSubmit={handleSubmit} className="modal-form-content">
- <div className="delete-modal-body">
- <div className="danger-alert-card">
- <p>
- 此操作<strong>无法撤销</strong>。该课程及其关联的 <strong>{course.episodes?.length || 0} 个分集</strong>、<strong>{course.assets?.length || 0} 份素材文件</strong>和讲师信息都将被永久删除。
- </p>
- </div>
- <div className="form-group">
- <label className="form-label" htmlFor="delete-course-input">
- 请输入课程名称进行确认:
- </label>
- <div className="target-course-name-box">
- <code>{course.name}</code>
- </div>
- <input
- id="delete-course-input"
- type="text"
- autoFocus
- value={confirmName}
- onChange={(e) => {
- setConfirmName(e.target.value)
- if (error) setError('')
- }}
- placeholder="在此输入完整的课程名称"
- disabled={busy}
- className="delete-confirm-input"
- />
- </div>
- {error && <div className="notice notice-error">{error}</div>}
- </div>
- <div className="modal-footer">
- <button
- type="button"
- className="secondary-button"
- onClick={onClose}
- disabled={busy}
- >
- 取消
- </button>
- <button
- type="submit"
- className="danger-button danger-submit-btn"
- disabled={!isMatch || busy}
- >
- {busy ? (
- <>
- <Loader2 size={16} className="spin" />
- 正在删除…
- </>
- ) : (
- <>
- <Trash2 size={16} />
- 确认彻底删除
- </>
- )}
- </button>
- </div>
- </form>
- </div>
- </div>
- )
- }
|