请输入文本
'; +const DEFAULT_TEXT_STYLE = { + fill: 'transparent', + stroke: '', + shadow: { + color: 'transparent', + blur: 0, + offsetX: 0, + offsetY: 0 + } +}; + +const parseSize = (value: unknown, fallback: number) => { + const next = Number(value); + return Number.isFinite(next) && next > 0 ? next : fallback; +}; + +const normalizeTextProperty = (rawText: any) => { + if (typeof rawText === 'string') { + return { + content: rawText, + rich: rawText.trim().startsWith('<') + }; + } + + if (rawText && typeof rawText === 'object') { + const content = typeof rawText.content === 'string' ? rawText.content : DEFAULT_TEXT_HTML; + const rich = rawText.rich == null ? content.trim().startsWith('<') : rawText.rich !== false; + return { + ...rawText, + content, + rich + }; + } + + return { + content: DEFAULT_TEXT_HTML, + rich: true + }; +}; + class TextNodeModel extends HtmlNodeModel { initNodeData(data: any) { super.initNodeData(data); - // 从 data 中读取宽高,支持调整大小后的持久化 - if (data.properties?.width) { - this.width = data.properties.width; - } else { - this.width = 200; - } + this.width = parseSize(data?.properties?.width, 200); + this.height = parseSize(data?.properties?.height, 120); - if (data.properties?.height) { - this.height = data.properties.height; - } else { - this.height = 120; - } + this.setProperty('width', this.width); + this.setProperty('height', this.height); + this.setProperty('text', normalizeTextProperty(data?.properties?.text)); - // 计算 Label 宽度 - const labelWidth = this.width - 20; - - // 初始化或更新 Label 配置 - if (data.properties?._label) { - // 如果已有 _label 配置,更新其宽度和坐标 - // 处理数组情况(兼容旧数据) - let currentLabel = data.properties._label; - if (Array.isArray(currentLabel)) { - currentLabel = currentLabel[0] || {}; - } - - this.setProperty('_label', { - value: currentLabel.value || '双击编辑文本', - content: currentLabel.content || currentLabel.value || '双击编辑文本', - x: data.x, - y: data.y, - labelWidth: labelWidth, - textOverflowMode: 'wrap', - editable: true, - draggable: false, - }); - } else if (data.properties?.text) { - // 如果有 text 属性但没有 _label,创建 _label - this.setProperty('_label', { - value: data.properties.text, - content: data.properties.text, - x: data.x, - y: data.y, - labelWidth: labelWidth, - textOverflowMode: 'wrap', - editable: true, - draggable: false, - }); - } else { - // 如果都没有,初始化一个默认的 label - this.setProperty('_label', { - value: '双击编辑文本', - content: '双击编辑文本', - x: data.x, - y: data.y, - labelWidth: labelWidth, - textOverflowMode: 'wrap', - editable: true, - draggable: false, - }); + const hasStyle = Object.prototype.hasOwnProperty.call(data?.properties || {}, 'style'); + if (!hasStyle) { + this.setProperty('style', DEFAULT_TEXT_STYLE); } } setAttributes() { - // 设置默认尺寸(如果 initNodeData 中没有设置) - if (!this.width) { - this.width = 200; - } - if (!this.height) { - this.height = 120; - } + if (!this.width) this.width = 200; + if (!this.height) this.height = 120; } - // 监听节点大小变化,更新 Label 宽度 resize(deltaX: number, deltaY: number) { const result = super.resize?.(deltaX, deltaY); - - // 持久化宽高到 properties this.setProperty('width', this.width); this.setProperty('height', this.height); - - // 更新 Label 宽度和坐标 - let currentLabel = this.properties._label || {}; - if (Array.isArray(currentLabel)) { - currentLabel = currentLabel[0] || {}; - } - - this.setProperty('_label', { - value: currentLabel.value || '双击编辑文本', - content: currentLabel.content || currentLabel.value || '双击编辑文本', - x: this.x, - y: this.y, - labelWidth: this.width - 20, - textOverflowMode: 'wrap', - editable: true, - draggable: false, - }); - return result; } - - // 当文本被编辑后,同步到 properties - updateText(value: string) { - super.updateText(value); - this.setProperty('text', value); - - // 同时更新 _label 中的 value - let currentLabel = this.properties._label || {}; - if (Array.isArray(currentLabel)) { - currentLabel = currentLabel[0] || {}; - } - - this.setProperty('_label', { - value: value, - content: value, - x: this.x, - y: this.y, - labelWidth: this.width - 20, - textOverflowMode: 'wrap', - editable: true, - draggable: false, - }); - } } export default TextNodeModel; diff --git a/src/components/flow/panels/AssetSelectorPanel.vue b/src/components/flow/panels/AssetSelectorPanel.vue index 2ba94c7..c3363ac 100644 --- a/src/components/flow/panels/AssetSelectorPanel.vue +++ b/src/components/flow/panels/AssetSelectorPanel.vue @@ -3,6 +3,7 @@ import { computed } from 'vue'; import { useDialogs } from '@/ts/useDialogs'; import { getLogicFlowInstance } from '@/ts/useLogicFlow'; import { SELECTOR_PRESETS } from '@/configs/selectorPresets'; +import type { SelectorConfig } from '@/types/selector'; const props = defineProps<{ node: any; @@ -10,30 +11,29 @@ const props = defineProps<{ const { openGenericSelector } = useDialogs(); -// 当前选中的资产库 const currentLibrary = computed(() => props.node.properties?.assetLibrary || 'shikigami'); -// 当前选中的资产 const currentAsset = computed(() => { return props.node.properties?.selectedAsset || { name: '未选择' }; }); -// 打开选择器 const handleOpenSelector = () => { const lf = getLogicFlowInstance(); const node = props.node; if (!lf || !node) return; const library = currentLibrary.value; - const config = SELECTOR_PRESETS[library]; + const preset = SELECTOR_PRESETS[library]; - if (!config) { + if (!preset) { console.error('未找到资产库配置:', library); return; } - // 设置当前选中项 - config.currentItem = node.properties?.selectedAsset; + const config: SelectorConfig = { + ...preset, + currentItem: node.properties?.selectedAsset || null + }; openGenericSelector(config, (selectedItem) => { lf.setProperties(node.id, { @@ -80,4 +80,4 @@ const handleOpenSelector = () => { color: #606266; margin-bottom: 8px; } - + \ No newline at end of file diff --git a/src/components/flow/panels/TextPanel.vue b/src/components/flow/panels/TextPanel.vue index 1d17be6..039b6f2 100644 --- a/src/components/flow/panels/TextPanel.vue +++ b/src/components/flow/panels/TextPanel.vue @@ -1,22 +1,121 @@