feat: ✨新增数据接口管理
This commit is contained in:
parent
c543fe894a
commit
eeb9c839f9
|
@ -1,5 +1,7 @@
|
||||||
# 基于 Vite2.x + Vue3.x + TypeScript H5 低代码平台
|
# 基于 Vite2.x + Vue3.x + TypeScript H5 低代码平台
|
||||||
|
|
||||||
|
### 后续可能会。。。搭建 PC 端后台管理系统低代码平台
|
||||||
|
|
||||||
[![license](https://img.shields.io/github/license/buqiyuan/vite-vue3-lowcode.svg)](LICENSE)
|
[![license](https://img.shields.io/github/license/buqiyuan/vite-vue3-lowcode.svg)](LICENSE)
|
||||||
|
|
||||||
**中文** | [English](./README.EN.md)
|
**中文** | [English](./README.EN.md)
|
||||||
|
@ -34,7 +36,7 @@ git clone --single-branch https://gitee.com/buqiyuan/vite-vue3-lowcode.git
|
||||||
- [x] 动态添加页面
|
- [x] 动态添加页面
|
||||||
- [x] 拖拽式生成组件
|
- [x] 拖拽式生成组件
|
||||||
- [ ] service worker + indexeddb 实现无服务端的前端交互
|
- [ ] service worker + indexeddb 实现无服务端的前端交互
|
||||||
- [ ] 数据源管理
|
- [ ] 数据源管理(支持导入 swagger JSON 生成数据模型及接口)
|
||||||
- [ ] 提供预置函数
|
- [ ] 提供预置函数
|
||||||
- [ ] 更多组件的封装
|
- [ ] 更多组件的封装
|
||||||
- [ ] 其他...
|
- [ ] 其他...
|
||||||
|
|
|
@ -15,8 +15,6 @@ declare module 'vue' {
|
||||||
ElTabPane: typeof import('element-plus/es/el-tab-pane')['default']
|
ElTabPane: typeof import('element-plus/es/el-tab-pane')['default']
|
||||||
ElTabs: typeof import('element-plus/es/el-tabs')['default']
|
ElTabs: typeof import('element-plus/es/el-tabs')['default']
|
||||||
ElDialog: typeof import('element-plus/es/el-dialog')['default']
|
ElDialog: typeof import('element-plus/es/el-dialog')['default']
|
||||||
ElCollapseItem: typeof import('element-plus/es/el-collapse-item')['default']
|
|
||||||
ElCollapse: typeof import('element-plus/es/el-collapse')['default']
|
|
||||||
ElTag: typeof import('element-plus/es/el-tag')['default']
|
ElTag: typeof import('element-plus/es/el-tag')['default']
|
||||||
ElDropdownItem: typeof import('element-plus/es/el-dropdown-item')['default']
|
ElDropdownItem: typeof import('element-plus/es/el-dropdown-item')['default']
|
||||||
ElDropdownMenu: typeof import('element-plus/es/el-dropdown-menu')['default']
|
ElDropdownMenu: typeof import('element-plus/es/el-dropdown-menu')['default']
|
||||||
|
@ -25,6 +23,9 @@ declare module 'vue' {
|
||||||
ElInput: typeof import('element-plus/es/el-input')['default']
|
ElInput: typeof import('element-plus/es/el-input')['default']
|
||||||
ElFormItem: typeof import('element-plus/es/el-form-item')['default']
|
ElFormItem: typeof import('element-plus/es/el-form-item')['default']
|
||||||
ElForm: typeof import('element-plus/es/el-form')['default']
|
ElForm: typeof import('element-plus/es/el-form')['default']
|
||||||
|
ElCollapseItem: typeof import('element-plus/es/el-collapse-item')['default']
|
||||||
|
ElCollapse: typeof import('element-plus/es/el-collapse')['default']
|
||||||
|
ElPopconfirm: typeof import('element-plus/es/el-popconfirm')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"dayjs": "^1.10.5",
|
"dayjs": "^1.10.5",
|
||||||
"dexie": "^3.0.3",
|
"dexie": "^3.0.3",
|
||||||
"element-plus": "1.0.2-beta.53",
|
"element-plus": "1.0.2-beta.52",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"monaco-editor": "^0.25.2",
|
"monaco-editor": "^0.25.2",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
"gh-pages": "^3.2.3",
|
"gh-pages": "^3.2.3",
|
||||||
"husky": "^6.0.0",
|
"husky": "^6.0.0",
|
||||||
"lint-staged": "^11.0.0",
|
"lint-staged": "^11.0.0",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.2",
|
||||||
"pretty-quick": "^3.1.1",
|
"pretty-quick": "^3.1.1",
|
||||||
"sass": "1.35.1",
|
"sass": "1.35.1",
|
||||||
"stylelint": "^13.13.1",
|
"stylelint": "^13.13.1",
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
"typescript": "^4.3.4",
|
"typescript": "^4.3.4",
|
||||||
"vite": "2.3.8",
|
"vite": "2.3.8",
|
||||||
"vite-plugin-components": "^0.11.2",
|
"vite-plugin-components": "^0.11.2",
|
||||||
"vite-plugin-style-import": "^1.0.0",
|
"vite-plugin-style-import": "^1.0.1",
|
||||||
"vite-plugin-windicss": "^1.1.1",
|
"vite-plugin-windicss": "^1.1.1",
|
||||||
"vue-eslint-parser": "^7.6.0",
|
"vue-eslint-parser": "^7.6.0",
|
||||||
"vue-tsc": "^0.2.0",
|
"vue-tsc": "^0.2.0",
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* @description: 请求结果集
|
||||||
|
*/
|
||||||
|
export enum ResultEnum {
|
||||||
|
SUCCESS = 0,
|
||||||
|
ERROR = -1,
|
||||||
|
TIMEOUT = 10042,
|
||||||
|
TYPE = 'success'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 请求方法
|
||||||
|
*/
|
||||||
|
export enum RequestEnum {
|
||||||
|
GET = 'GET',
|
||||||
|
POST = 'POST',
|
||||||
|
PATCH = 'PATCH',
|
||||||
|
PUT = 'PUT',
|
||||||
|
DELETE = 'DELETE'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 常用的contentTyp类型
|
||||||
|
*/
|
||||||
|
export enum ContentTypeEnum {
|
||||||
|
// json
|
||||||
|
JSON = 'application/json;charset=UTF-8',
|
||||||
|
// json
|
||||||
|
TEXT = 'text/plain;charset=UTF-8',
|
||||||
|
// form-data 一般配合qs
|
||||||
|
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||||
|
// form-data 上传
|
||||||
|
FORM_DATA = 'multipart/form-data;charset=UTF-8'
|
||||||
|
}
|
|
@ -0,0 +1,260 @@
|
||||||
|
<!--
|
||||||
|
* @Author: 卜启缘
|
||||||
|
* @Date: 2021-06-24 18:36:03
|
||||||
|
* @LastEditTime: 2021-06-26 21:34:53
|
||||||
|
* @LastEditors: 卜启缘
|
||||||
|
* @Description: 接口请求
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\data-fetch.vue
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="!mb-10px">
|
||||||
|
<el-button type="primary" size="small" @click="showModelMoal">添加</el-button>
|
||||||
|
<el-button type="warning" size="small" @click="showImportSwaggerJsonModal"
|
||||||
|
>导入swagger</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-collapse v-model="state.activeNames">
|
||||||
|
<template v-for="item in apis" :key="item.key">
|
||||||
|
<el-collapse-item :title="item.name" :name="item.key">
|
||||||
|
<template #title>
|
||||||
|
<div class="model-item-title">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<div class="model-actions">
|
||||||
|
<i class="el-icon-edit" @click="editApiItem(item)"></i>
|
||||||
|
<el-popconfirm
|
||||||
|
confirm-button-text="确定"
|
||||||
|
cancel-button-text="取消"
|
||||||
|
icon="el-icon-info"
|
||||||
|
icon-color="red"
|
||||||
|
title="确定要删除该接口吗?"
|
||||||
|
@confirm="deleteFetchApi(item.key)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<i class="el-icon-delete"></i>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="low-model-item">
|
||||||
|
<pre class="code">{{ JSON.stringify(item, null, 2) }}</pre>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</template>
|
||||||
|
</el-collapse>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { reactive, computed } from 'vue'
|
||||||
|
import {
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElInput,
|
||||||
|
ElSelect,
|
||||||
|
ElOption,
|
||||||
|
ElButton,
|
||||||
|
ElMessage,
|
||||||
|
ElCascader
|
||||||
|
} from 'element-plus'
|
||||||
|
import { useVisualData, fieldTypes } from '@/visual-editor/hooks/useVisualData'
|
||||||
|
import type { FetchApiItem, VisualEditorModel } from '@/visual-editor/visual-editor.utils'
|
||||||
|
import { useModal } from '@/visual-editor/hooks/useModal'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
import { generateUUID } from '@/visual-editor/utils/'
|
||||||
|
import { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum'
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
activeNames: string[]
|
||||||
|
ruleFormRef: any
|
||||||
|
ruleForm: FetchApiItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const { jsonData, incrementFetchApi, updateFetchApi, deleteFetchApi } = useVisualData()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 接口集合
|
||||||
|
*/
|
||||||
|
const apis = computed(() => cloneDeep(jsonData.actions.fetch.apis))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 模型集合
|
||||||
|
*/
|
||||||
|
const models = computed(() => cloneDeep(jsonData.models))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 是否处于编辑状态
|
||||||
|
*/
|
||||||
|
const isEdit = computed(() => apis.value.some((item) => item.key == state.ruleForm.key))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 创建空的数据接口对象
|
||||||
|
*/
|
||||||
|
const createEmptyApiItem = (): FetchApiItem => ({
|
||||||
|
key: generateUUID(),
|
||||||
|
name: '',
|
||||||
|
options: {
|
||||||
|
url: '', // 请求的url
|
||||||
|
method: RequestEnum.GET, // 请求的方法
|
||||||
|
contentType: 'JSON' // 请求的内容类型
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
bind: '', // 请求绑定对应的某个实体
|
||||||
|
recv: '' // 响应的结果绑定到某个实体上
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive<IState>({
|
||||||
|
activeNames: [],
|
||||||
|
ruleFormRef: null,
|
||||||
|
ruleForm: createEmptyApiItem()
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
name: [{ required: true, message: '请输入接口名称', trigger: 'change' }],
|
||||||
|
'options.url': [{ required: true, message: '请输入接口名称', trigger: 'change' }],
|
||||||
|
'options.contentType': [{ required: true, message: '请选择内容类型', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBindChange = (e: VisualEditorModel[]) => {
|
||||||
|
console.log(e, 'kkk')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 显示添加接口弹窗
|
||||||
|
*/
|
||||||
|
const showModelMoal = () => {
|
||||||
|
useModal({
|
||||||
|
title: `${isEdit.value ? '编辑' : '新增'}接口`,
|
||||||
|
props: {
|
||||||
|
width: 600
|
||||||
|
},
|
||||||
|
content: () => (
|
||||||
|
<ElForm
|
||||||
|
model={state.ruleForm}
|
||||||
|
ref={(el) => el && (state.ruleFormRef = el)}
|
||||||
|
label-width="100px"
|
||||||
|
size={'mini'}
|
||||||
|
rules={rules}
|
||||||
|
class="demo-ruleForm"
|
||||||
|
>
|
||||||
|
<ElFormItem label="名称" prop="name">
|
||||||
|
<ElInput v-model={state.ruleForm.name} placeholder={'请输入接口名称'}></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="接口" prop={'options.url'}>
|
||||||
|
<ElInput v-model={state.ruleForm.options.url} placeholder={'请输入接口地址'}>
|
||||||
|
{{
|
||||||
|
prepend: () => (
|
||||||
|
<ElSelect v-model={state.ruleForm.options.method} class={'w-90px'}>
|
||||||
|
{Object.keys(RequestEnum).map((key) => (
|
||||||
|
<ElOption key={key} label={key} value={key}></ElOption>
|
||||||
|
))}
|
||||||
|
</ElSelect>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="内容类型" prop={'options.contentType'}>
|
||||||
|
<ElSelect v-model={state.ruleForm.options.contentType}>
|
||||||
|
{Object.keys(ContentTypeEnum).map((key) => (
|
||||||
|
<ElOption key={key} label={key} value={key}></ElOption>
|
||||||
|
))}
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="请求数据" prop={'data.bind'}>
|
||||||
|
<ElCascader
|
||||||
|
clearable={true}
|
||||||
|
props={{
|
||||||
|
checkStrictly: true,
|
||||||
|
children: 'entitys',
|
||||||
|
label: 'name',
|
||||||
|
value: 'key',
|
||||||
|
expandTrigger: 'hover'
|
||||||
|
}}
|
||||||
|
placeholder="请选择绑定的请求数据"
|
||||||
|
onChange={handleBindChange}
|
||||||
|
v-model={state.ruleForm.data.bind}
|
||||||
|
options={models.value}
|
||||||
|
></ElCascader>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
),
|
||||||
|
onConfirm: () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
state.ruleFormRef.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
if (isEdit.value) {
|
||||||
|
updateFetchApi(cloneDeep(state.ruleForm))
|
||||||
|
} else {
|
||||||
|
incrementFetchApi(cloneDeep(state.ruleForm))
|
||||||
|
}
|
||||||
|
ElMessage.success(`${isEdit.value ? '修改' : '新增'}接口成功!`)
|
||||||
|
state.ruleForm = createEmptyApiItem()
|
||||||
|
resolve('submit!')
|
||||||
|
} else {
|
||||||
|
reject()
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCancel: () => (state.ruleForm = createEmptyApiItem())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 编辑模型
|
||||||
|
*/
|
||||||
|
const editApiItem = (apiItem: FetchApiItem) => {
|
||||||
|
console.log(apiItem)
|
||||||
|
state.ruleForm = cloneDeep(apiItem)
|
||||||
|
showModelMoal()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 显示导入swagger JSON模态框
|
||||||
|
*/
|
||||||
|
const showImportSwaggerJsonModal = () => {
|
||||||
|
ElMessage.info('敬请期待!')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.code {
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-item-title {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.model-actions {
|
||||||
|
i {
|
||||||
|
padding: 6px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 2px;
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: all 0.1s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-icon-delete {
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-icon-edit {
|
||||||
|
color: #2196f3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,290 @@
|
||||||
|
<!--
|
||||||
|
* @Author: 卜启缘
|
||||||
|
* @Date: 2021-06-24 18:36:03
|
||||||
|
* @LastEditTime: 2021-06-26 21:35:13
|
||||||
|
* @LastEditors: 卜启缘
|
||||||
|
* @Description: 数据模型管理
|
||||||
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\data-model.vue
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="!mb-10px">
|
||||||
|
<el-button type="primary" size="small" @click="showModelMoal">添加</el-button>
|
||||||
|
<el-button type="warning" size="small" @click="showImportSwaggerJsonModal"
|
||||||
|
>导入swagger</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-collapse v-model="state.activeNames">
|
||||||
|
<template v-for="item in models" :key="item.key">
|
||||||
|
<el-collapse-item :title="item.name" :name="item.key">
|
||||||
|
<template #title>
|
||||||
|
<div class="model-item-title">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<div class="model-actions">
|
||||||
|
<i class="el-icon-edit" @click="editModel(item)"></i>
|
||||||
|
<el-popconfirm
|
||||||
|
confirm-button-text="确定"
|
||||||
|
cancel-button-text="取消"
|
||||||
|
icon="el-icon-info"
|
||||||
|
icon-color="red"
|
||||||
|
title="确定要删除该模型吗?"
|
||||||
|
@confirm="deleteModel(item.key)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<i class="el-icon-delete"></i>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-for="entity in item.entitys" :key="entity.key">
|
||||||
|
<div class="low-model-item">
|
||||||
|
<pre class="code">{{ JSON.stringify(entity, null, 2) }}</pre>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-collapse-item>
|
||||||
|
</template>
|
||||||
|
</el-collapse>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { reactive, computed } from 'vue'
|
||||||
|
import {
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElInput,
|
||||||
|
ElSelect,
|
||||||
|
ElOption,
|
||||||
|
ElCard,
|
||||||
|
ElButton,
|
||||||
|
ElMessage
|
||||||
|
} from 'element-plus'
|
||||||
|
import { useVisualData, fieldTypes } from '@/visual-editor/hooks/useVisualData'
|
||||||
|
import type { VisualEditorModel } from '@/visual-editor/visual-editor.utils'
|
||||||
|
import { useModal } from '@/visual-editor/hooks/useModal'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
import { generateUUID } from '@/visual-editor/utils/'
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
activeNames: string[]
|
||||||
|
ruleFormRef: any
|
||||||
|
ruleForm: VisualEditorModel
|
||||||
|
}
|
||||||
|
|
||||||
|
const { jsonData, incrementModel, updateModel, deleteModel } = useVisualData()
|
||||||
|
/**
|
||||||
|
* @description 模型集合
|
||||||
|
*/
|
||||||
|
const models = computed(() => cloneDeep(jsonData.models))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 是否处于编辑状态
|
||||||
|
*/
|
||||||
|
const isEdit = computed(() => models.value.some((item) => item.key == state.ruleForm.key))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 创建空的实体对象
|
||||||
|
*/
|
||||||
|
const createEmptyEntity = () => ({ key: '', name: '', type: 'string', value: '' })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 创建空的数据模型
|
||||||
|
*/
|
||||||
|
const createEmptyModel = () => ({
|
||||||
|
name: '',
|
||||||
|
key: generateUUID(),
|
||||||
|
entitys: [createEmptyEntity()]
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive<IState>({
|
||||||
|
activeNames: [],
|
||||||
|
ruleFormRef: null,
|
||||||
|
ruleForm: createEmptyModel()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} 索引
|
||||||
|
* @description 删除实体项
|
||||||
|
*/
|
||||||
|
const deleteEntityItem = (index: number) => {
|
||||||
|
state.ruleForm.entitys.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 添加实体项
|
||||||
|
*/
|
||||||
|
const addEntityItem = () => {
|
||||||
|
state.ruleForm.entitys.push(createEmptyEntity())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 显示添加接口弹窗
|
||||||
|
*/
|
||||||
|
const showModelMoal = () => {
|
||||||
|
useModal({
|
||||||
|
title: `${isEdit.value ? '编辑' : '新增'}数据源`,
|
||||||
|
props: {
|
||||||
|
width: 600
|
||||||
|
},
|
||||||
|
content: () => (
|
||||||
|
<ElForm
|
||||||
|
model={state.ruleForm}
|
||||||
|
ref={(el) => el && (state.ruleFormRef = el)}
|
||||||
|
label-width="100px"
|
||||||
|
size={'mini'}
|
||||||
|
class="demo-ruleForm"
|
||||||
|
>
|
||||||
|
<ElFormItem
|
||||||
|
label="数据源名称"
|
||||||
|
prop="name"
|
||||||
|
rules={[{ required: true, message: '请输入数据源名称', trigger: 'change' }]}
|
||||||
|
>
|
||||||
|
<ElInput v-model={state.ruleForm.name} placeholder={'请输入数据源名称'}></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
{!state.ruleForm.entitys.length && (
|
||||||
|
<ElFormItem>
|
||||||
|
<ElButton onClick={addEntityItem} type={'primary'} size={'mini'}>
|
||||||
|
添加实体
|
||||||
|
</ElButton>
|
||||||
|
</ElFormItem>
|
||||||
|
)}
|
||||||
|
{state.ruleForm.entitys.map((entity, index) => (
|
||||||
|
<ElCard
|
||||||
|
key={index}
|
||||||
|
shadow={'hover'}
|
||||||
|
class={'mt-10px'}
|
||||||
|
v-slots={{
|
||||||
|
header: () => (
|
||||||
|
<div class={'flex justify-between'}>
|
||||||
|
<ElFormItem
|
||||||
|
label="实体名称"
|
||||||
|
prop={`entitys.${index}.name`}
|
||||||
|
rules={[{ required: true, message: '请输入实体名称', trigger: 'change' }]}
|
||||||
|
showMessage={false}
|
||||||
|
class={'w-300px !mb-0'}
|
||||||
|
>
|
||||||
|
<ElInput v-model={entity.name} placeholder={'请输入实体名称'}></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
<div>
|
||||||
|
<ElButton onClick={() => deleteEntityItem(index)} type={'danger'} size={'mini'}>
|
||||||
|
删除
|
||||||
|
</ElButton>
|
||||||
|
<ElButton onClick={addEntityItem} type={'primary'} size={'mini'}>
|
||||||
|
添加
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ElFormItem
|
||||||
|
label="实体字段"
|
||||||
|
prop={`entitys.${index}.key`}
|
||||||
|
rules={[{ required: true, message: '请输入实体字段', trigger: 'change' }]}
|
||||||
|
>
|
||||||
|
<ElInput v-model={entity.key} placeholder={'请输入实体字段'}></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem
|
||||||
|
label="数据类型"
|
||||||
|
prop={`entitys.${index}.type`}
|
||||||
|
rules={[{ required: true, message: '请输入数据类型', trigger: 'change' }]}
|
||||||
|
>
|
||||||
|
<ElSelect v-model={entity.type}>
|
||||||
|
{fieldTypes.map((typeItem) => (
|
||||||
|
<ElOption
|
||||||
|
key={typeItem.value}
|
||||||
|
label={typeItem.label}
|
||||||
|
value={typeItem.value}
|
||||||
|
></ElOption>
|
||||||
|
))}
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="默认数据" prop={`entitys.${index}.value`}>
|
||||||
|
<ElInput
|
||||||
|
v-model={entity.value}
|
||||||
|
placeholder={'实体默认数据,不填则为对应类型数据'}
|
||||||
|
></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCard>
|
||||||
|
))}
|
||||||
|
</ElForm>
|
||||||
|
),
|
||||||
|
onConfirm: () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
state.ruleFormRef.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
if (isEdit.value) {
|
||||||
|
updateModel(cloneDeep(state.ruleForm))
|
||||||
|
} else {
|
||||||
|
incrementModel(cloneDeep(state.ruleForm))
|
||||||
|
}
|
||||||
|
ElMessage.success(`${isEdit.value ? '修改' : '新增'}模型成功!`)
|
||||||
|
state.ruleForm = createEmptyModel()
|
||||||
|
resolve('submit!')
|
||||||
|
} else {
|
||||||
|
reject()
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCancel: () => (state.ruleForm = createEmptyModel())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 编辑模型
|
||||||
|
*/
|
||||||
|
const editModel = (model: VisualEditorModel) => {
|
||||||
|
console.log(model)
|
||||||
|
state.ruleForm = cloneDeep(model)
|
||||||
|
showModelMoal()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 显示导入swagger JSON模态框
|
||||||
|
*/
|
||||||
|
const showImportSwaggerJsonModal = () => {
|
||||||
|
ElMessage.info('敬请期待!')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.code {
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-item-title {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.model-actions {
|
||||||
|
i {
|
||||||
|
padding: 6px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 2px;
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: all 0.1s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-icon-delete {
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-icon-edit {
|
||||||
|
color: #2196f3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,255 +1,31 @@
|
||||||
<!--
|
<!--
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-24 18:36:03
|
* @Date: 2021-06-24 18:36:03
|
||||||
* @LastEditTime: 2021-06-25 21:38:33
|
* @LastEditTime: 2021-06-26 14:15:33
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 数据源管理
|
* @Description: 数据源管理
|
||||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\index.vue
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\index.vue
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<el-button class="!my-10px" type="primary" size="small" @click="showModelMoal">添加</el-button>
|
<el-tabs type="border-card" stretch>
|
||||||
<el-collapse v-model="state.activeNames">
|
<el-tab-pane label="数据模型">
|
||||||
<template v-for="item in models" :key="item.key">
|
<data-model />
|
||||||
<el-collapse-item :title="item.name" :name="item.key">
|
</el-tab-pane>
|
||||||
<template #title>
|
<el-tab-pane label="数据接口">
|
||||||
<div class="model-item-title">
|
<data-fetch />
|
||||||
<span>{{ item.name }}</span>
|
</el-tab-pane>
|
||||||
<div class="model-actions">
|
</el-tabs>
|
||||||
<i class="el-icon-edit" @click="editModel(item)"></i>
|
|
||||||
<i class="el-icon-delete" @click="deleteModel(item.key)"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-for="entity in item.entitys" :key="entity.key">
|
|
||||||
<div class="low-model-item">
|
|
||||||
<pre class="code">{{ JSON.stringify(entity, null, 2) }}</pre>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-collapse-item>
|
|
||||||
</template>
|
|
||||||
</el-collapse>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { reactive, computed } from 'vue'
|
import DataModel from './data-model.vue'
|
||||||
import {
|
import DataFetch from './data-fetch.vue'
|
||||||
ElForm,
|
|
||||||
ElFormItem,
|
|
||||||
ElInput,
|
|
||||||
ElSelect,
|
|
||||||
ElOption,
|
|
||||||
ElCard,
|
|
||||||
ElButton,
|
|
||||||
ElMessage
|
|
||||||
} from 'element-plus'
|
|
||||||
import { useVisualData, fieldTypes } from '@/visual-editor/hooks/useVisualData'
|
|
||||||
import type { VisualEditorModel } from '@/visual-editor/visual-editor.utils'
|
|
||||||
import { useModal } from '@/visual-editor/hooks/useModal'
|
|
||||||
import { cloneDeep } from 'lodash'
|
|
||||||
import { generateUUID } from '@/visual-editor/utils/'
|
|
||||||
|
|
||||||
interface IState {
|
|
||||||
activeNames: string[]
|
|
||||||
ruleFormRef: any
|
|
||||||
ruleForm: VisualEditorModel
|
|
||||||
}
|
|
||||||
|
|
||||||
const { jsonData, incrementModel, updateModel, deleteModel } = useVisualData()
|
|
||||||
/**
|
|
||||||
* @description 模型集合
|
|
||||||
*/
|
|
||||||
const models = computed(() => cloneDeep(jsonData.models))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 是否处于编辑状态
|
|
||||||
*/
|
|
||||||
const isEdit = computed(() => models.value.some((item) => item.key == state.ruleForm.key))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 创建空的实体对象
|
|
||||||
*/
|
|
||||||
const createEmptyEntity = () => ({ field: '', name: '', type: 'string', value: '' })
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 创建空的数据模型
|
|
||||||
*/
|
|
||||||
const createEmptyModel = () => ({
|
|
||||||
name: '',
|
|
||||||
key: generateUUID(),
|
|
||||||
entitys: [createEmptyEntity()]
|
|
||||||
})
|
|
||||||
|
|
||||||
const state = reactive<IState>({
|
|
||||||
activeNames: [],
|
|
||||||
ruleFormRef: null,
|
|
||||||
ruleForm: createEmptyModel()
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} 索引
|
|
||||||
* @description 删除实体项
|
|
||||||
*/
|
|
||||||
const deleteEntityItem = (index: number) => {
|
|
||||||
state.ruleForm.entitys.splice(index, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 添加实体项
|
|
||||||
*/
|
|
||||||
const addEntityItem = () => {
|
|
||||||
state.ruleForm.entitys.push(createEmptyEntity())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 显示添加接口弹窗
|
|
||||||
*/
|
|
||||||
const showModelMoal = () => {
|
|
||||||
useModal({
|
|
||||||
title: `${isEdit.value ? '编辑' : '新增'}数据源`,
|
|
||||||
content: () => (
|
|
||||||
<ElForm
|
|
||||||
model={state.ruleForm}
|
|
||||||
ref={(el) => el && (state.ruleFormRef = el)}
|
|
||||||
label-width="100px"
|
|
||||||
size={'mini'}
|
|
||||||
class="demo-ruleForm"
|
|
||||||
>
|
|
||||||
<ElFormItem
|
|
||||||
label="数据源名称"
|
|
||||||
prop="name"
|
|
||||||
rules={[{ required: true, message: '请输入数据源名称', trigger: 'change' }]}
|
|
||||||
>
|
|
||||||
<ElInput v-model={state.ruleForm.name} placeholder={'请输入数据源名称'}></ElInput>
|
|
||||||
</ElFormItem>
|
|
||||||
{state.ruleForm.entitys.map((entity, index) => (
|
|
||||||
<ElCard
|
|
||||||
key={index}
|
|
||||||
shadow={'hover'}
|
|
||||||
v-slots={{
|
|
||||||
header: () => (
|
|
||||||
<div class={'flex justify-between'}>
|
|
||||||
<ElFormItem
|
|
||||||
label="实体名称"
|
|
||||||
prop={`entitys.${index}.name`}
|
|
||||||
rules={[{ required: true, message: '请输入实体名称', trigger: 'change' }]}
|
|
||||||
showMessage={false}
|
|
||||||
class={'w-300px !mb-0'}
|
|
||||||
>
|
|
||||||
<ElInput v-model={entity.name} placeholder={'请输入实体名称'}></ElInput>
|
|
||||||
</ElFormItem>
|
|
||||||
<div>
|
|
||||||
<ElButton onClick={() => deleteEntityItem(index)} type={'danger'} size={'mini'}>
|
|
||||||
删除
|
|
||||||
</ElButton>
|
|
||||||
<ElButton onClick={addEntityItem} type={'primary'} size={'mini'}>
|
|
||||||
添加
|
|
||||||
</ElButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ElFormItem
|
|
||||||
label="实体字段"
|
|
||||||
prop={`entitys.${index}.field`}
|
|
||||||
rules={[{ required: true, message: '请输入实体字段', trigger: 'change' }]}
|
|
||||||
>
|
|
||||||
<ElInput v-model={entity.field} placeholder={'请输入实体字段'}></ElInput>
|
|
||||||
</ElFormItem>
|
|
||||||
<ElFormItem
|
|
||||||
label="数据类型"
|
|
||||||
prop={`entitys.${index}.type`}
|
|
||||||
rules={[{ required: true, message: '请输入数据类型', trigger: 'change' }]}
|
|
||||||
>
|
|
||||||
<ElSelect v-model={entity.type}>
|
|
||||||
{fieldTypes.map((typeItem) => (
|
|
||||||
<ElOption
|
|
||||||
key={typeItem.value}
|
|
||||||
label={typeItem.label}
|
|
||||||
value={typeItem.value}
|
|
||||||
></ElOption>
|
|
||||||
))}
|
|
||||||
</ElSelect>
|
|
||||||
</ElFormItem>
|
|
||||||
<ElFormItem label="默认数据" prop={`entitys.${index}.value`}>
|
|
||||||
<ElInput
|
|
||||||
v-model={entity.value}
|
|
||||||
placeholder={'实体默认数据,不填则为对应类型数据'}
|
|
||||||
></ElInput>
|
|
||||||
</ElFormItem>
|
|
||||||
</ElCard>
|
|
||||||
))}
|
|
||||||
</ElForm>
|
|
||||||
),
|
|
||||||
onConfirm: () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
state.ruleFormRef.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
if (isEdit.value) {
|
|
||||||
updateModel(cloneDeep(state.ruleForm))
|
|
||||||
} else {
|
|
||||||
incrementModel(cloneDeep(state.ruleForm))
|
|
||||||
}
|
|
||||||
ElMessage.success(`${isEdit.value ? '修改' : '新增'}模型成功!`)
|
|
||||||
state.ruleForm = createEmptyModel()
|
|
||||||
resolve('submit!')
|
|
||||||
} else {
|
|
||||||
reject()
|
|
||||||
console.log('error submit!!')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onCancel: () => (state.ruleForm = createEmptyModel())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @description 编辑模型
|
|
||||||
*/
|
|
||||||
const editModel = (model: VisualEditorModel) => {
|
|
||||||
console.log(model)
|
|
||||||
state.ruleForm = cloneDeep(model)
|
|
||||||
showModelMoal()
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.code {
|
::v-deep(.el-tabs__header) {
|
||||||
padding: 4px 10px;
|
position: sticky;
|
||||||
font-size: 12px;
|
top: 0;
|
||||||
line-height: 1.4;
|
z-index: 10;
|
||||||
}
|
|
||||||
|
|
||||||
.model-item-title {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.model-actions {
|
|
||||||
i {
|
|
||||||
padding: 6px;
|
|
||||||
margin: 0 2px;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 2px;
|
|
||||||
opacity: 0.7;
|
|
||||||
transition: all 0.1s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #f1f1f1;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.el-icon-delete {
|
|
||||||
color: #f44336;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.el-icon-edit {
|
|
||||||
color: #2196f3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
<!--页面树-->
|
<!--页面树-->
|
||||||
<template>
|
<template>
|
||||||
<el-button type="primary" size="small" style="margin: 10px 0" icon="el-icon-plus" @click="addPage"
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
class="!my-10px !mx-6px"
|
||||||
|
icon="el-icon-plus"
|
||||||
|
@click="addPage"
|
||||||
>添加页面</el-button
|
>添加页面</el-button
|
||||||
>
|
>
|
||||||
<el-tree
|
<el-tree
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<!--
|
<!--
|
||||||
* @Author: 卜启缘
|
* @Author: 卜启缘
|
||||||
* @Date: 2021-06-24 00:35:17
|
* @Date: 2021-06-24 00:35:17
|
||||||
* @LastEditTime: 2021-06-25 21:05:57
|
* @LastEditTime: 2021-06-26 00:24:40
|
||||||
* @LastEditors: 卜启缘
|
* @LastEditors: 卜启缘
|
||||||
* @Description: 左侧边栏
|
* @Description: 左侧边栏
|
||||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\index.vue
|
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\index.vue
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<el-tabs v-model="activeName" tab-position="left" @tab-click="handleClick">
|
<el-tabs v-model="activeName" tab-position="left" class="left-aside">
|
||||||
<template v-for="tabItem in tabs" :key="tabItem.componentName">
|
<template v-for="tabItem in tabs" :key="tabItem.componentName">
|
||||||
<el-tab-pane :name="tabItem.componentName">
|
<el-tab-pane :name="tabItem.componentName">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex flex-col items-center justify-center">
|
<div :ref="(el) => el && (tabItemRef[tabItem.componentName] = el)" class="tab-item">
|
||||||
<i :class="tabItem.icon"></i>
|
<i :class="tabItem.icon"></i>
|
||||||
{{ tabItem.label }}
|
{{ tabItem.label }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, toRefs } from 'vue'
|
import { defineComponent, reactive, toRefs, onMounted, ComponentInternalInstance } from 'vue'
|
||||||
import { tabs } from './tabs'
|
import { tabs } from './tabs'
|
||||||
import components from './components'
|
import components from './components'
|
||||||
|
|
||||||
|
@ -35,32 +35,46 @@ export default defineComponent({
|
||||||
components,
|
components,
|
||||||
setup() {
|
setup() {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeName: tabs[0].componentName
|
activeName: tabs[0].componentName,
|
||||||
|
tabItemRef: {} as { [prop: string]: ComponentInternalInstance | Element }
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleClick = (tab, event) => {
|
onMounted(() => {
|
||||||
console.log(tab, event)
|
setTimeout(() => {
|
||||||
}
|
tabs.forEach((item) => {
|
||||||
|
;(state.tabItemRef[item.componentName] as HTMLDivElement)
|
||||||
|
?.closest('.el-tabs__item')
|
||||||
|
?.setAttribute('data-custom-css', '')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
tabs,
|
tabs
|
||||||
handleClick
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.el-tabs {
|
.left-aside {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
::v-deep(.el-tabs__item) {
|
::v-deep(.el-tabs__header.is-left) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep(.el-tabs__item[data-custom-css]) {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
padding: 20px 16px;
|
padding: 20px 16px;
|
||||||
|
|
||||||
[class^='el-icon-'] {
|
.tab-item {
|
||||||
font-size: 20px;
|
@apply flex flex-col items-center justify-center;
|
||||||
|
|
||||||
|
[class^='el-icon-'] {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ const Modal = defineComponent({
|
||||||
methods.hide()
|
methods.hide()
|
||||||
},
|
},
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
methods.hide()
|
|
||||||
state.options.onCancel?.()
|
state.options.onCancel?.()
|
||||||
|
methods.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +69,9 @@ const Modal = defineComponent({
|
||||||
<ElDialog
|
<ElDialog
|
||||||
modelValue={state.visible}
|
modelValue={state.visible}
|
||||||
title={state.options.title}
|
title={state.options.title}
|
||||||
|
destroyOnClose={true}
|
||||||
{...state.options.props}
|
{...state.options.props}
|
||||||
onClose={methods.hide}
|
onClose={handler.onCancel}
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
default: () =>
|
default: () =>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { VisualEditorProps } from './visual-editor.props'
|
import type { VisualEditorProps } from './visual-editor.props'
|
||||||
import { inject, provide } from 'vue'
|
import { inject, provide } from 'vue'
|
||||||
import { useDotProp } from '@/visual-editor/hooks/useDotProp'
|
import { useDotProp } from '@/visual-editor/hooks/useDotProp'
|
||||||
|
import type { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 组件属性
|
* @description 组件属性
|
||||||
|
@ -51,7 +52,7 @@ export interface VisualEditorPages {
|
||||||
* @description 实体类型
|
* @description 实体类型
|
||||||
*/
|
*/
|
||||||
export type EntityType = {
|
export type EntityType = {
|
||||||
field: string // 绑定的字段 输入
|
key: string // 绑定的字段 输入
|
||||||
name: string // 实体名称 输入
|
name: string // 实体名称 输入
|
||||||
type: string // 数据类型 选择
|
type: string // 数据类型 选择
|
||||||
value: string // 默认值 输入
|
value: string // 默认值 输入
|
||||||
|
@ -73,8 +74,8 @@ export interface FetchApiItem {
|
||||||
name: string // 当前api名字
|
name: string // 当前api名字
|
||||||
options: {
|
options: {
|
||||||
url: string // 请求的url
|
url: string // 请求的url
|
||||||
method: string // 请求的方法
|
method: keyof typeof RequestEnum // 请求的方法
|
||||||
contentType: string // 请求的内容类型
|
contentType: keyof typeof ContentTypeEnum // 请求的内容类型
|
||||||
}
|
}
|
||||||
data: {
|
data: {
|
||||||
bind: string // 请求绑定对应的某个实体
|
bind: string // 请求绑定对应的某个实体
|
||||||
|
|
|
@ -12,4 +12,9 @@ Object.keys(containerComponent).forEach((name: string) =>
|
||||||
visualConfig.registry('containerComponents', name, containerComponent[name])
|
visualConfig.registry('containerComponents', name, containerComponent[name])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'%c成功加载组件数量:' + Object.keys(visualConfig.componentMap).length,
|
||||||
|
'color:#409EFF;background-color:#ecf5ff;padding:0 10px;line-height:2;margin-bottom:4px;'
|
||||||
|
)
|
||||||
|
|
||||||
console.log('visualConfig:', visualConfig)
|
console.log('visualConfig:', visualConfig)
|
||||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -2153,10 +2153,10 @@ electron-to-chromium@^1.3.723:
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.755.tgz#4b6101f13de910cf3f0a1789ddc57328133b9332"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.755.tgz#4b6101f13de910cf3f0a1789ddc57328133b9332"
|
||||||
integrity sha512-BJ1s/kuUuOeo1bF/EM2E4yqW9te0Hpof3wgwBx40AWJE18zsD1Tqo0kr7ijnOc+lRsrlrqKPauJAHqaxOItoUA==
|
integrity sha512-BJ1s/kuUuOeo1bF/EM2E4yqW9te0Hpof3wgwBx40AWJE18zsD1Tqo0kr7ijnOc+lRsrlrqKPauJAHqaxOItoUA==
|
||||||
|
|
||||||
element-plus@1.0.2-beta.53:
|
element-plus@1.0.2-beta.52:
|
||||||
version "1.0.2-beta.53"
|
version "1.0.2-beta.52"
|
||||||
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.2-beta.53.tgz#52208eccce487f452ffc5de8722cb718d6e02953"
|
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.2-beta.52.tgz#c7ed94d498e390658478aa2438bc35247325b2d0"
|
||||||
integrity sha512-PhhOBy1BWSVGWpCcu8fkmjcXvnAlc5dvith9vbNo1hPjm1cqf3AZbbt955VUTyFKWOLUOV9oD76HrNEG5ZTlxg==
|
integrity sha512-oAuJHwXyvM4dsuOz7HSDPIBVPqRJ1KEzFzGqYdqbBjQ/aw79uCJxvS9Q4q9/XrPMfPire09+bPTypiIaHkNBhA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@popperjs/core" "^2.4.4"
|
"@popperjs/core" "^2.4.4"
|
||||||
"@types/lodash" "^4.14.161"
|
"@types/lodash" "^4.14.161"
|
||||||
|
@ -4785,10 +4785,10 @@ prettier@^1.16.4, prettier@^1.18.2:
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||||
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
||||||
|
|
||||||
prettier@^2.3.1:
|
prettier@^2.3.2:
|
||||||
version "2.3.1"
|
version "2.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
|
||||||
integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==
|
integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==
|
||||||
|
|
||||||
pretty-quick@^3.1.1:
|
pretty-quick@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
|
@ -6331,10 +6331,10 @@ vite-plugin-components@^0.11.2:
|
||||||
magic-string "^0.25.7"
|
magic-string "^0.25.7"
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
|
|
||||||
vite-plugin-style-import@^1.0.0:
|
vite-plugin-style-import@^1.0.1:
|
||||||
version "1.0.0"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/vite-plugin-style-import/-/vite-plugin-style-import-1.0.0.tgz#344b7f14bcb5aefeb730d3192012c19a0604bb5e"
|
resolved "https://registry.yarnpkg.com/vite-plugin-style-import/-/vite-plugin-style-import-1.0.1.tgz#bf61337dd11e4ebc0f355f271e06d374b1ca5c79"
|
||||||
integrity sha512-5KCFN+WePRHsjZBtSPsN3Ii/Uas3Ld7d4B2s/I0NB4Iv7SuXuFudMz5IjoFaBqsbitXP7WEJ4XnZFan1fW1hAg==
|
integrity sha512-qinzdBxqkmX4fEyLZJVIBQTrgKivbROgcKJfBRz66knbghYAoe9cQeRptWKh35hE7obiidItWSCrHWkeu+JMVw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@rollup/pluginutils" "^4.1.0"
|
"@rollup/pluginutils" "^4.1.0"
|
||||||
change-case "^4.1.2"
|
change-case "^4.1.2"
|
||||||
|
|
Loading…
Reference in New Issue