fix(presentation): 修复 presentation 模块类型错误和语法问题
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- 创建 types.ts 定义完整的类型系统 - 重写 DocumentRenderer.tsx 修复语法错误 - 重写 QuizRenderer.tsx 修复语法错误 - 重写 PresentationContainer.tsx 添加类型守卫 - 重写 TypeSwitcher.tsx 修复类型引用 - 更新 index.ts 移除不存在的 ChartRenderer 导出 审计结果: - 类型检查: 通过 - 单元测试: 222 passed - 构建: 成功
This commit is contained in:
@@ -1569,6 +1569,101 @@ async fn load_skill_from_dir(&self, dir: &PathBuf) -> Result<()> {
|
||||
|
||||
---
|
||||
|
||||
## 10.4 Pipeline YAML 解析失败 - 类型不匹配
|
||||
|
||||
**症状**:
|
||||
- Pipeline 列表显示为空(Found 0 pipelines)
|
||||
- 后端调试日志显示扫描目录成功但没有找到任何 Pipeline
|
||||
- 没有明显的错误消息
|
||||
|
||||
**根本原因**: YAML 文件中的字段类型与 Rust 类型定义不匹配
|
||||
|
||||
**问题分析**:
|
||||
|
||||
1. **FileExport action formats 字段类型不匹配**:
|
||||
- Rust 定义:`formats: Vec<ExportFormat>`(枚举数组)
|
||||
- YAML 写法:`formats: ${inputs.export_formats}`(表达式字符串)
|
||||
- serde_yaml 无法将字符串解析为枚举数组,静默失败
|
||||
|
||||
2. **InputType serde rename_all 配置错误**:
|
||||
- YAML 使用 `multi-select`(kebab-case)
|
||||
- Rust serde 配置 `rename_all = "snake_case"`
|
||||
- 期望 `multi_select` 但收到 `multi-select`,解析失败
|
||||
|
||||
**修复方案**:
|
||||
|
||||
1. **将 formats 字段改为 String 类型** (`types.rs`):
|
||||
```rust
|
||||
FileExport {
|
||||
formats: String, // 从 Vec<ExportFormat> 改为 String
|
||||
input: String,
|
||||
output_dir: Option<String>,
|
||||
}
|
||||
```
|
||||
|
||||
2. **在运行时解析 formats 表达式** (`executor.rs`):
|
||||
```rust
|
||||
let resolved_formats = context.resolve(formats)?;
|
||||
let format_strings: Vec<String> = if resolved_formats.is_array() {
|
||||
resolved_formats.as_array()?
|
||||
.iter()
|
||||
.filter_map(|v| v.as_str().map(|s| s.to_string()))
|
||||
.collect()
|
||||
} else if resolved_formats.is_string() {
|
||||
// 尝试解析为 JSON 数组
|
||||
serde_json::from_str(s).unwrap_or_else(|_| vec![s.to_string()])
|
||||
} else {
|
||||
return Err(...);
|
||||
};
|
||||
|
||||
// 转换为 ExportFormat 枚举
|
||||
let export_formats: Vec<ExportFormat> = format_strings
|
||||
.iter()
|
||||
.filter_map(|s| match s.to_lowercase().as_str() {
|
||||
"pptx" => Some(ExportFormat::Pptx),
|
||||
"html" => Some(ExportFormat::Html),
|
||||
"pdf" => Some(ExportFormat::Pdf),
|
||||
"markdown" | "md" => Some(ExportFormat::Markdown),
|
||||
"json" => Some(ExportFormat::Json),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
```
|
||||
|
||||
3. **修正 InputType serde 配置** (`types.rs`):
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "kebab-case")] // 从 snake_case 改为 kebab-case
|
||||
pub enum InputType {
|
||||
#[default]
|
||||
String,
|
||||
Number,
|
||||
Boolean,
|
||||
Select,
|
||||
MultiSelect, // YAML 中写 multi-select
|
||||
File,
|
||||
Text,
|
||||
}
|
||||
```
|
||||
|
||||
**影响范围**:
|
||||
- `crates/zclaw-pipeline/src/types.rs` - InputType serde, FileExport formats
|
||||
- `crates/zclaw-pipeline/src/executor.rs` - 运行时解析 formats
|
||||
- `pipelines/**/*.yaml` - 确保使用 `multi-select` 而非 `multi_select`
|
||||
|
||||
**验证修复**:
|
||||
```
|
||||
[DEBUG pipeline_list] Found 5 pipelines
|
||||
[DEBUG pipeline_list] Pipeline: classroom-generator -> category: education, industry: 'education'
|
||||
```
|
||||
|
||||
**最佳实践**:
|
||||
- YAML 中的表达式(如 `${inputs.xxx}`)应该定义为 String 类型
|
||||
- 在运行时通过 ExecutionContext.resolve() 解析表达式
|
||||
- 使用 `kebab-case` 命名风格更符合 YAML 惯例
|
||||
|
||||
---
|
||||
|
||||
## 11. 相关文档
|
||||
|
||||
- [OpenFang 配置指南](./openfang-configuration.md) - 配置文件位置、格式和最佳实践
|
||||
|
||||
Reference in New Issue
Block a user