Compare commits
5 Commits
641e06e675
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f1f864033d | |||
| 26ee91d519 | |||
| 7bdf159d9c | |||
| cea28f94b9 | |||
| 1f5ac5e0ca |
@@ -0,0 +1 @@
|
||||
o-ZsCxEnxBF8w8EmIGEjyzXwjruHy6xjD7214zN8BBY.rsG2PpWul6LvK6yzgH7E1PafqwKFm6HWKVE8X0AgD-U
|
||||
130
404.html
Normal file
130
404.html
Normal 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
130
404.html.bak
Normal 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>
|
||||
BIN
Dashboard/MaterialIcons-Regular.woff
Normal file
BIN
Dashboard/MaterialIcons-Regular.woff
Normal file
Binary file not shown.
BIN
Dashboard/MaterialIcons-Regular.woff2
Normal file
BIN
Dashboard/MaterialIcons-Regular.woff2
Normal file
Binary file not shown.
1058
Dashboard/app.css
Normal file
1058
Dashboard/app.css
Normal file
File diff suppressed because it is too large
Load Diff
1058
Dashboard/app.css.bak
Normal file
1058
Dashboard/app.css.bak
Normal file
File diff suppressed because it is too large
Load Diff
93
Dashboard/app.js
Normal file
93
Dashboard/app.js
Normal 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
91
Dashboard/app.js.bak
Normal 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
49
Dashboard/b.php
Normal 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
49
Dashboard/bing.html
Normal 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
53
Dashboard/bing.html.bak
Normal 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
49
Dashboard/bing.js
Normal 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
47
Dashboard/bing.js.bak
Normal 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
267
Dashboard/index.html
Normal 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
267
Dashboard/index.html.bak
Normal 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
235
Dashboard/msg.js
Normal 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
235
Dashboard/msg.js.bak
Normal 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
984
Dashboard/t.html
Normal 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
983
Dashboard/t.html.bak
Normal 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>
|
||||
0
Log/ExpiryReminder/.last_clean
Normal file
0
Log/ExpiryReminder/.last_clean
Normal file
3
Log/ExpiryReminder/ExpiryReminder_2025-03-01.log
Normal file
3
Log/ExpiryReminder/ExpiryReminder_2025-03-01.log
Normal 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 <提示> - 查询中
|
||||
63
Main/BuyGoods/generated_strings.txt
Normal file
63
Main/BuyGoods/generated_strings.txt
Normal 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
98
Main/BuyGoods/index.php
Normal 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);
|
||||
|
||||
@数据库运行($语句);
|
||||
终止并输出();
|
||||
93
Main/BuyGoods/index.php.bak
Normal file
93
Main/BuyGoods/index.php.bak
Normal 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);
|
||||
|
||||
@数据库运行($语句);
|
||||
终止并输出();
|
||||
22
Main/BuyGoods/product_codes.txt
Normal file
22
Main/BuyGoods/product_codes.txt
Normal 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
17
Main/CheckIn/index.php
Normal 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);
|
||||
终止并输出();
|
||||
}
|
||||
17
Main/CheckIn/index.php.bak
Normal file
17
Main/CheckIn/index.php.bak
Normal 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
50
Main/GetGoods/index.php
Normal 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);
|
||||
|
||||
|
||||
?>
|
||||
46
Main/GetGoods/index.php.bak
Normal file
46
Main/GetGoods/index.php.bak
Normal 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
5
Main/GetInfo/index.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
include_once "../Hv4.Logged.php";
|
||||
定义输出("msg",$用户数据);
|
||||
定义输出("code",200);
|
||||
终止并输出();
|
||||
5
Main/GetInfo/index.php.bak
Normal file
5
Main/GetInfo/index.php.bak
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
include_once "../Hv4.Logged.php";
|
||||
定义输出("msg",$用户信息);
|
||||
定义输出("code",200);
|
||||
终止并输出();
|
||||
33
Main/GetProducts/index.php
Normal file
33
Main/GetProducts/index.php
Normal 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",$产品元数据);
|
||||
终止并输出();
|
||||
?>
|
||||
26
Main/GetProducts/index.php.bak
Normal file
26
Main/GetProducts/index.php.bak
Normal 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
234
Main/Hv4.Function.php
Normal 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
179
Main/Hv4.Function.php.bak
Normal 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
64
Main/Hv4.Logged.php
Normal 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
63
Main/Hv4.Logged.php.bak
Normal 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
31
Main/Login/CallBack.php
Normal 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>");
|
||||
}
|
||||
31
Main/Login/CallBack.php.bak
Normal file
31
Main/Login/CallBack.php.bak
Normal 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
53
Main/Login/index.php
Normal 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
53
Main/Login/index.php.bak
Normal 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>
|
||||
30
Main/Login/product_codes.txt
Normal file
30
Main/Login/product_codes.txt
Normal 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
|
||||
120
Main/ProductsModule/HK-FREE-EP/Main.php
Normal file
120
Main/ProductsModule/HK-FREE-EP/Main.php
Normal 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);
|
||||
}
|
||||
120
Main/ProductsModule/HK-FREE-EP/Main.php.bak
Normal file
120
Main/ProductsModule/HK-FREE-EP/Main.php.bak
Normal 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);
|
||||
}
|
||||
374
Main/ProductsModule/HK-FREE-EP/s.html
Normal file
374
Main/ProductsModule/HK-FREE-EP/s.html
Normal 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>
|
||||
375
Main/ProductsModule/HK-FREE-EP/s.html.bak
Normal file
375
Main/ProductsModule/HK-FREE-EP/s.html.bak
Normal 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>
|
||||
211
Main/System/ExpiredProductsCleaner.php
Normal file
211
Main/System/ExpiredProductsCleaner.php
Normal 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';
|
||||
";
|
||||
@数据库运行($语句);
|
||||
|
||||
日志写入("已更新业务状态","提示");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
日志写入("任务结束","提示");
|
||||
日志写入(">>>==================================>>>","结束");
|
||||
|
||||
?>
|
||||
211
Main/System/ExpiredProductsCleaner.php.bak
Normal file
211
Main/System/ExpiredProductsCleaner.php.bak
Normal 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';
|
||||
";
|
||||
@数据库运行($语句);
|
||||
|
||||
日志写入("已更新业务状态","提示");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
日志写入("任务结束","提示");
|
||||
日志写入(">>>==================================>>>","结束");
|
||||
|
||||
?>
|
||||
212
Main/System/ExpiryReminder.php
Normal file
212
Main/System/ExpiryReminder.php
Normal 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 {
|
||||
|
||||
日志写入("发送失败 " . $结果,"错误");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
日志写入("任务结束","提示");
|
||||
日志写入(">>>==================================>>>","结束");
|
||||
|
||||
?>
|
||||
202
Main/System/ExpiryReminder.php.bak
Normal file
202
Main/System/ExpiryReminder.php.bak
Normal 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 {
|
||||
|
||||
日志写入("发送失败 " . $结果,"错误");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
日志写入("任务结束","提示");
|
||||
日志写入(">>>==================================>>>","结束");
|
||||
|
||||
?>
|
||||
0
Main/System/Log/.last_clean
Normal file
0
Main/System/Log/.last_clean
Normal file
0
Main/System/Log/ExpiredProductsCleaner/.last_clean
Normal file
0
Main/System/Log/ExpiredProductsCleaner/.last_clean
Normal file
File diff suppressed because it is too large
Load Diff
0
Main/System/Log/ExpiryReminder/.last_clean
Normal file
0
Main/System/Log/ExpiryReminder/.last_clean
Normal file
1069
Main/System/Log/ExpiryReminder/ExpiryReminder_2025-03-01.log
Normal file
1069
Main/System/Log/ExpiryReminder/ExpiryReminder_2025-03-01.log
Normal file
File diff suppressed because it is too large
Load Diff
74
Main/System/Res/ExpiredProductsCleaner.html
Normal file
74
Main/System/Res/ExpiredProductsCleaner.html
Normal 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>
|
||||
73
Main/System/Res/ExpiredProductsCleaner.html.bak
Normal file
73
Main/System/Res/ExpiredProductsCleaner.html.bak
Normal 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>
|
||||
86
Main/System/Res/ExpiryReminder.html
Normal file
86
Main/System/Res/ExpiryReminder.html
Normal 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>
|
||||
117
Main/System/Res/ExpiryReminder.html.bak
Normal file
117
Main/System/Res/ExpiryReminder.html.bak
Normal 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
74
Main/System/try.php
Normal 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
74
Main/System/try.php.bak
Normal 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($结果);
|
||||
}
|
||||
28
Main/ViewProduct/index.php
Normal file
28
Main/ViewProduct/index.php
Normal 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 展示产品($业务元数据,$产品元数据);
|
||||
|
||||
?>
|
||||
28
Main/ViewProduct/index.php.bak
Normal file
28
Main/ViewProduct/index.php.bak
Normal 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
50
More/Get.php
Normal 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
50
More/Get.php.bak
Normal 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
1
More/jwt.txt
Normal file
@@ -0,0 +1 @@
|
||||
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaW5mbyI6eyJpZCI6NDUwMywidXNlcm5hbWUiOiJcdTRmNTlcdTY2MTVcdTViNjkifSwiaXNzIjoid3d3LmlkY1NtYXJ0LmNvbSIsImF1ZCI6Ind3dy5pZGNTbWFydC5jb20iLCJpcCI6IjQ3Ljk2LjIyNS4xOTAiLCJpYXQiOjE3NDEwODU0OTgsIm5iZiI6MTc0MTA4NTQ5OCwiZXhwIjoxNzQxMDkyNjk4fQ.N9d6V1gkBnqKNAwCaM918FJyUdx4dg-tsGMM_jgXiXA
|
||||
16
More/t.php
Normal file
16
More/t.php
Normal 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
834
README.md
@@ -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
200
app.js
Normal 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
145
app.js.bak
Normal 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
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 229 KiB |
311
inde.php
Normal file
311
inde.php
Normal 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
380
index.html
Normal 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
380
index.html.bak
Normal 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>
|
||||
432
index.php.bak
Normal file
432
index.php.bak
Normal 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>
|
||||
Reference in New Issue
Block a user