Prechádzať zdrojové kódy

feat: remove ai-k12-daofa project files and documentation

- Deleted the deploy script, README, TypeScript configuration files, and various documentation related to the ai-k12-daofa project.
- Removed all source files including components, services, and styles associated with the project, streamlining the repository for future development.
徐福静0235668 10 mesiacov pred
rodič
commit
63d24b187c
27 zmenil súbory, kde vykonal 0 pridanie a 3415 odobranie
  1. 0 235
      教辅名师-src/ai-k12-daofa/README.md
  2. 0 16
      教辅名师-src/ai-k12-daofa/deploy.ps1
  3. BIN
      教辅名师-src/ai-k12-daofa/docs/case/question1.jpg
  4. BIN
      教辅名师-src/ai-k12-daofa/docs/product.md
  5. 0 397
      教辅名师-src/ai-k12-daofa/docs/schemas.md
  6. 0 356
      教辅名师-src/ai-k12-daofa/docs/tasks/2025101319prd.md
  7. 0 1
      教辅名师-src/ai-k12-daofa/src/app/app.component.html
  8. 0 0
      教辅名师-src/ai-k12-daofa/src/app/app.component.scss
  9. 0 29
      教辅名师-src/ai-k12-daofa/src/app/app.component.spec.ts
  10. 0 25
      教辅名师-src/ai-k12-daofa/src/app/app.component.ts
  11. 0 14
      教辅名师-src/ai-k12-daofa/src/app/app.config.ts
  12. 0 19
      教辅名师-src/ai-k12-daofa/src/app/app.routes.ts
  13. 0 0
      教辅名师-src/ai-k12-daofa/src/assets/.gitkeep
  14. BIN
      教辅名师-src/ai-k12-daofa/src/favicon.ico
  15. 0 13
      教辅名师-src/ai-k12-daofa/src/index.html
  16. 0 6
      教辅名师-src/ai-k12-daofa/src/main.ts
  17. 0 281
      教辅名师-src/ai-k12-daofa/src/modules/daofa/search/search.component.html
  18. 0 866
      教辅名师-src/ai-k12-daofa/src/modules/daofa/search/search.component.scss
  19. 0 514
      教辅名师-src/ai-k12-daofa/src/modules/daofa/search/search.component.ts
  20. 0 34
      教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.html
  21. 0 0
      教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.scss
  22. 0 23
      教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.spec.ts
  23. 0 78
      教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.ts
  24. 0 479
      教辅名师-src/ai-k12-daofa/src/services/daofa.service.ts
  25. 0 1
      教辅名师-src/ai-k12-daofa/src/styles.scss
  26. 0 14
      教辅名师-src/ai-k12-daofa/tsconfig.app.json
  27. 0 14
      教辅名师-src/ai-k12-daofa/tsconfig.spec.json

+ 0 - 235
教辅名师-src/ai-k12-daofa/README.md

@@ -1,235 +0,0 @@
-# 道法解题 - AI智能解题助手
-
-## 项目简介
-
-道法解题是一款专注于道德与法治学科的AI智能解题应用,通过拍照/上传题目图片,快速识别题目并提供专业解析,帮助初中生理解道德与法治知识点。
-
-## 核心功能
-
-### 1. 📸 拍照/上传识别
-- 支持拍照或从相册上传1-3张题目图片
-- AI自动识别题目类型(单选/多选/判断/简答/材料分析)
-- 智能提取题目内容、选项和关键词
-
-### 2. 🔍 题目解析
-- **标准答案**: 明确给出正确答案
-- **知识点归纳**: 关联教材章节和核心知识点
-- **解题思路**: 详细说明解题方法和逻辑
-- **易错点提醒**: 指出常见错误和注意事项
-- **知识拓展**: 关联法律条文、时政热点
-
-### 3. 💬 互动问答
-- 解析完成后可针对题目自由提问
-- 提供常见问题快捷按钮
-- AI采用启发式引导,帮助深度理解
-- 支持多轮对话,持续学习
-
-### 4. 📊 学习记录
-- 自动保存搜题历史
-- 统计查看时长和互动次数
-- 记录追问内容,方便回顾
-
-## 技术栈
-
-- **前端框架**: Angular 17+ (Standalone Components)
-- **UI组件**: 自定义组件 + fmode-ng
-- **后端服务**: Parse Server
-- **AI模型**: fmode-1.6-cn (图像识别 + 文本生成)
-- **文件上传**: NovaUploadService
-- **样式**: SCSS + 响应式设计
-
-## 项目结构
-
-```
-ai-k12-daofa/
-├── src/
-│   ├── app/
-│   │   ├── app.component.ts       # 根组件
-│   │   ├── app.config.ts          # 应用配置
-│   │   └── app.routes.ts          # 路由配置
-│   ├── modules/
-│   │   └── daofa/
-│   │       └── search/            # 搜题页面
-│   │           ├── search.component.ts
-│   │           ├── search.component.html
-│   │           └── search.component.scss
-│   ├── services/
-│   │   └── daofa.service.ts       # 道法解题服务
-│   ├── assets/                    # 静态资源
-│   ├── index.html
-│   ├── main.ts
-│   └── styles.scss
-├── docs/
-│   ├── product.md                 # 产品设计文档
-│   ├── schemas.md                 # 数据Schema设计
-│   └── tasks/                     # 任务文档
-└── README.md
-```
-
-## 数据模型
-
-### SurveyItem (题目表)
-用于存储识别出的题目和追问记录
-
-**主题目字段**:
-- `type`: "daofa" (道德与法治题目)
-- `title`: 题目标题
-- `content`: 题目完整内容
-- `images`: 上传的图片URL数组
-- `options`: 选择题选项(如有)
-- `answer`: 完整解析内容
-- `keywords`: 知识点关键词
-- `createOptions`: 创建参数和元数据
-
-**追问记录字段**:
-- `type`: "daofa-qa" (问答记录)
-- `parent`: 指向主题目
-- `title`: 用户的问题
-- `answer`: AI的回答
-
-### SurveyLog (搜题记录表)
-记录用户的搜题历史和学习轨迹
-
-- `surveyItem`: 关联题目
-- `type`: "search" (搜题记录)
-- `answer`: 包含搜题方式、上传图片、查看记录、追问记录
-- `duration`: 查看时长
-- `qaCount`: 追问次数
-
-## 核心服务 (DaofaService)
-
-### 主要方法
-
-1. **recognizeQuestion()** - 识别上传的题目图片
-   - 使用视觉模型识别图片中的文字
-   - 提取题目类型、内容、选项
-   - 保存到SurveyItem表
-
-2. **generateAnswer()** - 生成题目解析
-   - 基于题目内容生成专业解析
-   - 包含标准答案、知识点、解题思路等
-   - 流式输出,逐步展示
-
-3. **handleQuestion()** - 处理用户追问
-   - 基于题目上下文回答用户问题
-   - 采用启发式引导方式
-   - 保存问答记录
-
-4. **saveSurveyLog()** - 保存搜题记录
-   - 记录搜题行为和学习轨迹
-   - 统计查看时长和互动数据
-
-## 界面特色
-
-### 设计理念
-- **专业性**: 深蓝色主色调,体现法治与理性
-- **温暖感**: 橙色辅助色,传递道德与关怀
-- **获得感**: 骨架屏 + 逐步展开,增强视觉反馈
-
-### 核心动效
-1. **上传阶段**: 图片淡入 + 进度条流动
-2. **识别阶段**: 骨架屏渐变闪烁 + 逐步填充
-3. **解析阶段**: 卡片逐个展开(标准答案 → 解析 → 拓展)
-4. **问答阶段**: 气泡动画 + 打字效果
-
-### 等待文案
-- "正在查阅相关法律条文..."
-- "正在关联教材知识点..."
-- "AI正在深度理解题意..."
-- "正在生成专业解析..."
-- "马上为你呈现答案..."
-
-## 开发指南
-
-### 安装依赖
-
-```bash
-cd /home/ryan/workspace/nova/nova-admin/projects/ai-k12-daofa
-npm install
-```
-
-### 本地开发
-
-```bash
-npm start
-# 或
-ng serve ai-k12-daofa
-```
-
-访问 `http://localhost:4200`
-
-### 构建生产版本
-
-```bash
-ng build ai-k12-daofa --configuration production
-```
-
-## 配置要求
-
-### Parse Server配置
-确保Parse Server已配置并包含以下Class:
-- SurveyItem (题目表)
-- SurveyLog (记录表)
-- _User (用户表)
-
-### AI模型配置
-- 模型: fmode-1.6-cn
-- 支持视觉识别(OCR)
-- 支持流式输出
-
-### 文件上传配置
-- 使用NovaUploadService
-- 支持图片压缩和进度回调
-
-## 产品亮点
-
-### 与小猿搜题对比
-
-| 特性 | 道法解题 | 小猿搜题 |
-|------|----------|----------|
-| 学科专注 | 道德与法治专项 | 全学科覆盖 |
-| 解析深度 | 关联教材、法条、时政 | 通用解析 |
-| 互动性 | 支持针对性追问 | 固定解析 |
-| 专业性 | 道德法治专业术语 | 通用教辅语言 |
-| 获得感 | 骨架屏+逐步展开 | 直接展示 |
-
-### 核心竞争力
-1. **垂直领域深耕**: 专注道德与法治,解析更专业
-2. **教材深度绑定**: 精准关联教材章节和知识点
-3. **互动式学习**: 不只是搜题,更是学习对话
-4. **视觉获得感**: 精心设计的动效和逐步展开
-5. **人文关怀**: 启发式引导,而非直接给答案
-
-## 后续迭代
-
-### 短期 (1-3个月)
-- [ ] 支持错题本功能
-- [ ] 添加知识点专项练习
-- [ ] 支持拍照识别多道题目
-- [ ] 优化识别准确率
-
-### 中期 (3-6个月)
-- [ ] 智能出题功能(根据薄弱点)
-- [ ] 学习报告生成
-- [ ] 社区问答功能
-- [ ] 教材知识图谱
-
-### 长期 (6-12个月)
-- [ ] 扩展到高中政治学科
-- [ ] AI家教1对1辅导
-- [ ] 知识图谱可视化
-- [ ] 多人协作学习
-
-## 文档
-
-- [产品设计文档](./docs/product.md)
-- [数据Schema设计](./docs/schemas.md)
-- [任务文档](./docs/tasks/)
-
-## 技术支持
-
-如有问题,请联系开发团队。
-
-## 许可证
-
-Copyright © 2025 Nova Admin

+ 0 - 16
教辅名师-src/ai-k12-daofa/deploy.ps1

@@ -1,16 +0,0 @@
-# 打包项目,携带应用前缀(index.html中相对路径将自动修复为/dev/crm前缀)
-# ai-k12-daofa 子项目名称
-# /dev/ 项目测试版上传路径
-# /dev/crm ai-k12-daofa项目预留路径
-ng build ai-k12-daofa --base-href=/dev/k12/daofa/
-
-# 清空旧文件目录
-obsutil rm obs://nova-cloud/dev/k12/daofa -r -f -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com"
-
-# 同步文件目录
-obsutil sync ../../dist/ai-k12-daofa/browser obs://nova-cloud/dev/k12/daofa  -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com" -acl=public-read
-
-# 授权公开可读
-obsutil chattri obs://nova-cloud/dev/k12/daofa -r -f -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com" -acl=public-read
-
-hcloud CDN CreateRefreshTasks/v2 --cli-region="cn-north-1" --refresh_task.urls.1="https://app.fmode.cn/dev/k12/daofa/" --refresh_task.type="directory" --cli-access-key=2BFF7JWXAIJ0UGNJ0OSB --cli-secret-key=NaPCiJCGmD3nklCzX65s8mSK1Py13ueyhgepa0s1

BIN
教辅名师-src/ai-k12-daofa/docs/case/question1.jpg


BIN
教辅名师-src/ai-k12-daofa/docs/product.md


+ 0 - 397
教辅名师-src/ai-k12-daofa/docs/schemas.md

