feat(editor): 代码块绑定功能完成

This commit is contained in:
parisma 2022-09-09 19:12:36 +08:00 committed by jia000
parent 040d5d0d2c
commit 0c25cf795f
8 changed files with 259 additions and 51 deletions

View 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>

View File

@ -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);
},
};

View File

@ -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>

View File

@ -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>

View File

@ -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() {

View File

@ -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;
}

View File

@ -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',
}

View File

@ -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',
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,
text: `${value.name}${key}`,
label: `${value.name}${key}`,
value: key,
}));
}
return [];
},
},
],
},
],
},
],
},