新增简易的8080面板😊
This commit is contained in:
145
store/@{FutureOSS}/webui/frontend/assets/css/main.css
Normal file
145
store/@{FutureOSS}/webui/frontend/assets/css/main.css
Normal file
@@ -0,0 +1,145 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
background: #f5f5f5;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
/* Dock 侧边栏 */
|
||||
.sidebar {
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
background: #1a1a2e;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 16px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-item i {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
background: rgba(74, 144, 217, 0.2);
|
||||
color: #4a90d9;
|
||||
}
|
||||
|
||||
.nav-item.active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 3px;
|
||||
height: 20px;
|
||||
background: #4a90d9;
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
/* Tooltip on hover */
|
||||
.nav-item:hover::after {
|
||||
content: attr(title);
|
||||
position: absolute;
|
||||
left: 52px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: #fff;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.nav-item:hover:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.settings-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.settings-btn i {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.settings-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 内容区 */
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.content-body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #999;
|
||||
font-size: 15px;
|
||||
}
|
||||
36
store/@{FutureOSS}/webui/frontend/assets/js/main.js
Normal file
36
store/@{FutureOSS}/webui/frontend/assets/js/main.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FutureOSS WebUI 主脚本
|
||||
* 提供基础框架功能
|
||||
*/
|
||||
|
||||
window.WebUI = {
|
||||
/**
|
||||
* 打开设置面板
|
||||
* 其他插件可以扩展此功能
|
||||
*/
|
||||
openSettings: function() {
|
||||
console.log('[WebUI] 打开设置面板');
|
||||
// 设置面板逻辑 - 其他插件可以扩展
|
||||
alert('设置功能需要其他插件支持');
|
||||
},
|
||||
|
||||
/**
|
||||
* 注册导航项
|
||||
* 其他插件可以调用此方法添加导航
|
||||
*/
|
||||
registerNavItem: function(item) {
|
||||
console.log('[WebUI] 注册导航项:', item);
|
||||
// 实际实现需要与后端通信
|
||||
},
|
||||
|
||||
/**
|
||||
* 加载内容到主内容区
|
||||
* 其他插件可以调用此方法加载内容
|
||||
*/
|
||||
loadContent: function(url) {
|
||||
console.log('[WebUI] 加载内容:', url);
|
||||
// 实际实现需要 AJAX 请求
|
||||
}
|
||||
};
|
||||
|
||||
console.log('FutureOSS WebUI 框架已加载');
|
||||
26
store/@{FutureOSS}/webui/frontend/config/config.php
Normal file
26
store/@{FutureOSS}/webui/frontend/config/config.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* FutureOSS WebUI 配置文件
|
||||
*/
|
||||
|
||||
return [
|
||||
// 数据库配置
|
||||
'database' => [
|
||||
'host' => 'localhost',
|
||||
'port' => 3306,
|
||||
'username' => 'root',
|
||||
'password' => '',
|
||||
'dbname' => 'futureoss',
|
||||
'charset' => 'utf8mb4'
|
||||
],
|
||||
|
||||
// 应用配置
|
||||
'app' => [
|
||||
'title' => 'FutureOSS',
|
||||
'theme' => 'dark',
|
||||
'version' => '1.0.0'
|
||||
],
|
||||
|
||||
// 其他插件可以添加配置
|
||||
'plugins' => []
|
||||
];
|
||||
115
store/@{FutureOSS}/webui/frontend/includes/database.php
Normal file
115
store/@{FutureOSS}/webui/frontend/includes/database.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* 数据库连接类
|
||||
* 提供 MySQL 数据库连接和基础查询功能
|
||||
*/
|
||||
|
||||
class Database {
|
||||
private static $instance = null;
|
||||
private $connection;
|
||||
private $config;
|
||||
|
||||
private function __construct() {
|
||||
$configFile = __DIR__ . '/../config/config.php';
|
||||
|
||||
if (!file_exists($configFile)) {
|
||||
throw new Exception('配置文件不存在: ' . $configFile);
|
||||
}
|
||||
|
||||
$this->config = include $configFile;
|
||||
$dbConfig = $this->config['database'];
|
||||
|
||||
try {
|
||||
$dsn = "mysql:host={$dbConfig['host']};port={$dbConfig['port']};dbname={$dbConfig['dbname']};charset={$dbConfig['charset']}";
|
||||
$this->connection = new PDO($dsn, $dbConfig['username'], $dbConfig['password']);
|
||||
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
// 数据库连接失败时记录日志但不阻止页面加载
|
||||
error_log('[FutureOSS WebUI] 数据库连接失败: ' . $e->getMessage());
|
||||
$this->connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例实例
|
||||
*/
|
||||
public static function getInstance() {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库连接
|
||||
*/
|
||||
public function getConnection() {
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据库是否可用
|
||||
*/
|
||||
public function isConnected() {
|
||||
return $this->connection !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行查询
|
||||
*/
|
||||
public function query($sql, $params = []) {
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $this->connection->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
return $stmt;
|
||||
} catch (PDOException $e) {
|
||||
error_log('[FutureOSS WebUI] 数据库查询错误: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有结果
|
||||
*/
|
||||
public function fetchAll($sql, $params = []) {
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt ? $stmt->fetchAll() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条结果
|
||||
*/
|
||||
public function fetchOne($sql, $params = []) {
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt ? $stmt->fetch() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据并返回 ID
|
||||
*/
|
||||
public function insert($sql, $params = []) {
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt ? $this->connection->lastInsertId() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 防止 SQL 注入
|
||||
*/
|
||||
public function escape($value) {
|
||||
if (!$this->isConnected()) {
|
||||
return addslashes($value);
|
||||
}
|
||||
return $this->connection->quote($value);
|
||||
}
|
||||
|
||||
// 防止克隆
|
||||
private function __clone() {}
|
||||
public function __wakeup() {
|
||||
throw new Exception("Cannot unserialize singleton");
|
||||
}
|
||||
}
|
||||
17
store/@{FutureOSS}/webui/frontend/views/dashboard.php
Normal file
17
store/@{FutureOSS}/webui/frontend/views/dashboard.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* 仪表盘页面视图
|
||||
*/
|
||||
|
||||
$pageTitle = 'FutureOSS - 仪表盘';
|
||||
$currentPage = 'dashboard';
|
||||
|
||||
// 内容区直接包含仪表盘内容
|
||||
if (isset($dashboardContent)) {
|
||||
$content = $dashboardContent;
|
||||
} else {
|
||||
$content = '<div class="empty-state"><p>仪表盘内容加载中...</p></div>';
|
||||
}
|
||||
|
||||
// 复用 layout
|
||||
include __DIR__ . '/layout.php';
|
||||
17
store/@{FutureOSS}/webui/frontend/views/index.php
Normal file
17
store/@{FutureOSS}/webui/frontend/views/index.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* 首页视图
|
||||
* 这是 webui 插件的默认首页
|
||||
* 其他插件可以替换或扩展此页面
|
||||
*/
|
||||
|
||||
$pageTitle = $config['title'] ?? 'FutureOSS';
|
||||
$currentPage = 'home';
|
||||
|
||||
// 默认导航项(其他插件可以添加更多)
|
||||
$navItems = [];
|
||||
|
||||
// 内容区(其他插件可以注入内容)
|
||||
$content = '<div class="empty-state"><p>暂无内容</p></div>';
|
||||
|
||||
include __DIR__ . '/layout.php';
|
||||
64
store/@{FutureOSS}/webui/frontend/views/layout.php
Normal file
64
store/@{FutureOSS}/webui/frontend/views/layout.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= htmlspecialchars($pageTitle ?? 'FutureOSS') ?></title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/remixicon/4.1.0/remixicon.min.css">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<nav class="sidebar-nav">
|
||||
<?php if (!empty($navItems)): ?>
|
||||
<?php foreach ($navItems as $item): ?>
|
||||
<?php
|
||||
$url = $item['url'] ?? '#';
|
||||
$isActive = ($currentPage ?? '') === $url;
|
||||
$icon = $item['icon'] ?? 'ri-dashboard-line';
|
||||
// 如果图标是 emoji,转换为 remixicon 类名
|
||||
$iconMap = [
|
||||
'🏠' => 'ri-home-4-line',
|
||||
'📊' => 'ri-dashboard-line',
|
||||
'📋' => 'ri-file-list-3-line',
|
||||
'🧩' => 'ri-puzzle-line',
|
||||
'⚙️' => 'ri-settings-3-line',
|
||||
'🔌' => 'ri-plug-line',
|
||||
'📦' => 'ri-box-3-line',
|
||||
'🌐' => 'ri-global-line',
|
||||
];
|
||||
$riIcon = $iconMap[$icon] ?? $icon;
|
||||
?>
|
||||
<a href="<?= htmlspecialchars($url) ?>"
|
||||
class="nav-item <?= $isActive ? 'active' : '' ?>"
|
||||
title="<?= htmlspecialchars($item['text'] ?? '') ?>">
|
||||
<i class="<?= htmlspecialchars($riIcon) ?>"></i>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</nav>
|
||||
<div class="sidebar-footer">
|
||||
<button class="settings-btn" title="设置">
|
||||
<i class="ri-settings-3-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="content">
|
||||
<div class="content-body">
|
||||
<?php if (isset($content)): ?>
|
||||
<?= $content ?>
|
||||
<?php else: ?>
|
||||
<div class="empty-state">
|
||||
<p>暂无内容</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user