Ver código fonte

feat: 新增 code 编辑器

lanceJiang 8 meses atrás
pai
commit
476bcd9506

+ 1 - 0
package.json

@@ -55,6 +55,7 @@
     "lodash-unified": "^1.0.3",
     "md5": "^2.3.0",
     "mitt": "^3.0.0",
+    "monaco-editor": "^0.52.0",
     "nanoid": "^4.0.0",
     "nprogress": "^0.2.0",
     "nzh": "^1.0.8",

+ 109 - 0
src/components/MonacoEditor/index.vue

@@ -0,0 +1,109 @@
+<template>
+	<div ref="monacoRef" :style="{ height }" class="le-monaco-editor" />
+</template>
+<script setup lang="ts">
+// import * as monaco from 'monaco-editor'
+import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
+import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
+defineOptions({ name: 'MonacoEditor' })
+const props = defineProps({
+	height: {
+		type: String,
+		default: '100%'
+	},
+	theme: {
+		type: String,
+		default: 'vs-light'
+	},
+	language: {
+		type: String,
+		default: 'javascript'
+		// default: 'verilog'
+	},
+	modelValue: {
+		type: String,
+		default: ''
+	}
+})
+const emits = defineEmits(['update:modelValue', 'change', 'editorDidMount'])
+const monacoRef = ref<HTMLElement>()
+const editor = ref()
+const _getValue = () => {
+	return editor.value?.getValue()
+}
+const _setValue = (value: string) => {
+	return editor.value?.setValue(value)
+}
+onMounted(() => {
+	const _editor = monaco.editor.create(monacoRef.value, {
+		// value: props.modelValue, // ``,
+		value: 'function hello() {\n  alert(\'Hello world!\');\n}', // ``,
+		language: props.language,
+		// theme: 'vs-dark'
+		theme: props.theme
+	})
+	editor.value = _editor
+	_editor.onDidChangeModelContent(event => {
+		const value = _editor.getValue()
+		console.error(event, 'change......', value)
+		// if (props.modelValue !== value) {
+		// 	emits('change', value, event)
+		// 	emits('update:modelValue', value)
+		// }
+	})
+	emits('editorDidMount', _editor)
+})
+watch(
+	() => props.modelValue,
+	(value: string) => {
+		console.error('modelValue ////', props.modelValue, _getValue())
+		// debugger
+		if (value !== _getValue()) {
+			_setValue(value)
+		}
+	}
+)
+watch(
+	() => props.language,
+	(lang: string) => {
+		console.error('watch', lang)
+		monaco.editor.setModelLanguage(editor.value.getModel(), lang)
+	}
+)
+watch(
+	() => props.theme,
+	(theme: string) => {
+		monaco.editor.setTheme(theme)
+	}
+)
+onBeforeUnmount(() => {
+	if (editor.value) {
+		editor.value.dispose()
+	}
+})
+</script>
+<style lang="scss">
+.le-monaco-editor {
+	width: 100%;
+	height: 100%;
+	min-height: 160px;
+	.monaco-editor {
+		height: 100%;
+		//border-radius: var(--n-border-radius)!important
+		.overflow-guard {
+			//border-radius: var(--n-border-radius)!important
+		}
+		.decorationsOverviewRuler,
+		.scrollbar,
+		.slider {
+			border: 0 !important;
+			width: 6px !important;
+			color: #00000080 !important;
+			border-radius: 6px !important;
+		}
+		.scroll-decoration {
+			//box-shadow: none!important
+		}
+	}
+}
+</style>

+ 326 - 0
src/views/codeGenerate/template/index.vue

