# Phase 2 · 前端页面代码 · 终端粘贴执行版 · 邀请码+主页+登录注册+管理后台

## 📋 说明

<aside>
📌

本页包含萌喵写作网 P0 阶段核心页面的前端代码。
技术栈：Next.js 14 (App Router) + Tailwind CSS
操作方式：在腾讯云终端逐个 Step 粘贴执行，跟 Phase 1 一模一样。
项目路径：`~/feimao-platform/src/app/`

</aside>

---

## 🔰 操作前须知

- 每个 Step 复制整个代码框 → 粘贴到腾讯云终端 → 回车
- 看到命令行回到 `$` 提示符就是成功了
- **先做 Step 0（创建文件夹）→ 再按顺序粘贴 Step 1~6 → 最后 Step 7 构建重启**
- 管理后台代码在页面底部备用区，等网站跑通再做
- 粘贴前先 `Ctrl+C` 确保终端没有在运行别的命令

---

## Step 0 · 创建新目录

```bash
mkdir -p ~/feimao-platform/src/app/home
mkdir -p ~/feimao-platform/src/app/register
```

---

## Step 1 · 全局样式替换（globals.css）

```bash
cat > ~/feimao-platform/src/app/globals.css << 'ENDOFFILE'
@tailwind base;
@tailwind components;
@tailwind utilities;

/* 光湖统一设计语言 */
:root {
  --gl-primary: #6366f1;
  --gl-primary-dark: #4f46e5;
  --gl-primary-light: #a5b4fc;
  --gl-bg: #0f0f1a;
  --gl-bg-card: #1a1a2e;
  --gl-bg-hover: #252540;
  --gl-text: #e2e8f0;
  --gl-text-muted: #94a3b8;
  --gl-border: #2d2d4a;
  --gl-accent: #f59e0b;
  --gl-success: #10b981;
  --gl-danger: #ef4444;
}

body {
  background-color: var(--gl-bg);
  color: var(--gl-text);
  font-family: 'Inter', 'Noto Sans SC', system-ui, sans-serif;
  min-height: 100vh;
}

::selection {
  background: rgba(99, 102, 241, 0.35);
  color: #fff;
}

::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 3px; }

.gl-card {
  background: var(--gl-bg-card);
  border: 1px solid var(--gl-border);
  border-radius: 16px;
  transition: all 0.3s ease;
}
.gl-card:hover {
  border-color: var(--gl-primary);
  box-shadow: 0 0 20px rgba(99, 102, 241, 0.15);
}

.gl-btn {
  padding: 12px 32px;
  border-radius: 12px;
  font-weight: 600;
  transition: all 0.2s ease;
  cursor: pointer;
  border: none;
}
.gl-btn-primary {
  background: linear-gradient(135deg, var(--gl-primary), var(--gl-primary-dark));
  color: white;
}
.gl-btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4);
}
.gl-btn-outline {
  background: transparent;
  border: 1px solid var(--gl-border);
  color: var(--gl-text);
}
.gl-btn-outline:hover {
  border-color: var(--gl-primary);
  color: var(--gl-primary-light);
}

.gl-input {
  background: var(--gl-bg);
  border: 1px solid var(--gl-border);
  border-radius: 12px;
  padding: 14px 20px;
  color: var(--gl-text);
  font-size: 16px;
  width: 100%;
  outline: none;
  transition: border-color 0.2s;
}
.gl-input:focus {
  border-color: var(--gl-primary);
  box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
.gl-input::placeholder {
  color: var(--gl-text-muted);
}
ENDOFFILE
```

---

## Step 2 · 根布局替换（layout.tsx）

```bash
cat > ~/feimao-platform/src/app/layout.tsx << 'ENDOFFILE'
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "萌喵写作网 · AI人格体驱动的智能写作平台",
  description: "陪你一起创作成长的平台",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="zh-CN">
      <head>
        <link
          href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap"
          rel="stylesheet"
        />
      </head>
      <body className="antialiased min-h-screen">
        {children}
      </body>
    </html>
  );
}
ENDOFFILE
```

