Files
yys-editor/docs/2design/DataModel.md
2025-12-24 16:49:50 +08:00

276 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数据模型v1
目标:在保持 LogicFlow 原生 GraphData 结构不改造的前提下只定义顶层导出结构Root Document和节点业务字段并通过 `schemaVersion` 管理导入导出与迁移,让精力集中在阴阳师业务数据上。
## 顶层导出结构Root Document
- 约定导出/本地持久化数据统一为如下结构,并包含 `schemaVersion`
```json
{
"schemaVersion": "1.0.0",
"fileList": [
{
"id": "file-1",
"label": "File 1",
"name": "File 1",
"type": "FLOW",
"visible": true,
"graphRawData": { "nodes": [], "edges": [] },
"transform": {
"SCALE_X": 1,
"SCALE_Y": 1,
"TRANSLATE_X": 0,
"TRANSLATE_Y": 0
},
"createdAt": 0,
"updatedAt": 0
}
],
"activeFileId": "file-1",
"activeFile": "File 1"
}
```
- 存量数据(无 `schemaVersion`)在加载时默认视为 `"0.x"`,并通过迁移器补齐。
## Graph/Node 基础模型
Graph/Node 结构整体沿用 LogicFlow 的 GraphData 定义nodes/edges、id/type/x/y/width/height 等);我们只约定节点 `properties` 中的业务字段,并在需要时适配 LogicFlow 的样式/图层信息,而不是重新定义一套独立的画布数据模型。
```ts
// Graph 文档(嵌入在每个 file.graphRawData 内)
interface GraphDocument {
nodes: GraphNode[];
edges: GraphEdge[];
}
interface GraphNode {
id: string;
type: string; // imageNode | textNode | vectorNode | shikigamiSelect | yuhunSelect | propertySelect | ...
x?: number; // LogicFlow 原生定位
y?: number;
width?: number; // 渲染冗余:由 properties.style.width 同步而来
height?: number; // 渲染冗余:由 properties.style.height 同步而来
properties: NodeProperties;
}
interface GraphEdge {
id: string;
type?: string;
sourceNodeId: string;
targetNodeId: string;
properties?: Record<string, any>;
}
interface NodeProperties {
style: NodeStyle; // 通用样式
meta?: NodeMeta; // 通用元信息(层级/锁定/可见/分组等)
// 具体节点类型的扩展字段(如下)
image?: ImageProps;
text?: TextProps;
vector?: VectorProps;
shikigami?: ShikigamiProps;
yuhun?: YuhunProps;
property?: PropertyRuleProps;
}
interface NodeStyle {
// 尺寸与变换(单一事实来源)
width: number; // px
height: number; // px
rotate?: number; // deg逆时针为正围绕节点中心旋转
// 形状/外观
fill?: string; // 颜色:#RGB/#RRGGBB/#RRGGBBAA/rgba()/transparent 等
stroke?: string; // 描边色
strokeWidth?: number; // px≥ 0
radius?: number | [number, number, number, number]; // 圆角rect 有效path/polygon 无效
opacity?: number; // 0..1
// 阴影
shadow?: {
color?: string;
blur?: number; // px
offsetX?: number; // px
offsetY?: number; // px
};
// 文本样式(当 text 节点或带文本的复合节点需要)
textStyle?: {
color?: string;
fontFamily?: string;
fontSize?: number; // px> 0
fontWeight?: number | string; // 400/700 或 normal/bold
lineHeight?: number; // 1..3
align?: 'left' | 'center' | 'right';
verticalAlign?: 'top' | 'middle' | 'bottom'; // 多行:用容器高度+行高模拟
letterSpacing?: number; // px
padding?: [number, number, number, number]; // 上右下左,≥ 0
background?: string; // 可选
};
}
interface NodeMeta {
z?: number; // 显式层级,缺省按插入顺序
locked?: boolean; // 锁定(不可选/不可拖动)
visible?: boolean; // 可见性
groupId?: string; // 组合/分组标识
name?: string; // 可选显示名
createdAt?: number;
updatedAt?: number;
}
```
> 说明:上述 `GraphDocument`、`GraphNode`、`GraphEdge`、`NodeStyle`、`NodeMeta` 主要用于说明结构,实际实现直接使用 LogicFlow 提供的 GraphData样式/图层字段属于可选扩展v1 只要求节点 `properties` 中的业务字段与阴阳师相关业务数据。
## 节点类型扩展字段
- ImageimageNode
```ts
interface ImageProps {
url: string; // 图片地址(本地 base64 或 assetId 由上层解析)
fit?: 'fill' | 'contain' | 'cover'; // 渲染适配
}
```
- TexttextNode
```ts
interface TextProps {
content: string; // 文本内容(富文本后续扩展)
rich?: boolean; // 是否富文本v1 仅纯文本)
}
```
- VectorvectorNode
```ts
interface VectorProps {
kind: 'path' | 'rect' | 'ellipse' | 'polygon';
path?: string; // 当 kind=path 时的 SVG Path 数据M/L/C...
points?: Array<[number, number]>; // 当 polygon 时的顶点(可选)
}
```
- Shikigami/阴阳师节点(保留现有结构)
```ts
interface ShikigamiProps { name: string; avatar: string; rarity: string; }
interface YuhunProps { name: string; type: string; avatar: string; shortName?: string; }
// PropertyRuleProps属性/御魂要求)延用现有字段,后续按规则引擎再细化
interface PropertyRuleProps { [k: string]: any }
```
## 同步与渲染约定
- 源数据以 `properties.style.width/height` 为准;渲染时将其同步到节点 `width/height`
- 层级以 `properties.meta.z` 为准;渲染前对 nodes 进行稳定排序(先 z再 createdAt
- 通用样式仅描述;具体生效由各节点视图组件(.vue解释执行。
- `vector.kind='rect'``radius` 生效;`path/polygon` 忽略;`fill/stroke/strokeWidth/opacity` 对所有 kind 生效。
- 旋转以节点中心为基点;正值逆时针;不单独提供 `transformOrigin` 字段(如需将以兼容方式新增)。
## 默认值v1
```ts
const DefaultNodeStyle: NodeStyle = {
width: 180, height: 120, rotate: 0,
fill: '#ffffff', stroke: '#dcdfe6', strokeWidth: 1, radius: 4, opacity: 1,
shadow: { color: 'rgba(0,0,0,0.1)', blur: 4, offsetX: 0, offsetY: 2 },
textStyle: { color: '#303133', fontFamily: 'system-ui', fontSize: 14, fontWeight: 400, lineHeight: 1.4, align: 'left', verticalAlign: 'top', letterSpacing: 0, padding: [8,8,8,8] }
};
```
## useStore 接入点与 schemaVersion
- 保存/导出:在 `saveStateToLocalStorage``exportData` 输出中添加 `schemaVersion: "1.0.0"`
- 读取/导入:`loadStateFromLocalStorage`/`importData` 检测 `schemaVersion`;无则走迁移器补齐:
-`node.width/height` 存在但 `properties.style` 缺失,创建 `style` 并拷贝宽高;
- 给所有节点补 `meta.visible=true``meta.locked=false`
- 生成 `createdAt/updatedAt`(以当前时间或从已有字段推断)。
- 常量:`const CURRENT_SCHEMA_VERSION = '1.0.0'` 存放于 `src/ts/useStore.ts``src/ts/schema.ts`
- 导出:同时写出 `activeFileId``activeFile`(名称),以兼容旧版。
- 导入:优先使用 `activeFileId` 匹配;若缺失则回退按 `activeFile`(名称)匹配;两者都缺则选首个文件。
## 迁移策略v0 → v1
1) 判定:无 `schemaVersion` 视为 v0。
2) 节点迁移:
- 将节点的 `width/height` 写入 `properties.style`
- 若节点已有颜色/文本样式散落在 `properties`,合并到 `properties.style.*``textStyle`
- 未定义的字段保持原样存放于 `properties`,由节点视图兼容。
3) 文件级:给每个 file 增加 `id/createdAt/updatedAt`(可选)。
4) 顶层:补 `schemaVersion='1.0.0'`
## 示例(含三类基础节点)
```json
{
"schemaVersion": "1.0.0",
"fileList": [
{
"id": "file-1",
"label": "海报示例",
"name": "海报示例",
"type": "FLOW",
"visible": true,
"graphRawData": {
"nodes": [
{
"id": "n-image-1",
"type": "imageNode",
"x": 200, "y": 160,
"properties": {
"style": { "width": 300, "height": 200, "radius": 8, "opacity": 1 },
"meta": { "z": 1, "visible": true, "locked": false },
"image": { "url": "/assets/banner.png", "fit": "cover" }
}
},
{
"id": "n-text-1",
"type": "textNode",
"x": 220, "y": 180,
"properties": {
"style": {
"width": 260, "height": 80,
"textStyle": { "color": "#111", "fontFamily": "Microsoft YaHei", "fontSize": 24, "fontWeight": 700, "align": "left" }
},
"meta": { "z": 2 },
"text": { "content": "阴阳师阵容编辑器" }
}
},
{
"id": "n-vector-1",
"type": "vectorNode",
"x": 180, "y": 300,
"properties": {
"style": { "width": 360, "height": 6, "fill": "#409EFF" },
"meta": { "z": 0 },
"vector": { "kind": "rect" }
}
}
],
"edges": []
},
"transform": { "SCALE_X": 1, "SCALE_Y": 1, "TRANSLATE_X": 0, "TRANSLATE_Y": 0 }
}
],
"activeFileId": "file-1",
"activeFile": "海报示例"
}
```
## 校验要点(建议)
- width/height > 0opacity ∈ [0,1]strokeWidth ≥ 0radius ≥ 0 或四元组均合法。
- 文本fontSize > 0lineHeight ∈ [1, 3]padding 四元组 ≥ 0。
- z 可为空(使用插入顺序),若存在必须为整数。
- `radius` 仅在 `vector.kind='rect'` 生效,其他 `kind` 忽略。
## 实施清单(与代码关联)
1) `src/ts/useStore.ts`
- 导出/保存时写入 `schemaVersion`;导入/读取时若缺失则调用 `migrateToV1(state)`
- 定义 `CURRENT_SCHEMA_VERSION = '1.0.0'`;新增 `migrateToV1`(按上文迁移策略)。
2) `src/components/flow/FlowEditor.vue`
- 渲染前对 `nodes``meta.z``createdAt` 稳定排序;
- `render` 前将 `properties.style.width/height` 同步到节点尺寸。
3) 节点视图(*.vue
- image/text/vector 节点按 `properties.style` 解析样式;
- 旧字段兼容期内保留 fallback逐步迁出。
4) 属性面板 `PropertyPanel.vue`
- 统一读取/写入 `properties.style.*`;文本属性写入 `textStyle``text.content`
---
附注v1 仅定义统一样式容器与最小字段集合;后续可在不破坏兼容的前提下增量扩展(如 blendMode、滤镜等并通过 `schemaVersion` 控制迁移。