@@ -0,0 +1,326 @@
+<template>
+	<div class="pageWrap bgc">
+		<div class="content-warp flex-column-page-wrap">
+			<!-- 公用搜索组件 -->
+<!--			<LeSearchForm ref="searchForm" v-model:searchData="searchData" :forms="forms" :loading="tableOpts.options.loading"></LeSearchForm>
+
+			&lt;!&ndash;  LeTable 组件使用  &ndash;&gt;
+			<LeTable
+				ref="tableRef"
+				v-model:searchParams="tableOpts.searchParams"
+				v-bind="tableOpts"
+				v-model:curRow="tableOpts.curRow"
+				v-model:checked-options="checkedColumns"
+				:columns="activeColumns"
+			>
+				<template #toolLeft>
+					<el-button
+						plain
+						:icon="Plus"
+						@click="addHandler"
+						type="primary">
+						新增</el-button>
+					<el-button plain :icon="Delete" :disabled="curSelectionRows.length === 0" @click="batch_del" type="danger">删除</el-button>
+				</template>
+
+				<template #actionSlot="{ row }">
+					<div class="flex flex-align-pack-center">
+						<LeIcon
+							class="text-lg text-icon-color cursor-pointer icon-mage&#45;&#45;edit"
+							icon-class="icon-processInfo-mage&#45;&#45;edit"
+							@click="table_edit(row)"
+						/>
+
+						<LeIcon class="text-lg ml-2 text-rose-700 cursor-pointer" icon-class="icon-processInfo-iconoir&#45;&#45;trash" @click="table_del(row)" />
+					</div>
+				</template>
+			</LeTable>-->
+			<MonacoEditor v-model="testCode" :language="language" @editorDidMount="testDid" />
+		</div>
+
+		<LeFormConfigDialog
+			v-if="visible"
+			ref="dialogUserRef"
+			v-model="visible"
+			:title="`${isCreate ? '新增' : '编辑'}应用`"
+			width="600px"
+			:form-data="activeData"
+			:form-options="formOptions"
+			@submit="submitHandler"
+		/>
+	</div>
+</template>
+<script lang="tsx" setup>
+import database from '@/api/codeGenerate/database'
+import MonacoEditor from '@/components/MonacoEditor'
+import { computed, nextTick, ref, watch } from 'vue'
+import { ElMessage, ElMessageBox, ElTree } from 'element-plus'
+import { useTablePage } from '@/hooks/useTablePage'
+import { Plus, Delete } from '@element-plus/icons-vue'
+
+
+// start
+const testCode = ref('function hello() {\n  alert(\'Hello world!\');\n}')
+const language = ref('javascript')
+const testDid = (editor) => {
+	window.editor = editor
+	window.testCode = testCode
+	window.language = language
+}
+// end
+
+
+
+const visible = ref(false) // 弹窗显示隐藏
+const isCreate = ref(true)
+const activeData = ref({})
+const formsDialog = [
+	{
+		prop: 'type',
+		label: '类型',
+		itemType: 'select',
+		options: [
+			{ label: 'PostgreSQL', value: 'pgsql' },
+			{ label: 'MySQL', value: 'mysql' },
+			{ label: 'Oracle', value: 'oracle' }
+		],
+		rules: [{ required: true, message: '请选择类型', trigger: 'change' }]
+	},
+	{
+		prop: 'alias',
+		label: '别名',
+		itemType: 'input',
+		rules: [{ required: true, message: '请输入别名', trigger: 'blur' }]
+	},
+	{
+		prop: 'host',
+		label: '主机',
+		itemType: 'input',
+		rules: [{ required: true, message: '请输入主机', trigger: 'blur' }]
+	},
+	{
+		prop: 'port',
+		label: '端口',
+		itemType: 'inputNumber',
+		rules: [{ required: true, message: '请输入端口', trigger: 'blur' }]
+	},
+	{
+		prop: 'database',
+		label: '库名称',
+		itemType: 'input',
+		rules: [{ required: true, message: '请输入库名称', trigger: 'blur' }]
+	},
+	{
+		prop: 'username',
+		label: '用户名',
+		itemType: 'input',
+		rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }]
+	},
+	{
+		prop: 'password',
+		label: '密码',
+		itemType: 'input',
+		rules: [{ required: true, message: '请输入密码', trigger: 'blur' }]
+	}
+]
+// 新增的表单 和 编辑的表单
+const formOptions = computed(() => {
+	return {
+		forms: formsDialog,
+		labelWidth: 120,
+		span: 30,
+		showResetBtn: true,
+		formConfig: {
+			showCancelBtn: true,
+			submitLoading: false
+		}
+	}
+})
+const groupFilterText = ref('')
+const treeRef = ref<InstanceType<typeof ElTree>>()
+
+// 表格搜索条件
+const forms = ref([
+	{
+		prop: 'alias',
+		label: '别名:',
+		itemType: 'input',
+		placeholder: '请输入别名'
+	},
+	{
+		prop: 'database',
+		label: '库名称:',
+		itemType: 'input',
+		placeholder: '请输入库名称'
+	},
+	{
+		prop: 'type',
+		label: '类型:',
+		itemType: 'select',
+		placeholder: '请选择类型',
+		options: [
+			{
+				label: 'PostgreSQL',
+				value: 'pgsql'
+			},
+			{
+				label: 'MySQL',
+				value: 'mysql'
+			},
+			{
+				label: 'Oracle',
+				value: 'oracle'
+			}
+		]
+	}
+])
+
+// table列表数据请求
+const queryList = async () => {
+	const { options, searchParams } = tableOpts
+	options.loading = true
+	try {
+		const { records: list, total } = await database.databasePageApi(searchParams)
+		tableOpts.total = total
+		tableOpts.list = list
+	} catch {
+		tableOpts.total = 0
+		tableOpts.list = []
+		options.loading = false // 更改加载中的 loading值
+	} finally {
+		options.loading = false
+	}
+}
+
+// table 参数
+const columns = [
+	{
+		prop: 'alias',
+		label: '别名'
+	},
+	{
+		prop: 'database',
+		label: '库名称',
+		minWidth: 100
+	},
+	{
+		prop: 'username',
+		label: '用户名'
+	},
+	{
+		prop: 'createTime',
+		label: '创建时间',
+		minWidth: 150
+	},
+	{
+		prop: 'action',
+		label: '操作',
+		align: 'center',
+		width: 100,
+		fixed: 'right',
+		slots: {
+			default: 'actionSlot'
+		}
+	}
+]
+
+const { searchData, tableOpts, checkedColumns, activeColumns, curSelectionRows, updateParams } = useTablePage(
+	{
+		options: {
+			showIndex: false,
+			defaultExpandAll: true
+		},
+		// 需要展示的列
+		columns,
+		// 控制列配置
+		columnsConfig: {
+			columns
+		}
+	},
+	{
+		queryList,
+		fetchImmediate: false
+	}
+)
+
+// 删除
+const deleteItem = async ids => {
+	// try {
+	await database.databaseDeleteApi(ids)
+	ElMessage.success(`删除成功~`)
+	updateParams()
+	// } catch (e) {
+	// 	console.log('删除失败')
+	// 	ElMessage.error(`删除失败~`)
+	// }
+}
+
+// 单个删除
+const table_del = (row: any) => {
+	ElMessageBox.confirm(`确认删除「${row.alias}」这条数据?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'error'
+	}).then(async () => {
+		deleteItem([row.id])
+	})
+}
+
+//批量删除
+const batch_del = () => {
+	const ids = curSelectionRows.value.map(item => item.id) // 多选数据
+	ElMessageBox.confirm('是否删除选中数据?', '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'error',
+		buttonSize: 'default'
+	}).then(() => {
+		deleteItem(ids)
+	})
+}
+
+const table_edit = async row => {
+	isCreate.value = false
+	// 通过databaseGetApi获取
+	await database.databaseGetApi(row.id).then(res => {
+		activeData.value = res
+	})
+	visible.value = true
+}
+
+// 弹窗事件
+const submitHandler = async params => {
+	formOptions.value.formConfig.submitLoading = true
+	try {
+		params.id = activeData.value.id ? activeData.value.id : null
+		await database.databaseAddOrEditSaveApi(params)
+		ElMessage.success(`${isCreate.value ? '新增' : '修改'}成功~`)
+		visible.value = false
+		updateParams()
+		formOptions.value.formConfig.submitLoading = false
+	} catch (e) {
+		console.log(e)
+		formOptions.value.formConfig.submitLoading = false
+	}
+}
+
+const addHandler = () => {
+	isCreate.value = true
+	activeData.value = {}
+	visible.value = true
+}
+
+const getDataBaseOptions = async () => {
+	const { data } = await database.databaseListSelectOptionsApi()
+	console.log(data)
+}
+
+nextTick(() => {
+	getDataBaseOptions()
+	queryList()
+})
+
+watch(groupFilterText, val => {
+	treeRef.value!.filter(val)
+})
+</script>