---

## Step 3 · 邀请码门禁页（page.tsx · 入口首页）

```bash
cat > ~/feimao-platform/src/app/page.tsx << 'ENDOFFILE'
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";

export default function InvitePage() {
  const [code, setCode] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const router = useRouter();

  const handleSubmit = async () => {
    if (!code.trim()) {
      setError("请输入邀请码");
      return;
    }
    setLoading(true);
    setError("");
    try {
      // TODO: 对接后端验证接口
      await new Promise((r) => setTimeout(r, 800));
      localStorage.setItem("gl_invite_code", code);
      router.push("/home");
    } catch {
      setError("邀请码无效，请重新输入");
    } finally {
      setLoading(false);
    }
  };

  return (
    <div
      className="min-h-screen flex items-center justify-center p-4"
      style= background: "radial-gradient(ellipse at center, #1a1a3e 0%, #0f0f1a 70%)" 
    >
      <div className="gl-card p-10 w-full max-w-[420px] aspect-square flex flex-col items-center justify-center gap-6">
        <div className="text-5xl mb-2">🌊</div>
        <div className="text-center">
          <h1 className="text-xl font-bold tracking-wide" style= color: "var(--gl-text)" >
            光湖码字平台 · 萌喵写作网
          </h1>
          <p className="mt-2 text-sm" style= color: "var(--gl-text-muted)" >
            陪你一起创作成长的平台
          </p>
        </div>
        <div className="w-full space-y-3">
          <input
            type="text"
            className="gl-input text-center tracking-widest"
            placeholder="请输入邀请码"
            value={code}
            onChange={(e) => { setCode(e.target.value); setError(""); }}
            onKeyDown={(e) => e.key === "Enter" && handleSubmit()}
          />
          {error && (
            <p className="text-center text-sm" style= color: "var(--gl-danger)" >{error}</p>
          )}
        </div>
        <button
          className="gl-btn gl-btn-primary w-full"
          onClick={handleSubmit}
          disabled={loading}
        >
          {loading ? "验证中..." : "进入光湖"}
        </button>
        <p className="text-xs" style= color: "var(--gl-text-muted)" >
          🐱 Powered by HoloLake · 光湖语言人格平台
        </p>
      </div>
    </div>
  );
}
ENDOFFILE
```

---

## Step 4 · 主页面（home/page.tsx · 对话框+五大模块）