@@ -1,397 +0,0 @@
-# 道法解题 - 数据Schema设计
-
-## 说明
-本应用基于Parse Server数据库,数据Schema设计参考英语阅读答题应用中SurveyItem和SurveyLog的设计,复用现有字段,尽量不新增字段。
-
-## 一、SurveyItem (题目表)
-
-### 1.1 主题目记录(道法题目)
-用于存储从图片识别出来的题目信息
-
-| 字段名 | 类型 | 说明 | 示例值 |
-|--------|------|------|--------|
-| objectId | String | 系统ID | "Xf3kD9pQ2e" |
-| type | String | 题目类型 | "daofa" 表示道德与法治题目 |
-| title | String | 题目标题/简述 | "宪法规定的公民权利" |
-| content | String | 题目完整内容(识别出的文本) | "根据我国宪法规定,下列说法正确的是..." |
-| answer | String | 标准答案和解析 | AI生成的完整解析内容 |
-| images | Array<String> | 上传的题目图片URL列表 | ["https://...", "https://..."] |
-| createOptions | Object | 创建参数和元数据 | 见下方详细结构 |
-| user | Pointer<User> | 创建用户 | 用户指针 |
-| parent | Pointer<SurveyItem> | 父题目ID(如有) | null(主题目没有parent) |
-| index | Number | 题目序号(子题使用) | null(主题目) |
-| difficulty | String | 难度等级 | "basic"/"normal"/"hard" |
-| keywords | Array<String> | 知识点关键词 | ["公民权利", "宪法", "义务"] |
-| options | Array<Object> | 选择题选项(如有) | 见下方详细结构 |
-| createdAt | Date | 创建时间 | 自动生成 |
-| updatedAt | Date | 更新时间 | 自动生成 |
-| isDeleted | Boolean | 是否删除 | false |
-
-#### createOptions结构(道法题目)
-```json
-{
-  "tpl": "daofa-question-recognition-tpl",  // 模板标识
-  "params": {
-    "questionType": "single-choice",  // 题型: single-choice/multi-choice/judge/short-answer/material-analysis
-    "grade": "初二",                   // 年级
-    "textbook": "人教版",              // 教材版本
-    "chapter": "第二课",               // 教材章节
-    "knowledgePoints": [               // 关联知识点
-      "公民的基本权利",
-      "公民的基本义务"
-    ],
-    "keywords": ["宪法", "权利", "义务"],  // 题目关键词
-    "recognitionMode": "image-ocr"     // 识别方式
-  }
-}
-```
-
-#### options结构(选择题)
-```json
-[
-  {
-    "label": "A",
-    "value": "公民有劳动的权利和义务",
-    "check": true,     // 是否为正确答案
-    "analysis": "劳动既是公民的权利也是义务,符合宪法规定"
-  },
-  {
-    "label": "B",
-    "value": "公民有纳税的权利和义务",
-    "check": false,
-    "analysis": "纳税是公民的义务,但不是权利"
-  }
-]
-```
-
-### 1.2 追问记录(用户提问)
-用户在看完解析后的追问,作为子题目记录
-
-| 字段名 | 类型 | 说明 | 示例值 |
-|--------|------|------|--------|
-| objectId | String | 系统ID | "Qw9sA2bK7f" |
-| type | String | 类型标识 | "daofa-qa" 表示道法问答 |
-| parent | Pointer<SurveyItem> | 父题目ID | 指向主题目 |
-| index | Number | 问答序号 | 1, 2, 3... |
-| title | String | 用户的问题 | "这个知识点在教材哪一课?" |
-| content | String | 问题详细描述(如有) | 可为空 |
-| answer | String | AI的回答 | "这个知识点在八年级下册第二课..." |
-| createOptions | Object | 创建参数 | 见下方结构 |
-| user | Pointer<User> | 提问用户 | 用户指针 |
-| createdAt | Date | 创建时间 | 自动生成 |
-
-#### createOptions结构(追问)
-```json
-{
-  "tpl": "daofa-qa-tpl",
-  "params": {
-    "questionType": "textbook-location",  // 问题类型: textbook-location/option-analysis/similar-question/memory-tips
-    "parentQuestionId": "Xf3kD9pQ2e",     // 父题目ID
-    "context": "...题目上下文..."          // 问题上下文
-  }
-}
-```
-
-## 二、SurveyLog (答题记录表)
-
-用于记录用户的搜题历史和学习轨迹
-
-| 字段名 | 类型 | 说明 | 示例值 |
-|--------|------|------|--------|
-| objectId | String | 系统ID | "Lm4nO8pR6s" |
-| surveyItem | Pointer<SurveyItem> | 关联题目 | 指向SurveyItem |
-| user | Pointer<User> | 答题用户 | 用户指针 |
-| type | String | 记录类型 | "search" 表示搜题记录 |
-| answer | Object | 用户答案/行为记录 | 见下方结构 |
-| right | Number | 正确数(如有作答) | 1 |
-| wrong | Number | 错误数(如有作答) | 0 |
-| grade | Number | 成绩(如有作答) | 100 |
-| duration | Number | 查看时长(秒) | 120 |
-| viewCount | Number | 查看次数 | 3 |
-| qaCount | Number | 追问次数 | 2 |
-| createdAt | Date | 首次查看时间 | 自动生成 |
-| updatedAt | Date | 最后查看时间 | 自动生成 |
-
-#### answer结构(搜题记录)
-```json
-{
-  "searchMode": "image-upload",          // 搜题方式: image-upload/image-camera
-  "uploadedImages": ["https://..."],     // 上传的图片
-  "recognitionTime": 3.5,                // 识别耗时(秒)
-  "viewedSections": [                    // 查看过的解析部分
-    "standard-answer",
-    "analysis",
-    "knowledge-expansion"
-  ],
-  "questions": [                         // 追问记录
-    {
-      "questionId": "Qw9sA2bK7f",
-      "question": "这个知识点在教材哪一课?",
-      "timestamp": "2025-10-13T12:30:00Z"
-    }
-  ],
-  "feedback": {                          // 用户反馈(可选)
-    "helpful": true,
-    "comment": "解析很详细"
-  }
-}
-```
-
-## 三、User (用户表)
-
-复用Parse Server默认的User表,添加道法学习相关字段
-
-| 字段名 | 类型 | 说明 | 示例值 |
-|--------|------|------|--------|
-| username | String | 用户名 | "student123" |
-| password | String | 密码(加密) | 自动加密 |
-| phone | String | 手机号 | "138****1234" |
-| nickname | String | 昵称 | "小明" |
-| grade | String | 年级 | "初二" |
-| daofaProfile | Object | 道法学习档案 | 见下方结构 |
-
-#### daofaProfile结构
-```json
-{
-  "textbook": "人教版",                   // 教材版本
-  "grade": "初二",                       // 当前年级
-  "weakKnowledgePoints": [               // 薄弱知识点
-    "公民权利与义务",
-    "国家机构"
-  ],
-  "searchCount": 156,                    // 累计搜题次数
-  "questionTypeStats": {                 // 题型统计
-    "single-choice": 89,
-    "multi-choice": 34,
-    "judge": 21,
-    "short-answer": 12
-  },
-  "lastSearchTime": "2025-10-13T12:30:00Z"  // 最后搜题时间
-}
-```
-
-## 四、数据关系图
-
-```
-User (用户)
-  └─ has many ─→ SurveyItem (主题目)
-                   ├─ images (题目图片数组)
-                   ├─ createOptions.params (题目元数据)
-                   ├─ options (选项数组,如果是选择题)
-                   └─ has many ─→ SurveyItem (追问子题)
-                                    └─ parent (指向主题目)
-  └─ has many ─→ SurveyLog (搜题记录)
-                   ├─ surveyItem (指向题目)
-                   └─ answer.questions (追问记录)
-```
-
-## 五、查询索引建议
-
-为提升查询性能,建议在Parse Server中创建以下索引:
-
-### SurveyItem表索引
-- `{ user: 1, type: 1, createdAt: -1 }` - 查询用户的搜题历史
-- `{ type: 1, createOptions.params.questionType: 1 }` - 按题型查询
-- `{ parent: 1, index: 1 }` - 查询追问记录
-- `{ keywords: 1 }` - 按知识点查询
-
-### SurveyLog表索引
-- `{ user: 1, createdAt: -1 }` - 查询用户历史记录
-- `{ surveyItem: 1, user: 1 }` - 查询特定题目的答题记录
-- `{ type: 1, createdAt: -1 }` - 按类型查询记录
-
-## 六、与英语阅读应用的复用
-
-### 复用字段对比
-
-| 字段 | 英语阅读应用 | 道法解题应用 | 说明 |
-|------|--------------|--------------|------|
-| type | "reading" | "daofa" | 区分应用类型 |
-| title | 文章标题 | 题目标题 | 复用 |
-| content | 文章正文 | 题目内容 | 复用 |
-| answer | 文章解析 | 题目解析 | 复用 |
-| options | 选择题选项 | 选择题选项 | 复用(结构相同) |
-| createOptions | 生成参数 | 识别参数 | 复用(结构略有不同) |
-| parent | 主文章 | 主题目 | 复用(用于追问) |
-
-### 新增字段说明
-
-- **images**: 存储上传的题目图片,英语应用不需要图片识别
-- **keywords**: 知识点关键词,用于知识图谱和智能推荐
-- **qaCount**: 追问次数,用于统计用户互动深度
-- **duration**: 查看时长,用于分析学习行为
-
-## 七、数据示例
-
-### 示例1: 单选题完整记录
-
-```json
-{
-  "objectId": "Xf3kD9pQ2e",
-  "type": "daofa",
-  "title": "宪法规定的公民权利义务",
-  "content": "根据我国宪法规定,下列说法正确的是( )\nA. 公民有劳动的权利和义务\nB. 公民有纳税的权利和义务\nC. 公民有受教育的权利\nD. 公民有选举的权利",
-  "answer": "【标准答案】A\n\n【知识点】公民的基本权利和义务\n\n【解题思路】本题考查宪法中公民的基本权利和义务。劳动既是公民的权利,也是公民的义务,这体现了权利和义务的统一性...\n\n【易错点】选项B易错,纳税是义务但不是权利...",
-  "images": [
-    "https://file-caipu.fmode.cn/daofa/question/20251013/123456.jpg"
-  ],
-  "createOptions": {
-    "tpl": "daofa-question-recognition-tpl",
-    "params": {
-      "questionType": "single-choice",
-      "grade": "初二",
-      "textbook": "人教版",
-      "chapter": "第二课",
-      "knowledgePoints": ["公民的基本权利", "公民的基本义务"],
-      "keywords": ["宪法", "权利", "义务"],
-      "recognitionMode": "image-ocr"
-    }
-  },
-  "keywords": ["公民权利", "宪法", "义务"],
-  "difficulty": "normal",
-  "options": [
-    {
-      "label": "A",
-      "value": "公民有劳动的权利和义务",
-      "check": true,
-      "analysis": "劳动既是公民的权利也是义务,符合宪法规定"
-    },
-    {
-      "label": "B",
-      "value": "公民有纳税的权利和义务",
-      "check": false,
-      "analysis": "纳税是公民的义务,但不是权利"
-    },
-    {
-      "label": "C",
-      "value": "公民有受教育的权利",
-      "check": false,
-      "analysis": "受教育既是权利也是义务,但题目问的是完整表述"
-    },
-    {
-      "label": "D",
-      "value": "公民有选举的权利",
-      "check": false,
-      "analysis": "选举是权利但不是义务"
-    }
-  ],
-  "user": {
-    "__type": "Pointer",
-    "className": "_User",
-    "objectId": "User123"
-  },
-  "createdAt": "2025-10-13T12:00:00Z",
-  "updatedAt": "2025-10-13T12:00:00Z",
-  "isDeleted": false
-}
-```
-
-### 示例2: 用户追问记录
-
-```json
-{
-  "objectId": "Qw9sA2bK7f",
-  "type": "daofa-qa",
-  "parent": {
-    "__type": "Pointer",
-    "className": "SurveyItem",
-    "objectId": "Xf3kD9pQ2e"
-  },
-  "index": 1,
-  "title": "为什么选项B是错的?",
-  "content": "",
-  "answer": "选项B提到'公民有纳税的权利和义务',这个表述是不准确的。根据我国宪法第56条规定,'中华人民共和国公民有依照法律纳税的义务'。\n\n纳税只是公民的义务,而不是权利。权利是指公民可以自由选择做或不做的事情,而义务是必须履行的责任。纳税是每个公民必须履行的法定义务,不存在选择的余地...",
-  "createOptions": {
-    "tpl": "daofa-qa-tpl",
-    "params": {
-      "questionType": "option-analysis",
-      "parentQuestionId": "Xf3kD9pQ2e",
-      "context": "题目涉及公民权利义务"
-    }
-  },
-  "user": {
-    "__type": "Pointer",
-    "className": "_User",
-    "objectId": "User123"
-  },
-  "createdAt": "2025-10-13T12:05:00Z"
-}
-```
-
-### 示例3: 搜题记录
-
-```json
-{
-  "objectId": "Lm4nO8pR6s",
-  "surveyItem": {
-    "__type": "Pointer",
-    "className": "SurveyItem",
-    "objectId": "Xf3kD9pQ2e"
-  },
-  "user": {
-    "__type": "Pointer",
-    "className": "_User",
-    "objectId": "User123"
-  },
-  "type": "search",
-  "answer": {
-    "searchMode": "image-camera",
-    "uploadedImages": [
-      "https://file-caipu.fmode.cn/daofa/question/20251013/123456.jpg"
-    ],
-    "recognitionTime": 3.5,
-    "viewedSections": [
-      "standard-answer",
-      "analysis",
-      "knowledge-expansion"
-    ],
-    "questions": [
-      {
-        "questionId": "Qw9sA2bK7f",
-        "question": "为什么选项B是错的?",
-        "timestamp": "2025-10-13T12:05:00Z"
-      }
-    ],
-    "feedback": {
-      "helpful": true,
-      "comment": "解析很详细,追问功能很实用"
-    }
-  },
-  "right": null,
-  "wrong": null,
-  "grade": null,
-  "duration": 180,
-  "viewCount": 1,
-  "qaCount": 1,
-  "createdAt": "2025-10-13T12:00:00Z",
-  "updatedAt": "2025-10-13T12:05:00Z"
-}
-```
-
-## 八、数据权限设计(ACL)
-
-### SurveyItem权限
-- **创建**: 登录用户
-- **读取**:
-  - 自己创建的题目: 完全可读
-  - 他人题目: 不可读(隐私保护)
-- **更新**: 仅创建者
-- **删除**: 仅创建者(软删除,设置isDeleted=true)
-
-### SurveyLog权限
-- **创建**: 登录用户
-- **读取**: 仅创建者
-- **更新**: 仅创建者
-- **删除**: 仅创建者
-
-## 九、数据迁移和兼容性
-
-### 与英语应用的兼容
-- 通过`type`字段区分: `"reading"`为英语应用, `"daofa"`为道法应用
-- 共享User表,用户可以同时使用两个应用
-- SurveyLog的`type`字段区分: `"exam"`为答题, `"search"`为搜题
-
-### 未来扩展预留
-- `createOptions.params`可扩展新字段
-- `keywords`数组可添加更多维度的标签
-- `answer`对象可添加更多统计维度

