新增种子收藏和种子促销,首页推荐显示

Change-Id: Ia8632b7909845230a0becf1616dc647e0c7e292b
diff --git a/front/src/AdminPage.js b/front/src/AdminPage.js
index dac05cb..f063c09 100644
--- a/front/src/AdminPage.js
+++ b/front/src/AdminPage.js
@@ -51,11 +51,6 @@
         }
     };
 
-    const handleConfigChange = (e) => {
-        const { name, value } = e.target;
-        setConfig({ ...config, [name]: value });
-    };
-
     const handleBan = (user) => {
         const adminId = getUserIdFromCookie();
         if (!adminId) {
@@ -97,28 +92,6 @@
             .catch((err) => console.error('解封用户失败:', err));
     };
 
-    // 保存系统参数到后端
-    const handleSave = () => {
-        const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
-        const userId = match ? match[2] : null;
-        if (!userId) {
-            alert('无法获取用户ID');
-            return;
-        }
-        fetch(`${API_BASE_URL}/api/save-config`, {
-            method: 'POST',
-            // credentials: 'include',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify({ userid: userId, ...config }),
-        })
-            .then((res) => {
-                if (!res.ok) throw new Error('Network response was not ok');
-                return res.json();
-            })
-            .then(() => alert('系统参数已保存'))
-            .catch((err) => console.error('保存系统参数失败:', err));
-    };
-
     // 初始化时向后端请求系统参数及用户列表
     useEffect(() => {
         const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
@@ -149,37 +122,10 @@
             {/* 参数设置 */}
             <div style={{ marginBottom: 32, padding: 18, background: "#f7faff", borderRadius: 12, display: "flex", gap: 24, alignItems: "center", justifyContent: "space-between" }}>
                 <b>系统参数:</b>
-                <label>
-                    FarmNumber:
-                    <input type="number" name="FarmNumber" value={config.FarmNumber} onChange={handleConfigChange} disabled style={{ width: 60, margin: "0 12px" }} />
-                </label>
-                <label>
-                    FakeTime:
-                    <input type="number" name="FakeTime" value={config.FakeTime} onChange={handleConfigChange} disabled style={{ width: 60, margin: "0 12px" }} />
-                </label>
-                <label>
-                    BegVote:
-                    <input type="number" name="BegVote" value={config.BegVote} onChange={handleConfigChange} disabled style={{ width: 60, margin: "0 12px" }} />
-                </label>
-                <label>
-                    CheatTime:
-                    <input type="number" name="CheatTime" value={config.CheatTime} onChange={handleConfigChange} disabled style={{ width: 60, margin: "0 12px" }} />
-                </label>
-                {/* <button
-                    onClick={handleSave}
-                    style={{
-                        background: '#1976d2',
-                        color: '#fff',
-                        border: 'none',
-                        borderRadius: 6,
-                        padding: '6px 18px',
-                        cursor: 'pointer',
-                        writingMode: 'horizontal-tb',
-                        whiteSpace: 'nowrap'
-                    }}
-                >
-                    保存
-                </button> */}
+                <span>FarmNumber: {config.FarmNumber}</span>
+                <span>FakeTime: {config.FakeTime}</span>
+                <span>BegVote: {config.BegVote}</span>
+                <span>CheatTime: {config.CheatTime}</span>
             </div>
             {/* 作弊用户 */}
             <div style={{ marginBottom: 32 }}>
@@ -201,7 +147,7 @@
                                 <td>{u.email}</td>
                                 <td>{u.username}</td>
                                 <td style={{ color: "#e53935" }}>
-                                    {"封禁" }
+                                    {"封禁"}
                                 </td>
                                 <td>
                                     <button
@@ -265,6 +211,12 @@
                 >
                     用户迁移
                 </button>
+                <button
+                    style={{ background: "#ff9800", color: "#fff", border: "none", borderRadius: 8, padding: "10px 28px", fontWeight: 600, fontSize: 16, cursor: "pointer" }}
+                    onClick={() => navigate("/seed-promotion")}
+                >
+                    促销管理
+                </button>
             </div>
         </div>
     );
diff --git a/front/src/App.js b/front/src/App.js
index 58fb58c..ad42aff 100644
--- a/front/src/App.js
+++ b/front/src/App.js
@@ -1,5 +1,6 @@
 import React from "react";
 import { BrowserRouter as Router, Routes, Route, useNavigate, Link, Navigate } from "react-router-dom";
+import HomeIcon from "@mui/icons-material/Home";
 import MovieIcon from "@mui/icons-material/Movie";
 import EmailIcon from "@mui/icons-material/Email";
 import MusicNoteIcon from "@mui/icons-material/MusicNote";
@@ -31,6 +32,8 @@
 import MigrationPage from './MigrationPage';
 import BegSeedPage from "./BegSeedPage";
 import BegInfo from "./BegInfo";
+import SeedPromotionPage from "./SeedPromotionPage";
+import HomePage from "./HomePage";
 
 
 const navItems = [
@@ -160,6 +163,7 @@
         <Route path="/" element={<Navigate to="/login" replace />} />
         {/* Protected routes */}
         <Route element={<RequireAuth />}>
+          <Route path="/home" element={<HomePage />} />
           <Route path="/movie" element={<MoviePage />} />
           <Route path="/tv" element={<TVPage />} />
           <Route path="/music" element={<MusicPage />} />
@@ -175,6 +179,7 @@
           <Route path="/admin" element={<AdminPage />} />
           <Route path="/appeal-review" element={<AppealPage />} />
           <Route path="/migration-review" element={<MigrationPage />} />
+          <Route path="/seed-promotion" element={<SeedPromotionPage />} />
           <Route path="/begseed" element={<BegSeedPage />} />
           <Route path="/begseed/:begid" element={<BegInfo />} />
         </Route>
diff --git a/front/src/HomePage.js b/front/src/HomePage.js
new file mode 100644
index 0000000..a657a72
--- /dev/null
+++ b/front/src/HomePage.js
@@ -0,0 +1,126 @@
+import React from "react";
+import HomeIcon from "@mui/icons-material/Home";
+import MovieIcon from "@mui/icons-material/Movie";
+import EmailIcon from "@mui/icons-material/Email";
+import MusicNoteIcon from "@mui/icons-material/MusicNote";
+import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople";
+import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
+import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
+import PersonIcon from "@mui/icons-material/Person";
+import AccountCircleIcon from "@mui/icons-material/AccountCircle";
+import ForumIcon from "@mui/icons-material/Forum";
+import HelpIcon from "@mui/icons-material/Help";
+import { useNavigate } from "react-router-dom";
+import "./App.css";
+
+// 导航栏
+const navItems = [
+    { label: "首页", icon: <HomeIcon />, path: "/home" },
+    { label: "电影", icon: <MovieIcon />, path: "/movie" },
+    { label: "剧集", icon: <EmailIcon />, path: "/tv" },
+    { label: "音乐", icon: <MusicNoteIcon />, path: "/music" },
+    { label: "动漫", icon: <EmojiPeopleIcon />, path: "/anime" },
+    { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },
+    { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },
+    { label: "资料", icon: <PersonIcon />, path: "/info" },
+    { label: "论坛", icon: <ForumIcon />, path: "/forum" },
+    { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
+    { label: "求种", icon: <HelpIcon />, path: "/begseed" },
+];
+
+// 示例种子数据
+const exampleSeeds = [
+    {
+        id: 1,
+        tags: "电影,科幻",
+        title: "三体 1080P 蓝光",
+        popularity: 123,
+        user: { username: "Alice" },
+    },
+    {
+        id: 2,
+        tags: "动漫,热血",
+        title: "灌篮高手 国语配音",
+        popularity: 88,
+        user: { username: "Bob" },
+    },
+    {
+        id: 3,
+        tags: "音乐,流行",
+        title: "周杰伦-稻香",
+        popularity: 56,
+        user: { username: "Jay" },
+    },
+    {
+        id: 4,
+        tags: "剧集,悬疑",
+        title: "隐秘的角落",
+        popularity: 77,
+        user: { username: "小明" },
+    },
+];
+
+export default function HomePage() {
+    const navigate = useNavigate();
+
+    return (
+        <div className="container">
+            {/* 顶部空白与电影界面一致 */}
+            <div style={{ height: 80 }} />
+            {/* 用户栏 */}
+            <div className="user-bar" style={{ position: 'fixed', top: 18, right: 42, zIndex: 100, display: 'flex', alignItems: 'center', background: '#e0f3ff', borderRadius: 12, padding: '6px 18px', boxShadow: '0 2px 8px #b2d8ea', minWidth: 320, minHeight: 48, width: 420 }}>
+                <div style={{ cursor: 'pointer', marginRight: 16 }} onClick={() => navigate('/user')}>
+                    <AccountCircleIcon style={{ fontSize: 38, color: '#1a237e', background: '#e0f3ff', borderRadius: '50%' }} />
+                </div>
+                <div style={{ color: '#222', fontWeight: 500, marginRight: 24 }}>用户栏</div>
+                <div style={{ display: 'flex', gap: 28, flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
+                    <span style={{ color: '#1976d2', fontWeight: 500 }}>魔力值: <b>12345</b></span>
+                    <span style={{ color: '#1976d2', fontWeight: 500 }}>分享率: <b>2.56</b></span>
+                    <span style={{ color: '#1976d2', fontWeight: 500 }}>上传量: <b>100GB</b></span>
+                    <span style={{ color: '#1976d2', fontWeight: 500 }}>下载量: <b>50GB</b></span>
+                </div>
+            </div>
+            {/* 下方内容整体下移,留出与电影界面一致的间距 */}
+            <div style={{ height: 32 }} />
+            <nav className="nav-bar card">
+                {navItems.map((item) => (
+                    <div
+                        key={item.label}
+                        className={item.label === "首页" ? "nav-item active" : "nav-item"}
+                        onClick={() => navigate(item.path)}
+                    >
+                        {item.icon}
+                        <span>{item.label}</span>
+                    </div>
+                ))}
+            </nav>
+            <div className="table-section card">
+                <table className="movie-table">
+                    <thead>
+                        <tr>
+                            <th>标签</th>
+                            <th>标题</th>
+                            <th>热度</th>
+                            <th>发布者</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {exampleSeeds.map((seed) => (
+                            <tr key={seed.id}>
+                                <td>{seed.tags}</td>
+                                <td>
+                                    <a href={`/torrent/${seed.id}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+                                        {seed.title}
+                                    </a>
+                                </td>
+                                <td>{seed.popularity}</td>
+                                <td>{seed.user.username}</td>
+                            </tr>
+                        ))}
+                    </tbody>
+                </table>
+            </div>
+            <div style={{ height: 32 }} />
+        </div>
+    );
+}
\ No newline at end of file
diff --git a/front/src/LoginPage.js b/front/src/LoginPage.js
index 492c018..31718d1 100644
--- a/front/src/LoginPage.js
+++ b/front/src/LoginPage.js
@@ -54,7 +54,7 @@
         return;

       }

       setErrorMessage('');

-      navigate('/movie');

+      navigate('/home');

     } catch (error) {

       setErrorMessage('网络错误,请稍后重试');

     }

diff --git a/front/src/SeedPromotionPage.js b/front/src/SeedPromotionPage.js
new file mode 100644
index 0000000..249533c
--- /dev/null
+++ b/front/src/SeedPromotionPage.js
@@ -0,0 +1,164 @@
+import React, { useEffect, useState } from "react";
+import { API_BASE_URL } from "./config";
+
+// 示例数据,实际应从后端获取
+const mockSeeds = [
+    {
+        seed_id: "seed001",
+        title: "三体 1080P 蓝光",
+        tags: "科幻,电影",
+        popularity: 123,
+        promotion: {
+            start_time: "",
+            end_time: "",
+            discount: 1,
+        },
+    },
+    {
+        seed_id: "seed002",
+        title: "灌篮高手 国语配音",
+        tags: "动画,体育",
+        popularity: 88,
+        promotion: {
+            start_time: "",
+            end_time: "",
+            discount: 1,
+        },
+    },
+];
+
+export default function SeedPromotionPage() {
+    const [seeds, setSeeds] = useState([]);
+    const [currentTime, setCurrentTime] = useState("");
+
+    useEffect(() => {
+        // 获取当前时间,格式为 yyyy-MM-ddTHH:mm
+        const now = new Date();
+        const pad = (n) => n.toString().padStart(2, "0");
+        const localISOTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`;
+        setCurrentTime(localISOTime);
+
+        // 实际应从后端获取种子及促销信息
+        setSeeds(mockSeeds);
+    }, []);
+
+    // 输入框变更处理
+    const handlePromotionChange = (seedId, field, value) => {
+        setSeeds((prev) =>
+            prev.map((s) =>
+                s.seed_id === seedId
+                    ? {
+                        ...s,
+                        promotion: {
+                            ...s.promotion,
+                            [field]: value,
+                        },
+                    }
+                    : s
+            )
+        );
+    };
+
+    // 结束时间校验
+    const isEndTimeInvalid = (start, end) => {
+        return start && end && end < start;
+    };
+
+    return (
+        <div style={{ padding: 40, maxWidth: 900, margin: "0 auto" }}>
+            <h1 style={{ textAlign: "center", marginBottom: 32 }}>种子促销管理</h1>
+            <table style={{ width: "100%", background: "#fff", borderRadius: 10, boxShadow: "0 2px 8px #e0e7ff" }}>
+                <thead>
+                    <tr style={{ background: "#f5f5f5" }}>
+                        <th>标题</th>
+                        <th>标签</th>
+                        <th>热度</th>
+                        <th>促销开始时间</th>
+                        <th>促销结束时间</th>
+                        <th>促销倍率</th>
+                        <th>操作</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {seeds.map((seed) => {
+                        const { start_time, end_time, discount } = seed.promotion;
+                        const endTimeInvalid = isEndTimeInvalid(start_time, end_time);
+                        const canStartPromotion = start_time && end_time && !endTimeInvalid && discount >= 1;
+                        return (
+                            <tr key={seed.seed_id}>
+                                <td>{seed.title}</td>
+                                <td>{seed.tags}</td>
+                                <td>{seed.popularity}</td>
+                                <td>
+                                    <input
+                                        type="datetime-local"
+                                        value={start_time}
+                                        min={currentTime}
+                                        onChange={(e) =>
+                                            handlePromotionChange(seed.seed_id, "start_time", e.target.value)
+                                        }
+                                    />
+                                </td>
+                                <td>
+                                    <input
+                                        type="datetime-local"
+                                        value={end_time}
+                                        min={start_time || currentTime}
+                                        onChange={(e) =>
+                                            handlePromotionChange(seed.seed_id, "end_time", e.target.value)
+                                        }
+                                        style={endTimeInvalid ? { border: "1.5px solid #e53935" } : {}}
+                                    />
+                                    {endTimeInvalid && (
+                                        <div style={{ color: "#e53935", fontSize: 12 }}>
+                                            结束时间不能早于开始时间
+                                        </div>
+                                    )}
+                                </td>
+                                <td>
+                                    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
+                                        <button
+                                            style={{ width: 28, height: 28, fontSize: 18, borderRadius: 4, border: "1px solid #ccc", background: "#f5f5f5", cursor: discount > 1 ? "pointer" : "not-allowed" }}
+                                            onClick={() =>
+                                                discount > 1 &&
+                                                handlePromotionChange(seed.seed_id, "discount", discount - 1)
+                                            }
+                                            disabled={discount <= 1}
+                                        >-</button>
+                                        <span style={{ minWidth: 24, textAlign: "center" }}>{discount}</span>
+                                        <button
+                                            style={{ width: 28, height: 28, fontSize: 18, borderRadius: 4, border: "1px solid #ccc", background: "#f5f5f5", cursor: "pointer" }}
+                                            onClick={() =>
+                                                handlePromotionChange(seed.seed_id, "discount", discount + 1)
+                                            }
+                                        >+</button>
+                                    </div>
+                                </td>
+                                <td>
+                                    <button
+                                        style={{
+                                            background: canStartPromotion ? "#1976d2" : "#ccc",
+                                            color: "#fff",
+                                            border: "none",
+                                            borderRadius: 6,
+                                            padding: "4px 16px",
+                                            cursor: canStartPromotion ? "pointer" : "not-allowed",
+                                            fontWeight: 600,
+                                        }}
+                                        disabled={!canStartPromotion}
+                                        onClick={() => {
+                                            // 这里可调用后端API开启促销
+                                            alert(`已为「${seed.title}」开启促销!`);
+                                        }}
+                                    >
+                                        开启促销
+                                    </button>
+                                </td>
+                            </tr>
+                        );
+                    })}
+                </tbody>
+            </table>
+        </div>
+    );
+}
\ No newline at end of file
diff --git a/front/src/TorrentDetailPage.js b/front/src/TorrentDetailPage.js
index cc2dd24..ab34d98 100644
--- a/front/src/TorrentDetailPage.js
+++ b/front/src/TorrentDetailPage.js
@@ -10,12 +10,13 @@
   const [error, setError] = React.useState(null);

   // 假设你从某个地方获取了 userId(例如登录状态、localStorage 等)

   const [userId] = React.useState('user1550e8400-e29b-41d4-a716-44665544000023'); // 替换为实际的用户 ID

+  const [isFavorite, setIsFavorite] = React.useState(false); // 收藏状态

 

   const handleClick = () => {

     // 构造下载 URL,包含 userId 和 torrentId 参数

     console.log(torrentId)

     const downloadUrl = `${API_BASE_URL}/api/get-torrent?userId=${encodeURIComponent(userId)}&torrentId=${encodeURIComponent(torrentId)}`;

-    

+

     // 发起 GET 请求下载文件

     fetch(downloadUrl)

       .then(response => {

@@ -41,6 +42,11 @@
       });

   };

 

+  // 收藏按钮示例逻辑(仅前端切换)

+  const handleFavorite = () => {

+    setIsFavorite(fav => !fav);

+  };

+

   React.useEffect(() => {

     setLoading(true);

     setError(null);

@@ -64,24 +70,65 @@
   if (!detail) return <div className="container"><h1>未找到详情</h1></div>;

 

   return (

-    <div className="container">

-      <h1>种子详情页</h1>

-      <h2 style={{ fontSize: 'inherit', fontWeight: 'normal', textAlign: 'left' }}>标题: {detail.title || `种子${torrentId}`}</h2>

-      <p style={{ fontSize: 'inherit', textAlign: 'left' }}>简介: {detail.description || `这是种子${torrentId}的详细信息。`}</p>

-      <div style={{ textAlign: 'center', marginTop: '20px' }}>

-        <button 

-          style={{ 

-            padding: '10px 20px', 

-            fontSize: '16px', 

-            cursor: 'pointer', 

-            backgroundColor: '#d3f0ff', 

-            border: 'none', 

-            borderRadius: '4px' 

-          }} 

-          onClick={handleClick}

-        >

-          下载

-        </button>

+    <div className="container" style={{ display: "flex", justifyContent: "center", alignItems: "center", minHeight: "100vh" }}>

+      <div

+        style={{

+          background: "#fff",

+          borderRadius: 16,

+          boxShadow: "0 4px 24px #e0e7ff",

+          padding: "36px 48px",

+          maxWidth: 540,

+          width: "100%",

+          marginTop: 48,

+        }}

+      >

+        <h1 style={{ color: "#1976d2", fontWeight: 700, marginBottom: 24, fontSize: 28, letterSpacing: 1 }}>种子详情页</h1>

+        <div style={{ marginBottom: 18 }}>

+          <div style={{ fontSize: 20, fontWeight: 600, marginBottom: 8, color: "#222" }}>

+            标题:{detail.title || `种子${torrentId}`}

+          </div>

+          <div style={{ fontSize: 16, color: "#555", marginBottom: 8 }}>

+            简介:{detail.description || `这是种子${torrentId}的详细信息。`}

+          </div>

+        </div>

+        <div style={{ display: "flex", gap: 24, marginTop: 32, justifyContent: "center" }}>

+          <button

+            style={{

+              padding: "10px 32px",

+              fontSize: "16px",

+              cursor: "pointer",

+              background: "linear-gradient(90deg, #42a5f5 0%, #1976d2 100%)",

+              color: "#fff",

+              border: "none",

+              borderRadius: "8px",

+              fontWeight: 600,

+              boxShadow: "0 2px 8px #b2d8ea",

+              transition: "background 0.2s",

+            }}

+            onClick={handleClick}

+          >

+            下载

+          </button>

+          <button

+            style={{

+              padding: "10px 32px",

+              fontSize: "16px",

+              cursor: "pointer",

+              background: isFavorite

+                ? "linear-gradient(90deg, #ffb74d 0%, #ff9800 100%)"

+                : "linear-gradient(90deg, #f0f0f0 0%, #bdbdbd 100%)",

+              color: isFavorite ? "#fff" : "#333",

+              border: "none",

+              borderRadius: "8px",

+              fontWeight: 600,

+              boxShadow: isFavorite ? "0 2px 8px #ffe0b2" : "0 2px 8px #e0e7ff",

+              transition: "background 0.2s",

+            }}

+            onClick={handleFavorite}

+          >

+            {isFavorite ? "已收藏" : "收藏"}

+          </button>

+        </div>

       </div>

     </div>

   );

diff --git a/src/main/java/entity/SeedPromotion.java b/src/main/java/entity/SeedPromotion.java
new file mode 100644
index 0000000..7bea9df
--- /dev/null
+++ b/src/main/java/entity/SeedPromotion.java
@@ -0,0 +1,32 @@
+package entity;
+
+import javax.persistence.*;
+import java.util.Date;
+import com.querydsl.core.annotations.QueryEntity;
+
+@QueryEntity
+@Entity
+@Table(name = "SeedPromotion")
+public class SeedPromotion {
+
+    @Id
+    @Column(name = "promotion_id", length = 64, nullable = false)
+    public String promotionId;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "seed_id", referencedColumnName = "seed_id", foreignKey = @ForeignKey(name = "fk_seed_promotion"), nullable = false)
+    public Seed seed;
+
+    @Column(name = "start_time", nullable = false)
+    @Temporal(TemporalType.TIMESTAMP)
+    public Date startTime;
+
+    @Column(name = "end_time", nullable = false)
+    @Temporal(TemporalType.TIMESTAMP)
+    public Date endTime;
+
+    @Column(name = "discount", nullable = false)
+    public int discount;
+
+    public SeedPromotion() {}
+}
\ No newline at end of file
diff --git "a/\345\274\200\345\217\221\346\226\207\346\241\243/create.sql" "b/\345\274\200\345\217\221\346\226\207\346\241\243/create.sql"
index 12d9233..24fe897 100644
--- "a/\345\274\200\345\217\221\346\226\207\346\241\243/create.sql"
+++ "b/\345\274\200\345\217\221\346\226\207\346\241\243/create.sql"
@@ -188,4 +188,15 @@
     FOREIGN KEY (`user_id`) REFERENCES `User` (`user_id`) ON DELETE CASCADE,
     FOREIGN KEY (`beg_id`) REFERENCES `BegSeed` (`beg_id`) ON DELETE CASCADE,
     FOREIGN KEY (`seed_id`) REFERENCES `Seed` (`seed_id`) ON DELETE CASCADE
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
+
+-- 种子促销表
+CREATE TABLE `SeedPromotion` (
+    `promotion_id` VARCHAR(64) NOT NULL,
+    `seed_id` VARCHAR(64) NOT NULL,
+    `start_time` DATETIME NOT NULL,
+    `end_time` DATETIME NOT NULL,
+    `discount` TINYINT NOT NULL DEFAULT 1 COMMENT '折扣率, 1表示无折扣',
+    PRIMARY KEY (`promotion_id`),
+    FOREIGN KEY (`seed_id`) REFERENCES `Seed` (`seed_id`) ON DELETE CASCADE
 ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
\ No newline at end of file