```bash
cat > ~/feimao-platform/src/app/home/page.tsx << 'ENDOFFILE'
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";

const modules = [
  { icon: "📚", name: "学习", desc: "拆书分析，和AI一起成长", color: "#6366f1" },
  { icon: "✍️", name: "写作", desc: "创作你自己的作品", color: "#8b5cf6" },
  { icon: "🎬", name: "剧本", desc: "剧本创作，提示词出剧本", color: "#ec4899" },
  { icon: "💡", name: "创意", desc: "五大作坊，灵感生成", color: "#f59e0b" },
  { icon: "💬", name: "论坛", desc: "讨论交流，建议反馈", color: "#10b981" },
];

export default function HomePage() {
  const router = useRouter();
  const [isLoggedIn] = useState(false);

  return (
    <div
      className="min-h-screen flex flex-col"
      style= background: "radial-gradient(ellipse at top, #1a1a3e 0%, #0f0f1a 60%)" 
    >
      <nav className="flex items-center justify-between px-8 py-4">
        <div className="flex items-center gap-3">
          <span className="text-2xl">🐱</span>
          <span className="font-bold text-lg" style= color: "var(--gl-text)" >
            萌喵写作网
          </span>
        </div>
        <div className="flex items-center gap-3">
          {!isLoggedIn && (
            <>
              <button
                className="gl-btn gl-btn-outline text-sm py-2 px-5"
                onClick={() => router.push("/login")}
              >
                登录
              </button>
              <button
                className="gl-btn gl-btn-primary text-sm py-2 px-5"
                onClick={() => router.push("/register")}
              >
                注册
              </button>
            </>
          )}
        </div>
      </nav>

      <main className="flex-1 flex flex-col items-center justify-center px-4 pb-8">
        <div className="text-center mb-8">
          <h1 className="text-3xl font-bold mb-3" style= color: "var(--gl-text)" >
            萌喵写作网
          </h1>
          <p style= color: "var(--gl-text-muted)" >
            你的专属AI人格体，陪你一起创作成长
          </p>
        </div>

        <div className="gl-card w-full max-w-2xl p-6 mb-8">
          <div className="flex items-start gap-4 mb-4">
            <div
              className="w-10 h-10 rounded-full flex items-center justify-center text-xl"
              style= background: "var(--gl-bg-hover)" 
            >
              🐱
            </div>
            <div className="flex-1 p-4 rounded-xl" style= background: "var(--gl-bg)" >
              <p className="text-sm" style= color: "var(--gl-text)" >
                嗨～我是你的专属萌喵人格体 🐱 注册账号后，我会一直陪着你写作、学习、创作。准备好了吗？
              </p>
            </div>
          </div>
          {!isLoggedIn ? (
            <div
              className="text-center space-y-4 pt-4"
              style= borderTop: "1px solid var(--gl-border)" 
            >
              <p className="text-sm" style= color: "var(--gl-text-muted)" >
                注册领取你的专属人格体，开始创作之旅
              </p>
              <div className="flex gap-3 justify-center">
                <button
                  className="gl-btn gl-btn-outline py-2 px-6"
                  onClick={() => router.push("/login")}
                >
                  登录
                </button>
                <button
                  className="gl-btn gl-btn-primary py-2 px-6"
                  onClick={() => router.push("/register")}
                >
                  注册领取你的专属人格体
                </button>
              </div>
            </div>
          ) : (
            <div
              className="flex gap-3 pt-4"
              style= borderTop: "1px solid var(--gl-border)" 
            >
              <input className="gl-input" placeholder="和你的人格体说点什么..." />
              <button className="gl-btn gl-btn-primary whitespace-nowrap">发送</button>
            </div>
          )}
        </div>

        <div className="grid grid-cols-5 gap-4 w-full max-w-3xl">
          {modules.map((m) => (
            <button
              key={m.name}
              className="gl-card p-5 flex flex-col items-center gap-3 cursor-pointer hover:scale-105 transition-transform"
            >
              <div className="text-3xl">{m.icon}</div>
              <span className="font-semibold text-sm" style= color: "var(--gl-text)" >
                {m.name}
              </span>
              <span
                className="text-xs text-center leading-tight"
                style= color: "var(--gl-text-muted)" 
              >
                {m.desc}
              </span>
            </button>
          ))}
        </div>
      </main>

      <footer className="text-center py-4 text-xs" style= color: "var(--gl-text-muted)" >
        🌊 Powered by HoloLake · 光湖语言人格平台
      </footer>
    </div>
  );
}
ENDOFFILE
```

---

## Step 5 · 登录页（login/page.tsx）

```bash
cat > ~/feimao-platform/src/app/login/page.tsx << 'ENDOFFILE'
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";

export default function LoginPage() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  const router = useRouter();

  const handleLogin = async () => {
    if (!username || !password) {
      setError("请填写用户名和密码");
      return;
    }
    await new Promise((r) => setTimeout(r, 500));
    localStorage.setItem("gl_user", username);
    router.push("/home");
  };

  return (
    <div
      className="min-h-screen flex items-center justify-center p-4"
      style= background: "radial-gradient(ellipse at center, #1a1a3e 0%, #0f0f1a 70%)" 
    >
      <div className="gl-card p-10 w-full max-w-[400px] flex flex-col items-center gap-6">
        <div className="text-4xl">🐱</div>
        <h1 className="text-xl font-bold">登录萌喵写作网</h1>
        <div className="w-full space-y-4">
          <input
            className="gl-input"
            placeholder="用户名"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
          <input
            className="gl-input"
            placeholder="密码"
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && handleLogin()}
          />
          {error && (
            <p className="text-sm text-center" style= color: "var(--gl-danger)" >
              {error}
            </p>
          )}
        </div>
        <button className="gl-btn gl-btn-primary w-full" onClick={handleLogin}>
          登录
        </button>
        <p className="text-sm" style= color: "var(--gl-text-muted)" >
          还没有账号？
          <span
            className="cursor-pointer ml-1"
            style= color: "var(--gl-primary-light)" 
            onClick={() => router.push("/register")}
          >
            立即注册
          </span>
        </p>
      </div>
    </div>
  );
}
ENDOFFILE
```