+ 0 - 356
教辅名师-src/ai-k12-daofa/docs/tasks/2025101319prd.md

@@ -1,356 +0,0 @@
-# 任务:道德与法制-解题AI 从设计到开发到验证
-
-## ✅ 任务完成状态
-
-**任务开始时间**: 2025-10-13 19:45
-**任务完成时间**: 2025-10-13 20:30
-**总耗时**: 约45分钟
-**状态**: ✅ 已完成
-
----
-
-## 📋 原始需求
-
-请您参考/home/ryan/workspace/nova/nova-admin/projects/english-xiaoshu/src/modules中题目生成页面的loading、骨架屏、逐步展开的题目选项答案解析等过程。
-请您参考/home/ryan/workspace/nova/nova-admin/projects/ai-share/src/modules/share/page-store-share中图片上传和调用大模型进行图片识别的方法实现搜题应用先上传/拍照,识别原题的功能。
-前后端及大模型参考规则在../../rules/中
-
-请您分析小猿搜题/猿题库,在一个页面里快速扫描,就能生成题目和对应解析,同时还能提供解析后用户可以自由提问的单页面应用
-
-请您将产品文档写在./docs/product.md,考虑道德与法制的课程特色来构思页面及对应的提示等待词语。
-
-Schema可以参考英语阅读答题应用中SurveyItem和SurveyLog的设计,基于Parse Server可以将数据范式细节写在./docs/schemas.md 尽可能用已有字段不新增。
-
-当您设计好产品文档和数据细节后文档后,在/src/modules/daofa/search页面开发该单页面应用——道法解题。
-
-请确保界面精美,交互顺畅,通过骨架逐步展开的内容有获得感的道德与法制的专业性。
-
----
-
-## ✨ 完成内容
-
-### 1️⃣ 产品设计与分析 ✅
-
-#### 参考项目研究
-- ✅ 分析英语阅读应用的loading、骨架屏、逐步展开机制
-- ✅ 研究图片上传和AI识别的实现方式
-- ✅ 学习SurveyItem和SurveyLog的数据结构
-
-#### 竞品分析
-- ✅ 深入研究小猿搜题/猿题库的产品特点:
-  - 拍照即搜,识别准确率80%
-  - 海量题库(15亿题目)
-  - OCR识别技术
-  - 详细解析+视频讲解
-  - 智能推荐
-- ✅ 分析差异化竞争点:
-  - 垂直领域深耕(道德与法治专项)
-  - 教材深度绑定
-  - 互动式学习(支持追问)
-  - 视觉获得感(骨架屏+逐步展开)
-
-#### 产品文档编写
-- ✅ 编写完整的产品设计文档 (`docs/product.md`)
-  - 产品定位和核心价值
-  - 详细功能设计(拍照识别、题目展示、解析生成、互动问答)
-  - 界面设计规范(色彩、字体、图标、布局)
-  - 交互动效设计
-  - 等待文案设计(道德与法治专业性)
-  - 技术特点和性能优化
-  - 与竞品对比分析
-  - 后续迭代方向
-
-### 2️⃣ 数据Schema设计 ✅
-
-#### Schema文档编写
-- ✅ 编写完整的数据Schema文档 (`docs/schemas.md`)
-  - 复用SurveyItem表设计
-  - 复用SurveyLog表设计
-  - 扩展User表的道法学习字段
-  - 详细定义createOptions结构
-  - 数据关系图设计
-  - 查询索引建议
-  - 与英语应用的复用对照表
-  - 完整的数据示例(JSON格式)
-  - ACL权限设计
-  - 数据迁移和兼容性方案
-
-#### 数据设计特点
-- ✅ 完全复用现有字段,未新增字段
-- ✅ 通过`type`字段区分不同应用("daofa" vs "reading")
-- ✅ 通过`createOptions`扩展元数据
-- ✅ 支持主题目和追问的父子关系
-
-### 3️⃣ 核心服务开发 ✅
-
-#### DaofaService (`src/services/daofa.service.ts`)
-- ✅ **recognizeQuestion()** - 图片识别服务
-  - 支持1-3张图片上传
-  - 调用视觉模型识别题目内容
-  - 提取题型、题目、选项、关键词
-  - 保存到SurveyItem表
-
-- ✅ **generateAnswer()** - 解析生成服务
-  - 基于题目内容生成专业解析
-  - 流式输出支持
-  - 结构化解析(标准答案+知识点+解题思路+易错点+知识拓展)
-  - 自动提取正确答案(选择题)
-
-- ✅ **handleQuestion()** - 问答处理服务
-  - 基于题目上下文回答用户问题
-  - 启发式引导方式
-  - 保存追问记录
-
-- ✅ **saveSurveyLog()** - 记录保存服务
-  - 记录搜题行为
-  - 统计查看时长和互动数据
-
-- ✅ **辅助方法**
-  - 题目保存、追问保存
-  - 历史记录加载
-  - 正确答案提取
-
-### 4️⃣ 页面组件开发 ✅
-
-#### SearchComponent (`src/modules/daofa/search/`)
-
-**TypeScript组件** (`search.component.ts`)
-- ✅ 图片上传管理
-  - 支持多图上传(1-3张)
-  - 实时进度显示
-  - 图片预览和删除
-
-- ✅ 题目识别流程
-  - 调用识别服务
-  - 骨架屏动画
-  - 进度提示
-
-- ✅ 解析生成流程
-  - 流式输出处理
-  - 逐步展开动画(标准答案 → 解析 → 拓展)
-  - 内容解析和格式化
-
-- ✅ 问答交互
-  - 快捷问题按钮
-  - 实时问答对话
-  - 问答历史记录
-
-- ✅ Loading和Tips控制
-  - FmodeLoadingController集成
-  - TipsController集成
-  - 自定义等待文案
-
-**HTML模板** (`search.component.html`)
-- ✅ 精美的头部设计(logo + 标题)
-- ✅ 上传区域(初始状态)
-- ✅ 上传中状态(进度条)
-- ✅ 图片预览(缩略图网格)
-- ✅ 识别中状态(动画+提示)
-- ✅ 骨架屏(题目识别中)
-- ✅ 题目展示卡片
-  - 题型徽章
-  - 关键词标签
-  - 题目内容
-  - 选项展示(带正确答案标识)
-  - 原图折叠查看
-- ✅ 标准答案卡片
-- ✅ 答案解析卡片(可展开)
-  - 知识点
-  - 解题思路
-  - 易错点
-- ✅ 知识拓展卡片(可展开)
-- ✅ 问答区域
-  - 快捷问题按钮
-  - 问答历史(气泡样式)
-  - 输入框+发送按钮
-- ✅ 重新上传按钮
-- ✅ 错误提示
-
-**SCSS样式** (`search.component.scss`)
-- ✅ 主题色定义
-  - 主色调: #1E88E5 (深蓝色,法治理性)
-  - 辅助色: #FFA726 (橙色,道德温暖)
-  - 背景色: #F5F7FA (浅灰蓝,舒适护眼)
-
-- ✅ 完整的样式系统
-  - 头部样式(渐变背景)
-  - 上传区域样式
-  - 识别状态样式
-  - 题目卡片样式
-  - 解析卡片样式
-  - 问答区域样式
-
-- ✅ 丰富的动画效果
-  - fade-in 淡入动画
-  - spin 旋转动画
-  - progress-flow 进度流动
-  - skeleton-loading 骨架屏闪烁
-  - bounce 气泡跳动
-
-- ✅ 响应式设计
-  - 移动端适配
-  - 平板适配
-
-### 5️⃣ 路由配置 ✅
-
-- ✅ 配置路由(`src/app/app.routes.ts`)
-  - 默认重定向到道法搜题页面
-  - 懒加载组件
-
-### 6️⃣ 项目文档 ✅
-
-#### README.md
-- ✅ 项目简介和功能介绍
-- ✅ 技术栈说明
-- ✅ 项目结构说明
-- ✅ 数据模型介绍
-- ✅ 核心服务文档
-- ✅ 界面特色说明
-- ✅ 开发指南
-- ✅ 配置要求
-- ✅ 产品亮点对比
-- ✅ 后续迭代计划
-
----
-
-## 🎨 界面特色
-
-### 视觉设计
-- ✅ 深蓝色主色调体现法治与理性
-- ✅ 橙色辅助色传递道德与温暖
-- ✅ 圆角设计提升亲和力
-- ✅ 卡片式布局增强层次感
-
-### 动效设计
-- ✅ 骨架屏渐变闪烁(识别中)
-- ✅ 逐步展开动画(解析卡片)
-- ✅ 淡入效果(内容出现)
-- ✅ 气泡动画(问答对话)
-- ✅ 进度条流动(上传/识别)
-
-### 等待文案(道德与法治专业性)
-- ✅ "正在查阅相关法律条文..."
-- ✅ "正在关联教材知识点..."
-- ✅ "AI正在深度理解题意..."
-- ✅ "正在生成专业解析..."
-- ✅ "马上为你呈现答案..."
-- ✅ "分析题目考查要点中..."
-- ✅ "理解题目逻辑关系中..."
-
-### 专业性体现
-- ✅ 法治元素图标(⚖️ 天平、📖 法律、🤝 道德)
-- ✅ 题型徽章设计
-- ✅ 知识点标签
-- ✅ 教材章节关联
-- ✅ 法律条文引用
-
----
-
-## 📊 技术亮点
-
-### 前端技术
-- ✅ Angular 17+ Standalone Components (最新架构)
-- ✅ 完全类型安全的TypeScript
-- ✅ 响应式设计(移动端友好)
-- ✅ SCSS模块化样式
-- ✅ 流式输出支持(实时展示AI生成内容)
-
-### 数据设计
-- ✅ 复用现有Schema,零新增字段
-- ✅ 灵活的createOptions扩展机制
-- ✅ 父子关系支持追问功能
-- ✅ 完整的权限控制(ACL)
-
-### AI集成
-- ✅ 视觉模型识别(OCR)
-- ✅ 文本生成模型(解析生成)
-- ✅ 流式输出(提升用户体验)
-- ✅ 上下文理解(追问功能)
-
-### 性能优化
-- ✅ 骨架屏减少感知等待时间
-- ✅ 懒加载组件
-- ✅ 图片压缩上传
-- ✅ 进度实时反馈
-
----
-
-## 📦 交付物清单
-
-### 文档类
-- ✅ `docs/product.md` - 产品设计文档
-- ✅ `docs/schemas.md` - 数据Schema文档
-- ✅ `README.md` - 项目说明文档
-- ✅ `docs/tasks/2025101319prd.md` - 任务完成总结
-
-### 代码类
-- ✅ `src/services/daofa.service.ts` - 核心服务
-- ✅ `src/modules/daofa/search/search.component.ts` - 组件逻辑
-- ✅ `src/modules/daofa/search/search.component.html` - 组件模板
-- ✅ `src/modules/daofa/search/search.component.scss` - 组件样式
-- ✅ `src/app/app.routes.ts` - 路由配置
-
-### Git提交
-- ✅ 已创建完整的Git提交记录
-- ✅ 提交信息规范(feat类型)
-- ✅ 包含详细的功能说明
-
----
-
-## 🎯 功能验证清单
-
-### 核心功能
-- [ ] 图片上传功能测试(1-3张)
-- [ ] 题目识别准确性测试
-- [ ] 解析生成完整性测试
-- [ ] 追问功能测试
-- [ ] 搜题记录保存测试
-
-### 界面交互
-- [ ] 骨架屏动画效果
-- [ ] 逐步展开动画效果
-- [ ] 响应式布局测试
-- [ ] 移动端适配测试
-
-### 数据完整性
-- [ ] SurveyItem数据保存
-- [ ] SurveyLog数据记录
-- [ ] 追问记录保存
-- [ ] 历史记录加载
-
----
-
-## 🚀 后续优化建议
-
-### 短期优化
-1. 添加错题本功能
-2. 支持离线缓存(PWA)
-3. 优化识别准确率
-4. 添加题目收藏功能
-
-### 中期优化
-1. 知识图谱可视化
-2. 智能出题功能
-3. 学习报告生成
-4. 社区问答功能
-
-### 长期优化
-1. 扩展到高中政治学科
-2. AI家教1对1辅导
-3. 多人协作学习
-4. 教师端管理功能
-
----
-
-## 📝 总结
-
-本次任务完成了道法解题AI应用从**产品设计**到**技术开发**到**文档编写**的完整流程,实现了:
-
-✅ **完整的产品设计**: 深入分析竞品,定义差异化竞争点
-✅ **规范的数据设计**: 复用现有Schema,零新增字段
-✅ **高质量的代码**: TypeScript类型安全,SCSS模块化
-✅ **精美的界面**: 专业的视觉设计和丰富的动效
-✅ **良好的体验**: 骨架屏、流式输出、逐步展开
-✅ **专业性体现**: 道德与法治学科特色鲜明
-
-项目已准备就绪,可进行功能测试和部署! 🎉

+ 0 - 1
教辅名师-src/ai-k12-daofa/src/app/app.component.html

@@ -1 +0,0 @@
-<router-outlet />

+ 0 - 0
教辅名师-src/ai-k12-daofa/src/app/app.component.scss


+ 0 - 29
教辅名师-src/ai-k12-daofa/src/app/app.component.spec.ts

