feat(editor): 代码块支持传递参数 (merge request !9)

Squash merge branch 'feature/parisma_codeDraft' into 'master'
1、 table支持items为函数
2、代码块支持传递参数
This commit is contained in:
parisma 2022-11-15 16:30:09 +08:00 committed by roymondchen
parent cc21c47829
commit 16f671cd8f
11 changed files with 135 additions and 47 deletions

View File

@ -17,7 +17,7 @@
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup name="MEditorCodeDraftEditor">
import { computed, inject, ref, watchEffect } from 'vue'; import { computed, inject, ref, watchEffect } from 'vue';
import type * as monaco from 'monaco-editor'; import type * as monaco from 'monaco-editor';

View File

@ -5,6 +5,19 @@
<div class="code-name-label">代码块名称</div> <div class="code-name-label">代码块名称</div>
<TMagicInput class="code-name-input" v-model="codeName" :disabled="!editable" /> <TMagicInput class="code-name-input" v-model="codeName" :disabled="!editable" />
</div> </div>
<div class="code-name-wrapper">
<div class="code-name-label">参数定义</div>
<m-form-table
style="width: 320px"
:config="tableConfig"
:model="tableModel"
:enableToggleMode="false"
name="params"
prop="params"
size="small"
>
</m-form-table>
</div>
</template> </template>
<CodeDraftEditor <CodeDraftEditor
:id="id" :id="id"
@ -19,16 +32,29 @@
></CodeDraftEditor> ></CodeDraftEditor>
</TMagicCard> </TMagicCard>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup name="MEditorFunctionEditor">
import { inject, ref, watchEffect } from 'vue'; import { inject, provide, ref, watchEffect } from 'vue';
import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design'; import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design';
import { Id } from '@tmagic/schema'; import { CodeParam, Id } from '@tmagic/schema';
import type { Services } from '../type'; import type { Services } from '../type';
import CodeDraftEditor from './CodeDraftEditor.vue'; import CodeDraftEditor from './CodeDraftEditor.vue';
const tableConfig = {
border: true,
enableFullscreen: false,
name: 'params',
items: [
{
type: 'text',
label: '参数名',
name: 'name',
},
],
};
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
id: Id; id: Id;
@ -44,20 +70,39 @@ const props = withDefaults(
}, },
); );
const emit = defineEmits(['change', 'field-input']);
const services = inject<Services>('services'); const services = inject<Services>('services');
const codeName = ref<string>(''); const codeName = ref<string>('');
const codeContent = ref<string>(''); const codeContent = ref<string>('');
const evalRes = ref(true); const evalRes = ref(true);
provide('mForm', {
$emit: emit,
setField: () => {},
});
const tableModel = ref<{ params: CodeParam[] }>();
watchEffect(() => { watchEffect(() => {
codeName.value = props.name; codeName.value = props.name;
codeContent.value = props.content; codeContent.value = props.content;
}); });
const initTableModel = () => {
const codeDsl = services?.codeBlockService.getCodeDslSync();
if (!codeDsl) return;
tableModel.value = {
params: codeDsl[props.id]?.params || [],
};
};
initTableModel();
// //
const beforeSave = (codeValue: string): boolean => { const beforeSave = (codeValue: string): boolean => {
try { try {
// evaljs
// eslint-disable-next-line no-eval // eslint-disable-next-line no-eval
eval(codeValue); eval(codeValue);
return true; return true;
@ -76,6 +121,7 @@ const saveCode = async (codeValue: string): Promise<void> => {
await services?.codeBlockService.setCodeDslById(props.id, { await services?.codeBlockService.setCodeDslById(props.id, {
name: codeName.value, name: codeName.value,
content: codeValue, content: codeValue,
params: tableModel.value?.params || [],
}); });
tMagicMessage.success('代码保存成功'); tMagicMessage.success('代码保存成功');
// 稿 // 稿

View File

@ -4,6 +4,7 @@
:config="tableConfig" :config="tableConfig"
:model="model[name]" :model="model[name]"
name="hookData" name="hookData"
:enableToggleMode="false"
:prop="prop" :prop="prop"
:size="size" :size="size"
@change="changeHandler" @change="changeHandler"
@ -17,9 +18,9 @@ import { computed, defineEmits, defineProps, inject, watch } from 'vue';
import { isEmpty, map } from 'lodash-es'; import { isEmpty, map } from 'lodash-es';
import { FormItem, TableConfig } from '@tmagic/form'; import { FormItem, TableConfig } from '@tmagic/form';
import { HookType } from '@tmagic/schema'; import { HookType, Id } from '@tmagic/schema';
import { Services } from '../type'; import { CodeParamStatement, HookData, Services } from '../type';
const services = inject<Services>('services'); const services = inject<Services>('services');
const emit = defineEmits(['change']); const emit = defineEmits(['change']);
@ -32,19 +33,22 @@ const props = defineProps<{
name: string; name: string;
size: 'mini' | 'small' | 'medium'; size: 'mini' | 'small' | 'medium';
}>(); }>();
const codeDsl = computed(() => services?.codeBlockService.getCodeDslSync());
const tableConfig = computed<FormItem>(() => { const tableConfig = computed<FormItem>(() => {
const defaultConfig = { const defaultConfig = {
dropSort: true, dropSort: true,
enableFullscreen: false,
border: true,
items: [ items: [
{ {
type: 'select', type: 'select',
label: '代码块', label: '代码块',
name: 'codeId', name: 'codeId',
options: async () => { width: '200px',
const codeDsl = await services?.codeBlockService.getCodeDsl(); options: () => {
if (codeDsl) { if (codeDsl.value) {
return map(codeDsl, (value, key) => ({ return map(codeDsl.value, (value, key) => ({
text: `${value.name}${key}`, text: `${value.name}${key}`,
label: `${value.name}${key}`, label: `${value.name}${key}`,
value: key, value: key,
@ -52,6 +56,16 @@ const tableConfig = computed<FormItem>(() => {
} }
return []; return [];
}, },
onChange: (formState: any, codeId: Id, { model }: any) => {
// itemscodeIdmodelcodeIdparams
model.params = {};
},
},
{
name: 'params',
label: '参数',
defaultValue: {},
itemsFunction: (row: HookData) => getParamsConfig(row.codeId),
}, },
], ],
}; };
@ -71,15 +85,6 @@ watch(
hookType: HookType.CODE, hookType: HookType.CODE,
hookData: [], hookData: [],
}; };
} else if (Array.isArray(value) && value.length > 0) {
// ['code1','code2']
const hookData = value.map((codeId) => ({
codeId,
}));
props.model[props.name] = {
hookType: HookType.CODE,
hookData,
};
} }
}, },
{ {
@ -90,4 +95,16 @@ watch(
const changeHandler = async () => { const changeHandler = async () => {
emit('change', props.model[props.name]); emit('change', props.model[props.name]);
}; };
const getParamsConfig = (codeId: Id) => {
if (!codeDsl.value) return [];
const paramStatements = codeDsl.value[codeId]?.params;
if (isEmpty(paramStatements)) return [];
return paramStatements.map((paramState: CodeParamStatement) => ({
name: paramState.name,
text: paramState.name,
labelWidth: '100px',
type: 'text',
}));
};
</script> </script>

View File

@ -145,7 +145,7 @@ const initList = async () => {
}; };
watch( watch(
[() => services?.codeBlockService.getCodeDsl(), () => services?.codeBlockService.refreshCombineInfo()], [() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.refreshCombineInfo()],
() => { () => {
initList(); initList();
}, },
@ -165,6 +165,7 @@ const createCodeBlock = async () => {
const codeConfig: CodeBlockContent = { const codeConfig: CodeBlockContent = {
name: '代码块', name: '代码块',
content: `() => {\n // place your code here\n}`, content: `() => {\n // place your code here\n}`,
params: [],
}; };
await codeBlockService.setMode(CodeEditorMode.EDITOR); await codeBlockService.setMode(CodeEditorMode.EDITOR);
const id = await codeBlockService.getUniqueId(); const id = await codeBlockService.getUniqueId();

View File

@ -71,12 +71,17 @@ class CodeBlock extends BaseService {
/** /**
* dsl数据源dsl中的codeBlocks字段读取 * dsl数据源dsl中的codeBlocks字段读取
* ,
* @param {boolean} forceRefresh dsl拉取刷新 * @param {boolean} forceRefresh dsl拉取刷新
* @returns {CodeBlockDSL | null} * @returns {CodeBlockDSL | null}
*/ */
public async getCodeDsl(forceRefresh = false): Promise<CodeBlockDSL | null> { public async getCodeDsl(forceRefresh = false): Promise<CodeBlockDSL | null> {
return this.getCodeDslSync(forceRefresh);
}
public getCodeDslSync(forceRefresh = false): CodeBlockDSL | null {
if (!this.state.codeDsl || forceRefresh) { if (!this.state.codeDsl || forceRefresh) {
this.state.codeDsl = await editorService.getCodeDsl(); this.state.codeDsl = editorService.getCodeDslSync();
} }
return this.state.codeDsl; return this.state.codeDsl;
} }

View File

@ -788,6 +788,12 @@ class Editor extends BaseService {
return root.codeBlocks || null; return root.codeBlocks || null;
} }
public getCodeDslSync(): CodeBlockDSL | null {
const root = this.get<MApp | null>('root');
if (!root) return null;
return root.codeBlocks || null;
}
/** /**
* dsl的codeBlocks字段 * dsl的codeBlocks字段
* @param {CodeBlockDSL} codeDsl DSL * @param {CodeBlockDSL} codeDsl DSL

View File

@ -87,7 +87,7 @@
height: 100%; height: 100%;
background: #fff; background: #fff;
.el-card__body { .el-card__body {
height: calc(100% - 80px); height: 100%;
background: #fff; background: #fff;
} }
} }
@ -127,6 +127,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 16px; font-size: 16px;
margin-bottom: 10px;
.code-name-label { .code-name-label {
margin-right: 10px; margin-right: 10px;
} }
@ -148,7 +149,7 @@
position: absolute; position: absolute;
top: 0; top: 0;
left: 4px; left: 4px;
width: calc(100% - 9px); width: 100%;
height: 100%; height: 100%;
z-index: 10; z-index: 10;
background: #fff; background: #fff;
@ -160,14 +161,17 @@
.m-editor-wrapper { .m-editor-wrapper {
height: 100%; height: 100%;
.m-editor-container { .m-editor-container {
height: calc(100% - 70px); height: calc(100% - 65px);
} }
.m-editor-content-bottom { .m-editor-content-bottom {
height: 40px; height: 45px;
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: end; justify-content: end;
background: #fff; background: #fff;
position: absolute;
right: 20px;
bottom: 0;
> button { > button {
height: 30px; height: 30px;
margin-top: 15px; margin-top: 15px;

View File

@ -383,3 +383,10 @@ export enum CodeDeleteErrorType {
// 代码块草稿localStorage key // 代码块草稿localStorage key
export const CODE_DRAFT_STORAGE_KEY = 'magicCodeDraft'; export const CODE_DRAFT_STORAGE_KEY = 'magicCodeDraft';
export interface CodeParamStatement {
/** 参数名称 */
name: string;
/** 参数类型 */
type?: string;
}

View File

@ -101,7 +101,7 @@
labelWidth="0" labelWidth="0"
:prop="getProp(scope.$index)" :prop="getProp(scope.$index)"
:rules="column.rules" :rules="column.rules"
:config="makeConfig(column)" :config="makeConfig(column, scope.row)"
:model="scope.row" :model="scope.row"
:size="size" :size="size"
@change="$emit('change', model[modelName])" @change="$emit('change', model[modelName])"
@ -432,8 +432,11 @@ const toggleRowSelection = (row: any, selected: boolean) => {
tMagicTable.value?.toggleRowSelection.call(tMagicTable.value, row, selected); tMagicTable.value?.toggleRowSelection.call(tMagicTable.value, row, selected);
}; };
const makeConfig = (config: ColumnConfig) => { const makeConfig = (config: ColumnConfig, row: any) => {
const newConfig = cloneDeep(config); const newConfig = cloneDeep(config);
if (typeof config.itemsFunction === 'function') {
newConfig.items = config.itemsFunction(row);
}
delete newConfig.display; delete newConfig.display;
return newConfig; return newConfig;
}; };

View File

@ -81,10 +81,16 @@ export interface CodeBlockContent {
name: string; name: string;
/** 代码块内容 */ /** 代码块内容 */
content: any; content: any;
/** 参数定义 */
params: CodeParam[] | [];
/** 扩展字段 */ /** 扩展字段 */
[propName: string]: any; [propName: string]: any;
} }
export interface CodeParam {
/** 参数名 */
name: string;
}
export interface PastePosition { export interface PastePosition {
left?: number; left?: number;
top?: number; top?: number;

View File

@ -24,13 +24,21 @@ export default {
code_5336: { code_5336: {
name: 'getData', name: 'getData',
// eslint-disable-next-line no-eval // eslint-disable-next-line no-eval
content: eval(`(vm, params) => {\n console.log("this is getData function",vm,params)\n}`), content: eval(`(vm, params) => {\n console.log("this is getData function",params)\n}`),
params: ['name', 'age'], params: [
{
name: 'age',
},
{
name: 'studentName',
},
],
}, },
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}`),
params: [],
}, },
}, },
items: [ items: [
@ -63,20 +71,13 @@ export default {
{ {
codeId: 'code_5336', codeId: 'code_5336',
params: { params: {
name: 'lisa', studentName: 'lisa',
age: 12, age: 14,
}, },
}, },
{ {
codeId: 'code_5316', codeId: 'code_5316',
}, params: {},
],
},
mounted: {
hookType: 'code',
hookData: [
{
codeId: 'code_5316',
}, },
], ],
}, },
@ -104,14 +105,6 @@ export default {
text: 'Tmagic editor 营销活动编辑器', text: 'Tmagic editor 营销活动编辑器',
multiple: true, multiple: true,
events: [], events: [],
created: {
hookType: 'code',
hookData: [
{
codeId: 'code_5316',
},
],
},
}, },
{ {
type: 'qrcode', type: 'qrcode',