---

## Step 6 · 注册页（register/page.tsx）

```bash
cat > ~/feimao-platform/src/app/register/page.tsx << 'ENDOFFILE'
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";

export default function RegisterPage() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPwd, setConfirmPwd] = useState("");
  const [error, setError] = useState("");
  const router = useRouter();

  const handleRegister = async () => {
    if (!username || !password || !confirmPwd) {
      setError("请填写所有字段");
      return;
    }
    if (password !== confirmPwd) {
      setError("两次密码不一致");
      return;
    }
    if (password.length < 6) {
      setError("密码至少6位");
      return;
    }
    await new Promise((r) => setTimeout(r, 500));
    localStorage.setItem("gl_user", username);
    router.push("/home");
  };

  return (
    <div
      className="min-h-screen flex items-center justify-center p-4"
      style= background: "radial-gradient(ellipse at center, #1a1a3e 0%, #0f0f1a 70%)" 
    >
      <div className="gl-card p-10 w-full max-w-[400px] flex flex-col items-center gap-6">
        <div className="text-4xl">🐱</div>
        <div className="text-center">
          <h1 className="text-xl font-bold">注册萌喵写作网</h1>
          <p className="text-sm mt-2" style= color: "var(--gl-text-muted)" >
            注册领取你的专属人格体
          </p>
        </div>
        <div className="w-full space-y-4">
          <input
            className="gl-input"
            placeholder="用户名"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
          <input
            className="gl-input"
            placeholder="密码"
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <input
            className="gl-input"
            placeholder="确认密码"
            type="password"
            value={confirmPwd}
            onChange={(e) => setConfirmPwd(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && handleRegister()}
          />
          {error && (
            <p className="text-sm text-center" style= color: "var(--gl-danger)" >
              {error}
            </p>
          )}
        </div>
        <button className="gl-btn gl-btn-primary w-full" onClick={handleRegister}>
          注册并领取人格体
        </button>
        <p className="text-sm" style= color: "var(--gl-text-muted)" >
          已有账号？
          <span
            className="cursor-pointer ml-1"
            style= color: "var(--gl-primary-light)" 
            onClick={() => router.push("/login")}
          >
            去登录
          </span>
        </p>
      </div>
    </div>
  );
}
ENDOFFILE
```

---

## Step 7 · 构建 + 重启 🚀

```bash
cd ~/feimao-platform
npm run build && pm2 restart feimao-platform
```

看到 `✓ Generating static pages` + PM2 显示 `restart` 就是全部成功 ✅

---

## Step 8 · 验证页面

浏览器打开这几个地址：

- 邀请码页：`http://43.133.36.90`
- 主页面：`http://43.133.36.90/home`
- 登录页：`http://43.133.36.90/login`
- 注册页：`http://43.133.36.90/register`

全部能打开就是成功 🎉

---

---

## 📦 管理后台代码（备用 · 等网站跑通再做）

<aside>
📌

以下是管理后台的代码，网站前台全部跑通后，再执行这部分。
执行前先运行：`mkdir -p ~/feimao-platform/src/app/admin/codes`

</aside>

### 后台 Step A · 管理后台布局（admin/layout.tsx）

