Skip to content

Commit f583c7d

Browse files
author
roymondchen
committed
feat(editor,data-source): 数据源支持内置"设置数据"方法
支持通过事件调用数据源的 setData 方法,可以选择数据源字段并根据字段类型动态设置数据; 重构 CodeParams 参数配置支持动态类型; DataSourceFieldSelect 支持指定数据源ID; 常量抽取到 utils/const.ts Made-with: Cursor
1 parent 172a7a1 commit f583c7d

10 files changed

Lines changed: 126 additions & 21 deletions

File tree

packages/core/src/App.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ class App extends EventEmitter {
297297
}
298298

299299
if (typeof dataSource[methodName] === 'function') {
300-
return await dataSource[methodName]();
300+
return await dataSource[methodName]({ params });
301301
}
302302
} catch (e: any) {
303303
if (this.errorHandler) {

packages/data-source/src/data-sources/Base.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import EventEmitter from 'events';
2020
import { cloneDeep } from 'lodash-es';
2121

2222
import type { CodeBlockContent, DataSchema, DataSourceSchema, default as TMagicApp } from '@tmagic/core';
23-
import { getDefaultValueFromFields } from '@tmagic/core';
23+
import { DATA_SOURCE_SET_DATA_METHOD_NAME, getDefaultValueFromFields } from '@tmagic/core';
2424

2525
import { ObservedData } from '@data-source/observed-data/ObservedData';
2626
import { SimpleObservedData } from '@data-source/observed-data/SimpleObservedData';
@@ -51,13 +51,19 @@ export default class DataSource<T extends DataSourceSchema = DataSourceSchema> e
5151
super();
5252

5353
this.#id = options.schema.id;
54+
this.#type = options.schema.type;
5455
this.#schema = options.schema;
5556

5657
this.app = options.app;
5758

5859
this.setFields(options.schema.fields);
5960
this.setMethods(options.schema.methods || []);
6061

62+
// @ts-ignore
63+
this[DATA_SOURCE_SET_DATA_METHOD_NAME] = ({ params }: { params: { field?: string[]; data: any } }) => {
64+
this.setData(params.data, params.field?.join('.'));
65+
};
66+
6167
let data = options.initialData;
6268
// eslint-disable-next-line @typescript-eslint/naming-convention
6369
const ObservedDataClass = options.ObservedDataClass || SimpleObservedData;

packages/editor/src/components/CodeParams.vue

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,29 @@ const getFormConfig = (items: FormItemConfig[] = []) => [
4646
4747
const codeParamsConfig = computed(() =>
4848
getFormConfig(
49-
props.paramsConfig.map(({ name, text, extra, ...config }) => ({
50-
type: 'data-source-field-select',
51-
name,
52-
text,
53-
extra,
54-
fieldConfig: config as FormItemConfig,
55-
})),
49+
props.paramsConfig.map(({ name, text, extra, ...config }) => {
50+
let { type } = config;
51+
if (typeof type === 'function') {
52+
type = type(undefined, {
53+
model: props.model[props.name],
54+
});
55+
}
56+
if (type && ['data-source-field-select', 'vs-code'].includes(type)) {
57+
return {
58+
...config,
59+
name,
60+
text,
61+
extra,
62+
};
63+
}
64+
return {
65+
type: 'data-source-field-select' as const,
66+
name,
67+
text,
68+
extra,
69+
fieldConfig: config,
70+
};
71+
}) as FormItemConfig[],
5672
),
5773
);
5874

packages/editor/src/fields/DataSourceFieldSelect/FieldSelect.vue

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
<template>
22
<div class="m-editor-data-source-field-select">
3-
<template v-if="checkStrictly">
3+
<template v-if="dataSourceId">
4+
<TMagicCascader
5+
:model-value="selectFieldsId"
6+
clearable
7+
filterable
8+
:size="size"
9+
:disabled="disabled"
10+
:options="fieldsOptions"
11+
:props="{
12+
checkStrictly,
13+
}"
14+
@change="fieldChangeHandler"
15+
></TMagicCascader>
16+
</template>
17+
18+
<template v-else-if="checkStrictly">
419
<TMagicSelect
520
:model-value="selectDataSourceId"
621
clearable
@@ -92,6 +107,8 @@ const props = defineProps<{
92107
dataSourceFieldType?: DataSourceFieldType[];
93108
/** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
94109
notEditable?: boolean | FilterFunction;
110+
/** 指定数据源ID,限定只能选择该数据源的字段 */
111+
dataSourceId?: string;
95112
}>();
96113
97114
const emit = defineEmits<{
@@ -106,7 +123,12 @@ const { dataSourceService, uiService } = useServices();
106123
const mForm = inject<FormState | undefined>('mForm');
107124
const eventBus = inject<EventBus>('eventBus');
108125
109-
const dataSources = computed(() => dataSourceService.get('dataSources') || []);
126+
const allDataSources = computed(() => dataSourceService.get('dataSources') || []);
127+
128+
const dataSources = computed(() => {
129+
if (!props.dataSourceId) return allDataSources.value;
130+
return allDataSources.value.filter((ds) => ds.id === props.dataSourceId);
131+
});
110132
111133
const valueIsKey = computed(() => props.value === 'key');
112134
const notEditable = computed(() => filterFunction(mForm, props.notEditable, props));
@@ -125,7 +147,13 @@ const selectFieldsId = ref<string[]>([]);
125147
watch(
126148
modelValue,
127149
(value) => {
128-
if (Array.isArray(value)) {
150+
if (props.dataSourceId) {
151+
const dsIdValue = valueIsKey.value
152+
? props.dataSourceId
153+
: `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${props.dataSourceId}`;
154+
selectDataSourceId.value = dsIdValue;
155+
selectFieldsId.value = Array.isArray(value) ? value : [];
156+
} else if (Array.isArray(value) && value.length) {
129157
const [dsId, ...fields] = value;
130158
selectDataSourceId.value = dsId;
131159
selectFieldsId.value = fields;
@@ -140,7 +168,7 @@ watch(
140168
);
141169
142170
const fieldsOptions = computed(() => {
143-
const ds = dataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(selectDataSourceId.value));
171+
const ds = allDataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(selectDataSourceId.value));
144172
145173
if (!ds) return [];
146174
@@ -163,8 +191,13 @@ const dsChangeHandler = (v: string) => {
163191
};
164192
165193
const fieldChangeHandler = (v: string[] = []) => {
166-
modelValue.value = [selectDataSourceId.value, ...v];
167-
emit('change', modelValue.value);
194+
if (props.dataSourceId) {
195+
modelValue.value = v;
196+
emit('change', v);
197+
} else {
198+
modelValue.value = [selectDataSourceId.value, ...v];
199+
emit('change', modelValue.value);
200+
}
168201
};
169202
170203
const onChangeHandler = (v: string[] = []) => {

packages/editor/src/fields/DataSourceFieldSelect/Index.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:value="config.value"
99
:checkStrictly="checkStrictly"
1010
:dataSourceFieldType="config.dataSourceFieldType"
11+
:dataSourceId="config.dataSourceId"
1112
@change="onChangeHandler"
1213
></FieldSelect>
1314

packages/editor/src/fields/DataSourceMethodSelect.vue

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ import {
5252
type FormState,
5353
MCascader,
5454
} from '@tmagic/form';
55+
import { DATA_SOURCE_SET_DATA_METHOD_NAME } from '@tmagic/utils';
5556
5657
import CodeParams from '@editor/components/CodeParams.vue';
5758
import MIcon from '@editor/components/Icon.vue';
5859
import { useServices } from '@editor/hooks/use-services';
5960
import type { CodeParamStatement, EventBus } from '@editor/type';
6061
import { SideItemKey } from '@editor/type';
62+
import { getFieldType } from '@editor/utils';
6163
6264
defineOptions({
6365
name: 'MFieldsDataSourceMethodSelect',
@@ -92,6 +94,42 @@ const isCustomMethod = computed(() => {
9294
const getParamItemsConfig = ([dataSourceId, methodName]: [Id, string] = ['', '']): CodeParamStatement[] => {
9395
if (!dataSourceId) return [];
9496
97+
if (methodName === DATA_SOURCE_SET_DATA_METHOD_NAME) {
98+
return [
99+
{
100+
name: 'field',
101+
text: '字段',
102+
type: 'data-source-field-select',
103+
dataSourceId,
104+
},
105+
{
106+
name: 'data',
107+
text: '数据',
108+
type: (_formState, { model }) => {
109+
const fieldType = getFieldType(dataSourceService.getDataSourceById(`${dataSourceId}`), model.field);
110+
111+
let type = 'vs-code';
112+
113+
if (fieldType === 'number') {
114+
type = 'number';
115+
} else if (fieldType === 'string') {
116+
type = 'text';
117+
} else if (fieldType === 'boolean') {
118+
type = 'switch';
119+
}
120+
121+
return type;
122+
},
123+
language: 'javascript',
124+
options: inject('codeOptions', {}),
125+
autosize: {
126+
minRows: 1,
127+
maxRows: 10,
128+
},
129+
},
130+
];
131+
}
132+
95133
const paramStatements = dataSources.value
96134
?.find((item) => item.id === dataSourceId)
97135
?.methods?.find((item) => item.name === methodName)?.params;
@@ -114,6 +152,10 @@ const methodsOptions = computed(
114152
label: ds.title || ds.id,
115153
value: ds.id,
116154
children: [
155+
{
156+
label: '设置数据',
157+
value: DATA_SOURCE_SET_DATA_METHOD_NAME,
158+
},
117159
...(dataSourceService?.getFormMethod(ds.type) || []),
118160
...(ds.methods || []).map((method) => ({
119161
label: method.name,

packages/editor/src/type.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import type { default as Sortable, Options, SortableEvent } from 'sortablejs';
2323
import type { PascalCasedProperties, Writable } from 'type-fest';
2424

2525
import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/core';
26-
import type { ChangeRecord, FormConfig, TableColumnConfig } from '@tmagic/form';
26+
import type { ChangeRecord, FormConfig, TableColumnConfig, TypeFunction } from '@tmagic/form';
2727
import type StageCore from '@tmagic/stage';
2828
import type {
2929
ContainerHighlightType,
@@ -541,7 +541,7 @@ export interface CodeParamStatement {
541541
/** 参数名称 */
542542
name: string;
543543
/** 参数类型 */
544-
type?: string;
544+
type?: string | TypeFunction<string>;
545545
[key: string]: any;
546546
}
547547

packages/form-schema/src/editor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface DataSourceFieldSelectConfig<T = never> extends FormItem {
2929
fieldConfig?: FormItemConfig<T>;
3030
/** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
3131
notEditable?: boolean | FilterFunction;
32+
33+
dataSourceId?: string;
3234
}
3335

3436
export interface CodeConfig extends FormItem {

packages/utils/src/const.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX = 'ds-field::';
2+
3+
export const DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX = 'ds-field-changed';
4+
5+
export const DATA_SOURCE_SET_DATA_METHOD_NAME = 'setDataFromEvent';

packages/utils/src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ import { NodeType } from '@tmagic/schema';
3535

3636
import type { EditorNodeInfo } from '@editor/type';
3737

38+
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from './const';
39+
3840
export * from './dom';
3941

42+
export * from './const';
43+
4044
// for typeof global checks without @types/node
4145
declare let global: {};
4246

@@ -542,10 +546,6 @@ export const getDefaultValueFromFields = (fields: DataSchema[]) => {
542546
return data;
543547
};
544548

545-
export const DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX = 'ds-field::';
546-
547-
export const DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX = 'ds-field-changed';
548-
549549
export const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>;
550550

551551
export const calculatePercentage = (value: number, percentageStr: string) => {

0 commit comments

Comments
 (0)