Compare commits

..

5 Commits

Author SHA1 Message Date
f1f864033d 更新 README.md 2025-10-18 14:05:07 +08:00
26ee91d519 更新 README.md 2025-10-18 11:18:09 +08:00
7bdf159d9c 更新 README.md 2025-10-18 11:15:44 +08:00
cea28f94b9 Merge branch 'main' of https://git.hztecha.com/admin/Fuxsto-V4 2025-10-18 10:20:01 +08:00
1f5ac5e0ca 删除 More/t.php.bak 2025-10-18 10:19:37 +08:00
80 changed files with 14326 additions and 1 deletions

1
.htaccess Normal file
View File

@@ -0,0 +1 @@

1
.user.ini Normal file
View File

@@ -0,0 +1 @@
open_basedir=/www/wwwroot/hv4.fuxsto.cn/:/tmp/

View File

@@ -0,0 +1 @@
o-ZsCxEnxBF8w8EmIGEjyzXwjruHy6xjD7214zN8BBY.rsG2PpWul6LvK6yzgH7E1PafqwKFm6HWKVE8X0AgD-U

130
404.html Normal file
View File

@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>超值数字资产转让 - 限时特惠</title>
<style>
body {
font-family: 'Segoe UI', Arial, sans-serif;
line-height: 1.6;
max-width: 800px;
margin: 20px auto;
padding: 20px;
background: #f6f9fc;
}
.header {
text-align: center;
padding: 30px;
background: linear-gradient(135deg, #2c3e50, #3498db);
color: white;
border-radius: 15px;
margin-bottom: 25px;
}
.section {
background: white;
padding: 25px;
margin: 20px 0;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.server-node {
border-left: 4px solid #3498db;
padding: 15px;
margin: 15px 0;
background: #f8f9fa;
}
.price {
color: #e74c3c;
font-weight: bold;
font-size: 1.2em;
}
.badge {
display: inline-block;
padding: 5px 10px;
border-radius: 20px;
font-size: 0.9em;
margin: 5px;
}
.warning {
border: 2px solid #e74c3c;
padding: 15px;
border-radius: 8px;
background: #fff5f5;
}
.highlight {
color: #3498db;
font-weight: 600;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
</style>
</head>
<body>
<div class="header">
<h1>✉️ 超值数字资产转让 ✉️</h1>
<h3>📌【云端资源特惠专区】📌</h3>
</div>
<div class="section">
<h2>🔒 高防云服务器集群 🔒</h2>
<div class="grid">
<div class="server-node">
<h3>📍 中国·成都节点</h3>
<p>✅ 16核16G | 100G SSD</p>
<p>🛡️ 100Gbps防护 | 📶 20M/50M</p>
<p class="price">💰 特惠价80元</p>
<span class="badge" style="background:#e8f4fc">2025-05-17 到期 剩余约2个月</span>
</div>
<div class="server-node">
<h3>📍 中国·香港节点</h3>
<p>✅ 4核4G | 40G SSD</p>
<p>🛡️ 2Gbps防护 | 📶 7M独享</p>
<p class="price">💰 清仓价8.8元 (续费 25)</p>
<span class="badge" style="background:#ffeeba">2025-04-05 到期 剩余约1个月</span>
</div>
<div class="server-node">
<h3>📍 美国·纽约节点</h3>
<p>✅ 2核2G | 30G+80G双盘</p>
<p>🌐 100M带宽 | 🔢 3+5 IP</p>
<p class="price">💰 特惠价20元 (续费同价)</p>
<span class="badge" style="background:#d4edda">2025-04-23 到期 剩余约2个月</span>
</div>
</div>
</div>
<div class="section">
<h2>💻 精品源码资产包 💻</h2>
<div class="grid">
<div>
<p>🔖 OAuth认证系统 <span class="price">💰25元</span></p>
<p>🔖 Fuxsto Host系列</p>
<p style="padding-left:20px">V3工单版 💰25元<br>
V4 CMS版 💰20元<br>
V5数据库版 💰25元</p>
</div>
<div>
<p>🔖 技术文档系统 <span class="price">💰10元</span></p>
<p>🔖 Ruaka源码 <span class="price">💰15元</span></p>
<p>🔖 MyBT主机系统 <span class="price">💰5元</span></p>
<p>🔖 全套CSS/JS <span class="price">💰1元</span></p>
</div>
</div>
</div>
<div class="section warning">
<h3>⚠️ 重要提示 ⚠️</h3>
<p>1⃣ 支付方式:支付宝/微信<br>
2⃣ 售出概不退换<br>
3⃣ BUG终身维护<br>
4⃣ 同类别两件7折<br>
5⃣ 直接联系:📞 QQ 3220257676</p>
</div>
<div class="header" style="background:linear-gradient(135deg, #e74c3c, #f39c12);padding:15px">
<h2>🔥 限时特惠 先到先得 🔥</h2>
</div>
</body>
</html>

130
404.html.bak Normal file
View File

@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>超值数字资产转让 - 限时特惠</title>
<style>
body {
font-family: 'Segoe UI', Arial, sans-serif;
line-height: 1.6;
max-width: 800px;
margin: 20px auto;
padding: 20px;
background: #f6f9fc;
}
.header {
text-align: center;
padding: 30px;
background: linear-gradient(135deg, #2c3e50, #3498db);
color: white;
border-radius: 15px;
margin-bottom: 25px;
}
.section {
background: white;
padding: 25px;
margin: 20px 0;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.server-node {
border-left: 4px solid #3498db;
padding: 15px;
margin: 15px 0;
background: #f8f9fa;
}
.price {
color: #e74c3c;
font-weight: bold;
font-size: 1.2em;
}
.badge {
display: inline-block;
padding: 5px 10px;
border-radius: 20px;
font-size: 0.9em;
margin: 5px;
}
.warning {
border: 2px solid #e74c3c;
padding: 15px;
border-radius: 8px;
background: #fff5f5;
}
.highlight {
color: #3498db;
font-weight: 600;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
</style>
</head>
<body>
<div class="header">
<h1>✉️ 超值数字资产转让 ✉️</h1>
<h3>📌【云端资源特惠专区】📌</h3>
</div>
<div class="section">
<h2>🔒 高防云服务器集群 🔒</h2>
<div class="grid">
<div class="server-node">
<h3>📍 中国·成都节点</h3>
<p>✅ 16核16G | 100G SSD</p>
<p>🛡️ 100Gbps防护 | 📶 20M/50M</p>
<p class="price">💰 特惠价80元</p>
<span class="badge" style="background:#e8f4fc">2025-05-17 到期 剩余约2个月</span>
</div>
<div class="server-node">
<h3>📍 中国·香港节点</h3>
<p>✅ 4核4G | 40G SSD</p>
<p>🛡️ 2Gbps防护 | 📶 7M独享</p>
<p class="price">💰 清仓价8.8元 (续费 25)</p>
<span class="badge" style="background:#ffeeba">2025-04-05 到期 剩余约1个月</span>
</div>
<div class="server-node">
<h3>📍 美国·纽约节点</h3>
<p>✅ 2核2G | 30G+80G双盘</p>
<p>🌐 100M带宽 | 🔢 3+5 IP</p>
<p class="price">💰 特惠价20元 (续费同价)</p>
<span class="badge" style="background:#d4edda">2025-04-23 到期 剩余约2个月</span>
</div>
</div>
</div>
<div class="section">
<h2>💻 精品源码资产包 💻</h2>
<div class="grid">
<div>
<p>🔖 OAuth认证系统 <span class="price">💰25元</span></p>
<p>🔖 Fuxsto Host系列</p>
<p style="padding-left:20px">V3工单版 💰25元<br>
V4 CMS版 💰20元<br>
V5数据库版 💰25元</p>
</div>
<div>
<p>🔖 技术文档系统 <span class="price">💰10元</span></p>
<p>🔖 Ruaka源码 <span class="price">💰15元</span></p>
<p>🔖 MyBT主机系统 <span class="price">💰5元</span></p>
<p>🔖 全套CSS/JS <span class="price">💰1元</span></p>
</div>
</div>
</div>
<div class="section warning">
<h3>⚠️ 重要提示 ⚠️</h3>
<p>1⃣ 支付方式:支付宝/微信<br>
2⃣ 售出概不退换<br>
3⃣ BUG终身维护<br>
4⃣ 同类别两件7折<br>
5⃣ 技术咨询:📞 QQ 3220257676</p>
</div>
<div class="header" style="background:linear-gradient(135deg, #e74c3c, #f39c12);padding:15px">
<h2>🔥 限时特惠 先到先得 🔥</h2>
</div>
</body>
</html>

Binary file not shown.

Binary file not shown.

1058
Dashboard/app.css Normal file

File diff suppressed because it is too large Load Diff

1058
Dashboard/app.css.bak Normal file

File diff suppressed because it is too large Load Diff

93
Dashboard/app.js Normal file
View File

@@ -0,0 +1,93 @@
// app.js
const { createApp } = Vue;
const { ElButton, ElMessage, ElInput, ElCard, ElRow, ElForm, ElFormItem, ElDivider, ElLoading } = ElementPlus;
const app = createApp({
data() {
return {
userlogo: null,
UserInfo: null,
page: null,
purchases: null,
cart: null,
ld: true,
}
},
async mounted() {
// 生命周期钩子 - 挂载后
console.log('应用已挂载');
this.getinfo();
},
methods: {
go(link) {
Message.info('跳转中...');
window.location.href = link;
},
viewcart() {
this.ldo();
axios.get('/Main/GetGoods/')
.then(response => {
this.ldx();
this.cart = response.data;
this.cart_fid = Object.keys(this.cart)[0];
})
},
ldo() {
this.ld = true;
},
ldx() {
this.ld = false;
},
getinfo() {
this.ldo();
axios.get('/Main/GetInfo/')
.then(response => {
this.ldx();
Message.closeAll();
if (response.data.code === 200) {
this.UserInfo = response.data.msg;
this.page = "home";
if (response.data.msg.qq != null) {
this.userlogo = "https://q1.qlogo.cn/g?b=qq&nk="+response.data.msg.qq+"&s=640";
}
} else {
Message.warning('请先登陆');
// 1 秒后跳转到指定页面
setTimeout(function() {
window.location.href = "/Main/Login";
}, 2000); // 1000 毫秒 = 1 秒
}
})
},
getpurchases() {
this.ldo();
axios.get('/Main/GetProducts/')
.then(response => {
this.ldx();
if (response.data.code === 200) {
this.purchases = response.data.msg;
} else {
Message.warning('获取业务失败');
}
})
},
}
});
// 挂载到DOM元素
app.use(ElementPlus);
app.mount('#app');

91
Dashboard/app.js.bak Normal file
View File

@@ -0,0 +1,91 @@
// app.js
const { createApp } = Vue;
const { ElButton, ElMessage, ElInput, ElCard, ElRow, ElForm, ElFormItem, ElDivider, ElLoading } = ElementPlus;
const app = createApp({
data() {
return {
userlogo: null,
UserInfo: null,
page: null,
purchases: null,
cart: null,
ld: true,
}
},
async mounted() {
// 生命周期钩子 - 挂载后
console.log('应用已挂载');
this.getinfo();
},
methods: {
go(link) {
Message.info('跳转中...');
window.location.href = link;
},
viewcart() {
axios.get('/Main/GetGoods/')
.then(response => {
this.cart = response.data;
this.cart_fid = Object.keys(this.cart)[0];
})
},
ldo() {
this.ld = true;
},
ldx() {
this.ld = false;
},
getinfo() {
this.ldo();
axios.get('/Main/GetInfo/')
.then(response => {
this.ldx();
Message.closeAll();
if (response.data.code === 200) {
this.UserInfo = response.data.msg;
this.page = "home";
if (response.data.msg.qq != null) {
this.userlogo = "https://q1.qlogo.cn/g?b=qq&nk="+response.data.msg.qq+"&s=640";
}
} else {
Message.warning('请先登陆');
// 1 秒后跳转到指定页面
setTimeout(function() {
window.location.href = "/Main/Login";
}, 2000); // 1000 毫秒 = 1 秒
}
})
},
getpurchases() {
this.ldo();
axios.get('/Main/GetProducts/')
.then(response => {
this.ldx();
if (response.data.code === 200) {
this.purchases = response.data.msg;
} else {
Message.warning('获取业务失败');
}
})
},
}
});
// 挂载到DOM元素
app.use(ElementPlus);
app.mount('#app');

49
Dashboard/b.php Normal file
View File

@@ -0,0 +1,49 @@
<?php
header('Content-Type: application/json');
function fetchBingResults($query) {
$url = "https://www.bing.com/search?q=" . urlencode($query) . "&count=10";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
$html = curl_exec($ch);
curl_close($ch);
if (!$html) return [];
$dom = new DOMDocument();
@$dom->loadHTML($html);
$results = [];
$blocks = $dom->getElementsByTagName('div')->item(0)->getElementsByTagName('div');
foreach ($blocks as $block) {
$title = $block->getElementsByTagName('h2')->item(0)->textContent;
$link = $block->getElementsByTagName('a')->item(0)->getAttribute('href');
$description = $block->getElementsByTagName('p')->item(0)->textContent;
$results[] = [
'title' => trim($title),
'link' => trim($link),
'description' => trim($description),
'icon' => null // 网页版Bing不显示图标
];
}
return $results;
}
$searchTerm = isset($_GET['p']) ? $_GET['p'] : 'Kentucky';
$results = fetchBingResults($searchTerm);
$response = [
'results' => $results,
'total' => count($results),
'max_page' => 1
];
echo json_encode($response);
?>

49
Dashboard/bing.html Normal file
View File

@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FuxSo</title>
<link rel="stylesheet" href="app.css" /> <!-- 移动到head内部 -->
</head>
<body class="container">
<div id="app">
<transition name="fade-blur">
<div v-if="s">
<div class="form-container min">
<h3 style="margin:0 0 16px;">Bing搜索</h3>
<label>关键字</label>
<input v-model="w" placeholder="请输入关键字"/>
<button @click="search">提交</button>
</div>
<div v-for="m in d" class="card min">
<div class="header">
<div class="icon-wrapper">
<img class="icon" :src="m.icon">
</div>
<div class="title-group">
<h2 class="title">{{ m.title }}</h2>
<a :href="m.link" class="status">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="12" r="10" />
</svg>
前往
</a>
</div>
</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">{{ m.description }}</span>
</div>
</div> <!-- 删除多余的闭合标签 -->
</div>
</transition>
</div>
<!-- 依赖库 -->
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3.5.13/dist/vue.global.prod.js"></script>
<script src="msg.js"></script>
<script src="bing.js"></script>
</body>
</html>

53
Dashboard/bing.html.bak Normal file
View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FuxSo</title>
<link rel="stylesheet" href="app.css" /> <!-- 移动到head内部 -->
</head>
<body class="container">
<div id="app">
<transition name="fade-blur">
<div v-if="s">
<div class="form-container min">
<h3 style="margin:0 0 16px;">Bing搜索</h3>
<label>关键字</label>
<input v-model="w" placeholder="请输入关键字"/>
<button @click="search">提交</button>
</div>
<div v-for="m in d" class="card min">
<div class="header">
<div class="icon-wrapper">
<img class="icon" :src="m.icon">
</div>
<div class="title-group">
<h2 class="title">{{ m.title }}</h2>
<a :href="m.link" class="status">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="12" r="10" />
</svg>
前往
</a>
</div>
</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">{{ m.description }}</span>
</div>
</div> <!-- 删除多余的闭合标签 -->
</div>
</transition>
</div>
<!-- 依赖库 -->
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>
eruda.init();
</script>
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3.5.13/dist/vue.global.prod.js"></script>
<script src="msg.js"></script>
<script src="bing.js"></script>
</body>
</html>

49
Dashboard/bing.js Normal file
View File

@@ -0,0 +1,49 @@
// app.js
const { createApp } = Vue;
const app = createApp({
data() {
return {
w: null,
p: null,
d: null,
s: true,
}
},
async mounted() {
// 生命周期钩子 - 挂载后
console.log('应用已挂载');
},
methods: {
search() {
Message.info('正在请求...', { duration: 5000000000000000 });
this.s = false;
axios.get('https://zk.aoidc.top/api/api.php?q='+this.w)
.then(response => {
Message.closeAll();
this.s = true;
if (response.data.results != null) {
this.d = response.data.results;
this.s = true;
Message.success('已载入~', { duration: 2000 });
console.log(this.d);
} else {
Message.warning('失败', { duration: 2000 });
}
})
},
}
});
// 挂载到DOM元素
app.mount('#app');

47
Dashboard/bing.js.bak Normal file
View File

@@ -0,0 +1,47 @@
// app.js
const { createApp } = Vue;
const app = createApp({
data() {
return {
w: null,
p: null,
d: null,
s: true,
}
},
async mounted() {
// 生命周期钩子 - 挂载后
console.log('应用已挂载');
},
methods: {
search() {
Message.info('正在请求...', { duration: 5000000000000000 });
this.s = false;
axios.get('https://zk.aoidc.top/api/api.php?q='+this.w)
.then(response => {
Message.closeAll();
this.s = true;
if (response.data.results != null) {
this.d = response.data.results;
this.s = true;
Message.success('已载入~', { duration: 2000 });
} else {
Message.warning('失败', { duration: 2000 });
}
})
},
}
});
// 挂载到DOM元素
app.mount('#app');

267
Dashboard/index.html Normal file
View File

@@ -0,0 +1,267 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fuxsto Host V5 - Dashboard</title>
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>eruda.init();</script>
<link rel="stylesheet" href="app.css">
<link rel="stylesheet" href="https://cdn.fss.fuxsto.cn/d/element-plus@2.9.4/dist/index.css" />
</head>
<body class="container">
<div id="app">
<transition name="ldo">
<div class="md" v-if="ld">
<div class="loader min"></div>
</div>
</transition>
<transition name="fade-blur">
<!-- 用户中心 -->
<div
class="min"
v-if="UserInfo && page == 'home'"
>
<!-- 用户卡片 -->
<div class="user-card">
<div class="user-card-header">
<div class="user-card-avatar">
<img
width="100%"
class="avatar-image"
:src="userlogo"
alt="头像"
>
</div>
<div class="user-card-info">
<div class="user-card-name">
{{ UserInfo.username }}
</div>
<div class="user-card-role">
{{ UserInfo.id }}
</div>
</div>
</div>
<div class="user-card-stats">
<div class="user-card-stat">
<div class="user-card-stat-value">
{{ UserInfo.balance }}
</div>
<div class="user-card-stat-label">
余额
</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">
{{ UserInfo.score }}
</div>
<div class="user-card-stat-label">
积分
</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">
{{ UserInfo.status }}
</div>
<div class="user-card-stat-label">
状态
</div>
</div>
</div>
</div>
<div class="quick-actions">
<button
@click="this.page = 'goods';this.viewcart()"
class="action-button">
<svg viewBox="0 0 24 24">
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</svg>
<span>创建业务</span>
</button>
<button
class="action-button"
@click="this.page = 'purchase';this.getpurchases()"
>
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
</svg>
<span>我的业务</span>
</button>
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/>
</svg>
<span>系统设置</span>
</button>
</div>
</div>
<div v-if="UserInfo && page !='home'">
<div class="min" style="display: grid; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="background: rgba(41, 98, 255, 0.1); border-radius: 99px; padding: 0px;">
<button @click="page = 'home';getinfo()" class="button">
<div class="button-box">
<span class="button-elem">
<svg viewBox="0 0 46 40" xmlns="http://www.w3.org/2000/svg">
<path
d="M46 20.038c0-.7-.3-1.5-.8-2.1l-16-17c-1.1-1-3.2-1.4-4.4-.3-1.2 1.1-1.2 3.3 0 4.4l11.3 11.9H3c-1.7 0-3 1.3-3 3s1.3 3 3 3h33.1l-11.3 11.9c-1 1-1.2 3.3 0 4.4 1.2 1.1 3.3.8 4.4-.3l16-17c.5-.5.8-1.1.8-1.9z"
></path>
</svg>
</span>
<span class="button-elem">
<svg viewBox="0 0 46 40">
<path
d="M46 20.038c0-.7-.3-1.5-.8-2.1l-16-17c-1.1-1-3.2-1.4-4.4-.3-1.2 1.1-1.2 3.3 0 4.4l11.3 11.9H3c-1.7 0-3 1.3-3 3s1.3 3 3 3h33.1l-11.3 11.9c-1 1-1.2 3.3 0 4.4 1.2 1.1 3.3.8 4.4-.3l16-17c.5-.5.8-1.1.8-1.9z"
></path>
</svg>
</span>
</div>
</button>
</div>
<div>
<div>返回</div>
<div style="font-size: 12px; color: var(--mdui-text-secondary);">Go to home</div>
</div>
</div>
<br>
</div>
<!-- 业务页面 -->
<div v-if="page == 'purchase'">
<div
class="min"
v-if="purchases"
>
<div
v-for="m in purchases"
class="card"
>
<div class="header">
<div class="icon-wrapper">
<svg
class="icon"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div class="title-group">
<h2 class="title">
{{ m.name }}
</h2>
<div class="status">
<svg
width="12"
height="12"
viewBox="0 0 24 24"
fill="currentColor"
>
<circle cx="12" cy="12" r="10"/>
</svg>
{{ m.status }}
</div>
</div>
</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">业务ID</span>
<span class="value">
{{ m.purchase_id }}
</span>
</div>
<div class="detail-item">
<span class="label">到期时间</span>
<span class="value">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<circle cx="12" cy="12" r="10"/>
<path d="M12 6V12L16 14"/>
</svg>
{{ m.expiry_time }}
</span>
</div>
</div>
</div>
</div>
</div>
<!-- 产品页面 -->
<div class="min" v-if="page == 'goods' && cart">
{{ cart }}
</div>
</transition>
</div>
<!-- 依赖库 -->
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3.5.13/dist/vue.global.prod.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/element-plus@2.9.4/dist/index.full.js"></script>
<script src="msg.js"></script>
<script src="app.js"></script>
</body>
</html>

267
Dashboard/index.html.bak Normal file
View File

@@ -0,0 +1,267 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fuxsto Host V5 - Dashboard</title>
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>eruda.init();</script>
<link rel="stylesheet" href="app.css">
<link rel="stylesheet" href="https://cdn.fss.fuxsto.cn/d/element-plus@2.9.4/dist/index.css" />
</head>
<body class="container">
<div id="app">
<transition name="ldo">
<div class="md min" v-if="ld">
<div class="loader"></div>
</div>
</transition>
<transition name="fade-blur">
<!-- 用户中心 -->
<div
class="min"
v-if="UserInfo && page == 'home'"
>
<!-- 用户卡片 -->
<div class="user-card">
<div class="user-card-header">
<div class="user-card-avatar">
<img
width="100%"
class="avatar-image"
:src="userlogo"
alt="头像"
>
</div>
<div class="user-card-info">
<div class="user-card-name">
{{ UserInfo.username }}
</div>
<div class="user-card-role">
{{ UserInfo.id }}
</div>
</div>
</div>
<div class="user-card-stats">
<div class="user-card-stat">
<div class="user-card-stat-value">
{{ UserInfo.balance }}
</div>
<div class="user-card-stat-label">
余额
</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">
{{ UserInfo.score }}
</div>
<div class="user-card-stat-label">
积分
</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">
{{ UserInfo.status }}
</div>
<div class="user-card-stat-label">
状态
</div>
</div>
</div>
</div>
<div class="quick-actions">
<button
@click="this.page = 'goods';this.viewcart()"
class="action-button">
<svg viewBox="0 0 24 24">
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</svg>
<span>创建业务</span>
</button>
<button
class="action-button"
@click="this.page = 'purchase';this.getpurchases()"
>
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
</svg>
<span>我的业务</span>
</button>
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/>
</svg>
<span>系统设置</span>
</button>
</div>
</div>
<div v-if="UserInfo && page !='home'">
<div class="min" style="display: grid; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="background: rgba(41, 98, 255, 0.1); border-radius: 99px; padding: 0px;">
<button @click="page = 'home';getinfo()" class="button">
<div class="button-box">
<span class="button-elem">
<svg viewBox="0 0 46 40" xmlns="http://www.w3.org/2000/svg">
<path
d="M46 20.038c0-.7-.3-1.5-.8-2.1l-16-17c-1.1-1-3.2-1.4-4.4-.3-1.2 1.1-1.2 3.3 0 4.4l11.3 11.9H3c-1.7 0-3 1.3-3 3s1.3 3 3 3h33.1l-11.3 11.9c-1 1-1.2 3.3 0 4.4 1.2 1.1 3.3.8 4.4-.3l16-17c.5-.5.8-1.1.8-1.9z"
></path>
</svg>
</span>
<span class="button-elem">
<svg viewBox="0 0 46 40">
<path
d="M46 20.038c0-.7-.3-1.5-.8-2.1l-16-17c-1.1-1-3.2-1.4-4.4-.3-1.2 1.1-1.2 3.3 0 4.4l11.3 11.9H3c-1.7 0-3 1.3-3 3s1.3 3 3 3h33.1l-11.3 11.9c-1 1-1.2 3.3 0 4.4 1.2 1.1 3.3.8 4.4-.3l16-17c.5-.5.8-1.1.8-1.9z"
></path>
</svg>
</span>
</div>
</button>
</div>
<div>
<div>返回</div>
<div style="font-size: 12px; color: var(--mdui-text-secondary);">Go to home</div>
</div>
</div>
<br>
</div>
<!-- 业务页面 -->
<div v-if="page == 'purchase'">
<div
class="min"
v-if="purchases"
>
<div
v-for="m in purchases"
class="card"
>
<div class="header">
<div class="icon-wrapper">
<svg
class="icon"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div class="title-group">
<h2 class="title">
{{ m.name }}
</h2>
<div class="status">
<svg
width="12"
height="12"
viewBox="0 0 24 24"
fill="currentColor"
>
<circle cx="12" cy="12" r="10"/>
</svg>
{{ m.status }}
</div>
</div>
</div>
<div class="detail-grid">
<div class="detail-item">
<span class="label">业务ID</span>
<span class="value">
{{ m.purchase_id }}
</span>
</div>
<div class="detail-item">
<span class="label">到期时间</span>
<span class="value">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<circle cx="12" cy="12" r="10"/>
<path d="M12 6V12L16 14"/>
</svg>
{{ m.expiry_time }}
</span>
</div>
</div>
</div>
</div>
</div>
<!-- 产品页面 -->
<div class="min" v-if="page == 'goods' && cart">
{{ cart }}
</div>
</transition>
</div>
<!-- 依赖库 -->
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3.5.13/dist/vue.global.prod.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/element-plus@2.9.4/dist/index.full.js"></script>
<script src="msg.js"></script>
<script src="app.js"></script>
</body>
</html>

235
Dashboard/msg.js Normal file
View File

@@ -0,0 +1,235 @@
// 终极消息系统 (保留所有优秀特性)
(() => {
// 完美图标系统
const icons = {
success: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15l-4-4 1.41-1.41L11 14.17l6.59-6.59L19 9l-8 8z"/></svg>',
error: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>',
warning: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',
info: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>'
};
// 专业配置系统
const config = {
duration: 3000,
spacing: 10,
maxMessages: 10,
closable: false,
enterAnimation: 'msg-slideIn',
exitAnimation: 'msg-fadeOutUp'
};
// 完美样式系统
const style = document.createElement('style');
style.textContent = `
@keyframes msg-slideIn {
0% { opacity: 0; transform: translate(-50%, -20px);
filter: blur(5px); }
100% { opacity: 1; transform: translate(-50%, 0);
filter: blur(0px); }
}
@keyframes msg-fadeOutUp {
0% { opacity: 1; transform: translate(-50%, 0);
filter: blur(0px); }
100% { opacity: 0; transform: translate(-50%, -100px);
filter: blur(5px); }
}
.msg {
position: fixed;
left: 50%;
transform: translateX(-50%);
min-width: 300px;
max-width: 90vw;
padding: 14px 20px;
border-radius: 15px;
background: #fff;
display: flex;
align-items: center;
z-index: 9999;
opacity: 0;
transition: top 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
font-family: system-ui, sans-serif;
}
.msg-enter {
animation: ${config.enterAnimation} 0.5s forwards;
}
.msg-exit {
animation: ${config.exitAnimation} 0.5s forwards;
}
.msg-icon {
width: 24px;
height: 24px;
margin-right: 12px;
flex-shrink: 0;
animation: msg-content-in 0.4s ease-in-out 0.5s forwards;
}
.msg-content {
flex: 1;
font-size: 14px;
line-height: 1.5;
padding-right: 8px;
transition: all 0.5s;
animation: msg-content-in 0.4s ease-in-out 0.55s forwards;
}
@keyframes msg-content-in {
0% { opacity: 1;
filter: blur(0px); }
50% { opacity: 1;
filter: blur(2px); }
} 100% { opacity: 1;
filter: blur(0px); }
}
.msg-close {
cursor: pointer;
width: 24px;
height: 24px;
margin-left: 8px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
transition: all 0.5s;
color: rgba(0,0,0,0.5);
flex-shrink: 0;
animation: msg-content-in 0.4s ease-in-out 0.6s forwards;
}
.msg-close:hover {
background: rgba(0,0,0,0.08);
color: rgba(0,0,0,0.8);
}
/* 专业配色方案 */
.msg-success { color: #10B981; box-shadow: 0px 0px 4px rgba(16, 185, 129, 0.2);}
.msg-error { color: #EF4444; box-shadow: 0px 0px 4px rgba(239, 68, 68, 0.2);}
.msg-warning { color: #F59E0B; box-shadow: 0px 0px 4px rgba(245, 158, 11, 0.2);}
.msg-info { color: #3B82F6; box-shadow: 0px 0px 4px rgba(59, 130, 246, 0.2);}
`;
document.head.appendChild(style);
// 终极消息管理器
class MsgManager {
static instances = [];
static add(msg) {
if (this.instances.length >= config.maxMessages) {
this.instances[0].close();
}
this.instances.push(msg);
this.updateLayout();
}
static remove(msg) {
const index = this.instances.indexOf(msg);
if (index > -1) {
this.instances.splice(index, 1);
this.updateLayout(true);
}
}
static updateLayout(animate = false) {
let top = 20;
this.instances.forEach(instance => {
instance.element.style.transition = animate ? 'top 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)' : 'none';
instance.element.style.top = `${top}px`;
top += instance.element.offsetHeight + config.spacing;
});
}
}
// 完美消息实例
class Msg {
constructor(type, content, options) {
this.type = type;
this.content = content;
this.options = { ...config, ...options };
this.element = this.createElement();
this.setupEvents();
this.show();
}
createElement() {
const el = document.createElement('div');
el.className = `msg msg-${this.type}`;
const closeBtn = this.options.closable
? '<div class="msg-close" role="button">×</div>'
: '';
el.innerHTML = `
<div class="msg-icon">${icons[this.type]}</div>
<div class="msg-content">${this.content}</div>
${closeBtn}
`;
return el;
}
setupEvents() {
if (this.options.closable) {
this.element.querySelector('.msg-close').addEventListener('click', () => this.close());
}
}
show() {
document.body.appendChild(this.element);
requestAnimationFrame(() => {
this.element.classList.add('msg-enter');
MsgManager.add(this);
});
this.autoCloseTimer = setTimeout(() => this.close(), this.options.duration);
}
close() {
clearTimeout(this.autoCloseTimer);
this.element.classList.remove('msg-enter');
this.element.classList.add('msg-exit');
setTimeout(() => {
this.element.remove();
MsgManager.remove(this);
}, 500);
}
}
// 终极API暴露
const Message = {
config(newConfig) {
Object.assign(config, newConfig);
},
success(content, options) {
return new Msg('success', content, options);
},
error(content, options) {
return new Msg('error', content, options);
},
warning(content, options) {
return new Msg('warning', content, options);
},
info(content, options) {
return new Msg('info', content, options);
},
closeAll() {
MsgManager.instances.slice().forEach(msg => msg.close());
}
};
window.Message = Message;
})();
// 完美调用示例
//Message.success('');
//Message.error('验证失败', { closable: true, duration: 5000 });

235
Dashboard/msg.js.bak Normal file
View File

@@ -0,0 +1,235 @@
// 终极消息系统 (保留所有优秀特性)
(() => {
// 完美图标系统
const icons = {
success: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15l-4-4 1.41-1.41L11 14.17l6.59-6.59L19 9l-8 8z"/></svg>',
error: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>',
warning: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',
info: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>'
};
// 专业配置系统
const config = {
duration: 3000,
spacing: 10,
maxMessages: 10,
closable: false,
enterAnimation: 'msg-slideIn',
exitAnimation: 'msg-fadeOutUp'
};
// 完美样式系统
const style = document.createElement('style');
style.textContent = `
@keyframes msg-slideIn {
0% { opacity: 0; transform: translate(-50%, -20px);
filter: blur(5px); }
100% { opacity: 1; transform: translate(-50%, 0);
filter: blur(0px); }
}
@keyframes msg-fadeOutUp {
0% { opacity: 1; transform: translate(-50%, 0);
filter: blur(0px); }
100% { opacity: 0; transform: translate(-50%, -100px);
filter: blur(5px); }
}
.msg {
position: fixed;
left: 50%;
transform: translateX(-50%);
min-width: 300px;
max-width: 90vw;
padding: 14px 20px;
border-radius: 15px;
background: #fff;
display: flex;
align-items: center;
z-index: 9999;
opacity: 0;
transition: top 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
font-family: system-ui, sans-serif;
}
.msg-enter {
animation: ${config.enterAnimation} 0.5s forwards;
}
.msg-exit {
animation: ${config.exitAnimation} 0.5s forwards;
}
.msg-icon {
width: 24px;
height: 24px;
margin-right: 12px;
flex-shrink: 0;
animation: msg-content-in 0.4s ease-in-out 0.5s forwards;
}
.msg-content {
flex: 1;
font-size: 14px;
line-height: 1.5;
padding-right: 8px;
transition: all 0.5s;
animation: msg-content-in 0.4s ease-in-out 0.55s forwards;
}
@keyframes msg-content-in {
0% { opacity: 1;
filter: blur(0px); }
50% { opacity: 1;
filter: blur(2px); }
} 100% { opacity: 1;
filter: blur(0px); }
}
.msg-close {
cursor: pointer;
width: 24px;
height: 24px;
margin-left: 8px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
transition: all 0.5s;
color: rgba(0,0,0,0.5);
flex-shrink: 0;
animation: msg-content-in 0.4s ease-in-out 0.6s forwards;
}
.msg-close:hover {
background: rgba(0,0,0,0.08);
color: rgba(0,0,0,0.8);
}
/* 专业配色方案 */
.msg-success { color: #10B981; box-shadow: 0px 0px 4px rgba(16, 185, 129, 0.2);}
.msg-error { color: #EF4444; box-shadow: 0px 0px 4px rgba(239, 68, 68, 0.2);}
.msg-warning { color: #F59E0B; box-shadow: 0px 0px 4px rgba(245, 158, 11, 0.2);}
.msg-info { color: #3B82F6; box-shadow: 0px 0px 4px rgba(59, 130, 246, 0.2);}
`;
document.head.appendChild(style);
// 终极消息管理器
class MsgManager {
static instances = [];
static add(msg) {
if (this.instances.length >= config.maxMessages) {
this.instances[0].close();
}
this.instances.push(msg);
this.updateLayout();
}
static remove(msg) {
const index = this.instances.indexOf(msg);
if (index > -1) {
this.instances.splice(index, 1);
this.updateLayout(true);
}
}
static updateLayout(animate = false) {
let top = 20;
this.instances.forEach(instance => {
instance.element.style.transition = animate ? 'top 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)' : 'none';
instance.element.style.top = `${top}px`;
top += instance.element.offsetHeight + config.spacing;
});
}
}
// 完美消息实例
class Msg {
constructor(type, content, options) {
this.type = type;
this.content = content;
this.options = { ...config, ...options };
this.element = this.createElement();
this.setupEvents();
this.show();
}
createElement() {
const el = document.createElement('div');
el.className = `msg msg-${this.type}`;
const closeBtn = this.options.closable
? '<div class="msg-close" role="button">×</div>'
: '';
el.innerHTML = `
<div class="msg-icon">${icons[this.type]}</div>
<div class="msg-content">${this.content}</div>
${closeBtn}
`;
return el;
}
setupEvents() {
if (this.options.closable) {
this.element.querySelector('.msg-close').addEventListener('click', () => this.close());
}
}
show() {
document.body.appendChild(this.element);
requestAnimationFrame(() => {
this.element.classList.add('msg-enter');
MsgManager.add(this);
});
this.autoCloseTimer = setTimeout(() => this.close(), this.options.duration);
}
close() {
clearTimeout(this.autoCloseTimer);
this.element.classList.remove('msg-enter');
this.element.classList.add('msg-exit');
setTimeout(() => {
this.element.remove();
MsgManager.remove(this);
}, 500);
}
}
// 终极API暴露
const Message = {
config(newConfig) {
Object.assign(config, newConfig);
},
success(content, options) {
return new Msg('success', content, options);
},
error(content, options) {
return new Msg('error', content, options);
},
warning(content, options) {
return new Msg('warning', content, options);
},
info(content, options) {
return new Msg('info', content, options);
},
closeAll() {
MsgManager.instances.slice().forEach(msg => msg.close());
}
};
window.Message = Message;
})();
// 完美调用示例
Message.success('支付成功!');
Message.error('验证失败', { closable: true, duration: 5000 });

984
Dashboard/t.html Normal file
View File

@@ -0,0 +1,984 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>移动端仪表盘</title>
<style>
:root {
--mdui-primary: #2962ff;
--mdui-surface: #ffffff;
--mdui-background: #f5f5f5;
--mdui-text-primary: rgba(0, 0, 0, 0.87);
--mdui-text-secondary: rgba(0, 0, 0, 0.6);
--mdui-shape-corner: 20px;
}
body {
margin: 0;
background: var(--mdui-background);
font-family: 'Segoe UI', system-ui;
color: var(--mdui-text-primary);
}
.container {
padding: 16px;
max-width: 500px;
margin: 0 auto;
}
.status-card {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 24px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
}
.status-card:hover {
transform: translateY(-2px);
}
.metric-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.metric-value {
font-size: 32px;
font-weight: 700;
color: var(--mdui-primary);
}
.metric-label {
color: var(--mdui-text-secondary);
font-size: 14px;
}
.quick-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin: 24px 0;
}
.action-button {
background: var(--mdui-surface);
border: none;
border-radius: 16px;
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
cursor: pointer;
transition: all 0.2s;
}
.action-button:hover {
background: #f0f4ff;
}
.action-button svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.chart-container {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin: 16px 0;
}
.progress-bar {
height: 8px;
background: #eeeeee;
border-radius: 4px;
overflow: hidden;
margin: 12px 0;
}
.progress-fill {
width: 65%;
height: 100%;
background: var(--mdui-primary);
border-radius: 4px;
transition: width 0.3s ease;
}
.nav-bottom {
position: fixed;
bottom: 0;
width: 100%;
background: var(--mdui-surface);
display: flex;
justify-content: space-around;
padding: 12px 0;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.05);
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
color: var(--mdui-text-secondary);
padding: 8px;
border-radius: 12px;
transition: all 0.2s;
}
.nav-item.active {
color: var(--mdui-primary);
background: #e8efff;
}
.nav-item svg {
width: 20px;
height: 20px;
margin-bottom: 4px;
}
.user-card {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
}
.user-card:hover {
transform: translateY(-2px);
}
.user-card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.user-card-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: #e8efff;
display: flex;
align-items: center;
justify-content: center;
}
.user-card-avatar svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.user-card-info {
flex: 1;
}
.user-card-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 4px;
}
.user-card-role {
font-size: 14px;
color: var(--mdui-text-secondary);
}
.user-card-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.user-card-stat {
text-align: center;
}
.user-card-stat-value {
font-size: 18px;
font-weight: 600;
color: var(--mdui-primary);
}
.user-card-stat-label {
font-size: 12px;
color: var(--mdui-text-secondary);
}
.user-info-card {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
}
.user-info-card:hover {
transform: translateY(-2px);
}
.user-info-card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.user-info-card-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: #e8efff;
display: flex;
align-items: center;
justify-content: center;
}
.user-info-card-avatar svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.user-info-card-info {
flex: 1;
}
.user-info-card-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 4px;
}
.user-info-card-role {
font-size: 14px;
color: var(--mdui-text-secondary);
}
.user-info-card-details {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.user-info-card-detail {
display: flex;
align-items: center;
gap: 8px;
}
.user-info-card-detail svg {
width: 18px;
height: 18px;
fill: var(--mdui-primary);
}
.user-info-card-detail-label {
font-size: 14px;
color: var(--mdui-text-secondary);
}
.user-info-card-detail-value {
font-size: 14px;
font-weight: 600;
}
.table-container {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.table-container table {
width: 100%;
border-collapse: collapse;
}
.table-container th,
.table-container td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #eeeeee;
}
.table-container th {
font-weight: 600;
color: var(--mdui-text-primary);
}
.table-container td {
color: var(--mdui-text-secondary);
}
.form-container {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.form-container label {
display: block;
font-size: 14px;
color: var(--mdui-text-secondary);
margin-bottom: 8px;
}
.form-container input,
.form-container select,
.form-container textarea {
width: 100%;
padding: 12px;
border: 1px solid #eeeeee;
border-radius: 8px;
font-size: 14px;
color: var(--mdui-text-primary);
margin-bottom: 16px;
transition: border-color 0.2s;
}
.form-container input:focus,
.form-container select:focus,
.form-container textarea:focus {
border-color: var(--mdui-primary);
outline: none;
}
.form-container button {
background: var(--mdui-primary);
color: white;
border: none;
border-radius: 8px;
padding: 12px 24px;
font-size: 14px;
cursor: pointer;
transition: background 0.2s;
}
.form-container button:hover {
background: #1e4dff;
}
.alert {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
gap: 12px;
}
.alert svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.alert-success {
background: #e8f5e9;
}
.alert-success svg {
fill: #4caf50;
}
.alert-warning {
background: #fff3e0;
}
.alert-warning svg {
fill: #ff9800;
}
.alert-error {
background: #ffebee;
}
.alert-error svg {
fill: #f44336;
}
.alert-info {
background: #e3f2fd;
}
.alert-info svg {
fill: #2196f3;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.modal-content {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 24px;
max-width: 400px;
width: 100%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.modal-title {
font-size: 18px;
font-weight: 600;
}
.modal-close {
background: none;
border: none;
cursor: pointer;
padding: 8px;
}
.modal-close svg {
width: 24px;
height: 24px;
fill: var(--mdui-text-secondary);
}
.modal-body {
margin-bottom: 16px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.modal-footer button {
padding: 8px 16px;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s;
}
.modal-footer button.primary {
background: var(--mdui-primary);
color: white;
}
.modal-footer button.primary:hover {
background: #1e4dff;
}
.modal-footer button.secondary {
background: #eeeeee;
color: var(--mdui-text-primary);
}
.modal-footer button.secondary:hover {
background: #dddddd;
}
.pagination {
display: flex;
justify-content: center;
gap: 8px;
margin: 16px 0;
}
.pagination button {
background: var(--mdui-surface);
border: none;
border-radius: 8px;
padding: 8px 12px;
cursor: pointer;
transition: background 0.2s;
}
.pagination button.active {
background: var(--mdui-primary);
color: white;
}
.pagination button:hover {
background: #f0f4ff;
}
.tabs {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.tabs button {
background: var(--mdui-surface);
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
transition: background 0.2s;
}
.tabs button.active {
background: var(--mdui-primary);
color: white;
}
.tabs button:hover {
background: #f0f4ff;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-button {
background: var(--mdui-surface);
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
transition: background 0.2s;
}
.dropdown-button:hover {
background: #f0f4ff;
}
.dropdown-content {
display: none;
position: absolute;
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
min-width: 160px;
z-index: 1;
}
.dropdown-content a {
display: block;
padding: 8px 16px;
text-decoration: none;
color: var(--mdui-text-primary);
transition: background 0.2s;
}
.dropdown-content a:hover {
background: #f0f4ff;
}
.dropdown:hover .dropdown-content {
display: block;
}
.timeline {
display: flex;
flex-direction: column;
gap: 16px;
}
.timeline-item {
display: flex;
align-items: flex-start;
gap: 12px;
}
.timeline-item-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: #e8efff;
display: flex;
align-items: center;
justify-content: center;
}
.timeline-item-icon svg {
width: 16px;
height: 16px;
fill: var(--mdui-primary);
}
.timeline-item-content {
flex: 1;
}
.timeline-item-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 4px;
}
.timeline-item-description {
font-size: 12px;
color: var(--mdui-text-secondary);
}
.timeline-item-time {
font-size: 12px;
color: var(--mdui-text-secondary);
}
</style>
</head>
<body>
<div class="container">
<!-- 状态卡片 -->
<div class="status-card">
<div class="metric-header">
<div>
<div class="metric-value">85%</div>
<div class="metric-label">本月完成进度</div>
</div>
<svg viewBox="0 0 24 24" style="width: 40px; height: 40px; fill: var(--mdui-primary);">
<path d="M13 2.05v2.02c3.95.49 7 3.85 7 7.93 0 3.21-1.92 6.03-4.72 7.32l-1.43-1.43c2.13-1.1 3.65-3.29 3.65-5.89 0-3.31-2.69-6-6-6H15l-4 4 4 4h-2.07c-.5-2.84 1.7-5.38 4.5-5.9l1.03-1.03c-.91-.87-2.12-1.43-3.45-1.62V2.05zM12 19c-3.87 0-7-3.13-7-7 0-3.53 2.61-6.43 6-6.92V2.05C6.07 2.55 2 6.81 2 12c0 5.52 4.47 10 9.99 10 3.31 0 6.24-1.61 8.06-4.09l-1.6-1.6A7.925 7.925 0 0 1 12 19z"/>
</svg>
</div>
<div class="progress-bar">
<div class="progress-fill"></div>
</div>
</div>
<!-- 快速操作 -->
<div class="quick-actions">
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</svg>
<span>新建项目</span>
</button>
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
</svg>
<span>数据分析</span>
</button>
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/>
</svg>
<span>系统设置</span>
</button>
</div>
<!-- 数据图表 -->
<div class="chart-container">
<h3 style="margin:0 0 16px;">存储使用情况</h3>
<div style="display: flex; gap: 16px; align-items: center;">
<div style="flex:1;">
<div style="font-size: 12px; color: var(--mdui-text-secondary); margin-bottom: 8px;">
已用 15.2GB / 50GB
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 30%;"></div>
</div>
</div>
<svg viewBox="0 0 24 24" style="width: 24px; height:24px; fill: var(--mdui-primary);">
<path d="M8 17v-7.31l2.6 2.6L12 11l4-4 4 4 1.4-1.4-5.4-5.4L12 3 5.4 9.6 6.8 11 8 9.8v7.5z"/>
</svg>
</div>
</div>
<!-- 用户卡片 -->
<div class="user-card">
<div class="user-card-header">
<div class="user-card-avatar">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="user-card-info">
<div class="user-card-name">张三</div>
<div class="user-card-role">管理员</div>
</div>
</div>
<div class="user-card-stats">
<div class="user-card-stat">
<div class="user-card-stat-value">12</div>
<div class="user-card-stat-label">项目</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">45</div>
<div class="user-card-stat-label">任务</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">98%</div>
<div class="user-card-stat-label">完成率</div>
</div>
</div>
</div>
<!-- 用户信息卡片 -->
<div class="user-info-card">
<div class="user-info-card-header">
<div class="user-info-card-avatar">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="user-info-card-info">
<div class="user-info-card-name">李四</div>
<div class="user-info-card-role">开发者</div>
</div>
</div>
<div class="user-info-card-details">
<div class="user-info-card-detail">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
<div>
<div class="user-info-card-detail-label">邮箱</div>
<div class="user-info-card-detail-value">lisi@example.com</div>
</div>
</div>
<div class="user-info-card-detail">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
<div>
<div class="user-info-card-detail-label">电话</div>
<div class="user-info-card-detail-value">+86 123 4567 8901</div>
</div>
</div>
</div>
</div>
<!-- 表格 -->
<div class="table-container">
<h3 style="margin:0 0 16px;">用户列表</h3>
<table>
<thead>
<tr>
<th>姓名</th>
<th>角色</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<td>张三</td>
<td>管理员</td>
<td>zhangsan@example.com</td>
</tr>
<tr>
<td>李四</td>
<td>开发者</td>
<td>lisi@example.com</td>
</tr>
<tr>
<td>王五</td>
<td>设计师</td>
<td>wangwu@example.com</td>
</tr>
</tbody>
</table>
</div>
<!-- 表单 -->
<div class="form-container">
<h3 style="margin:0 0 16px;">用户注册</h3>
<form>
<label for="name">姓名</label>
<input type="text" id="name" placeholder="请输入姓名">
<label for="email">邮箱</label>
<input type="email" id="email" placeholder="请输入邮箱">
<label for="role">角色</label>
<select id="role">
<option value="admin">管理员</option>
<option value="developer">开发者</option>
<option value="designer">设计师</option>
</select>
<label for="bio">简介</label>
<textarea id="bio" rows="4" placeholder="请输入简介"></textarea>
<button type="submit">提交</button>
</form>
</div>
<!-- 提示信息 -->
<div class="alert alert-success">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
</svg>
<div>操作成功!</div>
</div>
<div class="alert alert-warning">
<svg viewBox="0 0 24 24">
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
</svg>
<div>请注意,您的存储空间即将用完。</div>
</div>
<div class="alert alert-error">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
</svg>
<div>操作失败,请重试。</div>
</div>
<div class="alert alert-info">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
</svg>
<div>这是一个信息提示。</div>
</div>
<!-- 模态框 -->
<div class="modal" id="modal">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">模态框标题</div>
<button class="modal-close" onclick="closeModal()">
<svg viewBox="0 0 24 24">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
</svg>
</button>
</div>
<div class="modal-body">
<p>这是一个模态框的内容。</p>
</div>
<div class="modal-footer">
<button class="secondary" onclick="closeModal()">取消</button>
<button class="primary" onclick="closeModal()">确定</button>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination">
<button class="active">1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
</div>
<!-- 标签页 -->
<div class="tabs">
<button class="active">标签1</button>
<button>标签2</button>
<button>标签3</button>
</div>
<!-- 下拉菜单 -->
<div class="dropdown">
<button class="dropdown-button">下拉菜单</button>
<div class="dropdown-content">
<a href="#">选项1</a>
<a href="#">选项2</a>
<a href="#">选项3</a>
</div>
</div>
<!-- 时间轴 -->
<div class="timeline">
<div class="timeline-item">
<div class="timeline-item-icon">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="timeline-item-content">
<div class="timeline-item-title">事件1</div>
<div class="timeline-item-description">这是事件1的描述。</div>
<div class="timeline-item-time">2023-10-01</div>
</div>
</div>
<div class="timeline-item">
<div class="timeline-item-icon">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="timeline-item-content">
<div class="timeline-item-title">事件2</div>
<div class="timeline-item-description">这是事件2的描述。</div>
<div class="timeline-item-time">2023-10-02</div>
</div>
</div>
</div>
<!-- 最近活动 -->
<div class="status-card">
<h3 style="margin:0 0 16px;">最近活动</h3>
<div style="display: grid; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="background: #e8efff; border-radius: 50%; padding: 8px;">
<svg viewBox="0 0 24 24" style="width: 18px; height:18px; fill: var(--mdui-primary);">
<path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/>
</svg>
</div>
<div>
<div>新用户注册</div>
<div style="font-size: 12px; color: var(--mdui-text-secondary);">2分钟前</div>
</div>
</div>
<!-- 更多活动项... -->
</div>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</div>
<!-- 底部导航 -->
<nav class="nav-bottom">
<div class="nav-item active">
<svg viewBox="0 0 24 24"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
首页
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
用户
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-8 12H8c-.55 0-1-.45-1-1s.45-1 1-1h3c.55 0 1 .45 1 1s-.45 1-1 1zm0-4H8c-.55 0-1-.45-1-1s.45-1 1-1h3c.55 0 1 .45 1 1s-.45 1-1 1zm0-4H8c-.55 0-1-.45-1-1s.45-1 1-1h3c.55 0 1 .45 1 1s-.45 1-1 1z"/></svg>
统计
</div>
</nav>
<script>
function openModal() {
document.getElementById('modal').style.display = 'flex';
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
</script>
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>eruda.init();</script>
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3.5.13/dist/vue.global.prod.js"></script>
<script src="msg.js"></script>
<script src="app.js"></script>
</body>
</html>

983
Dashboard/t.html.bak Normal file
View File

@@ -0,0 +1,983 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>移动端仪表盘</title>
<style>
:root {
--mdui-primary: #2962ff;
--mdui-surface: #ffffff;
--mdui-background: #f5f5f5;
--mdui-text-primary: rgba(0, 0, 0, 0.87);
--mdui-text-secondary: rgba(0, 0, 0, 0.6);
--mdui-shape-corner: 20px;
}
body {
margin: 0;
background: var(--mdui-background);
font-family: 'Segoe UI', system-ui;
color: var(--mdui-text-primary);
}
.container {
padding: 16px;
max-width: 500px;
margin: 0 auto;
}
.status-card {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 24px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
}
.status-card:hover {
transform: translateY(-2px);
}
.metric-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.metric-value {
font-size: 32px;
font-weight: 700;
color: var(--mdui-primary);
}
.metric-label {
color: var(--mdui-text-secondary);
font-size: 14px;
}
.quick-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin: 24px 0;
}
.action-button {
background: var(--mdui-surface);
border: none;
border-radius: 16px;
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
cursor: pointer;
transition: all 0.2s;
}
.action-button:hover {
background: #f0f4ff;
}
.action-button svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.chart-container {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin: 16px 0;
}
.progress-bar {
height: 8px;
background: #eeeeee;
border-radius: 4px;
overflow: hidden;
margin: 12px 0;
}
.progress-fill {
width: 65%;
height: 100%;
background: var(--mdui-primary);
border-radius: 4px;
transition: width 0.3s ease;
}
.nav-bottom {
position: fixed;
bottom: 0;
width: 100%;
background: var(--mdui-surface);
display: flex;
justify-content: space-around;
padding: 12px 0;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.05);
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
color: var(--mdui-text-secondary);
padding: 8px;
border-radius: 12px;
transition: all 0.2s;
}
.nav-item.active {
color: var(--mdui-primary);
background: #e8efff;
}
.nav-item svg {
width: 20px;
height: 20px;
margin-bottom: 4px;
}
.user-card {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
}
.user-card:hover {
transform: translateY(-2px);
}
.user-card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.user-card-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: #e8efff;
display: flex;
align-items: center;
justify-content: center;
}
.user-card-avatar svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.user-card-info {
flex: 1;
}
.user-card-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 4px;
}
.user-card-role {
font-size: 14px;
color: var(--mdui-text-secondary);
}
.user-card-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.user-card-stat {
text-align: center;
}
.user-card-stat-value {
font-size: 18px;
font-weight: 600;
color: var(--mdui-primary);
}
.user-card-stat-label {
font-size: 12px;
color: var(--mdui-text-secondary);
}
.user-info-card {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.2s;
}
.user-info-card:hover {
transform: translateY(-2px);
}
.user-info-card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.user-info-card-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: #e8efff;
display: flex;
align-items: center;
justify-content: center;
}
.user-info-card-avatar svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.user-info-card-info {
flex: 1;
}
.user-info-card-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 4px;
}
.user-info-card-role {
font-size: 14px;
color: var(--mdui-text-secondary);
}
.user-info-card-details {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.user-info-card-detail {
display: flex;
align-items: center;
gap: 8px;
}
.user-info-card-detail svg {
width: 18px;
height: 18px;
fill: var(--mdui-primary);
}
.user-info-card-detail-label {
font-size: 14px;
color: var(--mdui-text-secondary);
}
.user-info-card-detail-value {
font-size: 14px;
font-weight: 600;
}
.table-container {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.table-container table {
width: 100%;
border-collapse: collapse;
}
.table-container th,
.table-container td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #eeeeee;
}
.table-container th {
font-weight: 600;
color: var(--mdui-text-primary);
}
.table-container td {
color: var(--mdui-text-secondary);
}
.form-container {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.form-container label {
display: block;
font-size: 14px;
color: var(--mdui-text-secondary);
margin-bottom: 8px;
}
.form-container input,
.form-container select,
.form-container textarea {
width: 100%;
padding: 12px;
border: 1px solid #eeeeee;
border-radius: 8px;
font-size: 14px;
color: var(--mdui-text-primary);
margin-bottom: 16px;
transition: border-color 0.2s;
}
.form-container input:focus,
.form-container select:focus,
.form-container textarea:focus {
border-color: var(--mdui-primary);
outline: none;
}
.form-container button {
background: var(--mdui-primary);
color: white;
border: none;
border-radius: 8px;
padding: 12px 24px;
font-size: 14px;
cursor: pointer;
transition: background 0.2s;
}
.form-container button:hover {
background: #1e4dff;
}
.alert {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
gap: 12px;
}
.alert svg {
width: 24px;
height: 24px;
fill: var(--mdui-primary);
}
.alert-success {
background: #e8f5e9;
}
.alert-success svg {
fill: #4caf50;
}
.alert-warning {
background: #fff3e0;
}
.alert-warning svg {
fill: #ff9800;
}
.alert-error {
background: #ffebee;
}
.alert-error svg {
fill: #f44336;
}
.alert-info {
background: #e3f2fd;
}
.alert-info svg {
fill: #2196f3;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.modal-content {
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
padding: 24px;
max-width: 400px;
width: 100%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.modal-title {
font-size: 18px;
font-weight: 600;
}
.modal-close {
background: none;
border: none;
cursor: pointer;
padding: 8px;
}
.modal-close svg {
width: 24px;
height: 24px;
fill: var(--mdui-text-secondary);
}
.modal-body {
margin-bottom: 16px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.modal-footer button {
padding: 8px 16px;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s;
}
.modal-footer button.primary {
background: var(--mdui-primary);
color: white;
}
.modal-footer button.primary:hover {
background: #1e4dff;
}
.modal-footer button.secondary {
background: #eeeeee;
color: var(--mdui-text-primary);
}
.modal-footer button.secondary:hover {
background: #dddddd;
}
.pagination {
display: flex;
justify-content: center;
gap: 8px;
margin: 16px 0;
}
.pagination button {
background: var(--mdui-surface);
border: none;
border-radius: 8px;
padding: 8px 12px;
cursor: pointer;
transition: background 0.2s;
}
.pagination button.active {
background: var(--mdui-primary);
color: white;
}
.pagination button:hover {
background: #f0f4ff;
}
.tabs {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.tabs button {
background: var(--mdui-surface);
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
transition: background 0.2s;
}
.tabs button.active {
background: var(--mdui-primary);
color: white;
}
.tabs button:hover {
background: #f0f4ff;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-button {
background: var(--mdui-surface);
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
transition: background 0.2s;
}
.dropdown-button:hover {
background: #f0f4ff;
}
.dropdown-content {
display: none;
position: absolute;
background: var(--mdui-surface);
border-radius: var(--mdui-shape-corner);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
min-width: 160px;
z-index: 1;
}
.dropdown-content a {
display: block;
padding: 8px 16px;
text-decoration: none;
color: var(--mdui-text-primary);
transition: background 0.2s;
}
.dropdown-content a:hover {
background: #f0f4ff;
}
.dropdown:hover .dropdown-content {
display: block;
}
.timeline {
display: flex;
flex-direction: column;
gap: 16px;
}
.timeline-item {
display: flex;
align-items: flex-start;
gap: 12px;
}
.timeline-item-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: #e8efff;
display: flex;
align-items: center;
justify-content: center;
}
.timeline-item-icon svg {
width: 16px;
height: 16px;
fill: var(--mdui-primary);
}
.timeline-item-content {
flex: 1;
}
.timeline-item-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 4px;
}
.timeline-item-description {
font-size: 12px;
color: var(--mdui-text-secondary);
}
.timeline-item-time {
font-size: 12px;
color: var(--mdui-text-secondary);
}
</style>
</head>
<body>
<div class="container">
<!-- 状态卡片 -->
<div class="status-card">
<div class="metric-header">
<div>
<div class="metric-value">85%</div>
<div class="metric-label">本月完成进度</div>
</div>
<svg viewBox="0 0 24 24" style="width: 40px; height: 40px; fill: var(--mdui-primary);">
<path d="M13 2.05v2.02c3.95.49 7 3.85 7 7.93 0 3.21-1.92 6.03-4.72 7.32l-1.43-1.43c2.13-1.1 3.65-3.29 3.65-5.89 0-3.31-2.69-6-6-6H15l-4 4 4 4h-2.07c-.5-2.84 1.7-5.38 4.5-5.9l1.03-1.03c-.91-.87-2.12-1.43-3.45-1.62V2.05zM12 19c-3.87 0-7-3.13-7-7 0-3.53 2.61-6.43 6-6.92V2.05C6.07 2.55 2 6.81 2 12c0 5.52 4.47 10 9.99 10 3.31 0 6.24-1.61 8.06-4.09l-1.6-1.6A7.925 7.925 0 0 1 12 19z"/>
</svg>
</div>
<div class="progress-bar">
<div class="progress-fill"></div>
</div>
</div>
<!-- 快速操作 -->
<div class="quick-actions">
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</svg>
<span>新建项目</span>
</button>
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
</svg>
<span>数据分析</span>
</button>
<button class="action-button">
<svg viewBox="0 0 24 24">
<path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/>
</svg>
<span>系统设置</span>
</button>
</div>
<!-- 数据图表 -->
<div class="chart-container">
<h3 style="margin:0 0 16px;">存储使用情况</h3>
<div style="display: flex; gap: 16px; align-items: center;">
<div style="flex:1;">
<div style="font-size: 12px; color: var(--mdui-text-secondary); margin-bottom: 8px;">
已用 15.2GB / 50GB
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 30%;"></div>
</div>
</div>
<svg viewBox="0 0 24 24" style="width: 24px; height:24px; fill: var(--mdui-primary);">
<path d="M8 17v-7.31l2.6 2.6L12 11l4-4 4 4 1.4-1.4-5.4-5.4L12 3 5.4 9.6 6.8 11 8 9.8v7.5z"/>
</svg>
</div>
</div>
<!-- 用户卡片 -->
<div class="user-card">
<div class="user-card-header">
<div class="user-card-avatar">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="user-card-info">
<div class="user-card-name">张三</div>
<div class="user-card-role">管理员</div>
</div>
</div>
<div class="user-card-stats">
<div class="user-card-stat">
<div class="user-card-stat-value">12</div>
<div class="user-card-stat-label">项目</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">45</div>
<div class="user-card-stat-label">任务</div>
</div>
<div class="user-card-stat">
<div class="user-card-stat-value">98%</div>
<div class="user-card-stat-label">完成率</div>
</div>
</div>
</div>
<!-- 用户信息卡片 -->
<div class="user-info-card">
<div class="user-info-card-header">
<div class="user-info-card-avatar">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="user-info-card-info">
<div class="user-info-card-name">李四</div>
<div class="user-info-card-role">开发者</div>
</div>
</div>
<div class="user-info-card-details">
<div class="user-info-card-detail">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
<div>
<div class="user-info-card-detail-label">邮箱</div>
<div class="user-info-card-detail-value">lisi@example.com</div>
</div>
</div>
<div class="user-info-card-detail">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
<div>
<div class="user-info-card-detail-label">电话</div>
<div class="user-info-card-detail-value">+86 123 4567 8901</div>
</div>
</div>
</div>
</div>
<!-- 表格 -->
<div class="table-container">
<h3 style="margin:0 0 16px;">用户列表</h3>
<table>
<thead>
<tr>
<th>姓名</th>
<th>角色</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<td>张三</td>
<td>管理员</td>
<td>zhangsan@example.com</td>
</tr>
<tr>
<td>李四</td>
<td>开发者</td>
<td>lisi@example.com</td>
</tr>
<tr>
<td>王五</td>
<td>设计师</td>
<td>wangwu@example.com</td>
</tr>
</tbody>
</table>
</div>
<!-- 表单 -->
<div class="form-container">
<h3 style="margin:0 0 16px;">用户注册</h3>
<form>
<label for="name">姓名</label>
<input type="text" id="name" placeholder="请输入姓名">
<label for="email">邮箱</label>
<input type="email" id="email" placeholder="请输入邮箱">
<label for="role">角色</label>
<select id="role">
<option value="admin">管理员</option>
<option value="developer">开发者</option>
<option value="designer">设计师</option>
</select>
<label for="bio">简介</label>
<textarea id="bio" rows="4" placeholder="请输入简介"></textarea>
<button type="submit">提交</button>
</form>
</div>
<!-- 提示信息 -->
<div class="alert alert-success">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
</svg>
<div>操作成功!</div>
</div>
<div class="alert alert-warning">
<svg viewBox="0 0 24 24">
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
</svg>
<div>请注意,您的存储空间即将用完。</div>
</div>
<div class="alert alert-error">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
</svg>
<div>操作失败,请重试。</div>
</div>
<div class="alert alert-info">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
</svg>
<div>这是一个信息提示。</div>
</div>
<!-- 模态框 -->
<div class="modal" id="modal">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">模态框标题</div>
<button class="modal-close" onclick="closeModal()">
<svg viewBox="0 0 24 24">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
</svg>
</button>
</div>
<div class="modal-body">
<p>这是一个模态框的内容。</p>
</div>
<div class="modal-footer">
<button class="secondary" onclick="closeModal()">取消</button>
<button class="primary" onclick="closeModal()">确定</button>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination">
<button class="active">1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
</div>
<!-- 标签页 -->
<div class="tabs">
<button class="active">标签1</button>
<button>标签2</button>
<button>标签3</button>
</div>
<!-- 下拉菜单 -->
<div class="dropdown">
<button class="dropdown-button">下拉菜单</button>
<div class="dropdown-content">
<a href="#">选项1</a>
<a href="#">选项2</a>
<a href="#">选项3</a>
</div>
</div>
<!-- 时间轴 -->
<div class="timeline">
<div class="timeline-item">
<div class="timeline-item-icon">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="timeline-item-content">
<div class="timeline-item-title">事件1</div>
<div class="timeline-item-description">这是事件1的描述。</div>
<div class="timeline-item-time">2023-10-01</div>
</div>
</div>
<div class="timeline-item">
<div class="timeline-item-icon">
<svg viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
</svg>
</div>
<div class="timeline-item-content">
<div class="timeline-item-title">事件2</div>
<div class="timeline-item-description">这是事件2的描述。</div>
<div class="timeline-item-time">2023-10-02</div>
</div>
</div>
</div>
<!-- 最近活动 -->
<div class="status-card">
<h3 style="margin:0 0 16px;">最近活动</h3>
<div style="display: grid; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="background: #e8efff; border-radius: 50%; padding: 8px;">
<svg viewBox="0 0 24 24" style="width: 18px; height:18px; fill: var(--mdui-primary);">
<path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/>
</svg>
</div>
<div>
<div>新用户注册</div>
<div style="font-size: 12px; color: var(--mdui-text-secondary);">2分钟前</div>
</div>
</div>
<!-- 更多活动项... -->
</div>
</div>
</div>
<!-- 底部导航 -->
<nav class="nav-bottom">
<div class="nav-item active">
<svg viewBox="0 0 24 24"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
首页
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
用户
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-8 12H8c-.55 0-1-.45-1-1s.45-1 1-1h3c.55 0 1 .45 1 1s-.45 1-1 1zm0-4H8c-.55 0-1-.45-1-1s.45-1 1-1h3c.55 0 1 .45 1 1s-.45 1-1 1zm0-4H8c-.55 0-1-.45-1-1s.45-1 1-1h3c.55 0 1 .45 1 1s-.45 1-1 1z"/></svg>
统计
</div>
</nav>
<script>
function openModal() {
document.getElementById('modal').style.display = 'flex';
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
</script>
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>eruda.init();</script>
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3.5.13/dist/vue.global.prod.js"></script>
<script src="msg.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

View File

@@ -0,0 +1,3 @@
[2025-03-01 15:17:22].341 <执行中> - >>>==================================>>>
[2025-03-01 15:17:22].341 <提示> - ExpiryReminder 任务开始
[2025-03-01 15:17:22].341 <提示> - 查询中

View File

@@ -0,0 +1,63 @@
nl01tnkt4t
lh6sr7t9sd
55irq9mt51hht8r
l6jbl3awye
0f7wilpmqlwrwb7
pfy5lwf18l
7tohfmfpf8k2x7m
mvirbu6hog
xm7x949ipbb0u4p
b10cxrewms
9x8w1pe9sssu17y
9ydyzcwap0
5lrxiq10snw2e4s
4456d5a8vv
z07lurkukdxho1j
w7o2w6vsva
f5sqqb01x66jjhn
1kwqp1bty6
sckk4u5e5iyu0cd
bmyvr14q3z
5mwf7jh2vwoezy1
hy25pbtvia
h13qspl8nfu38r2
i6b29cufv1
k7brk5as0zgro0f
9mwvjh1t01
sneg222cuhu06uh
y07mjuo1cf
oulpjda4h72bp9d
zvn19ce909
8qugxyavcgoaxm9
ojsrsgpy46
3u8a2hivbyxj947
gy3accf815
dohwpxuxu36f445
bm4h3na5xj
3jmwv9cv2o62j5h
8mvaysfctg
beqktcwt9g0n1bf
an3hydsfbb
cld06vc4ba2t9tr
nuy7sak0vp
c2wz01xoyw6xjpa
ac1ddtz5uz
s4ammf90ludjpxx
u3jocjlecs
mrm9h0qex58wnu4
jlgne3buvp
1cp744jvbvhyw07
3ywmpl50l2
ou84orvyac2q5ih
fmccgczjr2
c9qgnzhp367p7sk
845jp6o44u
ox9py3z8e41usol
gdfk38lg9q
c62dmgesi1ik6lo
x8jhc04f68
6iys03f3o1zxtp0
n1dmp5v1ou
2utduxhqu3m75tj
srtonx74oz
ajzrbq4mdw1tlsv

98
Main/BuyGoods/index.php Normal file
View File

@@ -0,0 +1,98 @@
<?php
require_once "../Hv4.Logged.php";
$产品标识 = @$_POST['product_id'];
$语句 = "SELECT * FROM products WHERE product_id = '$产品标识';";
$产品元数据 = @reset(@数据库运行($语句));
if (!$产品元数据) {
定义输出("code",100);
定义输出("msg","获取产品元数据失败");
终止并输出();
}
$产品模块 = $产品元数据["module"];
$产品周期 = $产品元数据["subscription_period"];
$模块路径 = "../ProductsModule/".$产品模块."/Main.php";
$产品名称 = $产品元数据["name"];
require_once $模块路径;
$产品唯一标识符 = @唯一字符串();
$价格 = $产品元数据["price"];
$货币 = $产品元数据["currency_type"];
$库存 = $产品元数据["stock"];
$限购 = $产品元数据["limit_per_user"];
$语句 = "SELECT * FROM purchases WHERE product_id = '$产品标识' AND user_id = $用户ID;";
$用户购买 = @count(@数据库运行($语句));
if ($限购 <= $用户购买) {
定义输出("code",100);
定义输出("msg","别买太多惹");
终止并输出();
}
if ($库存 <= 0) {
定义输出("code",100);
定义输出("msg","库存不足惹");
终止并输出();
}
if ($货币 == "score") {
$比较项 = $积分;
} else {
$比较项 = $余额;
}
$减后余额 = $比较项 - $价格;
if ($减后余额 < 0) {
定义输出("code",100);
定义输出("msg","余额不足惹");
终止并输出();
}
if ($货币 == "score") {
设置用户积分($减后余额);
} else {
设置用户余额($减后余额);
}
$结果 = @开通产品($产品元数据,$产品唯一标识符);
$储存数据 = @转JSON($结果["data"]);
if ($结果["code"] == 200) {
定义输出("code",$结果["code"]);
定义输出("msg","开通成功");
$产品状态 = "activated";
} else {
定义输出("code",$结果["code"]);
定义输出("msg","开通失败");
$产品状态 = "pending_activation";
}
$库存 = $库存 - 1;
$语句 = "UPDATE products
SET stock = $库存
WHERE product_id = '$产品标识';";
@数据库运行($语句);
$语句 = "INSERT INTO `purchases`
(`user_id`, `product_id`, `purchase_id`, `purchase_time`, `expiry_time`, `status`, `subscription_period`, `extra_data`, `name`)
VALUES
($用户ID, '$产品标识', '$产品唯一标识符', NOW(), DATE_ADD(NOW(), INTERVAL $产品周期 DAY), '$产品状态', $产品周期, '$储存数据', '$产品名称');";
//$definedVars = get_defined_vars();
//print_r($definedVars);
@数据库运行($语句);
终止并输出();

View File

@@ -0,0 +1,93 @@
<?php
require_once "../Hv4.Logged.php";
$产品标识 = @$_POST['product_id'];
$语句 = "SELECT * FROM products WHERE product_id = '$产品标识';";
$产品元数据 = @reset(@数据库运行($语句));
if (!$产品元数据) {
定义输出("code",100);
定义输出("msg","获取产品元数据失败");
终止并输出();
}
$产品模块 = $产品元数据["module"];
$产品周期 = $产品元数据["subscription_period"];
$模块路径 = "../ProductsModule/".$产品模块."/Main.php";
$产品名称 = $产品元数据["name"];
require_once $模块路径;
$产品唯一标识符 = @唯一字符串();
$价格 = $产品元数据["price"];
$货币 = $产品元数据["currency_type"];
$库存 = $产品元数据["stock"];
$限购 = $产品元数据["limit_per_user"];
$语句 = "SELECT * FROM purchases WHERE product_id = '$产品标识' AND user_id = $用户ID;";
$用户购买 = @数据库运行($语句);
print_r($用户购买);
if ($库存 <= 0) {
定义输出("code",100);
定义输出("msg","库存不足惹");
终止并输出();
}
if ($货币 == "score") {
$比较项 = $积分;
} else {
$比较项 = $余额;
}
$减后余额 = $比较项 - $价格;
if ($减后余额 < 0) {
定义输出("code",100);
定义输出("msg","余额不足惹");
终止并输出();
}
if ($货币 == "score") {
设置用户积分($减后余额);
} else {
设置用户余额($减后余额);
}
$结果 = @开通产品($产品元数据,$产品唯一标识符);
$储存数据 = @转JSON($结果["data"]);
if ($结果["code"] == 200) {
定义输出("code",$结果["code"]);
定义输出("msg","开通成功");
$产品状态 = "activated";
} else {
定义输出("code",$结果["code"]);
定义输出("msg","开通失败");
$产品状态 = "pending_activation";
}
$库存 = $库存 - 1;
$语句 = "UPDATE products
SET stock = $库存
WHERE product_id = '$产品标识';";
@数据库运行($语句);
$语句 = "INSERT INTO `purchases`
(`user_id`, `product_id`, `purchase_id`, `purchase_time`, `expiry_time`, `status`, `subscription_period`, `extra_data`, `name`)
VALUES
($用户ID, '$产品标识', '$产品唯一标识符', NOW(), DATE_ADD(NOW(), INTERVAL $产品周期 DAY), '$产品状态', $产品周期, '$储存数据', '$产品名称');";
//$definedVars = get_defined_vars();
//print_r($definedVars);
@数据库运行($语句);
终止并输出();

View File

@@ -0,0 +1,22 @@
FVE563ASY
QAN542WLC
KNV363EYM
AZL454TBN
UMF778BBF
XCR437DCQ
ATD274VBT
GRG432HXY
UNX238ALT
UJT689XHC
KWT876HWV
KUW648VDF
MAT899TQY
ULA589MBU
YUR377DRU
TEP894VRP
TTY527ZUE
VTT629AMQ
KQA857VAY
ZEZ853WFP
XZJ787EBL
LWC296XGX

17
Main/CheckIn/index.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
include_once "../Hv4.Logged.php";
if (!$未签到) {
定义输出("msg","已经签到过啦");
定义输出("code",100);
终止并输出();
} else {
$获取积分 = mt_rand(80, 200);
$语句 = "UPDATE `users`
SET `last_sign_in_date` = CURRENT_DATE
WHERE `id` = $用户ID;";
@数据库运行($语句);
@设置用户积分($积分+$获取积分);
定义输出("msg","获得积分 ".$获取积分);
定义输出("code",200);
终止并输出();
}

View File

@@ -0,0 +1,17 @@
<?php
include_once "../Hv4.Logged.php";
if (!$未签到) {
定义输出("msg","已经签到过啦");
定义输出("code",100);
终止并输出();
} else {
$获取积分 = mt_rand(80, 200);
$语句 = "UPDATE `users`
SET `last_sign_in_date` = CURRENT_DATE
WHERE `id` = $用户ID;";
@数据库运行($语句);
@设置用户积分($积分+$获取积分);
定义输出("msg","获得积分 ".$获得积分);
定义输出("code",200);
终止并输出();
}

50
Main/GetGoods/index.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
include_once "../Hv4.Function.php";
$语句 = "SELECT * FROM products WHERE status = 'visible';";
$商品元数据 = @数据库运行($语句);
// 原始数据
$data = $商品元数据;
// 用来存储分类结果的数组
$categories = [];
// 分类和整理数据
foreach ($data as $item) {
// 移除分类中的 [xxx] 数字部分
$category1 = preg_replace('/\[\d+\]$/', '', $item['category_1']);
$category2 = preg_replace('/\[\d+\]$/', '', $item['category_2']);
if ($item['currency_type'] == 'score') {
$item['currency_type'] = '积分';
} else {
$item['currency_type'] = '元';
}
// 分类1和分类2作为键来组织数据
if (!isset($categories[$category1])) {
$categories[$category1] = [];
}
// 确保分类2的存在并添加产品到分类2
if (!isset($categories[$category1][$category2])) {
$categories[$category1][$category2] = [];
}
// 将当前商品添加到相应的分类下
$categories[$category1][$category2][] = $item;
}
// 对每个分类内的数据进行排序
foreach ($categories as $category1 => &$category1Items) {
foreach ($category1Items as $category2 => &$category2Items) {
// 按照 sort_order 字段降序排序
usort($category2Items, function ($a, $b) {
return $b['sort_order'] - $a['sort_order'];
});
}
}
// 转换为 JSON 格式输出
echo 转JSON($categories);
?>

View File

@@ -0,0 +1,46 @@
<?php
include_once "../Hv4.Function.php";
$语句 = "SELECT * FROM products WHERE status = 'visible';";
$商品元数据 = @数据库运行($语句);
// 原始数据
$data = $商品元数据;
// 用来存储分类结果的数组
$categories = [];
// 分类和整理数据
foreach ($data as $item) {
// 移除分类中的 [xxx] 数字部分
$category1 = preg_replace('/\[\d+\]$/', '', $item['category_1']);
$category2 = preg_replace('/\[\d+\]$/', '', $item['category_2']);
// 分类1和分类2作为键来组织数据
if (!isset($categories[$category1])) {
$categories[$category1] = [];
}
// 确保分类2的存在并添加产品到分类2
if (!isset($categories[$category1][$category2])) {
$categories[$category1][$category2] = [];
}
// 将当前商品添加到相应的分类下
$categories[$category1][$category2][] = $item;
}
// 对每个分类内的数据进行排序
foreach ($categories as $category1 => &$category1Items) {
foreach ($category1Items as $category2 => &$category2Items) {
// 按照 sort_order 字段降序排序
usort($category2Items, function ($a, $b) {
return $b['sort_order'] - $a['sort_order'];
});
}
}
// 转换为 JSON 格式输出
echo 转JSON($categories);
?>

5
Main/GetInfo/index.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
include_once "../Hv4.Logged.php";
定义输出("msg",$用户数据);
定义输出("code",200);
终止并输出();

View File

@@ -0,0 +1,5 @@
<?php
include_once "../Hv4.Logged.php";
定义输出("msg",$用户信息);
定义输出("code",200);
终止并输出();

View File

@@ -0,0 +1,33 @@
<?php
require_once "../Hv4.Logged.php";
// 获取数据
$语句 = "SELECT * FROM purchases WHERE user_id = $用户ID";
$产品元数据 = @数据库运行($语句);
if (!$产品元数据) {
定义输出("code",100);
定义输出("msg","没有产品数据咩");
终止并输出();
}
// 先获取当前时间,转换成时间戳
$current_time = time();
// 使用 usort 对数据按 expiry_time 排序,越远的排前面
usort($产品元数据, function($a, $b) use ($current_time) {
$expiry_a = strtotime($a['expiry_time']);
$expiry_b = strtotime($b['expiry_time']);
// 计算距离当前时间的差值
$diff_a = abs($expiry_a - $current_time);
$diff_b = abs($expiry_b - $current_time);
// 越远的排前面
return $diff_b - $diff_a;
});
定义输出("code",200);
定义输出("msg",$产品元数据);
终止并输出();
?>

View File

@@ -0,0 +1,26 @@
<?php
require_once "../Hv4.Logged.php";
// 获取数据
$语句 = "SELECT * FROM purchases WHERE user_id = $用户ID";
$产品元数据 = @数据库运行($语句);
// 先获取当前时间,转换成时间戳
$current_time = time();
// 使用 usort 对数据按 expiry_time 排序,越远的排前面
usort($产品元数据, function($a, $b) use ($current_time) {
$expiry_a = strtotime($a['expiry_time']);
$expiry_b = strtotime($b['expiry_time']);
// 计算距离当前时间的差值
$diff_a = abs($expiry_a - $current_time);
$diff_b = abs($expiry_b - $current_time);
// 越远的排前面
return $diff_b - $diff_a;
});
// 输出数据
print_r($产品元数据);
?>

234
Main/Hv4.Function.php Normal file
View File

@@ -0,0 +1,234 @@
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
session_start();
// 自动将 JSON 请求体转为 $_POST
if ($_SERVER['CONTENT_TYPE'] === 'application/json') {
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if ($data) {
$_POST = array_merge($_POST, $data);
}
}
//祖传适配CDN
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// 获取 'X-Forwarded-For' 中的第一个 IP 地址
$ipArray = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = trim($ipArray[0]); // 更新 REMOTE_ADDR
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
// 如果 'X-Forwarded-For' 不存在,则尝试使用 'HTTP_CLIENT_IP'
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CLIENT_IP'];
}
//祖传输出
$Out = "{}";
function 定义输出($key,$value) {
global $Out;
$Out = json_decode($Out, true);
$Out[$key] = $value;
$Out = json_encode($Out, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
function 终止并输出() {
global $Out;
die($Out);
}
//祖传数据库函数
function 数据库运行($sql) {
// 数据库连接参数
$servername = "110.40.52.75";
$username = "fuxstohostv4";
$password = "yxh20080130";
$dbname = "fuxstohostv4";
// 创建数据库连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 检查连接是否成功
if ($conn->connect_error) {
return "连接失败: " . $conn->connect_error;
}
// 执行 SQL 查询
$result = $conn->query($sql);
// 查询失败,返回错误信息
if ($result === FALSE) {
$conn->close();
return "查询失败: " . $conn->error;
}
// 如果是 SELECT 查询,自动处理并返回结果
if (stripos($sql, 'SELECT') === 0) {
// 创建一个数组存储所有的查询结果
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row; // 将每一行的数据加入结果数组
}
$conn->close();
return $data; // 返回查询结果
}
// 对于非 SELECT 查询INSERT, UPDATE, DELETE直接返回 true
$conn->close();
return true;
}
// 生成随机字符串的函数
function 生成随机字符串($长度, $字符集, $字符集长度) {
$随机字符串 = '';
for ($i = 0; $i < $长度; $i++) {
$随机字符串 .= $字符集[rand(0, $字符集长度 - 1)];
}
return $随机字符串;
}
function 唯一随机字符串($长度) {
// 定义字符集
$字符集 = 'abcdefghijklmnopqrstuvwxyz0123456789';
$字符集长度 = strlen($字符集);
// 文件路径,用来存储已生成的字符串
$文件路径 = 'generated_strings.txt';
// 检查文件是否存在,如果不存在则创建
if (!file_exists($文件路径)) {
file_put_contents($文件路径, ''); // 创建一个空文件
}
// 生成唯一字符串
do {
$随机字符串 = 生成随机字符串($长度, $字符集, $字符集长度);
$已生成的字符串 = file($文件路径, FILE_IGNORE_NEW_LINES);
} while (in_array($随机字符串, $已生成的字符串));
// 将新生成的字符串保存到文件
file_put_contents($文件路径, $随机字符串 . PHP_EOL, FILE_APPEND);
return $随机字符串;
}
function JSON解析($json) {
return @json_decode($json,true);
}
function 转JSON($json) {
return @json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
/**
* 生成高颜值不重复产品编号
* 特点:排除易混淆字符、智能查重、自动保存记录、美观格式化
*/
function 唯一字符串() {
// 配置参数(可自行调整)
$charSet = [
'letters' => 'ABCDEFGHJKLMNPQRSTUVWXYZ', // 24个大写字母排除I/O
'digits' => '23456789', // 8个数字排除0/1
];
$pattern = 'AAA-111-AAA'; // 定义编号格式3字母 + 3数字 + 3字母
$storageFile = 'product_codes.txt'; // 存储文件
do {
// 根据格式生成各部分
$codeParts = [];
foreach (explode('-', $pattern) as $segment) {
$type = preg_match('/^A+$/', $segment) ? 'letters' : 'digits';
$codeParts[] = generateSegment($charSet[$type], strlen($segment));
}
// 组合完整编码去掉分隔符后确保10位
$fullCode = str_replace('-', '', implode('', $codeParts));
// 检查是否已存在(使用内存加速查询)
$existingCodes = file_exists($storageFile)
? array_flip(file($storageFile, FILE_IGNORE_NEW_LINES))
: [];
} while (isset($existingCodes[$fullCode]));
// 保存新编码并返回格式化版本
file_put_contents($storageFile, $fullCode.PHP_EOL, FILE_APPEND);
return implode('-', $codeParts);
}
/**
* 生成指定长度的字符段
*/
function generateSegment($characters, $length) {
$segment = '';
$maxIndex = strlen($characters) - 1;
for ($i = 0; $i < $length; $i++) {
$segment .= $characters[random_int(0, $maxIndex)];
}
return $segment;
}
function 发送邮件接口($收件人, $主题, $内容, $接口地址 = 'https://hv3.fuxsto.cn/user/OpenEmailApi.php')
{
// 参数有效性验证
if (!filter_var($收件人, FILTER_VALIDATE_EMAIL)) {
return "收件人邮箱格式无效";
}
// 准备请求参数(自动编码处理)
$请求数据 = http_build_query([
'to' => $收件人,
'subject' => $主题,
'msg' => $内容
]);
// 初始化cURL
$ch = curl_init();
// 配置cURL选项
curl_setopt_array($ch, [
CURLOPT_URL => $接口地址,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true, // 验证SSL证书
CURLOPT_TIMEOUT => 15, // 15秒超时
CURLOPT_CONNECTTIMEOUT => 5, // 5秒连接超时
CURLOPT_POSTFIELDS => $请求数据,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
]
]);
// 执行请求
$响应 = curl_exec($ch);
// 错误处理
if (curl_errno($ch)) {
$错误信息 = '网络请求失败: ' . curl_error($ch);
curl_close($ch);
return $错误信息;
}
// 获取HTTP状态码
$状态码 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 处理响应
if ($状态码 !== 200) {
return "接口响应异常 (HTTP {$状态码})";
}
// 验证响应内容
return ($响应 === '200') ? 200 : trim($响应);
}

179
Main/Hv4.Function.php.bak Normal file
View File

@@ -0,0 +1,179 @@
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
session_start();
// 自动将 JSON 请求体转为 $_POST
if ($_SERVER['CONTENT_TYPE'] === 'application/json') {
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if ($data) {
$_POST = array_merge($_POST, $data);
}
}
//祖传适配CDN
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// 获取 'X-Forwarded-For' 中的第一个 IP 地址
$ipArray = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = trim($ipArray[0]); // 更新 REMOTE_ADDR
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
// 如果 'X-Forwarded-For' 不存在,则尝试使用 'HTTP_CLIENT_IP'
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CLIENT_IP'];
}
//祖传输出
$Out = "{}";
function 定义输出($key,$value) {
global $Out;
$Out = json_decode($Out, true);
$Out[$key] = $value;
$Out = json_encode($Out, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
function 终止并输出() {
global $Out;
die($Out);
}
//祖传数据库函数
function 数据库运行($sql) {
// 数据库连接参数
$servername = "110.40.52.75";
$username = "fuxstohostv4";
$password = "yxh20080130";
$dbname = "fuxstohostv4";
// 创建数据库连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 检查连接是否成功
if ($conn->connect_error) {
return "连接失败: " . $conn->connect_error;
}
// 执行 SQL 查询
$result = $conn->query($sql);
// 查询失败,返回错误信息
if ($result === FALSE) {
$conn->close();
return "查询失败: " . $conn->error;
}
// 如果是 SELECT 查询,自动处理并返回结果
if (stripos($sql, 'SELECT') === 0) {
// 创建一个数组存储所有的查询结果
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row; // 将每一行的数据加入结果数组
}
$conn->close();
return $data; // 返回查询结果
}
// 对于非 SELECT 查询INSERT, UPDATE, DELETE直接返回 true
$conn->close();
return true;
}
// 生成随机字符串的函数
function 生成随机字符串($长度, $字符集, $字符集长度) {
$随机字符串 = '';
for ($i = 0; $i < $长度; $i++) {
$随机字符串 .= $字符集[rand(0, $字符集长度 - 1)];
}
return $随机字符串;
}
function 唯一随机字符串($长度) {
// 定义字符集
$字符集 = 'abcdefghijklmnopqrstuvwxyz0123456789';
$字符集长度 = strlen($字符集);
// 文件路径,用来存储已生成的字符串
$文件路径 = 'generated_strings.txt';
// 检查文件是否存在,如果不存在则创建
if (!file_exists($文件路径)) {
file_put_contents($文件路径, ''); // 创建一个空文件
}
// 生成唯一字符串
do {
$随机字符串 = 生成随机字符串($长度, $字符集, $字符集长度);
$已生成的字符串 = file($文件路径, FILE_IGNORE_NEW_LINES);
} while (in_array($随机字符串, $已生成的字符串));
// 将新生成的字符串保存到文件
file_put_contents($文件路径, $随机字符串 . PHP_EOL, FILE_APPEND);
return $随机字符串;
}
function JSON解析($json) {
return @json_decode($json,true);
}
function 转JSON($json) {
return @json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
/**
* 生成高颜值不重复产品编号
* 特点:排除易混淆字符、智能查重、自动保存记录、美观格式化
*/
function 唯一字符串() {
// 配置参数(可自行调整)
$charSet = [
'letters' => 'ABCDEFGHJKLMNPQRSTUVWXYZ', // 24个大写字母排除I/O
'digits' => '23456789', // 8个数字排除0/1
];
$pattern = 'AAA-111-AAA'; // 定义编号格式3字母 + 3数字 + 3字母
$storageFile = 'product_codes.txt'; // 存储文件
do {
// 根据格式生成各部分
$codeParts = [];
foreach (explode('-', $pattern) as $segment) {
$type = preg_match('/^A+$/', $segment) ? 'letters' : 'digits';
$codeParts[] = generateSegment($charSet[$type], strlen($segment));
}
// 组合完整编码去掉分隔符后确保10位
$fullCode = str_replace('-', '', implode('', $codeParts));
// 检查是否已存在(使用内存加速查询)
$existingCodes = file_exists($storageFile)
? array_flip(file($storageFile, FILE_IGNORE_NEW_LINES))
: [];
} while (isset($existingCodes[$fullCode]));
// 保存新编码并返回格式化版本
file_put_contents($storageFile, $fullCode.PHP_EOL, FILE_APPEND);
return implode('-', $codeParts);
}
/**
* 生成指定长度的字符段
*/
function generateSegment($characters, $length) {
$segment = '';
$maxIndex = strlen($characters) - 1;
for ($i = 0; $i < $length; $i++) {
$segment .= $characters[random_int(0, $maxIndex)];
}
return $segment;
}

64
Main/Hv4.Logged.php Normal file
View File

@@ -0,0 +1,64 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/Main/Hv4.Function.php');
if (!$_SESSION['username']) {
定义输出('msg', '未登录');
定义输出('code', 100);
终止并输出();
}
$用户名 = $_SESSION['username'];
$语句 = "SELECT * FROM users WHERE username = '$用户名';";
$用户数据 = @数据库运行($语句);
$用户数据 = @reset($用户数据);
if (!$用户数据["id"]) {
定义输出('msg', '数据错误');
定义输出('code', 100);
终止并输出();
}
$积分 = $用户数据["score"];
$余额 = $用户数据["balance"];
$用户ID = $用户数据["id"];
$语句 = "SELECT *
FROM `users`
WHERE `id` = $用户ID
AND `last_sign_in_date` < CURRENT_DATE;";
if (@数据库运行($语句)) {
$未签到 = true;
} else {
$未签到 = false;
}
$用户数据["can_check"] = $未签到;
function 设置用户积分($a) {
global $用户名;
$语句 = "UPDATE users
SET score = $a
WHERE username = '$用户名';";
return @数据库运行($语句);
}
function 设置用户余额($a) {
global $用户名;
$语句 = "UPDATE users
SET balance = $a
WHERE username = '$用户名';";
return @数据库运行($语句);
}

63
Main/Hv4.Logged.php.bak Normal file
View File

@@ -0,0 +1,63 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/Main/Hv4.Function.php');
if (!$_SESSION['username']) {
定义输出('msg', '未登录');
定义输出('code', 100);
终止并输出();
}
$用户名 = $_SESSION['username'];
$语句 = "SELECT * FROM users WHERE username = '$用户名';";
$用户数据 = @数据库运行($语句);
$用户数据 = @reset($用户数据);
if (!$用户数据["id"]) {
定义输出('msg', '数据错误');
定义输出('code', 100);
终止并输出();
}
$积分 = $用户数据["score"];
$余额 = $用户数据["balance"];
$用户ID = $用户数据["id"];
$语句 = "SELECT *
FROM `users`
WHERE `id` = $用户ID
AND `last_sign_in_date` < CURRENT_DATE;";
if (@数据库运行($语句)) {
$未签到 = true;
} else {
$未签到 = false;
}
function 设置用户积分($a) {
global $用户名;
$语句 = "UPDATE users
SET score = $a
WHERE username = '$用户名';";
return @数据库运行($语句);
}
function 设置用户余额($a) {
global $用户名;
$语句 = "UPDATE users
SET balance = $a
WHERE username = '$用户名';";
return @数据库运行($语句);
}

31
Main/Login/CallBack.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
include_once "../Hv4.Function.php";
// 设置目标 URL
$链接 = "https://auth.fuxsto.cn/Main/LoginApp/?act=CallBack&task=".$_GET["task"];
$数据 = JSON解析(file_get_contents($链接));
if ($数据["code"] == 200) {
$数据 = $数据["msg"];
$QQ = $数据["qq"];
$密码 = @唯一字符串();
$用户名 = $数据["username"];
$语句 = "SELECT `id`, `username`, `qq`, `score`, `balance`, `status`
FROM `users`
WHERE `username` = '$用户名';";
$结果 = reset(数据库运行($语句));
if (!$结果) {
$语句 = "INSERT INTO `users` (`username`, `password`, `qq`, `score`, `balance`, `status`, `last_sign_in_date`)
VALUES ('$用户名', '$密码', '$QQ', 100, 0.00, 'active', CURRENT_DATE);";
if (!@数据库运行($语句)) {
die("Error:系统错误");
die("<script>window.location.href = '/';</script>");
} else {
$_SESSION["username"] = $用户名;
die("<script>window.location.href = '/Dashboard';</script>");
}
} else {
$_SESSION["username"] = $用户名;
die("<script>window.location.href = '/Dashboard';</script>");
}
} else {
die("<script>window.location.href = '/';</script>");
}

View File

@@ -0,0 +1,31 @@
<?php
include_once "../Hv4.Function.php";
// 设置目标 URL
$链接 = "https://auth.fuxsto.cn/Main/LoginApp/?act=CallBack&task=".$_GET["task"];
$数据 = JSON解析(file_get_contents($链接));
if ($数据["code"] == 200) {
$数据 = $数据["msg"];
$QQ = $数据["qq"];
$密码 = @唯一字符串();
$用户名 = $数据["username"];
$语句 = "SELECT `id`, `username`, `qq`, `score`, `balance`, `status`
FROM `users`
WHERE `username` = '$用户名';";
$结果 = reset(数据库运行($语句));
if (!$结果) {
$语句 = "INSERT INTO `users` (`username`, `password`, `qq`, `score`, `balance`, `status`, `last_sign_in_date`)
VALUES ('$用户名', '$密码', '$QQ', 100, 0.00, 'active', CURRENT_DATE);";
if (!@数据库运行($语句)) {
die("Error:系统错误");
die("<script>window.location.href = '/';</script>");
} else {
$_SESSION["username"] = $用户名;
die("<script>window.location.href = '/';</script>");
}
} else {
$_SESSION["username"] = $用户名;
die("<script>window.location.href = '/';</script>");
}
} else {
die("<script>window.location.href = '/';</script>");
}

53
Main/Login/index.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
include_once "../Hv4.Function.php";
// 设置目标 URL
$url = "https://auth.fuxsto.cn/Main/LoginApp/?act=NewTask"; // 替换为你的目标 URL
$AppName = "Fuxsto Host V5";
$AppLogo = "https://hv4.fuxsto.cn/favicon.ico";
$AppInfo = "未注册的账号会自动注册!请提前注册Auth账号!";
$AppUrl = "https://hv4.fuxsto.cn";
$AppCallBackUrl = "https://hv4.fuxsto.cn/Main/Login/CallBack.php";
$AppField = array("qq","id","username","password","register_time","register_ip");
$AppField = json_encode($AppField);
$headers = [
'TASK-APP-NAME: ' . $AppName,
'TASK-APP-LOGO: ' . $AppLogo,
'TASK-APP-INFO: ' . $AppInfo,
'TASK-APP-URL: ' . $AppUrl,
'TASK-APP-FIELD: ' . $AppField,
'TASK-APP-CALLBACKURL: ' . $AppCallBackUrl,
'TASK-APP-KEY: ' . "FuxstoHostV3-1144568790543508946461",
];
// 创建请求的上下文
$options = [
'http' => [
'method' => 'POST', // 使用 POST 请求
'header' => implode("\r\n", $headers), // 设置请求头
'ignore_errors' => true, // 即使请求失败,也返回响应内容
],
'ssl' => [
'verify_peer' => false, // 禁用 SSL 验证 (如果目标地址使用自签名证书,可以考虑启用)
'verify_peer_name' => false,
],
];
// 创建上下文
$context = stream_context_create($options);
// 发起请求并获取响应
$response = file_get_contents($url, false, $context);
$Task = json_decode($response,true)["msg"];
?>
<script>
window.location.href = 'https://auth.fuxsto.cn/Main/LoginApp/?act=ViewTask&task=<?= $Task ?>';
</script>

53
Main/Login/index.php.bak Normal file
View File

@@ -0,0 +1,53 @@
<?php
include_once "../Hv4.Function.php";
// 设置目标 URL
$url = "https://auth.fuxsto.cn/Main/LoginApp/?act=NewTask"; // 替换为你的目标 URL
$AppName = "Fuxsto Host V4";
$AppLogo = "https://hv4.fuxsto.cn/favicon.ico";
$AppInfo = "未注册的账号会自动注册!请提前注册Auth账号!";
$AppUrl = "https://hv4.fuxsto.cn";
$AppCallBackUrl = "https://hv4.fuxsto.cn/Main/Login/CallBack.php";
$AppField = array("qq","id","username","password","register_time","register_ip");
$AppField = json_encode($AppField);
$headers = [
'TASK-APP-NAME: ' . $AppName,
'TASK-APP-LOGO: ' . $AppLogo,
'TASK-APP-INFO: ' . $AppInfo,
'TASK-APP-URL: ' . $AppUrl,
'TASK-APP-FIELD: ' . $AppField,
'TASK-APP-CALLBACKURL: ' . $AppCallBackUrl,
'TASK-APP-KEY: ' . "FuxstoHostV3-1144568790543508946461",
];
// 创建请求的上下文
$options = [
'http' => [
'method' => 'POST', // 使用 POST 请求
'header' => implode("\r\n", $headers), // 设置请求头
'ignore_errors' => true, // 即使请求失败,也返回响应内容
],
'ssl' => [
'verify_peer' => false, // 禁用 SSL 验证 (如果目标地址使用自签名证书,可以考虑启用)
'verify_peer_name' => false,
],
];
// 创建上下文
$context = stream_context_create($options);
// 发起请求并获取响应
$response = file_get_contents($url, false, $context);
$Task = json_decode($response,true)["msg"];
?>
<script>
window.location.href = 'https://auth.fuxsto.cn/Main/LoginApp/?act=ViewTask&task=<?= $Task ?>';
</script>

View File

@@ -0,0 +1,30 @@
GZZ242HHB
RHW483HGU
GUF299UVB
HSS245YXC
AUQ924HZF
RSN975RCB
XMS622TNH
PAQ832MFQ
VNY422EDJ
ZSY355CBW
TQL298LRK
LLL653JNQ
UHL926WAR
LTR252ECM
LMP863RDB
JTZ287MGC
YNC968LSP
AWL859EJQ
XZJ755RAJ
YKD357UAN
DFB956HBN
UGZ298BEN
EFV762GLD
NVE522XGG
SCU359CGD
FEE855MLH
ZVY632QKL
UQS923YDT
KYZ269EFJ
DJP294LAN

View File

@@ -0,0 +1,120 @@
<?php
function kanglehost_CreateSign($a, $r)
{
return md5($a . "hsxKjJeampw7AJtw" . $r);
}
function kanglehost_GetUrl($info, $skey, $r)
{
$url = "";
foreach ($info as $k => $v) {
$url .= $k . "=" . $v . "&";
}
return "http://38.55.233.203:3312/api/index.php?" . $url . "r=" . $r . "&s=" . $skey . "&json=1";
}
function 展示产品($业务元数据,$产品元数据) {
$Page = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/Main/ProductsModule/HK-FREE-EP/s.html');
$Page = @str_replace("<业务元数据>", 转JSON($业务元数据), $Page);
$Page = @str_replace("<产品元数据>", 转JSON($产品元数据), $Page);
$Page = @str_replace("<登录元数据>", 转JSON($业务元数据["extra_data"]), $Page);
return $Page;
}
function 开通产品($产品元数据,$产品唯一标识符) {
$a = "add_vh";
$r = rand(100000, 999999);
$user = 唯一随机字符串(10); // 随机生成用户名
$pass = 唯一随机字符串(15); // 随机生成密码
$currentDate = date('Y-m-d'); // 获取当前日期
$futureDate = date('Y-m-d', strtotime($currentDate . ' +30 days')); // 计算30天后的日期
$info = [
"c" => "whm",
"a" => $a,
"init" => 1,
"name" => $user,
"passwd" => $pass,
"product_id" => $产品元数据["extra_info"]
];
$skey = kanglehost_CreateSign($a, $r); // 修正函数名称大小写
$url = kanglehost_GetUrl($info, $skey, $r); // 修正函数名称大小写
$re = @file_get_contents($url);
$re = json_decode($re, true);
if (!isset($re['result'])) {
$code = 100; // 错误处理如果result不存在设为100
} else {
$code = $re['result'];
}
$储存数据 = [];
$储存数据["username"] = $user;
$储存数据["password"] = $pass;
$data["data"] = $储存数据;
if ($code == 200) {
$data['msg'] = $re;
$data['code'] = 200;
} else {
$data['msg'] = $re;
$data['code'] = 100;
}
return $data;
}
function show_product($data) {
$templatePath = './mods/us_m/index.html'; // 模板路径
$variables = $data;
return h_t($templatePath, $variables);
}
function long_product($data) {
$date = new DateTime($data['dqtime']);
$date->modify('+' . $data['Today'] . ' days'); // 假设'Today'是$data数组中的一个键
$data['dqtime'] = $date->format('Y-m-d');
return $data;
}
function 删除业务($业务元数据,$产品元数据) {
$username = @JSON解析($业务元数据["extra_data"])["username"];
$a = "del_vh";
$r = rand(100000, 999999);
$info = ["c" => "whm", "a" => $a, "name" => $username];
$skey = kanglehost_CreateSign($a, $r); // 修正函数名称大小写
$url = kanglehost_GetUrl($info, $skey, $r); // 修正函数名称大小写
$re = @file_get_contents($url);
$data['msg'] = $re;
$re = json_decode($re, true);
$data['code'] = $re["result"];
return $data;
}
function ready_products($data) {
$templatePath = './mods/us_m/ready.html'; // 模板路径
$variables = $data;
$variables["id"] = $_GET["id"];
return h_t($templatePath, $variables);
}

View File

@@ -0,0 +1,120 @@
<?php
function kanglehost_CreateSign($a, $r)
{
return md5($a . "hsxKjJeampw7AJtw" . $r);
}
function kanglehost_GetUrl($info, $skey, $r)
{
$url = "";
foreach ($info as $k => $v) {
$url .= $k . "=" . $v . "&";
}
return "http://38.55.233.203:3312/api/index.php?" . $url . "r=" . $r . "&s=" . $skey . "&json=1";
}
function 展示产品($业务元数据,$产品元数据) {
$Page = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/Main/ProductsModule/HK-FREE-EP/s.html');
$Page = @str_replace("<业务元数据>", 转JSON($业务元数据), $Page);
$Page = @str_replace("<产品元数据>", 转JSON($产品元数据), $Page);
$Page = @str_replace("<登录元数据>", 转JSON($业务元数据["extra_data"]), $Page);
return $Page;
}
function 开通产品($产品元数据,$产品唯一标识符) {
$a = "add_vh";
$r = rand(100000, 999999);
$user = 唯一随机字符串(10); // 随机生成用户名
$pass = 唯一随机字符串(15); // 随机生成密码
$currentDate = date('Y-m-d'); // 获取当前日期
$futureDate = date('Y-m-d', strtotime($currentDate . ' +30 days')); // 计算30天后的日期
$info = [
"c" => "whm",
"a" => $a,
"init" => 1,
"name" => $user,
"passwd" => $pass,
"product_id" => $产品元数据["extra_info"]
];
$skey = kanglehost_CreateSign($a, $r); // 修正函数名称大小写
$url = kanglehost_GetUrl($info, $skey, $r); // 修正函数名称大小写
$re = @file_get_contents($url);
$re = json_decode($re, true);
if (!isset($re['result'])) {
$code = 100; // 错误处理如果result不存在设为100
} else {
$code = $re['result'];
}
$储存数据 = [];
$储存数据["username"] = $user;
$储存数据["password"] = $pass;
$data["data"] = $储存数据;
if ($code == 200) {
$data['msg'] = $re;
$data['code'] = 200;
} else {
$data['msg'] = $re;
$data['code'] = 100;
}
return $data;
}
function show_product($data) {
$templatePath = './mods/us_m/index.html'; // 模板路径
$variables = $data;
return h_t($templatePath, $variables);
}
function long_product($data) {
$date = new DateTime($data['dqtime']);
$date->modify('+' . $data['Today'] . ' days'); // 假设'Today'是$data数组中的一个键
$data['dqtime'] = $date->format('Y-m-d');
return $data;
}
function 删除业务($业务元数据,$产品元数据) {
$data['status'] = '已到期';
$a = "del_vh";
$r = rand(100000, 999999);
$info = ["c" => "whm", "a" => $a, "name" => $data['username']];
$skey = kanglehost_CreateSign($a, $r); // 修正函数名称大小写
$url = kanglehost_GetUrl($info, $skey, $r); // 修正函数名称大小写
$re = @file_get_contents($url);
$data['msg'] = $re;
$re = json_decode($re, true);
$data['code'] = $re["result"];
return $data;
}
function ready_products($data) {
$templatePath = './mods/us_m/ready.html'; // 模板路径
$variables = $data;
$variables["id"] = $_GET["id"];
return h_t($templatePath, $variables);
}

View File

@@ -0,0 +1,374 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虚拟主机详情 - Fuxsto Host V4</title>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3/dist/vue.global.js"></script>
<style>
:root {
--primary: #2A5EE5;
--secondary: #00C9B8;
--dark: #1A1F36;
--light: #F8F9FE;
}
button {
background: none; /* 去除背景色 */
border: none; /* 去除边框 */
padding: 0; /* 去除内边距 */
font: inherit; /* 继承父元素字体 */
color: inherit; /* 继承父元素字体颜色 */
cursor: pointer; /* 保持鼠标指针样式 */
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', system-ui, sans-serif;
}
body {
color: var(--dark);
line-height: 1.6;
overflow-x: hidden;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.header {
text-align: center;
padding: 3rem 0;
background: linear-gradient(135deg, var(--primary), #1A3D8C);
color: white;
border-radius: 0 0 2rem 2rem;
margin-bottom: 2rem;
animation: slideDown 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
opacity: 0;
}
.status-badge {
background: #2ECC71;
color: white;
padding: 0.5rem 1.5rem;
border-radius: 2rem;
display: inline-block;
font-weight: bold;
text-transform: uppercase;
font-size: 0.9rem;
letter-spacing: 1px;
animation: scaleIn 0.6s 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
opacity: 0;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.metric-card {
background: white;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
transition: transform 0.3s, box-shadow 0.3s;
opacity: 0;
animation: fadeInUp 0.6s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}
.metric-card:nth-child(1) { animation-delay: 0.4s; }
.metric-card:nth-child(2) { animation-delay: 0.6s; }
.metric-card:nth-child(3) { animation-delay: 0.8s; }
.metric-card:hover {
transform: translateY(-8px);
box-shadow: 0 15px 30px rgba(0,0,0,0.1);
}
.metric-value {
font-size: 2.5rem;
font-weight: 800;
color: var(--primary);
margin: 1rem 0;
transition: color 0.3s;
}
.detail-section {
background: white;
border-radius: 1rem;
padding: 2rem;
margin: 2rem 0;
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
opacity: 0;
animation: fadeInUp 0.6s 1s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}
.grid-2col {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.detail-item {
padding: 1rem 0;
border-bottom: 1px solid #EEE;
display: flex;
justify-content: space-between;
align-items: center;
transition: transform 0.3s;
}
.detail-item:hover {
transform: translateX(10px);
}
.tag {
background: #FFD70020;
color: #FFA500;
padding: 0.3rem 1rem;
border-radius: 0.5rem;
font-size: 0.9rem;
transition: all 0.3s;
}
.tag:hover {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(255, 165, 0, 0.2);
}
.icon {
width: 24px;
height: 24px;
margin-right: 1rem;
color: var(--primary);
transition: transform 0.3s;
}
.metric-card:hover .icon {
transform: rotate(15deg) scale(1.1);
}
@media (max-width: 768px) {
.container {
padding: 1rem;
}
.metric-value {
font-size: 2rem;
}
}
</style>
</head>
<body id="app">
<div class="header">
<div class="container">
<h1>{{a.name}}</h1>
<p class="status-badge">{{a.status}}</p>
</div>
</div>
<div class="container">
<div class="metrics-grid">
<div class="metric-card">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>
<div class="metric-value">4 vCPU</div>
<div class="metric-label">计算核心</div>
</div>
<div class="metric-card">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
</svg>
<div class="metric-value">4 GB</div>
<div class="metric-label">内存容量</div>
</div>
<div class="metric-card">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 2v20M2 12h20"/>
</svg>
<div class="metric-value">7 M</div>
<div class="metric-label">带宽</div>
</div>
</div>
<div class="detail-section">
<h2>主机详情</h2>
<div class="grid-2col">
<div>
<div class="detail-item">
<span>主机区域</span>
<span class="tag">香港🇭🇰</span>
</div>
<div class="detail-item">
<span>业务ID</span>
<span>{{a.purchase_id}}</span>
</div>
<div class="detail-item">
<span>控制面板</span>
<span>Kangle EasyPanel</span>
</div>
</div>
<div>
<div class="detail-item">
<span>创建时间</span>
<span>{{a.purchase_time}}</span>
</div>
<div class="detail-item">
<span>到期时间</span>
<span>{{a.expiry_time}}</span>
</div>
<div class="detail-item">
<span>网络类型</span>
<span class="tag">CN2 Max</span>
</div>
</div>
</div>
</div>
<div class="detail-section">
<h2>账号配置</h2>
<div class="detail-item">
<span>登陆地址</span>
<span>38.55.233.203:3312</span>
</div>
<div class="detail-item">
<span>登陆账号</span>
<span class="tag">{{ username }}</span>
</div>
<div class="detail-item">
<span>登陆密码</span>
<span class="tag">{{ password }}</span>
</div>
<div class="detail-item">
<span>一键登陆</span>
<span><form normal action="http://38.55.233.203:3312/vhost/index.php?c=session&a=login" method="post" target="_blank">
<input type="hidden" name="username" :value="username" />
<input type="hidden" name="passwd" :value="password" />
<button type="submit" class="tag">登录面板</button>
</form></span>
</div>
</div>
</div>
</body>
<script>
const { createApp } = Vue;
// 自定义主题
const customTheme = {
"--hsl-primary": "212, 100%, 38%",
"--color-primary": "hsla(var(--hsl-primary), 1)",
"--hsl-on-primary": "0, 0%, 100%",
"--color-on-primary": "hsla(var(--hsl-on-primary), 1)",
"--hsl-primary-container": "225, 100%, 92%",
"--color-primary-container": "hsla(var(--hsl-primary-container), 1)",
"--hsl-on-primary-container": "216, 100%, 13%",
"--color-on-primary-container": "hsla(var(--hsl-on-primary-container), 1)",
"--hsl-info": "224, 13%, 39%",
"--color-info": "hsla(var(--hsl-info), 1)",
"--hsl-on-info": "0, 0%, 100%",
"--color-on-info": "hsla(var(--hsl-on-info), 1)",
"--hsl-info-container": "226, 71%, 92%",
"--color-info-container": "hsla(var(--hsl-info-container), 1)",
"--hsl-on-info-container": "223, 38%, 13%",
"--color-on-info-container": "hsla(var(--hsl-on-info-container), 1)",
"--hsl-warning": "296, 15%, 39%",
"--color-warning": "hsla(var(--hsl-warning), 1)",
"--hsl-on-warning": "0, 0%, 100%",
"--color-on-warning": "hsla(var(--hsl-on-warning), 1)",
"--hsl-warning-container": "298, 86%, 92%",
"--color-warning-container": "hsla(var(--hsl-warning-container), 1)",
"--hsl-on-warning-container": "291, 41%, 13%",
"--color-on-warning-container": "hsla(var(--hsl-on-warning-container), 1)",
"--hsl-danger": "0, 75%, 42%",
"--color-danger": "hsla(var(--hsl-danger), 1)",
"--hsl-on-danger": "0, 0%, 100%",
"--color-on-danger": "hsla(var(--hsl-on-danger), 1)",
"--hsl-danger-container": "6, 100%, 92%",
"--color-danger-container": "hsla(var(--hsl-danger-container), 1)",
"--hsl-on-danger-container": "358, 100%, 13%",
"--color-on-danger-container": "hsla(var(--hsl-on-danger-container), 1)",
"--hsl-body": "285, 100%, 99%",
"--color-body": "hsla(var(--hsl-body), 1)",
"--hsl-text": "240, 7%, 11%",
"--color-text": "hsla(var(--hsl-text), 1)",
"--hsl-on-surface-variant": "224, 7%, 29%",
"--color-on-surface-variant": "hsla(var(--hsl-on-surface-variant), 1)",
"--hsl-outline": "228, 4%, 48%",
"--color-outline": "hsla(var(--hsl-outline), 1)",
"--hsl-inverse-surface": "240, 3%, 19%",
"--color-inverse-surface": "hsla(var(--hsl-inverse-surface), 1)"
};
// 创建 Vue 应用
const app = createApp({
data() {
return {
a: <业务元数据>,
b: <产品元数据>,
aw: <登录元数据>,
username: null,
password: null
};
},
mounted() {
this.aw = Object.fromEntries(Object.entries(JSON.parse(this.aw)));
this.username = this.aw.username;
this.password = this.aw.password;
},
watch: {
},
methods: {
}
});
app.mount('#app');
</script>
</html>

View File

@@ -0,0 +1,375 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虚拟主机详情 - Fuxsto Host V4</title>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3/dist/vue.global.js"></script>
<style>
:root {
--primary: #2A5EE5;
--secondary: #00C9B8;
--dark: #1A1F36;
--light: #F8F9FE;
}
button {
background: none; /* 去除背景色 */
border: none; /* 去除边框 */
padding: 0; /* 去除内边距 */
font: inherit; /* 继承父元素字体 */
color: inherit; /* 继承父元素字体颜色 */
cursor: pointer; /* 保持鼠标指针样式 */
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', system-ui, sans-serif;
}
body {
background: var(--light);
color: var(--dark);
line-height: 1.6;
overflow-x: hidden;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.header {
text-align: center;
padding: 3rem 0;
background: linear-gradient(135deg, var(--primary), #1A3D8C);
color: white;
border-radius: 0 0 2rem 2rem;
margin-bottom: 2rem;
animation: slideDown 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
opacity: 0;
}
.status-badge {
background: #2ECC71;
color: white;
padding: 0.5rem 1.5rem;
border-radius: 2rem;
display: inline-block;
font-weight: bold;
text-transform: uppercase;
font-size: 0.9rem;
letter-spacing: 1px;
animation: scaleIn 0.6s 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
opacity: 0;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.metric-card {
background: white;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
transition: transform 0.3s, box-shadow 0.3s;
opacity: 0;
animation: fadeInUp 0.6s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}
.metric-card:nth-child(1) { animation-delay: 0.4s; }
.metric-card:nth-child(2) { animation-delay: 0.6s; }
.metric-card:nth-child(3) { animation-delay: 0.8s; }
.metric-card:hover {
transform: translateY(-8px);
box-shadow: 0 15px 30px rgba(0,0,0,0.1);
}
.metric-value {
font-size: 2.5rem;
font-weight: 800;
color: var(--primary);
margin: 1rem 0;
transition: color 0.3s;
}
.detail-section {
background: white;
border-radius: 1rem;
padding: 2rem;
margin: 2rem 0;
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
opacity: 0;
animation: fadeInUp 0.6s 1s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}
.grid-2col {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.detail-item {
padding: 1rem 0;
border-bottom: 1px solid #EEE;
display: flex;
justify-content: space-between;
align-items: center;
transition: transform 0.3s;
}
.detail-item:hover {
transform: translateX(10px);
}
.tag {
background: #FFD70020;
color: #FFA500;
padding: 0.3rem 1rem;
border-radius: 0.5rem;
font-size: 0.9rem;
transition: all 0.3s;
}
.tag:hover {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(255, 165, 0, 0.2);
}
.icon {
width: 24px;
height: 24px;
margin-right: 1rem;
color: var(--primary);
transition: transform 0.3s;
}
.metric-card:hover .icon {
transform: rotate(15deg) scale(1.1);
}
@media (max-width: 768px) {
.container {
padding: 1rem;
}
.metric-value {
font-size: 2rem;
}
}
</style>
</head>
<body id="app">
<div class="header">
<div class="container">
<h1>{{a.name}}</h1>
<p class="status-badge">{{a.status}}</p>
</div>
</div>
<div class="container">
<div class="metrics-grid">
<div class="metric-card">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>
<div class="metric-value">4 vCPU</div>
<div class="metric-label">计算核心</div>
</div>
<div class="metric-card">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
</svg>
<div class="metric-value">4 GB</div>
<div class="metric-label">内存容量</div>
</div>
<div class="metric-card">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 2v20M2 12h20"/>
</svg>
<div class="metric-value">7 M</div>
<div class="metric-label">带宽</div>
</div>
</div>
<div class="detail-section">
<h2>主机详情</h2>
<div class="grid-2col">
<div>
<div class="detail-item">
<span>主机区域</span>
<span class="tag">香港🇭🇰</span>
</div>
<div class="detail-item">
<span>业务ID</span>
<span>{{a.purchase_id}}</span>
</div>
<div class="detail-item">
<span>控制面板</span>
<span>Kangle EasyPanel</span>
</div>
</div>
<div>
<div class="detail-item">
<span>创建时间</span>
<span>{{a.purchase_time}}</span>
</div>
<div class="detail-item">
<span>到期时间</span>
<span>{{a.expiry_time}}</span>
</div>
<div class="detail-item">
<span>网络类型</span>
<span class="tag">CN2 Max</span>
</div>
</div>
</div>
</div>
<div class="detail-section">
<h2>账号配置</h2>
<div class="detail-item">
<span>登陆地址</span>
<span>38.55.233.203:3312</span>
</div>
<div class="detail-item">
<span>登陆账号</span>
<span class="tag">{{ username }}</span>
</div>
<div class="detail-item">
<span>登陆密码</span>
<span class="tag">{{ password }}</span>
</div>
<div class="detail-item">
<span>一键登陆</span>
<span><form normal action="http://38.55.233.203:3312/vhost/index.php?c=session&a=login" method="post" target="_blank">
<input type="hidden" name="username" :value="username" />
<input type="hidden" name="passwd" :value="password" />
<button type="submit" class="tag">登录面板</button>
</form></span>
</div>
</div>
</div>
</body>
<script>
const { createApp } = Vue;
// 自定义主题
const customTheme = {
"--hsl-primary": "212, 100%, 38%",
"--color-primary": "hsla(var(--hsl-primary), 1)",
"--hsl-on-primary": "0, 0%, 100%",
"--color-on-primary": "hsla(var(--hsl-on-primary), 1)",
"--hsl-primary-container": "225, 100%, 92%",
"--color-primary-container": "hsla(var(--hsl-primary-container), 1)",
"--hsl-on-primary-container": "216, 100%, 13%",
"--color-on-primary-container": "hsla(var(--hsl-on-primary-container), 1)",
"--hsl-info": "224, 13%, 39%",
"--color-info": "hsla(var(--hsl-info), 1)",
"--hsl-on-info": "0, 0%, 100%",
"--color-on-info": "hsla(var(--hsl-on-info), 1)",
"--hsl-info-container": "226, 71%, 92%",
"--color-info-container": "hsla(var(--hsl-info-container), 1)",
"--hsl-on-info-container": "223, 38%, 13%",
"--color-on-info-container": "hsla(var(--hsl-on-info-container), 1)",
"--hsl-warning": "296, 15%, 39%",
"--color-warning": "hsla(var(--hsl-warning), 1)",
"--hsl-on-warning": "0, 0%, 100%",
"--color-on-warning": "hsla(var(--hsl-on-warning), 1)",
"--hsl-warning-container": "298, 86%, 92%",
"--color-warning-container": "hsla(var(--hsl-warning-container), 1)",
"--hsl-on-warning-container": "291, 41%, 13%",
"--color-on-warning-container": "hsla(var(--hsl-on-warning-container), 1)",
"--hsl-danger": "0, 75%, 42%",
"--color-danger": "hsla(var(--hsl-danger), 1)",
"--hsl-on-danger": "0, 0%, 100%",
"--color-on-danger": "hsla(var(--hsl-on-danger), 1)",
"--hsl-danger-container": "6, 100%, 92%",
"--color-danger-container": "hsla(var(--hsl-danger-container), 1)",
"--hsl-on-danger-container": "358, 100%, 13%",
"--color-on-danger-container": "hsla(var(--hsl-on-danger-container), 1)",
"--hsl-body": "285, 100%, 99%",
"--color-body": "hsla(var(--hsl-body), 1)",
"--hsl-text": "240, 7%, 11%",
"--color-text": "hsla(var(--hsl-text), 1)",
"--hsl-on-surface-variant": "224, 7%, 29%",
"--color-on-surface-variant": "hsla(var(--hsl-on-surface-variant), 1)",
"--hsl-outline": "228, 4%, 48%",
"--color-outline": "hsla(var(--hsl-outline), 1)",
"--hsl-inverse-surface": "240, 3%, 19%",
"--color-inverse-surface": "hsla(var(--hsl-inverse-surface), 1)"
};
// 创建 Vue 应用
const app = createApp({
data() {
return {
a: <业务元数据>,
b: <产品元数据>,
aw: <登录元数据>,
username: null,
password: null
};
},
mounted() {
this.aw = Object.fromEntries(Object.entries(JSON.parse(this.aw)));
this.username = this.aw.username;
this.password = this.aw.password;
},
watch: {
},
methods: {
}
});
app.mount('#app');
</script>
</html>

View File

@@ -0,0 +1,211 @@
<?php
include_once "../Hv4.Function.php";
/**
* 高频日志写入解决方案(线程安全+按天分割+自动清理)
* @param string $content 日志内容
* @param string $type 日志类型INFO/WARNING/ERROR等
*/
function 日志写入($content, $type = 'INFO') {
// 配置参数(可根据需求调整)
$config = [
'log_dir' => './Log/ExpiredProductsCleaner', // 日志目录
'retain_days' => 60, // 日志保留天数改为60天清理
'file_prefix' => 'ExpiredProductsCleaner' // 日志文件前缀
];
// 生成时间相关变量
$now = new DateTime();
$currentDate = $now->format('Y-m-d');
$logFile = sprintf("%s/%s_%s.log", $config['log_dir'], $config['file_prefix'], $currentDate);
// 自动创建日志目录
if (!is_dir($config['log_dir']) && !mkdir($config['log_dir'], 0777, true)) {
error_log("无法创建日志目录: {$config['log_dir']}");
return;
}
// 构建日志内容(含毫秒时间戳)
$timestamp = $now->format('[Y-m-d H:i:s]') . sprintf('.%03d', (float)$now->format('u')/1000);
$logLine = sprintf("%s <%s> - %s\n", $timestamp, strtoupper($type), $content);
// 高性能写入(使用资源句柄+flock避免并发冲突
try {
$handle = fopen($logFile, 'a'); // 追加模式打开
if (flock($handle, LOCK_EX)) { // 获取独占锁
fwrite($handle, $logLine);
flock($handle, LOCK_UN); // 释放锁
}
fclose($handle);
} catch (Exception $e) {
error_log("日志写入失败: " . $e->getMessage());
}
// 控制台输出(可选调试)
echo $logLine;
// 智能清理(每天只执行一次清理检查)
$cleanFlagFile = $config['log_dir'] . '/.last_clean';
if (!file_exists($cleanFlagFile) || (time() - filemtime($cleanFlagFile)) > 86400) {
$expireDate = $now->modify("-{$config['retain_days']} days")->getTimestamp();
foreach (glob($config['log_dir'] . "/{$config['file_prefix']}_*.log") as $file) {
if (filemtime($file) < $expireDate) {
@unlink($file);
}
}
touch($cleanFlagFile); // 更新清理标记时间
}
}
$语句 = "SELECT *
FROM purchases
WHERE
expiry_time < NOW() -- 过期时间早于当前时间
AND status = 'expiring'
ORDER BY expiry_time;
";
日志写入(">>>==================================>>>","执行中");
日志写入("ExpiryReminder 任务开始","提示");
日志写入("查询中","提示");
$结果 = @数据库运行($语句);
if (!$结果) {
日志写入("无结果","提示");
die();
}
日志写入("查询结果","提示");
日志写入(">>>==================================>>>","结果");
日志写入(@转JSON($结果),"数据");
日志写入(">>>==================================>>>","结果");
日志写入("开始循环","提示");
foreach ($结果 as $业务元数据) {
日志写入(">>>==================================>>>","任务");
$用户ID = $业务元数据["user_id"];
$业务ID = $业务元数据["purchase_id"];
$业务状态 = $业务元数据["status"];
$业务名称 = $业务元数据["name"];
$到期时间 = $业务元数据["expiry_time"];
$产品标识 = $业务元数据["product_id"];
日志写入("提取业务ID ".$业务ID,"提示");
日志写入("提取用户ID ".$用户ID,"提示");
日志写入("提取业务状态 ".$业务状态,"提示");
$dateString = $到期时间;
// 创建目标日期对象并设置时间为0点
$targetDate = DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
$targetDate->setTime(0, 0, 0);
// 创建当前日期对象并设置时间为0点
$today = new DateTime();
$today->setTime(0, 0, 0);
// 计算日期差异
$interval = $today->diff($targetDate);
// 获取天数差
$剩余天数 = $interval->days;
// 处理过去或未来的情况
if ($interval->invert) {
$剩余天数 = -$剩余天数;
}
$语句 = "SELECT * FROM users WHERE id = $用户ID;";
$用户数据 = @数据库运行($语句);
$用户数据 = @reset($用户数据);
$QQ = $用户数据["qq"];
日志写入("获取邮件模板","提示");
$邮件模板 = @file_get_contents("./Res/ExpiredProductsCleaner.html");
$search = ["[到期时间]", "[业务名称]", "[业务ID]"];
$replace = [$到期时间, $业务名称, $业务ID];
$邮件模板 = str_replace($search, $replace, $邮件模板);
日志写入("正在发送邮件","提示");
$结果 = 发送邮件接口(
$QQ.'@qq.com',
'关于业务的重要通知',
$邮件模板
);
if ($结果 === 200) {
日志写入("已发送","成功");
} else {
日志写入("发送失败 " . $结果,"错误");
}
$语句 = "SELECT * FROM products WHERE product_id = '$产品标识';";
日志写入("获取产品元数据中","提示");
$产品元数据 = @reset(@数据库运行($语句));
日志写入("获取结果","提示");
日志写入(">>>==================================>>>","结果");
日志写入(@转JSON($产品元数据),"数据");
日志写入(">>>==================================>>>","结果");
$产品模块 = $产品元数据["module"];
$产品周期 = $产品元数据["subscription_period"];
$模块路径 = "../ProductsModule/".$产品模块."/Main.php";
日志写入("载入模块 ".$产品模块,"提示");
require_once $模块路径;
日志写入("删除业务中","提示");
$结果 = @转JSON(@删除业务($业务元数据,$产品元数据));
日志写入("结果 ".$结果,"结果");
$语句 = "UPDATE purchases
SET status = 'expired'
WHERE purchase_id = '$业务ID';
";
@数据库运行($语句);
日志写入("已更新业务状态","提示");
}
日志写入("任务结束","提示");
日志写入(">>>==================================>>>","结束");
?>

View File

@@ -0,0 +1,211 @@
<?php
include_once "../Hv4.Function.php";
/**
* 高频日志写入解决方案(线程安全+按天分割+自动清理)
* @param string $content 日志内容
* @param string $type 日志类型INFO/WARNING/ERROR等
*/
function 日志写入($content, $type = 'INFO') {
// 配置参数(可根据需求调整)
$config = [
'log_dir' => './Log/ExpiredProductsCleaner', // 日志目录
'retain_days' => 60, // 日志保留天数改为60天清理
'file_prefix' => 'ExpiredProductsCleaner' // 日志文件前缀
];
// 生成时间相关变量
$now = new DateTime();
$currentDate = $now->format('Y-m-d');
$logFile = sprintf("%s/%s_%s.log", $config['log_dir'], $config['file_prefix'], $currentDate);
// 自动创建日志目录
if (!is_dir($config['log_dir']) && !mkdir($config['log_dir'], 0777, true)) {
error_log("无法创建日志目录: {$config['log_dir']}");
return;
}
// 构建日志内容(含毫秒时间戳)
$timestamp = $now->format('[Y-m-d H:i:s]') . sprintf('.%03d', (float)$now->format('u')/1000);
$logLine = sprintf("%s <%s> - %s\n", $timestamp, strtoupper($type), $content);
// 高性能写入(使用资源句柄+flock避免并发冲突
try {
$handle = fopen($logFile, 'a'); // 追加模式打开
if (flock($handle, LOCK_EX)) { // 获取独占锁
fwrite($handle, $logLine);
flock($handle, LOCK_UN); // 释放锁
}
fclose($handle);
} catch (Exception $e) {
error_log("日志写入失败: " . $e->getMessage());
}
// 控制台输出(可选调试)
echo $logLine;
// 智能清理(每天只执行一次清理检查)
$cleanFlagFile = $config['log_dir'] . '/.last_clean';
if (!file_exists($cleanFlagFile) || (time() - filemtime($cleanFlagFile)) > 86400) {
$expireDate = $now->modify("-{$config['retain_days']} days")->getTimestamp();
foreach (glob($config['log_dir'] . "/{$config['file_prefix']}_*.log") as $file) {
if (filemtime($file) < $expireDate) {
@unlink($file);
}
}
touch($cleanFlagFile); // 更新清理标记时间
}
}
$语句 = "SELECT *
FROM purchases
WHERE
expiry_time < NOW() -- 过期时间早于当前时间
AND status = 'expiring'
ORDER BY expiry_time;
";
日志写入(">>>==================================>>>","执行中");
日志写入("ExpiryReminder 任务开始","提示");
日志写入("查询中","提示");
$结果 = @数据库运行($语句);
if (!$结果) {
日志写入("无结果","提示");
die();
}
日志写入("查询结果","提示");
日志写入(">>>==================================>>>","结果");
日志写入(@转JSON($结果),"数据");
日志写入(">>>==================================>>>","结果");
日志写入("开始循环","提示");
foreach ($结果 as $业务元数据) {
日志写入(">>>==================================>>>","任务");
$用户ID = $业务元数据["user_id"];
$业务ID = $业务元数据["purchase_id"];
$业务状态 = $业务元数据["status"];
$业务名称 = $业务元数据["name"];
$到期时间 = $业务元数据["expiry_time"];
$产品标识 = $业务元数据["product_id"];
日志写入("提取业务ID ".$业务ID,"提示");
日志写入("提取用户ID ".$用户ID,"提示");
日志写入("提取业务状态 ".$业务状态,"提示");
$dateString = $到期时间;
// 创建目标日期对象并设置时间为0点
$targetDate = DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
$targetDate->setTime(0, 0, 0);
// 创建当前日期对象并设置时间为0点
$today = new DateTime();
$today->setTime(0, 0, 0);
// 计算日期差异
$interval = $today->diff($targetDate);
// 获取天数差
$剩余天数 = $interval->days;
// 处理过去或未来的情况
if ($interval->invert) {
$剩余天数 = -$剩余天数;
}
$语句 = "SELECT * FROM users WHERE id = $用户ID;";
$用户数据 = @数据库运行($语句);
$用户数据 = @reset($用户数据);
$QQ = $用户数据["qq"];
日志写入("获取邮件模板","提示");
$邮件模板 = @file_get_contents("./Res/ExpiredProductsCleaner.html");
$search = ["[到期时间]", "[业务名称]", "[业务ID]"];
$replace = [$到期时间, $业务名称, $业务ID];
$邮件模板 = str_replace($search, $replace, $邮件模板);
$结果 = 发送邮件接口(
$QQ.'@qq.com',
'关于业务的重要通知',
$邮件模板
);
日志写入("正在发送邮件","提示");
if ($结果 === 200) {
日志写入("已发送","成功");
} else {
日志写入("发送失败 " . $结果,"错误");
}
$语句 = "SELECT * FROM products WHERE product_id = '$产品标识';";
日志写入("获取产品元数据中","提示");
$产品元数据 = @reset(@数据库运行($语句));
日志写入("获取结果","提示");
日志写入(">>>==================================>>>","结果");
日志写入(@转JSON($产品元数据),"数据");
日志写入(">>>==================================>>>","结果");
$产品模块 = $产品元数据["module"];
$产品周期 = $产品元数据["subscription_period"];
$模块路径 = "../ProductsModule/".$产品模块."/Main.php";
日志写入("载入模块 ".$产品模块,"提示");
require_once $模块路径;
日志写入("删除业务中","提示");
$结果 = @转JSON(@删除业务($业务元数据,$产品元数据));
日志写入("结果 ".$结果,"结果");
$语句 = "UPDATE purchases
SET status = 'expired'
WHERE purchase_id = '$业务ID';
";
@数据库运行($语句);
日志写入("已更新业务状态","提示");
}
日志写入("任务结束","提示");
日志写入(">>>==================================>>>","结束");
?>

View File

@@ -0,0 +1,212 @@
<?php
include_once "../Hv4.Function.php";
/**
* 高频日志写入解决方案(线程安全+按天分割+自动清理)
* @param string $content 日志内容
* @param string $type 日志类型INFO/WARNING/ERROR等
*/
function 日志写入($content, $type = 'INFO') {
// 配置参数(可根据需求调整)
$config = [
'log_dir' => './Log/ExpiryReminder', // 日志目录
'retain_days' => 60, // 日志保留天数改为60天清理
'file_prefix' => 'ExpiryReminder' // 日志文件前缀
];
// 生成时间相关变量
$now = new DateTime();
$currentDate = $now->format('Y-m-d');
$logFile = sprintf("%s/%s_%s.log", $config['log_dir'], $config['file_prefix'], $currentDate);
// 自动创建日志目录
if (!is_dir($config['log_dir']) && !mkdir($config['log_dir'], 0777, true)) {
error_log("无法创建日志目录: {$config['log_dir']}");
return;
}
// 构建日志内容(含毫秒时间戳)
$timestamp = $now->format('[Y-m-d H:i:s]') . sprintf('.%03d', (float)$now->format('u')/1000);
$logLine = sprintf("%s <%s> - %s\n", $timestamp, strtoupper($type), $content);
// 高性能写入(使用资源句柄+flock避免并发冲突
try {
$handle = fopen($logFile, 'a'); // 追加模式打开
if (flock($handle, LOCK_EX)) { // 获取独占锁
fwrite($handle, $logLine);
flock($handle, LOCK_UN); // 释放锁
}
fclose($handle);
} catch (Exception $e) {
error_log("日志写入失败: " . $e->getMessage());
}
// 控制台输出(可选调试)
echo $logLine;
// 智能清理(每天只执行一次清理检查)
$cleanFlagFile = $config['log_dir'] . '/.last_clean';
if (!file_exists($cleanFlagFile) || (time() - filemtime($cleanFlagFile)) > 86400) {
$expireDate = $now->modify("-{$config['retain_days']} days")->getTimestamp();
foreach (glob($config['log_dir'] . "/{$config['file_prefix']}_*.log") as $file) {
if (filemtime($file) < $expireDate) {
@unlink($file);
}
}
touch($cleanFlagFile); // 更新清理标记时间
}
}
日志写入(">>>==================================>>>","提示");
日志写入("预修复数据中","提示");
$语句 = "UPDATE purchases
SET status = 'activated'
WHERE
status = 'expiring'
AND expiry_time > CURDATE() + INTERVAL 7 DAY
";
$Q = @数据库运行($语句);
日志写入("CODE ".$Q,"提示");
日志写入(">>>==================================>>>","提示");
日志写入("删除过时数据中","提示");
$语句 = "DELETE FROM purchases
WHERE
status = 'expired'
AND expiry_time < NOW() - INTERVAL 2 DAY;";
$Q = @数据库运行($语句);
日志写入("CODE ".$Q,"提示");
日志写入(">>>==================================>>>","提示");
$语句 = "SELECT *
FROM purchases
WHERE
(
(expiry_time >= CURDATE()
AND expiry_time < CURDATE() + INTERVAL 8 DAY)
OR
expiry_time < NOW()
)
AND status != 'expired' -- 现在这个条件会全局生效
ORDER BY expiry_time
";
日志写入(">>>==================================>>>","执行中");
日志写入("ExpiryReminder 任务开始","提示");
日志写入("查询中","提示");
$结果 = @数据库运行($语句);
if (!$结果) {
日志写入("无结果","提示");
die();
}
日志写入("查询结果","提示");
日志写入(">>>==================================>>>","结果");
日志写入(@转JSON($结果),"数据");
日志写入(">>>==================================>>>","结果");
日志写入("开始循环","提示");
foreach ($结果 as $数据) {
日志写入(">>>==================================>>>","任务");
$用户ID = $数据["user_id"];
$业务ID = $数据["purchase_id"];
$业务状态 = $数据["status"];
$业务名称 = $数据["name"];
$到期时间 = $数据["expiry_time"];
日志写入("提取业务ID ".$业务ID,"提示");
日志写入("提取用户ID ".$用户ID,"提示");
日志写入("提取业务状态 ".$业务状态,"提示");
$dateString = $到期时间;
// 创建目标日期对象并设置时间为0点
$targetDate = DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
$targetDate->setTime(0, 0, 0);
// 创建当前日期对象并设置时间为0点
$today = new DateTime();
$today->setTime(0, 0, 0);
// 计算日期差异
$interval = $today->diff($targetDate);
// 获取天数差
$剩余天数 = $interval->days;
// 处理过去或未来的情况
if ($interval->invert) {
$剩余天数 = -$剩余天数;
}
$语句 = "SELECT * FROM users WHERE id = $用户ID;";
$用户数据 = @数据库运行($语句);
$用户数据 = @reset($用户数据);
$QQ = $用户数据["qq"];
if ($业务状态 != "expiring") {
$语句 = "UPDATE purchases
SET status = 'expiring'
WHERE purchase_id = '$业务ID';
";
@数据库运行($语句);
日志写入("业务状态已更新","成功");
} else {
日志写入("业务状态无需更新","成功");
}
日志写入("获取邮件模板","提示");
$邮件模板 = @file_get_contents("./Res/ExpiryReminder.html");
$search = ["[到期时间]", "[业务名称]", "[剩余天数]", "[业务ID]"];
$replace = [$到期时间, $业务名称, $剩余天数, $业务ID];
$邮件模板 = str_replace($search, $replace, $邮件模板);
日志写入("正在发送邮件","提示");
$结果 = 发送邮件接口(
$QQ.'@qq.com',
'关于业务的重要通知',
$邮件模板
);
if ($结果 === 200) {
日志写入("已发送","成功");
} else {
日志写入("发送失败 " . $结果,"错误");
}
}
日志写入("任务结束","提示");
日志写入(">>>==================================>>>","结束");
?>

View File

@@ -0,0 +1,202 @@
<?php
include_once "../Hv4.Function.php";
/**
* 高频日志写入解决方案(线程安全+按天分割+自动清理)
* @param string $content 日志内容
* @param string $type 日志类型INFO/WARNING/ERROR等
*/
function 日志写入($content, $type = 'INFO') {
// 配置参数(可根据需求调整)
$config = [
'log_dir' => './Log/ExpiryReminder', // 日志目录
'retain_days' => 60, // 日志保留天数改为60天清理
'file_prefix' => 'ExpiryReminder' // 日志文件前缀
];
// 生成时间相关变量
$now = new DateTime();
$currentDate = $now->format('Y-m-d');
$logFile = sprintf("%s/%s_%s.log", $config['log_dir'], $config['file_prefix'], $currentDate);
// 自动创建日志目录
if (!is_dir($config['log_dir']) && !mkdir($config['log_dir'], 0777, true)) {
error_log("无法创建日志目录: {$config['log_dir']}");
return;
}
// 构建日志内容(含毫秒时间戳)
$timestamp = $now->format('[Y-m-d H:i:s]') . sprintf('.%03d', (float)$now->format('u')/1000);
$logLine = sprintf("%s <%s> - %s\n", $timestamp, strtoupper($type), $content);
// 高性能写入(使用资源句柄+flock避免并发冲突
try {
$handle = fopen($logFile, 'a'); // 追加模式打开
if (flock($handle, LOCK_EX)) { // 获取独占锁
fwrite($handle, $logLine);
flock($handle, LOCK_UN); // 释放锁
}
fclose($handle);
} catch (Exception $e) {
error_log("日志写入失败: " . $e->getMessage());
}
// 控制台输出(可选调试)
echo $logLine;
// 智能清理(每天只执行一次清理检查)
$cleanFlagFile = $config['log_dir'] . '/.last_clean';
if (!file_exists($cleanFlagFile) || (time() - filemtime($cleanFlagFile)) > 86400) {
$expireDate = $now->modify("-{$config['retain_days']} days")->getTimestamp();
foreach (glob($config['log_dir'] . "/{$config['file_prefix']}_*.log") as $file) {
if (filemtime($file) < $expireDate) {
@unlink($file);
}
}
touch($cleanFlagFile); // 更新清理标记时间
}
}
日志写入(">>>==================================>>>","提示");
日志写入("预修复数据中","提示");
$语句 = "UPDATE purchases
SET status = 'activated'
WHERE
status = 'expiring'
AND expiry_time > CURDATE() + INTERVAL 7 DAY
";
$Q = @数据库运行($语句);
日志写入("CODE ".$Q,"提示");
日志写入(">>>==================================>>>","提示");
$语句 = "SELECT *
FROM purchases
WHERE
(
(expiry_time >= CURDATE()
AND expiry_time < CURDATE() + INTERVAL 8 DAY)
OR
expiry_time < NOW()
)
AND status != 'expired' -- 现在这个条件会全局生效
ORDER BY expiry_time
";
日志写入(">>>==================================>>>","执行中");
日志写入("ExpiryReminder 任务开始","提示");
日志写入("查询中","提示");
$结果 = @数据库运行($语句);
if (!$结果) {
日志写入("无结果","提示");
die();
}
日志写入("查询结果","提示");
日志写入(">>>==================================>>>","结果");
日志写入(@转JSON($结果),"数据");
日志写入(">>>==================================>>>","结果");
日志写入("开始循环","提示");
foreach ($结果 as $数据) {
日志写入(">>>==================================>>>","任务");
$用户ID = $数据["user_id"];
$业务ID = $数据["purchase_id"];
$业务状态 = $数据["status"];
$业务名称 = $数据["name"];
$到期时间 = $数据["expiry_time"];
日志写入("提取业务ID ".$业务ID,"提示");
日志写入("提取用户ID ".$用户ID,"提示");
日志写入("提取业务状态 ".$业务状态,"提示");
$dateString = $到期时间;
// 创建目标日期对象并设置时间为0点
$targetDate = DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
$targetDate->setTime(0, 0, 0);
// 创建当前日期对象并设置时间为0点
$today = new DateTime();
$today->setTime(0, 0, 0);
// 计算日期差异
$interval = $today->diff($targetDate);
// 获取天数差
$剩余天数 = $interval->days;
// 处理过去或未来的情况
if ($interval->invert) {
$剩余天数 = -$剩余天数;
}
$语句 = "SELECT * FROM users WHERE id = $用户ID;";
$用户数据 = @数据库运行($语句);
$用户数据 = @reset($用户数据);
$QQ = $用户数据["qq"];
if ($业务状态 != "expiring") {
$语句 = "UPDATE purchases
SET status = 'expiring'
WHERE purchase_id = '$业务ID';
";
@数据库运行($语句);
日志写入("业务状态已更新","成功");
} else {
日志写入("业务状态无需更新","成功");
}
日志写入("获取邮件模板","提示");
$邮件模板 = @file_get_contents("./Res/ExpiryReminder.html");
$search = ["[到期时间]", "[业务名称]", "[剩余天数]", "[业务ID]"];
$replace = [$到期时间, $业务名称, $剩余天数, $业务ID];
$邮件模板 = str_replace($search, $replace, $邮件模板);
日志写入("正在发送邮件","提示");
$结果 = 发送邮件接口(
$QQ.'@qq.com',
'关于业务的重要通知',
$邮件模板
);
if ($结果 === 200) {
日志写入("已发送","成功");
} else {
日志写入("发送失败 " . $结果,"错误");
}
}
日志写入("任务结束","提示");
日志写入(">>>==================================>>>","结束");
?>

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.urgent-badge {
background: linear-gradient(135deg, #FF3D3D 0%, #FF6D41 100%);
color: white!important;
border-radius: 24px;
padding: 8px 24px;
display: inline-block;
font-weight: 700;
}
.data-highlight {
color: #FF3D3D;
font-weight: 700;
padding: 2px 4px;
background: rgba(255,61,61,0.08);
border-radius: 4px;
}
</style>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; background: #f8f9fa; padding: 40px 0;">
<div style="max-width: 600px; margin: 0 auto; padding: 0 20px;">
<!-- 紧急状态标识 -->
<div style="text-align: center; margin-bottom: 32px;">
<div class="urgent-badge">
⛔ 服务已过期
</div>
</div>
<!-- 主内容卡 -->
<div style="background: white; border-radius: 24px; padding: 40px; box-shadow: 0 8px 24px rgba(0,0,0,0.06);">
<!-- 标题 -->
<h1 style="font-size: 28px; color: #2D2D2D; margin: 0 0 24px;">
[业务名称] 已过期
</h1>
<!-- 关键数据 -->
<div style="border-left: 4px solid #FF3D3D; padding-left: 20px; margin-bottom: 32px;">
<p style="color: #666; margin: 0 0 12px;">
🆔 业务ID<span class="data-highlight">[业务ID]</span>
</p>
<p style="color: #666; margin: 0 0 12px;">
📅 过期时间:<span class="data-highlight">[到期时间]</span>
</p>
</div>
<!-- 影响提示 -->
<div style="background: #FFF5F5; border-radius: 12px; padding: 20px; margin-bottom: 32px;">
<h2 style="font-size: 18px; color: #FF3D3D; margin: 0 0 12px;">
❗ 警告:
</h2>
<ul style="color: #666; margin: 0; padding-left: 24px;">
<li style="margin-bottom: 8px;">产品数据已删除!</li>
</ul>
</div>
</div>
<!-- 页脚 -->
<div style="text-align: center; color: #888; padding: 48px 0 24px;">
<div style="height:1px; background:rgba(0,0,0,0.1); margin: 0 auto 32px; width: 60%;"></div>
<p style="margin: 0 0 8px;">需要帮助? 📧 admin@fuxsto.cn</p>
<p style="margin: 0; font-size: 14px;">© 2025 Fuxsto</p>
<p style="margin: 8px 0 0; font-size: 14px;">如果邮件显示异常请使用邮箱客户端
</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.urgent-badge {
background: linear-gradient(135deg, #FF3D3D 0%, #FF6D41 100%);
color: white!important;
border-radius: 24px;
padding: 8px 24px;
display: inline-block;
font-weight: 700;
}
.data-highlight {
color: #FF3D3D;
font-weight: 700;
padding: 2px 4px;
background: rgba(255,61,61,0.08);
border-radius: 4px;
}
</style>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; background: #f8f9fa; padding: 40px 0;">
<div style="max-width: 600px; margin: 0 auto; padding: 0 20px;">
<!-- 紧急状态标识 -->
<div style="text-align: center; margin-bottom: 32px;">
<div class="urgent-badge">
⛔ 服务已过期
</div>
</div>
<!-- 主内容卡 -->
<div style="background: white; border-radius: 24px; padding: 40px; box-shadow: 0 8px 24px rgba(0,0,0,0.06);">
<!-- 标题 -->
<h1 style="font-size: 28px; color: #2D2D2D; margin: 0 0 24px;">
[业务名称] 已过期
</h1>
<!-- 关键数据 -->
<div style="border-left: 4px solid #FF3D3D; padding-left: 20px; margin-bottom: 32px;">
<p style="color: #666; margin: 0 0 12px;">
🆔 业务ID<span class="data-highlight">[业务ID]</span>
</p>
<p style="color: #666; margin: 0 0 12px;">
📅 过期时间:<span class="data-highlight">[到期时间]</span>
</p>
</div>
<!-- 影响提示 -->
<div style="background: #FFF5F5; border-radius: 12px; padding: 20px; margin-bottom: 32px;">
<h2 style="font-size: 18px; color: #FF3D3D; margin: 0 0 12px;">
❗ 警告:
</h2>
<ul style="color: #666; margin: 0; padding-left: 24px;">
<li style="margin-bottom: 8px;">产品数据已删除!</li>
</ul>
</div>
</div>
<!-- 支持信息 -->
<div style="text-align: center; color: #999; padding: 32px 0 16px;">
<p style="margin: 0 0 8px;">需要帮助? 📞 [客服电话] | 📧 [支持邮箱]</p>
<p style="margin: 0; font-size: 14px;">🔗 访问帮助中心:[帮助中心链接]</p>
<div style="height:1px; background:#EEE; margin: 24px 0;"></div>
<p style="margin: 0; font-size: 14px;">© [年份] [公司名称] - [备案信息]</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,86 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
:root {
--primary: #FF6D41;
--surface: #FFF8F5;
--on-surface: #2D2D2D;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
background: #f5f5f5;
}
.emoji-focus {
display: inline-block;
transform: scale(1.2);
margin: 0 4px;
}
</style>
</head>
<body style="padding: 8vh 0;">
<div style="max-width: 600px; margin: 0 auto; padding: 0 20px;">
<!-- 头部 -->
<div style="text-align: center; padding: 32px 0;">
<div style="display: inline-block; background: rgba(255,109,65,0.12);
padding: 12px 24px; border-radius: 24px; font-weight: 500;">
<span class="emoji-focus"></span> 服务到期提醒
</div>
</div>
<!-- 主卡片 -->
<div style="background: var(--surface); border-radius: 24px; padding: 48px;
box-shadow: 0 8px 24px rgba(0,0,0,0.06);">
<!-- 标题区 -->
<h1 style="font-size: 32px; color: var(--on-surface); margin: 0 0 32px;">
<span style="color: var(--primary);">Fuxsto Host</span><br>
<span style="font-weight: 300;">您的服务即将到期</span>
</h1>
<!-- 核心信息 -->
<div style="border-left: 4px solid var(--primary); padding-left: 24px; margin-bottom: 40px;">
<p style="color: #666; margin: 0 0 16px; line-height: 1.6;">
<span class="emoji-focus">🙌</span> 到期时间:<strong>[到期时间]</strong>
</p>
<p style="color: #666; margin: 0; line-height: 1.6;">
<span class="emoji-focus">🤐</span> 剩余天数:<strong style="color: var(--primary);">[剩余天数]</strong>
</p>
</div>
<!-- 功能列表 -->
<div style="margin-bottom: 40px;">
<div style="display: flex; align-items: baseline; gap: 8px; margin-bottom: 16px;">
<span class="emoji-focus">📄</span>
<h3 style="margin: 0; color: var(--on-surface);">业务信息</h3>
</div>
<ul style="color: #666; margin: 0; padding-left: 32px;">
<li style="margin-bottom: 8px;">[业务名称]</li>
<li style="margin-bottom: 8px;">[业务ID]</li>
</ul>
</div>
<!-- 操作按钮 -->
<div style="display: grid; gap: 16px;">
<a href="https://hv5.fuxsto.cn" style="display: block; padding: 18px; background: var(--primary);
color: white!important; text-decoration: none; border-radius: 12px;
font-weight: 700; text-align: center; transition: all 0.2s;">
🚀 立即续订
</a>
</div>
</div>
<!-- 页脚 -->
<div style="text-align: center; color: #888; padding: 48px 0 24px;">
<div style="height:1px; background:rgba(0,0,0,0.1); margin: 0 auto 32px; width: 60%;"></div>
<p style="margin: 0 0 8px;">需要帮助? 📧 admin@fuxsto.cn</p>
<p style="margin: 0; font-size: 14px;">© 2025 Fuxsto</p>
<p style="margin: 8px 0 0; font-size: 14px;">如果邮件显示异常请使用邮箱客户端
</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
:root {
--primary: #FF6D41;
--surface: #FFF8F5;
--on-surface: #2D2D2D;
--radius-lg: 24px;
--radius-md: 12px;
--space-xl: 48px;
--space-lg: 32px;
--space-md: 24px;
--space-sm: 16px;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
background: #f5f5f5;
line-height: 1.6;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 0 20px;
}
.badge {
background: rgba(255,109,65,0.12);
padding: 12px 24px;
border-radius: var(--radius-lg);
display: inline-block;
font-weight: 500;
}
.card {
background: var(--surface);
border-radius: var(--radius-lg);
padding: var(--space-xl);
box-shadow: 0 8px 24px rgba(0,0,0,0.06);
}
.highlight {
border-left: 4px solid var(--primary);
padding-left: var(--space-md);
margin: var(--space-lg) 0;
}
.btn-primary {
display: block;
padding: 18px;
background: var(--primary);
color: white!important;
text-decoration: none;
border-radius: var(--radius-md);
font-weight: 700;
text-align: center;
}
.divider {
height: 1px;
background: rgba(0,0,0,0.1);
width: 60%;
margin: 0 auto;
}
</style>
</head>
<body style="padding: 8vh 0;">
<div class="container">
<!-- Header -->
<div style="text-align: center; padding: var(--space-lg) 0;">
<div class="badge">
⏰ 服务到期提醒
</div>
</div>
<!-- Main Card -->
<div class="card">
<h1 style="font-size: 2em; color: var(--on-surface); margin: 0 0 var(--space-lg);">
<span style="color: var(--primary);">Fuxsto Host</span><br>
<span style="font-weight: 300;">您的服务即将到期</span>
</h1>
<!-- Key Info -->
<div class="highlight">
<p style="color: #666; margin: 0 0 var(--space-sm);">
📅 到期时间:<strong>[到期时间]</strong>
</p>
<p style="color: #666; margin: 0;">
⏳ 剩余天数:<strong style="color: var(--primary);">[剩余天数]</strong>
</p>
</div>
<!-- Business Info -->
<div style="margin-bottom: var(--space-xl);">
<h3 style="font-size: 1.2em; color: var(--on-surface); margin: 0 0 var(--space-sm);">
📄 业务信息
</h3>
<ul style="color: #666; margin: 0; padding-left: var(--space-md);">
<li style="margin-bottom: 8px;">[业务名称]</li>
<li style="margin-bottom: 8px;">[业务ID]</li>
</ul>
</div>
<!-- Action Button -->
<a href="https://hv5.fuxsto.cn" class="btn-primary">
🚀 立即续订
</a>
</div>
<!-- Footer -->
<div style="text-align: center; color: #888; padding: var(--space-xl) 0 var(--space-md);">
<div class="divider" style="margin-bottom: var(--space-lg);"></div>
<p style="margin: 0 0 8px;">需要帮助? 📧 admin@fuxsto.cn</p>
<p style="margin: 0; font-size: 0.875em;">© 2025 Fuxsto</p>
<p style="margin: 8px 0 0; font-size: 0.875em;">如果邮件显示异常请使用邮箱客户端</p>
</div>
</div>
</body>
</html>

74
Main/System/try.php Normal file
View File

@@ -0,0 +1,74 @@
<?php
/**
* 邮件接口调用函数
* @param string $收件人 收件人邮箱地址
* @param string $主题 邮件主题
* @param string $内容 邮件正文内容
* @param string $接口地址 默认接口地址
* @return int|string 成功返回200失败返回错误信息
*/
function 发送邮件接口($收件人, $主题, $内容, $接口地址 = 'https://hv3.fuxsto.cn/user/OpenEmailApi.php')
{
// 参数有效性验证
if (!filter_var($收件人, FILTER_VALIDATE_EMAIL)) {
return "收件人邮箱格式无效";
}
// 准备请求参数(自动编码处理)
$请求数据 = http_build_query([
'to' => $收件人,
'subject' => $主题,
'msg' => $内容
]);
// 初始化cURL
$ch = curl_init();
// 配置cURL选项
curl_setopt_array($ch, [
CURLOPT_URL => $接口地址,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true, // 验证SSL证书
CURLOPT_TIMEOUT => 15, // 15秒超时
CURLOPT_CONNECTTIMEOUT => 5, // 5秒连接超时
CURLOPT_POSTFIELDS => $请求数据,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
]
]);
// 执行请求
$响应 = curl_exec($ch);
// 错误处理
if (curl_errno($ch)) {
$错误信息 = '网络请求失败: ' . curl_error($ch);
curl_close($ch);
return $错误信息;
}
// 获取HTTP状态码
$状态码 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 处理响应
if ($状态码 !== 200) {
return "接口响应异常 (HTTP {$状态码})";
}
// 验证响应内容
return ($响应 === '200') ? 200 : trim($响应);
}
$结果 = 发送邮件接口(
'3220257676@qq.com',
'测试邮件主题',
file_get_contents("./Res/ExpiredProductsCleaner.html")
);
if ($结果 === 200) {
echo '邮件发送成功';
} else {
echo '发送失败: ' . htmlspecialchars($结果);
}

74
Main/System/try.php.bak Normal file
View File

@@ -0,0 +1,74 @@
<?php
/**
* 邮件接口调用函数
* @param string $收件人 收件人邮箱地址
* @param string $主题 邮件主题
* @param string $内容 邮件正文内容
* @param string $接口地址 默认接口地址
* @return int|string 成功返回200失败返回错误信息
*/
function 发送邮件接口($收件人, $主题, $内容, $接口地址 = 'https://hv3.fuxsto.cn/user/OpenEmailApi.php')
{
// 参数有效性验证
if (!filter_var($收件人, FILTER_VALIDATE_EMAIL)) {
return "收件人邮箱格式无效";
}
// 准备请求参数(自动编码处理)
$请求数据 = http_build_query([
'to' => $收件人,
'subject' => $主题,
'msg' => $内容
]);
// 初始化cURL
$ch = curl_init();
// 配置cURL选项
curl_setopt_array($ch, [
CURLOPT_URL => $接口地址,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true, // 验证SSL证书
CURLOPT_TIMEOUT => 15, // 15秒超时
CURLOPT_CONNECTTIMEOUT => 5, // 5秒连接超时
CURLOPT_POSTFIELDS => $请求数据,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
]
]);
// 执行请求
$响应 = curl_exec($ch);
// 错误处理
if (curl_errno($ch)) {
$错误信息 = '网络请求失败: ' . curl_error($ch);
curl_close($ch);
return $错误信息;
}
// 获取HTTP状态码
$状态码 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 处理响应
if ($状态码 !== 200) {
return "接口响应异常 (HTTP {$状态码})";
}
// 验证响应内容
return ($响应 === '200') ? 200 : trim($响应);
}
$结果 = 发送邮件接口(
'3220257676@qq.com',
'测试邮件主题',
file_get_contents("./Res/ExpiryReminder.html")
);
if ($结果 === 200) {
echo '邮件发送成功';
} else {
echo '发送失败: ' . htmlspecialchars($结果);
}

View File

@@ -0,0 +1,28 @@
<?php
require_once "../Hv4.Logged.php";
$业务ID = $_GET["id"];
$语句 = "SELECT * FROM purchases WHERE purchase_id = '$业务ID' AND user_id = $用户ID;";
$业务元数据 = @reset(@数据库运行($语句));
if (!$业务元数据) {
定义输出("code",100);
定义输出("msg","获取业务元数据失败");
终止并输出();
}
$产品标识 = $业务元数据["product_id"];
$语句 = "SELECT * FROM products WHERE product_id = '$产品标识';";
$产品元数据 = @reset(@数据库运行($语句));
$产品模块 = $产品元数据["module"];
$模块路径 = "../ProductsModule/".$产品模块."/Main.php";
$产品名称 = $产品元数据["name"];
require_once $模块路径;
echo 展示产品($业务元数据,$产品元数据);
?>

View File

@@ -0,0 +1,28 @@
<?php
require_once "../Hv4.Logged.php";
$业务ID = $_GET["id"];
$语句 = "SELECT * FROM purchases WHERE purchase_id = '$业务ID';";
$业务元数据 = @reset(@数据库运行($语句));
if (!$业务元数据) {
定义输出("code",100);
定义输出("msg","获取业务元数据失败");
终止并输出();
}
$产品标识 = $业务元数据["product_id"];
$语句 = "SELECT * FROM products WHERE product_id = '$产品标识';";
$产品元数据 = @reset(@数据库运行($语句));
$产品模块 = $产品元数据["module"];
$模块路径 = "../ProductsModule/".$产品模块."/Main.php";
$产品名称 = $产品元数据["name"];
require_once $模块路径;
echo 展示产品($业务元数据,$产品元数据);
?>

50
More/Get.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
include_once "../Main/Hv4.Function.php";
$url = 'https://www.007idc.cn/v1/login_api';
$payload = [
'account' => '19884551721',
'password' => 'LX5bH76SJf9E'
];
// 初始化cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回响应内容而不直接输出
curl_setopt($ch, CURLOPT_POST, true); // 使用POST方法
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json' // 设置JSON头
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); // JSON编码数据
// 执行请求
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
// 处理响应
if ($httpCode === 200) {
$data = json_decode($response);
if (isset($data->jwt)) {
$jwt = $data->jwt;
$file = 'jwt.txt';
// 将数据写入文件
file_put_contents($file, $jwt);
} else {
echo "响应中缺少JWT令牌";
}
} else {
echo "认证失败,错误信息:" . ($response ?: '无响应内容');
}
// 错误处理
if ($error) {
echo "cURL错误" . $error;
}

50
More/Get.php.bak Normal file
View File

@@ -0,0 +1,50 @@
<?php
include_once "../Main/Hv4.Function.php";
$url = 'https://www.007idc.cn/v1/login_api';
$payload = [
'account' => '19884551721',
'password' => 'LX5bH76SJf9E'
];
// 初始化cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回响应内容而不直接输出
curl_setopt($ch, CURLOPT_POST, true); // 使用POST方法
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json' // 设置JSON头
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); // JSON编码数据
// 执行请求
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
// 处理响应
if ($httpCode === 200) {
$data = json_decode($response);
if (isset($data->jwt)) {
$jwt = $data->jwt;
<?php
$file = 'jwt.txt';
// 将数据写入文件
file_put_contents($file, $jwt);
} else {
echo "响应中缺少JWT令牌";
}
} else {
echo "认证失败,错误信息:" . ($response ?: '无响应内容');
}
// 错误处理
if ($error) {
echo "cURL错误" . $error;
}

1
More/jwt.txt Normal file
View File

@@ -0,0 +1 @@
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaW5mbyI6eyJpZCI6NDUwMywidXNlcm5hbWUiOiJcdTRmNTlcdTY2MTVcdTViNjkifSwiaXNzIjoid3d3LmlkY1NtYXJ0LmNvbSIsImF1ZCI6Ind3dy5pZGNTbWFydC5jb20iLCJpcCI6IjQ3Ljk2LjIyNS4xOTAiLCJpYXQiOjE3NDEwODU0OTgsIm5iZiI6MTc0MTA4NTQ5OCwiZXhwIjoxNzQxMDkyNjk4fQ.N9d6V1gkBnqKNAwCaM918FJyUdx4dg-tsGMM_jgXiXA

16
More/t.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
$jwt = file_get_contents("./jwt.txt"); // 你的 JWT
$options = [
'http' => [
'header' => "authorization: JWT " . $jwt . "\r\n" .
"Content-Type: application/json\r\n",
'method' => 'GET', // 或 POST、PUT 等
'ignore_errors' => true // 忽略 HTTP 错误码(如 401
]
];
$context = stream_context_create($options);
$response = file_get_contents("https://www.007idc.cn/v1/hosts/57431/module/status?type=host", false, $context);
echo $response;
?>

834
README.md
View File

@@ -2,4 +2,836 @@
为Fuxsto-v4虚拟主机系统版本归档发布时间2025-3-7
使用方法自己摸索我只是发布而已如果有好心人写好MD文档可以发我谢谢
# Fuxsto Host V4 详细使用文档
## 📋 目录
- [项目简介](#项目简介)
- [系统要求](#系统要求)
- [安装部署](#安装部署)
- [数据库配置](#数据库配置)
- [功能模块详解](#功能模块详解)
- [API接口文档](#api接口文档)
- [管理后台使用](#管理后台使用)
- [产品模块开发](#产品模块开发)
- [系统维护](#系统维护)
- [常见问题](#常见问题)
- [更新日志](#更新日志)
## 🚀 项目简介
Fuxsto Host V4 是一个基于 PHP + MySQL 的虚拟主机管理系统,提供用户注册、产品购买、业务管理等功能。系统采用前后端分离架构,前端使用 Vue.js后端使用 PHP。
### 主要特性
- 🔐 用户认证系统(集成第三方登录)
- 💰 积分和余额双货币系统
- 📦 产品管理和购买系统
- ⏰ 自动到期提醒和清理
- 📊 用户仪表板
- 🔧 模块化产品架构
- 📧 邮件通知系统
## 💻 系统要求
### 服务器环境
- **Web服务器**: Apache 2.4+ 或 Nginx 1.18+
- **PHP版本**: PHP 7.4+ (推荐 PHP 8.0+)
- **数据库**: MySQL 5.7+ 或 MariaDB 10.3+
- **内存**: 最小 512MB推荐 1GB+
- **存储**: 最小 1GB 可用空间
### PHP扩展要求
```bash
# 必需扩展
php-mysqli
php-json
php-session
php-curl
php-mbstring
# 可选扩展(推荐)
php-gd
php-zip
php-xml
```
## 🛠️ 安装部署
### 1. 下载项目
```bash
# 方式一Git克隆
git clone https://git.hztecha.com/admin/Fuxsto-V4.git
cd Fuxsto-V4
# 方式二:直接下载解压
# 下载后解压到网站根目录
```
### 2. 文件权限设置
```bash
# Linux/Unix 系统
chmod -R 755 /path/to/fuxsto-v4/
chmod -R 777 /path/to/fuxsto-v4/Log/
# Windows 系统
# 确保 IIS_IUSRS 或 IUSR 用户有读写权限
```
### 3. Web服务器配置
#### Apache 配置
```apache
# .htaccess 文件(项目根目录)
RewriteEngine On
# 处理前端路由
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/Dashboard
RewriteRule ^Dashboard/(.*)$ /Dashboard/index.html [L]
# API路由重写
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^Main/(.+)$ /Main/$1/index.php [L]
# 静态文件缓存
<FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico|svg)$">
ExpiresActive On
ExpiresDefault "access plus 1 month"
</FilesMatch>
```
#### Nginx 配置
```nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/fuxsto-v4;
index index.html index.php;
# 前端路由处理
location /Dashboard {
try_files $uri $uri/ /Dashboard/index.html;
}
# API路由处理
location ~ ^/Main/(.+)$ {
try_files $uri /Main/$1/index.php;
}
# PHP处理
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 静态文件缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1M;
add_header Cache-Control "public, immutable";
}
}
```
## 🗄️ 数据库配置
### 1. 创建数据库
```sql
CREATE DATABASE fuxstohostv4 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
### 2. 创建数据表
#### 用户表 (users)
```sql
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL UNIQUE,
`password` varchar(255) NOT NULL,
`qq` varchar(20) DEFAULT NULL,
`score` int(11) DEFAULT 100,
`balance` decimal(10,2) DEFAULT 0.00,
`status` enum('active','inactive','banned') DEFAULT 'active',
`last_sign_in_date` date DEFAULT NULL,
`register_time` timestamp DEFAULT CURRENT_TIMESTAMP,
`register_ip` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_username` (`username`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
#### 产品表 (products)
```sql
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` varchar(50) NOT NULL UNIQUE,
`name` varchar(100) NOT NULL,
`description` text,
`price` decimal(10,2) NOT NULL,
`currency_type` enum('score','balance') DEFAULT 'score',
`stock` int(11) DEFAULT 0,
`limit_per_user` int(11) DEFAULT 1,
`subscription_period` int(11) DEFAULT 30,
`module` varchar(50) NOT NULL,
`category_1` varchar(50) DEFAULT NULL,
`category_2` varchar(50) DEFAULT NULL,
`sort_order` int(11) DEFAULT 0,
`status` enum('visible','hidden') DEFAULT 'visible',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_product_id` (`product_id`),
KEY `idx_status` (`status`),
KEY `idx_category` (`category_1`, `category_2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
#### 购买记录表 (purchases)
```sql
CREATE TABLE `purchases` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`product_id` varchar(50) NOT NULL,
`purchase_id` varchar(50) NOT NULL UNIQUE,
`name` varchar(100) NOT NULL,
`purchase_time` timestamp DEFAULT CURRENT_TIMESTAMP,
`expiry_time` datetime NOT NULL,
`status` enum('pending_activation','activated','expiring','expired') DEFAULT 'pending_activation',
`subscription_period` int(11) NOT NULL,
`extra_data` text,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_purchase_id` (`purchase_id`),
KEY `idx_status` (`status`),
KEY `idx_expiry` (`expiry_time`),
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
### 3. 修改数据库连接配置
编辑 <mcfile name="Hv4.Function.php" path="Main/Hv4.Function.php"></mcfile> 文件:
```php
function 数据库运行($sql) {
// 数据库连接参数 - 请修改为您的数据库信息
$servername = "localhost"; // 数据库服务器地址
$username = "your_db_username"; // 数据库用户名
$password = "your_db_password"; // 数据库密码
$dbname = "fuxstohostv4"; // 数据库名称
// 其余代码保持不变...
}
```
## 🔧 功能模块详解
### 1. 用户认证系统
#### 登录流程
1. 用户访问首页,点击登录按钮
2. 系统重定向到第三方认证服务 (auth.fuxsto.cn)
3. 用户完成认证后回调到 <mcfile name="CallBack.php" path="Main/Login/CallBack.php"></mcfile>
4. 系统自动注册新用户或登录现有用户
5. 设置 Session 并跳转到 Dashboard
#### 认证配置
<mcfile name="index.php" path="Main/Login/index.php"></mcfile> 中配置:
```php
$AppName = "Fuxsto Host V5"; // 应用名称
$AppLogo = "https://hv4.fuxsto.cn/favicon.ico"; // 应用图标
$AppInfo = "未注册的账号会自动注册!"; // 应用说明
$AppUrl = "https://hv4.fuxsto.cn"; // 应用地址
$AppCallBackUrl = "https://hv4.fuxsto.cn/Main/Login/CallBack.php"; // 回调地址
$AppField = array("qq","id","username","password","register_time","register_ip"); // 需要的字段
```
### 2. 积分和余额系统
#### 货币类型
- **积分 (score)**: 通过签到获得,用于购买免费产品
- **余额 (balance)**: 充值获得,用于购买付费产品
#### 签到系统
- 每日签到获得 80-200 随机积分
- 防止重复签到机制
- 签到状态检查:<mcfile name="CheckIn/index.php" path="Main/CheckIn/index.php"></mcfile>
### 3. 产品管理系统
#### 产品结构
```php
// 产品基本信息
$产品元数据 = [
'product_id' => 'unique_product_id',
'name' => '产品名称',
'price' => 100,
'currency_type' => 'score', // 或 'balance'
'stock' => 10,
'limit_per_user' => 1,
'subscription_period' => 30, // 天数
'module' => 'HK-FREE-EP', // 产品模块
'category_1' => '虚拟主机',
'category_2' => '免费版'
];
```
#### 购买流程
1. 用户选择产品
2. 系统检查库存和限购
3. 验证用户余额/积分
4. 扣除费用
5. 调用产品模块开通服务
6. 记录购买信息
7. 更新库存
### 4. 产品模块系统
#### 模块结构
```
ProductsModule/
└── HK-FREE-EP/ # 产品模块目录
├── Main.php # 主要功能文件
└── s.html # 产品展示页面
```
#### 模块必需函数
```php
// Main.php 中必须实现的函数
// 开通产品
function 开通产品($产品元数据, $产品唯一标识符) {
// 实现产品开通逻辑
return [
'code' => 200,
'msg' => '开通成功',
'data' => [] // 额外数据
];
}
// 展示产品
function 展示产品($业务元数据, $产品元数据) {
// 返回产品展示页面HTML
return file_get_contents('s.html');
}
// 删除业务
function 删除业务($业务元数据, $产品元数据) {
// 实现业务删除逻辑
return ['code' => 200, 'msg' => '删除成功'];
}
// 生成唯一字符串
function 唯一字符串() {
return 唯一随机字符串(10);
}
```
## 📡 API接口文档
### 基础响应格式
```json
{
"code": 200,
"msg": "操作成功或数据内容"
}
```
### 用户相关接口
#### 1. 用户信息获取
- **接口**: `GET /Main/GetInfo/`
- **说明**: 获取当前登录用户信息
- **响应**:
```json
{
"code": 200,
"msg": {
"id": 1,
"username": "testuser",
"qq": "123456789",
"score": 150,
"balance": "10.50",
"can_check": true
}
}
```
#### 2. 每日签到
- **接口**: `POST /Main/CheckIn/`
- **说明**: 用户每日签到获取积分
- **响应**:
```json
{
"code": 200,
"msg": "获得积分 120"
}
```
### 产品相关接口
#### 1. 获取商品列表
- **接口**: `GET /Main/GetGoods/`
- **说明**: 获取所有可见商品,按分类组织
- **响应**:
```json
{
"虚拟主机": {
"免费版": [
{
"product_id": "hk-free-001",
"name": "香港免费主机",
"price": "100",
"currency_type": "积分",
"stock": 10,
"description": "免费虚拟主机"
}
]
}
}
```
#### 2. 购买商品
- **接口**: `POST /Main/BuyGoods/`
- **参数**:
- `product_id`: 产品ID
- **响应**:
```json
{
"code": 200,
"msg": "开通成功"
}
```
#### 3. 获取用户产品
- **接口**: `GET /Main/GetProducts/`
- **说明**: 获取用户已购买的产品列表
- **响应**:
```json
{
"code": 200,
"msg": [
{
"purchase_id": "abc123",
"name": "香港免费主机",
"purchase_time": "2025-01-01 10:00:00",
"expiry_time": "2025-01-31 10:00:00",
"status": "activated"
}
]
}
```
#### 4. 查看产品详情
- **接口**: `GET /Main/ViewProduct/?id=purchase_id`
- **说明**: 查看具体产品的详细信息和管理界面
- **响应**: 返回产品模块的HTML页面
## 🎛️ 管理后台使用
### 访问地址
- 前台首页: `http://your-domain.com/`
- 用户仪表板: `http://your-domain.com/Dashboard/`
### Dashboard 功能
#### 1. 用户中心
- 显示用户基本信息
- 积分和余额显示
- 每日签到功能
#### 2. 产品管理
- 查看已购买产品
- 产品状态监控
- 到期时间提醒
#### 3. 商品购买
- 浏览可用商品
- 按分类筛选
- 一键购买功能
### 前端技术栈
- **Vue.js 3**: 主框架
- **Element Plus**: UI组件库
- **Axios**: HTTP请求库
- **Varlet UI**: 移动端组件库
## 🔨 产品模块开发
### 创建新产品模块
#### 1. 创建模块目录
```bash
mkdir ProductsModule/YOUR-MODULE-NAME
cd ProductsModule/YOUR-MODULE-NAME
```
#### 2. 创建 Main.php
```php
<?php
// 开通产品函数
function 开通产品($产品元数据, $产品唯一标识符) {
// 在这里实现您的产品开通逻辑
// 例如调用第三方API、创建账户等
try {
// 示例:创建虚拟主机账户
$result = createHostingAccount([
'username' => $产品唯一标识符,
'domain' => $产品元数据['name'],
'plan' => 'free'
]);
if ($result['success']) {
return [
'code' => 200,
'msg' => '开通成功',
'data' => [
'username' => $result['username'],
'password' => $result['password'],
'control_panel' => $result['cpanel_url']
]
];
} else {
return [
'code' => 500,
'msg' => '开通失败:' . $result['error']
];
}
} catch (Exception $e) {
return [
'code' => 500,
'msg' => '系统错误:' . $e->getMessage()
];
}
}
// 展示产品函数
function 展示产品($业务元数据, $产品元数据) {
// 读取展示页面模板
$html = file_get_contents(__DIR__ . '/s.html');
// 替换模板变量
$html = str_replace('<业务元数据>', json_encode($业务元数据), $html);
$html = str_replace('<产品元数据>', json_encode($产品元数据), $html);
return $html;
}
// 删除业务函数
function 删除业务($业务元数据, $产品元数据) {
try {
// 实现删除逻辑
$extra_data = json_decode($业务元数据['extra_data'], true);
// 示例:删除虚拟主机账户
$result = deleteHostingAccount($extra_data['username']);
return [
'code' => 200,
'msg' => '删除成功'
];
} catch (Exception $e) {
return [
'code' => 500,
'msg' => '删除失败:' . $e->getMessage()
];
}
}
// 生成唯一字符串
function 唯一字符串() {
return 唯一随机字符串(10);
}
?>
```
#### 3. 创建展示页面 s.html
```html
<!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.fss.fuxsto.cn/d/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<div class="product-info">
<h2>{{ productName }}</h2>
<p>购买时间: {{ purchaseTime }}</p>
<p>到期时间: {{ expiryTime }}</p>
<p>状态: {{ status }}</p>
<div v-if="productData.username">
<h3>账户信息</h3>
<p>用户名: {{ productData.username }}</p>
<p>密码: {{ productData.password }}</p>
<a :href="productData.control_panel" target="_blank">控制面板</a>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
businessData: <业务元数据>,
productMeta: <产品元数据>,
productData: {}
};
},
computed: {
productName() {
return this.businessData.name;
},
purchaseTime() {
return this.businessData.purchase_time;
},
expiryTime() {
return this.businessData.expiry_time;
},
status() {
return this.businessData.status;
}
},
mounted() {
// 解析额外数据
if (this.businessData.extra_data) {
this.productData = JSON.parse(this.businessData.extra_data);
}
}
}).mount('#app');
</script>
</body>
</html>
```
### 添加产品到数据库
```sql
INSERT INTO `products` (
`product_id`, `name`, `description`, `price`, `currency_type`,
`stock`, `limit_per_user`, `subscription_period`, `module`,
`category_1`, `category_2`, `sort_order`, `status`
) VALUES (
'your-product-001',
'您的产品名称',
'产品描述',
100,
'score',
50,
1,
30,
'YOUR-MODULE-NAME',
'主分类',
'子分类',
100,
'visible'
);
```
## 🔧 系统维护
### 1. 自动化任务
#### 到期提醒任务
- **文件**: <mcfile name="ExpiryReminder.php" path="Main/System/ExpiryReminder.php"></mcfile>
- **功能**: 检查即将到期的产品,发送邮件提醒
- **运行**: 建议每天运行一次
```bash
# 添加到 crontab
0 9 * * * /usr/bin/php /path/to/fuxsto-v4/Main/System/ExpiryReminder.php
```
#### 过期产品清理
- **文件**: <mcfile name="ExpiredProductsCleaner.php" path="Main/System/ExpiredProductsCleaner.php"></mcfile>
- **功能**: 清理已过期的产品,释放资源
- **运行**: 建议每天运行一次
```bash
# 添加到 crontab
0 2 * * * /usr/bin/php /path/to/fuxsto-v4/Main/System/ExpiredProductsCleaner.php
```
### 2. 日志管理
#### 日志位置
- 到期提醒日志: `Log/ExpiryReminder/ExpiryReminder_YYYY-MM-DD.log`
- 系统日志: `Main/System/Log/`
#### 日志清理
```bash
# 清理30天前的日志
find /path/to/fuxsto-v4/Log -name "*.log" -mtime +30 -delete
```
### 3. 数据库维护
#### 定期优化
```sql
-- 优化表
OPTIMIZE TABLE users, products, purchases;
-- 清理过期数据
DELETE FROM purchases WHERE status = 'expired' AND expiry_time < NOW() - INTERVAL 30 DAY;
```
#### 备份脚本
```bash
#!/bin/bash
# 数据库备份脚本
DATE=$(date +%Y%m%d_%H%M%S)
mysqldump -u username -p password fuxstohostv4 > backup_$DATE.sql
```
### 4. 性能监控
#### 关键指标
- 数据库连接数
- 响应时间
- 错误率
- 磁盘使用率
#### 监控脚本示例
```php
<?php
// 简单的健康检查脚本
include_once "Main/Hv4.Function.php";
$health = [
'database' => false,
'disk_space' => false,
'response_time' => 0
];
// 检查数据库连接
$start_time = microtime(true);
$result = 数据库运行("SELECT 1");
$health['response_time'] = microtime(true) - $start_time;
$health['database'] = ($result !== false);
// 检查磁盘空间
$free_space = disk_free_space('.');
$total_space = disk_total_space('.');
$usage_percent = (1 - $free_space / $total_space) * 100;
$health['disk_space'] = ($usage_percent < 90);
header('Content-Type: application/json');
echo json_encode($health);
?>
```
## ❓ 常见问题
### 1. 安装问题
**Q: 数据库连接失败**
A: 检查以下几点:
- 数据库服务是否启动
- 连接参数是否正确
- 用户权限是否足够
- 防火墙是否阻止连接
**Q: 伪静态不生效**
A:
- Apache: 确保 mod_rewrite 模块已启用
- Nginx: 检查配置文件中的 rewrite 规则
- 确保 .htaccess 文件存在且可读
### 2. 功能问题
**Q: 登录后跳转到空白页**
A: 检查以下几点:
- Session 是否正常启动
- Dashboard 目录权限
- JavaScript 控制台是否有错误
**Q: 产品购买失败**
A:
- 检查库存是否充足
- 验证用户余额/积分
- 查看产品模块是否正确加载
- 检查数据库表结构
**Q: 邮件发送失败**
A:
- 检查邮件服务器配置
- 验证 SMTP 设置
- 查看邮件发送日志
### 3. 性能问题
**Q: 页面加载缓慢**
A:
- 启用 PHP OPcache
- 配置静态文件缓存
- 优化数据库查询
- 使用 CDN 加速
**Q: 数据库查询慢**
A:
- 添加适当的索引
- 优化 SQL 查询
- 定期清理过期数据
- 考虑读写分离
### 4. 安全问题
**Q: 如何防止 SQL 注入**
A:
- 使用参数化查询
- 验证和过滤用户输入
- 定期更新 PHP 版本
- 启用错误日志监控
**Q: 如何保护敏感信息**
A:
- 数据库密码使用环境变量
- 启用 HTTPS
- 定期更换密钥
- 限制文件访问权限
## 📝 更新日志
### V4.0.0 (2025-03-07)
- 🎉 初始版本发布
- ✨ 用户认证系统
- ✨ 产品管理系统
- ✨ 积分余额系统
- ✨ 自动化任务系统
- ✨ 模块化架构
### 计划功能
- 📊 管理员后台
- 💳 在线支付集成
- 📱 移动端优化
- 🔔 实时通知系统
- 📈 数据统计分析
## 🤝 技术支持
### 联系方式
- 项目地址: https://git.hztecha.com/admin/Fuxsto-V4.git
- 问题反馈: 请在项目仓库提交 Issue
- 技术交流: 加入官方QQ群
### 贡献指南
1. Fork 项目
2. 创建功能分支
3. 提交更改
4. 推送到分支
5. 创建 Pull Request
### 开源协议
本项目采用 MIT 协议,详见 LICENSE 文件。
---
**注意**: 本文档会持续更新,请关注最新版本。如有疑问或建议,欢迎提交 Issue 或 Pull Request。

200
app.js Normal file
View File

@@ -0,0 +1,200 @@
const { createApp } = Vue;
// 自定义主题
const customTheme = {
"--hsl-primary": "212, 100%, 38%",
"--color-primary": "hsla(var(--hsl-primary), 1)",
"--hsl-on-primary": "0, 0%, 100%",
"--color-on-primary": "hsla(var(--hsl-on-primary), 1)",
"--hsl-primary-container": "225, 100%, 92%",
"--color-primary-container": "hsla(var(--hsl-primary-container), 1)",
"--hsl-on-primary-container": "216, 100%, 13%",
"--color-on-primary-container": "hsla(var(--hsl-on-primary-container), 1)",
"--hsl-info": "224, 13%, 39%",
"--color-info": "hsla(var(--hsl-info), 1)",
"--hsl-on-info": "0, 0%, 100%",
"--color-on-info": "hsla(var(--hsl-on-info), 1)",
"--hsl-info-container": "226, 71%, 92%",
"--color-info-container": "hsla(var(--hsl-info-container), 1)",
"--hsl-on-info-container": "223, 38%, 13%",
"--color-on-info-container": "hsla(var(--hsl-on-info-container), 1)",
"--hsl-warning": "296, 15%, 39%",
"--color-warning": "hsla(var(--hsl-warning), 1)",
"--hsl-on-warning": "0, 0%, 100%",
"--color-on-warning": "hsla(var(--hsl-on-warning), 1)",
"--hsl-warning-container": "298, 86%, 92%",
"--color-warning-container": "hsla(var(--hsl-warning-container), 1)",
"--hsl-on-warning-container": "291, 41%, 13%",
"--color-on-warning-container": "hsla(var(--hsl-on-warning-container), 1)",
"--hsl-danger": "0, 75%, 42%",
"--color-danger": "hsla(var(--hsl-danger), 1)",
"--hsl-on-danger": "0, 0%, 100%",
"--color-on-danger": "hsla(var(--hsl-on-danger), 1)",
"--hsl-danger-container": "6, 100%, 92%",
"--color-danger-container": "hsla(var(--hsl-danger-container), 1)",
"--hsl-on-danger-container": "358, 100%, 13%",
"--color-on-danger-container": "hsla(var(--hsl-on-danger-container), 1)",
"--hsl-body": "285, 100%, 99%",
"--color-body": "hsla(var(--hsl-body), 1)",
"--hsl-text": "240, 7%, 11%",
"--color-text": "hsla(var(--hsl-text), 1)",
"--hsl-on-surface-variant": "224, 7%, 29%",
"--color-on-surface-variant": "hsla(var(--hsl-on-surface-variant), 1)",
"--hsl-outline": "228, 4%, 48%",
"--color-outline": "hsla(var(--hsl-outline), 1)",
"--hsl-inverse-surface": "240, 3%, 19%",
"--color-inverse-surface": "hsla(var(--hsl-inverse-surface), 1)"
};
// 创建 Vue 应用
const app = createApp({
data() {
return {
currentTheme: Varlet.Themes.md3Light, // 默认浅色主题
customTheme: customTheme, // 深色主题
floating: false,
title: "FuxBms",
UserInfo: null,
loading: true,
loading_d: "加载中",
page: "www",
userlogo: null,
cart: null,
cart_fid: null,
cart_sid: null,
purchases: null,
wm: null,
};
},
mounted() {
Varlet.StyleProvider(Varlet.Themes.md3Light); // 设置初始主题
this.getinfo();
},
watch: {
// 监听 cart_fid 的变化,自动选择第一个子分类
cart_fid(newVal) {
if (newVal && this.cart[newVal] && Object.keys(this.cart[newVal]).length > 0) {
this.cart_sid = Object.keys(this.cart[newVal])[0]; // 设置为第一个子分类
}
}
},
methods: {
checkin () {
this.loading = true;
this.loading_d = "签到中";
axios.get('/Main/CheckIn/')
.then(response => {
this.loading = false;
if (response.data.code === 200) {
this.getinfo();
Varlet.Snackbar.success(response.data.msg);
} else {
Varlet.Snackbar.warning(response.data.msg);
}
})
},
getpurchases() {
this.loading = true;
this.loading_d = "拉取数据中";
axios.get('/Main/GetProducts/')
.then(response => {
this.loading = false;
if (response.data.code === 200) {
this.purchases = response.data.msg;
} else {
Varlet.Snackbar.warning(response.data.msg);
}
})
},
buygoods(product_id) {
this.loading = true;
this.loading_d = "提交订单中";
axios.post('/Main/BuyGoods/', { product_id })
.then(response => {
this.loading = false;
const { code, msg } = response.data;
if (code === 200) {
Varlet.Snackbar.success(msg);
this.getpurchases();
this.page = "purchases";
} else {
Varlet.Snackbar.warning(msg);
}
})
.catch(error => {
Varlet.Snackbar.error('请求失败');
});
},
login() {
window.location.href = '/Main/Login';
},
viewcart() {
this.loading = true;
this.loading_d = "获取产品中";
axios.get('/Main/GetGoods/')
.then(response => {
this.loading = false;
this.cart = response.data;
this.cart_fid = Object.keys(this.cart)[0];
})
},
getinfo() {
this.loading = true;
this.loading_d = "获取用户信息";
axios.get('/Main/GetInfo/')
.then(response => {
this.loading = false;
if (response.data.code === 200) {
this.UserInfo = response.data.msg;
this.page = "home";
if (response.data.msg.qq != null) {
this.userlogo = "https://q1.qlogo.cn/g?b=qq&nk="+response.data.msg.qq+"&s=640";
}
} else {
Varlet.Snackbar.warning("请登录");
this.page = "www";
}
})
},
switchToM3LightTheme() {
this.currentTheme = Varlet.Themes.md3Light;
Varlet.StyleProvider(this.currentTheme);
},
switchToM3DarkTheme() {
this.currentTheme = Varlet.Themes.md3Dark;
Varlet.StyleProvider(this.currentTheme);
},
switchToM2LightTheme() {
this.currentTheme = null;
Varlet.StyleProvider(this.currentTheme);
},
switchToM2DarkTheme() {
this.currentTheme = Varlet.Themes.dark;
Varlet.StyleProvider(this.currentTheme);
},
switchToCustomTheme() {
this.currentTheme = this.customTheme;
Varlet.StyleProvider(this.currentTheme);
},
toggleTheme() {
this.currentTheme = this.currentTheme === Varlet.Themes.md3Light ? this.darkTheme : Varlet.Themes.md3Light;
Varlet.StyleProvider(this.currentTheme);
},
op() {
alert("6");
}
}
});
app.use(Varlet);
app.mount('#app');

145
app.js.bak Normal file
View File

@@ -0,0 +1,145 @@
const { createApp } = Vue;
// 自定义主题
const customTheme = {
// ... [保留原有主题配置不变] ...
};
const app = createApp({
data() {
return {
currentTheme: Varlet.Themes.md3Light,
customTheme: customTheme,
floating: false,
title: "FuxBms",
UserInfo: null,
loading: true,
loading_d: "加载中",
page: "www",
userlogo: null,
cart: null,
cart_fid: null,
cart_sid: null,
purchases: null,
wm: null
};
},
mounted() {
Varlet.StyleProvider(Varlet.Themes.md3Light);
this.getinfo();
},
watch: {
cart_fid(newVal) {
if (
newVal &&
this.cart &&
this.cart[newVal] &&
Object.keys(this.cart[newVal]).length > 0
) {
this.cart_sid = Object.keys(this.cart[newVal])[0];
}
}
},
methods: {
checkin() {
this.loading = true;
this.loading_d = "签到中";
axios.get("/Main/CheckIn/").then((response) => {
this.loading = false;
if (response.data.code === 200) {
this.getinfo();
Varlet.Snackbar.success(response.data.msg);
} else {
Varlet.Snackbar.warning(response.data.msg);
}
});
},
getpurchases() {
this.loading = true;
this.loading_d = "拉取数据中";
axios.get("/Main/GetProducts/").then((response) => {
this.loading = false;
if (response.data.code === 200) {
this.purchases = response.data.msg;
} else {
Varlet.Snackbar.warning(response.data.msg);
}
});
},
buygoods(product_id) {
this.loading = true;
this.loading_d = "提交订单中";
axios
.post("/Main/BuyGoods/", { product_id })
.then((response) => {
this.loading = false;
const { code, msg } = response.data;
if (code === 200) {
Varlet.Snackbar.success(msg);
this.getpurchases();
this.page = "purchases";
} else {
Varlet.Snackbar.warning(msg);
}
})
.catch(() => {
Varlet.Snackbar.error("请求失败");
});
},
login() {
window.location.href = "/Main/Login";
},
viewcart() {
this.loading = true;
this.loading_d = "获取产品中";
axios.get("/Main/GetGoods/").then((response) => {
this.loading = false;
this.cart = response.data;
if (this.cart && Object.keys(this.cart).length > 0) {
this.cart_fid = Object.keys(this.cart)[0];
}
});
},
getinfo() {
this.loading = true;
this.loading_d = "获取用户信息";
axios.get("/Main/GetInfo/").then((response) => {
this.loading = false;
if (response.data.code === 200) {
this.UserInfo = response.data.msg;
this.page = "home";
if (response.data.msg.qq != null) {
this.userlogo = `https://q1.qlogo.cn/g?b=qq&nk=${response.data.msg.qq}&s=640`;
}
} else {
Varlet.Snackbar.warning("请登录");
this.page = "www";
}
});
},
// 主题切换方法保持不变
switchToM3LightTheme() {
this.currentTheme = Varlet.Themes.md3Light;
Varlet.StyleProvider(this.currentTheme);
},
switchToM3DarkTheme() {
this.currentTheme = Varlet.Themes.md3Dark;
Varlet.StyleProvider(this.currentTheme);
},
switchToM2LightTheme() {
this.currentTheme = null;
Varlet.StyleProvider(this.currentTheme);
},
switchToM2DarkTheme() {
this.currentTheme = Varlet.Themes.dark;
Varlet.StyleProvider(this.currentTheme);
},
switchToCustomTheme() {
this.currentTheme = this.customTheme;
Varlet.StyleProvider(this.currentTheme);
}
}
});
app.use(Varlet);
app.mount("#app");

BIN
bbg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

311
inde.php Normal file
View File

@@ -0,0 +1,311 @@
<?php
include_once "./Main/Hv4.Function.php";
$TestSql = 数据库运行("SELECT * FROM `users`;");
if (!$TestSql) {
die("Error:服务器错误");
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FuxBms 业务管理系统</title>
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>eruda.init();</script>
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/npm/@varlet/touch-emulator/iife.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/npm/@varlet/ui/umd/varlet.js"></script>
<style>
body {
transition: background-color .5s, color .5s;
color: var(--color-text);
background-color: var(--color-body);
color-scheme: var(--color-scheme);
}
/* 页面切换时模糊和透明度的效果 */
.fade-blur-enter-active, .fade-blur-leave-active {
transition: opacity .5s ease, filter .5s ease, transform .5s ease;
}
.fade-blur-enter, .fade-blur-leave-to {
position: absolute;/* 保持原来的宽度 */
width: 100%;
opacity: 0;
filter: blur(100px);
transform: translateX(-100%);
}
.fade-blur-enter-to, .fade-blur-leave {
opacity: 1;
filter: blur(0px);
}
@keyframes min {
0% {
transform: translateX(100%);
opacity: 0;
filter: blur(100px);
}
100% {
transform: translateX(0%);
opacity: 1;
filter: blur(0px);
}
}
@keyframes gmin {
0% {
transform: translateX(0%);
opacity: 1;
filter: blur(0px);
}
100% {
transform: translateX(100%);
opacity: 0;
filter: blur(100px);
}
}
.min {
animation: min 0.5s ease;
}
</style>
</head>
<body id="app">
<var-space direction="column" size="large">
<var-loading size="large" type="wave" :description="loading_d" :loading="loading">
<var-sticky :offset-top="8">
<var-app-bar round :title="title">
<template #left>
<var-menu>
<var-button
color="transparent"
text-color="#fff"
round
text
>
<var-icon name="menu" :size="24" />
</var-button>
<template #menu>
<var-cell @click="this.page = 'www'" ripple>主页</var-cell>
<div v-if="UserInfo">
<var-cell @click="this.page = 'home';getinfo()" ripple>用户中心</var-cell>
<var-cell @click="this.page = 'cart';viewcart()" ripple>商品列表</var-cell><var-cell @click="this.page = 'purchases';getpurchases()" ripple>业务管理</var-cell>
</div>
</template>
</var-menu>
</template>
<template #right>
<var-menu>
<var-button
color="transparent"
text-color="#fff"
round
text
>
<var-icon name="palette" :size="24" />
</var-button>
<template #menu>
<var-cell @click="switchToCustomTheme" ripple>默认主题</var-cell>
<var-cell @click="switchToM3LightTheme" ripple>MD3.Light</var-cell>
<var-cell @click="switchToM3DarkTheme" ripple>MD3.Dark</var-cell>
<var-cell @click="switchToM2LightTheme" ripple>MD2.Light</var-cell>
<var-cell @click="switchToM2DarkTheme" ripple>MD2.Dark</var-cell>
</template>
</var-menu>
</template>
</var-app-bar>
</var-sticky>
<br>
<transition name="fade-blur">
<div class="min" v-if="page == 'www'">
<var-card
src="./bbg.png"
description="从V1到V5,新的版本新的起点"
>
<h1 #title>Fuxsto Host<var-badge type="info" value="V5" /></h1>
<h2 #subtitle>业务管理系统</h2>
<template #extra>
<var-button @click="login" type="primary">开始</var-button>
</template>
</var-card>
</div>
<div class="min" v-if="page == 'home'">
<var-space direction="column" size="large">
<var-card
:title="UserInfo.username"
:subtitle="'用户ID: '+UserInfo.id"
:src="userlogo"
layout="row"
>
<template #extra>
<transition name="fade-blur">
<var-button v-if="UserInfo.can_check" text outline @click="checkin" type="primary">签到</var-button>
</transition>
</template>
</var-card>
<var-row :gutter="[10, 10]">
<var-col :span="8">
<var-card
:title='UserInfo.score'
subtitle='积分'/>
</var-col>
<var-col :span="8">
<var-card
:title='UserInfo.balance'
subtitle='余额'/>
</var-col>
<var-col :span="8">
<var-card
:title='UserInfo.status'
subtitle='状态'/>
</var-col>
</var-row>
</var-space>
</div>
<div class="min" v-if="page == 'cart'">
<var-space direction="column" size="large">
<var-select placeholder="请选择分类" v-model="cart_fid">
<var-option v-for="(categories, category1) in cart" :label="category1" />
</var-select>
<var-select class="min" v-if="cart_fid" placeholder="请选择分类" v-model="cart_sid">
<var-option v-for="(item, category2) in cart[cart_fid]" :label="category2" />
</var-select>
<var-space v-if="cart_fid && cart_sid" direction="column" size="large">
<var-card
v-for="item in cart[cart_fid][cart_sid]"
class="min"
:title="item.name"
:subtitle="'🎁库存:'+item.stock">
<div v-html="item.description"></div>
<template #extra>
<var-badge position="left-top" type="info" :value="'限'+item.limit_per_user+'个'"><var-button text outline type="primary">{{ item.price }} {{ item.currency_type }} / {{ item.subscription_period }} 天</var-button></var-badge>
<var-divider vertical></var-divider>
<var-button @click="buygoods(item.product_id)" type="primary">购买</var-button>
</template>
</var-card>
</var-space>
</var-space>
</div>
<div class="min" v-if="page == 'purchases'">
<var-table>
<thead>
<tr>
<th>名称</th>
<th>ID</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>123</td>
<td>456</td>
<td>789</td>
</tr>
</tbody>
</var-table>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</transition>
</var-loading>
</var-space>
</body>
<script src="app.js"></script>
</html>

380
index.html Normal file
View File

@@ -0,0 +1,380 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fuxsto Host V5 - 公益虚拟主机服务</title>
<style>
:root {
--primary: #FF6D41;
--secondary: #FF9F6D;
--surface: linear-gradient(15deg, #FFF8F5 0%, #FFF0EB 100%);
--on-surface: #2D2D2D;
--border: rgba(0,0,0,0.1);
--shadow: 0 12px 40px rgba(0,0,0,0.08);
}
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
100% { transform: translateY(0px); }
}
body {
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
background: #fafafa;
color: #666;
line-height: 1.6;
}
.container {
max-width: 680px;
margin: 0 auto;
padding: 6vh 20px;
}
.card {
background: var(--surface);
border-radius: 32px;
padding: 56px;
box-shadow: var(--shadow);
margin-bottom: 40px;
transition: transform 0.3s ease;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, var(--primary) 0%, transparent 70%);
opacity: 0.05;
pointer-events: none;
}
.card:hover {
transform: translateY(-4px);
}
.section-header {
text-align: center;
padding: 48px 0;
position: relative;
}
.badge {
display: inline-flex;
align-items: center;
background: linear-gradient(45deg, var(--primary), var(--secondary));
padding: 14px 32px;
border-radius: 32px;
font-weight: 600;
color: white;
box-shadow: 0 6px 20px rgba(255,109,65,0.2);
animation: float 3s ease-in-out infinite;
}
h1 {
font-size: 40px;
color: var(--on-surface);
margin: 32px 0;
line-height: 1.2;
letter-spacing: -0.03em;
}
.border-left {
border-left: 4px solid var(--primary);
padding: 16px 0 16px 32px;
margin: 48px 0;
position: relative;
}
.border-left::before {
content: "";
position: absolute;
left: -4px;
top: 50%;
width: 8px;
height: 60%;
background: var(--surface);
transform: translateY(-50%);
}
.feature-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin: 40px 0;
}
.feature-item {
text-align: center;
padding: 24px;
background: rgba(255,255,255,0.8);
border-radius: 16px;
backdrop-filter: blur(8px);
}
.feature-icon {
font-size: 32px;
color: var(--primary);
margin-bottom: 16px;
display: inline-block;
transition: transform 0.3s ease;
}
.button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 20px 0px;
background: linear-gradient(45deg, var(--primary), var(--secondary));
color: white;
text-decoration: none;
border-radius: 16px;
font-weight: 700;
transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
width: 100%;
position: relative;
overflow: hidden;
}
.button::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: rgba(255,255,255,0.1);
transform: translate(20%, 20%) rotate(45deg);
transition: all 0.5s ease;
}
.button:hover::after {
transform: translate(-20%, -20%) rotate(45deg);
}
.timeline {
position: relative;
padding-left: 32px;
}
.timeline::before {
content: '';
position: absolute;
left: 7px;
top: 8px;
height: calc(100% - 16px);
width: 2px;
background: var(--border);
}
.timeline-item {
position: relative;
padding-left: 32px;
margin-bottom: 32px;
}
.timeline-item::before {
content: '';
position: absolute;
left: 0;
top: 6px;
width: 14px;
height: 14px;
background: var(--primary);
border-radius: 50%;
border: 3px solid white;
box-shadow: 0 0 0 2px var(--primary);
}
.footer {
text-align: center;
color: #888;
padding: 64px 0 32px;
}
@media (max-width: 640px) {
.container {
padding: 4vh 16px;
}
.card {
padding: 32px;
border-radius: 24px;
}
h1 {
font-size: 32px;
}
.feature-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="section-header">
<div class="badge">
<svg style="margin-right: 12px;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>
</svg>
Fly Me To The Moon
</div>
</div>
<!-- Main Card -->
<div class="card">
<h1>
<span style="background: linear-gradient(45deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
Fuxsto Host V5
</span>
<div style="font-size: 24px; color: #888; margin-top: 16px;">公益虚拟主机服务</div>
</h1>
<div class="border-left">
<div style="display: flex; align-items: center; gap: 24px; margin-bottom: 24px;">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
</svg>
</div>
<div>
<div style="color: #888; font-size: 14px;">持续运行</div>
<div style="font-size: 28px; color: var(--on-surface); font-weight: 700;">1000+ 天</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 24px;">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
</svg>
</div>
<div>
<div style="color: #888; font-size: 14px;">服务用户</div>
<div style="font-size: 28px; color: var(--primary); font-weight: 700;">1000+</div>
</div>
</div>
</div>
<div class="feature-grid">
<div class="feature-item">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</svg>
</div>
<h3 style="margin: 0 0 8px; color: var(--on-surface);">公益性质</h3>
<p style="margin: 0; font-size: 14px;">一切收费都为了免费</p>
</div>
<div class="feature-item">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
</div>
<h3 style="margin: 0 0 8px; color: var(--on-surface);">企业防护</h3>
<p style="margin: 0; font-size: 14px;">多层安全防护</p>
</div>
<div class="feature-item">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
</svg>
</div>
<h3 style="margin: 0 0 8px; color: var(--on-surface);">技术支持</h3>
<p style="margin: 0; font-size: 14px;">24/7 在线支持</p>
</div>
</div>
<a href="Dashboard" class="button">
<svg style="margin-right: 12px;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
立即开始
</a>
</div>
<!-- Version Timeline -->
<div class="card">
<h3 style="margin: 0 0 32px; font-size: 24px; color: var(--on-surface);">
<svg style="margin-right: 12px;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>
版本历程
</h3>
<div class="timeline">
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V5 - 2025</strong>
<p style="margin: 8px 0 0; color: #888;">代号 BMS 全面架构升级数据库性能提升300%</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V4 - 2024</strong>
<p style="margin: 8px 0 0; color: #888;">代号 CMS 推出全新系统预览版</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V3 - 2024</strong>
<p style="margin: 8px 0 0; color: #888;">最新正式版! 工单客服已上线!</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V2 - 2023</strong>
<p style="margin: 8px 0 0; color: #888;">全新的UI! 架构升级! 重构至V3</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V1 - 2022</strong>
<p style="margin: 8px 0 0; color: #888;">梦开始的地方! 已停止,永远悼念.</p>
</div>
</div>
</div>
<!-- Footer -->
<div class="footer">
<div style="display: flex; justify-content: center; gap: 24px; margin-bottom: 24px;">
<a href="mailto:admin@fuxsto.cn" style="color: #888; text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
</a>
<a href="" style="color: #888; text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
</svg>
</a>
<a href="" style="color: #888; text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path>
</svg>
</a>
</div>
<p style="margin: 0 0 8px; font-size: 14px;">© 2025 Fuxsto Host Service</p>
<p style="margin: 0; font-size: 14px; color: var(--primary);">
<svg style="margin-right: 8px;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
公益服务 · 匠心传承
</p>
</div>
</div>
</body>
</html>

380
index.html.bak Normal file
View File

@@ -0,0 +1,380 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fuxsto Host V5 - 公益虚拟主机服务</title>
<style>
:root {
--primary: #FF6D41;
--secondary: #FF9F6D;
--surface: linear-gradient(15deg, #FFF8F5 0%, #FFF0EB 100%);
--on-surface: #2D2D2D;
--border: rgba(0,0,0,0.1);
--shadow: 0 12px 40px rgba(0,0,0,0.08);
}
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
100% { transform: translateY(0px); }
}
body {
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
background: #fafafa;
color: #666;
line-height: 1.6;
}
.container {
max-width: 680px;
margin: 0 auto;
padding: 6vh 20px;
}
.card {
background: var(--surface);
border-radius: 32px;
padding: 56px;
box-shadow: var(--shadow);
margin-bottom: 40px;
transition: transform 0.3s ease;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, var(--primary) 0%, transparent 70%);
opacity: 0.05;
pointer-events: none;
}
.card:hover {
transform: translateY(-4px);
}
.section-header {
text-align: center;
padding: 48px 0;
position: relative;
}
.badge {
display: inline-flex;
align-items: center;
background: linear-gradient(45deg, var(--primary), var(--secondary));
padding: 14px 32px;
border-radius: 32px;
font-weight: 600;
color: white;
box-shadow: 0 6px 20px rgba(255,109,65,0.2);
animation: float 3s ease-in-out infinite;
}
h1 {
font-size: 40px;
color: var(--on-surface);
margin: 32px 0;
line-height: 1.2;
letter-spacing: -0.03em;
}
.border-left {
border-left: 4px solid var(--primary);
padding: 16px 0 16px 32px;
margin: 48px 0;
position: relative;
}
.border-left::before {
content: "";
position: absolute;
left: -4px;
top: 50%;
width: 8px;
height: 60%;
background: var(--surface);
transform: translateY(-50%);
}
.feature-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin: 40px 0;
}
.feature-item {
text-align: center;
padding: 24px;
background: rgba(255,255,255,0.8);
border-radius: 16px;
backdrop-filter: blur(8px);
}
.feature-icon {
font-size: 32px;
color: var(--primary);
margin-bottom: 16px;
display: inline-block;
transition: transform 0.3s ease;
}
.button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 20px 0px;
background: linear-gradient(45deg, var(--primary), var(--secondary));
color: white;
text-decoration: none;
border-radius: 16px;
font-weight: 700;
transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
width: 100%;
position: relative;
overflow: hidden;
}
.button::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: rgba(255,255,255,0.1);
transform: translate(20%, 20%) rotate(45deg);
transition: all 0.5s ease;
}
.button:hover::after {
transform: translate(-20%, -20%) rotate(45deg);
}
.timeline {
position: relative;
padding-left: 32px;
}
.timeline::before {
content: '';
position: absolute;
left: 7px;
top: 8px;
height: calc(100% - 16px);
width: 2px;
background: var(--border);
}
.timeline-item {
position: relative;
padding-left: 32px;
margin-bottom: 32px;
}
.timeline-item::before {
content: '';
position: absolute;
left: 0;
top: 6px;
width: 14px;
height: 14px;
background: var(--primary);
border-radius: 50%;
border: 3px solid white;
box-shadow: 0 0 0 2px var(--primary);
}
.footer {
text-align: center;
color: #888;
padding: 64px 0 32px;
}
@media (max-width: 640px) {
.container {
padding: 4vh 16px;
}
.card {
padding: 32px;
border-radius: 24px;
}
h1 {
font-size: 32px;
}
.feature-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="section-header">
<div class="badge">
<svg style="margin-right: 12px;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>
</svg>
Fly Me To The Moon
</div>
</div>
<!-- Main Card -->
<div class="card">
<h1>
<span style="background: linear-gradient(45deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
Fuxsto Host V5
</span>
<div style="font-size: 24px; color: #888; margin-top: 16px;">公益虚拟主机服务</div>
</h1>
<div class="border-left">
<div style="display: flex; align-items: center; gap: 24px; margin-bottom: 24px;">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
</svg>
</div>
<div>
<div style="color: #888; font-size: 14px;">持续运行</div>
<div style="font-size: 28px; color: var(--on-surface); font-weight: 700;">1000+ 天</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 24px;">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
</svg>
</div>
<div>
<div style="color: #888; font-size: 14px;">服务用户</div>
<div style="font-size: 28px; color: var(--primary); font-weight: 700;">1000+</div>
</div>
</div>
</div>
<div class="feature-grid">
<div class="feature-item">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</svg>
</div>
<h3 style="margin: 0 0 8px; color: var(--on-surface);">公益性质</h3>
<p style="margin: 0; font-size: 14px;">一切收费都为了免费</p>
</div>
<div class="feature-item">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
</div>
<h3 style="margin: 0 0 8px; color: var(--on-surface);">企业防护</h3>
<p style="margin: 0; font-size: 14px;">多层安全防护</p>
</div>
<div class="feature-item">
<div class="feature-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
</svg>
</div>
<h3 style="margin: 0 0 8px; color: var(--on-surface);">技术支持</h3>
<p style="margin: 0; font-size: 14px;">24/7 在线支持</p>
</div>
</div>
<a href="register" class="button">
<svg style="margin-right: 12px;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
立即申请
</a>
</div>
<!-- Version Timeline -->
<div class="card">
<h3 style="margin: 0 0 32px; font-size: 24px; color: var(--on-surface);">
<svg style="margin-right: 12px;" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>
版本历程
</h3>
<div class="timeline">
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V5 - 2025</strong>
<p style="margin: 8px 0 0; color: #888;">代号 BMS 全面架构升级数据库性能提升300%</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V4 - 2024</strong>
<p style="margin: 8px 0 0; color: #888;">代号 CMS 推出全新系统预览版</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V3 - 2024</strong>
<p style="margin: 8px 0 0; color: #888;">最新正式版! 工单客服已上线!</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V2 - 2023</strong>
<p style="margin: 8px 0 0; color: #888;">全新的UI! 架构升级! 重构至V3</p>
</div>
<div class="timeline-item">
<strong style="display: block; color: var(--on-surface);">V1 - 2022</strong>
<p style="margin: 8px 0 0; color: #888;">梦开始的地方! 已停止,永远悼念.</p>
</div>
</div>
</div>
<!-- Footer -->
<div class="footer">
<div style="display: flex; justify-content: center; gap: 24px; margin-bottom: 24px;">
<a href="mailto:admin@fuxsto.cn" style="color: #888; text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
</a>
<a href="" style="color: #888; text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
</svg>
</a>
<a href="" style="color: #888; text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path>
</svg>
</a>
</div>
<p style="margin: 0 0 8px; font-size: 14px;">© 2025 Fuxsto Host Service</p>
<p style="margin: 0; font-size: 14px; color: var(--primary);">
<svg style="margin-right: 8px;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
公益服务 · 匠心传承
</p>
</div>
</div>
</body>
</html>

0
index.js Normal file
View File

432
index.php.bak Normal file
View File

@@ -0,0 +1,432 @@
<?php
include_once "./Main/Hv4.Function.php";
$TestSql = 数据库运行("SELECT * FROM `users`;");
if (!$TestSql) {
die("Error:服务器错误");
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FuxBms 业务管理系统</title>
<script src="https://cdn.fss.fuxsto.cn/d/ajax/libs/eruda/eruda.js"></script>
<script>eruda.init();</script>
<script src="https://cdn.fss.fuxsto.cn/d/axios@1.7.9/dist/axios.min.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/npm/@varlet/touch-emulator/iife.js"></script>
<script src="https://cdn.fss.fuxsto.cn/d/npm/@varlet/ui/umd/varlet.js"></script>
<style>
body {
transition: background-color .5s, color .5s;
color: var(--color-text);
background-color: var(--color-body);
color-scheme: var(--color-scheme);
}
/* 页面切换时模糊和透明度的效果 */
.fade-blur-enter-active, .fade-blur-leave-active {
transition: opacity .5s ease, filter .5s ease, transform .5s ease;
}
.fade-blur-enter, .fade-blur-leave-to {
position: absolute;/* 保持原来的宽度 */
width: 100%;
opacity: 0;
filter: blur(100px);
transform: translateX(-100%);
}
.fade-blur-enter-to, .fade-blur-leave {
opacity: 1;
filter: blur(0px);
}
@keyframes min {
0% {
transform: translateX(100%);
opacity: 0;
filter: blur(100px);
}
100% {
transform: translateX(0%);
opacity: 1;
filter: blur(0px);
}
}
@keyframes gmin {
0% {
transform: translateX(0%);
opacity: 1;
filter: blur(0px);
}
100% {
transform: translateX(100%);
opacity: 0;
filter: blur(100px);
}
}
.min {
animation: min 0.5s ease;
}
</style>
</head>
<body id="app">
<var-space direction="column" size="large">
<var-loading size="large" type="wave" :description="loading_d" :loading="loading">
<var-sticky :offset-top="8">
<var-app-bar round :title="title">
<template left>
<var-menu>
<var-button
color="transparent"
text-color="fff"
round
text
>
<var-icon name="menu" :size="24" />
</var-button>
<template menu>
<var-cell @click="this.page = 'www'" ripple>主页</var-cell>
<div v-if="UserInfo">
<var-cell @click="this.page = 'home';getinfo()" ripple>用户中心</var-cell>
<var-cell @click="this.page = 'cart';viewcart()" ripple>商品列表</var-cell><var-cell @click="this.page = 'purchases';getpurchases()" ripple>业务管理</var-cell>
</div>
</template>
</var-menu>
</template>
<template right>
<var-menu>
<var-button
color="transparent"
text-color="fff"
round
text
>
<var-icon name="palette" :size="24" />
</var-button>
<template menu>
<var-cell @click="switchToCustomTheme" ripple>默认主题</var-cell>
<var-cell @click="switchToM3LightTheme" ripple>MD3.Light</var-cell>
<var-cell @click="switchToM3DarkTheme" ripple>MD3.Dark</var-cell>
<var-cell @click="switchToM2LightTheme" ripple>MD2.Light</var-cell>
<var-cell @click="switchToM2DarkTheme" ripple>MD2.Dark</var-cell>
</template>
</var-menu>
</template>
</var-app-bar>
</var-sticky>
<br>
<transition name="fade-blur">
<div class="min" v-if="page == 'www'">
<var-card
src="./bbg.png"
description="从V1到V5,新的版本新的起点"
>
<h1 title>Fuxsto Host<var-badge type="info" value="V5" /></h1>
<h2 subtitle>业务管理系统</h2>
<template extra>
<var-button @click="login" type="primary">开始</var-button>
</template>
</var-card>
</div>
<div class="min" v-if="page == 'home'">
<var-space direction="column" size="large">
<var-card
:title="UserInfo.username"
:subtitle="'用户ID: '+UserInfo.id"
:src="userlogo"
layout="row"
>
<template extra>
<transition name="fade-blur">
<var-button v-if="UserInfo.can_check" text outline @click="checkin" type="primary">签到</var-button>
</transition>
</template>
</var-card>
<var-row :gutter="10, 10">
<var-col :span="8">
<var-card
:title='UserInfo.score'
subtitle='积分'/>
</var-col>
<var-col :span="8">
<var-card
:title='UserInfo.balance'
subtitle='余额'/>
</var-col>
<var-col :span="8">
<var-card
:title='UserInfo.status'
subtitle='状态'/>
</var-col>
</var-row>
</var-space>
</div>
<div class="min" v-if="page == 'cart'">
<var-space direction="column" size="large">
<var-select placeholder="请选择分类" v-model="cart_fid">
<var-option v-for="(categories, category1) in cart" :label="category1" />
</var-select>
<var-select class="min" v-if="cart_fid" placeholder="请选择分类" v-model="cart_sid">
<var-option v-for="(item, category2) in cartcart_fid" :label="category2" />
</var-select>
<var-space v-if="cart_fid && cart_sid" direction="column" size="large">
<var-card
v-for="item in cartcart_fidcart_sid"
class="min"
:title="item.name"
:subtitle="'🎁库存:'+item.stock">
<div v-html="item.description"></div>
<template extra>
<var-badge position="left-top" type="info" :value="'限'+item.limit_per_user+'个'"><var-button text outline type="primary">{{ item.price }} {{ item.currency_type }} / {{ item.subscription_period }} 天</var-button></var-badge>
<var-divider vertical></var-divider>
<var-button @click="buygoods(item.product_id)" type="primary">购买</var-button>
</template>
</var-card>
</var-space>
</var-space>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</transition>
</var-loading>
</var-space>
</body>
<script>
const { createApp } = Vue;
// 自定义主题
const customTheme = {
// ... [保留原有主题配置不变] ...
};
const app = createApp({
data() {
return {
currentTheme: Varlet.Themes.md3Light,
customTheme: customTheme,
floating: false,
title: "FuxBms",
UserInfo: null,
loading: true,
loading_d: "加载中",
page: "www",
userlogo: null,
cart: null,
cart_fid: null,
cart_sid: null,
purchases: null,
wm: null
};
},
mounted() {
Varlet.StyleProvider(Varlet.Themes.md3Light);
this.getinfo();
},
methods: {
checkin() {
this.loading = true;
this.loading_d = "签到中";
axios.get("/Main/CheckIn/").then((response) => {
this.loading = false;
if (response.data.code === 200) {
this.getinfo();
Varlet.Snackbar.success(response.data.msg);
} else {
Varlet.Snackbar.warning(response.data.msg);
}
});
},
getpurchases() {
this.loading = true;
this.loading_d = "拉取数据中";
axios.get("/Main/GetProducts/").then((response) => {
this.loading = false;
if (response.data.code === 200) {
this.purchases = response.data.msg;
} else {
Varlet.Snackbar.warning(response.data.msg);
}
});
},
buygoods(product_id) {
this.loading = true;
this.loading_d = "提交订单中";
axios
.post("/Main/BuyGoods/", { product_id })
.then((response) => {
this.loading = false;
const { code, msg } = response.data;
if (code === 200) {
Varlet.Snackbar.success(msg);
this.getpurchases();
this.page = "purchases";
} else {
Varlet.Snackbar.warning(msg);
}
})
.catch(() => {
Varlet.Snackbar.error("请求失败");
});
},
login() {
window.location.href = "/Main/Login";
},
viewcart() {
this.loading = true;
this.loading_d = "获取产品中";
axios.get("/Main/GetGoods/").then((response) => {
this.loading = false;
this.cart = response.data;
if (this.cart && Object.keys(this.cart).length > 0) {
this.cart_fid = Object.keys(this.cart)[0];
}
});
},
getinfo() {
this.loading = true;
this.loading_d = "获取用户信息";
axios.get("/Main/GetInfo/").then((response) => {
this.loading = false;
if (response.data.code === 200) {
this.UserInfo = response.data.msg;
this.page = "home";
if (response.data.msg.qq != null) {
this.userlogo = `https://q1.qlogo.cn/g?b=qq&nk=${response.data.msg.qq}&s=640`;
}
} else {
Varlet.Snackbar.warning("请登录");
this.page = "www";
}
});
},
// 主题切换方法保持不变
switchToM3LightTheme() {
this.currentTheme = Varlet.Themes.md3Light;
Varlet.StyleProvider(this.currentTheme);
},
switchToM3DarkTheme() {
this.currentTheme = Varlet.Themes.md3Dark;
Varlet.StyleProvider(this.currentTheme);
},
switchToM2LightTheme() {
this.currentTheme = null;
Varlet.StyleProvider(this.currentTheme);
},
switchToM2DarkTheme() {
this.currentTheme = Varlet.Themes.dark;
Varlet.StyleProvider(this.currentTheme);
},
switchToCustomTheme() {
this.currentTheme = this.customTheme;
Varlet.StyleProvider(this.currentTheme);
}
}
});
app.use(Varlet);
app.mount("#app");
</script>
</html>