```bash
cat > ~/feimao-platform/src/app/admin/layout.tsx << 'ENDOFFILE'
"use client";
import { useRouter, usePathname } from "next/navigation";

const menuItems = [
  { name: "数据面板", path: "/admin", icon: "📊" },
  { name: "兑换码管理", path: "/admin/codes", icon: "🎫" },
  { name: "历史记录", path: "/admin/history", icon: "📜" },
  { name: "用户管理", path: "/admin/users", icon: "👤" },
];

export default function AdminLayout({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const pathname = usePathname();

  return (
    <div className="min-h-screen flex" style= background: "var(--gl-bg)" >
      <aside
        className="w-56 flex flex-col p-4 border-r"
        style= borderColor: "var(--gl-border)", background: "var(--gl-bg-card)" 
      >
        <div className="flex items-center gap-2 mb-8 px-2">
          <span className="text-xl">🐱</span>
          <span className="font-bold text-sm">萌喵管理后台</span>
        </div>
        <nav className="space-y-1">
          {menuItems.map((item) => (
            <button
              key={item.path}
              onClick={() => router.push(item.path)}
              className="w-full text-left px-4 py-3 rounded-xl text-sm flex items-center gap-3 transition-colors"
              style=
                background: pathname === item.path ? "var(--gl-bg-hover)" : "transparent",
                color: pathname === item.path ? "var(--gl-primary-light)" : "var(--gl-text-muted)",
                fontWeight: pathname === item.path ? 600 : 400,
              
            >
              <span>{item.icon}</span>
              <span>{item.name}</span>
            </button>
          ))}
        </nav>
        <div className="mt-auto pt-4 px-2 text-xs" style= color: "var(--gl-text-muted)" >
          🌊 HoloLake Admin
        </div>
      </aside>
      <main className="flex-1 p-8 overflow-auto">{children}</main>
    </div>
  );
}
ENDOFFILE
```

---

### 后台 Step B · 管理后台首页（admin/page.tsx）

```bash
cat > ~/feimao-platform/src/app/admin/page.tsx << 'ENDOFFILE'
const stats = [
  { label: "今日活跃", value: "1", icon: "👥", color: "#6366f1" },
  { label: "总注册用户", value: "15", icon: "📈", color: "#8b5cf6" },
  { label: "AI调用次数", value: "148", icon: "🤖", color: "#ec4899" },
  { label: "总生成字数", value: "2.3M", icon: "✍️", color: "#f59e0b" },
  { label: "敏感词触发率", value: "0.05%", icon: "🛡️", color: "#10b981" },
];

export default function AdminDashboard() {
  return (
    <div>
      <h1 className="text-2xl font-bold mb-6">📊 数据监控面板</h1>
      <div className="grid grid-cols-5 gap-4 mb-8">
        {stats.map((s) => (
          <div key={s.label} className="gl-card p-5 text-center">
            <div className="text-2xl mb-2">{s.icon}</div>
            <div className="text-2xl font-bold mb-1" style= color: s.color >
              {s.value}
            </div>
            <div className="text-xs" style= color: "var(--gl-text-muted)" >
              {s.label}
            </div>
          </div>
        ))}
      </div>
      <div className="gl-card p-6">
        <h2 className="font-semibold mb-4">📋 最近活动</h2>
        <div className="space-y-3">
          {[
            { time: "17:30", text: '新兑换码 #227 已生成 (50万字)', status: "未核销" },
            { time: "16:57", text: '新兑换码 #226 已生成 (50万字)', status: "未核销" },
            { time: "16:54", text: '用户「莫戈」使用兑换码 #225', status: "已核销" },
            { time: "20:21", text: '兑换码 #224 已生成 (50万字)', status: "未核销" },
          ].map((item, i) => (
            <div
              key={i}
              className="flex items-center justify-between py-2 px-4 rounded-lg"
              style= background: "var(--gl-bg)" 
            >
              <div className="flex items-center gap-3">
                <span className="text-xs font-mono" style= color: "var(--gl-text-muted)" >
                  {item.time}
                </span>
                <span className="text-sm">{item.text}</span>
              </div>
              <span
                className={`text-xs px-3 py-1 rounded-full ${
                  item.status === "已核销"
                    ? "bg-green-900/30 text-green-400"
                    : "bg-yellow-900/30 text-yellow-400"
                }`}
              >
                {item.status}
              </span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
ENDOFFILE
```

