feat: 数据源管理

This commit is contained in:
bqy_fe 2021-06-25 21:44:36 +08:00
parent f387fa8993
commit c543fe894a
52 changed files with 796 additions and 123 deletions

2
components.d.ts vendored
View File

@ -15,6 +15,8 @@ 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']

View File

@ -27,12 +27,13 @@
"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.51", "element-plus": "1.0.2-beta.53",
"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",
"nprogress": "^1.0.0-1", "nprogress": "^1.0.0-1",
"qrcode": "^1.4.4", "qrcode": "^1.4.4",
"qs": "^6.10.1",
"vant": "^3.1.0", "vant": "^3.1.0",
"vue": "3.1.2", "vue": "3.1.2",
"vue-router": "^4.0.10", "vue-router": "^4.0.10",
@ -57,7 +58,7 @@
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.4.0", "eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.11.1", "eslint-plugin-vue": "^7.12.1",
"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",

View File

@ -1,5 +1,13 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-25 08:47:07
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\preview\router.ts
*/
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import { VisualEditorModelValue } from '@/visual-editor/visual-editor.utils' import type { VisualEditorModelValue } from '@/visual-editor/visual-editor.utils'
import { CacheEnum } from '@/enums' import { CacheEnum } from '@/enums'
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [

View File

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

View File

@ -0,0 +1,103 @@
/*
* @Author:
* @Date: 2021-06-24 23:19:48
* @LastEditTime: 2021-06-24 23:35:57
* @LastEditors:
* @Description: axios简单的封装
* @FilePath: \vite-vue3-lowcode\src\utils\http\request.ts
*/
import axios, { AxiosRequestConfig } from 'axios'
import qs from 'qs'
import store from '@/store'
import { Toast } from 'vant'
import router from '@/router'
import { ContentTypeEnum } from './httpEnum'
// create an axios instance
const service = axios.create({
baseURL: import.meta.env.VITE_API_URL as string, // url = base api url + request url
withCredentials: true, // send cookies when cross-domain requests
timeout: 10000 // request timeout
})
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
hideLoading?: boolean
}
interface BaseResponse<T = any> {
code: number
data: T
msg: string
}
// request拦截器 request interceptor
service.interceptors.request.use(
(config: CustomAxiosRequestConfig) => {
// 不传递默认开启loading
if (!config.hideLoading) {
// loading
Toast.loading({
forbidClick: true
})
}
console.log(store.getters, "store.getters['user']")
if (store.getters['user/token']) {
config.headers['X-Token'] = store.getters['user/token']
}
const contentType = config.headers['content-type'] || config.headers['Content-Type']
const data = config.data
if (config.method?.toLocaleUpperCase() == 'POST' && data) {
if (ContentTypeEnum.FORM_DATA == contentType) {
const fd = new FormData()
Object.keys(data).forEach((key) => fd.append(key, data[key]))
config.data = fd
} else if (ContentTypeEnum.FORM_URLENCODED == contentType) {
config.data = qs.stringify(config.data)
}
}
return config
},
(error) => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
(response) => {
Toast.clear()
const res = response.data
if (res.code && res.code !== 0) {
// 登录超时,重新登录
if (res.code === 401) {
// store.dispatch('FedLogOut').then(() => {
// location.reload()
// })
router.replace('/error')
} else {
Toast(res.msg || '服务器访问出错了~')
}
return Promise.reject(res || 'error')
} else {
return Promise.resolve(response)
}
},
(error: Error) => {
if (error.message?.includes('timeout')) {
Toast('请求超时!')
}
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
const request = <T = any>(config: CustomAxiosRequestConfig): Promise<BaseResponse<T>> => {
return new Promise((resolve, reject) => {
service
.request<BaseResponse<T>>(config)
.then((res) => resolve(res.data))
.catch((err) => reject(err))
})
}
export default request

View File

@ -1,13 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-05-04 05:36:58 * @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-06-24 00:36:24 * @LastEditTime: 2021-06-25 08:47:18
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\simulator-editor\comp-render.tsx * @FilePath: \vite-vue3-lowcode\preview\views\comp-render.tsx
*/ */
import { defineComponent, PropType } from 'vue' import { defineComponent, PropType } from 'vue'
import { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils' import type { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils'
export default defineComponent({ export default defineComponent({
name: 'CompRender', name: 'CompRender',

View File

@ -1,7 +1,7 @@
<!-- <!--
* @Author: 卜启缘 * @Author: 卜启缘
* @Date: 2021-06-01 09:45:21 * @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-24 00:19:14 * @LastEditTime: 2021-06-25 08:47:36
* @LastEditors: 卜启缘 * @LastEditors: 卜启缘
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\preview\views\preview.vue * @FilePath: \vite-vue3-lowcode\preview\views\preview.vue
@ -17,7 +17,7 @@ import { defineComponent, reactive, toRefs, onMounted } from 'vue'
import { Toast } from 'vant' import { Toast } from 'vant'
import { visualConfig } from '@/visual.config' import { visualConfig } from '@/visual.config'
import { CacheEnum } from '@/enums' import { CacheEnum } from '@/enums'
import { VisualEditorModelValue } from '@/visual-editor/visual-editor.utils' import type { VisualEditorModelValue } from '@/visual-editor/visual-editor.utils'
import SlotItem from './slot-item.vue' import SlotItem from './slot-item.vue'
import router from '../router' import router from '../router'
@ -58,8 +58,13 @@ export default defineComponent({
onMounted(() => { onMounted(() => {
const { bgImage, bgColor } = currentPage.config const { bgImage, bgColor } = currentPage.config
document.body.style.setProperty('--image', `url(${bgImage})`) const bodyStyleStr = `
document.body.style.setProperty('--bg-color', bgColor) body {
background-color: ${bgColor};
background-image: url(${bgImage});
}
`
document.styleSheets[0].insertRule(bodyStyleStr)
}) })
return { return {
@ -69,10 +74,3 @@ export default defineComponent({
} }
}) })
</script> </script>
<style lang="scss">
body {
background-color: var(--bg-color);
background-image: var(--image);
}
</style>

View File

@ -1,3 +1,11 @@
<!--
* @Author: 卜启缘
* @Date: 2021-06-12 22:18:48
* @LastEditTime: 2021-06-25 08:48:07
* @LastEditors: 卜启缘
* @Description:
* @FilePath: \vite-vue3-lowcode\preview\views\slot-item.vue
-->
<template> <template>
<div class="__slot-item"> <div class="__slot-item">
<comp-render :element="element" :config="config"> <comp-render :element="element" :config="config">
@ -11,17 +19,10 @@
</template> </template>
<script lang="ts"> <script lang="ts">
/**
* @name: slot-item
* @author:卜启缘
* @date: 2021/5/3 13:18
* @descriptionslot-item
* @update: 2021/5/3 14:18
*/
import { defineComponent, onMounted, PropType } from 'vue' import { defineComponent, onMounted, PropType } from 'vue'
import CompRender from './comp-render' import CompRender from './comp-render'
import { useAnimate } from '@/hooks/useAnimate' import { useAnimate } from '@/hooks/useAnimate'
import { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils' import type { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils'
export default defineComponent({ export default defineComponent({
name: 'SlotItem', name: 'SlotItem',

View File

@ -1,13 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-12 21:29:32 * @Date: 2021-06-12 21:29:32
* @LastEditTime: 2021-06-13 19:27:04 * @LastEditTime: 2021-06-25 08:48:30
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\hooks\useAnimate.ts * @FilePath: \vite-vue3-lowcode\src\hooks\useAnimate.ts
*/ */
import { Animation } from '@/visual-editor/visual-editor.utils' import type { Animation } from '@/visual-editor/visual-editor.utils'
export const useAnimate = async ( export const useAnimate = async (
animateEl: HTMLElement, animateEl: HTMLElement,

View File

@ -4,7 +4,7 @@ import {
createEditorSelectProp, createEditorSelectProp,
createEditorSwitchProp createEditorSwitchProp
} from '@/visual-editor/visual-editor.props' } from '@/visual-editor/visual-editor.props'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
export default { export default {

View File

@ -1,5 +1,5 @@
import { Field, Checkbox, CheckboxGroup } from 'vant' import { Field, Checkbox, CheckboxGroup } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -1,5 +1,5 @@
import { Field, Popup, DatetimePicker } from 'vant' import { Field, Popup, DatetimePicker } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 09:45:21 * @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-22 23:13:09 * @LastEditTime: 2021-06-25 08:49:31
* @LastEditors: * @LastEditors:
* @Description: 线 * @Description: 线
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\divider\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\divider\index.tsx
@ -13,7 +13,7 @@ import {
createEditorInputProp, createEditorInputProp,
createEditorSelectProp createEditorSelectProp
} from '@/visual-editor/visual-editor.props' } from '@/visual-editor/visual-editor.props'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
export default { export default {

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 09:45:21 * @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-14 10:31:27 * @LastEditTime: 2021-06-25 08:53:12
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx
@ -12,7 +12,7 @@ import {
createEditorSelectProp, createEditorSelectProp,
createEditorSwitchProp createEditorSwitchProp
} from '@/visual-editor/visual-editor.props' } from '@/visual-editor/visual-editor.props'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
export default { export default {

View File

@ -1,5 +1,13 @@
/*
* @Author:
* @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-06-25 08:49:50
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\input\index.tsx
*/
import { Field } from 'vant' import { Field } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'

View File

@ -1,14 +1,14 @@
/* /*
* @Author: * @Author:
* @Date: 2021-05-04 05:36:58 * @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-06-22 22:51:42 * @LastEditTime: 2021-06-25 08:49:41
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\nav-bar\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\nav-bar\index.tsx
*/ */
import { NavBar } from 'vant' import { NavBar } from 'vant'
import 'vant/lib/nav-bar/index.css' import 'vant/lib/nav-bar/index.css'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createEditorInputProp, createEditorSwitchProp } from '@/visual-editor/visual-editor.props' import { createEditorInputProp, createEditorSwitchProp } from '@/visual-editor/visual-editor.props'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'

View File

@ -1,13 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-14 12:24:12 * @Date: 2021-06-14 12:24:12
* @LastEditTime: 2021-06-14 12:56:23 * @LastEditTime: 2021-06-25 08:53:22
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\notice-bar\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\notice-bar\index.tsx
*/ */
import { NoticeBar } from 'vant' import { NoticeBar } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'

View File

@ -1,5 +1,5 @@
import { Field, Popup, Picker } from 'vant' import { Field, Popup, Picker } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { createEditorInputProp, createEditorTableProp } from '@/visual-editor/visual-editor.props' import { createEditorInputProp, createEditorTableProp } from '@/visual-editor/visual-editor.props'

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-12 22:18:48 * @Date: 2021-06-12 22:18:48
* @LastEditTime: 2021-06-22 23:14:22 * @LastEditTime: 2021-06-25 08:50:11
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\process\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\process\index.tsx
@ -13,7 +13,7 @@ import {
createEditorInputProp, createEditorInputProp,
createEditorInputNumberProp createEditorInputNumberProp
} from '@/visual-editor/visual-editor.props' } from '@/visual-editor/visual-editor.props'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
export default { export default {
key: 'process', key: 'process',

View File

@ -1,5 +1,5 @@
import { Field, Radio, RadioGroup } from 'vant' import { Field, Radio, RadioGroup } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -1,5 +1,13 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-25 08:50:29
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\rate\index.tsx
*/
import { Field, Rate } from 'vant' import { Field, Rate } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -1,5 +1,13 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-25 08:50:47
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\slider\index.tsx
*/
import { Field, Slider } from 'vant' import { Field, Slider } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -1,13 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 09:45:21 * @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-22 23:08:50 * @LastEditTime: 2021-06-25 08:51:08
* @LastEditors: * @LastEditors:
* @Description: ' - * @Description: ' -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\stepper\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\stepper\index.tsx
*/ */
import { Field, Stepper } from 'vant' import { Field, Stepper } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -7,7 +7,7 @@
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\swipe\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\swipe\index.tsx
*/ */
import { Swipe, SwipeItem } from 'vant' import { Swipe, SwipeItem } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'

View File

@ -1,13 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 09:45:21 * @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-23 10:16:32 * @LastEditTime: 2021-06-25 08:51:21
* @LastEditors: * @LastEditors:
* @Description: - * @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\switch\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\switch\index.tsx
*/ */
import { Field, Switch } from 'vant' import { Field, Switch } from 'vant'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { createFieldProps } from './createFieldProps' import { createFieldProps } from './createFieldProps'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { import {

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 09:45:21 * @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-22 23:14:46 * @LastEditTime: 2021-06-25 08:51:29
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx * @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx
@ -13,7 +13,7 @@ import {
createEditorSelectProp, createEditorSelectProp,
createEditorInputNumberProp createEditorInputNumberProp
} from '@/visual-editor/visual-editor.props' } from '@/visual-editor/visual-editor.props'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { fontArr } from './fontArr' import { fontArr } from './fontArr'
export default { export default {

View File

@ -1,6 +1,6 @@
import { Form, Field, Button } from 'vant' import { Form, Field, Button } from 'vant'
import { renderSlot, getCurrentInstance } from 'vue' import { renderSlot, getCurrentInstance } from 'vue'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'
import { compProps } from './compProps' import { compProps } from './compProps'

View File

@ -1,7 +1,7 @@
import { Col, Row } from 'vant' import { Col, Row } from 'vant'
import { renderSlot, getCurrentInstance } from 'vue' import { renderSlot, getCurrentInstance } from 'vue'
import { createEditorInputProp, createEditorSelectProp } from '@/visual-editor/visual-editor.props' import { createEditorInputProp, createEditorSelectProp } from '@/visual-editor/visual-editor.props'
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils' import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import styles from './index.module.scss' import styles from './index.module.scss'
import { useGlobalProperties } from '@/hooks/useGlobalProperties' import { useGlobalProperties } from '@/hooks/useGlobalProperties'

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 13:22:14 * @Date: 2021-06-01 13:22:14
* @LastEditTime: 2021-06-12 14:38:09 * @LastEditTime: 2021-06-25 09:10:19
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\container-component\index.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\container-component\index.tsx
@ -12,6 +12,7 @@ import { visualConfig } from '@/visual.config'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import styles from './index.module.scss' import styles from './index.module.scss'
import { createNewBlock } from '@/visual-editor/visual-editor.utils' import { createNewBlock } from '@/visual-editor/visual-editor.utils'
import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
export default defineComponent({ export default defineComponent({
name: 'ContainerComponent', name: 'ContainerComponent',
@ -40,7 +41,7 @@ export default defineComponent({
onChange={log} onChange={log}
> >
{{ {{
item: ({ element }) => ( item: ({ element }: { element: VisualEditorComponent }) => (
<div class={styles.listGroupItem} data-label={element.label}> <div class={styles.listGroupItem} data-label={element.label}>
{element.preview()} {element.preview()}
</div> </div>

View File

@ -0,0 +1,255 @@
<!--
* @Author: 卜启缘
* @Date: 2021-06-24 18:36:03
* @LastEditTime: 2021-06-25 21:38:33
* @LastEditors: 卜启缘
* @Description: 数据源管理
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\index.vue
-->
<template>
<el-button class="!my-10px" type="primary" size="small" @click="showModelMoal">添加</el-button>
<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>
<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>
<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 = () => ({ 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>
<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>

View File

@ -6,7 +6,7 @@ console.log(modules, '起航')
for (const path in modules) { for (const path in modules) {
const comp = modules[path].default const comp = modules[path].default
components[comp.name] = comp components[comp.name || path.split('/')[1]] = comp
} }
console.log('left-aside components:', components) console.log('left-aside components:', components)

View File

@ -1,8 +1,15 @@
<!--左侧边栏--> <!--
* @Author: 卜启缘
* @Date: 2021-06-24 00:35:17
* @LastEditTime: 2021-06-25 21:05:57
* @LastEditors: 卜启缘
* @Description: 左侧边栏
* @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" @tab-click="handleClick">
<template v-for="tabItem in tabs" :key="tabItem.name"> <template v-for="tabItem in tabs" :key="tabItem.componentName">
<el-tab-pane :name="tabItem.name"> <el-tab-pane :name="tabItem.componentName">
<template #label> <template #label>
<div class="flex flex-col items-center justify-center"> <div class="flex flex-col items-center justify-center">
<i :class="tabItem.icon"></i> <i :class="tabItem.icon"></i>
@ -28,7 +35,7 @@ export default defineComponent({
components, components,
setup() { setup() {
const state = reactive({ const state = reactive({
activeName: tabs[0].name activeName: tabs[0].componentName
}) })
const handleClick = (tab, event) => { const handleClick = (tab, event) => {

View File

@ -1,24 +1,33 @@
/*
* @Author:
* @Date: 2021-06-01 09:39:52
* @LastEditTime: 2021-06-24 18:50:16
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\tabs.ts
*/
export const tabs = [ export const tabs = [
{ {
name: 'pages',
icon: 'el-icon-tickets', icon: 'el-icon-tickets',
label: '页面', label: '页面',
componentName: 'PageTree' componentName: 'PageTree'
}, },
{ {
name: 'base-widget', icon: 'el-icon-data-board',
label: '数据源',
componentName: 'data-source'
},
{
icon: 'el-icon-edit', icon: 'el-icon-edit',
label: '基础控件', label: '基础控件',
componentName: 'BaseWidgets' componentName: 'BaseWidgets'
}, },
{ {
name: 'complex-component',
icon: 'el-icon-suitcase', icon: 'el-icon-suitcase',
label: '容器组件', label: '容器组件',
componentName: 'ContainerComponent' componentName: 'ContainerComponent'
}, },
{ {
name: 'custom-component',
icon: 'el-icon-upload', icon: 'el-icon-upload',
label: '自定义组件', label: '自定义组件',
componentName: 'custom-component' componentName: 'custom-component'

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-11 18:08:01 * @Date: 2021-06-11 18:08:01
* @LastEditTime: 2021-06-13 18:32:53 * @LastEditTime: 2021-06-25 08:52:10
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\animate\Animate.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\animate\Animate.tsx
@ -12,7 +12,7 @@ import { animationTabs } from './animateConfig'
import styles from './animate.module.scss' import styles from './animate.module.scss'
import { onClickOutside } from '@vueuse/core' import { onClickOutside } from '@vueuse/core'
import { useVisualData } from '@/visual-editor/hooks/useVisualData' import { useVisualData } from '@/visual-editor/hooks/useVisualData'
import { Animation } from '@/visual-editor/visual-editor.utils' import type { Animation } from '@/visual-editor/visual-editor.utils'
import { useAnimate } from '@/hooks/useAnimate' import { useAnimate } from '@/hooks/useAnimate'
export const Animate = defineComponent({ export const Animate = defineComponent({

View File

@ -1,4 +1,4 @@
import { Animation } from '@/visual-editor/visual-editor.utils' import type { Animation } from '@/visual-editor/visual-editor.utils'
export interface animationBoxTs { export interface animationBoxTs {
label: string label: string

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-10 16:23:06 * @Date: 2021-06-10 16:23:06
* @LastEditTime: 2021-06-21 10:00:54 * @LastEditTime: 2021-06-24 18:32:04
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\attr-editor\AttrEditor.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\attr-editor\AttrEditor.tsx
@ -19,7 +19,7 @@ import {
ElPopover ElPopover
} from 'element-plus' } from 'element-plus'
import { VisualEditorProps, VisualEditorPropsType } from '@/visual-editor/visual-editor.props' import { VisualEditorProps, VisualEditorPropsType } from '@/visual-editor/visual-editor.props'
import { TablePropEditor, CrossSortableOptionsEditor } from '../' import { TablePropEditor, CrossSortableOptionsEditor } from './components'
import { useDotProp } from '@/visual-editor/hooks/useDotProp' import { useDotProp } from '@/visual-editor/hooks/useDotProp'
import { useVisualData } from '@/visual-editor/hooks/useVisualData' import { useVisualData } from '@/visual-editor/hooks/useVisualData'

View File

@ -1,10 +1,10 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-14 15:00:45 * @Date: 2021-06-14 15:00:45
* @LastEditTime: 2021-06-14 17:41:14 * @LastEditTime: 2021-06-24 18:28:07
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\cross-sortable-options\cross-sortable-options.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\cross-sortable-options-editor\cross-sortable-options-editor.tsx
*/ */
import { defineComponent, reactive, computed, PropType } from 'vue' import { defineComponent, reactive, computed, PropType } from 'vue'
@ -53,7 +53,7 @@ export const CrossSortableOptionsEditor = defineComponent({
{{ {{
item: ({ element, index }) => ( item: ({ element, index }) => (
<div class={'flex items-center justify-between'}> <div class={'flex items-center justify-between'}>
<i class={'el-icon-s-grid handle'}></i> <i class={'el-icon-rank handle'}></i>
<ElInput <ElInput
v-model={state.list[index]} v-model={state.list[index]}
class={'m-12px'} class={'m-12px'}

View File

@ -0,0 +1,11 @@
/*
* @Author:
* @Date: 2021-06-12 22:18:48
* @LastEditTime: 2021-06-24 18:31:54
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\attr-editor\components\index.ts
*/
export { CrossSortableOptionsEditor } from './cross-sortable-options-editor/cross-sortable-options-editor'
export { TablePropEditor } from './table-prop-editor/table-prop-editor'

View File

@ -1,6 +1,6 @@
import { VisualEditorProps } from '../../../../visual-editor.props' import { VisualEditorProps } from '@/visual-editor/visual-editor.props'
import { defineComponent, getCurrentInstance, onMounted, PropType, reactive, createApp } from 'vue' import { defineComponent, getCurrentInstance, onMounted, PropType, reactive, createApp } from 'vue'
import { defer } from '../../../../utils/defer' import { defer } from '@/visual-editor/utils/defer'
import { ElButton, ElDialog, ElTable, ElTableColumn, ElInput } from 'element-plus' import { ElButton, ElDialog, ElTable, ElTableColumn, ElInput } from 'element-plus'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'

View File

@ -0,0 +1,19 @@
/*
* @Author:
* @Date: 2021-06-24 11:01:45
* @LastEditTime: 2021-06-24 11:12:56
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\event-action\index.tsx
*/
import { defineComponent } from 'vue'
export const EventAction = defineComponent({
setup() {
return () => (
<>
<div></div>
</>
)
}
})

View File

@ -1,14 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-12 22:18:48 * @Date: 2021-06-12 22:18:48
* @LastEditTime: 2021-06-23 22:17:38 * @LastEditTime: 2021-06-24 18:30:44
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\index.ts * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\index.ts
*/ */
export { TablePropEditor } from './table-prop-editor/table-prop-editor'
export { AttrEditor } from './attr-editor/AttrEditor' export { AttrEditor } from './attr-editor/AttrEditor'
export { Animate } from './animate/Animate' export { Animate } from './animate/Animate'
export { CrossSortableOptionsEditor } from './cross-sortable-options-editor/cross-sortable-options-editor'
export { PageSetting } from './page-setting/pageSetting' export { PageSetting } from './page-setting/pageSetting'
export { EventAction } from './event-action/'

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-13 22:07:29 * @Date: 2021-06-13 22:07:29
* @LastEditTime: 2021-06-24 00:23:39 * @LastEditTime: 2021-06-24 17:42:31
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\page-setting\pageSetting.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\page-setting\pageSetting.tsx
@ -33,7 +33,7 @@ export const PageSetting = defineComponent({
<ElColorPicker v-model={pageConfig.bgColor} /> <ElColorPicker v-model={pageConfig.bgColor} />
</ElFormItem> </ElFormItem>
<ElFormItem label="背景图片"> <ElFormItem label="背景图片">
<ElInput v-model={pageConfig.bgImage} placeholder={'图片地址'} /> <ElInput v-model={pageConfig.bgImage} placeholder={'图片地址'} clearable />
</ElFormItem> </ElFormItem>
<ElUpload action={''} beforeUpload={beforeUpload} class={styles.upload}> <ElUpload action={''} beforeUpload={beforeUpload} class={styles.upload}>
{pageConfig.bgImage ? ( {pageConfig.bgImage ? (

View File

@ -13,7 +13,7 @@ $boxShadow: -2px 0 4px 0 rgb(0 0 0 / 10%);
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 20; z-index: 20;
width: 350px; width: 390px;
background-color: white; background-color: white;
transform: translateX(100%); transform: translateX(100%);
box-shadow: $boxShadow; box-shadow: $boxShadow;

View File

@ -1,7 +1,7 @@
/* /*
* @Author: * @Author:
* @Date: 2021-06-01 13:22:14 * @Date: 2021-06-01 13:22:14
* @LastEditTime: 2021-06-23 22:18:34 * @LastEditTime: 2021-06-24 11:21:35
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\index.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\index.tsx
@ -13,7 +13,7 @@ import styles from './index.module.scss'
import { ElTabPane, ElTabs } from 'element-plus' import { ElTabPane, ElTabs } from 'element-plus'
import MonacoEditor from '../common/monaco-editor/MonacoEditor' import MonacoEditor from '../common/monaco-editor/MonacoEditor'
import { useVisualData } from '@/visual-editor/hooks/useVisualData' import { useVisualData } from '@/visual-editor/hooks/useVisualData'
import { AttrEditor, Animate, PageSetting } from './components' import { AttrEditor, Animate, PageSetting, EventAction } from './components'
export default defineComponent({ export default defineComponent({
name: 'RightAttributePanel', name: 'RightAttributePanel',
@ -41,17 +41,25 @@ export default defineComponent({
<i class={`el-icon-d-arrow-${state.isOpen ? 'right' : 'left'}`}></i> <i class={`el-icon-d-arrow-${state.isOpen ? 'right' : 'left'}`}></i>
</div> </div>
<div class={styles.attrs}> <div class={styles.attrs}>
<ElTabs v-model={state.activeName} type="border-card" class={styles.tabs}> <ElTabs
<ElTabPane label="属性面板" name="attr"> v-model={state.activeName}
type="border-card"
stretch={true}
class={styles.tabs}
>
<ElTabPane label="属性" name="attr">
<AttrEditor /> <AttrEditor />
</ElTabPane> </ElTabPane>
<ElTabPane label="动画" name="animate" lazy> <ElTabPane label="动画" name="animate" lazy>
<Animate /> <Animate />
</ElTabPane> </ElTabPane>
<ElTabPane label="事件" name="events">
<EventAction />
</ElTabPane>
<ElTabPane label="JSON" name="json" lazy> <ElTabPane label="JSON" name="json" lazy>
<MonacoEditor <MonacoEditor
code={JSON.stringify(currentBlock.value)} code={JSON.stringify(currentBlock.value)}
layout={{ width: 320, height: 800 }} layout={{ width: 360, height: 800 }}
vid={state.activeName == 'json' ? currentBlock.value._vid : -1} vid={state.activeName == 'json' ? currentBlock.value._vid : -1}
onChange={handleSchemaChange} onChange={handleSchemaChange}
title="" title=""

View File

@ -1,13 +1,13 @@
/* /*
* @Author: * @Author:
* @Date: 2021-05-04 05:36:58 * @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-06-24 00:36:24 * @LastEditTime: 2021-06-25 08:52:37
* @LastEditors: * @LastEditors:
* @Description: * @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\simulator-editor\comp-render.tsx * @FilePath: \vite-vue3-lowcode\src\visual-editor\components\simulator-editor\comp-render.tsx
*/ */
import { defineComponent, PropType } from 'vue' import { defineComponent, PropType } from 'vue'
import { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils' import type { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils'
export default defineComponent({ export default defineComponent({
name: 'CompRender', name: 'CompRender',

View File

@ -54,7 +54,7 @@
<script lang="tsx"> <script lang="tsx">
import { defineComponent, reactive, computed, toRefs } from 'vue' import { defineComponent, reactive, computed, toRefs } from 'vue'
import { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils' import type { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils'
import DraggableTransitionGroup from './draggable-transition-group.vue' import DraggableTransitionGroup from './draggable-transition-group.vue'
import { $$dropdown, DropdownOption } from '@/visual-editor/utils/dropdown-service' import { $$dropdown, DropdownOption } from '@/visual-editor/utils/dropdown-service'
import CompRender from './comp-render' import CompRender from './comp-render'

View File

@ -53,9 +53,9 @@ const Modal = defineComponent({
} }
const handler = { const handler = {
onConfirm: () => { onConfirm: async () => {
await state.options.onConfirm?.()
methods.hide() methods.hide()
state.options.onConfirm?.()
}, },
onCancel: () => { onCancel: () => {
methods.hide() methods.hide()
@ -83,7 +83,9 @@ const Modal = defineComponent({
state.options.footer === null ? null : ( state.options.footer === null ? null : (
<div> <div>
<ElButton {...({ onClick: handler.onCancel } as any)}></ElButton> <ElButton {...({ onClick: handler.onCancel } as any)}></ElButton>
<ElButton {...({ onClick: handler.onConfirm } as any)}></ElButton> <ElButton type={'primary'} {...({ onClick: handler.onConfirm } as any)}>
</ElButton>
</div> </div>
) )
}} }}

View File

@ -16,11 +16,13 @@ import {
DeepReadonly DeepReadonly
} from 'vue' } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { import type {
VisualEditorModelValue, VisualEditorModelValue,
VisualEditorBlockData, VisualEditorBlockData,
VisualEditorPage, VisualEditorPage,
VisualEditorConfig VisualEditorConfig,
FetchApiItem,
VisualEditorModel
} from '@/visual-editor/visual-editor.utils' } from '@/visual-editor/visual-editor.utils'
import { visualConfig } from '@/visual.config' import { visualConfig } from '@/visual.config'
@ -35,7 +37,7 @@ export const injectKey: InjectionKey<string> = Symbol()
interface IState { interface IState {
currentBlock: VisualEditorBlockData // 当前正在操作的组件 currentBlock: VisualEditorBlockData // 当前正在操作的组件
currentPage: VisualEditorPage // 当前正在操作的页面 currentPage: VisualEditorPage // 当前正在操作的页面
jsonData: VisualEditorModelValue // 整JSON树 jsonData: VisualEditorModelValue // 整JSON树
} }
export interface VisualData { export interface VisualData {
@ -50,6 +52,12 @@ export interface VisualData {
updatePageBlock: (path: string, blocks: VisualEditorBlockData[]) => void // 更新某页面下的所有组件 updatePageBlock: (path: string, blocks: VisualEditorBlockData[]) => void // 更新某页面下的所有组件
setCurrentPage: (path: string) => void // 设置当前正在操作的页面 setCurrentPage: (path: string) => void // 设置当前正在操作的页面
setCurrentBlock: (block: VisualEditorBlockData) => void // 设置当前正在操作的组件 setCurrentBlock: (block: VisualEditorBlockData) => void // 设置当前正在操作的组件
incrementFetchApi: (api: FetchApiItem) => void // 新增api接口
deleteFetchApi: (key: string) => void // 删除某个api接口
updateFetchApi: (newApi: FetchApiItem) => void // 更新某个api接口
incrementModel: (api: VisualEditorModel) => void // 新增模型
deleteModel: (key: string) => void // 删除某个模型
updateModel: (newApi: VisualEditorModel) => void // 更新某个模型
} }
/** /**
@ -66,12 +74,21 @@ export const createNewPage = ({ title = '新页面', path = '/' }) => ({
}) })
const defaultValue: VisualEditorModelValue = { const defaultValue: VisualEditorModelValue = {
container: {
width: 360,
height: 960
},
pages: { pages: {
// 页面
'/': createNewPage({ title: '首页' }) '/': createNewPage({ title: '首页' })
},
models: [], // 模型实体集合
actions: {
// 动作
fetch: {
name: '接口请求',
apis: []
},
dialog: {
name: '对话框',
handles: []
}
} }
} }
@ -153,6 +170,59 @@ export const initVisualData = (): VisualData => {
const updatePageBlock = (path = '', blocks: VisualEditorBlockData[] = []) => { const updatePageBlock = (path = '', blocks: VisualEditorBlockData[] = []) => {
state.jsonData.pages[path].blocks = blocks state.jsonData.pages[path].blocks = blocks
} }
/**
* @description API接口请求
*/
const incrementFetchApi = (api: FetchApiItem) => {
state.jsonData.actions.fetch.apis.push(api)
}
/**
* @description API接口
*/
const deleteFetchApi = (key: string) => {
const index = state.jsonData.actions.fetch.apis.findIndex((item) => item.key == key)
if (index !== -1) {
state.jsonData.actions.fetch.apis.splice(index, 1)
}
}
/**
* @description API接口
*/
const updateFetchApi = (api: FetchApiItem) => {
const target = state.jsonData.actions.fetch.apis.find((item) => item.key == api.key)
Object.assign(target, api)
}
/**
* @description
*/
const incrementModel = (model: VisualEditorModel) => {
state.jsonData.models.push(model)
}
/**
* @description
*/
const deleteModel = (key: string) => {
const index = state.jsonData.models.findIndex((item) => item.key == key)
if (index !== -1) {
state.jsonData.models.splice(index, 1)
}
}
/**
* @description
*/
const updateModel = (model: VisualEditorModel) => {
const index = state.jsonData.models.findIndex((item) => item.key == model.key)
if (index !== -1) {
state.jsonData.models.splice(index, 1, model)
}
}
// 使用自定义JSON覆盖整个项目 // 使用自定义JSON覆盖整个项目
const overrideProject = (jsonData) => { const overrideProject = (jsonData) => {
state.jsonData = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData state.jsonData = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData
@ -164,6 +234,12 @@ export const initVisualData = (): VisualData => {
currentPage: computed(() => state.currentPage), currentPage: computed(() => state.currentPage),
currentBlock: computed(() => state.currentBlock), currentBlock: computed(() => state.currentBlock),
overrideProject, overrideProject,
incrementFetchApi,
deleteFetchApi,
updateFetchApi,
incrementModel,
deleteModel,
updateModel,
setCurrentPage, setCurrentPage,
setCurrentBlock, setCurrentBlock,
updatePage, updatePage,
@ -174,3 +250,25 @@ export const initVisualData = (): VisualData => {
} }
export const useVisualData = () => inject<VisualData>(injectKey)! export const useVisualData = () => inject<VisualData>(injectKey)!
/**
*
*/
export const fieldTypes = [
{
label: '字符串',
value: 'string'
},
{
label: '数字',
value: 'number'
},
{
label: '数组',
value: 'array'
},
{
label: '布尔值',
value: 'boolean'
}
]

View File

@ -1,8 +1,30 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-24 21:57:31
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\utils\index.ts
*/
/** /**
* @name: index * @description URL
* @author:
* @date: 2021/5/6 0:04
* @descriptionindex
* @update: 2021/5/6 0:04
*/ */
export const BASE_URL = import.meta.env.BASE_URL export const BASE_URL = import.meta.env.BASE_URL
/**
* @description UUID
* @param {boolean} [noSymbol=false] -
* @returns {string}
*/
export function generateUUID(noSymbol = false) {
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
if (noSymbol) {
uuid = uuid.replace(/-/g, '')
}
return uuid
}

View File

@ -47,16 +47,65 @@ export interface VisualEditorPage {
export interface VisualEditorPages { export interface VisualEditorPages {
[path: string]: VisualEditorPage [path: string]: VisualEditorPage
} }
/**
export interface VisualEditorModelValue { * @description
container: { */
width: number export type EntityType = {
height: number field: string // 绑定的字段 输入
} name: string // 实体名称 输入
// 页面 type: string // 数据类型 选择
pages: VisualEditorPages value: string // 默认值 输入
} }
/**
* @description
*/
export interface VisualEditorModel {
name: string // 数据源名称
key: string // 绑定的字段 该字段创建的时候生成
entitys: EntityType[] // 实体集合
}
/**
* @description
*/
export interface FetchApiItem {
key: string // 随机生成的key
name: string // 当前api名字
options: {
url: string // 请求的url
method: string // 请求的方法
contentType: string // 请求的内容类型
}
data: {
bind: string // 请求绑定对应的某个实体
recv: string // 响应的结果绑定到某个实体上
}
}
/**
* @description
*/
export interface VisualEditorActions {
fetch: {
name: '接口请求'
apis: FetchApiItem[]
}
dialog: {
name: '对话框'
handles: []
}
}
/**
* @description
*/
export interface VisualEditorModelValue {
pages: VisualEditorPages // 页面
models: VisualEditorModel[] // 实体
actions: VisualEditorActions // 动作
}
/**
* @description
*/
export interface Animation { export interface Animation {
label: string // 动画名称 label: string // 动画名称
value: string // 动画类名 value: string // 动画类名
@ -65,6 +114,9 @@ export interface Animation {
count: number // 动画执行次数 count: number // 动画执行次数
infinite: boolean // 是否无限循环动画 infinite: boolean // 是否无限循环动画
} }
/**
* @description
*/
export interface VisualEditorComponent { export interface VisualEditorComponent {
key: string // 组件名称 key: string // 组件名称
moduleName: keyof ComponentModules // 模块名称 moduleName: keyof ComponentModules // 模块名称
@ -154,7 +206,10 @@ export interface ComponentModules {
baseWidgets: VisualEditorComponent[] // 基础组件 baseWidgets: VisualEditorComponent[] // 基础组件
containerComponents: VisualEditorComponent[] // 容器组件 containerComponents: VisualEditorComponent[] // 容器组件
} }
/**
* @description
* @returns {}
*/
export function createVisualEditorConfig() { export function createVisualEditorConfig() {
const componentModules: ComponentModules = { const componentModules: ComponentModules = {
baseWidgets: [], baseWidgets: [],

View File

@ -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.51: element-plus@1.0.2-beta.53:
version "1.0.2-beta.51" version "1.0.2-beta.53"
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.2-beta.51.tgz#5f27a7fcfef313fd1344f6ef2433ff2fe9335cc8" resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.2-beta.53.tgz#52208eccce487f452ffc5de8722cb718d6e02953"
integrity sha512-DLBXIt3gRleo769GV6rHHPUhDubWcwWZdvZIwH0CYrpNQW0Jqs8lXFvG+u0dgr+lnul6GZU31ZDoe3Ffq6NLBg== integrity sha512-PhhOBy1BWSVGWpCcu8fkmjcXvnAlc5dvith9vbNo1hPjm1cqf3AZbbt955VUTyFKWOLUOV9oD76HrNEG5ZTlxg==
dependencies: dependencies:
"@popperjs/core" "^2.4.4" "@popperjs/core" "^2.4.4"
"@types/lodash" "^4.14.161" "@types/lodash" "^4.14.161"
@ -2343,10 +2343,10 @@ eslint-plugin-prettier@^3.4.0:
dependencies: dependencies:
prettier-linter-helpers "^1.0.0" prettier-linter-helpers "^1.0.0"
eslint-plugin-vue@^7.11.1: eslint-plugin-vue@^7.12.1:
version "7.11.1" version "7.12.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.11.1.tgz#77eb4b44032d5cca79f9af21d06991d8694a314a" resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.12.1.tgz#ef6499ce4fe0566659c8e12c71713f5308630a76"
integrity sha512-lbw3vkEAGqYjqd1HpPFWHXtYaS8mILTJ5KOpJfRxO3Fo7o0wCf1zD7vSOasbm6nTA9xIgvZQ4VcyGIzQXxznHw== integrity sha512-xHf/wCt88qmzqQerjaSteUFGASj7fPreglKD4ijnvoKRkoSJ3/H3kuJE8QFFtc+2wjw6hRDs834HH7vpuTJQzg==
dependencies: dependencies:
eslint-utils "^2.1.0" eslint-utils "^2.1.0"
natural-compare "^1.4.0" natural-compare "^1.4.0"
@ -4300,7 +4300,7 @@ object-assign@^4.0.1, object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-inspect@^1.10.3: object-inspect@^1.10.3, object-inspect@^1.9.0:
version "1.10.3" version "1.10.3"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==
@ -4970,6 +4970,13 @@ qrcode@^1.4.4:
pngjs "^3.3.0" pngjs "^3.3.0"
yargs "^13.2.4" yargs "^13.2.4"
qs@^6.10.1:
version "6.10.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a"
integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==
dependencies:
side-channel "^1.0.4"
queue-microtask@^1.2.2: queue-microtask@^1.2.2:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@ -5366,6 +5373,15 @@ shellsubstitute@^1.1.0:
resolved "https://registry.yarnpkg.com/shellsubstitute/-/shellsubstitute-1.2.0.tgz#e4f702a50c518b0f6fe98451890d705af29b6b70" resolved "https://registry.yarnpkg.com/shellsubstitute/-/shellsubstitute-1.2.0.tgz#e4f702a50c518b0f6fe98451890d705af29b6b70"
integrity sha1-5PcCpQxRiw9v6YRRiQ1wWvKba3A= integrity sha1-5PcCpQxRiw9v6YRRiQ1wWvKba3A=
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
call-bind "^1.0.0"
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"