个人主页V3.0

/ 邓工 / 50阅读 / 0评论 / 分类: 网络

这是一个非常明确的信号:您看到的 HTML 代码是“宝塔面板 (BT Panel)”的标准 404 错误页。

这意味着:服务器上确实找不到 bridge.php 这个文件

即使您觉得上传了,它可能在错误的文件夹,或者文件名不对。

请按照以下 3 步 彻底修复这个问题,然后使用下方的 V3.0 代码


第一步:彻底修复 404 错误 (必做)

请登录您的 宝塔面板 (BT Panel) -> 文件 (Files),严格检查以下 3 点:

  1. 目录是否正确?

    • 文件必须在:/www/wwwroot/www.hzpm.com/ 这个目录下。

    • 错误示范:上传到了 /www/wwwroot/default/ 或者 /root/

  2. 文件名是否正确?

    • 在宝塔里看,文件名必须是 bridge.php

    • 常见错误:文件名变成了 bridge.php.txt (Windows上传常见问题)。如果后面有 .txt,请右键重命名删掉。

  3. 新建一个文件夹 (推荐方案)

    • 为了避开 Emlog 的伪静态规则冲突,建议在根目录下新建一个文件夹叫 tools

    • bridge.php 移动到 /www/wwwroot/www.hzpm.com/tools/ 里面。

    • 现在的访问地址应该是:https://www.hzpm.com/tools/bridge.php


第二步:重新上传最强壮的 bridge.php

为了防止 config.php 加载失败,我们这次直接在 PHP 里填写数据库密码(最稳妥)。

请修改本地的 bridge.php,填入您的数据库信息,然后上传到 /tools/ 文件夹中:

PHP
<?php
/**
 * 放在 /tools/bridge.php
 * 作用:直接连接数据库,避开所有 CMS 限制
 */
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Content-Type: application/json; charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { exit; }

// ==========================================
// 请在这里直接填写宝塔里的数据库信息 (最稳)
// ==========================================
$db_host = 'localhost';      // 数据库地址
$db_user = 'hzpm_com';       // 数据库用户名 (请在宝塔数据库页查看)
$db_pass = '您的数据库密码';   // 数据库密码 (请在宝塔数据库页查看)
$db_name = 'hzpm_com';       // 数据库名
$prefix  = 'emlog_';         // 表前缀 (默认是 emlog_)

// 1. 连接数据库
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);

if ($conn->connect_error) {
    // 如果连接失败,输出错误原因
    die(json_encode(['code' => 500, 'msg' => 'DB Connect Error: ' . $conn->connect_error]));
}
$conn->set_charset("utf8mb4");

// 2. 查询文章
$sql = "SELECT gid, title, date FROM {$prefix}blog WHERE type='blog' AND hide='n' AND checked='y' ORDER BY date DESC LIMIT 6";
$result = $conn->query($sql);

$data = [];
if ($result) {
    while ($row = $result->fetch_assoc()) {
        $data[] = [
            'title' => $row['title'],
            'link'  => 'https://www.hzpm.com/?post=' . $row['gid'],
            'date'  => date('Y-m-d', $row['date'])
        ];
    }
    echo json_encode(['code' => 200, 'data' => $data]);
} else {
    echo json_encode(['code' => 500, 'msg' => 'Query Error: ' . $conn->error]);
}
$conn->close();
?>

第三步:验证文件是否存在

上传后,请直接在浏览器打开:

