/* ===================================================================== * model.rs — 数据模型(对应 src/core/types.ts) * * 所有结构体 derive Serialize/Deserialize/TS,确保: * - serde: JSON 序列化(Rust ↔ IPC ↔ JS) * - ts-rs: 自动生成 TypeScript 类型定义(Rust ↔ TS 类型同步) * * 运行 `cargo test --features export-types` 会在 ../bindings/ 生成 .ts 文件。 * ===================================================================== */ use serde::{Deserialize, Serialize}; use ts_rs::TS; /* ---------- 颜色 / 背景 / 动画 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub enum ChartType { #[serde(rename = "bar")] Bar, #[serde(rename = "line")] Line, #[serde(rename = "pie")] Pie, #[serde(rename = "area")] Area, #[serde(rename = "doughnut")] Doughnut, #[serde(rename = "radar")] Radar, #[serde(rename = "hbar")] Hbar, #[serde(rename = "progress")] Progress, } impl Default for ChartType { fn default() -> Self { ChartType::Bar } } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub enum ShapeType { #[serde(rename = "rect")] Rect, #[serde(rename = "circle")] Circle, #[serde(rename = "triangle")] Triangle, } impl Default for ShapeType { fn default() -> Self { ShapeType::Rect } } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub enum AnimType { #[serde(rename = "fade-up")] FadeUp, #[serde(rename = "fade")] Fade, #[serde(rename = "scale")] Scale, #[serde(rename = "zoom")] Zoom, #[serde(rename = "slide-l")] SlideL, #[serde(rename = "slide-r")] SlideR, #[serde(rename = "pop")] Pop, #[serde(rename = "rotate")] Rotate, #[serde(rename = "bounce")] Bounce, #[serde(rename = "flip")] Flip, #[serde(rename = "blur")] Blur, } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub enum ElementType { #[serde(rename = "title")] Title, #[serde(rename = "text")] Text, #[serde(rename = "list")] List, #[serde(rename = "stat")] Stat, #[serde(rename = "quote")] Quote, #[serde(rename = "image")] Image, #[serde(rename = "shape")] Shape, #[serde(rename = "chart")] Chart, #[serde(rename = "card")] Card, #[serde(rename = "table")] Table, #[serde(rename = "code")] Code, #[serde(rename = "formula")] Formula, } /* ---------- 主题 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct Theme { pub name: String, pub primary: String, pub accent: String, pub bg: String, pub panel: String, pub text: String, pub muted: String, } /* ---------- 富文本 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct RichSegment { pub text: String, pub bold: Option, pub italic: Option, pub underline: Option, pub strike: Option, pub color: Option, pub highlight: Option, pub code: Option, #[serde(rename = "sup")] pub sup_: Option, #[serde(rename = "sub")] pub sub_: Option, pub font_size: Option, pub link: Option, } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct RichLine { pub segments: Vec, } /* ---------- 元素 ---------- */ #[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] #[serde(rename_all = "camelCase")] pub struct ElementStyle { pub font_size: Option, pub color: Option, pub align: Option, pub bold: Option, pub italic: Option, pub anim: Option, // stat pub label: Option, pub label_color: Option, pub label_size: Option, // image pub fit: Option, // shape pub shape_type: Option, pub fill: Option, pub gradient: Option, pub opacity: Option, pub radius: Option, // chart pub max: Option, pub chart_type: Option, pub legend: Option, pub stack: Option, pub grid: Option, // table pub header: Option, // code pub lang: Option, // formula #[serde(rename = "inline")] pub inline_: Option, // card pub icon: Option, pub accent: Option, } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct SlideElement { pub id: String, #[serde(rename = "type")] pub element_type: String, pub x: f64, pub y: f64, pub w: f64, pub h: f64, pub content: String, pub style: ElementStyle, pub segments: Option>, } /* ---------- 幻灯片 / Deck ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct Slide { pub id: String, pub background: String, pub elements: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct Deck { pub v: i32, pub theme: String, pub slides: Vec, pub chat_id: Option, } /* ---------- AI 配置 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct AiCfg { pub preset: String, pub protocol: String, pub base: String, pub key: String, pub model: String, pub proxy: String, pub img_base: Option, pub img_key: Option, pub img_model: Option, } /* ---------- 文库 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct LibItem { pub id: String, pub name: String, pub deck: Deck, pub created_at: f64, pub updated_at: f64, } /* ---------- 模板 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct PageTemplate { pub id: String, pub name: String, pub category: String, pub background: String, pub elements: Vec, pub created_at: Option, } /* ---------- 会话 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct ChatMessage { pub role: String, pub content: String, } /* ---------- Op Log(对应 src/core/op.ts) ---------- */ /// Op 的 payload 是任意 JSON(不导出 TS,因为 payload 是动态的) #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Op { #[serde(rename = "type")] pub op_type: String, pub client_id: Option, pub timestamp: Option, #[serde(flatten)] pub payload: serde_json::Value, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HistoryEntry { pub forward: Op, pub backward: Op, } /* ---------- 图表数据 ---------- */ #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export, export_to = "../bindings/types.ts")] pub struct ChartItem { pub label: Option, pub value: Option, }