feat: 数据源管理
This commit is contained in:
parent
f387fa8993
commit
c543fe894a
|
@ -15,6 +15,8 @@ declare module 'vue' {
|
|||
ElTabPane: typeof import('element-plus/es/el-tab-pane')['default']
|
||||
ElTabs: typeof import('element-plus/es/el-tabs')['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']
|
||||
ElDropdownItem: typeof import('element-plus/es/el-dropdown-item')['default']
|
||||
ElDropdownMenu: typeof import('element-plus/es/el-dropdown-menu')['default']
|
||||
|
|
|
@ -27,12 +27,13 @@
|
|||
"axios": "^0.21.1",
|
||||
"dayjs": "^1.10.5",
|
||||
"dexie": "^3.0.3",
|
||||
"element-plus": "1.0.2-beta.51",
|
||||
"element-plus": "1.0.2-beta.53",
|
||||
"lodash": "^4.17.21",
|
||||
"monaco-editor": "^0.25.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^1.0.0-1",
|
||||
"qrcode": "^1.4.4",
|
||||
"qs": "^6.10.1",
|
||||
"vant": "^3.1.0",
|
||||
"vue": "3.1.2",
|
||||
"vue-router": "^4.0.10",
|
||||
|
@ -57,7 +58,7 @@
|
|||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-vue": "^7.11.1",
|
||||
"eslint-plugin-vue": "^7.12.1",
|
||||
"gh-pages": "^3.2.3",
|
||||
"husky": "^6.0.0",
|
||||
"lint-staged": "^11.0.0",
|
||||
|
|
|
@ -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 { VisualEditorModelValue } from '@/visual-editor/visual-editor.utils'
|
||||
import type { VisualEditorModelValue } from '@/visual-editor/visual-editor.utils'
|
||||
import { CacheEnum } from '@/enums'
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
|
|
|
@ -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,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
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-05-04 05:36:58
|
||||
* @LastEditTime: 2021-06-24 00:36:24
|
||||
* @LastEditTime: 2021-06-25 08:47:18
|
||||
* @LastEditors: 卜启缘
|
||||
* @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 { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils'
|
||||
import type { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CompRender',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!--
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 09:45:21
|
||||
* @LastEditTime: 2021-06-24 00:19:14
|
||||
* @LastEditTime: 2021-06-25 08:47:36
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description:
|
||||
* @FilePath: \vite-vue3-lowcode\preview\views\preview.vue
|
||||
|
@ -17,7 +17,7 @@ import { defineComponent, reactive, toRefs, onMounted } from 'vue'
|
|||
import { Toast } from 'vant'
|
||||
import { visualConfig } from '@/visual.config'
|
||||
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 router from '../router'
|
||||
|
||||
|
@ -58,8 +58,13 @@ export default defineComponent({
|
|||
|
||||
onMounted(() => {
|
||||
const { bgImage, bgColor } = currentPage.config
|
||||
document.body.style.setProperty('--image', `url(${bgImage})`)
|
||||
document.body.style.setProperty('--bg-color', bgColor)
|
||||
const bodyStyleStr = `
|
||||
body {
|
||||
background-color: ${bgColor};
|
||||
background-image: url(${bgImage});
|
||||
}
|
||||
`
|
||||
document.styleSheets[0].insertRule(bodyStyleStr)
|
||||
})
|
||||
|
||||
return {
|
||||
|
@ -69,10 +74,3 @@ export default defineComponent({
|
|||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
background-image: var(--image);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -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>
|
||||
<div class="__slot-item">
|
||||
<comp-render :element="element" :config="config">
|
||||
|
@ -11,17 +19,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* @name: slot-item
|
||||
* @author:卜启缘
|
||||
* @date: 2021/5/3 13:18
|
||||
* @description:slot-item
|
||||
* @update: 2021/5/3 14:18
|
||||
*/
|
||||
import { defineComponent, onMounted, PropType } from 'vue'
|
||||
import CompRender from './comp-render'
|
||||
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({
|
||||
name: 'SlotItem',
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-12 21:29:32
|
||||
* @LastEditTime: 2021-06-13 19:27:04
|
||||
* @LastEditTime: 2021-06-25 08:48:30
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 执行组件动画
|
||||
* @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 (
|
||||
animateEl: HTMLElement,
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
createEditorSelectProp,
|
||||
createEditorSwitchProp
|
||||
} 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'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 09:45:21
|
||||
* @LastEditTime: 2021-06-22 23:13:09
|
||||
* @LastEditTime: 2021-06-25 08:49:31
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 分割线
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\divider\index.tsx
|
||||
|
@ -13,7 +13,7 @@ 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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 09:45:21
|
||||
* @LastEditTime: 2021-06-14 10:31:27
|
||||
* @LastEditTime: 2021-06-25 08:53:12
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 图片组件
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx
|
||||
|
@ -12,7 +12,7 @@ import {
|
|||
createEditorSelectProp,
|
||||
createEditorSwitchProp
|
||||
} 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'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -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 { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import { createFieldProps } from './createFieldProps'
|
||||
import { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-05-04 05:36:58
|
||||
* @LastEditTime: 2021-06-22 22:51:42
|
||||
* @LastEditTime: 2021-06-25 08:49:41
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 导航栏
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\nav-bar\index.tsx
|
||||
*/
|
||||
import { NavBar } from 'vant'
|
||||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-14 12:24:12
|
||||
* @LastEditTime: 2021-06-14 12:56:23
|
||||
* @LastEditTime: 2021-06-25 08:53:22
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description:
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\notice-bar\index.tsx
|
||||
*/
|
||||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import { createEditorInputProp, createEditorTableProp } from '@/visual-editor/visual-editor.props'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-12 22:18:48
|
||||
* @LastEditTime: 2021-06-22 23:14:22
|
||||
* @LastEditTime: 2021-06-25 08:50:11
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 进度条
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\process\index.tsx
|
||||
|
@ -13,7 +13,7 @@ import {
|
|||
createEditorInputProp,
|
||||
createEditorInputNumberProp
|
||||
} 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 {
|
||||
key: 'process',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -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 { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import { createFieldProps } from './createFieldProps'
|
||||
import { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -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 { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import { createFieldProps } from './createFieldProps'
|
||||
import { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 09:45:21
|
||||
* @LastEditTime: 2021-06-22 23:08:50
|
||||
* @LastEditTime: 2021-06-25 08:51:08
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: '表单项类型 - 步进器
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\stepper\index.tsx
|
||||
*/
|
||||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\swipe\index.tsx
|
||||
*/
|
||||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 09:45:21
|
||||
* @LastEditTime: 2021-06-23 10:16:32
|
||||
* @LastEditTime: 2021-06-25 08:51:21
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 表单项类型 - 开关
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\switch\index.tsx
|
||||
*/
|
||||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 09:45:21
|
||||
* @LastEditTime: 2021-06-22 23:14:46
|
||||
* @LastEditTime: 2021-06-25 08:51:29
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 文本
|
||||
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx
|
||||
|
@ -13,7 +13,7 @@ import {
|
|||
createEditorSelectProp,
|
||||
createEditorInputNumberProp
|
||||
} 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'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Form, Field, Button } from 'vant'
|
||||
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 { compProps } from './compProps'
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Col, Row } from 'vant'
|
||||
import { renderSlot, getCurrentInstance } from 'vue'
|
||||
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 { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 13:22:14
|
||||
* @LastEditTime: 2021-06-12 14:38:09
|
||||
* @LastEditTime: 2021-06-25 09:10:19
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description:
|
||||
* @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 styles from './index.module.scss'
|
||||
import { createNewBlock } from '@/visual-editor/visual-editor.utils'
|
||||
import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ContainerComponent',
|
||||
|
@ -40,7 +41,7 @@ export default defineComponent({
|
|||
onChange={log}
|
||||
>
|
||||
{{
|
||||
item: ({ element }) => (
|
||||
item: ({ element }: { element: VisualEditorComponent }) => (
|
||||
<div class={styles.listGroupItem} data-label={element.label}>
|
||||
{element.preview()}
|
||||
</div>
|
||||
|
|
|
@ -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>
|
|
@ -6,7 +6,7 @@ console.log(modules, '起航')
|
|||
|
||||
for (const path in modules) {
|
||||
const comp = modules[path].default
|
||||
components[comp.name] = comp
|
||||
components[comp.name || path.split('/')[1]] = comp
|
||||
}
|
||||
console.log('left-aside components:', components)
|
||||
|
||||
|
|
|
@ -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>
|
||||
<el-tabs v-model="activeName" tab-position="left" @tab-click="handleClick">
|
||||
<template v-for="tabItem in tabs" :key="tabItem.name">
|
||||
<el-tab-pane :name="tabItem.name">
|
||||
<template v-for="tabItem in tabs" :key="tabItem.componentName">
|
||||
<el-tab-pane :name="tabItem.componentName">
|
||||
<template #label>
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<i :class="tabItem.icon"></i>
|
||||
|
@ -28,7 +35,7 @@ export default defineComponent({
|
|||
components,
|
||||
setup() {
|
||||
const state = reactive({
|
||||
activeName: tabs[0].name
|
||||
activeName: tabs[0].componentName
|
||||
})
|
||||
|
||||
const handleClick = (tab, event) => {
|
||||
|
|
|
@ -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 = [
|
||||
{
|
||||
name: 'pages',
|
||||
icon: 'el-icon-tickets',
|
||||
label: '页面',
|
||||
componentName: 'PageTree'
|
||||
},
|
||||
{
|
||||
name: 'base-widget',
|
||||
icon: 'el-icon-data-board',
|
||||
label: '数据源',
|
||||
componentName: 'data-source'
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-edit',
|
||||
label: '基础控件',
|
||||
componentName: 'BaseWidgets'
|
||||
},
|
||||
{
|
||||
name: 'complex-component',
|
||||
icon: 'el-icon-suitcase',
|
||||
label: '容器组件',
|
||||
componentName: 'ContainerComponent'
|
||||
},
|
||||
{
|
||||
name: 'custom-component',
|
||||
icon: 'el-icon-upload',
|
||||
label: '自定义组件',
|
||||
componentName: 'custom-component'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-11 18:08:01
|
||||
* @LastEditTime: 2021-06-13 18:32:53
|
||||
* @LastEditTime: 2021-06-25 08:52:10
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 动画组件
|
||||
* @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 { onClickOutside } from '@vueuse/core'
|
||||
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'
|
||||
|
||||
export const Animate = defineComponent({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Animation } from '@/visual-editor/visual-editor.utils'
|
||||
import type { Animation } from '@/visual-editor/visual-editor.utils'
|
||||
|
||||
export interface animationBoxTs {
|
||||
label: string
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-10 16:23:06
|
||||
* @LastEditTime: 2021-06-21 10:00:54
|
||||
* @LastEditTime: 2021-06-24 18:32:04
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 组件属性编辑器
|
||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\attr-editor\AttrEditor.tsx
|
||||
|
@ -19,7 +19,7 @@ import {
|
|||
ElPopover
|
||||
} from 'element-plus'
|
||||
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 { useVisualData } from '@/visual-editor/hooks/useVisualData'
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-14 15:00:45
|
||||
* @LastEditTime: 2021-06-14 17:41:14
|
||||
* @LastEditTime: 2021-06-24 18:28:07
|
||||
* @LastEditors: 卜启缘
|
||||
* @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'
|
||||
|
@ -53,7 +53,7 @@ export const CrossSortableOptionsEditor = defineComponent({
|
|||
{{
|
||||
item: ({ element, index }) => (
|
||||
<div class={'flex items-center justify-between'}>
|
||||
<i class={'el-icon-s-grid handle'}></i>
|
||||
<i class={'el-icon-rank handle'}></i>
|
||||
<ElInput
|
||||
v-model={state.list[index]}
|
||||
class={'m-12px'}
|
|
@ -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'
|
|
@ -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 { defer } from '../../../../utils/defer'
|
||||
import { defer } from '@/visual-editor/utils/defer'
|
||||
import { ElButton, ElDialog, ElTable, ElTableColumn, ElInput } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
})
|
|
@ -1,14 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-12 22:18:48
|
||||
* @LastEditTime: 2021-06-23 22:17:38
|
||||
* @LastEditTime: 2021-06-24 18:30:44
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description:
|
||||
* @Description: 统一导出组件
|
||||
* @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 { Animate } from './animate/Animate'
|
||||
export { CrossSortableOptionsEditor } from './cross-sortable-options-editor/cross-sortable-options-editor'
|
||||
export { PageSetting } from './page-setting/pageSetting'
|
||||
export { EventAction } from './event-action/'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-13 22:07:29
|
||||
* @LastEditTime: 2021-06-24 00:23:39
|
||||
* @LastEditTime: 2021-06-24 17:42:31
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 当前页面配置
|
||||
* @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} />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="背景图片">
|
||||
<ElInput v-model={pageConfig.bgImage} placeholder={'图片地址'} />
|
||||
<ElInput v-model={pageConfig.bgImage} placeholder={'图片地址'} clearable />
|
||||
</ElFormItem>
|
||||
<ElUpload action={''} beforeUpload={beforeUpload} class={styles.upload}>
|
||||
{pageConfig.bgImage ? (
|
||||
|
|
|
@ -13,7 +13,7 @@ $boxShadow: -2px 0 4px 0 rgb(0 0 0 / 10%);
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 20;
|
||||
width: 350px;
|
||||
width: 390px;
|
||||
background-color: white;
|
||||
transform: translateX(100%);
|
||||
box-shadow: $boxShadow;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-06-01 13:22:14
|
||||
* @LastEditTime: 2021-06-23 22:18:34
|
||||
* @LastEditTime: 2021-06-24 11:21:35
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description: 属性编辑器
|
||||
* @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 MonacoEditor from '../common/monaco-editor/MonacoEditor'
|
||||
import { useVisualData } from '@/visual-editor/hooks/useVisualData'
|
||||
import { AttrEditor, Animate, PageSetting } from './components'
|
||||
import { AttrEditor, Animate, PageSetting, EventAction } from './components'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RightAttributePanel',
|
||||
|
@ -41,17 +41,25 @@ export default defineComponent({
|
|||
<i class={`el-icon-d-arrow-${state.isOpen ? 'right' : 'left'}`}></i>
|
||||
</div>
|
||||
<div class={styles.attrs}>
|
||||
<ElTabs v-model={state.activeName} type="border-card" class={styles.tabs}>
|
||||
<ElTabPane label="属性面板" name="attr">
|
||||
<ElTabs
|
||||
v-model={state.activeName}
|
||||
type="border-card"
|
||||
stretch={true}
|
||||
class={styles.tabs}
|
||||
>
|
||||
<ElTabPane label="属性" name="attr">
|
||||
<AttrEditor />
|
||||
</ElTabPane>
|
||||
<ElTabPane label="动画" name="animate" lazy>
|
||||
<Animate />
|
||||
</ElTabPane>
|
||||
<ElTabPane label="事件" name="events">
|
||||
<EventAction />
|
||||
</ElTabPane>
|
||||
<ElTabPane label="JSON" name="json" lazy>
|
||||
<MonacoEditor
|
||||
code={JSON.stringify(currentBlock.value)}
|
||||
layout={{ width: 320, height: 800 }}
|
||||
layout={{ width: 360, height: 800 }}
|
||||
vid={state.activeName == 'json' ? currentBlock.value._vid : -1}
|
||||
onChange={handleSchemaChange}
|
||||
title=""
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* @Author: 卜启缘
|
||||
* @Date: 2021-05-04 05:36:58
|
||||
* @LastEditTime: 2021-06-24 00:36:24
|
||||
* @LastEditTime: 2021-06-25 08:52:37
|
||||
* @LastEditors: 卜启缘
|
||||
* @Description:
|
||||
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\simulator-editor\comp-render.tsx
|
||||
*/
|
||||
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({
|
||||
name: 'CompRender',
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
<script lang="tsx">
|
||||
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 { $$dropdown, DropdownOption } from '@/visual-editor/utils/dropdown-service'
|
||||
import CompRender from './comp-render'
|
||||
|
|
|
@ -53,9 +53,9 @@ const Modal = defineComponent({
|
|||
}
|
||||
|
||||
const handler = {
|
||||
onConfirm: () => {
|
||||
onConfirm: async () => {
|
||||
await state.options.onConfirm?.()
|
||||
methods.hide()
|
||||
state.options.onConfirm?.()
|
||||
},
|
||||
onCancel: () => {
|
||||
methods.hide()
|
||||
|
@ -83,7 +83,9 @@ const Modal = defineComponent({
|
|||
state.options.footer === null ? null : (
|
||||
<div>
|
||||
<ElButton {...({ onClick: handler.onCancel } as any)}>取消</ElButton>
|
||||
<ElButton {...({ onClick: handler.onConfirm } as any)}>确定</ElButton>
|
||||
<ElButton type={'primary'} {...({ onClick: handler.onConfirm } as any)}>
|
||||
确定
|
||||
</ElButton>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -16,11 +16,13 @@ import {
|
|||
DeepReadonly
|
||||
} from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
import type {
|
||||
VisualEditorModelValue,
|
||||
VisualEditorBlockData,
|
||||
VisualEditorPage,
|
||||
VisualEditorConfig
|
||||
VisualEditorConfig,
|
||||
FetchApiItem,
|
||||
VisualEditorModel
|
||||
} from '@/visual-editor/visual-editor.utils'
|
||||
|
||||
import { visualConfig } from '@/visual.config'
|
||||
|
@ -35,7 +37,7 @@ export const injectKey: InjectionKey<string> = Symbol()
|
|||
interface IState {
|
||||
currentBlock: VisualEditorBlockData // 当前正在操作的组件
|
||||
currentPage: VisualEditorPage // 当前正在操作的页面
|
||||
jsonData: VisualEditorModelValue // 整颗JSON树
|
||||
jsonData: VisualEditorModelValue // 整棵JSON树
|
||||
}
|
||||
|
||||
export interface VisualData {
|
||||
|
@ -50,6 +52,12 @@ export interface VisualData {
|
|||
updatePageBlock: (path: string, blocks: VisualEditorBlockData[]) => void // 更新某页面下的所有组件
|
||||
setCurrentPage: (path: string) => 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 = {
|
||||
container: {
|
||||
width: 360,
|
||||
height: 960
|
||||
},
|
||||
pages: {
|
||||
// 页面
|
||||
'/': createNewPage({ title: '首页' })
|
||||
},
|
||||
models: [], // 模型实体集合
|
||||
actions: {
|
||||
// 动作
|
||||
fetch: {
|
||||
name: '接口请求',
|
||||
apis: []
|
||||
},
|
||||
dialog: {
|
||||
name: '对话框',
|
||||
handles: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +170,59 @@ export const initVisualData = (): VisualData => {
|
|||
const updatePageBlock = (path = '', blocks: VisualEditorBlockData[] = []) => {
|
||||
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覆盖整个项目
|
||||
const overrideProject = (jsonData) => {
|
||||
state.jsonData = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData
|
||||
|
@ -164,6 +234,12 @@ export const initVisualData = (): VisualData => {
|
|||
currentPage: computed(() => state.currentPage),
|
||||
currentBlock: computed(() => state.currentBlock),
|
||||
overrideProject,
|
||||
incrementFetchApi,
|
||||
deleteFetchApi,
|
||||
updateFetchApi,
|
||||
incrementModel,
|
||||
deleteModel,
|
||||
updateModel,
|
||||
setCurrentPage,
|
||||
setCurrentBlock,
|
||||
updatePage,
|
||||
|
@ -174,3 +250,25 @@ export const initVisualData = (): VisualData => {
|
|||
}
|
||||
|
||||
export const useVisualData = () => inject<VisualData>(injectKey)!
|
||||
|
||||
/**
|
||||
* 实体的字段数据类型
|
||||
*/
|
||||
export const fieldTypes = [
|
||||
{
|
||||
label: '字符串',
|
||||
value: 'string'
|
||||
},
|
||||
{
|
||||
label: '数字',
|
||||
value: 'number'
|
||||
},
|
||||
{
|
||||
label: '数组',
|
||||
value: 'array'
|
||||
},
|
||||
{
|
||||
label: '布尔值',
|
||||
value: 'boolean'
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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
|
||||
* @author: 卜启缘
|
||||
* @date: 2021/5/6 0:04
|
||||
* @description:index
|
||||
* @update: 2021/5/6 0:04
|
||||
* @description 部署应用时的基本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
|
||||
}
|
||||
|
|
|
@ -47,16 +47,65 @@ export interface VisualEditorPage {
|
|||
export interface VisualEditorPages {
|
||||
[path: string]: VisualEditorPage
|
||||
}
|
||||
|
||||
export interface VisualEditorModelValue {
|
||||
container: {
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
// 页面
|
||||
pages: VisualEditorPages
|
||||
/**
|
||||
* @description 实体类型
|
||||
*/
|
||||
export type EntityType = {
|
||||
field: string // 绑定的字段 输入
|
||||
name: string // 实体名称 输入
|
||||
type: string // 数据类型 选择
|
||||
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 {
|
||||
label: string // 动画名称
|
||||
value: string // 动画类名
|
||||
|
@ -65,6 +114,9 @@ export interface Animation {
|
|||
count: number // 动画执行次数
|
||||
infinite: boolean // 是否无限循环动画
|
||||
}
|
||||
/**
|
||||
* @description 单个组件注册规则
|
||||
*/
|
||||
export interface VisualEditorComponent {
|
||||
key: string // 组件名称
|
||||
moduleName: keyof ComponentModules // 模块名称
|
||||
|
@ -154,7 +206,10 @@ export interface ComponentModules {
|
|||
baseWidgets: VisualEditorComponent[] // 基础组件
|
||||
containerComponents: VisualEditorComponent[] // 容器组件
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建编辑器配置
|
||||
* @returns {} 返回编辑器注册组件的方法等
|
||||
*/
|
||||
export function createVisualEditorConfig() {
|
||||
const componentModules: ComponentModules = {
|
||||
baseWidgets: [],
|
||||
|
|
34
yarn.lock
34
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"
|
||||
integrity sha512-BJ1s/kuUuOeo1bF/EM2E4yqW9te0Hpof3wgwBx40AWJE18zsD1Tqo0kr7ijnOc+lRsrlrqKPauJAHqaxOItoUA==
|
||||
|
||||
element-plus@1.0.2-beta.51:
|
||||
version "1.0.2-beta.51"
|
||||
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.2-beta.51.tgz#5f27a7fcfef313fd1344f6ef2433ff2fe9335cc8"
|
||||
integrity sha512-DLBXIt3gRleo769GV6rHHPUhDubWcwWZdvZIwH0CYrpNQW0Jqs8lXFvG+u0dgr+lnul6GZU31ZDoe3Ffq6NLBg==
|
||||
element-plus@1.0.2-beta.53:
|
||||
version "1.0.2-beta.53"
|
||||
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-1.0.2-beta.53.tgz#52208eccce487f452ffc5de8722cb718d6e02953"
|
||||
integrity sha512-PhhOBy1BWSVGWpCcu8fkmjcXvnAlc5dvith9vbNo1hPjm1cqf3AZbbt955VUTyFKWOLUOV9oD76HrNEG5ZTlxg==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.4.4"
|
||||
"@types/lodash" "^4.14.161"
|
||||
|
@ -2343,10 +2343,10 @@ eslint-plugin-prettier@^3.4.0:
|
|||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
|
||||
eslint-plugin-vue@^7.11.1:
|
||||
version "7.11.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.11.1.tgz#77eb4b44032d5cca79f9af21d06991d8694a314a"
|
||||
integrity sha512-lbw3vkEAGqYjqd1HpPFWHXtYaS8mILTJ5KOpJfRxO3Fo7o0wCf1zD7vSOasbm6nTA9xIgvZQ4VcyGIzQXxznHw==
|
||||
eslint-plugin-vue@^7.12.1:
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.12.1.tgz#ef6499ce4fe0566659c8e12c71713f5308630a76"
|
||||
integrity sha512-xHf/wCt88qmzqQerjaSteUFGASj7fPreglKD4ijnvoKRkoSJ3/H3kuJE8QFFtc+2wjw6hRDs834HH7vpuTJQzg==
|
||||
dependencies:
|
||||
eslint-utils "^2.1.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"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-inspect@^1.10.3:
|
||||
object-inspect@^1.10.3, object-inspect@^1.9.0:
|
||||
version "1.10.3"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
|
||||
integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==
|
||||
|
@ -4970,6 +4970,13 @@ qrcode@^1.4.4:
|
|||
pngjs "^3.3.0"
|
||||
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:
|
||||
version "1.2.3"
|
||||
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"
|
||||
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:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
|
|
Loading…
Reference in New Issue