这是一个非常实际的问题。鉴于当前对话已经超长,我建议您创建一个新的独立对话,并在新对话中引用本次对话的“最终成果摘要”。
以下是您可以复制到新对话中的项目总结:
项目总结:AIVitaaly 插件前端模块化重构
1. 项目概述
Discuz 插件 AIVitaaly 是一款“虚拟人”对话系统,用户可以与自己的虚拟人或其他用户的虚拟人进行 AI 对话。本次重构将原本 7000+ 行的单文件 chat_computer.htm 拆分为多个独立模块,并修复了多个功能问题。
2. 最终文件结构
text
/source/plugin/AIVita3.1/js/
├── config.js # 全局配置 (CONFIG, appState)
├── utils.js # 工具函数 (escapeHtml, showNotification, showMessage, scrollToBottom,
│ # convertHTMLToMarkdown, addNewFormatMessageToChat, startNewConversation,
│ # toggleCategory, syncInputPosition, initUserProfile, getAvatarUrl)
├── sidebar.js # 侧边栏切换 (toggleKnowledgePanel, toggleHistoryPanel, toggleDocumentsPanel,
│ # toggleRelationTreePanel, toggleSettingsPanel, toggleLLMPanel)
├── settings.js # 设置面板 (initSettingsPanel, applyCreate, openPersonalProfileModal,
│ # savePersonalProfile, submitBind, initBindModal)
├── chat.js # 对话核心 (askQuestion, buildRequestData, sendChatRequest,
│ # addUserMessage, createAssistantMessage, handleStreamData)
├── knowledge.js # 虚拟人列表 (loadKnowledgeList, renderKnowledgeList, setDefaultKnowledge,
│ # loadUserRelations, renderUserRelations, selectAI, changeVirtualAssistant)
├── history.js # 历史记录 (loadHistoryList, renderHistoryList, loadConversation,
│ # bindHistoryItemEvents, changeVirtualAssistantWithoutConfirm)
├── project.js # 项目辅助 (loadProjectTree, buildTreeWithDOM, showLogsSidebar,
│ # loadLogsList, searchLogs, renderLogsList, updateMainSelectedDisplay,
│ # saveAsContext)
├── logreader.js # 第三侧窗日志阅读器 (openLogReader, closeLogReader)
├── fileupload.js # 文件上传 (独立作用域,暴露 getUploadedFilesContext, clearAllAttachments)
├── llm.js # 大语言模型选择 (loadLLMList, renderLLMList, selectLLM, toggleLLMPanel)
└── main.js # 主入口 (DOMContentLoaded 事件绑定、初始化)
3. 关键功能实现
3.1 日志阅读权限控制
支持 pre_home_blog 表中 friend 字段的 5 个值:
0:全站用户可见
1:好友可见(检查 pre_home_friend 表)
2:指定好友可见
3:仅自己可见
4:密码可见(弹窗输入密码)
3.2 头像显示
使用 UCenter 接口:http://uc.sseuu.com/uc_server/avatar.php?uid={uid}&size=middle
备用方案:SVG 生成用户名首字母头像
3.3 第三侧窗(日志阅读器)
位置:覆盖主内容区域的一半宽度
样式:参照 md_log_manager.php 的 Markdown 渲染
内容类型自动检测:
树状图(含 ┣、┃、┗ 等字符)→ 等宽字体保留格式
HTML 内容 → 直接渲染(保留 、<a>、
标签)
Markdown 内容 → 使用 marked 解析
3.4 项目辅助模块
树形菜单:使用 DOM API 递归构建,支持多级展开/折叠
日志列表:从 simple_api.php 获取,显示权限状态标签(公开/好友/密码/我的)
参考日志选择:保存到 selectedBlogIds Map,发送消息时作为上下文
3.5 侧边栏切换
所有侧边栏支持点击打开/关闭切换
关闭时自动关闭其他面板
4. API 接口 4.1 ceshi02.php 路由(Discuz 环境) ask_question:AI 对话(流式响应)
get_history_titles:获取历史记录列表
load_conversation:加载历史对话内容
get_knowledge_list:获取虚拟人列表
select_knowledge:选择虚拟人
get_user_relations:获取用户关系(好友、群组等)
apply_Create:申请虚拟人创建
bind_Account:绑定已有账号
get_bind_requests:获取绑定申请列表
handle_bind_request:处理绑定申请
get_personal_profile / save_personal_profile:个人资料提示词
get_blog_content:获取日志内容(用于阅读器)
get_llm_list / select_llm:大语言模型列表与选择
4.2 simple_api.php(项目辅助专用) get_blog_categories_tree:获取分类树
get_blog_list_by_category:获取分类下的日志列表(含权限过滤)
get_blog_full_content:获取日志完整内容(含密码验证)
get_blog_titles_by_ids:批量获取日志标题
search_logs:搜索日志
4.3 search_api.php(独立搜索) 按关键词搜索日志
5. 全局状态管理 (appState) javascript window.appState = {
// 虚拟人相关 currentKnowledgeId, currentKnowledgeName, currentUsername, currentVirtualUid, currentWebsiteId, currentSelectedUniqueId, currentLoggedInUser, currentUserUid, // 对话相关 isNewConversation, conversationStatus, currentConversationId, currentConversationBlogid, isDeepThinking, isInitialLoad, currentLLMModule, // 项目辅助相关 selectedBlogIds: new Map(), currentLogsSidebar, currentSearchKeyword, currentReadingLog, currentLogsListData, currentCategoryId, currentCategoryName, // 其他 useIframeForDocuments, currentRequestType, uploadedFiles: new Map()
}; 6. 修复的关键问题 handleError is not defined:在 chat.js 中完善错误处理
convertHTMLToMarkdown 未定义:统一放到 utils.js
toggleCategory 未定义:统一放到 utils.js
startNewConversation 未定义:统一放到 utils.js
selectedBlogIds 重复声明:只在 config.js 中声明一次
项目辅助面板切换:使用 onclick 替代 addEventListener 避免覆盖
第三窗口头像:使用 UCenter 接口 + SVG 备用
树状图显示:检测特殊字符,使用等宽字体