👉 https://www.hzpm.com/tools/bridge.php

  • 如果看到一段 JSON 代码(类似 {"code":200, "data": [...]}:恭喜!成功了!

  • 如果还是漂亮的 404 页面:说明文件位置还是不对,请继续检查路径。


第四步:使用 V3.0 前端代码

确认第三步成功后,使用这段代码。它指向了新的 /tools/bridge.php 地址,并且增加了极其详细的错误反馈。

请复制完整代码覆盖:

 

我把这份 V3.0 的代码拆解成了中文详细注释版

你可以直接复制覆盖你原来的文件,这些注释(`` 和 // 之后的内容)浏览器会自动忽略,不会影响运行,但能让你看懂每一行在干什么。

📚 V3.0 全注释教学版

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Engr. Deng | HZPM</title>

    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Playfair+Display:ital,wght@0,600;1,600&display=swap" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">

    <style>
        /* === 1. 基础设置 === */
        /* 让所有元素的宽高计算包含边框,防止布局错位 */
        * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

        /* === 2. 网页背景 === */
        body {
            margin: 0; padding: 0; 
            min-height: 100vh; /* 只要内容不够多,至少占满一屏幕高度 */
            font-family: 'Inter', sans-serif; /* 默认字体 */
            background-color: #f8fafc; /* 底色:灰白 */
            /* 这种写法是用来画那个淡淡的蓝色光晕背景的 */
            background-image: 
                radial-gradient(at 0% 0%, hsla(210, 40%, 96%, 1) 0, transparent 50%), 
                radial-gradient(at 100% 100%, hsla(220, 40%, 96%, 1) 0, transparent 50%);
            color: #333; 
            /* Flex布局三件套:让卡片在屏幕正中间显示 */
            display: flex; justify-content: center; align-items: center;
        }

        /* === 3. 核心卡片 (玻璃质感) === */
        .glass-card {
            display: flex; /* 左右布局 */
            width: 100%; max-width: 850px; height: 500px; /* 固定最大宽高 */
            background: rgba(255, 255, 255, 0.98); /* 背景几乎不透明的白色 */
            backdrop-filter: blur(20px); /* 核心代码:背景毛玻璃模糊效果 */
            border: 1px solid rgba(255, 255, 255, 1); /* 给卡片加个白边框 */
            box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.1); /* 底部柔和的阴影 */
            border-radius: 24px; /* 圆角 */
            position: relative; overflow: hidden; z-index: 1;
        }

        /* === 4. 右上角折角 (CSS画三角形) === */
        .corner-bookmark {
            position: absolute; top: 0; right: 0; /* 固定在右上角 */
            width: 0; height: 0;
            /* 利用边框画出一个橙色的三角形 */
            border-top: 80px solid #ea580c; 
            border-left: 80px solid transparent;
            z-index: 999; cursor: pointer;
            filter: drop-shadow(-3px 3px 4px rgba(0,0,0,0.2)); /* 折角的阴影 */
            transition: all 0.3s; /* 鼠标放上去时的动画过渡时间 */
        }
        /* 鼠标悬停时,折角稍微放大一点 */
        .corner-bookmark:hover { transform: scale(1.1) translate(2px, -2px); }
        /* 折角里的图标位置微调 */
        .corner-icon { position: absolute; top: -60px; right: 14px; color: #fff; font-size: 18px; pointer-events: none; }

        /* === 5. 左侧栏 (照片区) === */
        .left-col { 
            flex: 1.3; /* 占用 1.3 份的宽度 */
            position: relative; background: #000; overflow: hidden; 
        }
        /* 您的个人照片 */
        .bg-img { 
            width: 100%; height: 100%; object-fit: cover; /* 保证图片填满不拉伸 */
            transition: transform 0.7s ease; opacity: 0.95; 
        }
        /* 鼠标放到卡片上时,照片缓慢放大一点点 */
        .glass-card:hover .bg-img { transform: scale(1.05); }
        /* 照片底部的文字遮罩 (渐变黑) */
        .txt-overlay { 
            position: absolute; bottom: 0; left: 0; width: 100%; 
            padding: 40px 30px; 
            background: linear-gradient(to top, rgba(0,0,0,0.8), transparent); 
            color: white; z-index: 2; 
        }

        /* === 6. 右侧栏 (内容区) === */
        .right-col { 
            flex: 1.7; /* 占用 1.7 份的宽度,比左边宽 */
            padding: 25px 45px 20px 45px; /* 上右下左的内边距 */
            display: flex; flex-direction: column; 
            overflow: hidden; /* 禁止出现滚动条,超出部分隐藏 */
            position: relative; 
        }

        /* 字体样式设置 */
        .en-font { font-family: 'Playfair Display', serif; font-size: 36px; font-weight: 600; font-style: italic; line-height: 1.1; margin-bottom: 5px; }
        .cn-font { font-size: 14px; font-weight: 300; opacity: 0.9; letter-spacing: 2px; text-transform: uppercase; }

        /* 标签 (HZPM / Portfolio) 的样式 */
        .tag { display: inline-block; font-size: 11px; font-weight: 600; letter-spacing: 1.5px; color: #64748b; background: #f1f5f9; padding: 8px 14px; border-radius: 4px; text-transform: uppercase; margin-bottom: 15px; }

        /* 个人信息网格布局 (两列) */
        .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 12px; } 

        /* 分割线 */
        .sep { width: 100%; height: 1px; background: #e2e8f0; margin: 5px 0 15px 0; }

        /* 标题栏 (Latest Updates + 刷新按钮) */
        .head { font-family: 'Playfair Display', serif; font-size: 20px; color: #0f172a; margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; }

        /* 刷新按钮样式 */
        .refresh-btn { background: none; border: none; cursor: pointer; padding: 5px; margin-left: 8px; color: #94a3b8; font-size: 14px; transition: all 0.3s ease; }
        .refresh-btn:hover { color: #ea580c; transform: rotate(180deg); }

        /* 旋转动画 (加载时用到) */
        .spin { animation: spin 1s linear infinite; color: #ea580c; pointer-events: none; }
        @keyframes spin { 100% { transform: rotate(360deg); } }

        /* 链接通用样式 */
        .link { text-decoration: none; color: #1e293b; display: flex; flex-direction: column; gap: 4px; }
        .lbl { font-size: 10px; color: #94a3b8; text-transform: uppercase; font-weight: 700; letter-spacing: 0.5px; display: flex; align-items: center; gap: 6px; }
        .lbl i { font-size: 11px; color: #2563eb; }
        .val { font-size: 13px; font-weight: 400; }

        /* 状态提示文字 */
        .loading-container { text-align: center; padding: 40px 0; color: #94a3b8; font-size: 13px; }
        .error-msg { font-size: 11px; color: #ef4444; margin-top: 15px; text-align: center; line-height: 1.6; background: #fff0f0; padding: 10px; border-radius: 8px;}
        .success-badge { font-size:10px; color:#22c55e; margin-left:5px; opacity:0; transition:opacity 0.5s; }
        .success-badge.show { opacity:1; }

        /* === 核心优化:文章标题样式 === */
        .article-title {
            font-size: 13px; color: #333; font-weight: 500;
            line-height: 1.6; /* 增加行距,让文字不拥挤 */
            /* 下面这4行代码是让标题最多显示两行,超过显示省略号 */
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        /* === 手机端适配 (如果屏幕宽度小于768px) === */
        @media (max-width: 768px) {
            body { display: block !important; padding: 15px !important; height: auto !important; }
            /* 手机上卡片变高,变成上下排列 */
            .glass-card { display: block !important; height: auto !important; max-height: none !important; background: #ffffff !important; border-radius: 16px; margin-bottom: 50px; }
            .left-col { height: 260px !important; width: 100% !important; }
            .right-col { padding: 30px 20px !important; }
            .grid { grid-template-columns: 1fr !important; } /* 手机上信息变成单列 */
        }
    </style>
</head>
<body>

    <div class="glass-card">
        <a href="https://www.hzpm.com" target="_blank" title="Visit Website">
            <div class="corner-bookmark">
                <i class="fas fa-external-link-alt corner-icon"></i>
            </div>
        </a>

        <div class="left-col">
            <img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80" alt="Profile" class="bg-img">
            <div class="txt-overlay">
                <div class="en-font">Engr. Deng</div>
                <div class="cn-font">PM Expert @ HZPM</div>
            </div>
        </div>

        <div class="right-col">
            <div class="tag">HZPM / Portfolio</div>

            <div class="grid">
                <a href="#" class="link" style="pointer-events: none;">
                    <span class="lbl"><i class="fas fa-briefcase"></i> Position</span>
                    <span class="val">Supervisor</span>
                </a>
                <a href="mailto:hi@hzpm.com" class="link">
                    <span class="lbl"><i class="fas fa-envelope"></i> Email</span>
                    <span class="val">hi@hzpm.com</span>
                </a>
                <a href="https://www.hzpm.com" target="_blank" class="link">
                    <span class="lbl"><i class="fas fa-globe"></i> Website</span>
                    <span class="val">hzpm.com</span>
                </a>
                <a href="#" class="link" style="pointer-events: none;">
                    <span class="lbl"><i class="fas fa-location-dot"></i> City</span>
                    <span class="val">Shenzhen</span>
                </a>
            </div>

            <div class="sep"></div>

            <div class="head">
                <div style="display:flex; align-items:center;">
                    <span style="color:#000;">Latest Updates</span>
                    <button class="refresh-btn" onclick="fetchBridgeData()" title="Refresh">
                        <i id="refresh-icon" class="fas fa-sync-alt"></i>
                    </button>
                    <span id="success-badge" class="success-badge"><i class="fas fa-check"></i> Connected</span>
                </div>
                <a href="https://www.hzpm.com" style="font-size:11px; color:#999; text-decoration:none;">View All</a>
            </div>

            <div id="article-list" style="display: block; width: 100%;">
                <div class="loading-container">
                    <i class="fas fa-circle-notch fa-spin"></i> Loading...
                </div>
            </div>
        </div>
    </div>

    <script>
        // 定义您的桥接文件地址 (就是您上传到 tools 文件夹里的那个 PHP)
        const BRIDGE_URL = 'https://www.hzpm.com/tools/bridge.php'; 

        // 定义抓取数据的函数
        function fetchBridgeData() {
            // 获取页面上的元素,方便后面操作它们
            const container = document.getElementById('article-list'); // 文章列表容器
            const icon = document.getElementById('refresh-icon');      // 刷新图标
            const badge = document.getElementById('success-badge');    // 成功提示

            // 1. 开始加载:让图标转起来,隐藏成功提示,显示加载中
            icon.classList.add('spin');
            badge.classList.remove('show');
            container.innerHTML = '<div class="loading-container"><i class="fas fa-circle-notch fa-spin"></i> Updating...</div>';

            // 2. 发起网络请求 (fetch)
            // '?t=' + Date.now() 是为了加上时间戳,防止浏览器缓存旧数据
            fetch(BRIDGE_URL + '?t=' + Date.now())
                .then(response => {
                    // 如果服务器返回 404,说明 bridge.php 没找到
                    if (response.status === 404) throw new Error("bridge.php not found");
                    // 如果网络有问题
                    if (!response.ok) throw new Error("Connection Error");
                    // 把返回的数据转换成 JSON 格式
                    return response.json();
                })
                .then(res => {
                    // 3. 数据获取成功了!
                    icon.classList.remove('spin'); // 停止旋转

                    let articles = [];
                    // 检查数据格式是否正确 (code 200 表示成功)
                    if (res.code === 200 && res.data) {
                        articles = res.data;
                    }

                    if (articles.length > 0) {
                        let html = '';
                        // 只取前 5 条数据 (Math.min 确保如果有3条就显示3条,有10条只显示5条)
                        const limit = Math.min(articles.length, 5); 

                        // 循环生成每一条文章的 HTML
                        for (let i = 0; i < limit; i++) {
                            const item = articles[i];
                            const title = item.title || "Untitled"; // 如果没有标题显示 Untitled
                            const link = item.link || "#";
                            const date = item.date || "";

                            // 判断是不是最后一条 (最后一条不需要下面的分割线)
                            const isLast = i === limit - 1;

                            // 生成左侧的竖线 HTML
                            const lineHtml = isLast ? '' : '<div style="position:absolute; left: 4px; top: 8px; bottom: 0; width: 1px; background: #e2e8f0;"></div>';

                            // 调整每篇文章的底部间距
                            const paddingHtml = isLast ? '' : 'padding-bottom: 15px;'; 

                            // 拼接 HTML 字符串
                            html += `
                            <div style="display:flex; position:relative; ${paddingHtml}">
                                ${lineHtml}
                                <div style="width: 9px; height: 9px; background: #2563eb; border-radius: 50%; z-index: 1; flex-shrink: 0; margin-top: 7px; box-shadow: 0 0 0 3px #eff6ff;"></div>
                                <div style="padding-left: 15px; width: 100%;">
                                    <a href="${link}" target="_blank" style="text-decoration: none; display: block;">
                                        <div class="article-title">${title}</div>
                                        ${date ? `<div style="font-size: 10px; color: #94a3b8; margin-top:3px;">${date}</div>` : ''}
                                    </a>
                                </div>
                            </div>`;
                        }
                        // 把拼接好的 HTML 塞到页面里
                        container.innerHTML = html;
                        // 显示绿色的 "Connected"
                        badge.classList.add('show');
                    } else {
                        throw new Error("No articles found");
                    }
                })
                .catch(err => {
                    // 4. 如果出错了
                    icon.classList.remove('spin');
                    // 显示红色的错误提示
                    container.innerHTML = `
                        <div class="error-msg">
                            <i class="fas fa-exclamation-circle"></i> Load Failed<br>
                            ${err.message}
                        </div>
                    `;
                });
        }

        // 页面一打开,就自动执行一次抓取
        document.addEventListener('DOMContentLoaded', fetchBridgeData);
    </script>
</body>
</html>

👨‍🏫 给小白的修改指南

如果你想改页面上的内容,只需要关注这几个地方:

  1. 改照片:搜索 img src=,把引号里的链接换成你自己的照片链接。

  2. 改名字:搜索 Engr. Deng,改成你的英文名。

  3. 改职位:搜索 PM Expert @ HZPM,改成你的签名。

  4. 改邮箱/城市:往下找 grid 那一块,里面的 Email 和 City 文字都可以直接改。

这个文件现在是全自动的,只要你网站发布了新文章,这里刷新一下(或者别人打开时)就会自动同步最新的 5 条!


扫描二维码,在手机上阅读
发表评论