mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-05-08 03:16:39 +08:00
feat(editor): 组件代码块的绑定关系记录到dsl中,修复删除组件解除关系的问题,代码块dsl支持扩展字段
This commit is contained in:
parent
0b3585c150
commit
92f3696e44
@ -65,7 +65,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onUnmounted, PropType, provide, reactive, toRaw, watch } from 'vue';
|
import { defineComponent, onUnmounted, PropType, provide, reactive, toRaw, watch } from 'vue';
|
||||||
import { isEmpty,union } from 'lodash-es';
|
|
||||||
|
|
||||||
import { EventOption } from '@tmagic/core';
|
import { EventOption } from '@tmagic/core';
|
||||||
import type { FormConfig } from '@tmagic/form';
|
import type { FormConfig } from '@tmagic/form';
|
||||||
@ -210,12 +209,6 @@ export default defineComponent({
|
|||||||
updateDragEl: {
|
updateDragEl: {
|
||||||
type: Function as PropType<(el: HTMLDivElement, target: HTMLElement) => void>,
|
type: Function as PropType<(el: HTMLDivElement, target: HTMLElement) => void>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 可挂载代码块的生命周期 */
|
|
||||||
codeHooks: {
|
|
||||||
type: Array<string>,
|
|
||||||
default: () => ['created', 'mounted'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['props-panel-mounted', 'update:modelValue'],
|
emits: ['props-panel-mounted', 'update:modelValue'],
|
||||||
@ -233,38 +226,11 @@ export default defineComponent({
|
|||||||
emit('update:modelValue', toRaw(editorService.get('root')));
|
emit('update:modelValue', toRaw(editorService.get('root')));
|
||||||
});
|
});
|
||||||
|
|
||||||
const initCodeRelation = (rootValue: MNode) => {
|
|
||||||
if (isEmpty(rootValue.items)) return;
|
|
||||||
rootValue.items.forEach((nodeValue: MNode) => {
|
|
||||||
let curNodeCombineIds:string[] = []
|
|
||||||
// 合并各钩子绑定的代码块Id
|
|
||||||
props.codeHooks.forEach((hook) => {
|
|
||||||
// continue
|
|
||||||
if (isEmpty(nodeValue[hook])) return true
|
|
||||||
// 兼容单选绑定场景
|
|
||||||
if(typeof nodeValue[hook] === 'string' && nodeValue[hook]) {
|
|
||||||
curNodeCombineIds = union(curNodeCombineIds,[nodeValue[hook]])
|
|
||||||
}else if(Array.isArray(nodeValue[hook])) {
|
|
||||||
curNodeCombineIds = union(curNodeCombineIds,nodeValue[hook])
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 设置组件与代码块的绑定关系
|
|
||||||
if(!isEmpty(curNodeCombineIds)) {
|
|
||||||
codeBlockService.setCompRelation(nodeValue.id, curNodeCombineIds);
|
|
||||||
}
|
|
||||||
if (!isEmpty(nodeValue.items)) {
|
|
||||||
initCodeRelation(nodeValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始值变化,重新设置节点信息
|
// 初始值变化,重新设置节点信息
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(modelValue) => {
|
(modelValue) => {
|
||||||
editorService.set('root', modelValue);
|
editorService.set('root', modelValue);
|
||||||
// 初始化代码块与组件的绑定关系
|
|
||||||
initCodeRelation(modelValue);
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
@ -370,7 +336,6 @@ export default defineComponent({
|
|||||||
containerHighlightType: props.containerHighlightType,
|
containerHighlightType: props.containerHighlightType,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
provide('codeHooks',props.codeHooks)
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
},
|
},
|
||||||
|
@ -35,14 +35,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineEmits, defineProps, inject, ref, watchEffect } from 'vue';
|
import { computed, defineEmits, defineProps, inject, ref, watchEffect } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { map, union } from 'lodash-es';
|
import { cloneDeep, map, xor } from 'lodash-es';
|
||||||
|
|
||||||
import { SelectConfig } from '@tmagic/form';
|
import { SelectConfig } from '@tmagic/form';
|
||||||
|
|
||||||
import type { Services } from '../type';
|
import type { Services } from '../type';
|
||||||
import { CodeEditorMode } from '../type';
|
import { CodeEditorMode, CodeSelectOp } from '../type';
|
||||||
const services = inject<Services>('services');
|
const services = inject<Services>('services');
|
||||||
const codeHooks = inject<string[]>('codeHooks');
|
|
||||||
|
|
||||||
const emit = defineEmits(['change']);
|
const emit = defineEmits(['change']);
|
||||||
|
|
||||||
@ -77,7 +76,9 @@ const selectConfig = computed(() => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
const fieldKey = ref('');
|
const fieldKey = ref('');
|
||||||
|
const multiple = ref(true);
|
||||||
const combineIds = ref<string[]>([]);
|
const combineIds = ref<string[]>([]);
|
||||||
|
let lastTagSnapshot = cloneDeep(props.model[props.name]) || [];
|
||||||
|
|
||||||
watchEffect(async () => {
|
watchEffect(async () => {
|
||||||
const combineNames = await Promise.all(
|
const combineNames = await Promise.all(
|
||||||
@ -90,29 +91,39 @@ watchEffect(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const changeHandler = async (value: any) => {
|
const changeHandler = async (value: any) => {
|
||||||
await setCombineRelation();
|
let codeIds = value;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
multiple.value = false;
|
||||||
|
lastTagSnapshot = [lastTagSnapshot];
|
||||||
|
codeIds = value ? [value] : [];
|
||||||
|
}
|
||||||
|
await setCombineRelation(codeIds);
|
||||||
emit('change', value);
|
emit('change', value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 同步绑定关系
|
// 同步绑定关系
|
||||||
const setCombineRelation = async () => {
|
const setCombineRelation = async (codeIds: string[]) => {
|
||||||
// 绑定数组先置空
|
|
||||||
combineIds.value = [];
|
|
||||||
// 组件id
|
// 组件id
|
||||||
const { id = '' } = services?.editorService.get('node') || {};
|
const { id = '' } = services?.editorService.get('node') || {};
|
||||||
codeHooks?.forEach((hook) => {
|
|
||||||
// continue
|
// 兼容单选
|
||||||
if (!props.model[hook]) return true;
|
let opFlag = CodeSelectOp.CHANGE;
|
||||||
if (typeof props.model[hook] === 'string' && props.model[hook]) {
|
let diffValues = codeIds;
|
||||||
combineIds.value = union(combineIds.value, [props.model[hook]]);
|
if (multiple.value) {
|
||||||
} else if (Array.isArray(props.model[hook])) {
|
opFlag = codeIds.length < lastTagSnapshot.length ? CodeSelectOp.DELETE : CodeSelectOp.ADD;
|
||||||
combineIds.value = union(combineIds.value, props.model[hook]);
|
diffValues = xor(codeIds, lastTagSnapshot) as string[];
|
||||||
}
|
}
|
||||||
});
|
|
||||||
// 记录组件与代码块的绑定关系
|
// 记录绑定关系
|
||||||
await services?.codeBlockService.setCompRelation(id, combineIds.value);
|
await services?.codeBlockService.setCombineRelation(id, diffValues, opFlag, props.prop);
|
||||||
// 记录当前已被绑定的代码块,为查看弹窗的展示内容
|
lastTagSnapshot = codeIds;
|
||||||
await services?.codeBlockService.setCombineIds(combineIds.value);
|
await setCombineIds(codeIds);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 记录当前已被绑定的代码块,为查看弹窗的展示内容
|
||||||
|
const setCombineIds = async (codeIds: string[]) => {
|
||||||
|
combineIds.value = codeIds;
|
||||||
|
await services?.codeBlockService.setCombineIds(codeIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
const viewHandler = async () => {
|
const viewHandler = async () => {
|
||||||
@ -120,7 +131,8 @@ const viewHandler = async () => {
|
|||||||
ElMessage.error('请先绑定代码块');
|
ElMessage.error('请先绑定代码块');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await setCombineRelation();
|
// 记录当前已被绑定的代码块,为查看弹窗的展示内容
|
||||||
|
await setCombineIds(props.model[props.name]);
|
||||||
await services?.codeBlockService.setMode(CodeEditorMode.LIST);
|
await services?.codeBlockService.setMode(CodeEditorMode.LIST);
|
||||||
services?.codeBlockService.setCodeEditorContent(true, combineIds.value[0]);
|
services?.codeBlockService.setCodeEditorContent(true, combineIds.value[0]);
|
||||||
};
|
};
|
||||||
|
@ -97,14 +97,14 @@
|
|||||||
import { computed, inject, reactive, ref, watch } from 'vue';
|
import { computed, inject, reactive, ref, watch } from 'vue';
|
||||||
import { Close, Edit, Link, View } from '@element-plus/icons-vue';
|
import { Close, Edit, Link, View } from '@element-plus/icons-vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { flattenDeep, forIn, isEmpty, values, xor } from 'lodash-es';
|
import { forIn, isEmpty } from 'lodash-es';
|
||||||
|
|
||||||
import { Id } from '@tmagic/schema';
|
import { Id } from '@tmagic/schema';
|
||||||
import StageCore from '@tmagic/stage';
|
import StageCore from '@tmagic/stage';
|
||||||
|
|
||||||
import Icon from '../../../components/Icon.vue';
|
import Icon from '../../../components/Icon.vue';
|
||||||
import type { CodeBlockContent, Services } from '../../../type';
|
import type { CodeBlockContent, CodeRelation, Services } from '../../../type';
|
||||||
import { CodeDeleteErrorType, CodeDslList, CodeEditorMode, ListState } from '../../../type';
|
import { CodeDeleteErrorType, CodeDslList, CodeEditorMode, ListRelationState } from '../../../type';
|
||||||
|
|
||||||
import codeBlockEditor from './CodeBlockEditor.vue';
|
import codeBlockEditor from './CodeBlockEditor.vue';
|
||||||
|
|
||||||
@ -113,10 +113,9 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const services = inject<Services>('services');
|
const services = inject<Services>('services');
|
||||||
// const codeHooks = inject<string[]>('codeHooks') || [];
|
|
||||||
|
|
||||||
// 代码块列表
|
// 代码块列表
|
||||||
const state = reactive<ListState>({
|
const state = reactive<ListRelationState>({
|
||||||
codeList: [],
|
codeList: [],
|
||||||
bindComps: {},
|
bindComps: {},
|
||||||
});
|
});
|
||||||
@ -124,13 +123,15 @@ const state = reactive<ListState>({
|
|||||||
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
||||||
|
|
||||||
// 根据代码块ID获取其绑定的组件信息
|
// 根据代码块ID获取其绑定的组件信息
|
||||||
const getBindCompsByCodeId = (codeId: string) => {
|
const getBindCompsByCodeId = (codeId: string, codeBlockContent: CodeBlockContent) => {
|
||||||
const bindCompIds = services?.codeBlockService.getCodeRelationById(codeId) || [];
|
if (isEmpty(codeBlockContent) || isEmpty(codeBlockContent.comps)) {
|
||||||
if (isEmpty(bindCompIds)) {
|
|
||||||
state.bindComps[codeId] = [];
|
state.bindComps[codeId] = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const compsInfo = bindCompIds.map((compId) => ({
|
const compsField = codeBlockContent.comps as CodeRelation;
|
||||||
|
const bindCompIds = Object.keys(compsField);
|
||||||
|
const bindCompsFiltered = bindCompIds.filter((compId) => !isEmpty(compsField[compId]));
|
||||||
|
const compsInfo = bindCompsFiltered.map((compId) => ({
|
||||||
id: compId,
|
id: compId,
|
||||||
name: getCompName(compId),
|
name: getCompName(compId),
|
||||||
}));
|
}));
|
||||||
@ -143,7 +144,7 @@ const initList = async () => {
|
|||||||
if (!codeDsl) return;
|
if (!codeDsl) return;
|
||||||
state.codeList = [];
|
state.codeList = [];
|
||||||
forIn(codeDsl, (value: CodeBlockContent, codeId: string) => {
|
forIn(codeDsl, (value: CodeBlockContent, codeId: string) => {
|
||||||
getBindCompsByCodeId(codeId);
|
getBindCompsByCodeId(codeId, value);
|
||||||
state.codeList.push({
|
state.codeList.push({
|
||||||
id: codeId,
|
id: codeId,
|
||||||
name: value.name,
|
name: value.name,
|
||||||
@ -160,22 +161,7 @@ watch(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
deep: true,
|
||||||
);
|
|
||||||
|
|
||||||
// 监听绑定关系修改,更新到代码块列表
|
|
||||||
watch(
|
|
||||||
() => services?.codeBlockService.getCompRelation(),
|
|
||||||
(curRelation, oldRelation) => {
|
|
||||||
forIn(curRelation, (codeArr, compId) => {
|
|
||||||
let oldCodeArr: string[] = [];
|
|
||||||
if (oldRelation) {
|
|
||||||
oldCodeArr = oldRelation[compId];
|
|
||||||
}
|
|
||||||
// 可能一次清空全部绑定关系,对比结果为数组
|
|
||||||
const diffCodeIds = xor(codeArr, oldCodeArr);
|
|
||||||
diffCodeIds.forEach((codeId) => getBindCompsByCodeId(codeId));
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -219,15 +205,14 @@ const editCode = async (key: string) => {
|
|||||||
|
|
||||||
// 删除代码块
|
// 删除代码块
|
||||||
const deleteCode = (key: string) => {
|
const deleteCode = (key: string) => {
|
||||||
const compRelation = services?.codeBlockService.getCompRelation();
|
const existBinds = !!(state.bindComps[key]?.length > 0);
|
||||||
const codeIds = flattenDeep(values(compRelation));
|
|
||||||
const undeleteableList = services?.codeBlockService.getUndeletableList() || [];
|
const undeleteableList = services?.codeBlockService.getUndeletableList() || [];
|
||||||
if (!codeIds.includes(key) && !undeleteableList.includes(key)) {
|
if (!existBinds && !undeleteableList.includes(key)) {
|
||||||
// 无绑定关系,且不在不可删除列表中
|
// 无绑定关系,且不在不可删除列表中
|
||||||
services?.codeBlockService.deleteCodeDslByIds([key]);
|
services?.codeBlockService.deleteCodeDslByIds([key]);
|
||||||
} else {
|
} else {
|
||||||
if (typeof props.customError === 'function') {
|
if (typeof props.customError === 'function') {
|
||||||
props.customError(key, codeIds.includes(key) ? CodeDeleteErrorType.BIND : CodeDeleteErrorType.UNDELETEABLE);
|
props.customError(key, existBinds ? CodeDeleteErrorType.BIND : CodeDeleteErrorType.UNDELETEABLE);
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error('代码块删除失败');
|
ElMessage.error('代码块删除失败');
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { forIn, isEmpty, keys, omit, pick } from 'lodash-es';
|
import { cloneDeep, forIn, isEmpty, keys, omit, pick } from 'lodash-es';
|
||||||
|
|
||||||
import { Id } from '@tmagic/schema';
|
import { Id, MNode } from '@tmagic/schema';
|
||||||
|
|
||||||
import editorService from '../services/editor';
|
import editorService from '../services/editor';
|
||||||
import type { CodeBlockContent, CodeBlockDSL, CodeState, CompRelation } from '../type';
|
import type { CodeBlockContent, CodeBlockDSL, CodeState } from '../type';
|
||||||
import { CodeEditorMode } from '../type';
|
import { CodeEditorMode, CodeSelectOp } from '../type';
|
||||||
import { info } from '../utils/logger';
|
import { error, info } from '../utils/logger';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
|
|
||||||
@ -36,7 +36,6 @@ class CodeBlock extends BaseService {
|
|||||||
editable: true,
|
editable: true,
|
||||||
mode: CodeEditorMode.EDITOR,
|
mode: CodeEditorMode.EDITOR,
|
||||||
combineIds: [],
|
combineIds: [],
|
||||||
compRelation: {},
|
|
||||||
undeletableList: [],
|
undeletableList: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,7 +51,6 @@ class CodeBlock extends BaseService {
|
|||||||
'setEditStatus',
|
'setEditStatus',
|
||||||
'setMode',
|
'setMode',
|
||||||
'setCombineIds',
|
'setCombineIds',
|
||||||
'setCompRelation',
|
|
||||||
'setUndeleteableList',
|
'setUndeleteableList',
|
||||||
'deleteCodeDslByIds',
|
'deleteCodeDslByIds',
|
||||||
]);
|
]);
|
||||||
@ -102,9 +100,14 @@ class CodeBlock extends BaseService {
|
|||||||
*/
|
*/
|
||||||
public async setCodeDslById(id: string, codeConfig: CodeBlockContent): Promise<void> {
|
public async setCodeDslById(id: string, codeConfig: CodeBlockContent): Promise<void> {
|
||||||
let codeDsl = await this.getCodeDsl();
|
let codeDsl = await this.getCodeDsl();
|
||||||
|
if (!codeDsl) return;
|
||||||
|
const existContent = codeDsl[id] || {};
|
||||||
codeDsl = {
|
codeDsl = {
|
||||||
...codeDsl,
|
...codeDsl,
|
||||||
[id]: codeConfig,
|
[id]: {
|
||||||
|
...existContent,
|
||||||
|
...codeConfig,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
await this.setCodeDsl(codeDsl);
|
await this.setCodeDsl(codeDsl);
|
||||||
}
|
}
|
||||||
@ -226,41 +229,73 @@ class CodeBlock extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置组件与代码块的绑定关系
|
* 设置绑定关系
|
||||||
* @param {number | string} compId 组件id
|
* @param {Id} 组件id
|
||||||
* @param {string[]} codeIds 代码块id数组
|
* @param {string[]} diffCodeIds 代码块id数组
|
||||||
|
* @param {CodeSelectOp} opFlag 操作类型
|
||||||
|
* @param {string} hook 代码块挂载hook名称
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
public async setCompRelation(compId: number | string, codeIds: string[]) {
|
public async setCombineRelation(compId: Id, diffCodeIds: string[], opFlag: CodeSelectOp, hook: string) {
|
||||||
if (!compId) return;
|
const codeDsl = cloneDeep(await this.getCodeDsl());
|
||||||
this.state.compRelation = {
|
if (!codeDsl) return;
|
||||||
...this.state.compRelation,
|
if (opFlag === CodeSelectOp.DELETE) {
|
||||||
[compId]: codeIds,
|
try {
|
||||||
};
|
diffCodeIds.forEach((codeId) => {
|
||||||
}
|
const compsContent = codeDsl[codeId].comps;
|
||||||
|
const index = compsContent[compId].findIndex((item) => item === hook);
|
||||||
/**
|
if (index !== -1) {
|
||||||
* 获取组件与代码块的绑定关系
|
compsContent[compId].splice(index, 1);
|
||||||
* @returns {CompRelation}
|
|
||||||
*/
|
|
||||||
public getCompRelation(): CompRelation {
|
|
||||||
return this.state.compRelation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取代码块与组件的绑定关系
|
|
||||||
* @param {string} codeId 代码块id
|
|
||||||
* @returns {Id[]} 该代码块绑定的组件id数组
|
|
||||||
*/
|
|
||||||
public getCodeRelationById(codeId: string): Id[] {
|
|
||||||
const codeRelation = reactive<Id[]>([]);
|
|
||||||
const compRelation = this.getCompRelation();
|
|
||||||
forIn(compRelation, (value, key) => {
|
|
||||||
if (value.includes(codeId)) {
|
|
||||||
codeRelation.push(key);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return codeRelation;
|
} catch (e) {
|
||||||
|
error(e);
|
||||||
|
throw new Error('解绑代码块失败');
|
||||||
|
}
|
||||||
|
} else if (opFlag === CodeSelectOp.ADD) {
|
||||||
|
try {
|
||||||
|
diffCodeIds.forEach((codeId) => {
|
||||||
|
const compsContent = codeDsl[codeId].comps;
|
||||||
|
const existHooks = compsContent?.[compId];
|
||||||
|
if (isEmpty(existHooks)) {
|
||||||
|
// comps属性不存在,或者comps为空:新增
|
||||||
|
codeDsl[codeId].comps = {
|
||||||
|
...(codeDsl[codeId].comps || {}),
|
||||||
|
[compId]: [hook],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// 往已有的关系中添加hook
|
||||||
|
existHooks.push(hook);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
error(e);
|
||||||
|
throw new Error('绑定代码块失败');
|
||||||
|
}
|
||||||
|
} else if (opFlag === CodeSelectOp.CHANGE) {
|
||||||
|
// 单选修改
|
||||||
|
forIn(codeDsl, (codeBlockContent, codeId) => {
|
||||||
|
if (codeId === diffCodeIds[0]) {
|
||||||
|
// 增加
|
||||||
|
codeBlockContent.comps = {
|
||||||
|
...(codeBlockContent?.comps || {}),
|
||||||
|
[compId]: [hook],
|
||||||
|
};
|
||||||
|
} else if (isEmpty(diffCodeIds) || codeId !== diffCodeIds[0]) {
|
||||||
|
// 清空或者移除之前的选项
|
||||||
|
const compHooks = codeBlockContent?.comps?.[compId];
|
||||||
|
// continue
|
||||||
|
if (!compHooks) return true;
|
||||||
|
const index = compHooks.findIndex((hookName) => hookName === hook);
|
||||||
|
if (index !== -1) {
|
||||||
|
compHooks.splice(index, 1);
|
||||||
|
// break
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setCodeDsl(codeDsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -306,30 +341,42 @@ class CodeBlock extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一对一解除绑定关系
|
* 一对一解除绑定关系 功能隐藏,暂时注释
|
||||||
* @param {string} compId 组件id
|
* @param {string} compId 组件id
|
||||||
* @param {string} codeId 代码块id
|
* @param {string} codeId 代码块id
|
||||||
* @param {string[]} codeHooks 代码块挂载hook名称
|
* @param {string[]} codeHooks 代码块挂载hook名称
|
||||||
* @returns {boolean} 结果
|
* @returns {boolean} 结果
|
||||||
*/
|
*/
|
||||||
public async unbind(compId: Id, codeId: string, codeHooks: string[]): Promise<boolean> {
|
// public async unbind(compId: Id, codeId: string, codeHooks: string[]): Promise<boolean> {
|
||||||
const nodeInfo = editorService.getNodeById(compId);
|
// const nodeInfo = editorService.getNodeById(compId);
|
||||||
if (!nodeInfo) return false;
|
// if (!nodeInfo) return false;
|
||||||
// 更新node节点信息
|
// // 更新node节点信息
|
||||||
codeHooks.forEach((hook) => {
|
// codeHooks.forEach((hook) => {
|
||||||
if (!isEmpty(nodeInfo[hook])) {
|
// if (!isEmpty(nodeInfo[hook])) {
|
||||||
const newHookInfo = nodeInfo[hook].filter((item: string) => item !== codeId);
|
// const newHookInfo = nodeInfo[hook].filter((item: string) => item !== codeId);
|
||||||
nodeInfo[hook] = newHookInfo;
|
// nodeInfo[hook] = newHookInfo;
|
||||||
editorService.update(nodeInfo);
|
// editorService.update(nodeInfo);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
// 更新绑定关系
|
// // 更新绑定关系
|
||||||
const oldRelation = await this.getCompRelation();
|
// const oldRelation = await this.getCompRelation();
|
||||||
const oldCodeIds = oldRelation[compId];
|
// const oldCodeIds = oldRelation[compId];
|
||||||
// 不能直接splice修改原数组,会导致绑定关系更新错乱
|
// // 不能直接splice修改原数组,会导致绑定关系更新错乱
|
||||||
const newCodeIds = oldCodeIds.filter((item) => item !== codeId);
|
// const newCodeIds = oldCodeIds.filter((item) => item !== codeId);
|
||||||
this.setCompRelation(compId, newCodeIds);
|
// this.setCompRelation(compId, newCodeIds);
|
||||||
return true;
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过组件id解除绑定关系(删除组件)
|
||||||
|
* @param {MNode} compId 组件节点
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
public async deleteCompsInRelation(node: MNode) {
|
||||||
|
const codeDsl = cloneDeep(await this.getCodeDsl());
|
||||||
|
if (!codeDsl) return;
|
||||||
|
this.recurseNodes(node, codeDsl);
|
||||||
|
this.setCodeDsl(codeDsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
@ -339,9 +386,22 @@ class CodeBlock extends BaseService {
|
|||||||
this.state.editable = true;
|
this.state.editable = true;
|
||||||
this.state.mode = CodeEditorMode.EDITOR;
|
this.state.mode = CodeEditorMode.EDITOR;
|
||||||
this.state.combineIds = [];
|
this.state.combineIds = [];
|
||||||
this.state.compRelation = {};
|
|
||||||
this.state.undeletableList = [];
|
this.state.undeletableList = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除组件时 如果是容器 需要遍历删除其包含节点的绑定信息
|
||||||
|
private recurseNodes(node: MNode, codeDsl: CodeBlockDSL) {
|
||||||
|
if (!node.id) return;
|
||||||
|
forIn(codeDsl, (codeBlockContent) => {
|
||||||
|
const compsContent = codeBlockContent.comps || {};
|
||||||
|
codeBlockContent.comps = omit(compsContent, node.id);
|
||||||
|
});
|
||||||
|
if (!isEmpty(node.items)) {
|
||||||
|
node.items.forEach((item: MNode) => {
|
||||||
|
this.recurseNodes(item, codeDsl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CodeBlockService = CodeBlock;
|
export type CodeBlockService = CodeBlock;
|
||||||
|
@ -24,6 +24,7 @@ import { NodeType } from '@tmagic/schema';
|
|||||||
import StageCore from '@tmagic/stage';
|
import StageCore from '@tmagic/stage';
|
||||||
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
||||||
|
|
||||||
|
import codeBlockService from '../services/codeBlock';
|
||||||
import historyService, { StepValue } from '../services/history';
|
import historyService, { StepValue } from '../services/history';
|
||||||
import storageService, { Protocol } from '../services/storage';
|
import storageService, { Protocol } from '../services/storage';
|
||||||
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '../type';
|
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '../type';
|
||||||
@ -421,6 +422,9 @@ class Editor extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.addModifiedNodeId(parent.id);
|
this.addModifiedNodeId(parent.id);
|
||||||
|
|
||||||
|
// 通知codeBlockService解除绑定关系
|
||||||
|
codeBlockService.deleteCompsInRelation(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -317,6 +317,10 @@ export interface CodeBlockContent {
|
|||||||
name: string;
|
name: string;
|
||||||
/** 代码块内容 */
|
/** 代码块内容 */
|
||||||
content: string;
|
content: string;
|
||||||
|
/** 代码块与组件的绑定关系 */
|
||||||
|
comps?: CodeRelation;
|
||||||
|
/** 扩展字段 */
|
||||||
|
[propName: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CodeState = {
|
export type CodeState = {
|
||||||
@ -332,12 +336,15 @@ export type CodeState = {
|
|||||||
mode: CodeEditorMode;
|
mode: CodeEditorMode;
|
||||||
/** list模式下左侧展示的代码列表 */
|
/** list模式下左侧展示的代码列表 */
|
||||||
combineIds: string[];
|
combineIds: string[];
|
||||||
/** 组件和代码块的绑定关系 */
|
|
||||||
compRelation: CompRelation;
|
|
||||||
/** 为业务逻辑预留的不可删除的代码块列表,由业务逻辑维护(如代码块上线后不可删除) */
|
/** 为业务逻辑预留的不可删除的代码块列表,由业务逻辑维护(如代码块上线后不可删除) */
|
||||||
undeletableList: string[];
|
undeletableList: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CodeRelation = {
|
||||||
|
/** 组件id:['created'] */
|
||||||
|
[compId: string | number]: string[];
|
||||||
|
};
|
||||||
|
|
||||||
export enum CodeEditorMode {
|
export enum CodeEditorMode {
|
||||||
/** 左侧菜单,右侧代码 */
|
/** 左侧菜单,右侧代码 */
|
||||||
LIST = 'list',
|
LIST = 'list',
|
||||||
@ -345,11 +352,6 @@ export enum CodeEditorMode {
|
|||||||
EDITOR = 'editor',
|
EDITOR = 'editor',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CompRelation = {
|
|
||||||
/** 代码块绑定关系:组件id-代码块id数组 */
|
|
||||||
[compId: Id]: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface CodeDslList {
|
export interface CodeDslList {
|
||||||
/** 代码块id */
|
/** 代码块id */
|
||||||
id: string;
|
id: string;
|
||||||
@ -364,6 +366,9 @@ export interface CodeDslList {
|
|||||||
export interface ListState {
|
export interface ListState {
|
||||||
/** 代码块列表 */
|
/** 代码块列表 */
|
||||||
codeList: CodeDslList[];
|
codeList: CodeDslList[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListRelationState extends ListState {
|
||||||
/** 与代码块绑定的组件id信息 */
|
/** 与代码块绑定的组件id信息 */
|
||||||
bindComps: {
|
bindComps: {
|
||||||
/** 代码块id : 组件信息 */
|
/** 代码块id : 组件信息 */
|
||||||
@ -377,3 +382,12 @@ export enum CodeDeleteErrorType {
|
|||||||
/** 代码块存在绑定关系 */
|
/** 代码块存在绑定关系 */
|
||||||
BIND = 'bind',
|
BIND = 'bind',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CodeSelectOp {
|
||||||
|
/** 增加 */
|
||||||
|
ADD = 'add',
|
||||||
|
/** 删除 */
|
||||||
|
DELETE = 'delete',
|
||||||
|
/** 单选修改 */
|
||||||
|
CHANGE = 'change',
|
||||||
|
}
|
||||||
|
@ -25,11 +25,18 @@ export default {
|
|||||||
name: 'getData',
|
name: 'getData',
|
||||||
// eslint-disable-next-line no-eval
|
// eslint-disable-next-line no-eval
|
||||||
content: eval(`(vm) => {\n console.log("this is getData function")\n}`),
|
content: eval(`(vm) => {\n console.log("this is getData function")\n}`),
|
||||||
|
comps: {
|
||||||
|
page_299: ['mounted', 'created'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
code_5316: {
|
code_5316: {
|
||||||
name: 'getList',
|
name: 'getList',
|
||||||
// eslint-disable-next-line no-eval
|
// eslint-disable-next-line no-eval
|
||||||
content: eval(`(vm) => {\n console.log("this is getList function")\n}`),
|
content: eval(`(vm) => {\n console.log("this is getList function")\n}`),
|
||||||
|
comps: {
|
||||||
|
text_9027: ['created'],
|
||||||
|
page_299: ['created'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
@ -56,7 +63,7 @@ export default {
|
|||||||
fontWeight: '',
|
fontWeight: '',
|
||||||
},
|
},
|
||||||
events: [],
|
events: [],
|
||||||
created: ['code_5316'],
|
created: ['code_5316', 'code_5336'],
|
||||||
mounted: ['code_5336'],
|
mounted: ['code_5336'],
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user