---

### 后台 Step C · 兑换码管理页（admin/codes/page.tsx）

```bash
cat > ~/feimao-platform/src/app/admin/codes/page.tsx << 'ENDOFFILE'
"use client";
import { useState } from "react";

const mockCodes = [
  { id: 227, code: "RFO26yHXGkrvDo0gmqQMZfd56a16b9b2", amount: 500000, creator: "dfm666", user: "-", status: "未核销", time: "2026-05-27 17:30:26" },
  { id: 226, code: "KGklS5A4Izq9ZpyfnCIOBRFc6a16b1e5", amount: 500000, creator: "dfm666", user: "-", status: "未核销", time: "2026-05-27 16:57:09" },
  { id: 225, code: "H5PeEDd6k9cWaZ3sF2480lmV6a16b145", amount: 500000, creator: "dfm666", user: "莫戈", status: "已核销", time: "2026-05-27 16:54:29" },
  { id: 224, code: "fmAyO1SUuhd54FqsNkVDg0cp6a159050", amount: 500000, creator: "dfm666", user: "-", status: "未核销", time: "2026-05-26 20:21:36" },
  { id: 223, code: "83hWlgUjBr1HLEAb2pZdC67M6a1569e2", amount: 500000, creator: "dfm666", user: "Dostoyevsky", status: "已核销", time: "2026-05-26 17:37:38" },
  { id: 220, code: "BQCs8R42m07Fk5uf1h3yv6Li6a13c237", amount: 500000, creator: "dfm666", user: "-", status: "未核销", time: "2026-05-25 11:29:59" },
  { id: 219, code: "t9K7Exh8qiORsMSLA2UovFnj6a102afb", amount: 500000, creator: "dfm666", user: "朝闻道", status: "已核销", time: "2026-05-22 18:07:55" },
  { id: 218, code: "GAIm5Oqbj7fTEJYr6nFz0Ps86a102ae8", amount: 500000, creator: "dfm666", user: "158****5024", status: "已核销", time: "2026-05-22 18:07:36" },
];

const tabs = ["全部", "未核销", "已核销", "已返现"];

export default function CodesPage() {
  const [activeTab, setActiveTab] = useState("全部");
  const [showAddModal, setShowAddModal] = useState(false);
  const [newAmount, setNewAmount] = useState("500000");

  const filteredCodes =
    activeTab === "全部" ? mockCodes : mockCodes.filter((c) => c.status === activeTab);

  return (
    <div>
      <h1 className="text-2xl font-bold mb-6">🎫 兑换码管理</h1>
      <div className="flex gap-2 mb-4">
        {tabs.map((tab) => (
          <button
            key={tab}
            onClick={() => setActiveTab(tab)}
            className="px-4 py-2 rounded-lg text-sm transition-colors"
            style={{
              background: activeTab === tab ? "var(--gl-primary)" : "var(--gl-bg-card)",
              color: activeTab === tab ? "white" : "var(--gl-text-muted)",
              border: `1px solid ${activeTab === tab ? "var(--gl-primary)" : "var(--gl-border)"}`,
            }}
          >
            {tab}
          </button>
        ))}
      </div>
      <div className="flex gap-3 mb-4">
        <button
          className="gl-btn gl-btn-primary text-sm py-2 px-4"
          onClick={() => setShowAddModal(true)}
        >
          + 添加
        </button>
        <button className="gl-btn gl-btn-outline text-sm py-2 px-4">
          批量生成免费兑换码
        </button>
        <div className="ml-auto flex gap-2">
          {["JSON", "CSV", "Excel"].map((f) => (
            <button key={f} className="gl-btn gl-btn-outline text-xs py-1 px-3">
              {f}
            </button>
          ))}
        </div>
      </div>
      <div className="gl-card overflow-hidden">
        <table className="w-full text-sm">
          <thead>
            <tr style= background: "var(--gl-bg-hover)", color: "var(--gl-text-muted)" >
              <th className="p-3 text-left">ID</th>
              <th className="p-3 text-left">卡密</th>
              <th className="p-3 text-left">字数</th>
              <th className="p-3 text-left">生成用户</th>
              <th className="p-3 text-left">使用用户</th>
              <th className="p-3 text-left">状态</th>
              <th className="p-3 text-left">创建时间</th>
              <th className="p-3 text-left">操作</th>
            </tr>
          </thead>
          <tbody>
            {filteredCodes.map((row) => (
              <tr
                key={row.id}
                className="border-t transition-colors"
                style= borderColor: "var(--gl-border)" 
              >
                <td className="p-3 font-mono text-xs">{row.id}</td>
                <td className="p-3 font-mono text-xs max-w-[200px] truncate">{row.code}</td>
                <td className="p-3">{row.amount.toLocaleString()}</td>
                <td className="p-3">{row.creator}</td>
                <td className="p-3">{row.user}</td>
                <td className="p-3">
                  <span
                    className={`text-xs px-2 py-1 rounded-full ${
                      row.status === "已核销"
                        ? "bg-green-900/30 text-green-400"
                        : "bg-yellow-900/30 text-yellow-400"
                    }`}
                  >
                    {row.status}
                  </span>
                </td>
                <td className="p-3 text-xs" style= color: "var(--gl-text-muted)" >
                  {row.time}
                </td>
                <td className="p-3">
                  <button
                    className="text-xs px-3 py-1 rounded-lg"
                    style= background: "var(--gl-primary)", color: "white" 
                  >
                    返现
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        <div
          className="flex items-center justify-between p-4"
          style= borderTop: "1px solid var(--gl-border)" 
        >
          <span className="text-xs" style= color: "var(--gl-text-muted)" >
            显示第 1 到第 {filteredCodes.length} 条记录，总共 15 条记录
          </span>
          <div className="flex gap-1">
            <button
              className="px-3 py-1 rounded text-xs"
              style= background: "var(--gl-primary)", color: "white" 
            >
              1
            </button>
            <button
              className="px-3 py-1 rounded text-xs"
              style= background: "var(--gl-bg-hover)", color: "var(--gl-text-muted)" 
            >
              2
            </button>
          </div>
        </div>
      </div>
      {showAddModal && (
        <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
          <div className="gl-card p-8 w-full max-w-md">
            <div className="flex justify-between items-center mb-6">
              <h2 className="font-bold text-lg">添加兑换码</h2>
              <button
                onClick={() => setShowAddModal(false)}
                className="text-xl"
                style= color: "var(--gl-text-muted)" 
              >
                x
              </button>
            </div>
            <div className="space-y-4">
              <div>
                <label className="text-sm mb-2 block" style= color: "var(--gl-text-muted)" >
                  字数额度
                </label>
                <input
                  className="gl-input"
                  value={newAmount}
                  onChange={(e) => setNewAmount(e.target.value)}
                />
              </div>
              <button
                className="gl-btn gl-btn-primary w-full"
                onClick={() => setShowAddModal(false)}
              >
                确定
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
ENDOFFILE
```

---

### 后台 Step D · 构建重启

```bash
cd ~/feimao-platform
npm run build && pm2 restart feimao-platform
```

然后验证：`http://43.133.36.90/admin` 和 `http://43.133.36.90/admin/codes`

---

<aside>
⚠️

**注意**：这次的代码会替换掉 Phase 1 的首页和登录页。Phase 1 的 /chat 和 /dashboard 路由不受影响，仍然可以访问。

</aside>

<aside>
🐱

**下一步**：基础页面跑通后，再逐个开发五大功能模块页面（用户个人后台 → 写作 → 学习 → 创意 → 剧本 → 论坛）。

</aside>