mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-13 00:09:20 +08:00
feat(editor): 代码块绑定功能完成
This commit is contained in:
parent
040d5d0d2c
commit
0c25cf795f
46
packages/editor/src/fields/CodeSelect.vue
Normal file
46
packages/editor/src/fields/CodeSelect.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div class="m-fields-code-select">
|
||||
<m-fields-select
|
||||
:config="config.selectConfig"
|
||||
:model="model"
|
||||
:prop="prop"
|
||||
:name="name"
|
||||
:size="size"
|
||||
@change="changeHandler"
|
||||
></m-fields-select>
|
||||
<el-button type="primary" :icon="View" :size="size" @click="viewHandler">查看</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineEmits, defineProps, inject } from 'vue';
|
||||
import { View } from '@element-plus/icons-vue';
|
||||
|
||||
import { SelectConfig } from '@tmagic/form';
|
||||
|
||||
import type { Services } from '../type';
|
||||
import { EditorMode } from '../type';
|
||||
const services = inject<Services>('services');
|
||||
|
||||
const emit = defineEmits(['change']);
|
||||
|
||||
const props = defineProps<{
|
||||
config: {
|
||||
selectConfig: SelectConfig;
|
||||
};
|
||||
model: any;
|
||||
prop: string;
|
||||
name: string;
|
||||
size: string;
|
||||
}>();
|
||||
|
||||
const changeHandler = (value: any) => {
|
||||
emit('change', value);
|
||||
};
|
||||
|
||||
const viewHandler = () => {
|
||||
services?.codeBlockService.setMode(EditorMode.LIST);
|
||||
services?.codeBlockService.setCombineIds(props.model[props.name]);
|
||||
services?.codeBlockService.setCodeEditorContent(true, props.model[props.name][0]);
|
||||
};
|
||||
</script>
|
@ -19,6 +19,7 @@ import { App } from 'vue';
|
||||
|
||||
import Code from './fields/Code.vue';
|
||||
import CodeLink from './fields/CodeLink.vue';
|
||||
import CodeSelect from './fields/CodeSelect.vue';
|
||||
import uiSelect from './fields/UISelect.vue';
|
||||
import CodeEditor from './layouts/CodeEditor.vue';
|
||||
import { setConfig } from './utils/config';
|
||||
@ -56,11 +57,11 @@ export default {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
app.config.globalProperties.$TMAGIC_EDITOR = option;
|
||||
setConfig(option);
|
||||
|
||||
app.component(Editor.name, Editor);
|
||||
app.component('m-fields-ui-select', uiSelect);
|
||||
app.component('m-fields-code-link', CodeLink);
|
||||
app.component('m-fields-vs-code', Code);
|
||||
app.component(CodeEditor.name, CodeEditor);
|
||||
app.component('m-fields-code-select', CodeSelect);
|
||||
},
|
||||
};
|
||||
|
@ -1,13 +1,31 @@
|
||||
<template>
|
||||
<el-dialog v-model="isShowCodeBlockEditor" title="代码块编辑面板" :fullscreen="true">
|
||||
<div class="m-editor-code-block-editor-panel">
|
||||
<el-dialog
|
||||
v-model="isShowCodeBlockEditor"
|
||||
title="代码块编辑面板"
|
||||
:fullscreen="true"
|
||||
:before-close="saveAndClose"
|
||||
:append-to-body="true"
|
||||
>
|
||||
<template v-if="mode === EditorMode.LIST">
|
||||
<el-menu default-active="0" class="el-menu-vertical-demo code-editor-side-menu">
|
||||
<el-menu-item v-for="(value, key) in selectedValue" :index="key" :key="key" @click="menuSelectHandler">
|
||||
<template #title>{{ value.name }}({{ key }})</template>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
<div
|
||||
:class="[
|
||||
mode === EditorMode.LIST ? 'm-editor-code-block-editor-panel-list-mode' : '',
|
||||
'm-editor-code-block-editor-panel',
|
||||
]"
|
||||
>
|
||||
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
||||
<el-row class="code-name-wrapper" justify="start">
|
||||
<el-col :span="2">
|
||||
<span>代码块名称</span>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-input size="small" v-model="codeConfig.name" />
|
||||
<el-input size="small" v-model="codeConfig.name" :disabled="!editable" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="m-editor-content">
|
||||
@ -22,24 +40,25 @@
|
||||
formatOnPaste: true,
|
||||
}"
|
||||
></magic-code-editor>
|
||||
<div class="m-editor-content-bottom clearfix">
|
||||
<div class="m-editor-content-bottom clearfix" v-if="editable">
|
||||
<el-button type="primary" class="button" @click="saveCode">保存</el-button>
|
||||
<el-button type="primary" class="button" @click="saveAndClose">保存并关闭</el-button>
|
||||
</div>
|
||||
<div class="m-editor-content-bottom clearfix" v-else>
|
||||
<el-button type="primary" class="button" @click="saveAndClose">关闭</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineProps, inject, ref, watchEffect } from 'vue';
|
||||
import { computed, inject, ref, watchEffect } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import type { CodeBlockContent, Services } from '../../../type';
|
||||
import { EditorMode } from '../../../type';
|
||||
|
||||
const props = defineProps<{
|
||||
id: string;
|
||||
}>();
|
||||
const services = inject<Services>('services');
|
||||
|
||||
const codeEditor = ref<any | null>(null);
|
||||
@ -48,14 +67,22 @@ const codeConfig = ref<CodeBlockContent | null>(null);
|
||||
|
||||
// 是否展示代码编辑区
|
||||
const isShowCodeBlockEditor = computed(() => codeConfig.value && services?.codeBlockService.getCodeEditorShowStatus());
|
||||
const mode = computed(() => services?.codeBlockService.getMode());
|
||||
const id = computed(() => services?.codeBlockService.getId() || '');
|
||||
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
||||
// select选择的内容(CodeBlockDSL)
|
||||
const selectedValue = computed(() => {
|
||||
const selectedIds = services?.codeBlockService.getCombineIds() || [];
|
||||
return services?.codeBlockService.getCodeDslByIds(selectedIds);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
codeConfig.value = services?.codeBlockService.getCodeDslById(props.id) ?? null;
|
||||
codeConfig.value = services?.codeBlockService.getCodeContentById(id.value) ?? null;
|
||||
});
|
||||
|
||||
// 保存代码
|
||||
const saveCode = () => {
|
||||
if (!codeEditor.value || !codeConfig.value) return;
|
||||
if (!codeEditor.value || !codeConfig.value || !editable.value) return;
|
||||
|
||||
try {
|
||||
// 代码内容
|
||||
@ -67,7 +94,7 @@ const saveCode = () => {
|
||||
return;
|
||||
}
|
||||
// 存入dsl
|
||||
services?.codeBlockService.setCodeDslById(props.id, {
|
||||
services?.codeBlockService.setCodeDslById(id.value, {
|
||||
name: codeConfig.value.name,
|
||||
content: codeConfig.value.content,
|
||||
});
|
||||
@ -79,4 +106,8 @@ const saveAndClose = () => {
|
||||
saveCode();
|
||||
services?.codeBlockService.setCodeEditorShowStatus(false);
|
||||
};
|
||||
|
||||
const menuSelectHandler = (item: any) => {
|
||||
services?.codeBlockService.setId(item.index);
|
||||
};
|
||||
</script>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="m-editor-code-block-list">
|
||||
<slot name="code-block-panel-header">
|
||||
<div class="create-code-button">
|
||||
<el-button type="primary" size="small" @click="createCodeBlock">新增代码块</el-button>
|
||||
<el-button type="primary" size="small" @click="createCodeBlock" :disabled="!editable">新增代码块</el-button>
|
||||
</div>
|
||||
<el-divider class="divider" />
|
||||
</slot>
|
||||
@ -23,7 +23,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 代码块编辑区 -->
|
||||
<code-block-editor :id="codeId">
|
||||
<code-block-editor>
|
||||
<template #code-block-edit-panel-header="{ id }">
|
||||
<slot name="code-block-edit-panel-header" :id="id"></slot>
|
||||
</template>
|
||||
@ -32,19 +32,20 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, ref } from 'vue';
|
||||
import { computed, inject } from 'vue';
|
||||
import { Edit } from '@element-plus/icons-vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import type { CodeBlockContent, Services } from '../../../type';
|
||||
import { EditorMode } from '../../../type';
|
||||
|
||||
import codeBlockEditor from './CodeBlockEditor.vue';
|
||||
|
||||
const services = inject<Services>('services');
|
||||
const codeId = ref('');
|
||||
|
||||
// 代码块列表
|
||||
const codeList = computed(() => services?.codeBlockService.getCodeDsl());
|
||||
const editable = computed(() => services?.codeBlockService.getEditStatus());
|
||||
|
||||
// 新增代码块
|
||||
const createCodeBlock = () => {
|
||||
@ -53,18 +54,19 @@ const createCodeBlock = () => {
|
||||
ElMessage.error('新增代码块失败');
|
||||
return;
|
||||
}
|
||||
codeId.value = codeBlockService.getUniqueId();
|
||||
const codeConfig: CodeBlockContent = {
|
||||
name: '代码块',
|
||||
content: `() => {\n // place your code here\n}`,
|
||||
};
|
||||
codeBlockService.setCodeDslById(codeId.value, codeConfig);
|
||||
codeBlockService.setCodeEditorShowStatus(true);
|
||||
services?.codeBlockService.setMode(EditorMode.EDITOR);
|
||||
const id = codeBlockService.getUniqueId();
|
||||
codeBlockService.setCodeDslById(id, codeConfig);
|
||||
codeBlockService.setCodeEditorContent(true, id);
|
||||
};
|
||||
|
||||
// 编辑代码块
|
||||
const editCode = (key: string) => {
|
||||
codeId.value = key;
|
||||
services?.codeBlockService.setCodeEditorShowStatus(true);
|
||||
services?.codeBlockService.setMode(EditorMode.EDITOR);
|
||||
services?.codeBlockService.setCodeEditorContent(true, key);
|
||||
};
|
||||
</script>
|
||||
|
@ -17,8 +17,10 @@
|
||||
*/
|
||||
|
||||
import { reactive } from 'vue';
|
||||
import { keys, pick } from 'lodash-es';
|
||||
|
||||
import type { CodeBlockContent, CodeBlockDSL, CodeState } from '../type';
|
||||
import { EditorMode } from '../type';
|
||||
import { info } from '../utils/logger';
|
||||
|
||||
import BaseService from './BaseService';
|
||||
@ -27,6 +29,10 @@ class CodeBlock extends BaseService {
|
||||
private state = reactive<CodeState>({
|
||||
isShowCodeEditor: false,
|
||||
codeDsl: null,
|
||||
id: '',
|
||||
editable: true,
|
||||
mode: EditorMode.EDITOR,
|
||||
combineIds: [],
|
||||
});
|
||||
|
||||
constructor() {
|
||||
@ -57,14 +63,15 @@ class CodeBlock extends BaseService {
|
||||
* @param {string} id 代码块id
|
||||
* @returns {CodeBlockContent | null}
|
||||
*/
|
||||
public getCodeDslById(id: string): CodeBlockContent | null {
|
||||
public getCodeContentById(id: string): CodeBlockContent | null {
|
||||
if (!id) return null;
|
||||
const totalCodeDsl = this.getCodeDsl();
|
||||
if (!totalCodeDsl) return null;
|
||||
return totalCodeDsl[id] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码块id设置代码块内容
|
||||
* 设置代码块ID和代码内容到源dsl
|
||||
* @param {string} id 代码块id
|
||||
* @param {CodeBlockContent} codeConfig 代码块内容配置信息
|
||||
* @returns {void}
|
||||
@ -78,6 +85,16 @@ class CodeBlock extends BaseService {
|
||||
this.setCodeDsl(codeDsl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码块id数组获取代码dsl
|
||||
* @param {string[]} ids 代码块id数组
|
||||
* @returns {CodeBlockDSL}
|
||||
*/
|
||||
public getCodeDslByIds(ids: string[]): CodeBlockDSL {
|
||||
const codeDsl = this.getCodeDsl();
|
||||
return pick(codeDsl, ids) as CodeBlockDSL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置代码编辑面板展示状态
|
||||
* @param {boolean} status 是否展示代码编辑面板
|
||||
@ -95,12 +112,106 @@ class CodeBlock extends BaseService {
|
||||
return this.state.isShowCodeEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置代码编辑面板展示状态及展示内容
|
||||
* @param {boolean} status 是否展示代码编辑面板
|
||||
* @param {string} id 代码块id
|
||||
* @returns {void}
|
||||
*/
|
||||
public setCodeEditorContent(status: boolean, id: string): void {
|
||||
if (!id) return;
|
||||
this.setId(id);
|
||||
this.state.isShowCodeEditor = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前选中的代码块内容
|
||||
* @returns {CodeBlockContent | null}
|
||||
*/
|
||||
public getCurrentDsl() {
|
||||
return this.getCodeContentById(this.state.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取编辑状态
|
||||
* @returns {boolean} 是否可编辑
|
||||
*/
|
||||
public getEditStatus(): boolean {
|
||||
return this.state.editable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编辑状态
|
||||
* @param {boolean} 是否可编辑
|
||||
* @returns {void}
|
||||
*/
|
||||
public setEditStatus(status: boolean): void {
|
||||
this.state.editable = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前选中的代码块ID
|
||||
* @param {string} id 代码块id
|
||||
* @returns {void}
|
||||
*/
|
||||
public setId(id: string) {
|
||||
if (!id) return;
|
||||
this.state.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前选中的代码块ID
|
||||
* @returns {string} id 代码块id
|
||||
*/
|
||||
public getId(): string {
|
||||
return this.state.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模式
|
||||
* @returns {EditorMode}
|
||||
*/
|
||||
public getMode(): EditorMode {
|
||||
return this.state.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前模式
|
||||
* @param {EditorMode} mode 模式
|
||||
* @returns {void}
|
||||
*/
|
||||
public setMode(mode: EditorMode): void {
|
||||
this.state.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前已关联绑定的代码块id数组
|
||||
* @param {string[]} ids 代码块id数组
|
||||
* @returns {void}
|
||||
*/
|
||||
public setCombineIds(ids: string[]): void {
|
||||
this.state.combineIds = ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前已关联绑定的代码块id数组
|
||||
* @returns {string[]}
|
||||
*/
|
||||
public getCombineIds(): string[] {
|
||||
return this.state.combineIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码块唯一id
|
||||
* @returns {string} 代码块唯一id
|
||||
*/
|
||||
public getUniqueId(): string {
|
||||
return (Date.now().toString(36) + Math.random().toString(36).substring(2)).padEnd(19, '0');
|
||||
const newId = (Date.now().toString(36) + Math.random().toString(36).substring(2)).padEnd(19, '0');
|
||||
// 判断是否重复
|
||||
const dsl = this.getCodeDsl();
|
||||
const existedIds = keys(dsl);
|
||||
if (!existedIds.includes(newId)) return newId;
|
||||
return this.getUniqueId();
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
@ -70,3 +70,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.m-fields-code-select {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
.code-editor-side-menu {
|
||||
width: 20%;
|
||||
}
|
||||
.m-editor-code-block-editor-panel-list-mode {
|
||||
width: 80%;
|
||||
position: absolute;
|
||||
height: 90%;
|
||||
left: 20%;
|
||||
top: 60px;
|
||||
}
|
||||
|
@ -322,6 +322,17 @@ export interface CodeBlockContent {
|
||||
export type CodeState = {
|
||||
/** 是否展示代码块编辑区 */
|
||||
isShowCodeEditor: boolean;
|
||||
/** 代码块DSL */
|
||||
/** 代码块DSL数据源 */
|
||||
codeDsl: CodeBlockDSL | null;
|
||||
/** 当前选中的代码块id */
|
||||
id: string;
|
||||
/** 代码块是否可编辑 */
|
||||
editable: boolean;
|
||||
mode: EditorMode;
|
||||
combineIds: string[];
|
||||
};
|
||||
|
||||
export enum EditorMode {
|
||||
LIST = 'list',
|
||||
EDITOR = 'editor',
|
||||
}
|
||||
|
@ -227,33 +227,24 @@ export const fillConfig = (config: FormConfig = []) => [
|
||||
lazy: true,
|
||||
items: [
|
||||
{
|
||||
type: 'tab',
|
||||
active: '0',
|
||||
items: [
|
||||
{
|
||||
title: 'created',
|
||||
lazy: true,
|
||||
items: [
|
||||
{
|
||||
labelWidth: '100px',
|
||||
name: 'created',
|
||||
text: '关联代码块',
|
||||
type: 'select',
|
||||
multiple: true,
|
||||
options: () => {
|
||||
const codeDsl = codeBlockService.getCodeDsl();
|
||||
if (codeDsl) {
|
||||
return map(codeDsl, (value, key) => ({
|
||||
text: value.name,
|
||||
value: key,
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
},
|
||||
},
|
||||
],
|
||||
name: 'created',
|
||||
text: 'created',
|
||||
type: 'code-select',
|
||||
labelWidth: '100px',
|
||||
selectConfig: {
|
||||
multiple: true,
|
||||
options: () => {
|
||||
const codeDsl = codeBlockService.getCodeDsl();
|
||||
if (codeDsl) {
|
||||
return map(codeDsl, (value, key) => ({
|
||||
text: `${value.name}(${key})`,
|
||||
label: `${value.name}(${key})`,
|
||||
value: key,
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user