Эх сурвалжийг харах

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 2 өдөр өмнө
parent
commit
63d24b187c
27 өөрчлөгдсөн 0 нэмэгдсэн , 3415 устгасан
  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"
-  ]
-}