反向代理配置

步骤 1:创建 D1 数据库
登录 Cloudflare → 左侧「Workers & Pages」→ 顶部「D1」→ 「创建数据库」;
输入数据库名称(如proxy-db)→ 「创建」;
进入数据库控制台 → 执行上面的无注释建表语句。
步骤 2:配置 Workers 绑定
进入你的 Worker → 「设置」→ 「变量」→ 「D1 数据库绑定」;
绑定名称填:PROXY_DB(必须和代码里的env.PROXY_DB一致);
选择你创建的 D1 数据库 → 「保存」。
步骤 3:部署代码
把上面的完整 Workers 代码复制到 Worker 编辑器;
点击「保存并部署」。
五、使用流程
第一次访问:打开 Worker 域名 → 进入初始化界面,设置后台路径(如/admin)、管理员账号密码 → 提交;
登录后台:访问你的域名/admin → 输入账号密码登录;
配置反代参数:
基础配置:可修改后台路径、账号密码;
反代配置:填写源站域名、Workers 域名、HTTP/HTTPS 端口、反代模式、缓存开关 / 时长;
使用反代:直接访问 Worker 域名 → 自动执行反代逻辑(按后台配置)。

数据库

CREATE TABLE IF NOT EXISTS proxy_config (id INTEGER PRIMARY KEY AUTOINCREMENT,admin_path TEXT NOT NULL DEFAULT '/admin',user_path TEXT NOT NULL DEFAULT '/user',username TEXT NOT NULL,password TEXT NOT NULL,target_domain TEXT DEFAULT '',worker_domain TEXT DEFAULT '',http_port INTEGER DEFAULT 0,https_port INTEGER DEFAULT 0,proxy_mode TEXT DEFAULT 'http_only',cache_enabled INTEGER DEFAULT 0,cache_ttl_seconds INTEGER DEFAULT 3600,auth_enabled INTEGER DEFAULT 0,initialized INTEGER DEFAULT 0);
CREATE TABLE IF NOT EXISTS proxy_users (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT NOT NULL,account TEXT NOT NULL UNIQUE,password TEXT NOT NULL,qq_number TEXT NOT NULL UNIQUE,is_banned INTEGER DEFAULT 0,auth_days INTEGER DEFAULT 0,auth_start_time TEXT NOT NULL,auth_end_time TEXT NOT NULL,create_time TEXT NOT NULL);