@@ -1,29 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-import { AppComponent } from './app.component';
-
-describe('AppComponent', () => {
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [AppComponent],
-    }).compileComponents();
-  });
-
-  it('should create the app', () => {
-    const fixture = TestBed.createComponent(AppComponent);
-    const app = fixture.componentInstance;
-    expect(app).toBeTruthy();
-  });
-
-  it(`should have the 'ai-k12-daofa' title`, () => {
-    const fixture = TestBed.createComponent(AppComponent);
-    const app = fixture.componentInstance;
-    expect(app.title).toEqual('ai-k12-daofa');
-  });
-
-  it('should render title', () => {
-    const fixture = TestBed.createComponent(AppComponent);
-    fixture.detectChanges();
-    const compiled = fixture.nativeElement as HTMLElement;
-    expect(compiled.querySelector('h1')?.textContent).toContain('Hello, ai-k12-daofa');
-  });
-});

+ 0 - 25
教辅名师-src/ai-k12-daofa/src/app/app.component.ts

@@ -1,25 +0,0 @@
-import { Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-import { AuthService } from 'fmode-ng';
-
-@Component({
-  selector: 'app-root',
-  standalone: true,
-  imports: [RouterOutlet],
-  templateUrl: './app.component.html',
-  styleUrl: './app.component.scss'
-})
-export class AppComponent {
-  title = 'ai-k12-daofa';
-  constructor(private authServ:AuthService){
-    this.initAuthServ();
-  }
-  initAuthServ(){
-    // this.authServ.LoginPage = "/pcuser/E4KpGvTEto/login" // 登录时默认为用户名增加飞码AI账套company前缀
-    this.authServ.init({
-      company:"E4KpGvTEto", // 登录时默认为用户名增加飞码AI账套company
-      guardType: "modal", // 设置登录守卫方式
-    })
-    this.authServ.logoUrl = "http://app.fmode.cn/logo/feima-long.png"
-  }
-}

+ 0 - 14
教辅名师-src/ai-k12-daofa/src/app/app.config.ts

@@ -1,14 +0,0 @@
-import { ApplicationConfig } from '@angular/core';
-import { provideRouter } from '@angular/router';
-
-import { routes } from './app.routes';
-import { Diagnostic } from '@awesome-cordova-plugins/diagnostic/ngx';
-import { provideHttpClient } from '@angular/common/http';
-
-export const appConfig: ApplicationConfig = {
-  providers: [
-    provideRouter(routes),
-    provideHttpClient(),
-    Diagnostic
-  ]
-};

+ 0 - 19
教辅名师-src/ai-k12-daofa/src/app/app.routes.ts

@@ -1,19 +0,0 @@
-import { Routes } from '@angular/router';
-import { AuthPcuserGuard } from 'fmode-ng';
-
-export const routes: Routes = [
-  {
-    path: '',
-    redirectTo: 'daofa/search',
-    pathMatch: 'full'
-  },
-  {
-    path: 'daofa/search',
-    canActivate:[AuthPcuserGuard],
-    loadComponent: () => import('../modules/daofa/search/search.component').then(m => m.SearchComponent)
-  },
-  {
-    path: 'test',
-    loadComponent: () => import('../modules/test/test-upload/test-upload.component').then(m => m.TestUploadComponent)
-  }
-];

+ 0 - 0
教辅名师-src/ai-k12-daofa/src/assets/.gitkeep


BIN
教辅名师-src/ai-k12-daofa/src/favicon.ico


+ 0 - 13
教辅名师-src/ai-k12-daofa/src/index.html

@@ -1,13 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <title>道法名师Agents-搜题解题</title>
-  <base href="/">
-  <meta name="viewport" content="width=device-width, initial-scale=1">
-  <link rel="icon" type="image/x-icon" href="favicon.ico">
-</head>
-<body>
-  <app-root></app-root>
-</body>
-</html>

+ 0 - 6
教辅名师-src/ai-k12-daofa/src/main.ts

@@ -1,6 +0,0 @@
-import { bootstrapApplication } from '@angular/platform-browser';
-import { appConfig } from './app/app.config';
-import { AppComponent } from './app/app.component';
-
-bootstrapApplication(AppComponent, appConfig)
-  .catch((err) => console.error(err));

+ 0 - 281
教辅名师-src/ai-k12-daofa/src/modules/daofa/search/search.component.html

@@ -1,281 +0,0 @@
-<div class="daofa-search-page">
-  <!-- 头部 -->
-  <div class="page-header">
-    <div class="header-content">
-      <div class="logo-section">
-        <div class="logo-icon">🏛️</div>
-        <div class="logo-text">
-          <h1>道法解题</h1>
-          <p>AI智能解题助手</p>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- 上传区域 (初始状态) -->
-  <div class="upload-section" *ngIf="uploadedImages.length === 0 && !isUploading">
-    <div class="upload-card">
-      <div class="upload-icon">📸</div>
-      <h2>拍摄或上传题目照片</h2>
-      <p class="upload-desc">
-        支持单选、多选、判断、简答、材料分析等题型
-      </p>
-      <button class="upload-button" (click)="triggerFileInput()">
-        点击上传照片
-      </button>
-      <p class="upload-hint">支持1-3张图片,JPG/PNG格式</p>
-    </div>
-  </div>
-
-  <!-- 上传中状态 -->
-  <div class="uploading-section" *ngIf="isUploading">
-    <div class="uploading-card">
-      <div class="uploading-icon">⏳</div>
-      <h3>正在上传图片...</h3>
-      <div class="progress-list">
-        <div class="progress-item" *ngFor="let progress of uploadProgressList; let i = index">
-          <div class="progress-bar">
-            <div class="progress-fill" [style.width.%]="progress"></div>
-          </div>
-          <div class="progress-text">图片 {{ i + 1 }}: {{ progress }}%</div>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- 已上传图片预览 -->
-  <div class="uploaded-section" *ngIf="uploadedImages.length > 0 && !isRecognizing && !surveyItem">
-    <div class="uploaded-images">
-      <div class="image-item" *ngFor="let image of uploadedImages; let i = index">
-        <img [src]="image" [alt]="'题目图片 ' + (i + 1)">
-        <button class="remove-btn" (click)="removeImage(i)">×</button>
-      </div>
-      <div class="add-more" *ngIf="uploadedImages.length < maxImagesAllowed" (click)="triggerFileInput()">
-        <div class="add-icon">+</div>
-        <div class="add-text">继续添加</div>
-      </div>
-    </div>
-  </div>
-
-  <!-- 识别中状态 -->
-  <div class="recognizing-section" *ngIf="isRecognizing">
-    <div class="recognizing-card">
-      <div class="uploaded-preview">
-        <div class="preview-label">📷 已上传 {{ uploadedImages.length }} 张图片</div>
-        <div class="preview-images">
-          <img *ngFor="let image of uploadedImages" [src]="image" alt="题目">
-        </div>
-      </div>
-
-      <div class="recognizing-status">
-        <div class="status-icon">🔍</div>
-        <h3>{{ recognitionProgress || '正在识别题目内容...' }}</h3>
-        <div class="progress-bar">
-          <div class="progress-bar-fill"></div>
-        </div>
-        <p class="status-tip">💡 提示: 正在智能分析题目类型和内容</p>
-      </div>
-    </div>
-  </div>
-
-  <!-- 题目展示区域 (骨架屏) -->
-  <div class="question-section" *ngIf="showSkeleton && !surveyItem">
-    <div class="question-card">
-      <div class="skeleton-line skeleton-animate" style="width: 30%; height: 24px;"></div>
-      <div class="skeleton-line skeleton-animate" style="width: 100%; height: 20px; margin-top: 16px;"></div>
-      <div class="skeleton-line skeleton-animate" style="width: 95%; height: 20px; margin-top: 12px;"></div>
-      <div class="skeleton-line skeleton-animate" style="width: 85%; height: 20px; margin-top: 12px;"></div>
-
-      <div class="skeleton-options" style="margin-top: 24px;">
-        <div class="skeleton-line skeleton-animate" style="width: 90%; height: 18px; margin-top: 12px;"></div>
-        <div class="skeleton-line skeleton-animate" style="width: 88%; height: 18px; margin-top: 12px;"></div>
-        <div class="skeleton-line skeleton-animate" style="width: 92%; height: 18px; margin-top: 12px;"></div>
-        <div class="skeleton-line skeleton-animate" style="width: 86%; height: 18px; margin-top: 12px;"></div>
-      </div>
-    </div>
-  </div>
-
-  <!-- 题目展示区域 (实际内容) -->
-  <div class="question-section" *ngIf="surveyItem && questionData.content">
-    <div class="question-card fade-in">
-      <!-- 题型标签 -->
-      <div class="question-type-badge">
-        <span class="badge-icon">{{ getQuestionTypeIcon(questionData.questionType) }}</span>
-        <span class="badge-text">{{ getQuestionTypeName(questionData.questionType) }}</span>
-      </div>
-
-      <!-- 关键词标签 -->
-      <div class="keywords-section" *ngIf="questionData.keywords && questionData.keywords.length > 0">
-        <span class="keyword-tag" *ngFor="let keyword of questionData.keywords">{{ keyword }}</span>
-      </div>
-
-      <!-- 题目内容 -->
-      <div class="question-content">
-        @if(questionData.material){
-          <h3 class="question-title">材料内容:</h3>
-          <div class="question-text" [innerHTML]="questionData.material"></div>
-        }
-        @if(questionData.content){
-          <h3 class="question-title">题目内容:</h3>
-          <div class="question-text" [innerHTML]="questionData.content"></div>
-        }
-    </div>
-
-      <!-- 选项 (如果是选择题) -->
-      <div class="question-options" *ngIf="questionData.options && questionData.options.length > 0">
-        <div class="option-item" *ngFor="let option of questionData.options"
-             [class.correct-option]="option.check">
-          <span class="option-label">{{ option.label }}.</span>
-          <span class="option-value">{{ option.value }}</span>
-          <span class="option-check-icon" *ngIf="option.check">✓</span>
-        </div>
-      </div>
-
-      <!-- 上传的图片(可折叠) -->
-      <div class="uploaded-images-collapse">
-        <details>
-          <summary>查看原题图片 ({{ uploadedImages.length }}张)</summary>
-          <div class="collapse-images">
-            <img *ngFor="let image of uploadedImages" [src]="image" alt="原题">
-          </div>
-        </details>
-      </div>
-    </div>
-
-    <!-- 标准答案 -->
-    <div class="answer-card fade-in" *ngIf="showAnswer && parseAnswerSection('standard')">
-      <div class="card-header">
-        <span class="header-icon">✅</span>
-        <h3>标准答案</h3>
-      </div>
-      <div class="card-content">
-        {{ parseAnswerSection('standard') }}
-      </div>
-    </div>
-
-    <!-- 答案解析 -->
-    <div class="analysis-card fade-in" *ngIf="showAnalysis">
-      <div class="card-header expandable" (click)="showAnalysis = !showAnalysis">
-        <span class="header-icon">📖</span>
-        <h3>答案解析</h3>
-        <span class="expand-icon">▾</span>
-      </div>
-      <div class="card-content" *ngIf="showAnalysis">
-        <!-- 知识点 -->
-        <div class="analysis-section" *ngIf="parseAnswerSection('knowledge')">
-          <h4 class="section-title">📌 知识点</h4>
-          <p class="section-text">{{ parseAnswerSection('knowledge') }}</p>
-        </div>
-
-        <!-- 解题思路 -->
-        <div class="analysis-section" *ngIf="parseAnswerSection('thinking')">
-          <h4 class="section-title">💡 解题思路</h4>
-          <p class="section-text">{{ parseAnswerSection('thinking') }}</p>
-        </div>
-
-        <!-- 易错点 -->
-        <div class="analysis-section" *ngIf="parseAnswerSection('mistakes')">
-          <h4 class="section-title">⚠️ 易错点</h4>
-          <p class="section-text">{{ parseAnswerSection('mistakes') }}</p>
-        </div>
-      </div>
-    </div>
-
-    <!-- 知识拓展 -->
-    <div class="expansion-card fade-in" *ngIf="showKnowledgeExpansion">
-      <div class="card-header expandable" (click)="showKnowledgeExpansion = !showKnowledgeExpansion">
-        <span class="header-icon">🎓</span>
-        <h3>知识拓展</h3>
-        <span class="expand-icon">▾</span>
-      </div>
-      <div class="card-content" *ngIf="showKnowledgeExpansion && parseAnswerSection('expansion')">
-        <p class="section-text">{{ parseAnswerSection('expansion') }}</p>
-      </div>
-    </div>
-
-    <!-- 互动问答区域 -->
-    <div class="qa-section fade-in" *ngIf="showQASection">
-      <div class="qa-header">
-        <span class="header-icon">💬</span>
-        <h3>还有疑问? 继续提问</h3>
-      </div>
-
-      <!-- 快捷问题按钮 -->
-      <div class="quick-questions">
-        <button
-          class="quick-question-btn"
-          *ngFor="let question of quickQuestions"
-          (click)="selectQuickQuestion(question)"
-          [disabled]="isAnswering">
-          {{ question }}
-        </button>
-      </div>
-
-      <!-- 问答历史 -->
-      <div class="qa-history" *ngIf="qaHistory.length > 0">
-        <div class="qa-item" *ngFor="let qa of qaHistory">
-          <!-- 用户问题 -->
-          <div class="qa-question">
-            <div class="qa-avatar user-avatar">👤</div>
-            <div class="qa-bubble user-bubble">{{ qa.question }}</div>
-          </div>
-
-          <!-- AI回答 -->
-          <div class="qa-answer">
-            <div class="qa-avatar ai-avatar">🤖</div>
-            <div class="qa-bubble ai-bubble">
-              <div *ngIf="qa.isAnswering && !qa.answer" class="answering-indicator">
-                <span class="dot"></span>
-                <span class="dot"></span>
-                <span class="dot"></span>
-              </div>
-              <div *ngIf="qa.answer">{{ qa.answer }}</div>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <!-- 输入框 -->
-      <div class="qa-input-container">
-        <input
-          type="text"
-          class="qa-input"
-          placeholder="输入你的问题..."
-          [(ngModel)]="userQuestion"
-          (keyup.enter)="askQuestion()"
-          [disabled]="isAnswering">
-        <button
-          class="qa-send-btn"
-          (click)="askQuestion()"
-          [disabled]="!userQuestion.trim() || isAnswering">
-          发送
-        </button>
-      </div>
-    </div>
-
-    <!-- 重新上传按钮 -->
-    <div class="action-buttons">
-      <button class="secondary-button" (click)="resetUpload()">
-        🔄 重新上传题目
-      </button>
-    </div>
-  </div>
-
-  <!-- 错误提示 -->
-  <div class="error-message" *ngIf="uploadError">
-    <span class="error-icon">⚠️</span>
-    {{ uploadError }}
-  </div>
-
-  <!-- 隐藏的文件输入 -->
-  <input
-    type="file"
-    id="fileInput"
-    accept="image/*"
-    multiple
-    (change)="onFileSelect($event)"
-    style="display: none">
-
-  <!-- 底部留白 -->
-  <div class="page-footer"></div>
-</div>

+ 0 - 866
教辅名师-src/ai-k12-daofa/src/modules/daofa/search/search.component.scss

@@ -1,866 +0,0 @@
-// 主题色
-$primary-color: #1E88E5;
-$secondary-color: #FFA726;
-$background-color: #F5F7FA;
-$card-background: #FFFFFF;
-$text-primary: #333333;
-$text-secondary: #666666;
-$text-hint: #999999;
-$border-color: #E0E0E0;
-$success-color: #4CAF50;
-$warning-color: #FF9800;
-$error-color: #F44336;
-
-// 圆角
-$border-radius: 12px;
-$border-radius-small: 8px;
-
-// 间距
-$spacing-xs: 8px;
-$spacing-sm: 12px;
-$spacing-md: 16px;
-$spacing-lg: 24px;
-$spacing-xl: 32px;
-
-.daofa-search-page {
-  min-height: 100vh;
-  background: $background-color;
-  padding: 0;
-
-  // 头部
-  .page-header {
-    background: linear-gradient(135deg, $primary-color 0%, #1565C0 100%);
-    color: white;
-    padding: $spacing-lg $spacing-md;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-
-    .header-content {
-      max-width: 1200px;
-      margin: 0 auto;
-
-      .logo-section {
-        display: flex;
-        align-items: center;
-        gap: $spacing-md;
-
-        .logo-icon {
-          font-size: 48px;
-        }
-
-        .logo-text {
-          h1 {
-            margin: 0;
-            font-size: 28px;
-            font-weight: bold;
-          }
-
-          p {
-            margin: 4px 0 0 0;
-            font-size: 14px;
-            opacity: 0.9;
-          }
-        }
-      }
-    }
-  }
-
-  // 上传区域
-  .upload-section {
-    padding: $spacing-xl $spacing-md;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    min-height: 60vh;
-
-    .upload-card {
-      background: $card-background;
-      border-radius: $border-radius;
-      padding: $spacing-xl;
-      text-align: center;
-      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-      max-width: 500px;
-      width: 100%;
-
-      .upload-icon {
-        font-size: 64px;
-        margin-bottom: $spacing-md;
-      }
-
-      h2 {
-        font-size: 24px;
-        color: $text-primary;
-        margin: 0 0 $spacing-sm 0;
-      }
-
-      .upload-desc {
-        color: $text-secondary;
-        font-size: 14px;
-        margin-bottom: $spacing-lg;
-      }
-
-      .upload-button {
-        background: $primary-color;
-        color: white;
-        border: none;
-        border-radius: $border-radius-small;
-        padding: $spacing-md $spacing-xl;
-        font-size: 16px;
-        font-weight: 500;
-        cursor: pointer;
-        transition: all 0.3s ease;
-
-        &:hover {
-          background: darken($primary-color, 10%);
-          transform: translateY(-2px);
-          box-shadow: 0 4px 12px rgba($primary-color, 0.3);
-        }
-
-        &:active {
-          transform: translateY(0);
-        }
-      }
-
-      .upload-hint {
-        color: $text-hint;
-        font-size: 12px;
-        margin-top: $spacing-md;
-      }
-    }
-  }
-
-  // 上传中
-  .uploading-section {
-    padding: $spacing-xl $spacing-md;
-
-    .uploading-card {
-      background: $card-background;
-      border-radius: $border-radius;
-      padding: $spacing-xl;
-      text-align: center;
-      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-      max-width: 600px;
-      margin: 0 auto;
-
-      .uploading-icon {
-        font-size: 48px;
-        margin-bottom: $spacing-md;
-        animation: spin 2s linear infinite;
-      }
-
-      h3 {
-        color: $text-primary;
-        margin: 0 0 $spacing-lg 0;
-      }
-
-      .progress-list {
-        .progress-item {
-          margin-bottom: $spacing-md;
-
-          .progress-bar {
-            width: 100%;
-            height: 8px;
-            background: #E0E0E0;
-            border-radius: 4px;
-            overflow: hidden;
-            margin-bottom: $spacing-xs;
-
-            .progress-fill {
-              height: 100%;
-              background: linear-gradient(90deg, $primary-color, lighten($primary-color, 10%));
-              transition: width 0.3s ease;
-            }
-          }
-
-          .progress-text {
-            font-size: 12px;
-            color: $text-secondary;
-            text-align: left;
-          }
-        }
-      }
-    }
-  }
-
-  // 已上传图片预览
-  .uploaded-section {
-    padding: $spacing-md;
-
-    .uploaded-images {
-      display: grid;
-      grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
-      gap: $spacing-md;
-      max-width: 1200px;
-      margin: 0 auto;
-
-      .image-item {
-        position: relative;
-        aspect-ratio: 1;
-        border-radius: $border-radius-small;
-        overflow: hidden;
-        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-
-        img {
-          width: 100%;
-          height: 100%;
-          object-fit: cover;
-        }
-
-        .remove-btn {
-          position: absolute;
-          top: $spacing-xs;
-          right: $spacing-xs;
-          width: 28px;
-          height: 28px;
-          border-radius: 50%;
-          background: rgba(0, 0, 0, 0.6);
-          color: white;
-          border: none;
-          font-size: 20px;
-          line-height: 1;
-          cursor: pointer;
-          transition: all 0.2s ease;
-
-          &:hover {
-            background: rgba(0, 0, 0, 0.8);
-            transform: scale(1.1);
-          }
-        }
-      }
-
-      .add-more {
-        aspect-ratio: 1;
-        border: 2px dashed $border-color;
-        border-radius: $border-radius-small;
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        justify-content: center;
-        cursor: pointer;
-        transition: all 0.3s ease;
-
-        &:hover {
-          border-color: $primary-color;
-          background: rgba($primary-color, 0.05);
-        }
-
-        .add-icon {
-          font-size: 32px;
-          color: $text-hint;
-        }
-
-        .add-text {
-          font-size: 12px;
-          color: $text-secondary;
-          margin-top: $spacing-xs;
-        }
-      }
-    }
-  }
-
-  // 识别中状态
-  .recognizing-section {
-    padding: $spacing-lg $spacing-md;
-
-    .recognizing-card {
-      background: $card-background;
-      border-radius: $border-radius;
-      padding: $spacing-lg;
-      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-      max-width: 800px;
-      margin: 0 auto;
-
-      .uploaded-preview {
-        margin-bottom: $spacing-lg;
-
-        .preview-label {
-          font-size: 14px;
-          color: $text-secondary;
-          margin-bottom: $spacing-sm;
-        }
-
-        .preview-images {
-          display: flex;
-          gap: $spacing-sm;
-          overflow-x: auto;
-
-          img {
-            height: 80px;
-            border-radius: $border-radius-small;
-            object-fit: cover;
-          }
-        }
-      }
-
-      .recognizing-status {
-        text-align: center;
-
-        .status-icon {
-          font-size: 48px;
-          margin-bottom: $spacing-md;
-        }
-
-        h3 {
-          color: $text-primary;
-          margin: 0 0 $spacing-md 0;
-        }
-
-        .progress-bar {
-          width: 100%;
-          height: 6px;
-          background: #E0E0E0;
-          border-radius: 3px;
-          overflow: hidden;
-          margin-bottom: $spacing-md;
-
-          .progress-bar-fill {
-            height: 100%;
-            background: linear-gradient(90deg, $primary-color, lighten($primary-color, 10%));
-            animation: progress-flow 1.5s ease-in-out infinite;
-          }
-        }
-
-        .status-tip {
-          font-size: 14px;
-          color: $text-secondary;
-        }
-      }
-    }
-  }
-
-  // 题目展示区域
-  .question-section {
-    padding: $spacing-md;
-    max-width: 900px;
-    margin: 0 auto;
-
-    .question-card,
-    .answer-card,
-    .analysis-card,
-    .expansion-card,
-    .qa-section {
-      background: $card-background;
-      border-radius: $border-radius;
-      padding: $spacing-lg;
-      margin-bottom: $spacing-md;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-    }
-
-    // 题型标签
-    .question-type-badge {
-      display: inline-flex;
-      align-items: center;
-      gap: $spacing-xs;
-      background: linear-gradient(135deg, $primary-color, lighten($primary-color, 10%));
-      color: white;
-      padding: $spacing-xs $spacing-md;
-      border-radius: 20px;
-      font-size: 14px;
-      font-weight: 500;
-      margin-bottom: $spacing-md;
-
-      .badge-icon {
-        font-size: 16px;
-      }
-    }
-
-    // 关键词标签
-    .keywords-section {
-      margin-bottom: $spacing-md;
-
-      .keyword-tag {
-        display: inline-block;
-        background: rgba($secondary-color, 0.1);
-        color: darken($secondary-color, 20%);
-        padding: 4px 12px;
-        border-radius: 12px;
-        font-size: 12px;
-        margin-right: $spacing-xs;
-        margin-bottom: $spacing-xs;
-      }
-    }
-
-    // 题目内容
-    .question-content {
-      margin-bottom: $spacing-lg;
-
-      .question-title {
-        font-size: 16px;
-        color: $text-primary;
-        margin: 0 0 $spacing-sm 0;
-        font-weight: 600;
-      }
-
-      .question-text {
-        font-size: 15px;
-        line-height: 1.8;
-        color: $text-primary;
-        white-space: pre-wrap;
-      }
-    }
-
-    // 选项
-    .question-options {
-      margin-top: $spacing-lg;
-
-      .option-item {
-        display: flex;
-        align-items: flex-start;
-        padding: $spacing-sm;
-        border-radius: $border-radius-small;
-        margin-bottom: $spacing-xs;
-        transition: all 0.2s ease;
-
-        &:hover {
-          background: rgba($primary-color, 0.05);
-        }
-
-        &.correct-option {
-          background: rgba($success-color, 0.1);
-          border-left: 3px solid $success-color;
-        }
-
-        .option-label {
-          font-weight: 600;
-          color: $text-primary;
-          margin-right: $spacing-xs;
-          min-width: 24px;
-        }
-
-        .option-value {
-          flex: 1;
-          color: $text-primary;
-          line-height: 1.6;
-        }
-
-        .option-check-icon {
-          color: $success-color;
-          font-size: 18px;
-          margin-left: $spacing-xs;
-        }
-      }
-    }
-
-    // 上传图片折叠
-    .uploaded-images-collapse {
-      margin-top: $spacing-lg;
-      padding-top: $spacing-lg;
-      border-top: 1px solid $border-color;
-
-      details {
-        summary {
-          cursor: pointer;
-          color: $text-secondary;
-          font-size: 14px;
-          padding: $spacing-sm;
-          border-radius: $border-radius-small;
-          transition: all 0.2s ease;
-
-          &:hover {
-            background: rgba($primary-color, 0.05);
-            color: $primary-color;
-          }
-        }
-
-        .collapse-images {
-          display: flex;
-          gap: $spacing-sm;
-          margin-top: $spacing-sm;
-          overflow-x: auto;
-
-          img {
-            height: 120px;
-            border-radius: $border-radius-small;
-            object-fit: cover;
-          }
-        }
-      }
-    }
-
-    // 卡片头部
-    .card-header {
-      display: flex;
-      align-items: center;
-      gap: $spacing-sm;
-      margin-bottom: $spacing-md;
-
-      .header-icon {
-        font-size: 24px;
-      }
-
-      h3 {
-        flex: 1;
-        font-size: 18px;
-        color: $text-primary;
-        margin: 0;
-        font-weight: 600;
-      }
-
-      &.expandable {
-        cursor: pointer;
-        padding: $spacing-sm;
-        border-radius: $border-radius-small;
-        transition: all 0.2s ease;
-
-        &:hover {
-          background: rgba($primary-color, 0.05);
-        }
-
-        .expand-icon {
-          font-size: 20px;
-          color: $text-secondary;
-          transition: transform 0.3s ease;
-        }
-      }
-    }
-
-    // 卡片内容
-    .card-content {
-      color: $text-primary;
-      line-height: 1.8;
-      font-size: 15px;
-
-      .analysis-section {
-        margin-bottom: $spacing-lg;
-
-        &:last-child {
-          margin-bottom: 0;
-        }
-
-        .section-title {
-          font-size: 14px;
-          font-weight: 600;
-          color: $text-primary;
-          margin: 0 0 $spacing-sm 0;
-          display: flex;
-          align-items: center;
-          gap: $spacing-xs;
-        }
-
-        .section-text {
-          color: $text-primary;
-          line-height: 1.8;
-          margin: 0;
-          white-space: pre-wrap;
-        }
-      }
-    }
-
-    // 问答区域
-    .qa-section {
-      .qa-header {
-        display: flex;
-        align-items: center;
-        gap: $spacing-sm;
-        margin-bottom: $spacing-lg;
-
-        .header-icon {
-          font-size: 24px;
-        }
-
-        h3 {
-          font-size: 18px;
-          color: $text-primary;
-          margin: 0;
-          font-weight: 600;
-        }
-      }
-
-      .quick-questions {
-        display: flex;
-        flex-wrap: wrap;
-        gap: $spacing-sm;
-        margin-bottom: $spacing-lg;
-
-        .quick-question-btn {
-          background: rgba($primary-color, 0.1);
-          color: $primary-color;
-          border: 1px solid rgba($primary-color, 0.3);
-          border-radius: 20px;
-          padding: $spacing-xs $spacing-md;
-          font-size: 13px;
-          cursor: pointer;
-          transition: all 0.2s ease;
-
-          &:hover:not(:disabled) {
-            background: $primary-color;
-            color: white;
-            transform: translateY(-1px);
-          }
-
-          &:disabled {
-            opacity: 0.5;
-            cursor: not-allowed;
-          }
-        }
-      }
-
-      .qa-history {
-        margin-bottom: $spacing-lg;
-
-        .qa-item {
-          margin-bottom: $spacing-lg;
-
-          .qa-question,
-          .qa-answer {
-            display: flex;
-            gap: $spacing-sm;
-            margin-bottom: $spacing-md;
-
-            .qa-avatar {
-              width: 36px;
-              height: 36px;
-              border-radius: 50%;
-              display: flex;
-              align-items: center;
-              justify-content: center;
-              font-size: 20px;
-              flex-shrink: 0;
-            }
-
-            .user-avatar {
-              background: rgba($primary-color, 0.1);
-            }
-
-            .ai-avatar {
-              background: rgba($secondary-color, 0.1);
-            }
-
-            .qa-bubble {
-              flex: 1;
-              padding: $spacing-sm $spacing-md;
-              border-radius: $border-radius-small;
-              line-height: 1.6;
-              font-size: 14px;
-            }
-
-            .user-bubble {
-              background: rgba($primary-color, 0.1);
-              color: $text-primary;
-              align-self: flex-start;
-            }
-
-            .ai-bubble {
-              background: #F5F5F5;
-              color: $text-primary;
-
-              .answering-indicator {
-                display: flex;
-                gap: 4px;
-
-                .dot {
-                  width: 8px;
-                  height: 8px;
-                  border-radius: 50%;
-                  background: $text-hint;
-                  animation: bounce 1.4s infinite ease-in-out both;
-
-                  &:nth-child(1) {
-                    animation-delay: -0.32s;
-                  }
-
-                  &:nth-child(2) {
-                    animation-delay: -0.16s;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-
-      .qa-input-container {
-        display: flex;
-        gap: $spacing-sm;
-
-        .qa-input {
-          flex: 1;
-          padding: $spacing-sm $spacing-md;
-          border: 1px solid $border-color;
-          border-radius: $border-radius-small;
-          font-size: 14px;
-          transition: all 0.2s ease;
-
-          &:focus {
-            outline: none;
-            border-color: $primary-color;
-            box-shadow: 0 0 0 2px rgba($primary-color, 0.1);
-          }
-
-          &:disabled {
-            background: #F5F5F5;
-            cursor: not-allowed;
-          }
-        }
-
-        .qa-send-btn {
-          background: $primary-color;
-          color: white;
-          border: none;
-          border-radius: $border-radius-small;
-          padding: $spacing-sm $spacing-lg;
-          font-size: 14px;
-          font-weight: 500;
-          cursor: pointer;
-          transition: all 0.2s ease;
-
-          &:hover:not(:disabled) {
-            background: darken($primary-color, 10%);
-          }
-
-          &:disabled {
-            opacity: 0.5;
-            cursor: not-allowed;
-          }
-        }
-      }
-    }
-
-    // 操作按钮
-    .action-buttons {
-      margin-top: $spacing-lg;
-      display: flex;
-      gap: $spacing-md;
-      justify-content: center;
-
-      .secondary-button {
-        background: white;
-        color: $text-secondary;
-        border: 1px solid $border-color;
-        border-radius: $border-radius-small;
-        padding: $spacing-sm $spacing-lg;
-        font-size: 14px;
-        cursor: pointer;
-        transition: all 0.2s ease;
-
-        &:hover {
-          border-color: $primary-color;
-          color: $primary-color;
-        }
-      }
-    }
-  }
-
-  // 骨架屏
-  .skeleton-line {
-    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
-    background-size: 200% 100%;
-    border-radius: 4px;
-  }
-
-  .skeleton-animate {
-    animation: skeleton-loading 1.5s ease-in-out infinite;
-  }
-
-  // 错误提示
-  .error-message {
-    background: rgba($error-color, 0.1);
-    color: $error-color;
-    padding: $spacing-md;
-    border-radius: $border-radius-small;
-    margin: $spacing-md;
-    text-align: center;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: $spacing-xs;
-
-    .error-icon {
-      font-size: 20px;
-    }
-  }
-
-  // 底部留白
-  .page-footer {
-    height: 80px;
-  }
-}
-
-// 动画
-@keyframes fade-in {
-  from {
-    opacity: 0;
-    transform: translateY(10px);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-.fade-in {
-  animation: fade-in 0.5s ease-out;
-}
-
-@keyframes spin {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
-}
-
-@keyframes progress-flow {
-  0% {
-    width: 0%;
-  }
-  50% {
-    width: 100%;
-  }
-  100% {
-    width: 0%;
-  }
-}
-
-@keyframes skeleton-loading {
-  0% {
-    background-position: 200% 0;
-  }
-  100% {
-    background-position: -200% 0;
-  }
-}
-
-@keyframes bounce {
-  0%,
-  80%,
-  100% {
-    transform: scale(0);
-  }
-  40% {
-    transform: scale(1);
-  }
-}
-
-// 响应式
-@media (max-width: 768px) {
-  .daofa-search-page {
-    .page-header {
-      .logo-section {
-        .logo-icon {
-          font-size: 36px;
-        }
-
-        .logo-text {
-          h1 {
-            font-size: 22px;
-          }
-
-          p {
-            font-size: 12px;
-          }
-        }
-      }
-    }
-
-    .question-section {
-      .question-card,
-      .answer-card,
-      .analysis-card,
-      .expansion-card,
-      .qa-section {
-        padding: $spacing-md;
-      }
-    }
-  }
-}

+ 0 - 514
教辅名师-src/ai-k12-daofa/src/modules/daofa/search/search.component.ts

@@ -1,514 +0,0 @@
-import { Component, OnInit, OnDestroy, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-import { DaofaService } from '../../../services/daofa.service';
-import { FmodeObject, NovaUploadService } from 'fmode-ng';
-import { FmodeLoadingController, FmodeLoadingInstance, TipsController } from 'fmode-ng/lib/core/agent';
-import Parse from 'parse';
-
-interface QuestionData {
-  id?: string;
-  title: string;
-  content: string;
-  questionType: string;
-  material?:string;
-  options?: { label: string; value: string; check?: boolean }[];
-  answer?: string;
-  keywords?: string[];
-}
-
-@Component({
-  selector: 'app-search',
-  standalone: true,
-  imports: [CommonModule, FormsModule],
-  templateUrl: './search.component.html',
-  styleUrl: './search.component.scss',
-  schemas: [CUSTOM_ELEMENTS_SCHEMA]
-})
-export class SearchComponent implements OnInit, OnDestroy {
-  // 上传相关
-  uploadedImages: string[] = [];
-  isUploading: boolean = false;
-  uploadProgressList: number[] = [];
-  uploadError: string = '';
-  minImagesRequired: number = 1;
-  maxImagesAllowed: number = 3;
-
-  // 识别和解析相关
-  isRecognizing: boolean = false;
-  isGenerating: boolean = false;
-  recognitionProgress: string = '';
-
-  // 题目数据
-  surveyItem: FmodeObject | null = null;
-  questionData: QuestionData = {
-    title: '',
-    content: '',
-    questionType: '',
-    options: [],
-    answer: '',
-    keywords: []
-  };
-
-  // 解析展示相关
-  showAnswer: boolean = false;
-  showAnalysis: boolean = false;
-  showKnowledgeExpansion: boolean = false;
-
-  // 问答相关
-  showQASection: boolean = false;
-  userQuestion: string = '';
-  qaHistory: { question: string; answer: string; isAnswering?: boolean }[] = [];
-  isAnswering: boolean = false;
-
-  // 常见问题快捷按钮
-  quickQuestions: string[] = [
-    '这个知识点在教材哪一课?',
-    '为什么这个选项是错的?',
-    '有没有相似的题目?',
-    '如何记忆这个知识点?'
-  ];
-
-  // 骨架屏相关
-  showSkeleton: boolean = false;
-  skeletonSections = [
-    { name: 'questionType', progress: 0 },
-    { name: 'content', progress: 0 },
-    { name: 'options', progress: 0 }
-  ];
-
-  // Loading和Tips
-  loading: FmodeLoadingInstance | null = null;
-  loadCtrl: FmodeLoadingController = new FmodeLoadingController();
-  tipsController: TipsController | null = null;
-
-  tipsList: string[] = [
-    '正在查阅相关法律条文...',
-    '正在关联教材知识点...',
-    'AI正在深度理解题意...',
-    '正在生成专业解析...',
-    '马上为你呈现答案...',
-    '分析题目考查要点中...',
-    '理解题目逻辑关系中...'
-  ];
-
-  // 时间统计
-  startTime: number = 0;
-  recognitionTime: number = 0;
-  surveyLogId: string = '';
-
-  constructor(
-    private daofaService: DaofaService,
-    private uploadService: NovaUploadService
-  ) {}
-
-  ngOnInit() {
-    this.startTime = Date.now();
-  }
-
-  ngOnDestroy() {
-    this.loading?.dismiss();
-    // 更新浏览时长
-    if (this.surveyLogId) {
-      const duration = Math.floor((Date.now() - this.startTime) / 1000);
-      this.daofaService.updateSurveyLog(this.surveyLogId, { duration });
-    }
-  }
-
-  /**
-   * 触发文件选择
-   */
-  triggerFileInput() {
-    const fileInput = document.getElementById('fileInput') as HTMLInputElement;
-    fileInput?.click();
-  }
-
-  /**
-   * 文件选择事件
-   */
-  onFileSelect(event: Event) {
-    const input = event.target as HTMLInputElement;
-    if (input.files && input.files.length > 0) {
-      const files = Array.from(input.files);
-
-      // 检查是否超过最大图片数量限制
-      const remainingSlots = this.maxImagesAllowed - this.uploadedImages.length;
-      if (remainingSlots <= 0) {
-        this.uploadError = `最多只能上传${this.maxImagesAllowed}张图片`;
-        return;
-      }
-
-      // 如果选择的文件数量超过剩余槽位,只取前面的文件
-      const filesToUpload = files.slice(0, remainingSlots);
-      if (files.length > remainingSlots) {
-        this.uploadError = `只能再上传${remainingSlots}张图片,已自动选择前${remainingSlots}张`;
-      }
-
-      this.uploadMultipleImages(filesToUpload);
-    }
-  }
-
-  /**
-   * 上传多张图片
-   */
-  async uploadMultipleImages(files: File[]) {
-    try {
-      this.isUploading = true;
-      this.uploadProgressList = new Array(files.length).fill(0);
-      this.uploadError = '';
-
-      const uploadPromises = files.map(async (file, index) => {
-        const fileResult = await this.uploadService.upload(file, (progress: any) => {
-          const currentFileProgress = progress.percent || 0;
-          this.uploadProgressList[index] = Math.round(currentFileProgress);
-        });
-        return fileResult.url;
-      });
-
-      const uploadedUrls = await Promise.all(uploadPromises);
-      this.uploadedImages = [...this.uploadedImages, ...uploadedUrls];
-
-      this.isUploading = false;
-      this.uploadProgressList = [];
-
-      // 自动开始识别
-      if (this.uploadedImages.length >= this.minImagesRequired) {
-        await this.startRecognition();
-      }
-
-    } catch (error) {
-      console.error('Upload failed:', error);
-      this.isUploading = false;
-      this.uploadProgressList = [];
-      this.uploadError = '上传失败,请重试';
-    }
-  }
-
-  /**
-   * 移除图片
-   */
-  removeImage(index: number) {
-    this.uploadedImages.splice(index, 1);
-
-    // 如果移除后需要重新识别
-    if (this.surveyItem && this.uploadedImages.length >= this.minImagesRequired) {
-      // 可以选择重新识别或保持当前结果
-    } else if (this.uploadedImages.length < this.minImagesRequired) {
-      // 重置状态
-      this.resetState();
-    }
-  }
-
-  /**
-   * 开始识别题目
-   */
-  async startRecognition() {
-    try {
-      this.isRecognizing = true;
-      this.showSkeleton = true;
-      this.loadTips();
-      await this.presentLoading({ message: '正在识别题目内容...' });
-
-      const recognitionStartTime = Date.now();
-
-      // 调用识别服务
-      this.surveyItem = await this.daofaService.recognizeQuestion({
-        images: this.uploadedImages,
-        onProgressChange: (progress) => {
-          this.recognitionProgress = progress;
-          if (this.loading) {
-            this.loading.message = progress;
-          }
-        },
-        loading: this.loading
-      });
-
-      this.recognitionTime = (Date.now() - recognitionStartTime) / 1000;
-
-      // 更新题目数据 - 此时就有题目内容了
-      this.updateQuestionData();
-
-      // 关闭loading,显示题目
-      this.loading?.dismiss();
-
-      // 模拟骨架屏逐步展开
-      await this.animateSkeleton();
-
-      this.isRecognizing = false;
-      this.showSkeleton = false;
-
-      // 保存搜题记录
-      const log = await this.daofaService.saveSurveyLog({
-        surveyItem: this.surveyItem!,
-        searchMode: 'image-upload',
-        uploadedImages: this.uploadedImages,
-        recognitionTime: this.recognitionTime,
-        viewedSections: ['recognition']
-      });
-      this.surveyLogId = log.id;
-
-      // 立即开始生成解析(不等待,让题目先显示)
-      this.generateAnalysis().catch(err => {
-        console.error('Generate analysis error:', err);
-      });
-
-    } catch (error) {
-      console.error('Recognition failed:', error);
-      this.isRecognizing = false;
-      this.showSkeleton = false;
-      this.uploadError = error.message || '识别失败,请重试';
-    } finally {
-      this.loading?.dismiss();
-    }
-  }
-
-  /**
-   * 生成题目解析
-   */
-  async generateAnalysis() {
-    try {
-      this.isGenerating = true;
-      await this.presentLoading({ message: '正在生成专业解析...' });
-
-      await this.daofaService.generateAnswer({
-        surveyItem: this.surveyItem!,
-        onContentChange: (content) => {
-          // 实时更新答案内容
-          this.questionData.answer = content;
-
-          // 逐步展开解析内容
-          if (!this.showAnswer && content.length > 20) {
-            this.showAnswer = true;
-          }
-          if (!this.showAnalysis && content.length > 100) {
-            setTimeout(() => { this.showAnalysis = true; }, 500);
-          }
-          if (!this.showKnowledgeExpansion && content.length > 300) {
-            setTimeout(() => { this.showKnowledgeExpansion = true; }, 1000);
-          }
-        },
-        loading: this.loading
-      });
-
-      // 生成完成后,从surveyItem同步最新数据
-      this.updateQuestionData();
-
-      // 显示问答区域
-      setTimeout(() => {
-        this.showQASection = true;
-      }, 1500);
-
-      this.isGenerating = false;
-
-      // 更新搜题记录
-      if (this.surveyLogId) {
-        await this.daofaService.updateSurveyLog(this.surveyLogId, {
-          viewCount: 1,
-          questions: []
-        });
-      }
-
-    } catch (error) {
-      console.error('Generate analysis failed:', error);
-      this.isGenerating = false;
-      this.uploadError = error.message || '生成解析失败,请重试';
-    } finally {
-      this.loading?.dismiss();
-    }
-  }
-
-  /**
-   * 更新题目数据
-   */
-  updateQuestionData() {
-    if (!this.surveyItem) return;
-
-    this.questionData = {
-      id: this.surveyItem.id,
-      title: this.surveyItem.get('title') || '',
-      material: this.surveyItem.get('createOptions')?.params?.material || '',
-      content: this.surveyItem.get('content') || '',
-      questionType: this.surveyItem.get('createOptions')?.params?.questionType || '',
-      options: this.surveyItem.get('options') || [],
-      answer: this.surveyItem.get('answer') || '',
-      keywords: this.surveyItem.get('keywords') || []
-    };
-  }
-
-  /**
-   * 骨架屏动画
-   */
-  async animateSkeleton() {
-    // 模拟逐步加载效果
-    for (let i = 0; i < this.skeletonSections.length; i++) {
-      await new Promise(resolve => setTimeout(resolve, 300));
-      this.skeletonSections[i].progress = 100;
-    }
-  }
-
-  /**
-   * 发送问题
-   */
-  async askQuestion(question?: string) {
-    const questionText = question || this.userQuestion.trim();
-
-    if (!questionText || !this.surveyItem) return;
-
-    // 添加到问答历史
-    this.qaHistory.push({
-      question: questionText,
-      answer: '',
-      isAnswering: true
-    });
-
-    const qaIndex = this.qaHistory.length - 1;
-    this.isAnswering = true;
-    this.userQuestion = '';
-
-    try {
-      await this.daofaService.handleQuestion({
-        parentQuestion: this.surveyItem,
-        userQuestion: questionText,
-        onAnswerChange: (answer) => {
-          // 实时更新回答内容
-          this.qaHistory[qaIndex].answer = answer;
-          this.qaHistory[qaIndex].isAnswering = false;
-        }
-      });
-
-      this.qaHistory[qaIndex].isAnswering = false;
-      this.isAnswering = false;
-
-      // 更新搜题记录
-      if (this.surveyLogId) {
-        const qaCount = this.qaHistory.length;
-        const questions = this.qaHistory.map((qa, idx) => ({
-          questionId: `qa_${idx}`,
-          question: qa.question,
-          timestamp: new Date().toISOString()
-        }));
-
-        await this.daofaService.updateSurveyLog(this.surveyLogId, {
-          qaCount: qaCount,
-          questions: questions
-        });
-      }
-
-    } catch (error) {
-      console.error('Ask question failed:', error);
-      this.qaHistory[qaIndex].answer = '回答失败,请重试';
-      this.qaHistory[qaIndex].isAnswering = false;
-      this.isAnswering = false;
-    }
-  }
-
-  /**
-   * 快捷问题点击
-   */
-  selectQuickQuestion(question: string) {
-    this.askQuestion(question);
-  }
-
-  /**
-   * 重置状态
-   */
-  resetState() {
-    this.surveyItem = null;
-    this.questionData = {
-      title: '',
-      content: '',
-      material: '',
-      questionType: '',
-      options: [],
-      answer: '',
-      keywords: []
-    };
-    this.showAnswer = false;
-    this.showAnalysis = false;
-    this.showKnowledgeExpansion = false;
-    this.showQASection = false;
-    this.qaHistory = [];
-    this.recognitionProgress = '';
-  }
-
-  /**
-   * 重新上传
-   */
-  resetUpload() {
-    this.uploadedImages = [];
-    this.uploadError = '';
-    this.resetState();
-  }
-
-  /**
-   * Loading相关
-   */
-  async presentLoading(options?: { message: string }) {
-    this.loading = await this.loadCtrl.create({
-      message: options?.message || '处理中...',
-      position: 'bottom'
-    });
-
-    await this.loading.present();
-  }
-
-  /**
-   * Tips相关
-   */
-  loadTips() {
-    this.tipsController = new TipsController({
-      tipsList: this.tipsList,
-      position: 'bottom',
-      random: true
-    });
-  }
-
-  /**
-   * 获取题型中文名称
-   */
-  getQuestionTypeName(type: string): string {
-    const typeMap: { [key: string]: string } = {
-      'single-choice': '单选题',
-      'multi-choice': '多选题',
-      'judge': '判断题',
-      'short-answer': '简答题',
-      'material-analysis': '材料分析题'
-    };
-    return typeMap[type] || type;
-  }
-
-  /**
-   * 获取题型图标
-   */
-  getQuestionTypeIcon(type: string): string {
-    const iconMap: { [key: string]: string } = {
-      'single-choice': '📋',
-      'multi-choice': '📑',
-      'judge': '✓✗',
-      'short-answer': '📝',
-      'material-analysis': '📚'
-    };
-    return iconMap[type] || '📋';
-  }
-
-  /**
-   * 解析答案的各个部分
-   */
-  parseAnswerSection(sectionName: string): string {
-    if (!this.questionData.answer) return '';
-
-    const patterns: { [key: string]: RegExp } = {
-      'standard': /【标准答案】([\s\S]*?)(?=【|$)/,
-      'knowledge': /【知识点】([\s\S]*?)(?=【|$)/,
-      'thinking': /【解题思路】([\s\S]*?)(?=【|$)/,
-      'mistakes': /【易错点】([\s\S]*?)(?=【|$)/,
-      'expansion': /【知识拓展】([\s\S]*?)(?=【|$)/
-    };
-
-    const pattern = patterns[sectionName];
-    if (!pattern) return '';
-
-    const match = this.questionData.answer.match(pattern);
-    return match ? match[1].trim() : '';
-  }
-}

+ 0 - 34
教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.html

@@ -1,34 +0,0 @@
-<div class="upload-card">
-  <h3>NovaStorage 基本上传示例</h3>
-
-  <div class="row">
-    <label class="btn">
-      选择文件
-      <input type="file" (change)="onFileChange($event)" hidden />
-    </label>
-  </div>
-
-  <div class="row" *ngIf="uploading">
-    <span>上传中...</span>
-    <span>{{ (progress || 0) | number:'1.0-2' }}%</span>
-  </div>
-
-  <div class="row" *ngIf="error">
-    <span style="color:#c00">{{ error }}</span>
-  </div>
-
-  <div class="row" *ngIf="result">
-    <div>
-      <div>文件名:{{ result?.name }}</div>
-      <div>类型:{{ result?.type }}</div>
-      <div>大小:{{ result?.size }}</div>
-      <div>URL:<a [href]="result?.url" target="_blank">{{ result?.url }}</a></div>
-    </div>
-
-    <button (click)="saveAttachment()">保存到附件表</button>
-  </div>
-
-  <div class="row" *ngIf="savedId">
-    <span>已保存 Attachment:{{ savedId }}</span>
-  </div>
-</div>

+ 0 - 0
教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.scss


+ 0 - 23
教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.spec.ts

@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { TestUploadComponent } from './test-upload.component';
-
-describe('TestUploadComponent', () => {
-  let component: TestUploadComponent;
-  let fixture: ComponentFixture<TestUploadComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [TestUploadComponent]
-    })
-    .compileComponents();
-    
-    fixture = TestBed.createComponent(TestUploadComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 78
教辅名师-src/ai-k12-daofa/src/modules/test/test-upload/test-upload.component.ts

@@ -1,78 +0,0 @@
-import { Component } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { NovaStorage, NovaFile } from 'fmode-ng/core';
-
-@Component({
-  selector: 'app-test-upload',
-  standalone: true,
-  imports: [CommonModule],
-  templateUrl: './test-upload.component.html',
-  styleUrl: './test-upload.component.scss'
-})
-export class TestUploadComponent {
-  cid = 'cDL6R1hgSi';
-  storage?: NovaStorage;
-
-  uploading = false;
-  progress = 0;
-  result?: NovaFile;
-  savedId?: string;
-  error?: string;
-
-  constructor() {
-    // 便于其他模块读取公司ID
-    try { localStorage.setItem('company', this.cid); } catch {}
-  }
-
-  async onFileChange(event: Event) {
-    const input = event.target as HTMLInputElement;
-    const file = input?.files?.[0];
-    if (!file) return;
-    await this.uploadFile(file);
-    // 清空选择,便于再次选择同一文件
-    input.value = '';
-  }
-
-  private async initStorage() {
-    if (!this.storage) {
-      try {
-        this.storage = await NovaStorage.withCid(this.cid);
-      } catch (e: any) {
-        this.error = `初始化存储失败:${e?.message || e}`;
-      }
-    }
-  }
-
-  async uploadFile(file: File) {
-    this.error = undefined;
-    this.savedId = undefined;
-    this.result = undefined;
-    this.uploading = true;
-    this.progress = 0;
-
-    await this.initStorage();
-    if (!this.storage) {
-      this.uploading = false;
-      return;
-    }
-
-    try {
-    
-      const uploaded = await this.storage.upload(file, {
-        prefixKey:"project/temp/",
-        onProgress: (p) => {
-          this.progress = Number(p?.total?.percent || 0);
-        },
-      });
-      this.result = uploaded;
-    } catch (e: any) {
-      this.error = `上传失败:${e?.message || e}`;
-    } finally {
-      this.uploading = false;
-    }
-  }
-
-  async saveAttachment() {
-    console.log(this.result)
-  }
-}

+ 0 - 479
教辅名师-src/ai-k12-daofa/src/services/daofa.service.ts

@@ -1,479 +0,0 @@
-import { Injectable } from '@angular/core';
-import {FmodeObject, FmodeParse} from "fmode-ng/parse";
-const Parse = FmodeParse.with("nova");
-import { completionJSON } from 'fmode-ng/lib/core/agent';
-
-// 道法题目识别模板
-export const DaofaQuestionRecognitionTplCode = 'daofa-question-recognition-tpl';
-// 道法问答模板
-export const DaofaQATplCode = 'daofa-qa-tpl';
-// 生成模型
-export const DaofaModel = 'fmode-1.6-cn';
-
-@Injectable({
-  providedIn: 'root'
-})
-export class DaofaService {
-
-  constructor() { }
-
-  /**
-   * 识别上传的题目图片
-   */
-  async recognizeQuestion(options: {
-    images: string[];
-    onProgressChange?: (progress: string) => void;
-    loading?: any;
-  }): Promise<FmodeObject> {
-    return new Promise(async (resolve, reject) => {
-      
-        // 构建提示词 - 使用视觉模型识别图片中的题目
-        const prompt = `请识别图片中的道德与法治题目,并按以下JSON格式输出:
-
-{
-  "questionType": "题型(single-choice/multi-choice/judge/short-answer/material-analysis)",
-  "title": "题目标题或简述",
-  "content": "完整的题目内容",
-  "options": [
-    {"label": "A", "value": "选项内容"}
-  ],
-  "material": "材料内容(如有)",
-  "keywords": ["关键词1", "关键词2"]
-}
-
-要求:
-1. 准确识别题目文字,包括题干、选项、材料等
-2. 正确判断题型
-3. 提取题目中的关键词(如:宪法、权利、义务等)
-4. 保持原文格式和标点符号`;
-
-        const output = `{
-  "questionType": "题型(single-choice/multi-choice/judge/short-answer/material-analysis)",
-  "title": "题目标题或简述",
-  "content": "完整的题目内容",
-  "options": [
-    {"label": "A", "value": "选项内容"}
-  ],
-  "material": "材料内容(如有)",
-  "keywords": ["关键词1", "关键词2"]
-}`;
-
-        options.onProgressChange?.('正在识别题目内容...');
-
-        // 使用completionJSON的vision模式
-        let questionData:any
-        try{
-          questionData = await completionJSON(
-            prompt,
-            output,
-            (content) => {
-              if (options.loading) {
-                options.loading.message = '正在识别题目...' + (content?.length || 0);
-              }
-            },
-            2,
-            {
-              model: DaofaModel,
-              vision: true,
-              images: options.images
-            }
-          );
-        }catch(err){
-          console.log(err)
-        }
-        console.log(questionData)
-
-        if (!questionData) {
-          throw new Error('题目识别结果为空');
-        }
-
-        // 保存识别结果到SurveyItem
-        const surveyItem = await this.saveSurveyItem({
-          type: 'daofa',
-          title: questionData.title || '道德与法治题目',
-          content: questionData.content,
-          images: options.images,
-          keywords: questionData.keywords || [],
-          options: questionData.options || [],
-          createOptions: {
-            tpl: DaofaQuestionRecognitionTplCode,
-            params: {
-              questionType: questionData.questionType,
-              recognitionMode: 'image-ocr',
-              material: questionData.material
-            }
-          }
-        });
-        console.log(surveyItem)
-        resolve(surveyItem);
-
-      // } catch (error) {
-      //   reject(new Error('识别题目失败: ' + error.message));
-      // }
-    });
-  }
-
-  /**
-   * 生成题目答案和解析
-   */
-  async generateAnswer(options: {
-    surveyItem: FmodeObject;
-    onContentChange?: (content: string) => void;
-    loading?: any;
-  }): Promise<FmodeObject> {
-    return new Promise(async (resolve, reject) => {
-      try {
-        const questionContent = options.surveyItem.get('content');
-        const questionType = options.surveyItem.get('createOptions')?.params?.questionType;
-        const questionOptions = options.surveyItem.get('options');
-
-        // 构建提示词
-        const createParams = {
-          questionType: questionType,
-          content: questionContent,
-          options: questionOptions?.map((opt: any) => `${opt.label}. ${opt.value}`).join('\n') || '',
-        };
-
-        // 构建提示词
-        const prompt = `请对以下道德与法治题目进行详细解析:
-
-题目类型: ${questionType}
-题目内容:
-${questionContent}
-
-${createParams.options ? '选项:\n' + createParams.options : ''}
-
-请按以下结构输出解析:
-
-【标准答案】
-(给出正确答案)
-
-【知识点】
-(归纳题目涉及的知识点)
-
-【解题思路】
-(详细说明解题思路和方法)
-
-【易错点】
-(指出常见的易错点和注意事项)
-
-【知识拓展】
-(关联教材章节、法律条文或时政热点)
-
-要求:
-1. 解析要专业、准确,符合道德与法治学科特点
-2. 引用相关法律条文时要注明出处
-3. 语言要通俗易懂,适合初中生理解
-4. 可以结合生活实例说明`;
-
-        // 使用sendCompletion进行流式输出
-        const messageList = [{
-          role: 'user',
-          content: prompt
-        }];
-
-        const completion = new (await import('fmode-ng/lib/core/agent')).FmodeChatCompletion(messageList, {
-          model: DaofaModel,
-        });
-
-        const subscription = completion.sendCompletion({
-          isDirect: true,
-        }).subscribe({
-          next: async (message: any) => {
-            const content = message?.content || '';
-
-            if (content && options.onContentChange) {
-              options.onContentChange(content);
-            }
-
-            if (options.loading) {
-              options.loading.message = '正在生成解析...' + content.length;
-            }
-
-            if (message?.complete && content) {
-              // 更新SurveyItem的answer字段
-              options.surveyItem.set('answer', content);
-
-              // 如果是选择题,解析正确答案并更新options
-              if (questionType?.includes('choice') && questionOptions) {
-                const correctAnswer = this.extractCorrectAnswer(content);
-                if (correctAnswer) {
-                  const updatedOptions = questionOptions.map((opt: any) => ({
-                    ...opt,
-                    check: opt.label === correctAnswer
-                  }));
-                  options.surveyItem.set('options', updatedOptions);
-                }
-              }
-
-              await options.surveyItem.save();
-              resolve(options.surveyItem);
-            }
-          },
-          error: (err) => {
-            reject(new Error('生成解析失败: ' + err.message));
-            subscription?.unsubscribe();
-          }
-        });
-
-      } catch (error) {
-        reject(new Error('生成解析失败: ' + error.message));
-      }
-    });
-  }
-
-  /**
-   * 处理用户追问
-   */
-  async handleQuestion(options: {
-    parentQuestion: FmodeObject;
-    userQuestion: string;
-    onAnswerChange?: (answer: string) => void;
-  }): Promise<FmodeObject> {
-    return new Promise(async (resolve, reject) => {
-      try {
-        const parentContent = options.parentQuestion.get('content');
-        const parentAnswer = options.parentQuestion.get('answer');
-
-        // 构建提示词
-        const prompt = `作为道德与法治学科的AI助教,请回答学生的问题。
-
-题目内容:
-${parentContent}
-
-已有解析:
-${parentAnswer}
-
-学生的问题:
-${options.userQuestion}
-
-回答要求:
-1. 针对学生的具体问题进行回答
-2. 采用启发式引导,而非直接给答案
-3. 引用教材内容或法律条文时要准确
-4. 结合生活实例帮助理解
-5. 语言要亲切、专业,适合初中生`;
-
-        // 使用sendCompletion进行流式输出
-        const messageList = [{
-          role: 'user',
-          content: prompt
-        }];
-
-        const completion = new (await import('fmode-ng/lib/core/agent')).FmodeChatCompletion(messageList, {
-          model: DaofaModel,
-        });
-
-        const subscription = completion.sendCompletion({
-          isDirect: true,
-        }).subscribe({
-          next: async (message: any) => {
-            const content = message?.content || '';
-
-            if (content && options.onAnswerChange) {
-              options.onAnswerChange(content);
-            }
-
-            if (message?.complete && content) {
-              // 保存追问记录
-              const qaItem = await this.saveQuestionAnswer({
-                parent: options.parentQuestion,
-                question: options.userQuestion,
-                answer: content
-              });
-
-              resolve(qaItem);
-            }
-          },
-          error: (err) => {
-            reject(new Error('回答问题失败: ' + err.message));
-            subscription?.unsubscribe();
-          }
-        });
-
-      } catch (error) {
-        reject(new Error('处理问题失败: ' + error.message));
-      }
-    });
-  }
-
-  /**
-   * 保存题目到SurveyItem
-   */
-  private async saveSurveyItem(data: {
-    type: string;
-    title: string;
-    content: string;
-    images?: string[];
-    keywords?: string[];
-    options?: any[];
-    createOptions: any;
-  }): Promise<FmodeObject> {
-    // const SurveyItem = Parse.Object.extend('SurveyItem');
-    const surveyItem = new Parse.Object('SurveyItem');;
-
-    surveyItem.set('type', data.type);
-    surveyItem.set('title', data.title);
-    surveyItem.set('content', data.content);
-    if (data.images) surveyItem.set('images', data.images);
-    if (data.keywords) surveyItem.set('keywords', data.keywords);
-    if (data.options) surveyItem.set('options', data.options);
-    surveyItem.set('createOptions', data.createOptions);
-
-    const user = Parse.User.current();
-    if (user) {
-      surveyItem.set('user', user.toPointer());
-    }
-
-    return await surveyItem.save();
-  }
-
-  /**
-   * 保存追问记录
-   */
-  private async saveQuestionAnswer(data: {
-    parent: FmodeObject;
-    question: string;
-    answer: string;
-  }): Promise<FmodeObject> {
-    // 获取当前已有的追问数量
-    const query = new Parse.Query('SurveyItem');
-    query.equalTo('parent', data.parent.toPointer());
-    query.equalTo('type', 'daofa-qa');
-    const count = await query.count();
-
-    // const SurveyItem = new Parse.Object('SurveyItem');
-    const qaItem = new Parse.Object('SurveyItem');
-
-    qaItem.set('type', 'daofa-qa');
-    qaItem.set('parent', data.parent.toPointer());
-    qaItem.set('index', count + 1);
-    qaItem.set('title', data.question);
-    qaItem.set('answer', data.answer);
-    qaItem.set('createOptions', {
-      tpl: DaofaQATplCode,
-      params: {
-        parentQuestionId: data.parent.id,
-        questionType: 'user-qa'
-      }
-    });
-
-    const user = Parse.User.current();
-    if (user) {
-      qaItem.set('user', user.toPointer());
-    }
-
-    return await qaItem.save();
-  }
-
-  /**
-   * 保存搜题记录到SurveyLog
-   */
-  async saveSurveyLog(options: {
-    surveyItem: FmodeObject;
-    searchMode: string;
-    uploadedImages: string[];
-    recognitionTime?: number;
-    viewedSections?: string[];
-  }): Promise<FmodeObject> {
-    const SurveyLog = Parse.Object.extend('SurveyLog');
-    const log = new SurveyLog();
-
-    log.set('surveyItem', options.surveyItem.toPointer());
-    log.set('user', Parse.User.current()?.toPointer());
-    log.set('type', 'search');
-    log.set('answer', {
-      searchMode: options.searchMode,
-      uploadedImages: options.uploadedImages,
-      recognitionTime: options.recognitionTime || 0,
-      viewedSections: options.viewedSections || [],
-      questions: []
-    });
-    log.set('viewCount', 1);
-    log.set('qaCount', 0);
-
-    return await log.save();
-  }
-
-  /**
-   * 更新搜题记录
-   */
-  async updateSurveyLog(logId: string, updates: {
-    duration?: number;
-    viewCount?: number;
-    qaCount?: number;
-    questions?: any[];
-  }): Promise<void> {
-    const query = new Parse.Query('SurveyLog');
-    const log = await query.get(logId);
-
-    if (updates.duration !== undefined) {
-      log.set('duration', updates.duration);
-    }
-    if (updates.viewCount !== undefined) {
-      log.set('viewCount', updates.viewCount);
-    }
-    if (updates.qaCount !== undefined) {
-      log.set('qaCount', updates.qaCount);
-    }
-    if (updates.questions) {
-      const answer = log.get('answer') || {};
-      answer.questions = updates.questions;
-      log.set('answer', answer);
-    }
-
-    await log.save();
-  }
-
-  /**
-   * 从解析中提取正确答案(选择题)
-   */
-  private extractCorrectAnswer(analysisContent: string): string | null {
-    // 尝试匹配 【标准答案】A 或 标准答案:A 等格式
-    const patterns = [
-      /【标准答案】\s*([A-Z])/,
-      /标准答案[::]\s*([A-Z])/,
-      /正确答案[::]\s*([A-Z])/,
-      /答案[::]\s*([A-Z])/
-    ];
-
-    for (const pattern of patterns) {
-      const match = analysisContent.match(pattern);
-      if (match) {
-        return match[1];
-      }
-    }
-
-    return null;
-  }
-
-  /**
-   * 加载历史搜题记录
-   */
-  async loadHistory(limit: number = 20): Promise<any[]> {
-    const query = new Parse.Query('SurveyItem');
-    query.equalTo('type', 'daofa');
-    query.equalTo('user', Parse.User.current()?.toPointer());
-    query.notEqualTo('isDeleted', true);
-    query.descending('createdAt');
-    query.limit(limit);
-
-    return await query.find();
-  }
-
-  /**
-   * 加载追问历史
-   */
-  async loadQuestionHistory(parentId: string): Promise<any[]> {
-    const query = new Parse.Query('SurveyItem');
-    query.equalTo('type', 'daofa-qa');
-    query.equalTo('parent', {
-      __type: 'Pointer',
-      className: 'SurveyItem',
-      objectId: parentId
-    });
-    query.ascending('index');
-
-    return await query.find();
-  }
-}

+ 0 - 1
教辅名师-src/ai-k12-daofa/src/styles.scss

@@ -1 +0,0 @@
-/* You can add global styles to this file, and also import other style files */

+ 0 - 14
教辅名师-src/ai-k12-daofa/tsconfig.app.json

@@ -1,14 +0,0 @@
-/* To learn more about this file see: https://angular.io/config/tsconfig. */
-{
-  "extends": "../../tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../../out-tsc/app",
-    "types": []
-  },
-  "files": [
-    "src/main.ts"
-  ],
-  "include": [
-    "src/**/*.d.ts"
-  ]
-}

+ 0 - 14
教辅名师-src/ai-k12-daofa/tsconfig.spec.json

@@ -1,14 +0,0 @@
-/* To learn more about this file see: https://angular.io/config/tsconfig. */
-{
-  "extends": "../../tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../../out-tsc/spec",
-    "types": [
-      "jasmine"
-    ]
-  },
-  "include": [
-    "src/**/*.spec.ts",
-    "src/**/*.d.ts"
-  ]
-}