update
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
{"cookie":{"secure":false,"httpOnly":true,"path":"/"},"userId":1,"username":"admin","requiresTwoFactor":false,"__lastAccess":1745499534213}
|
||||||
+1
-18
@@ -9,27 +9,10 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "3001:3001" # 将容器的 3001 端口映射到宿主机的 3001 端口
|
- "3001:3001" # 将容器的 3001 端口映射到宿主机的 3001 端口
|
||||||
environment:
|
environment:
|
||||||
# 这里需要添加后端运行所需的环境变量
|
|
||||||
# 例如:
|
|
||||||
# NODE_ENV: production
|
|
||||||
# PORT: 3001 # 确保容器内端口与 EXPOSE 一致
|
|
||||||
# DATABASE_PATH: /app/data/database.sqlite # 如果使用 SQLite
|
|
||||||
# ENCRYPTION_KEY: your_strong_encryption_key # 需要设置强密钥
|
|
||||||
# SESSION_SECRET: your_strong_session_secret # 需要设置强密钥
|
|
||||||
# JWT_SECRET: your_strong_jwt_secret # 如果使用 JWT
|
|
||||||
# ... 其他后端需要的环境变量
|
|
||||||
# 注意:敏感信息最好通过 .env 文件或 Docker secrets 管理
|
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
PORT: 3001
|
PORT: 3001
|
||||||
# 示例:如果数据库文件在容器内的 /app/data 目录下
|
|
||||||
DATABASE_PATH: /app/data/database.sqlite
|
|
||||||
# !! 请务必替换下面的示例密钥为强随机值 !!
|
|
||||||
ENCRYPTION_KEY: replace_with_strong_random_key_32_bytes
|
|
||||||
SESSION_SECRET: replace_with_strong_random_secret
|
|
||||||
JWT_SECRET: replace_with_strong_random_jwt_secret
|
|
||||||
volumes:
|
volumes:
|
||||||
# 如果后端需要持久化数据(例如 SQLite 数据库),则挂载卷
|
|
||||||
# 将宿主机上的 ./data 目录映射到容器内的 /app/data 目录
|
|
||||||
- ./data:/app/data # 确保宿主机上的 ./data 目录存在或 Docker 会创建它
|
- ./data:/app/data # 确保宿主机上的 ./data 目录存在或 Docker 会创建它
|
||||||
networks:
|
networks:
|
||||||
- nexus_network # 将服务连接到自定义网络
|
- nexus_network # 将服务连接到自定义网络
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ const initializeDatabase = async () => {
|
|||||||
const startServer = () => {
|
const startServer = () => {
|
||||||
// --- 会话中间件配置 ---
|
// --- 会话中间件配置 ---
|
||||||
const FileStore = sessionFileStore(session);
|
const FileStore = sessionFileStore(session);
|
||||||
const sessionsPath = path.join(__dirname, '..', 'sessions');
|
// 修改路径以匹配 Docker volume 挂载点 /app/data
|
||||||
|
const sessionsPath = path.join('/app/data', 'sessions');
|
||||||
if (!fs.existsSync(sessionsPath)) {
|
if (!fs.existsSync(sessionsPath)) {
|
||||||
fs.mkdirSync(sessionsPath, { recursive: true });
|
fs.mkdirSync(sessionsPath, { recursive: true });
|
||||||
}
|
}
|
||||||
@@ -157,9 +158,12 @@ const startServer = () => {
|
|||||||
secret: process.env.SESSION_SECRET as string,
|
secret: process.env.SESSION_SECRET as string,
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
|
proxy: true, // 信任反向代理设置的 X-Forwarded-Proto 头
|
||||||
cookie: {
|
cookie: {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === 'production'
|
// secure: 'auto' in newer versions, relies on proxy: true here
|
||||||
|
// secure: process.env.NODE_ENV === 'production', // Keep original logic, but proxy:true adjusts behavior
|
||||||
|
secure: false, // Temporarily force secure to false for debugging proxy issues
|
||||||
// maxAge: 默认会话期
|
// maxAge: 默认会话期
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -250,15 +250,21 @@ export const deleteTheme = async (id: number): Promise<boolean> => {
|
|||||||
*/
|
*/
|
||||||
export const initializePresetThemes = async (db: Database, presets: Array<Omit<TerminalTheme, '_id' | 'createdAt' | 'updatedAt' | 'isSystemDefault'> & { name: string }>) => {
|
export const initializePresetThemes = async (db: Database, presets: Array<Omit<TerminalTheme, '_id' | 'createdAt' | 'updatedAt' | 'isSystemDefault'> & { name: string }>) => {
|
||||||
console.log('[DB Init] 开始检查并初始化预设主题...');
|
console.log('[DB Init] 开始检查并初始化预设主题...');
|
||||||
|
// 在这里添加日志,显示总共要处理多少个预设主题
|
||||||
|
console.log(`[DB Init] 发现 ${presets.length} 个预设主题定义。`);
|
||||||
const nowSeconds = Math.floor(Date.now() / 1000); // Use seconds for DB consistency
|
const nowSeconds = Math.floor(Date.now() / 1000); // Use seconds for DB consistency
|
||||||
// const db = await getDbInstance(); // Use the passed db instance
|
// const db = await getDbInstance(); // Use the passed db instance
|
||||||
|
|
||||||
for (const preset of presets) {
|
for (const preset of presets) {
|
||||||
|
// 在循环开始时添加日志,显示正在处理哪个主题
|
||||||
|
console.log(`[DB Init] 正在处理预设主题: "${preset.name}"`);
|
||||||
try {
|
try {
|
||||||
// Check using name and theme_type
|
// Check using name and theme_type
|
||||||
const existing = await getDb<{ id: number }>(db, `SELECT id FROM terminal_themes WHERE name = ? AND theme_type = 'preset'`, [preset.name]);
|
const existing = await getDb<{ id: number }>(db, `SELECT id FROM terminal_themes WHERE name = ? AND theme_type = 'preset'`, [preset.name]);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
|
// 添加日志,表明正在插入新主题
|
||||||
|
console.log(`[DB Init] 主题 "${preset.name}" 不存在,正在插入...`);
|
||||||
// Map preset.themeData to individual columns
|
// Map preset.themeData to individual columns
|
||||||
const theme = preset.themeData;
|
const theme = preset.themeData;
|
||||||
const columns = [
|
const columns = [
|
||||||
@@ -284,7 +290,8 @@ export const initializePresetThemes = async (db: Database, presets: Array<Omit<T
|
|||||||
await runDb(db, insertSql, values);
|
await runDb(db, insertSql, values);
|
||||||
console.log(`[DB Init] 预设主题 "${preset.name}" 已初始化到数据库。`);
|
console.log(`[DB Init] 预设主题 "${preset.name}" 已初始化到数据库。`);
|
||||||
} else {
|
} else {
|
||||||
// console.log(`[DB Init] 预设主题 "${preset.name}" 已存在,跳过初始化。`);
|
// 取消注释并添加日志,表明主题已存在
|
||||||
|
console.log(`[DB Init] 预设主题 "${preset.name}" 已存在,跳过初始化。`);
|
||||||
}
|
}
|
||||||
} catch (err: any) { // Add type annotation for err
|
} catch (err: any) { // Add type annotation for err
|
||||||
// Remove reference to non-existent preset_key
|
// Remove reference to non-existent preset_key
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ server {
|
|||||||
|
|
||||||
# Proxy API requests to the backend service
|
# Proxy API requests to the backend service
|
||||||
location /api/ {
|
location /api/ {
|
||||||
rewrite ^/api(/.*)$ $1 break; # Remove /api prefix before proxying
|
# rewrite ^/api(/.*)$ $1 break; # Remove /api prefix before proxying - REMOVED to match backend routes
|
||||||
proxy_pass http://backend:3001; # Proxy to backend root
|
proxy_pass http://backend:3001; # Proxy to backend root, backend expects /api/v1/...
|
||||||
|
|
||||||
# Standard proxy headers
|
# Standard proxy headers
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
|
|||||||
@@ -255,6 +255,21 @@ export const useLayoutStore = defineStore('layout', () => {
|
|||||||
sidebarPanes.value = getDefaultSidebarPanes();
|
sidebarPanes.value = getDefaultSidebarPanes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Final Check: Ensure defaults are applied if loading failed or resulted in null ---
|
||||||
|
if (!layoutTree.value) {
|
||||||
|
console.warn('[Layout Store] Layout tree is still null after all loading attempts. Applying default layout.');
|
||||||
|
layoutTree.value = getDefaultLayout();
|
||||||
|
// Optionally save the default to localStorage now?
|
||||||
|
// try { localStorage.setItem(LAYOUT_STORAGE_KEY, JSON.stringify(layoutTree.value)); } catch(e) {}
|
||||||
|
}
|
||||||
|
// Basic check for sidebarPanes structure validity before potentially applying default
|
||||||
|
if (!sidebarPanes.value || !Array.isArray(sidebarPanes.value.left) || !Array.isArray(sidebarPanes.value.right)) {
|
||||||
|
console.warn('[Layout Store] Sidebar panes are null or invalid after all loading attempts. Applying default sidebar panes.');
|
||||||
|
sidebarPanes.value = getDefaultSidebarPanes();
|
||||||
|
// Optionally save the default to localStorage now?
|
||||||
|
// try { localStorage.setItem(SIDEBAR_STORAGE_KEY, JSON.stringify(sidebarPanes.value)); } catch(e) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Helper for debounced persistence ---
|
// --- Helper for debounced persistence ---
|
||||||
|
|||||||
Reference in New Issue
Block a user