Workers

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const db = env.PROXY_DB;

    const getBeijingTime = () => {
      const now = new Date();
      const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
      return new Date(utc + (8 * 3600000));
    };

    const calcAuthEndTime = (startTime, days) => {
      const start = new Date(startTime);
      start.setDate(start.getDate() + parseInt(days));
      return start.toISOString();
    };

    const configResult = await db.prepare('SELECT * FROM proxy_config LIMIT 1').all();
    let config = configResult.results[0] || { initialized: 0, user_path: '/user', auth_enabled: 0 };

    if (config.initialized === 0) {
      if (request.method === 'POST') {
        const formData = await request.formData();
        const adminPath = formData.get('admin_path') || '/admin';
        const userPath = formData.get('user_path') || '/user';
        const username = formData.get('username');
        const password = formData.get('password');
        
        if (username && password) {
          const encryptedPwd = btoa(password);
          await db.prepare('INSERT INTO proxy_config (admin_path, user_path, username, password, initialized, auth_enabled) VALUES (?, ?, ?, ?, 1, 0)').bind(adminPath, userPath, username, encryptedPwd).run();
          return Response.redirect(`${url.origin}${adminPath}`, 302);
        }
        return new Response('请填写完整信息', { status: 400 });
      }
      return new Response(getInitHtml(), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    const adminPath = config.admin_path || '/admin';
    if (url.pathname.startsWith(adminPath)) {
      const authHeader = request.headers.get('Authorization');
      const isAdminAuth = authHeader && authHeader === `Basic ${btoa(`${config.username}:${atob(config.password)}`)}`;

      if (!isAdminAuth) {
        return new Response(getLoginHtml(), {
          status: 401,
          headers: { 'WWW-Authenticate': 'Basic realm="Proxy Admin Panel"', 'Content-Type': 'text/html; charset=utf-8' }
        });
      }

      if (request.method === 'POST') {
        const formData = await request.formData();
        const action = formData.get('action');
        
        if (action === 'update_base') {
          const newAdminPath = formData.get('new_admin_path') || config.admin_path;
          const newUserPath = formData.get('new_user_path') || config.user_path;
          const newUsername = formData.get('new_username') || config.username;
          const newPassword = formData.get('new_password');
          const authEnabled = formData.get('auth_enabled') ? 1 : 0;
          const encryptedNewPwd = newPassword ? btoa(newPassword) : config.password;
          
          await db.prepare('UPDATE proxy_config SET admin_path=?, user_path=?, username=?, password=?, auth_enabled=? WHERE id=?').bind(newAdminPath, newUserPath, newUsername, encryptedNewPwd, authEnabled, config.id).run();
          return Response.redirect(`${url.origin}${newAdminPath}`, 302);
        }

        if (action === 'update_proxy') {
          const targetDomain = formData.get('target_domain') || '';
          const workerDomain = formData.get('worker_domain') || '';
          const httpPort = parseInt(formData.get('http_port') || 0);
          const httpsPort = parseInt(formData.get('https_port') || 0);
          const proxyMode = formData.get('proxy_mode') || 'http_only';
          const cacheEnabled = formData.get('cache_enabled') ? 1 : 0;
          const cacheTtl = parseInt(formData.get('cache_ttl') || 3600);
          
          await db.prepare('UPDATE proxy_config SET target_domain=?, worker_domain=?, http_port=?, https_port=?, proxy_mode=?, cache_enabled=?, cache_ttl_seconds=? WHERE id=?').bind(targetDomain, workerDomain, httpPort, httpsPort, proxyMode, cacheEnabled, cacheTtl, config.id).run();
          return Response.redirect(`${url.origin}${adminPath}`, 302);
        }

        if (action === 'manage_user') {
          const userId = parseInt(formData.get('user_id') || 0);
          const operation = formData.get('operation');
          const authDays = parseInt(formData.get('auth_days') || 0);

          if (userId && operation) {
            switch (operation) {
              case 'ban':
                await db.prepare('UPDATE proxy_users SET is_banned=1 WHERE id=?').bind(userId).run();
                break;
              case 'unban':
                await db.prepare('UPDATE proxy_users SET is_banned=0 WHERE id=?').bind(userId).run();
                break;
              case 'update_auth':
                const now = getBeijingTime().toISOString();
                const endTime = calcAuthEndTime(now, authDays);
                await db.prepare('UPDATE proxy_users SET auth_days=?, auth_start_time=?, auth_end_time=? WHERE id=?').bind(authDays, now, endTime, userId).run();
                break;
            }
          }
          return Response.redirect(`${url.origin}${adminPath}#user-manage`, 302);
        }
      }

      const userListResult = await db.prepare('SELECT * FROM proxy_users').all();
      const userList = userListResult.results || [];
      return new Response(getAdminHtml(config, userList), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    const userPath = config.user_path || '/user';
    if (url.pathname.startsWith(userPath)) {
      const path = url.pathname.replace(userPath, '');
      
      if (path === '/register' && request.method === 'POST') {
        const formData = await request.formData();
        const username = formData.get('username');
        const account = formData.get('account');
        const password = formData.get('password');
        const qqNumber = formData.get('qq_number');

        if (!username || !account || !password || !qqNumber) {
          return new Response('请填写完整注册信息', { status: 400 });
        }

        const existCheck = await db.prepare('SELECT * FROM proxy_users WHERE account=? OR qq_number=?').bind(account, qqNumber).all();
        if (existCheck.results.length > 0) {
          return new Response('账号或QQ号已存在', { status: 400 });
        }

        const now = getBeijingTime().toISOString();
        const encryptedPwd = btoa(password);
        await db.prepare('INSERT INTO proxy_users (username, account, password, qq_number, is_banned, auth_days, auth_start_time, auth_end_time, create_time) VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?)').bind(username, account, encryptedPwd, qqNumber, now, now, now).run();
        return Response.redirect(`${url.origin}${userPath}/login`, 302);
      }

      if (path === '/login' && request.method === 'POST') {
        const formData = await request.formData();
        const account = formData.get('account');
        const password = formData.get('password');

        const userResult = await db.prepare('SELECT * FROM proxy_users WHERE account=?').bind(account).all();
        if (userResult.results.length === 0) {
          return new Response(getUserLoginHtml('账号不存在'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
        }

        const user = userResult.results[0];
        if (user.is_banned === 1) {
          return new Response(getUserLoginHtml('账号已被封禁,无法登录!如需解封请联系管理员QQ:3890053645'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
        }

        if (atob(user.password) !== password) {
          return new Response(getUserLoginHtml('密码错误'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
        }

        if (config.auth_enabled === 1) {
          const now = getBeijingTime();
          const authEnd = new Date(user.auth_end_time);
          if (authEnd <= now || user.auth_days <= 0) {
            return new Response(getUserLoginHtml('账号授权已到期,无法登录!如需续期请联系管理员QQ:3890053645'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
          }
        }

        const loginToken = btoa(`${account}-${Date.now()}-${getBeijingTime().getTime()}`);
        return new Response('', {
          status: 302,
          headers: {
            'Location': `${url.origin}`,
            'Set-Cookie': `proxy_login=${loginToken}; Path=/; HttpOnly; Secure; SameSite=Lax`,
            'Content-Type': 'text/html; charset=utf-8'
          }
        });
      }

      if (path === '/find-pwd' && request.method === 'POST') {
        const formData = await request.formData();
        const qqNumber = formData.get('qq_number');
        const newPassword = formData.get('new_password');

        const userResult = await db.prepare('SELECT * FROM proxy_users WHERE qq_number=?').bind(qqNumber).all();
        if (userResult.results.length === 0) {
          return new Response(getUserFindPwdHtml('QQ号未注册'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
        }

        const user = userResult.results[0];
        if (newPassword) {
          const encryptedNewPwd = btoa(newPassword);
          await db.prepare('UPDATE proxy_users SET password=? WHERE qq_number=?').bind(encryptedNewPwd, qqNumber).run();
          return new Response(getUserFindPwdHtml(`账号:${user.account}<br>密码已重置成功,请返回登录`), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
        }

        return new Response(getUserFindPwdHtml(`你的账号是:${user.account}<br>请设置新密码`), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
      }

      if (path === '/register') return new Response(getUserRegisterHtml(), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
      if (path === '/find-pwd') return new Response(getUserFindPwdHtml(''), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
      return new Response(getUserLoginHtml(''), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    const loginCookie = request.headers.get('Cookie') || '';
    if (!loginCookie.includes('proxy_login=')) {
      return Response.redirect(`${url.origin}${userPath}/login`, 302);
    }

    const tokenParts = loginCookie.split('proxy_login=')[1]?.split(';')[0];
    if (!tokenParts) {
      return Response.redirect(`${url.origin}${userPath}/login`, 302);
    }

    const account = atob(tokenParts).split('-')[0];
    const userResult = await db.prepare('SELECT * FROM proxy_users WHERE account=?').bind(account).all();
    if (userResult.results.length === 0) {
      return new Response(getAccessDeniedHtml('账号不存在,请重新登录'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    const user = userResult.results[0];
    if (user.is_banned === 1) {
      return new Response(getAccessDeniedHtml('你的账号已被封禁,无法访问该网站!如需解封请联系管理员QQ:3890053645'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    if (config.auth_enabled === 1) {
      const now = getBeijingTime();
      const authEnd = new Date(user.auth_end_time);
      if (authEnd <= now || user.auth_days <= 0) {
        return new Response(getAccessDeniedHtml('你的账号授权已到期,无法访问该网站!如需续期请联系管理员QQ:3890053645'), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
      }
    }

    if (!config.target_domain || !config.worker_domain) {
      return new Response('请先在后台配置反代参数', { status: 500 });
    }

    let response, targetHost;
    const cfCacheConfig = {
      cacheTtl: config.cache_enabled ? config.cache_ttl_seconds : 0,
      cacheEverything: config.cache_enabled === 1,
      cacheKey: url.href
    };

    switch (config.proxy_mode) {
      case 'https_only':
        if (!config.https_port) throw new Error('HTTPS端口未配置');
        const targetHttps = new URL(`https://${config.target_domain}:${config.https_port}`);
        url.protocol = targetHttps.protocol;
        targetHost = targetHttps.host;
        url.host = targetHost;
        response = await fetch(new Request(url, {
          method: request.method,
          headers: buildHeaders(request.headers, targetHost),
          body: request.body,
          redirect: 'manual',
          duplex: 'half'
        }), { cf: cfCacheConfig });
        break;

      case 'http_only':
        if (!config.http_port) throw new Error('HTTP端口未配置');
        const targetHttp = new URL(`http://${config.target_domain}:${config.http_port}`);
        url.protocol = targetHttp.protocol;
        targetHost = targetHttp.host;
        url.host = targetHost;
        response = await fetch(new Request(url, {
          method: request.method,
          headers: buildHeaders(request.headers, targetHost),
          body: request.body,
          redirect: 'manual',
          duplex: 'half'
        }), { cf: cfCacheConfig });
        break;

      case 'auto':
        if (!config.https_port || !config.http_port) throw new Error('auto模式需同时配置HTTP/HTTPS端口');
        try {
          const targetHttpsAuto = new URL(`https://${config.target_domain}:${config.https_port}`);
          url.protocol = targetHttpsAuto.protocol;
          targetHost = targetHttpsAuto.host;
          url.host = targetHost;
          response = await fetch(new Request(url, {
            method: request.method,
            headers: buildHeaders(request.headers, targetHost),
            body: request.body,
            redirect: 'manual',
            duplex: 'half'
          }), { cf: cfCacheConfig });
        } catch (e) {
          const targetHttpAuto = new URL(`http://${config.target_domain}:${config.http_port}`);
          url.protocol = targetHttpAuto.protocol;
          targetHost = targetHttpAuto.host;
          url.host = targetHost;
          response = await fetch(new Request(url, {
            method: request.method,
            headers: buildHeaders(request.headers, targetHost),
            body: request.body,
            redirect: 'manual',
            duplex: 'half'
          }), { cf: cfCacheConfig });
        }
        break;
    }

    let resp = await handleResponse(response, config);
    return resp;
  },
};

function buildHeaders(headers, host) {
  const h = new Headers(headers);
  h.set('Host', host);
  h.set('X-Forwarded-Host', host);
  h.set('X-Forwarded-Proto', 'https');
  h.set('User-Agent', headers.get('User-Agent') || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
  h.set('Upgrade', headers.get('Upgrade') || '');
  h.set('Connection', headers.get('Connection') || '');
  h.set('Range', headers.get('Range') || '');
  h.set('If-Range', headers.get('If-Range') || '');
  h.set('Cookie', headers.get('Cookie') || '');
  h.set('Set-Cookie', headers.get('Set-Cookie') || '');
  h.delete('X-Forwarded-For');
  return h;
}

async function handleResponse(response, config) {
  let resp = new Response(response.body, response);
  const contentType = resp.headers.get('Content-Type') || '';

  if (contentType.includes('text/') || contentType.includes('html') || contentType.includes('json') || contentType.includes('javascript')) {
    let content = await response.text();
    if (config.https_port) content = content.replace(new RegExp(`https://${config.target_domain}:${config.https_port}`, 'g'), `https://${config.worker_domain}`);
    if (config.http_port) content = content.replace(new RegExp(`http://${config.target_domain}:${config.http_port}`, 'g'), `https://${config.worker_domain}`);
    content = content.replace(new RegExp(`http://${config.target_domain}`, 'g'), `https://${config.worker_domain}`);
    content = content.replace(new RegExp(`https://${config.target_domain}`, 'g'), `https://${config.worker_domain}`);
    resp = new Response(content, response);
  }

  resp.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate');
  resp.headers.set('Pragma', 'no-cache');
  resp.headers.delete('X-Frame-Options');
  resp.headers.delete('Content-Security-Policy');
  resp.headers.set('Access-Control-Allow-Origin', '*');
  resp.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  resp.headers.set('Access-Control-Allow-Headers', 'Range, Cookie, Upgrade, Connection, Content-Type');
  return resp;
}

function getInitHtml() {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>反代管理系统 - 初始化</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .init-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 500px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .submit-btn {
      width: 100%;
      padding: 1rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 1rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 1rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .submit-btn:active {
      transform: translateY(0);
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="init-card">
    <div class="card-header">
      <h1><i class="fa fa-cogs icon"></i>反代管理系统</h1>
      <p>首次使用,请完成初始化配置</p>
    </div>
    <form method="POST">
      <div class="form-group">
        <label class="form-label">后台访问路径</label>
        <input type="text" name="admin_path" class="form-input" placeholder="/admin" value="/admin" required>
      </div>
      <div class="form-group">
        <label class="form-label">用户访问路径(注册/登录)</label>
        <input type="text" name="user_path" class="form-input" placeholder="/user" value="/user" required>
      </div>
      <div class="form-group">
        <label class="form-label">管理员账号</label>
        <input type="text" name="username" class="form-input" placeholder="请设置管理员账号" required>
      </div>
      <div class="form-group">
        <label class="form-label">管理员密码</label>
        <input type="password" name="password" class="form-input" placeholder="请设置管理员密码" required>
      </div>
      <button type="submit" class="submit-btn">
        <i class="fa fa-check-circle icon"></i>完成初始化
      </button>
    </form>
  </div>
</body>
</html>
  `;
}

function getLoginHtml() {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>反代管理系统 - 登录</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .login-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 450px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .alert {
      background: #fee2e2;
      color: #dc2626;
      padding: 1rem;
      border-radius: 8px;
      margin-bottom: 1.5rem;
      text-align: center;
      font-size: 0.95rem;
      border-left: 4px solid #dc2626;
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="login-card">
    <div class="card-header">
      <h1><i class="fa fa-lock icon"></i>管理员登录</h1>
      <p>请输入正确的账号和密码</p>
    </div>
    <div class="alert">
      <i class="fa fa-exclamation-circle"></i> 身份验证失败,请重新登录
    </div>
    <p class="text-center text-gray-600 text-sm">若未初始化,请先完成系统初始化配置</p>
  </div>
</body>
</html>
  `;
}

function getAdminHtml(config, userList) {
  const formatBeijingTime = (isoStr) => {
    const date = new Date(isoStr);
    return date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
  };

  let userTableHtml = '';
  if (userList.length > 0) {
    userTableHtml = userList.map(user => `
      <tr class="border-b border-gray-200">
        <td class="px-4 py-3">${user.username}</td>
        <td class="px-4 py-3">${user.account}</td>
        <td class="px-4 py-3">${atob(user.password)}</td>
        <td class="px-4 py-3">${user.qq_number}</td>
        <td class="px-4 py-3">${user.is_banned === 1 ? '<span class="text-red-600">已封禁</span>' : '<span class="text-green-600">正常</span>'}</td>
        <td class="px-4 py-3">${user.auth_days}天</td>
        <td class="px-4 py-3">${formatBeijingTime(user.auth_end_time)}</td>
        <td class="px-4 py-3">
          <form method="POST" style="display: inline;">
            <input type="hidden" name="action" value="manage_user">
            <input type="hidden" name="user_id" value="${user.id}">
            <input type="hidden" name="operation" value="${user.is_banned === 1 ? 'unban' : 'ban'}">
            <button type="submit" class="px-2 py-1 text-sm rounded ${user.is_banned === 1 ? 'bg-green-600 text-white' : 'bg-red-600 text-white'}">
              ${user.is_banned === 1 ? '解禁' : '封禁'}
            </button>
          </form>
        </td>
        <td class="px-4 py-3">
          <form method="POST" style="display: flex; gap: 0.5rem;">
            <input type="hidden" name="action" value="manage_user">
            <input type="hidden" name="user_id" value="${user.id}">
            <input type="hidden" name="operation" value="update_auth">
            <input type="number" name="auth_days" placeholder="授权天数" class="px-2 py-1 text-sm border rounded" required>
            <button type="submit" class="px-2 py-1 text-sm bg-blue-600 text-white rounded">设置</button>
          </form>
        </td>
      </tr>
    `).join('');
  } else {
    userTableHtml = '<tr><td colspan="9" class="px-4 py-3 text-center text-gray-500">暂无用户</td></tr>';
  }

  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>反代管理系统 - 后台</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: #f8fafc;
      color: #1e293b;
      min-height: 100vh;
      display: flex;
    }
    .sidebar {
      width: 250px;
      background: #1e293b;
      color: #f8fafc;
      min-height: 100vh;
      padding: 1.5rem 0;
      position: fixed;
    }
    .sidebar-header {
      padding: 0 1.5rem 1.5rem;
      border-bottom: 1px solid #334155;
      margin-bottom: 1rem;
    }
    .sidebar-header h2 {
      font-size: 1.2rem;
      font-weight: 600;
      color: #ffffff;
      display: flex;
      align-items: center;
    }
    .sidebar-header h2 i {
      margin-right: 0.75rem;
      color: #38bdf8;
    }
    .sidebar-menu {
      padding: 0.5rem 0;
    }
    .menu-item {
      padding: 0.875rem 1.5rem;
      display: flex;
      align-items: center;
      color: #94a3b8;
      text-decoration: none;
      transition: all 0.2s ease;
      cursor: pointer;
      border-left: 3px solid transparent;
    }
    .menu-item.active {
      background: #334155;
      color: #ffffff;
      border-left-color: #38bdf8;
    }
    .menu-item:hover {
      background: #273449;
      color: #e2e8f0;
    }
    .menu-item i {
      margin-right: 0.75rem;
      font-size: 1rem;
    }
    .main-content {
      margin-left: 250px;
      flex: 1;
      padding: 2rem;
    }
    .content-header {
      margin-bottom: 2rem;
      padding-bottom: 1rem;
      border-bottom: 1px solid #e2e8f0;
    }
    .content-header h1 {
      font-size: 1.75rem;
      font-weight: 600;
      color: #0f172a;
    }
    .content-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
      padding: 2rem;
      margin-bottom: 2rem;
      overflow-x: auto;
    }
    .card-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 1.5rem;
      display: flex;
      align-items: center;
    }
    .card-title i {
      margin-right: 0.75rem;
      color: #2563eb;
    }
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input, .form-select {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus, .form-select:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .form-select {
      appearance: none;
      background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E") right 0.75rem center/1.5rem 1.5rem no-repeat #f8fafc;
      padding-right: 2.5rem;
    }
    .switch-group {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      margin-bottom: 1.5rem;
    }
    .switch-group input {
      width: auto;
      height: 1.25rem;
      width: 1.25rem;
      accent-color: #2563eb;
    }
    .submit-btn {
      padding: 0.875rem 1.5rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 0.95rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 0.5rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .submit-btn:active {
      transform: translateY(0);
    }
    .tab-content {
      display: none;
    }
    .tab-content.active {
      display: block;
    }
    .user-table {
      width: 100%;
      border-collapse: collapse;
      margin-top: 1rem;
    }
    .user-table th {
      padding: 0.75rem 1rem;
      text-align: left;
      background: #f1f5f9;
      font-weight: 500;
      color: #334155;
    }
    .user-table td {
      padding: 0.75rem 1rem;
      color: #1e293b;
    }
    @media (max-width: 768px) {
      .sidebar {
        width: 80px;
        padding: 1rem 0;
      }
      .sidebar-header h2 span {
        display: none;
      }
      .menu-item span {
        display: none;
      }
      .menu-item {
        justify-content: center;
        padding: 1rem;
      }
      .menu-item i {
        margin-right: 0;
        font-size: 1.2rem;
      }
      .main-content {
        margin-left: 80px;
        padding: 1.5rem 1rem;
      }
    }
  </style>
</head>
<body>
  <div class="sidebar">
    <div class="sidebar-header">
      <h2><i class="fa fa-cogs"></i> <span>反代管理系统</span></h2>
    </div>
    <div class="sidebar-menu">
      <div class="menu-item active" onclick="switchTab('base-tab')">
        <i class="fa fa-user-circle"></i>
        <span>基础配置</span>
      </div>
      <div class="menu-item" onclick="switchTab('proxy-tab')">
        <i class="fa fa-cloud"></i>
        <span>反代配置</span>
      </div>
      <div class="menu-item" onclick="switchTab('user-manage-tab')">
        <i class="fa fa-users"></i>
        <span>用户管理</span>
      </div>
    </div>
  </div>
  <div class="main-content">
    <div class="content-header">
      <h1>后台管理中心</h1>
    </div>
    <div id="base-tab" class="tab-content active">
      <div class="content-card">
        <h3 class="card-title"><i class="fa fa-user-circle"></i>基础配置</h3>
        <form method="POST">
          <input type="hidden" name="action" value="update_base">
          <div class="form-group">
            <label class="form-label">后台访问路径</label>
            <input type="text" name="new_admin_path" class="form-input" value="${config.admin_path || '/admin'}" required>
          </div>
          <div class="form-group">
            <label class="form-label">用户访问路径(注册/登录)</label>
            <input type="text" name="new_user_path" class="form-input" value="${config.user_path || '/user'}" required>
          </div>
          <div class="form-group">
            <label class="form-label">管理员账号</label>
            <input type="text" name="new_username" class="form-input" value="${config.username || ''}" required>
          </div>
          <div class="form-group">
            <label class="form-label">管理员密码(留空则不修改)</label>
            <input type="password" name="new_password" class="form-input" placeholder="留空不修改密码">
          </div>
          <div class="switch-group">
            <input type="checkbox" name="auth_enabled" id="auth_enabled" ${config.auth_enabled === 1 ? 'checked' : ''}>
            <label for="auth_enabled" class="form-label mb-0">开启授权验证(开启后仅授权用户可登录)</label>
          </div>
          <button type="submit" class="submit-btn">
            <i class="fa fa-save"></i> 保存基础配置
          </button>
        </form>
      </div>
    </div>
    <div id="proxy-tab" class="tab-content">
      <div class="content-card">
        <h3 class="card-title"><i class="fa fa-cloud"></i>反代配置</h3>
        <form method="POST">
          <input type="hidden" name="action" value="update_proxy">
          <div class="form-group">
            <label class="form-label">源站域名</label>
            <input type="text" name="target_domain" class="form-input" value="${config.target_domain || ''}" placeholder="例如:your-domain.com">
          </div>
          <div class="form-group">
            <label class="form-label">Workers中转域名</label>
            <input type="text" name="worker_domain" class="form-input" value="${config.worker_domain || ''}" placeholder="例如:your-worker.workers.dev">
          </div>
          <div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;">
            <div>
              <label class="form-label">HTTP端口</label>
              <input type="number" name="http_port" class="form-input" value="${config.http_port || 0}" placeholder="例如:10087">
            </div>
            <div>
              <label class="form-label">HTTPS端口</label>
              <input type="number" name="https_port" class="form-input" value="${config.https_port || 0}" placeholder="例如:10086">
            </div>
          </div>
          <div class="form-group">
            <label class="form-label">反代模式</label>
            <select name="proxy_mode" class="form-select">
              <option value="http_only" ${config.proxy_mode === 'http_only' ? 'selected' : ''}>仅HTTP</option>
              <option value="https_only" ${config.proxy_mode === 'https_only' ? 'selected' : ''}>仅HTTPS</option>
              <option value="auto" ${config.proxy_mode === 'auto' ? 'selected' : ''}>HTTP+HTTPS自适应</option>
            </select>
          </div>
          <div class="switch-group">
            <input type="checkbox" name="cache_enabled" id="cache_enabled" ${config.cache_enabled === 1 ? 'checked' : ''}>
            <label for="cache_enabled" class="form-label mb-0">开启边缘缓存</label>
          </div>
          <div class="form-group">
            <label class="form-label">缓存时长(秒)</label>
            <input type="number" name="cache_ttl" class="form-input" value="${config.cache_ttl_seconds || 3600}" placeholder="例如:3600(1小时)">
          </div>
          <button type="submit" class="submit-btn">
            <i class="fa fa-save"></i> 保存反代配置
          </button>
        </form>
      </div>
    </div>
    <div id="user-manage-tab" class="tab-content">
      <div class="content-card">
        <h3 class="card-title"><i class="fa fa-users"></i>用户管理</h3>
        <table class="user-table">
          <thead>
            <tr class="border-b border-gray-300">
              <th>用户名</th>
              <th>账号</th>
              <th>密码</th>
              <th>QQ号</th>
              <th>状态</th>
              <th>授权天数</th>
              <th>授权到期时间</th>
              <th>封禁/解禁</th>
              <th>设置授权天数</th>
            </tr>
          </thead>
          <tbody>
            ${userTableHtml}
          </tbody>
        </table>
      </div>
    </div>
  </div>
  <script>
    function switchTab(tabId) {
      document.querySelectorAll('.tab-content').forEach(tab => {
        tab.classList.remove('active');
      });
      document.querySelectorAll('.menu-item').forEach(item => {
        item.classList.remove('active');
      });
      document.getElementById(tabId).classList.add('active');
      event.target.classList.add('active');
    }
  </script>
</body>
</html>
  `;
}

function getUserRegisterHtml() {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>用户注册</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 500px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .submit-btn {
      width: 100%;
      padding: 1rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 1rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 1rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .link-group {
      text-align: center;
      margin-top: 1.5rem;
      font-size: 0.95rem;
    }
    .link-group a {
      color: #2563eb;
      text-decoration: none;
    }
    .link-group a:hover {
      text-decoration: underline;
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="card">
    <div class="card-header">
      <h1><i class="fa fa-user-plus icon"></i>用户注册</h1>
      <p>填写信息完成注册,即可访问反代服务</p>
    </div>
    <form method="POST">
      <div class="form-group">
        <label class="form-label">用户名(中英文均可)</label>
        <input type="text" name="username" class="form-input" placeholder="请输入用户名" required>
      </div>
      <div class="form-group">
        <label class="form-label">登录账号</label>
        <input type="text" name="account" class="form-input" placeholder="请设置登录账号" required>
      </div>
      <div class="form-group">
        <label class="form-label">登录密码</label>
        <input type="password" name="password" class="form-input" placeholder="请设置登录密码" required>
      </div>
      <div class="form-group">
        <label class="form-label">QQ号(用于找回密码)</label>
        <input type="text" name="qq_number" class="form-input" placeholder="请输入QQ号" required>
      </div>
      <button type="submit" class="submit-btn">
        <i class="fa fa-check-circle icon"></i>完成注册
      </button>
    </form>
    <div class="link-group">
      已有账号?<a href="./login">立即登录</a> | <a href="./find-pwd">找回密码</a>
    </div>
  </div>
</body>
</html>
  `;
}

function getUserLoginHtml(errorMsg = '') {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>用户登录</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 500px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .alert {
      background: #fee2e2;
      color: #dc2626;
      padding: 1rem;
      border-radius: 8px;
      margin-bottom: 1.5rem;
      text-align: center;
      font-size: 0.95rem;
      border-left: 4px solid #dc2626;
    }
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .submit-btn {
      width: 100%;
      padding: 1rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 1rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 1rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .link-group {
      text-align: center;
      margin-top: 1.5rem;
      font-size: 0.95rem;
    }
    .link-group a {
      color: #2563eb;
      text-decoration: none;
    }
    .link-group a:hover {
      text-decoration: underline;
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="card">
    <div class="card-header">
      <h1><i class="fa fa-lock icon"></i>用户登录</h1>
      <p>登录后即可访问反代服务</p>
    </div>
    ${errorMsg ? `<div class="alert"><i class="fa fa-exclamation-circle"></i> ${errorMsg}</div>` : ''}
    <form method="POST">
      <div class="form-group">
        <label class="form-label">登录账号</label>
        <input type="text" name="account" class="form-input" placeholder="请输入登录账号" required>
      </div>
      <div class="form-group">
        <label class="form-label">登录密码</label>
        <input type="password" name="password" class="form-input" placeholder="请输入登录密码" required>
      </div>
      <button type="submit" class="submit-btn">
        <i class="fa fa-sign-in icon"></i>立即登录
      </button>
    </form>
    <div class="link-group">
      没有账号?<a href="./register">立即注册</a> | <a href="./find-pwd">找回密码</a>
    </div>
  </div>
</body>
</html>
  `;
}

function getUserFindPwdHtml(msg = '') {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>找回密码</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 500px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .msg-box {
      background: #e0f2fe;
      color: #0369a1;
      padding: 1rem;
      border-radius: 8px;
      margin-bottom: 1.5rem;
      text-align: center;
      font-size: 0.95rem;
      border-left: 4px solid #0369a1;
    }
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .submit-btn {
      width: 100%;
      padding: 1rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 1rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 1rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .link-group {
      text-align: center;
      margin-top: 1.5rem;
      font-size: 0.95rem;
    }
    .link-group a {
      color: #2563eb;
      text-decoration: none;
    }
    .link-group a:hover {
      text-decoration: underline;
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="card">
    <div class="card-header">
      <h1><i class="fa fa-key icon"></i>找回密码</h1>
      <p>输入QQ号找回账号并重置密码</p>
    </div>
    ${msg ? `<div class="msg-box"><i class="fa fa-info-circle"></i> ${msg}</div>` : ''}
    <form method="POST">
      <div class="form-group">
        <label class="form-label">注册时填写的QQ号</label>
        <input type="text" name="qq_number" class="form-input" placeholder="请输入QQ号" required>
      </div>
      <div class="form-group">
        <label class="form-label">新密码(留空仅查询账号)</label>
        <input type="password" name="new_password" class="form-input" placeholder="请设置新密码">
      </div>
      <button type="submit" class="submit-btn">
        <i class="fa fa-search icon"></i>找回/重置
      </button>
    </form>
    <div class="link-group">
      返回 <a href="./login">登录</a> | <a href="./register">注册</a>
    </div>
  </div>
</body>
</html>
  `;
}

function getAccessDeniedHtml(msg) {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>访问被拒绝</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .denied-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 3rem 2.5rem;
      max-width: 500px;
      width: 100%;
      text-align: center;
    }
    .denied-icon {
      font-size: 4rem;
      color: #dc2626;
      margin-bottom: 1.5rem;
    }
    .denied-title {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 1rem;
    }
    .denied-msg {
      font-size: 1.1rem;
      color: #dc2626;
      line-height: 1.6;
      margin-bottom: 2rem;
    }
    .back-btn {
      display: inline-block;
      padding: 0.875rem 2rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border-radius: 8px;
      font-size: 1rem;
      font-weight: 500;
      text-decoration: none;
      transition: all 0.2s ease;
    }
    .back-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
  </style>
</head>
<body>
  <div class="denied-card">
    <div class="denied-icon">
      <i class="fa fa-ban"></i>
    </div>
    <h2 class="denied-title">访问被拒绝</h2>
    <div class="denied-msg">${msg}</div>
    <a href="./user/login" class="back-btn">返回登录</a>
  </div>
</body>
</html>
  `;
}

老版本

数据库

CREATE TABLE IF NOT EXISTS proxy_config (id INTEGER PRIMARY KEY AUTOINCREMENT,admin_path TEXT NOT NULL DEFAULT '/admin',username TEXT NOT NULL,password TEXT NOT NULL,target_domain TEXT DEFAULT '',worker_domain TEXT DEFAULT '',http_port INTEGER DEFAULT 0,https_port INTEGER DEFAULT 0,proxy_mode TEXT DEFAULT 'http_only',cache_enabled INTEGER DEFAULT 0,cache_ttl_seconds INTEGER DEFAULT 3600,initialized INTEGER DEFAULT 0);

网站代码

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const db = env.PROXY_DB; // 替换为你的D1数据库绑定名称

    // 1. 读取配置
    const configResult = await db.prepare('SELECT * FROM proxy_config LIMIT 1').all();
    let config = configResult.results[0] || { initialized: 0 };

    // 2. 未初始化:显示初始化界面
    if (config.initialized === 0) {
      if (request.method === 'POST') {
        const formData = await request.formData();
        const adminPath = formData.get('admin_path') || '/admin';
        const username = formData.get('username');
        const password = formData.get('password');
        
        if (username && password) {
          // 加密密码(简单base64,生产可换更安全方式)
          const encryptedPwd = btoa(password);
          await db.prepare('INSERT INTO proxy_config (admin_path, username, password, initialized) VALUES (?, ?, ?, 1)').bind(adminPath, username, encryptedPwd).run();
          return Response.redirect(`${url.origin}${adminPath}`, 302);
        }
        return new Response('请填写完整信息', { status: 400 });
      }
      return new Response(getInitHtml(), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    // 3. 匹配后台路径:显示登录/后台界面
    const adminPath = config.admin_path || '/admin';
    if (url.pathname.startsWith(adminPath)) {
      // 登录验证
      const authHeader = request.headers.get('Authorization');
      const isAuth = authHeader && authHeader === `Basic ${btoa(`${config.username}:${atob(config.password)}`)}`;

      // 未登录:显示登录界面
      if (!isAuth) {
        return new Response(getLoginHtml(), {
          status: 401,
          headers: { 'WWW-Authenticate': 'Basic realm="Proxy Admin Panel"', 'Content-Type': 'text/html; charset=utf-8' }
        });
      }

      // 已登录:处理后台操作
      if (request.method === 'POST') {
        const formData = await request.formData();
        const action = formData.get('action');
        
        // 修改基础配置(路径/账号/密码)
        if (action === 'update_base') {
          const newAdminPath = formData.get('new_admin_path') || config.admin_path;
          const newUsername = formData.get('new_username') || config.username;
          const newPassword = formData.get('new_password');
          const encryptedNewPwd = newPassword ? btoa(newPassword) : config.password;
          
          await db.prepare('UPDATE proxy_config SET admin_path=?, username=?, password=? WHERE id=?').bind(newAdminPath, newUsername, encryptedNewPwd, config.id).run();
          return Response.redirect(`${url.origin}${newAdminPath}`, 302);
        }

        // 修改反代配置
        if (action === 'update_proxy') {
          const targetDomain = formData.get('target_domain') || '';
          const workerDomain = formData.get('worker_domain') || '';
          const httpPort = parseInt(formData.get('http_port') || 0);
          const httpsPort = parseInt(formData.get('https_port') || 0);
          const proxyMode = formData.get('proxy_mode') || 'http_only';
          const cacheEnabled = formData.get('cache_enabled') ? 1 : 0;
          const cacheTtl = parseInt(formData.get('cache_ttl') || 3600);
          
          await db.prepare('UPDATE proxy_config SET target_domain=?, worker_domain=?, http_port=?, https_port=?, proxy_mode=?, cache_enabled=?, cache_ttl_seconds=? WHERE id=?').bind(targetDomain, workerDomain, httpPort, httpsPort, proxyMode, cacheEnabled, cacheTtl, config.id).run();
          return Response.redirect(`${url.origin}${adminPath}`, 302);
        }
      }

      // 显示后台管理界面
      return new Response(getAdminHtml(config), { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
    }

    // 4. 已初始化且非后台路径:执行反代逻辑
    if (!config.target_domain || !config.worker_domain) {
      return new Response('请先在后台配置反代参数', { status: 500 });
    }

    // 反代核心逻辑
    let response, targetHost;
    const cfCacheConfig = {
      cacheTtl: config.cache_enabled ? config.cache_ttl_seconds : 0,
      cacheEverything: config.cache_enabled === 1,
      cacheKey: url.href
    };

    switch (config.proxy_mode) {
      case 'https_only':
        if (!config.https_port) throw new Error('HTTPS端口未配置');
        const targetHttps = new URL(`https://${config.target_domain}:${config.https_port}`);
        url.protocol = targetHttps.protocol;
        targetHost = targetHttps.host;
        url.host = targetHost;
        response = await fetch(new Request(url, {
          method: request.method,
          headers: buildHeaders(request.headers, targetHost),
          body: request.body,
          redirect: 'manual',
          duplex: 'half'
        }), { cf: cfCacheConfig });
        break;

      case 'http_only':
        if (!config.http_port) throw new Error('HTTP端口未配置');
        const targetHttp = new URL(`http://${config.target_domain}:${config.http_port}`);
        url.protocol = targetHttp.protocol;
        targetHost = targetHttp.host;
        url.host = targetHost;
        response = await fetch(new Request(url, {
          method: request.method,
          headers: buildHeaders(request.headers, targetHost),
          body: request.body,
          redirect: 'manual',
          duplex: 'half'
        }), { cf: cfCacheConfig });
        break;

      case 'auto':
        if (!config.https_port || !config.http_port) throw new Error('auto模式需同时配置HTTP/HTTPS端口');
        try {
          const targetHttpsAuto = new URL(`https://${config.target_domain}:${config.https_port}`);
          url.protocol = targetHttpsAuto.protocol;
          targetHost = targetHttpsAuto.host;
          url.host = targetHost;
          response = await fetch(new Request(url, {
            method: request.method,
            headers: buildHeaders(request.headers, targetHost),
            body: request.body,
            redirect: 'manual',
            duplex: 'half'
          }), { cf: cfCacheConfig });
        } catch (e) {
          const targetHttpAuto = new URL(`http://${config.target_domain}:${config.http_port}`);
          url.protocol = targetHttpAuto.protocol;
          targetHost = targetHttpAuto.host;
          url.host = targetHost;
          response = await fetch(new Request(url, {
            method: request.method,
            headers: buildHeaders(request.headers, targetHost),
            body: request.body,
            redirect: 'manual',
            duplex: 'half'
          }), { cf: cfCacheConfig });
        }
        break;
    }

    // 响应处理:强制HTTPS链接
    let resp = await handleResponse(response, config);
    return resp;

  },
};

// 构建请求头
function buildHeaders(headers, host) {
  const h = new Headers(headers);
  h.set('Host', host);
  h.set('X-Forwarded-Host', host);
  h.set('X-Forwarded-Proto', 'https');
  h.set('User-Agent', headers.get('User-Agent') || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
  h.set('Upgrade', headers.get('Upgrade') || '');
  h.set('Connection', headers.get('Connection') || '');
  h.set('Range', headers.get('Range') || '');
  h.set('If-Range', headers.get('If-Range') || '');
  h.set('Cookie', headers.get('Cookie') || '');
  h.set('Set-Cookie', headers.get('Set-Cookie') || '');
  h.delete('X-Forwarded-For');
  return h;
}

// 处理响应
async function handleResponse(response, config) {
  let resp = new Response(response.body, response);
  const contentType = resp.headers.get('Content-Type') || '';

  if (contentType.includes('text/') || contentType.includes('html') || contentType.includes('json') || contentType.includes('javascript')) {
    let content = await response.text();
    if (config.https_port) content = content.replace(new RegExp(`https://${config.target_domain}:${config.https_port}`, 'g'), `https://${config.worker_domain}`);
    if (config.http_port) content = content.replace(new RegExp(`http://${config.target_domain}:${config.http_port}`, 'g'), `https://${config.worker_domain}`);
    content = content.replace(new RegExp(`http://${config.target_domain}`, 'g'), `https://${config.worker_domain}`);
    content = content.replace(new RegExp(`https://${config.target_domain}`, 'g'), `https://${config.worker_domain}`);
    resp = new Response(content, response);
  }

  resp.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate');
  resp.headers.set('Pragma', 'no-cache');
  resp.headers.delete('X-Frame-Options');
  resp.headers.delete('Content-Security-Policy');
  resp.headers.set('Access-Control-Allow-Origin', '*');
  resp.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  resp.headers.set('Access-Control-Allow-Headers', 'Range, Cookie, Upgrade, Connection, Content-Type');
  return resp;
}

// 初始化界面HTML(优化版)
function getInitHtml() {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>反代管理系统 - 初始化</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .init-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 500px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .submit-btn {
      width: 100%;
      padding: 1rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 1rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 1rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .submit-btn:active {
      transform: translateY(0);
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="init-card">
    <div class="card-header">
      <h1><i class="fa fa-cogs icon"></i>反代管理系统</h1>
      <p>首次使用,请完成初始化配置</p>
    </div>
    <form method="POST">
      <div class="form-group">
        <label class="form-label">后台访问路径</label>
        <input type="text" name="admin_path" class="form-input" placeholder="/admin" value="/admin" required>
      </div>
      <div class="form-group">
        <label class="form-label">管理员账号</label>
        <input type="text" name="username" class="form-input" placeholder="请设置管理员账号" required>
      </div>
      <div class="form-group">
        <label class="form-label">管理员密码</label>
        <input type="password" name="password" class="form-input" placeholder="请设置管理员密码" required>
      </div>
      <button type="submit" class="submit-btn">
        <i class="fa fa-check-circle icon"></i>完成初始化
      </button>
    </form>
  </div>
</body>
</html>
  `;
}

// 登录界面HTML(优化版)
function getLoginHtml() {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>反代管理系统 - 登录</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .login-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      border: 1px solid rgba(255, 255, 255, 0.18);
      padding: 2.5rem;
      max-width: 450px;
      width: 100%;
    }
    .card-header {
      text-align: center;
      margin-bottom: 2rem;
    }
    .card-header h1 {
      font-size: 1.8rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 0.5rem;
    }
    .card-header p {
      color: #64748b;
      font-size: 0.95rem;
    }
    .alert {
      background: #fee2e2;
      color: #dc2626;
      padding: 1rem;
      border-radius: 8px;
      margin-bottom: 1.5rem;
      text-align: center;
      font-size: 0.95rem;
      border-left: 4px solid #dc2626;
    }
    .icon {
      color: #2563eb;
      margin-right: 0.5rem;
    }
  </style>
</head>
<body>
  <div class="login-card">
    <div class="card-header">
      <h1><i class="fa fa-lock icon"></i>管理员登录</h1>
      <p>请输入正确的账号和密码</p>
    </div>
    <div class="alert">
      <i class="fa fa-exclamation-circle"></i> 身份验证失败,请重新登录
    </div>
    <p class="text-center text-gray-600 text-sm">若未初始化,请先完成系统初始化配置</p>
  </div>
</body>
</html>
  `;
}

// 后台管理界面HTML(左侧导航版)
function getAdminHtml(config) {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>反代管理系统 - 后台</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { 
      font-family: 'Inter', system-ui, -apple-system, sans-serif;
      background: #f8fafc;
      color: #1e293b;
      min-height: 100vh;
      display: flex;
    }
    /* 左侧导航 */
    .sidebar {
      width: 250px;
      background: #1e293b;
      color: #f8fafc;
      min-height: 100vh;
      padding: 1.5rem 0;
      position: fixed;
    }
    .sidebar-header {
      padding: 0 1.5rem 1.5rem;
      border-bottom: 1px solid #334155;
      margin-bottom: 1rem;
    }
    .sidebar-header h2 {
      font-size: 1.2rem;
      font-weight: 600;
      color: #ffffff;
      display: flex;
      align-items: center;
    }
    .sidebar-header h2 i {
      margin-right: 0.75rem;
      color: #38bdf8;
    }
    .sidebar-menu {
      padding: 0.5rem 0;
    }
    .menu-item {
      padding: 0.875rem 1.5rem;
      display: flex;
      align-items: center;
      color: #94a3b8;
      text-decoration: none;
      transition: all 0.2s ease;
      cursor: pointer;
      border-left: 3px solid transparent;
    }
    .menu-item.active {
      background: #334155;
      color: #ffffff;
      border-left-color: #38bdf8;
    }
    .menu-item:hover {
      background: #273449;
      color: #e2e8f0;
    }
    .menu-item i {
      margin-right: 0.75rem;
      font-size: 1rem;
    }

    /* 右侧内容区 */
    .main-content {
      margin-left: 250px;
      flex: 1;
      padding: 2rem;
    }
    .content-header {
      margin-bottom: 2rem;
      padding-bottom: 1rem;
      border-bottom: 1px solid #e2e8f0;
    }
    .content-header h1 {
      font-size: 1.75rem;
      font-weight: 600;
      color: #0f172a;
    }
    .content-card {
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
      padding: 2rem;
      margin-bottom: 2rem;
    }
    .card-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
      margin-bottom: 1.5rem;
      display: flex;
      align-items: center;
    }
    .card-title i {
      margin-right: 0.75rem;
      color: #2563eb;
    }
    /* 表单样式 */
    .form-group {
      margin-bottom: 1.5rem;
    }
    .form-label {
      display: block;
      margin-bottom: 0.75rem;
      font-weight: 500;
      color: #334155;
      font-size: 0.95rem;
    }
    .form-input, .form-select {
      width: 100%;
      padding: 0.875rem 1rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 0.95rem;
      color: #1e293b;
      transition: all 0.2s ease;
      background: #f8fafc;
    }
    .form-input:focus, .form-select:focus {
      outline: none;
      border-color: #2563eb;
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
      background: #ffffff;
    }
    .form-select {
      appearance: none;
      background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E") right 0.75rem center/1.5rem 1.5rem no-repeat #f8fafc;
      padding-right: 2.5rem;
    }
    .switch-group {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      margin-bottom: 1.5rem;
    }
    .switch-group input {
      width: auto;
      height: 1.25rem;
      width: 1.25rem;
      accent-color: #2563eb;
    }
    .submit-btn {
      padding: 0.875rem 1.5rem;
      background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
      color: #ffffff;
      border: none;
      border-radius: 8px;
      font-size: 0.95rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      margin-top: 0.5rem;
    }
    .submit-btn:hover {
      background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
      transform: translateY(-1px);
    }
    .submit-btn:active {
      transform: translateY(0);
    }
    /* 内容切换 */
    .tab-content {
      display: none;
    }
    .tab-content.active {
      display: block;
    }
    /* 响应式 */
    @media (max-width: 768px) {
      .sidebar {
        width: 80px;
        padding: 1rem 0;
      }
      .sidebar-header h2 span {
        display: none;
      }
      .menu-item span {
        display: none;
      }
      .menu-item {
        justify-content: center;
        padding: 1rem;
      }
      .menu-item i {
        margin-right: 0;
        font-size: 1.2rem;
      }
      .main-content {
        margin-left: 80px;
        padding: 1.5rem 1rem;
      }
    }
  </style>
</head>
<body>
  <!-- 左侧导航 -->
  <div class="sidebar">
    <div class="sidebar-header">
      <h2><i class="fa fa-cogs"></i> <span>反代管理系统</span></h2>
    </div>
    <div class="sidebar-menu">
      <div class="menu-item active" onclick="switchTab('base-tab')">
        <i class="fa fa-user-circle"></i>
        <span>基础配置</span>
      </div>
      <div class="menu-item" onclick="switchTab('proxy-tab')">
        <i class="fa fa-cloud"></i>
        <span>反代配置</span>
      </div>
    </div>
  </div>

  <!-- 右侧内容 -->
  <div class="main-content">
    <div class="content-header">
      <h1>后台管理中心</h1>
    </div>

    <!-- 基础配置 Tab -->
    <div id="base-tab" class="tab-content active">
      <div class="content-card">
        <h3 class="card-title"><i class="fa fa-user-circle"></i>基础配置(路径/账号/密码)</h3>
        <form method="POST">
          <input type="hidden" name="action" value="update_base">
          <div class="form-group">
            <label class="form-label">后台访问路径</label>
            <input type="text" name="new_admin_path" class="form-input" value="${config.admin_path || '/admin'}" required>
          </div>
          <div class="form-group">
            <label class="form-label">管理员账号</label>
            <input type="text" name="new_username" class="form-input" value="${config.username || ''}" required>
          </div>
          <div class="form-group">
            <label class="form-label">管理员密码(留空则不修改)</label>
            <input type="password" name="new_password" class="form-input" placeholder="留空不修改密码">
          </div>
          <button type="submit" class="submit-btn">
            <i class="fa fa-save"></i> 保存基础配置
          </button>
        </form>
      </div>
    </div>

    <!-- 反代配置 Tab -->
    <div id="proxy-tab" class="tab-content">
      <div class="content-card">
        <h3 class="card-title"><i class="fa fa-cloud"></i>反代配置</h3>
        <form method="POST">
          <input type="hidden" name="action" value="update_proxy">
          <div class="form-group">
            <label class="form-label">源站域名</label>
            <input type="text" name="target_domain" class="form-input" value="${config.target_domain || ''}" placeholder="例如:your-domain.com">
          </div>
          <div class="form-group">
            <label class="form-label">Workers中转域名</label>
            <input type="text" name="worker_domain" class="form-input" value="${config.worker_domain || ''}" placeholder="例如:your-worker.workers.dev">
          </div>
          <div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;">
            <div>
              <label class="form-label">HTTP端口</label>
              <input type="number" name="http_port" class="form-input" value="${config.http_port || 0}" placeholder="例如:10087">
            </div>
            <div>
              <label class="form-label">HTTPS端口</label>
              <input type="number" name="https_port" class="form-input" value="${config.https_port || 0}" placeholder="例如:10086">
            </div>
          </div>
          <div class="form-group">
            <label class="form-label">反代模式</label>
            <select name="proxy_mode" class="form-select">
              <option value="http_only" ${config.proxy_mode === 'http_only' ? 'selected' : ''}>仅HTTP</option>
              <option value="https_only" ${config.proxy_mode === 'https_only' ? 'selected' : ''}>仅HTTPS</option>
              <option value="auto" ${config.proxy_mode === 'auto' ? 'selected' : ''}>HTTP+HTTPS自适应</option>
            </select>
          </div>
          <div class="switch-group">
            <input type="checkbox" name="cache_enabled" id="cache_enabled" ${config.cache_enabled === 1 ? 'checked' : ''}>
            <label for="cache_enabled" class="form-label mb-0">开启边缘缓存</label>
          </div>
          <div class="form-group">
            <label class="form-label">缓存时长(秒)</label>
            <input type="number" name="cache_ttl" class="form-input" value="${config.cache_ttl_seconds || 3600}" placeholder="例如:3600(1小时)">
          </div>
          <button type="submit" class="submit-btn">
            <i class="fa fa-save"></i> 保存反代配置
          </button>
        </form>
      </div>
    </div>
  </div>

  <script>
    // Tab切换逻辑
    function switchTab(tabId) {
      // 隐藏所有tab
      document.querySelectorAll('.tab-content').forEach(tab => {
        tab.classList.remove('active');
      });
      // 移除所有菜单激活状态
      document.querySelectorAll('.menu-item').forEach(item => {
        item.classList.remove('active');
      });
      // 激活选中的tab和菜单
      document.getElementById(tabId).classList.add('active');
      event.target.classList.add('active');
    }
  </script>
</body>
</html>
  `;
}
© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容