后端:重构postgre数据结构
前端:定义好主题,插件,上下文参数的接口
This commit is contained in:
parent
ddbb770923
commit
7f2a02dc61
@ -1,36 +1,64 @@
|
||||
// main.rs
|
||||
mod config;
|
||||
mod sql;
|
||||
use crate::sql::Database;
|
||||
use once_cell::sync::Lazy;
|
||||
use rocket::{get, http::Status, launch, response::status, routes, serde::json::Json};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
// /d:/data/echoes/backend/src/main.rs
|
||||
|
||||
/* 修改全局变量的类型定义 */
|
||||
/**
|
||||
* 主程序入口,提供数据库连接和相关API接口。
|
||||
*
|
||||
* 接口:
|
||||
* - GET /api/install: 测试数据库连接
|
||||
* - GET /api/sql: 执行SQL查询并返回结果
|
||||
*/
|
||||
|
||||
mod config; // 配置模块
|
||||
mod sql; // SQL模块
|
||||
use crate::sql::Database; // 引入数据库结构
|
||||
use once_cell::sync::Lazy; // 用于延迟初始化
|
||||
use rocket::{get, http::Status, launch, response::status, routes, serde::json::Json}; // 引入Rocket框架相关功能
|
||||
use std::sync::Arc; // 引入Arc用于线程安全的引用计数
|
||||
use tokio::sync::Mutex; // 引入Mutex用于异步锁
|
||||
|
||||
// 全局数据库连接变量
|
||||
static DB: Lazy<Arc<Mutex<Option<Database>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
|
||||
|
||||
/* 数据库连接函数 */
|
||||
/**
|
||||
* 初始化数据库连接
|
||||
*
|
||||
* # 参数
|
||||
* - `database`: 数据库配置
|
||||
*
|
||||
* # 返回
|
||||
* - `Result<(), Box<dyn std::error::Error>>`: 初始化结果
|
||||
*/
|
||||
async fn init_db(database: config::Database) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let database = Database::init(database).await?;
|
||||
*DB.lock().await = Some(database);
|
||||
let database = Database::init(database).await?; // 初始化数据库
|
||||
*DB.lock().await = Some(database); // 保存数据库实例
|
||||
Ok(())
|
||||
}
|
||||
/* 获取数据库的引用 */
|
||||
|
||||
/**
|
||||
* 获取数据库的引用
|
||||
*
|
||||
* # 返回
|
||||
* - `Result<Database, Box<dyn std::error::Error>>`: 数据库实例或错误
|
||||
*/
|
||||
async fn get_db() -> Result<Database, Box<dyn std::error::Error>> {
|
||||
DB.lock()
|
||||
.await
|
||||
.clone()
|
||||
.ok_or_else(|| "Database not initialized".into())
|
||||
.ok_or_else(|| "Database not initialized".into()) // 返回错误信息
|
||||
}
|
||||
/* 用于测试数据库 */
|
||||
|
||||
/**
|
||||
* 测试数据库接口
|
||||
*
|
||||
* # 返回
|
||||
* - `Result<Json<Vec<std::collections::HashMap<String, String>>>, status::Custom<String>>`: 查询结果或错误
|
||||
*/
|
||||
#[get("/sql")]
|
||||
async fn ssql(
|
||||
) -> Result<Json<Vec<std::collections::HashMap<String, String>>>, status::Custom<String>> {
|
||||
async fn ssql() -> Result<Json<Vec<std::collections::HashMap<String, String>>>, status::Custom<String>> {
|
||||
let db = get_db().await.map_err(|e| {
|
||||
status::Custom(
|
||||
Status::InternalServerError,
|
||||
format!("Database error: {}", e),
|
||||
format!("Database error: {}", e), // 数据库错误信息
|
||||
)
|
||||
})?;
|
||||
|
||||
@ -40,27 +68,39 @@ async fn ssql(
|
||||
.await
|
||||
.map_err(|e| status::Custom(Status::InternalServerError, format!("Query error: {}", e)))?;
|
||||
|
||||
Ok(Json(query_result))
|
||||
Ok(Json(query_result)) // 返回查询结果
|
||||
}
|
||||
/* 安装接口 */
|
||||
|
||||
/**
|
||||
* 数据库安装接口
|
||||
*
|
||||
* # 返回
|
||||
* - `status::Custom<String>`: 连接成功或失败的信息
|
||||
*/
|
||||
#[get("/install")]
|
||||
async fn install() -> status::Custom<String> {
|
||||
get_db()
|
||||
.await
|
||||
.map(|_| status::Custom(Status::Ok, "Database connected successfully".into()))
|
||||
.map(|_| status::Custom(Status::Ok, "Database connected successfully".into())) // 连接成功
|
||||
.unwrap_or_else(|e| {
|
||||
status::Custom(
|
||||
Status::InternalServerError,
|
||||
format!("Failed to connect: {}", e),
|
||||
format!("Failed to connect: {}", e), // 连接失败信息
|
||||
)
|
||||
})
|
||||
}
|
||||
/* 启动函数 */
|
||||
|
||||
/**
|
||||
* 启动Rocket应用
|
||||
*
|
||||
* # 返回
|
||||
* - `rocket::Rocket`: Rocket实例
|
||||
*/
|
||||
#[launch]
|
||||
async fn rocket() -> _ {
|
||||
let config = config::Config::read("./src/config/config.toml").expect("Failed to read config");
|
||||
let config = config::Config::read("./src/config/config.toml").expect("Failed to read config"); // 读取配置
|
||||
init_db(config.database)
|
||||
.await
|
||||
.expect("Failed to connect to database");
|
||||
rocket::build().mount("/api", routes![install, ssql])
|
||||
.expect("Failed to connect to database"); // 初始化数据库连接
|
||||
rocket::build().mount("/api", routes![install, ssql]) // 挂载API路由
|
||||
}
|
||||
|
90
backend/src/sql/postgresql/init.sql
Normal file
90
backend/src/sql/postgresql/init.sql
Normal file
@ -0,0 +1,90 @@
|
||||
--- 安装自动生成uuid插件
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
--- 网站信息表
|
||||
CREATE TABLE settings
|
||||
(
|
||||
settings_keys VARCHAR(255) PRIMARY KEY,
|
||||
settings_values TEXT NOT NULL
|
||||
);
|
||||
--- 页面状态枚举
|
||||
CREATE TYPE publication_status AS ENUM ('draft', 'published', 'private','hide');
|
||||
--- 独立页面表
|
||||
CREATE TABLE pages
|
||||
(
|
||||
page_id SERIAL PRIMARY KEY, --- 独立页面唯一id主键
|
||||
page_meta_keywords VARCHAR(255) NOT NULL, ---页面mata关键字
|
||||
page_meta_description VARCHAR(255) NOT NULL, ---页面mata描述
|
||||
post_title VARCHAR(255) NOT NULL, --- 文章标题
|
||||
page_content TEXT NOT NULL, --- 独立页面内容
|
||||
page_mould VARCHAR(50), --- 独立页面模板名称
|
||||
page_fields JSON, --- 自定义字段
|
||||
page_path VARCHAR(255), --- 文章路径
|
||||
page_status publication_status DEFAULT 'draft' --- 文章状态
|
||||
);
|
||||
--- 文章表
|
||||
CREATE TABLE posts
|
||||
(
|
||||
post_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), --- 文章主键
|
||||
post_title VARCHAR(255) NOT NULL, --- 文章标题
|
||||
post_meta_keywords VARCHAR(255) NOT NULL, ---文章mata关键字
|
||||
post_meta_description VARCHAR(255) NOT NULL, ---文章mata描述
|
||||
post_content TEXT NOT NULL, --- 文章内容
|
||||
post_status publication_status DEFAULT 'draft', --- 文章状态
|
||||
post_editor BOOLEAN DEFAULT FALSE, --- 文章是否编辑未保存
|
||||
posts_unsaved_content TEXT, --- 未保存的文章
|
||||
posts_path VARCHAR(255), --- 文章路径
|
||||
post_created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, --- 文章创建时间
|
||||
post_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, --- 文章更新时间
|
||||
post_published_at TIMESTAMP, --- 文章发布时间
|
||||
CONSTRAINT post_updated_at_check CHECK (post_updated_at >= post_created_at) --- 文章时间约束
|
||||
);
|
||||
--- 标签表
|
||||
CREATE TABLE tags
|
||||
(
|
||||
tag_name VARCHAR(50) PRIMARY KEY CHECK (LOWER(tag_name) = tag_name) --- 标签名称主键
|
||||
);
|
||||
--- 文章与标签的关系表
|
||||
CREATE TABLE post_tags
|
||||
(
|
||||
post_id UUID REFERENCES posts (post_id) ON DELETE CASCADE, --- 外键约束,引用posts的主键
|
||||
tag_name VARCHAR(50) REFERENCES tags (tag_name) ON DELETE CASCADE, --- 外键约束,引用tag的主键
|
||||
PRIMARY KEY (post_id, tag_name) --- 复合主键
|
||||
);
|
||||
--- 分类表
|
||||
CREATE TABLE categories
|
||||
(
|
||||
category_name VARCHAR(50) PRIMARY KEY, ---分类表名称主键
|
||||
parent_category_name VARCHAR(50), -- 父类分类 ID(可以为空)
|
||||
FOREIGN KEY (parent_category_name) REFERENCES categories (category_name) -- 外键约束,引用同一表的 category_id
|
||||
);
|
||||
--- 文章与分类的关系表
|
||||
CREATE TABLE post_categories
|
||||
(
|
||||
post_id UUID REFERENCES posts (post_id) ON DELETE CASCADE, --- 外键约束,引用posts的主键
|
||||
category_id VARCHAR(50) REFERENCES categories (category_name) ON DELETE CASCADE, --- 外键约束,引用categories的主键
|
||||
PRIMARY KEY (post_id, category_id) --- 复合主键
|
||||
);
|
||||
--- 资源库
|
||||
CREATE TABLE library
|
||||
(
|
||||
library_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), --- 资源ID
|
||||
library_name VARCHAR(255) NOT NULL, --- 资源名称
|
||||
library_size BIGINT NOT NULL, --- 大小
|
||||
library_storage_path VARCHAR(255) NOT NULL UNIQUE, --- 储存路径
|
||||
library_type VARCHAR(50) NOT NULL REFERENCES library_type (library_type) ON DELETE CASCADE, --- 资源类别
|
||||
library_description VARCHAR(255), --- 资源描述
|
||||
library_created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP --- 创建时间
|
||||
|
||||
);
|
||||
--- 资源库类别
|
||||
CREATE TABLE library_type
|
||||
(
|
||||
library_type VARCHAR(50) PRIMARY KEY, --- 资源类别
|
||||
library_description VARCHAR(200) --- 资源类别描述
|
||||
);
|
||||
--- 配置文件库
|
||||
CREATE TABLE config
|
||||
(
|
||||
config_name VARCHAR(50) PRIMARY KEY, --- 配置文件名称
|
||||
config_config JSON --- 配置文件
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
// sql/psotgresql.rs
|
||||
/*
|
||||
/*
|
||||
为postgresql数据库实现具体的方法
|
||||
*/
|
||||
use super::DatabaseTrait;
|
||||
@ -18,39 +18,46 @@ impl DatabaseTrait for Postgresql {
|
||||
async fn connect(database: config::Database) -> Result<Self, Box<dyn Error>> {
|
||||
let connection_str = format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
database.user,
|
||||
database.password,
|
||||
database.address,
|
||||
database.prot,
|
||||
database.db_name
|
||||
database.user, database.password, database.address, database.prot, database.db_name
|
||||
);
|
||||
|
||||
// 连接到数据库池
|
||||
let pool = PgPool::connect(&connection_str)
|
||||
.await
|
||||
.map_err(|e| Box::new(e) as Box<dyn Error>)?;
|
||||
|
||||
// 返回Postgresql实例
|
||||
Ok(Postgresql { pool })
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行查询并返回结果。
|
||||
*/
|
||||
async fn query<'a>(
|
||||
&'a self,
|
||||
query: String,
|
||||
) -> Result<Vec<HashMap<String, String>>, Box<dyn Error + 'a>> {
|
||||
// 执行查询并获取所有行
|
||||
let rows = sqlx::query(&query)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| Box::new(e) as Box<dyn Error>)?;
|
||||
|
||||
// 存储查询结果
|
||||
let mut results = Vec::new();
|
||||
|
||||
// 遍历每一行并构建结果映射
|
||||
for row in rows {
|
||||
let mut map = HashMap::new();
|
||||
for column in row.columns() {
|
||||
// 获取列的值,若失败则使用默认值
|
||||
let value: String = row.try_get(column.name()).unwrap_or_default();
|
||||
map.insert(column.name().to_string(), value);
|
||||
}
|
||||
results.push(map);
|
||||
}
|
||||
|
||||
// 返回查询结果
|
||||
Ok(results)
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
// hooks/usePluginLoader.ts
|
||||
import { useState, useEffect } from 'react';
|
||||
import { DependencyChecker } from '../../services/dependency-checker';
|
||||
import { PerformanceMonitor } from '../../services/performance-monitor';
|
||||
import { CacheManager } from '../../services/cache-manager';
|
||||
|
||||
/**
|
||||
* 插件加载Hook
|
||||
* @param pluginId 插件ID
|
||||
* @returns 加载状态和错误信息
|
||||
*/
|
||||
export function usePluginLoader(pluginId: string) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const loadPlugin = async () => {
|
||||
try {
|
||||
// 检查缓存
|
||||
const cached = CacheManager.get(`plugin:${pluginId}`);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 开始性能监控
|
||||
const monitor = PerformanceMonitor.startMonitoring(pluginId);
|
||||
|
||||
// 获取插件配置
|
||||
const plugin = await fetch(`/api/admin/plugins/${pluginId}`).then(r => r.json());
|
||||
|
||||
// 检查依赖
|
||||
if (plugin.dependencies) {
|
||||
const dependenciesOk = await DependencyChecker.checkDependencies(plugin.dependencies);
|
||||
if (!dependenciesOk) {
|
||||
throw new Error('依赖检查失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 加载插件
|
||||
const component = await import(/* @vite-ignore */plugin.entry);
|
||||
|
||||
// 缓存结果
|
||||
CacheManager.set(`plugin:${pluginId}`, component);
|
||||
|
||||
// 结束监控
|
||||
monitor.end();
|
||||
|
||||
return component;
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : '插件加载失败');
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadPlugin();
|
||||
}, [pluginId]);
|
||||
|
||||
return { loading, error };
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// components/theme/themeManager.tsx
|
||||
import React, { useEffect } from 'react';
|
||||
import { useThemeLoader } from './useThemeLoader';
|
||||
|
||||
interface ThemeManagerProps {
|
||||
themeName: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const ThemeManager: React.FC<ThemeManagerProps> = ({
|
||||
themeName,
|
||||
children
|
||||
}) => {
|
||||
const { theme, loading, error } = useThemeLoader(themeName);
|
||||
|
||||
if (loading) {
|
||||
return <div>加载主题中...</div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div>主题加载失败: {error}</div>;
|
||||
}
|
||||
|
||||
if (!theme) {
|
||||
return <div>主题未找到</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`theme-${themeName}`}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
// components/theme/themeSwitch.tsx
|
||||
import React from 'react';
|
||||
|
||||
interface ThemeSwitchProps {
|
||||
currentTheme: string;
|
||||
availableThemes: string[];
|
||||
onThemeChange: (themeName: string) => void;
|
||||
}
|
||||
|
||||
export const ThemeSwitch: React.FC<ThemeSwitchProps> = ({
|
||||
currentTheme,
|
||||
availableThemes,
|
||||
onThemeChange
|
||||
}) => {
|
||||
return (
|
||||
<select
|
||||
value={currentTheme}
|
||||
onChange={(e) => onThemeChange(e.target.value)}
|
||||
>
|
||||
{availableThemes.map(theme => (
|
||||
<option key={theme} value={theme}>
|
||||
{theme}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
};
|
@ -1,66 +0,0 @@
|
||||
// hooks/theme/useThemeLoader.ts
|
||||
import { useState, useEffect } from 'react';
|
||||
import { ThemeConfig } from '../../types/theme';
|
||||
import { DependencyChecker } from '../../services/dependency-checker';
|
||||
import { PerformanceMonitor } from '../../services/performance-monitor';
|
||||
import { CacheManager } from '../../services/cache-manager';
|
||||
|
||||
/**
|
||||
* 主题加载Hook
|
||||
*/
|
||||
export function useThemeLoader(themeName: string) {
|
||||
const [theme, setTheme] = useState<ThemeConfig | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const loadTheme = async () => {
|
||||
const monitor = PerformanceMonitor.startMonitoring(`theme:${themeName}`);
|
||||
|
||||
try {
|
||||
// 1. 检查缓存
|
||||
const cached = CacheManager.get(`theme:${themeName}`);
|
||||
if (cached) {
|
||||
setTheme(cached);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 获取主题配置
|
||||
const response = await fetch(`/api/themes/${themeName}`);
|
||||
const themeConfig: ThemeConfig = await response.json();
|
||||
|
||||
// 3. 检查依赖
|
||||
if (themeConfig.dependencies) {
|
||||
const dependenciesOk = await DependencyChecker.checkDependencies(
|
||||
themeConfig.dependencies
|
||||
);
|
||||
if (!dependenciesOk) {
|
||||
throw new Error('主题依赖检查失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 加载主题样式
|
||||
if (themeConfig.globalStyles) {
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.innerHTML = themeConfig.globalStyles;
|
||||
document.head.appendChild(styleElement);
|
||||
}
|
||||
|
||||
// 5. 缓存主题配置
|
||||
CacheManager.set(`theme:${themeName}`, themeConfig, 3600000); // 1小时缓存
|
||||
|
||||
setTheme(themeConfig);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : '加载主题失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
monitor.end();
|
||||
}
|
||||
};
|
||||
|
||||
loadTheme();
|
||||
}, [themeName]);
|
||||
|
||||
return { theme, loading, error };
|
||||
}
|
13
frontend/index.html
Normal file
13
frontend/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,41 +0,0 @@
|
||||
// services/cache-manager.ts
|
||||
/**
|
||||
* 缓存管理服务
|
||||
*/
|
||||
export class CacheManager {
|
||||
private static cache = new Map<string, any>();
|
||||
private static ttl = new Map<string, number>();
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
* @param key 缓存键
|
||||
* @param value 缓存值
|
||||
* @param expiresIn 过期时间(毫秒)
|
||||
*/
|
||||
static set(key: string, value: any, expiresIn: number = 3600000) {
|
||||
this.cache.set(key, value);
|
||||
this.ttl.set(key, Date.now() + expiresIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
* @param key 缓存键
|
||||
* @returns 缓存值或null(如果已过期或不存在)
|
||||
*/
|
||||
static get(key: string): any {
|
||||
if (this.ttl.has(key) && Date.now() > (this.ttl.get(key) || 0)) {
|
||||
this.cache.delete(key);
|
||||
this.ttl.delete(key);
|
||||
return null;
|
||||
}
|
||||
return this.cache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有缓存
|
||||
*/
|
||||
static clear() {
|
||||
this.cache.clear();
|
||||
this.ttl.clear();
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
// services/performance-monitor.ts
|
||||
/**
|
||||
* 性能指标接口
|
||||
*/
|
||||
interface PerformanceMetrics {
|
||||
loadTime: number; // 加载时间(毫秒)
|
||||
memoryUsage: number; // 内存使用量(bytes)
|
||||
errors: string[]; // 错误信息列表
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能监控服务
|
||||
*/
|
||||
export class PerformanceMonitor {
|
||||
private static metrics: Map<string, PerformanceMetrics> = new Map();
|
||||
|
||||
/**
|
||||
* 开始监控性能
|
||||
* @param id 监控对象的唯一标识符
|
||||
*/
|
||||
static startMonitoring(id: string) {
|
||||
const startTime = performance.now();
|
||||
const startMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
||||
|
||||
return {
|
||||
// 结束监控并记录指标
|
||||
end: () => {
|
||||
const loadTime = performance.now() - startTime;
|
||||
const memoryUsage = ((performance as any).memory?.usedJSHeapSize || 0) - startMemory;
|
||||
|
||||
this.metrics.set(id, {
|
||||
loadTime,
|
||||
memoryUsage,
|
||||
errors: []
|
||||
});
|
||||
},
|
||||
|
||||
// 记录错误信息
|
||||
error: (err: string) => {
|
||||
const metrics = this.metrics.get(id) || { loadTime: 0, memoryUsage: 0, errors: [] };
|
||||
metrics.errors.push(err);
|
||||
this.metrics.set(id, metrics);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性能指标
|
||||
* @param id 监控对象的唯一标识符
|
||||
*/
|
||||
static getMetrics(id: string): PerformanceMetrics | undefined {
|
||||
return this.metrics.get(id);
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
// services/plugin-communication.ts
|
||||
/**
|
||||
* 消息处理器类型定义
|
||||
*/
|
||||
type MessageHandler = (data: any) => void;
|
||||
|
||||
/**
|
||||
* 插件通信服务
|
||||
*/
|
||||
export class PluginMessenger {
|
||||
// 存储所有消息处理器
|
||||
private static handlers: Map<string, Set<MessageHandler>> = new Map();
|
||||
|
||||
/**
|
||||
* 订阅消息通道
|
||||
* @param channel 通道名称
|
||||
* @param handler 消息处理函数
|
||||
* @returns 取消订阅函数
|
||||
*/
|
||||
static subscribe(channel: string, handler: MessageHandler) {
|
||||
if (!this.handlers.has(channel)) {
|
||||
this.handlers.set(channel, new Set());
|
||||
}
|
||||
this.handlers.get(channel)?.add(handler);
|
||||
|
||||
return () => {
|
||||
this.handlers.get(channel)?.delete(handler);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布消息到指定通道
|
||||
* @param channel 通道名称
|
||||
* @param data 消息数据
|
||||
*/
|
||||
static publish(channel: string, data: any) {
|
||||
this.handlers.get(channel)?.forEach(handler => handler(data));
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// types/common.ts
|
||||
/**
|
||||
* 版本信息接口
|
||||
*/
|
||||
export interface VersionInfo {
|
||||
major: number; // 主版本号 - 不兼容的API修改
|
||||
minor: number; // 次版本号 - 向下兼容的功能性新增
|
||||
patch: number; // 修订号 - 向下兼容的问题修正
|
||||
}
|
||||
|
||||
/**
|
||||
* 依赖项配置接口
|
||||
*/
|
||||
export interface Dependency {
|
||||
id: string; // 依赖项的唯一标识符
|
||||
version: string; // 依赖项的版本要求
|
||||
type: 'plugin' | 'theme'; // 依赖项类型:插件或主题
|
||||
}
|
12
frontend/types/context.ts
Normal file
12
frontend/types/context.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// File path: /d:/data/echoes/frontend/types/context.ts
|
||||
/**
|
||||
* 应用程序上下文配置接口
|
||||
*
|
||||
* 此接口定义了应用程序的上下文配置,包括API基础URL、主题、插件和资源目录的路径。
|
||||
*/
|
||||
export interface AppContext {
|
||||
apiBaseUrl: string; // 用于访问API的基础URL
|
||||
themesPath: string; // 存储主题文件的目录路径
|
||||
pluginsPath: string; // 存储插件文件的目录路径
|
||||
assetsPath: string; // 存储静态资源的目录路径
|
||||
}
|
@ -1,23 +1,41 @@
|
||||
// types/plugin.ts
|
||||
import {Dependency} from "./common";
|
||||
// File path: /d:/data/echoes/frontend/types/plugin.ts
|
||||
|
||||
/**
|
||||
* 插件配置接口
|
||||
*
|
||||
* 该接口定义了插件的基本配置,包括插件的名称、版本、描述、作者等信息。
|
||||
* 还包括插件的生命周期钩子和依赖项的配置。
|
||||
*/
|
||||
export interface PluginConfig {
|
||||
id: string; // 插件唯一标识符
|
||||
name: string; // 插件名称
|
||||
version: string; // 插件版本
|
||||
displayName: string; // 插件显示名称
|
||||
description?: string; // 插件描述
|
||||
author?: string; // 插件作者
|
||||
description?: string; // 插件描述(可选)
|
||||
author?: string; // 插件作者(可选)
|
||||
enabled: boolean; // 插件是否启用
|
||||
icon?: string; // 插件图标URL
|
||||
adminPath?: string; // 插件管理页面路径
|
||||
icon?: string; // 插件图标URL(可选)
|
||||
managePath?: string; // 插件管理页面路径(可选)
|
||||
entry: string; // 插件入口组件路径
|
||||
dependencies?: Dependency[]; // 插件依赖项
|
||||
performance?: {
|
||||
maxLoadTime?: number; // 最大加载时间(毫秒)
|
||||
maxMemoryUsage?: number; // 最大内存使用量(bytes)
|
||||
// 主题配置
|
||||
settingsSchema?: {
|
||||
type: string; // 配置类型
|
||||
properties: Record<string, {
|
||||
type: string; // 属性类型
|
||||
title: string; // 属性标题
|
||||
description?: string; // 属性描述(可选)
|
||||
data?: any; // 额外数据(可选)
|
||||
}>;
|
||||
};
|
||||
// 依赖
|
||||
dependencies?: {
|
||||
plugins?: string[]; // 依赖的插件列表(可选)
|
||||
themes?: string[]; // 依赖的主题列表(可选)
|
||||
};
|
||||
// 插件生命周期钩子
|
||||
hooks?: {
|
||||
onInstall?: string; // 安装时调用的钩子(可选)
|
||||
onUninstall?: string; // 卸载时调用的钩子(可选)
|
||||
onEnable?: string; // 启用时调用的钩子(可选)
|
||||
onDisable?: string; // 禁用时调用的钩子(可选)
|
||||
};
|
||||
}
|
@ -1,20 +1,55 @@
|
||||
// types/theme.ts
|
||||
import {Dependency} from "./common.ts";
|
||||
// /d:/data/echoes/frontend/types/theme.ts
|
||||
/**
|
||||
* 主题配置和模板接口定义文件
|
||||
* 该文件包含主题配置接口和主题模板接口的定义,用于主题管理和渲染。
|
||||
*/
|
||||
|
||||
/**
|
||||
* 主题配置接口
|
||||
*/
|
||||
export interface ThemeConfig {
|
||||
name: string; // 主题的唯一名称标识符
|
||||
version: string; // 主题版本
|
||||
displayName: string; // 主题显示名称
|
||||
description?: string; // 主题描述
|
||||
author?: string; // 主题作者
|
||||
preview?: string; // 主题预览图URL
|
||||
globalStyles?: string; // 主题全局样式
|
||||
dependencies?: Dependency[]; // 主题依赖项
|
||||
performance?: {
|
||||
maxLoadTime?: number; // 最大加载时间(毫秒)
|
||||
maxMemoryUsage?: number; // 最大内存使用量(bytes)
|
||||
name: string; // 主题的唯一标识符
|
||||
displayName: string; // 主题的显示名称
|
||||
version: string; // 主题的版本号
|
||||
description?: string; // 主题的描述信息
|
||||
author?: string; // 主题的作者信息
|
||||
entry: string; // 主题的入口组件路径
|
||||
templates: Map<string, ThemeTemplate>; // 主题模板的映射表
|
||||
/** 主题全局配置 */
|
||||
globalSettings?: {
|
||||
layout?: string; // 主题的布局配置
|
||||
css?: string; // 主题的CSS配置
|
||||
};
|
||||
}
|
||||
/** 主题配置文件 */
|
||||
settingsSchema?: {
|
||||
type: string; // 配置文件的类型
|
||||
/** 属性定义 */
|
||||
properties: Record<string, {
|
||||
type: string; // 属性的数据类型
|
||||
title: string; // 属性的标题
|
||||
description?: string; // 属性的描述信息
|
||||
data?: any; // 属性的默认数据
|
||||
}>;
|
||||
};
|
||||
/** 依赖 */
|
||||
dependencies?: {
|
||||
plugins?: string[]; // 主题所依赖的插件列表
|
||||
assets?: string[]; // 主题所依赖的资源列表
|
||||
};
|
||||
/** 钩子 */
|
||||
hooks?: {
|
||||
beforeRender?: string; // 渲染前执行的钩子
|
||||
afterRender?: string; // 渲染后执行的钩子
|
||||
onActivate?: string; // 主题激活时执行的钩子
|
||||
onDeactivate?: string; // 主题停用时执行的钩子
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 主题模板接口
|
||||
*/
|
||||
export interface ThemeTemplate {
|
||||
path: string; // 模板文件的路径
|
||||
name: string; // 模板的名称
|
||||
description?: string; // 模板的描述信息
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user