diff --git a/.omo/run-continuation/ses_1dede8a7affeG6DxtfPUOviXrp.json b/.omo/run-continuation/ses_1dede8a7affeG6DxtfPUOviXrp.json index 77e46da..173fa2d 100644 --- a/.omo/run-continuation/ses_1dede8a7affeG6DxtfPUOviXrp.json +++ b/.omo/run-continuation/ses_1dede8a7affeG6DxtfPUOviXrp.json @@ -1,10 +1,11 @@ { "sessionID": "ses_1dede8a7affeG6DxtfPUOviXrp", - "updatedAt": "2026-06-17T07:11:26.600Z", + "updatedAt": "2026-06-17T08:18:52.213Z", "sources": { "background-task": { - "state": "idle", - "updatedAt": "2026-06-17T07:11:26.600Z" + "state": "active", + "reason": "2 background task(s) active", + "updatedAt": "2026-06-17T08:18:52.213Z" } } } \ No newline at end of file diff --git a/platform/backend/app/api/admin.py b/platform/backend/app/api/admin.py index aca1b27..073d243 100644 --- a/platform/backend/app/api/admin.py +++ b/platform/backend/app/api/admin.py @@ -9,7 +9,7 @@ from ..database import get_db from ..models import User, Topic, SystemConfig from ..schemas import UserCreate, UserUpdate, UserResponse from ..core.audit_logger import audit_log -from .auth import get_current_admin, org_filter +from .auth import get_current_admin, require_role, org_filter import json router = APIRouter(prefix="/api/admin", tags=["admin"]) diff --git a/platform/backend/app/api/collector_mgmt.py b/platform/backend/app/api/collector_mgmt.py index 28f148f..1d461c1 100644 --- a/platform/backend/app/api/collector_mgmt.py +++ b/platform/backend/app/api/collector_mgmt.py @@ -7,7 +7,7 @@ from typing import Optional from ..database import get_db from ..models import CollectorCategory, CollectorSource -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/collector", tags=["collector_mgmt"], dependencies=[Depends(get_current_admin)]) diff --git a/platform/backend/app/api/config_items.py b/platform/backend/app/api/config_items.py index edec30a..9f2bec2 100644 --- a/platform/backend/app/api/config_items.py +++ b/platform/backend/app/api/config_items.py @@ -7,7 +7,7 @@ import json from ..database import get_db from ..models import KeywordDomainMap, SensitiveWord, ContentCleanRule, TrendFieldMapping, CollectorCategory -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/config", tags=["admin"]) diff --git a/platform/backend/app/api/llm_configs.py b/platform/backend/app/api/llm_configs.py index f434785..4c00b09 100644 --- a/platform/backend/app/api/llm_configs.py +++ b/platform/backend/app/api/llm_configs.py @@ -5,7 +5,7 @@ from typing import List from ..database import get_db from ..models import LLMConfig from ..schemas import LLMConfigBase, LLMConfigResponse -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/llmconfigs", tags=["admin"]) diff --git a/platform/backend/app/api/menu_configs.py b/platform/backend/app/api/menu_configs.py index 3fda0d0..c25d492 100644 --- a/platform/backend/app/api/menu_configs.py +++ b/platform/backend/app/api/menu_configs.py @@ -5,7 +5,7 @@ from typing import List from ..database import get_db from ..models import Menu, User from ..schemas import MenuCreate, MenuUpdate, MenuResponse -from .auth import get_current_admin, get_current_user +from .auth import get_current_admin, require_role, get_current_user router = APIRouter(prefix="/api/admin/menus", tags=["admin"]) public_router = APIRouter(prefix="/api/menus", tags=["menus"]) diff --git a/platform/backend/app/api/prompt_configs.py b/platform/backend/app/api/prompt_configs.py index 72bd39e..b65c570 100644 --- a/platform/backend/app/api/prompt_configs.py +++ b/platform/backend/app/api/prompt_configs.py @@ -6,7 +6,7 @@ from datetime import datetime from ..database import get_db from ..models import PromptConfig -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/prompt-configs", tags=["admin"]) diff --git a/platform/backend/app/api/role_configs.py b/platform/backend/app/api/role_configs.py index 03017d5..73453b2 100644 --- a/platform/backend/app/api/role_configs.py +++ b/platform/backend/app/api/role_configs.py @@ -5,7 +5,7 @@ from typing import List from ..database import get_db from ..models import Role, User from ..schemas import RoleCreate, RoleUpdate, RoleResponse -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/roles", tags=["admin"]) diff --git a/platform/backend/app/api/search_providers.py b/platform/backend/app/api/search_providers.py index e9f6c28..502d23a 100644 --- a/platform/backend/app/api/search_providers.py +++ b/platform/backend/app/api/search_providers.py @@ -9,7 +9,7 @@ from datetime import datetime, timezone from ..database import get_db from ..models import SearchProvider -from .auth import get_current_admin +from .auth import get_current_admin, require_role logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/search-providers", tags=["search_providers"]) diff --git a/platform/backend/app/api/system_configs.py b/platform/backend/app/api/system_configs.py index 2f72391..affb2de 100644 --- a/platform/backend/app/api/system_configs.py +++ b/platform/backend/app/api/system_configs.py @@ -5,7 +5,7 @@ from typing import List, Dict, Any from ..database import get_db from ..models import SystemConfig from ..schemas import SystemConfigBase, SystemConfigResponse -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/systemconfigs", tags=["admin"]) diff --git a/platform/backend/app/api/task_configs.py b/platform/backend/app/api/task_configs.py index 6029d5c..14cdf0f 100644 --- a/platform/backend/app/api/task_configs.py +++ b/platform/backend/app/api/task_configs.py @@ -6,7 +6,7 @@ from typing import List, Optional from ..database import get_db from ..models import TaskConfig, TaskLog from ..schemas import TaskConfigBase, TaskConfigUpdate, TaskConfigResponse, TaskLogResponse -from .auth import get_current_admin +from .auth import get_current_admin, require_role router = APIRouter(prefix="/api/admin/task-configs", tags=["admin"]) diff --git a/platform/frontend/ai-assistant.js b/platform/frontend/ai-assistant.js index 8425819..1df5fe6 100644 --- a/platform/frontend/ai-assistant.js +++ b/platform/frontend/ai-assistant.js @@ -169,13 +169,15 @@ var token = localStorage.getItem('authToken'); if (!token) return; - var pageMap = { - '/': 'dashboard', '/index.html': 'dashboard', - 'topics.html': 'topics', 'metrics.html': 'metrics', - 'calendar.html': 'calendar', 'assets.html': 'assets', - 'tasks.html': 'tasks', 'platforms.html': 'platforms', - 'admin.html': 'admin' - }; + var pageMap = { + '/': 'dashboard', '/index.html': 'dashboard', + 'topics.html': 'topics', 'metrics.html': 'metrics', + 'calendar.html': 'calendar', 'assets.html': 'assets', + 'tasks.html': 'tasks', 'platforms.html': 'platforms', + 'admin.html': 'admin', + 'factory.html': 'factory', + 'insights.html': 'insights' + }; var path = window.location.pathname; var currentPage = pageMap[path] || pageMap['/']; @@ -187,8 +189,10 @@ 'assets': '🖼️ 素材库管理图片和文件。我可以指导你如何上传素材、添加标签分类,或关联到相关选题。', 'tasks': '⚡ 任务页面跟踪所有创作任务。我可以解释各任务的含义、查看执行进度,或排查任务失败原因。', 'platforms': '🔗 平台配置管理各发布渠道。我可以帮你了解如何配置平台参数、设置发布格式。', - 'admin': '⚙️ 系统管理页面。我可以帮你管理用户、配置 LLM、查看运行日志,或设置采集类别和信息源。', - }; + 'admin': '⚙️ 系统管理页面。我可以帮你管理用户、配置 LLM、查看运行日志,或设置采集类别和信息源。', + 'factory': '🏭 这里是内容工厂。我可以帮你了解创作流程,从选题到发布的全链路跟踪,或排查任务失败原因。', + 'insights': '📈 数据洞察页面。我可以帮你解读内容表现数据、搜索排名变化趋势,或建议如何提升 GEO 就绪度。', + }; var HISTORY_KEY = 'ai_assistant_history_' + currentPage; var saved = []; @@ -289,7 +293,9 @@ var resp = await fetch('/api/assistant/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, - body: JSON.stringify({ message: text, page: currentPage, history: history }) + var currentUser = null; + try { currentUser = JSON.parse(localStorage.getItem('currentUser')); } catch(e) {} + body: JSON.stringify({ message: text, page: currentPage, history: history, org_id: currentUser?.org_id || 'default' }) }); removeTyping(); if (resp.ok) { diff --git a/platform/frontend/index.html b/platform/frontend/index.html index 6d59cff..535a157 100644 --- a/platform/frontend/index.html +++ b/platform/frontend/index.html @@ -30,121 +30,312 @@ .plan-item:hover { border-color: var(--color-primary); } .plan-date { font-size: var(--font-size-caption); color: var(--color-text-secondary); font-weight: 600; min-width: 36px; } .plan-title { flex: 1; font-size: var(--font-size-body); color: var(--color-text-primary); } - @media (max-width: 768px) { .module-grid { grid-template-columns: 1fr; } } + + /* ===== Workspace summary cards ===== */ + .workspace-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--spacing-md); margin-bottom: var(--spacing-xl); } + .ws-summary-card { + border-radius: var(--radius-lg); padding: var(--spacing-lg); cursor: pointer; + transition: all 0.3s var(--ease-out); position: relative; overflow: hidden; + border: 1px solid transparent; + } + .ws-summary-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); } + .ws-summary-card .ws-icon { font-size: 28px; margin-bottom: var(--spacing-sm); display: block; } + .ws-summary-card .ws-value { font-size: var(--font-size-h1); font-weight: 800; line-height: 1.2; } + .ws-summary-card .ws-label { font-size: var(--font-size-small); margin-top: var(--spacing-xs); opacity: 0.85; } + .ws-summary-card .ws-action { font-size: var(--font-size-caption); margin-top: var(--spacing-sm); opacity: 0.7; display: flex; align-items: center; gap: 4px; } + .ws-summary-card.ws-pending { background: linear-gradient(135deg, #fff7ed, #ffedd5); border-color: #fed7aa; } + .ws-summary-card.ws-pending .ws-value { color: #c2410c; } + .ws-summary-card.ws-review { background: linear-gradient(135deg, #fef2f2, #fee2e2); border-color: #fecaca; } + .ws-summary-card.ws-review .ws-value { color: #dc2626; } + .ws-summary-card.ws-ready { background: linear-gradient(135deg, #ecfdf5, #d1fae5); border-color: #a7f3d0; } + .ws-summary-card.ws-ready .ws-value { color: #059669; } + .ws-summary-card.ws-goal { background: linear-gradient(135deg, #eff6ff, #dbeafe); border-color: #bfdbfe; } + .ws-summary-card.ws-goal .ws-value { color: #2563eb; } + + /* ===== Today Todo ===== */ + .todo-list { display: flex; flex-direction: column; gap: var(--spacing-sm); } + .todo-item { + display: flex; align-items: flex-start; gap: var(--spacing-md); + padding: var(--spacing-md) var(--spacing-lg); + background: var(--color-bg-raised); border: 1px solid var(--color-border); + border-radius: var(--radius-md); transition: all 0.2s; cursor: pointer; + } + .todo-item:hover { border-color: var(--color-primary); box-shadow: var(--shadow-sm); } + .todo-priority { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; } + .todo-priority.high { background: var(--color-danger); box-shadow: 0 0 6px rgba(245,108,108,0.5); } + .todo-priority.medium { background: var(--color-warning); } + .todo-priority.low { background: var(--color-success); } + .todo-overdue { background: #fef2f2; border-color: #fecaca; } + .todo-overdue .todo-priority.high { animation: pulse-glow 2s infinite; } + .todo-content { flex: 1; min-width: 0; } + .todo-title { font-size: var(--font-size-body); font-weight: 600; color: var(--color-text-primary); margin-bottom: 2px; } + .todo-meta { font-size: var(--font-size-small); color: var(--color-text-secondary); } + .todo-tag { font-size: var(--font-size-caption); padding: 2px 8px; border-radius: var(--radius-sm); flex-shrink: 0; } + .todo-tag.overdue { background: #fef2f2; color: #dc2626; } + .todo-tag.priority { background: #fff7ed; color: #c2410c; } + + /* ===== AI Suggestions ===== */ + .ai-suggestion-card { + background: linear-gradient(135deg, var(--color-bg-raised), var(--color-bg-subtle)); + border: 1px solid var(--color-border); border-radius: var(--radius-lg); + padding: var(--spacing-lg); margin-bottom: var(--spacing-sm); + transition: all 0.3s var(--ease-out); + } + .ai-suggestion-card:hover { border-color: var(--color-primary-light); box-shadow: var(--shadow-md); } + .ai-suggestion-header { display: flex; align-items: center; gap: var(--spacing-sm); margin-bottom: var(--spacing-sm); } + .ai-suggestion-icon { font-size: 20px; } + .ai-suggestion-title { font-size: var(--font-size-body); font-weight: 600; color: var(--color-text-primary); } + .ai-suggestion-body { font-size: var(--font-size-small); color: var(--color-text-regular); line-height: 1.6; margin-bottom: var(--spacing-sm); } + .ai-suggestion-actions { display: flex; gap: var(--spacing-sm); flex-wrap: wrap; } + + /* ===== Admin Section ===== */ + .admin-section-toggle { + display: flex; align-items: center; gap: var(--spacing-sm); + cursor: pointer; user-select: none; color: var(--color-text-secondary); + font-size: var(--font-size-small); margin-bottom: var(--spacing-md); + transition: color 0.2s; + } + .admin-section-toggle:hover { color: var(--color-text-regular); } + .admin-section-toggle .toggle-icon { transition: transform 0.3s var(--ease-out); } + .admin-section-toggle.collapsed .toggle-icon { transform: rotate(-90deg); } + + /* ===== Welcome Banner ===== */ + .welcome-banner { + background: linear-gradient(135deg, var(--color-primary), var(--color-accent)); + border-radius: var(--radius-lg); padding: var(--spacing-xl) var(--spacing-xl); + color: white; margin-bottom: var(--spacing-xl); position: relative; overflow: hidden; + } + .welcome-banner::before { + content: ''; position: absolute; top: -50%; right: -20%; + width: 300px; height: 300px; border-radius: 50%; + background: rgba(255,255,255,0.08); + } + .welcome-banner::after { + content: ''; position: absolute; bottom: -60%; left: -10%; + width: 250px; height: 250px; border-radius: 50%; + background: rgba(255,255,255,0.05); + } + .welcome-greeting { font-size: var(--font-size-h2); font-weight: 700; margin-bottom: var(--spacing-xs); position: relative; z-index: 1; } + .welcome-sub { font-size: var(--font-size-body); opacity: 0.9; position: relative; z-index: 1; } + + /* ===== Section Headers ===== */ + .section-header { + display: flex; align-items: center; justify-content: space-between; + margin-bottom: var(--spacing-md); margin-top: var(--spacing-xl); + } + .section-header:first-of-type { margin-top: 0; } + .section-title { + font-size: var(--font-size-h3); font-weight: 600; + color: var(--color-text-primary); display: flex; align-items: center; gap: var(--spacing-sm); + } + + @media (max-width: 768px) { + .module-grid { grid-template-columns: 1fr; } + .workspace-summary { grid-template-columns: repeat(2, 1fr); } + .ws-summary-card { padding: var(--spacing-md); } + .ws-summary-card .ws-value { font-size: 24px; } + .welcome-banner { padding: var(--spacing-lg); } + .welcome-greeting { font-size: var(--font-size-h3); } + }