1
0
mirror of synced 2026-04-18 18:18:35 +08:00
Files
tmagic-editor/packages/editor/src/fields/DataSourceMethodSelect.vue
roymondchen 31f4d2b4e2 fix(editor): 数据源方法选择器展示所有数据源并支持字段非叶子节点选择
移除 methodsOptions 中过滤无自定义方法数据源的逻辑,因为所有数据源都有内置"设置数据"方法;字段选择增加 checkStrictly 支持选择非叶子节点

Made-with: Cursor
2026-04-09 15:32:35 +08:00

217 lines
5.8 KiB
Vue

<template>
<div class="m-fields-data-source-method-select">
<div class="data-source-method-select-container">
<MCascader
class="select"
:config="cascaderConfig"
:model="model"
:name="name"
:size="size"
:disabled="disabled"
:prop="prop"
@change="onChangeHandler"
></MCascader>
<TMagicTooltip
v-if="model[name] && isCustomMethod && hasDataSourceSidePanel"
:content="notEditable ? '查看' : '编辑'"
>
<TMagicButton class="m-fields-select-action-button" :size="size" @click="editCodeHandler">
<MIcon :icon="!notEditable ? Edit : View"></MIcon>
</TMagicButton>
</TMagicTooltip>
</div>
<CodeParams
v-if="paramsConfig.length"
name="params"
:key="model[name]"
:model="model"
:size="size"
:disabled="disabled"
:params-config="paramsConfig"
@change="onParamsChangeHandler"
></CodeParams>
</div>
</template>
<script lang="ts" setup name="">
import { computed, inject, ref } from 'vue';
import { Edit, View } from '@element-plus/icons-vue';
import type { Id } from '@tmagic/core';
import { TMagicButton, TMagicTooltip } from '@tmagic/design';
import {
type CascaderConfig,
type ContainerChangeEventData,
createValues,
type DataSourceMethodSelectConfig,
type FieldProps,
filterFunction,
type FormItemConfig,
type FormState,
MCascader,
} from '@tmagic/form';
import { DATA_SOURCE_SET_DATA_METHOD_NAME } from '@tmagic/utils';
import CodeParams from '@editor/components/CodeParams.vue';
import MIcon from '@editor/components/Icon.vue';
import { useServices } from '@editor/hooks/use-services';
import type { CodeParamStatement, EventBus } from '@editor/type';
import { SideItemKey } from '@editor/type';
import { getFieldType } from '@editor/utils';
defineOptions({
name: 'MFieldsDataSourceMethodSelect',
});
const { dataSourceService, uiService } = useServices();
const mForm = inject<FormState | undefined>('mForm');
const eventBus = inject<EventBus>('eventBus');
const emit = defineEmits(['change']);
const props = withDefaults(defineProps<FieldProps<DataSourceMethodSelectConfig>>(), {
disabled: false,
});
const hasDataSourceSidePanel = computed(() =>
(uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
);
const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
const dataSources = computed(() => dataSourceService.get('dataSources'));
const isCustomMethod = computed(() => {
const [id, name] = props.model[props.name];
const dataSource = dataSourceService.getDataSourceById(id);
return Boolean(dataSource?.methods.find((method) => method.name === name));
});
const getParamItemsConfig = ([dataSourceId, methodName]: [Id, string] = ['', '']): CodeParamStatement[] => {
if (!dataSourceId) return [];
if (methodName === DATA_SOURCE_SET_DATA_METHOD_NAME) {
return [
{
name: 'field',
text: '字段',
type: 'data-source-field-select',
dataSourceId,
checkStrictly: true,
},
{
name: 'data',
text: '数据',
type: (_formState, { model }) => {
const fieldType = getFieldType(dataSourceService.getDataSourceById(`${dataSourceId}`), model.field);
let type = 'vs-code';
if (fieldType === 'number') {
type = 'number';
} else if (fieldType === 'string') {
type = 'text';
} else if (fieldType === 'boolean') {
type = 'switch';
}
return type;
},
language: 'javascript',
options: inject('codeOptions', {}),
autosize: {
minRows: 1,
maxRows: 10,
},
},
];
}
const paramStatements = dataSources.value
?.find((item) => item.id === dataSourceId)
?.methods?.find((item) => item.name === methodName)?.params;
if (!paramStatements) return [];
return paramStatements.map((paramState: CodeParamStatement) => ({
text: paramState.name,
...paramState,
}));
};
const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model[props.name || 'dataSourceMethod']));
const methodsOptions = computed(
() =>
dataSources.value?.map((ds) => ({
label: ds.title || ds.id,
value: ds.id,
children: [
{
label: '设置数据',
value: DATA_SOURCE_SET_DATA_METHOD_NAME,
},
...(dataSourceService?.getFormMethod(ds.type) || []),
...(ds.methods || []).map((method) => ({
label: method.name,
value: method.name,
})),
],
})) || [],
);
const cascaderConfig = computed<CascaderConfig>(() => ({
type: 'cascader',
options: methodsOptions.value,
}));
/**
* 参数值修改更新
*/
const onChangeHandler = (value: any) => {
paramsConfig.value = getParamItemsConfig(value);
const changeRecords = [
{
propPath: props.prop,
value,
},
];
changeRecords.push({
propPath: props.prop.replace(`${props.name}`, 'params'),
value: paramsConfig.value.length
? createValues(mForm, paramsConfig.value as unknown as FormItemConfig[], {}, props.model.params)
: {},
});
emit('change', value, {
changeRecords,
});
};
/**
* 参数值修改更新
*/
const onParamsChangeHandler = (value: any, eventData: ContainerChangeEventData) => {
eventData.changeRecords?.forEach((record) => {
record.propPath = `${props.prop.replace(`${props.name}`, '')}${record.propPath}`;
});
emit('change', props.model[props.name], eventData);
};
const editCodeHandler = () => {
const [id] = props.model[props.name];
const dataSource = dataSourceService.getDataSourceById(id);
if (!dataSource) return;
eventBus?.emit('edit-data-source', id);
};
</script>