feat(editor): 支持禁用数据源与代码块

This commit is contained in:
roymondchen 2025-06-09 16:35:08 +08:00
parent b1f020d532
commit 6152a78467
10 changed files with 263 additions and 47 deletions

View File

@ -415,6 +415,26 @@ const renderFunction = async (stage) => {
</script>
```
## renderType
- **详情:**
是用iframe渲染还是直接渲染
- **默认值:** `iframe`
- **类型:** `string`
'iframe' | 'native'
- **示例:**
```html
<template>
<m-editor render-type="native"></m-editor>
</template>
```
## autoScrollIntoView
- **详情:**
@ -942,4 +962,88 @@ const updateDragEl = (el, target) => {
<m-editor :disabled-multi-select="true"></m-editor>
</template>
```
## guidesOptions
- **详情:**
标尺配置
- **类型:** `Partial<GuidesOptions>`
## disabledPageFragment
- **详情:**
禁用页面片
- **类型:** `boolean`
## disabledStageOverlay
- **详情:**
禁用双击在浮层中单独编辑选中组件
- **类型:** `boolean`
## disabledShowSrc
- **详情:**
禁用属性配置面板右下角显示源码的按钮
- **类型:** `boolean`
## disabledDataSource
- **详情:**
禁用数据源
- **类型:** `boolean`
## disabledCodeBlock
- **详情:**
禁用代码块
- **类型:** `boolean`
## treeIndent
- **详情:**
已选组件、代码编辑、数据源缩进配置
- **类型:** `number`
## treeNextLevelIndentIncrement
- **详情:**
已选组件、代码编辑、数据源子节点缩进增量配置
- **类型:** `number`
## customContentMenu
- **详情:**
用于自定义组件树与画布的右键菜单
- **类型:** `function`
## pageBarSortOptions
- **详情:**
页面顺序拖拽配置参数
## pageFilterFunction
- **详情:**
页面搜索函数

View File

@ -81,6 +81,10 @@ export interface EditorProps {
disabledStageOverlay?: boolean;
/** 禁用属性配置面板右下角显示源码的按钮 */
disabledShowSrc?: boolean;
/** 禁用数据源 */
disabledDataSource?: boolean;
/** 禁用代码块 */
disabledCodeBlock?: boolean;
/** 已选组件、代码编辑、数据源缩进配置 */
treeIndent?: number;
/** 已选组件、代码编辑、数据源子节点缩进增量配置 */
@ -111,6 +115,8 @@ export const defaultEditorProps = {
containerHighlightDuration: 800,
containerHighlightType: ContainerHighlightType.DEFAULT,
disabledShowSrc: false,
disabledDataSource: false,
disabledCodeBlock: false,
componentGroupList: () => [],
datasourceList: () => [],
menu: () => ({ left: [], right: [] }),

View File

@ -1,7 +1,7 @@
<template>
<div class="m-fields-data-source-field-select">
<FieldSelect
v-if="showDataSourceFieldSelect || !config.fieldConfig"
v-if="!disabledDataSource && (showDataSourceFieldSelect || !config.fieldConfig)"
:model-value="model[name]"
:disabled="disabled"
:size="size"
@ -26,7 +26,11 @@
@change="onChangeHandler"
></component>
<TMagicTooltip v-if="config.fieldConfig" :disabled="showDataSourceFieldSelect" content="选择数据源">
<TMagicTooltip
v-if="config.fieldConfig && !disabledDataSource"
:disabled="showDataSourceFieldSelect"
content="选择数据源"
>
<TMagicButton
style="margin-left: 5px"
:type="showDataSourceFieldSelect ? 'primary' : 'default'"
@ -83,10 +87,11 @@ watch(
},
);
const { dataSourceService } = useServices();
const { dataSourceService, propsService } = useServices();
const mForm = inject<FormState | undefined>('mForm');
const dataSources = computed(() => dataSourceService.get('dataSources') || []);
const disabledDataSource = computed(() => propsService.getDisabledDataSource());
const type = computed((): string => {
let type = props.config.fieldConfig?.type;

View File

@ -1,6 +1,14 @@
<template>
<TMagicInput
v-if="disabledDataSource"
v-model="state"
:disabled="disabled"
:size="size"
:clearable="true"
@change="changeHandler"
></TMagicInput>
<component
v-if="disabled || isFocused"
v-else-if="disabled || isFocused"
:is="getDesignConfig('components')?.autocomplete.component || 'el-autocomplete'"
class="tmagic-design-auto-complete"
ref="autocomplete"
@ -52,7 +60,7 @@ import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
import { Coin } from '@element-plus/icons-vue';
import type { DataSchema, DataSourceSchema } from '@tmagic/core';
import { getDesignConfig, TMagicAutocomplete, TMagicTag } from '@tmagic/design';
import { getDesignConfig, TMagicAutocomplete, TMagicInput, TMagicTag } from '@tmagic/design';
import type { DataSourceInputConfig, FieldProps } from '@tmagic/form';
import { getKeysArray, isNumber } from '@tmagic/utils';
@ -72,7 +80,7 @@ const emit = defineEmits<{
change: [value: string];
}>();
const { dataSourceService } = useServices();
const { dataSourceService, propsService } = useServices();
const autocompleteRef = useTemplateRef<InstanceType<typeof TMagicAutocomplete>>('autocomplete');
const isFocused = ref(false);
@ -81,6 +89,7 @@ const displayState = ref<{ value: string; type: 'var' | 'text' }[]>([]);
const input = computed<HTMLInputElement>(() => autocompleteRef.value?.inputRef?.input);
const dataSources = computed(() => dataSourceService.get('dataSources'));
const disabledDataSource = computed(() => propsService.getDisabledDataSource());
const setDisplayState = () => {
displayState.value = getDisplayField(dataSources.value, state.value);

View File

@ -85,7 +85,7 @@ const emit = defineEmits<{
change: [v: any, eventData?: ContainerChangeEventData];
}>();
const { editorService, dataSourceService, eventsService, codeBlockService } = useServices();
const { editorService, dataSourceService, eventsService, codeBlockService, propsService } = useServices();
//
const eventNameConfig = computed(() => {
@ -173,24 +173,39 @@ const actionTypeConfig = computed(() => {
text: '联动类型',
type: 'select',
defaultValue: ActionType.COMP,
options: () => [
{
text: '组件',
label: '组件',
value: ActionType.COMP,
},
{
text: '代码',
label: '代码',
disabled: !Object.keys(codeBlockService.getCodeDsl() || {}).length,
value: ActionType.CODE,
},
{
text: '数据源',
label: '数据源',
value: ActionType.DATA_SOURCE,
},
],
options: () => {
const o: {
text: string;
label: string;
value: string;
disabled?: boolean;
}[] = [
{
text: '组件',
label: '组件',
value: ActionType.COMP,
},
];
if (!propsService.getDisabledCodeBlock()) {
o.push({
text: '代码',
label: '代码',
disabled: !Object.keys(codeBlockService.getCodeDsl() || {}).length,
value: ActionType.CODE,
});
}
if (!propsService.getDisabledDataSource()) {
o.push({
text: '数据源',
label: '数据源',
value: ActionType.DATA_SOURCE,
});
}
return o;
},
};
return { ...defaultActionTypeConfig, ...props.config.actionTypeConfig };
});

View File

@ -197,6 +197,22 @@ export const initServiceState = (
},
);
watch(
() => props.disabledCodeBlock,
(disabledCodeBlock) => propsService.setDisabledCodeBlock(disabledCodeBlock ?? false),
{
immediate: true,
},
);
watch(
() => props.disabledDataSource,
(disabledDataSource) => propsService.setDisabledDataSource(disabledDataSource ?? false),
{
immediate: true,
},
);
onBeforeUnmount(() => {
editorService.resetState();
historyService.resetState();

View File

@ -201,7 +201,7 @@ const props = withDefaults(
},
);
const { depService, uiService } = useServices();
const { depService, uiService, propsService } = useServices();
const collecting = computed(() => depService.get('collecting'));
const taskLength = computed(() => depService.get('taskLength'));
@ -283,7 +283,19 @@ const getItemConfig = (data: SideItem): SideComponent => {
return typeof data === 'string' ? map[data] : data;
};
const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
const sideBarItems = computed(() =>
props.data.items
.map((item) => getItemConfig(item))
.filter((item) => {
if (item.$key === SideItemKey.DATA_SOURCE) {
return !propsService.getDisabledDataSource();
}
if (item.$key === SideItemKey.CODE_BLOCK) {
return !propsService.getDisabledCodeBlock();
}
return true;
}),
);
watch(
sideBarItems,

View File

@ -57,6 +57,10 @@ class Props extends BaseService {
propsConfigMap: {},
propsValueMap: {},
relateIdMap: {},
/** 禁用数据源 */
disabledDataSource: false,
/** 禁用代码块 */
disabledCodeBlock: false,
});
constructor() {
@ -66,6 +70,22 @@ class Props extends BaseService {
]);
}
public setDisabledDataSource(disabled: boolean) {
this.state.disabledDataSource = disabled;
}
public setDisabledCodeBlock(disabled: boolean) {
this.state.disabledCodeBlock = disabled;
}
public getDisabledDataSource(): boolean {
return this.state.disabledDataSource;
}
public getDisabledCodeBlock(): boolean {
return this.state.disabledCodeBlock;
}
public setPropsConfigs(configs: Record<string, FormConfig | PropsFormConfigFunction>) {
Object.keys(configs).forEach((type: string) => {
this.setPropsConfig(toLine(type), configs[type]);
@ -74,7 +94,11 @@ class Props extends BaseService {
}
public async fillConfig(config: FormConfig, labelWidth?: string) {
return fillConfig(config, typeof labelWidth !== 'function' ? labelWidth : '80px');
return fillConfig(config, {
labelWidth: typeof labelWidth !== 'function' ? labelWidth : '80px',
disabledDataSource: this.getDisabledDataSource(),
disabledCodeBlock: this.getDisabledCodeBlock(),
});
}
public async setPropsConfig(type: string, config: FormConfig | PropsFormConfigFunction) {

View File

@ -188,6 +188,10 @@ export interface PropsState {
propsConfigMap: Record<string, FormConfig>;
propsValueMap: Record<string, Partial<MNode>>;
relateIdMap: Record<Id, Id>;
/** 禁用数据源 */
disabledDataSource: boolean;
/** 禁用代码块 */
disabledCodeBlock: boolean;
}
export interface StageOverlayState {

View File

@ -19,7 +19,7 @@
import { NODE_CONDS_KEY } from '@tmagic/core';
import { tMagicMessage } from '@tmagic/design';
import type { FormConfig, FormState, TabPaneConfig } from '@tmagic/form';
import type { FormConfig, FormState, TabConfig, TabPaneConfig } from '@tmagic/form';
export const arrayOptions = [
{ text: '包含', value: 'include' },
@ -165,7 +165,14 @@ export const displayTabConfig: TabPaneConfig = {
* @param config
* @returns Object
*/
export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormConfig => {
export const fillConfig = (
config: FormConfig = [],
{
labelWidth = '80px',
disabledDataSource = false,
disabledCodeBlock = false,
}: { labelWidth?: string; disabledDataSource?: boolean; disabledCodeBlock?: boolean } = {},
): FormConfig => {
const propsConfig: FormConfig = [];
// 组件类型,必须要有
@ -208,20 +215,34 @@ export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormCo
});
}
return [
{
type: 'tab',
labelWidth,
items: [
{
title: '属性',
items: [...propsConfig, ...config],
},
{ ...styleTabConfig },
{ ...eventTabConfig },
{ ...advancedTabConfig },
{ ...displayTabConfig },
],
},
];
const noCodeAdvancedTabItems = advancedTabConfig.items.filter((item) => item.type !== 'code-select');
if (noCodeAdvancedTabItems.length > 0 && disabledCodeBlock) {
advancedTabConfig.items = noCodeAdvancedTabItems;
}
const tabConfig: TabConfig = {
type: 'tab',
labelWidth,
items: [
{
title: '属性',
items: [...propsConfig, ...config],
},
{ ...styleTabConfig },
{ ...eventTabConfig },
],
};
if (!disabledCodeBlock) {
tabConfig.items.push({ ...advancedTabConfig });
} else if (noCodeAdvancedTabItems.length > 0) {
tabConfig.items.push({ ...advancedTabConfig });
}
if (!disabledDataSource) {
tabConfig.items.push({ ...displayTabConfig });
}
return [tabConfig];
};