个人主页V3.0
这是一个非常明确的信号:您看到的 HTML 代码是“宝塔面板 (BT Panel)”的标准 404 错误页。
这意味着:服务器上确实找不到 bridge.php 这个文件。
即使您觉得上传了,它可能在错误的文件夹,或者文件名不对。
请按照以下 3 步 彻底修复这个问题,然后使用下方的 V3.0 代码。
第一步:彻底修复 404 错误 (必做)
请登录您的 宝塔面板 (BT Panel) -> 文件 (Files),严格检查以下 3 点:
-
目录是否正确?
-
文件必须在:
/www/wwwroot/www.hzpm.com/这个目录下。 -
错误示范:上传到了
/www/wwwroot/default/或者/root/。
-
-
文件名是否正确?
-
在宝塔里看,文件名必须是
bridge.php。 -
常见错误:文件名变成了
bridge.php.txt(Windows上传常见问题)。如果后面有.txt,请右键重命名删掉。
-
-
新建一个文件夹 (推荐方案)
-
为了避开 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
/**
* 放在 /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 全注释教学版
<!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>
👨🏫 给小白的修改指南
如果你想改页面上的内容,只需要关注这几个地方:
-
改照片:搜索
img src=,把引号里的链接换成你自己的照片链接。 -
改名字:搜索
Engr. Deng,改成你的英文名。 -
改职位:搜索
PM Expert @ HZPM,改成你的签名。 -
改邮箱/城市:往下找
grid那一块,里面的 Email 和 City 文字都可以直接改。
这个文件现在是全自动的,只要你网站发布了新文章,这里刷新一下(或者别人打开时)就会自动同步最新的 5 条!
