10 KiB
数据模型(v1)
目标:在保持 LogicFlow 原生 GraphData 结构不改造的前提下,只定义顶层导出结构(Root Document)和节点业务字段,并通过 schemaVersion 管理导入导出与迁移,让精力集中在阴阳师业务数据上。
顶层导出结构(Root Document)
- 约定导出/本地持久化数据统一为如下结构,并包含
schemaVersion。
{
"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 的样式/图层信息,而不是重新定义一套独立的画布数据模型。
// 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中的业务字段与阴阳师相关业务数据。
节点类型扩展字段
- Image(imageNode)
interface ImageProps {
url: string; // 图片地址(本地 base64 或 assetId 由上层解析)
fit?: 'fill' | 'contain' | 'cover'; // 渲染适配
}
- Text(textNode)
interface TextProps {
content: string; // 文本内容(富文本后续扩展)
rich?: boolean; // 是否富文本(v1 仅纯文本)
}
- Vector(vectorNode)
interface VectorProps {
kind: 'path' | 'rect' | 'ellipse' | 'polygon';
path?: string; // 当 kind=path 时的 SVG Path 数据(M/L/C...)
points?: Array<[number, number]>; // 当 polygon 时的顶点(可选)
}
- Shikigami/阴阳师节点(保留现有结构)
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)
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)
- 判定:无
schemaVersion视为 v0。 - 节点迁移:
- 将节点的
width/height写入properties.style; - 若节点已有颜色/文本样式散落在
properties,合并到properties.style.*或textStyle; - 未定义的字段保持原样存放于
properties,由节点视图兼容。
- 将节点的
- 文件级:给每个 file 增加
id/createdAt/updatedAt(可选)。 - 顶层:补
schemaVersion='1.0.0'。
示例(含三类基础节点)
{
"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 > 0;opacity ∈ [0,1];strokeWidth ≥ 0;radius ≥ 0 或四元组均合法。
- 文本:fontSize > 0;lineHeight ∈ [1, 3];padding 四元组 ≥ 0。
- z 可为空(使用插入顺序),若存在必须为整数。
radius仅在vector.kind='rect'生效,其他kind忽略。
实施清单(与代码关联)
src/ts/useStore.ts- 导出/保存时写入
schemaVersion;导入/读取时若缺失则调用migrateToV1(state)。 - 定义
CURRENT_SCHEMA_VERSION = '1.0.0';新增migrateToV1(按上文迁移策略)。
- 导出/保存时写入
src/components/flow/FlowEditor.vue- 渲染前对
nodes按meta.z与createdAt稳定排序; render前将properties.style.width/height同步到节点尺寸。
- 渲染前对
- 节点视图(*.vue)
- image/text/vector 节点按
properties.style解析样式; - 旧字段兼容期内保留 fallback,逐步迁出。
- image/text/vector 节点按
- 属性面板
PropertyPanel.vue- 统一读取/写入
properties.style.*;文本属性写入textStyle与text.content。
- 统一读取/写入
附注:v1 仅定义统一样式容器与最小字段集合;后续可在不破坏兼容的前提下增量扩展(如 blendMode、滤镜等),并通过 schemaVersion 控制迁移。