fix: some bug
This commit is contained in:
parent
25b3d69041
commit
65493e128a
21
README.md
21
README.md
|
@ -32,6 +32,27 @@
|
|||
目前在使用表单时,需要把相关的`表单控件`放到`表单容器`内部,并且需要将`按钮`放到`表单容器`内,
|
||||
然后再讲`按钮的type`设置为`表单提交按钮`这时候点击提交按钮才会自动收集表单容器内部的所有字段和值
|
||||
|
||||
### 快速生成组件属性
|
||||
|
||||
```javascript
|
||||
// 在vant文档中 chrome控制台输入以下代码,快速生成组件属性
|
||||
let propObj = {
|
||||
string: (config) => `createEditorInputProp(${JSON.stringify(config)})`,
|
||||
number: (config) => `createEditorInputNumberProp(${JSON.stringify(config)})`,
|
||||
boolean: (config) => `createEditorSwitchProp(${JSON.stringify(config)})`
|
||||
}
|
||||
|
||||
$$('#props + table tr').reduce((prev, curr) => {
|
||||
const children = curr.children
|
||||
const key = children[0].textContent.replace(/-([a-z])/g, (all, i) => i.toUpperCase())
|
||||
const value = (propObj[children[2].textContent] ?? propObj['string'])({
|
||||
label: `'${children[1].textContent}'`
|
||||
}).replaceAll('"', '')
|
||||
prev[key] = value
|
||||
return prev
|
||||
}, {})
|
||||
```
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
本地开发推荐使用`Chrome 80+` 浏览器
|
||||
|
|
24
package.json
24
package.json
|
@ -20,20 +20,20 @@
|
|||
"prepare": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vant/touch-emulator": "^1.2.0",
|
||||
"@vant/touch-emulator": "^1.3.0",
|
||||
"@vueuse/core": "^4.11.1",
|
||||
"@vueuse/integrations": "^4.11.1",
|
||||
"axios": "^0.21.1",
|
||||
"dayjs": "^1.10.4",
|
||||
"dexie": "^3.0.3",
|
||||
"element-plus": "^1.0.2-beta.44",
|
||||
"element-plus": "^1.0.2-beta.45",
|
||||
"lodash": "^4.17.21",
|
||||
"monaco-editor": "^0.24.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^1.0.0-1",
|
||||
"qrcode": "^1.4.4",
|
||||
"vant": "^3.0.17",
|
||||
"vue": "^3.1.0-beta.4",
|
||||
"vue": "3.0.11",
|
||||
"vue-router": "^4.0.8",
|
||||
"vuedraggable": "^4.0.1",
|
||||
"vuex": "^4.0.1"
|
||||
|
@ -41,13 +41,13 @@
|
|||
"devDependencies": {
|
||||
"@commitlint/cli": "^12.1.4",
|
||||
"@commitlint/config-conventional": "^12.1.4",
|
||||
"@types/node": "^14.17.1",
|
||||
"@types/node": "^15.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
||||
"@typescript-eslint/parser": "^4.25.0",
|
||||
"@vitejs/plugin-legacy": "^1.4.0",
|
||||
"@vitejs/plugin-vue": "^1.2.2",
|
||||
"@vitejs/plugin-vue-jsx": "^1.1.4",
|
||||
"@vue/compiler-sfc": "^3.1.0-beta.4",
|
||||
"@vue/compiler-sfc": "3.0.11",
|
||||
"commitizen": "^4.2.4",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"cz-customizable": "^6.3.0",
|
||||
|
@ -56,24 +56,24 @@
|
|||
"eslint-plugin-import": "^2.23.3",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-vue": "^7.9.0",
|
||||
"gh-pages": "^3.1.0",
|
||||
"gh-pages": "^3.2.0",
|
||||
"husky": "^6.0.0",
|
||||
"lint-staged": "^10.5.4",
|
||||
"lint-staged": "^11.0.0",
|
||||
"prettier": "^2.3.0",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"sass": "1.32.13",
|
||||
"sass": "1.34.0",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"typescript": "^4.2.4",
|
||||
"typescript": "^4.3.2",
|
||||
"vite": "2.3.4",
|
||||
"vite-plugin-components": "^0.10.2",
|
||||
"vite-plugin-components": "^0.10.3",
|
||||
"vite-plugin-style-import": "^0.10.1",
|
||||
"vite-plugin-windicss": "^0.16.0",
|
||||
"vite-plugin-windicss": "^0.16.7",
|
||||
"vue-eslint-parser": "^7.6.0",
|
||||
"vue-tsc": "^0.1.6",
|
||||
"windicss": "^2.5.14"
|
||||
"windicss": "^3.0.12"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -3,10 +3,13 @@ import App from './App.vue'
|
|||
|
||||
import router from './router'
|
||||
|
||||
import '@/plugins/vant'
|
||||
import { setupVant } from '@/plugins/vant'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
// 安装vant插件
|
||||
setupVant(app)
|
||||
|
||||
app.config.globalProperties.$$refs = {}
|
||||
|
||||
// if (import.meta.env.DEV) {
|
||||
|
|
|
@ -44,26 +44,9 @@ export default defineComponent({
|
|||
router.replace('/')
|
||||
}
|
||||
|
||||
// 渲染组件
|
||||
const renderCom = (element) => {
|
||||
if (Array.isArray(element)) {
|
||||
return element.map((item) => renderCom(item))
|
||||
}
|
||||
const component = visualConfig.componentMap[element.componentKey]
|
||||
|
||||
return component.render({
|
||||
size: {},
|
||||
props: element.props || {},
|
||||
block: element,
|
||||
model: {},
|
||||
custom: {}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
visualConfig,
|
||||
renderCom
|
||||
visualConfig
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createApp } from 'vue'
|
|||
import App from './App.vue'
|
||||
|
||||
import './plugins/element-plus'
|
||||
import './plugins/vant'
|
||||
import { setupVant } from './plugins/vant'
|
||||
|
||||
import 'normalize.css'
|
||||
import 'virtual:windi.css'
|
||||
|
@ -13,6 +13,9 @@ import store from './store/'
|
|||
|
||||
const app = createApp(App)
|
||||
|
||||
// 使用vant插件
|
||||
setupVant(app)
|
||||
|
||||
app.config.globalProperties.$$refs = {}
|
||||
|
||||
// if (import.meta.env.DEV) {
|
||||
|
|
|
@ -37,23 +37,23 @@ export default {
|
|||
options: [
|
||||
{
|
||||
label: '主要按钮',
|
||||
val: 'primary'
|
||||
value: 'primary'
|
||||
},
|
||||
{
|
||||
label: '成功按钮',
|
||||
val: 'success'
|
||||
value: 'success'
|
||||
},
|
||||
{
|
||||
label: '默认按钮',
|
||||
val: 'default'
|
||||
value: 'default'
|
||||
},
|
||||
{
|
||||
label: '警告按钮',
|
||||
val: 'warning'
|
||||
value: 'warning'
|
||||
},
|
||||
{
|
||||
label: '危险按钮',
|
||||
val: 'danger'
|
||||
value: 'danger'
|
||||
}
|
||||
],
|
||||
defaultValue: 'default'
|
||||
|
@ -63,19 +63,19 @@ export default {
|
|||
options: [
|
||||
{
|
||||
label: '大型',
|
||||
val: 'large'
|
||||
value: 'large'
|
||||
},
|
||||
{
|
||||
label: '普通',
|
||||
val: 'normal'
|
||||
value: 'normal'
|
||||
},
|
||||
{
|
||||
label: '小型',
|
||||
val: 'small'
|
||||
value: 'small'
|
||||
},
|
||||
{
|
||||
label: '迷你',
|
||||
val: 'mini'
|
||||
value: 'mini'
|
||||
}
|
||||
],
|
||||
defaultValue: 'normal'
|
||||
|
@ -83,10 +83,10 @@ export default {
|
|||
'native-type': createEditorSelectProp({
|
||||
label: '原生button的type属性',
|
||||
options: [
|
||||
{ label: '普通button', val: 'button' },
|
||||
{ label: '普通button', value: 'button' },
|
||||
{
|
||||
label: '表单提交按钮',
|
||||
val: 'submit'
|
||||
value: 'submit'
|
||||
}
|
||||
],
|
||||
defaultValue: 'button'
|
||||
|
@ -110,11 +110,11 @@ export default {
|
|||
options: [
|
||||
{
|
||||
label: '左侧',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '右侧',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
]
|
||||
}),
|
||||
|
@ -128,8 +128,8 @@ export default {
|
|||
'loading-type': createEditorSelectProp({
|
||||
label: '加载图标类型',
|
||||
options: [
|
||||
{ label: 'circular', val: 'circular' },
|
||||
{ label: 'spinner', val: 'spinner' }
|
||||
{ label: 'circular', value: 'circular' },
|
||||
{ label: 'spinner', value: 'spinner' }
|
||||
],
|
||||
defaultValue: 'circular'
|
||||
})
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -54,13 +54,13 @@ export default {
|
|||
modelValue: createEditorSelectProp({
|
||||
label: '默认值',
|
||||
options: [
|
||||
{ label: '萝卜', val: 'radish' },
|
||||
{ label: '青菜', val: 'greens' }
|
||||
{ label: '萝卜', value: 'radish' },
|
||||
{ label: '青菜', value: 'greens' }
|
||||
],
|
||||
multiple: true,
|
||||
defaultValue: []
|
||||
}),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'checkbox' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'checkbox' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '复选框' }),
|
||||
options: createEditorTableProp({
|
||||
label: '默认选项',
|
||||
|
@ -82,11 +82,11 @@ export default {
|
|||
options: [
|
||||
{
|
||||
label: '水平',
|
||||
val: 'horizontal'
|
||||
value: 'horizontal'
|
||||
},
|
||||
{
|
||||
label: '垂直',
|
||||
val: 'vertical'
|
||||
value: 'vertical'
|
||||
}
|
||||
],
|
||||
defaultValue: 'horizontal'
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -12,6 +12,14 @@ import { reactive } from 'vue'
|
|||
import { isDate } from '@/visual-editor/utils/is'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const dateType = {
|
||||
'month-day': 'MM-DD',
|
||||
'year-month': 'YYYY-MM',
|
||||
date: 'YYYY-MM-DD',
|
||||
datehour: 'YYYY-MM-DD HH',
|
||||
datetime: 'YYYY-MM-DD HH:mm:ss'
|
||||
}
|
||||
|
||||
export default {
|
||||
key: 'datetimePicker',
|
||||
moduleName: 'baseWidgets',
|
||||
|
@ -21,11 +29,12 @@ export default {
|
|||
const { registerRef } = useGlobalProperties()
|
||||
const state = reactive({
|
||||
showPicker: false,
|
||||
text: ''
|
||||
text: '',
|
||||
currentDate: new Date()
|
||||
})
|
||||
|
||||
const onConfirm = (value) => {
|
||||
const date = isDate(value) ? dayjs(value).format(props.format) : value
|
||||
const date = isDate(value) ? dayjs(value).format(props.format || dateType[props.type]) : value
|
||||
props.modelValue = date
|
||||
state.text = date
|
||||
state.showPicker = false
|
||||
|
@ -56,6 +65,7 @@ export default {
|
|||
<DatetimePicker
|
||||
ref={(el) => registerRef(el, block._vid)}
|
||||
{...props}
|
||||
v-model={state.currentDate}
|
||||
onConfirm={onConfirm}
|
||||
onCancel={() => (state.showPicker = false)}
|
||||
/>
|
||||
|
@ -63,16 +73,12 @@ export default {
|
|||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<PopupPicker />
|
||||
</>
|
||||
)
|
||||
return <PopupPicker />
|
||||
},
|
||||
props: {
|
||||
modelValue: createEditorInputProp({ label: '默认值' }),
|
||||
name: createEditorInputProp({
|
||||
label: '名称,提交表单的标识符',
|
||||
label: '字段名',
|
||||
defaultValue: 'datetimePicker'
|
||||
}),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '时间选择器' }),
|
||||
|
@ -82,31 +88,31 @@ export default {
|
|||
options: [
|
||||
{
|
||||
label: 'date',
|
||||
val: 'date'
|
||||
value: 'date'
|
||||
},
|
||||
{
|
||||
label: 'time',
|
||||
val: 'time'
|
||||
label: 'datetime',
|
||||
value: 'datetime'
|
||||
},
|
||||
{
|
||||
label: 'year-month',
|
||||
val: 'year-month'
|
||||
value: 'year-month'
|
||||
},
|
||||
{
|
||||
label: 'month-day',
|
||||
val: 'month-day'
|
||||
value: 'month-day'
|
||||
},
|
||||
{
|
||||
label: 'datehour',
|
||||
val: 'datehour'
|
||||
value: 'datehour'
|
||||
}
|
||||
],
|
||||
defaultValue: 'time'
|
||||
defaultValue: 'datetime'
|
||||
}),
|
||||
format: createEditorInputProp({
|
||||
label: '选择时间后格式化值',
|
||||
label: '自定义日期格式化值',
|
||||
tips: 'YYYY-MM-DD HH:mm:ss',
|
||||
defaultValue: 'YYYY-MM-DD HH:mm:ss'
|
||||
defaultValue: ''
|
||||
}),
|
||||
cancelButtonText: createEditorInputProp({ label: '取消按钮文字' }),
|
||||
columnsOrder: createEditorInputProp({
|
||||
|
|
|
@ -27,9 +27,9 @@ export default {
|
|||
'content-position': createEditorSelectProp({
|
||||
label: '文本位置',
|
||||
options: [
|
||||
{ label: '左边', val: 'left' },
|
||||
{ label: '中间', val: 'center' },
|
||||
{ label: '右边', val: 'right' }
|
||||
{ label: '左边', value: 'left' },
|
||||
{ label: '中间', value: 'center' },
|
||||
{ label: '右边', value: 'right' }
|
||||
],
|
||||
defaultValue: 'center'
|
||||
}),
|
||||
|
|
|
@ -29,45 +29,45 @@ export default {
|
|||
label: '图片链接',
|
||||
defaultValue: 'https://img.yzcdn.cn/vant/cat.jpeg'
|
||||
}),
|
||||
width: createEditorInputProp({ label: '宽度,默认单位为 px', defaultValue: 100 }),
|
||||
height: createEditorInputProp({ label: '高度,默认单位为 px', defaultValue: 100 }),
|
||||
'error-icon': createEditorInputProp({ label: '失败时提示的图标名称或图片链接' }),
|
||||
width: createEditorInputProp({ label: '宽度', defaultValue: 100 }),
|
||||
height: createEditorInputProp({ label: '高度', defaultValue: 100 }),
|
||||
errorIcon: createEditorInputProp({ label: '失败时提示的图标名称或图片链接' }),
|
||||
fit: createEditorSelectProp({
|
||||
label: '图片填充模式',
|
||||
options: [
|
||||
{
|
||||
label: '保持宽高缩放图片,使图片的长边能完全显示出来',
|
||||
val: 'contain'
|
||||
value: 'contain'
|
||||
},
|
||||
{
|
||||
label: '保持宽高缩放图片,使图片的短边能完全显示出来,裁剪长边',
|
||||
val: 'cover'
|
||||
value: 'cover'
|
||||
},
|
||||
{
|
||||
label: '拉伸图片,使图片填满元素',
|
||||
val: 'fill'
|
||||
value: 'fill'
|
||||
},
|
||||
{
|
||||
label: '保持图片原有尺寸',
|
||||
val: 'none'
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
label: '取 none 或 contain 中较小的一个',
|
||||
val: 'scale-down'
|
||||
value: 'scale-down'
|
||||
}
|
||||
],
|
||||
defaultValue: 'fill'
|
||||
}),
|
||||
'icon-prefix': createEditorInputProp({
|
||||
iconPrefix: createEditorInputProp({
|
||||
label: '图标类名前缀',
|
||||
tips: '图标类名前缀,同 Icon 组件的 class-prefix 属性'
|
||||
}),
|
||||
'icon-size': createEditorInputProp({ label: '加载图标和失败图标的大小' }),
|
||||
'lazy-load': createEditorSwitchProp({
|
||||
iconSize: createEditorInputProp({ label: '加载图标和失败图标的大小' }),
|
||||
lazyLoad: createEditorSwitchProp({
|
||||
label: '是否开启图片懒加载',
|
||||
tips: '须配合 Lazyload 组件使用'
|
||||
}),
|
||||
'loading-icon': createEditorInputProp({ label: '加载时提示的图标名称或图片链接' }),
|
||||
loadingIcon: createEditorInputProp({ label: '加载时提示的图标名称或图片链接' }),
|
||||
radius: createEditorInputProp({ label: '圆角大小', tips: '默认单位为 px' }),
|
||||
round: createEditorSwitchProp({ label: '是否显示为圆形' }),
|
||||
'show-error': createEditorSwitchProp({ label: '是否展示图片加载失败提示' }),
|
||||
|
|
|
@ -16,17 +16,17 @@ export const createFieldProps = () => ({
|
|||
label: '默认值',
|
||||
defaultValue: ''
|
||||
}),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'input' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'input' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '输入框' }),
|
||||
type: createEditorSelectProp({
|
||||
label: '输入框类型',
|
||||
options: [
|
||||
{ label: '文本', val: 'text' },
|
||||
{ label: '数字', val: 'number' },
|
||||
{ label: '文本域', val: 'textarea' },
|
||||
{ label: '密码', val: 'password' },
|
||||
{ label: '电话', val: 'tel' },
|
||||
{ label: '小数点', val: 'digit' }
|
||||
{ label: '文本', value: 'text' },
|
||||
{ label: '数字', value: 'number' },
|
||||
{ label: '文本域', value: 'textarea' },
|
||||
{ label: '密码', value: 'password' },
|
||||
{ label: '电话', value: 'tel' },
|
||||
{ label: '小数点', value: 'digit' }
|
||||
],
|
||||
defaultValue: 'text'
|
||||
}),
|
||||
|
@ -40,15 +40,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
@ -66,8 +66,7 @@ export const createFieldProps = () => ({
|
|||
autosize: createEditorSwitchProp({
|
||||
label: '自适应内容高度',
|
||||
defaultValue: false,
|
||||
tips:
|
||||
'是否自适应内容高度,只对 textarea 有效,可传入对象,如 { maxHeight: 100, minHeight: 50 },单位为px'
|
||||
tips: '是否自适应内容高度,只对 textarea 有效,可传入对象,如 { maxHeight: 100, minHeight: 50 },单位为px'
|
||||
}),
|
||||
border: createEditorSwitchProp({ label: '是否显示内边框', defaultValue: true }),
|
||||
center: createEditorSwitchProp({ label: '内容垂直居中' }),
|
||||
|
@ -78,8 +77,8 @@ export const createFieldProps = () => ({
|
|||
'clear-trigger': createEditorSelectProp({
|
||||
label: '清除图标显示时机',
|
||||
options: [
|
||||
{ label: '输入框不为空时展示', val: 'always' },
|
||||
{ label: '输入框聚焦且不为空时展示', val: 'focus' }
|
||||
{ label: '输入框不为空时展示', value: 'always' },
|
||||
{ label: '输入框聚焦且不为空时展示', value: 'focus' }
|
||||
],
|
||||
defaultValue: 'always',
|
||||
tips: '显示清除图标的时机,always 表示输入框不为空时展示,focus 表示输入框聚焦且不为空时展示'
|
||||
|
@ -101,15 +100,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
@ -119,15 +118,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -39,7 +39,8 @@ export default {
|
|||
style={{
|
||||
width: size.width ? `${size.width}px` : null
|
||||
}}
|
||||
v-slots={{
|
||||
>
|
||||
{{
|
||||
input: () =>
|
||||
state.text?.trim() == '' ? (
|
||||
<span class={'placeholder'}>{props.placeholder}</span>
|
||||
|
@ -47,7 +48,7 @@ export default {
|
|||
state.text
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<Popup v-model={[state.showPicker, 'show', ['modifier']]} position={'bottom'}>
|
||||
<Picker
|
||||
ref={(el) => registerRef(el, block._vid)}
|
||||
|
@ -60,15 +61,11 @@ export default {
|
|||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<PopupPicker />
|
||||
</>
|
||||
)
|
||||
return <PopupPicker />
|
||||
},
|
||||
props: {
|
||||
modelValue: createEditorInputProp({ label: '默认值' }),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'picker' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'picker' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '选择器' }),
|
||||
columns: createEditorTableProp({
|
||||
label: '数据项',
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -48,7 +48,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
modelValue: createEditorInputProp({ label: '默认值', defaultValue: '' }),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'radio' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'radio' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '单选框' }),
|
||||
options: createEditorTableProp({
|
||||
label: '默认选项',
|
||||
|
@ -70,11 +70,11 @@ export default {
|
|||
options: [
|
||||
{
|
||||
label: '水平',
|
||||
val: 'horizontal'
|
||||
value: 'horizontal'
|
||||
},
|
||||
{
|
||||
label: '垂直',
|
||||
val: 'vertical'
|
||||
value: 'vertical'
|
||||
}
|
||||
],
|
||||
defaultValue: 'horizontal'
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -44,7 +44,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
modelValue: createEditorInputNumberProp({ label: '默认值', defaultValue: 0 }),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'rate' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'rate' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '评分' }),
|
||||
count: createEditorInputNumberProp({ label: '图标总数' }),
|
||||
size: createEditorInputProp({ label: '图标大小' }),
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -44,7 +44,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
modelValue: createEditorInputNumberProp({ label: '默认值', defaultValue: 0 }),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'slider' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'slider' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '滑块' }),
|
||||
min: createEditorInputNumberProp({ label: '最小值' }),
|
||||
max: createEditorInputNumberProp({ label: '最大值' }),
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -43,7 +43,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
modelValue: createEditorInputNumberProp({ label: '默认值', defaultValue: 0 }),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'stepper' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'stepper' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '步进器' }),
|
||||
min: createEditorInputNumberProp({ label: '最小值' }),
|
||||
max: createEditorInputNumberProp({ label: '最大值' }),
|
||||
|
|
|
@ -19,15 +19,15 @@ export const createFieldProps = () => ({
|
|||
options: [
|
||||
{
|
||||
label: '左对齐',
|
||||
val: 'left'
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
val: 'center'
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
val: 'right'
|
||||
value: 'right'
|
||||
}
|
||||
],
|
||||
defaultValue: 'left'
|
||||
|
|
|
@ -35,7 +35,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
modelValue: createEditorInputProp({ label: '默认值', defaultValue: 'false' }),
|
||||
name: createEditorInputProp({ label: '名称,提交表单的标识符', defaultValue: 'switch' }),
|
||||
name: createEditorInputProp({ label: '字段名', defaultValue: 'switch' }),
|
||||
label: createEditorInputProp({ label: '输入框左侧文本', defaultValue: '开关' }),
|
||||
'active-color': createEditorInputProp({ label: '打开时的背景色' }),
|
||||
'active-value': createEditorInputProp({ label: '打开时对应的值' }),
|
||||
|
|
|
@ -19,9 +19,9 @@ export default {
|
|||
size: createEditorSelectProp({
|
||||
label: '字体大小',
|
||||
options: [
|
||||
{ label: '14px', val: '14px' },
|
||||
{ label: '18px', val: '18px' },
|
||||
{ label: '24px', val: '24px' }
|
||||
{ label: '14px', value: '14px' },
|
||||
{ label: '18px', value: '18px' },
|
||||
{ label: '24px', value: '24px' }
|
||||
]
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* @name: createProps
|
||||
* @author: 卜启缘
|
||||
* @date: 2021/5/30 10:50
|
||||
* @description:createProps
|
||||
* @update: 2021/5/30 10:50
|
||||
*/
|
||||
|
||||
import {
|
||||
createEditorInputProp,
|
||||
createEditorSelectProp,
|
||||
createEditorSwitchProp,
|
||||
createEditorTableProp
|
||||
} from '@/visual-editor/visual-editor.props'
|
||||
|
||||
// 对齐方式
|
||||
const alignOptions = [
|
||||
{
|
||||
label: '左对齐',
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
label: '右对齐',
|
||||
value: 'right'
|
||||
},
|
||||
{
|
||||
label: '居中对齐',
|
||||
value: 'center'
|
||||
}
|
||||
]
|
||||
|
||||
export const compProps = {
|
||||
'slots.default.children': createEditorTableProp({
|
||||
label: '表单项',
|
||||
option: {
|
||||
options: [
|
||||
{ label: '显示值', field: 'label' },
|
||||
{ label: '绑定值', field: 'value' },
|
||||
{ label: '备注', field: 'comments' }
|
||||
],
|
||||
showKey: 'label'
|
||||
},
|
||||
defaultValue: []
|
||||
}),
|
||||
colon: createEditorSwitchProp({ label: '是否在 label 后面添加冒号' }),
|
||||
disabled: createEditorSwitchProp({ label: '是否禁用表单中的所有输入框' }),
|
||||
errorMessageAlign: createEditorSelectProp({
|
||||
label: '错误提示文案对齐方式',
|
||||
defaultValue: 'left',
|
||||
options: alignOptions
|
||||
}),
|
||||
inputAlign: createEditorSelectProp({
|
||||
label: '输入框对齐方式',
|
||||
defaultValue: 'left',
|
||||
options: alignOptions
|
||||
}),
|
||||
labelAlign: createEditorSelectProp({
|
||||
label: '表单项 label 对齐方式',
|
||||
defaultValue: 'left',
|
||||
options: alignOptions
|
||||
}),
|
||||
labelWidth: createEditorInputProp({ label: '表单项 label 宽度,默认单位为px' }),
|
||||
readonly: createEditorSwitchProp({ label: '是否将表单中的所有输入框设置为只读状态' }),
|
||||
scrollToError: createEditorSwitchProp({
|
||||
label: '在提交表单且校验不通过时滚动至错误的表单项'
|
||||
}),
|
||||
showError: createEditorSwitchProp({ label: '是否在校验不通过时标红输入框' }),
|
||||
showErrorMessage: createEditorSwitchProp({
|
||||
label: '是否在校验不通过时在输入框下方展示错误提示'
|
||||
}),
|
||||
submitOnEnter: createEditorSwitchProp({ label: '是否在按下回车键时提交表单' }),
|
||||
validateFirst: createEditorSwitchProp({ label: '是否在某一项校验不通过时停止校验' }),
|
||||
validateTrigger: createEditorInputProp({
|
||||
label: '表单校验触发时机,可选值为 onChange、onSubmit,详见下表'
|
||||
})
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import { Form, Field, Button } from 'vant'
|
||||
import { renderSlot, getCurrentInstance } from 'vue'
|
||||
import { createEditorTableProp } from '@/visual-editor/visual-editor.props'
|
||||
import { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
|
||||
import { useGlobalProperties } from '@/hooks/useGlobalProperties'
|
||||
import { compProps } from './compProps'
|
||||
|
||||
export default {
|
||||
key: 'form',
|
||||
|
@ -37,18 +37,5 @@ export default {
|
|||
height: true,
|
||||
width: true
|
||||
},
|
||||
props: {
|
||||
'slots.default.children': createEditorTableProp({
|
||||
label: '表单项',
|
||||
option: {
|
||||
options: [
|
||||
{ label: '显示值', field: 'label' },
|
||||
{ label: '绑定值', field: 'value' },
|
||||
{ label: '备注', field: 'comments' }
|
||||
],
|
||||
showKey: 'label'
|
||||
},
|
||||
defaultValue: []
|
||||
})
|
||||
}
|
||||
props: compProps
|
||||
} as VisualEditorComponent
|
||||
|
|
|
@ -85,32 +85,32 @@ export default {
|
|||
slots: createEditorSelectProp({
|
||||
label: '列比例',
|
||||
options: [
|
||||
{ label: '24', val: createSlots('24') },
|
||||
{ label: '12:12', val: createSlots('12:12') },
|
||||
{ label: '6:18', val: createSlots('6:18') },
|
||||
{ label: '18:6', val: createSlots('18:6') },
|
||||
{ label: '8:8:8', val: createSlots('8:8:8') },
|
||||
{ label: '6:12:6', val: createSlots('6:12:6') },
|
||||
{ label: '6:6:6:6', val: createSlots('6:6:6:6') }
|
||||
{ label: '24', value: createSlots('24') },
|
||||
{ label: '12:12', value: createSlots('12:12') },
|
||||
{ label: '6:18', value: createSlots('6:18') },
|
||||
{ label: '18:6', value: createSlots('18:6') },
|
||||
{ label: '8:8:8', value: createSlots('8:8:8') },
|
||||
{ label: '6:12:6', value: createSlots('6:12:6') },
|
||||
{ label: '6:6:6:6', value: createSlots('6:6:6:6') }
|
||||
],
|
||||
defaultValue: createSlots('12:12')
|
||||
}),
|
||||
justify: createEditorSelectProp({
|
||||
label: '主轴对齐方式',
|
||||
options: [
|
||||
{ label: '左对齐', val: 'start' },
|
||||
{ label: '居中排列', val: 'center' },
|
||||
{ label: '均匀对齐', val: 'space-around' },
|
||||
{ label: '两端对齐', val: 'space-between' },
|
||||
{ label: '右对齐', val: 'end' }
|
||||
{ label: '左对齐', value: 'start' },
|
||||
{ label: '居中排列', value: 'center' },
|
||||
{ label: '均匀对齐', value: 'space-around' },
|
||||
{ label: '两端对齐', value: 'space-between' },
|
||||
{ label: '右对齐', value: 'end' }
|
||||
]
|
||||
}),
|
||||
align: createEditorSelectProp({
|
||||
label: '交叉轴对齐方式',
|
||||
options: [
|
||||
{ label: '顶部对齐', val: 'top' },
|
||||
{ label: '垂直居中', val: 'center' },
|
||||
{ label: '底部对齐', val: 'bottom' }
|
||||
{ label: '顶部对齐', value: 'top' },
|
||||
{ label: '垂直居中', value: 'center' },
|
||||
{ label: '底部对齐', value: 'bottom' }
|
||||
]
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
import { App } from 'vue'
|
||||
import '@vant/touch-emulator'
|
||||
import 'vant/lib/index.css'
|
||||
|
||||
import { Lazyload } from 'vant'
|
||||
|
||||
export const setupVant = (app: App) => {
|
||||
app.use(Lazyload)
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
>删除</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item icon="el-icon-link" @click="setDefaultPage(data)"
|
||||
>设为默认</el-dropdown-item
|
||||
>设为首页</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* @name: index
|
||||
* @author: 卜启缘
|
||||
* @date: 2021/5/30 10:57
|
||||
* @description:index
|
||||
* @update: 2021/5/30 10:57
|
||||
*/
|
||||
export { TablePropEditor } from './table-prop-editor/table-prop-editor'
|
|
@ -1,8 +1,8 @@
|
|||
import { defineComponent, PropType } from 'vue'
|
||||
import { VisualEditorProps } from '../../../../visual-editor.props'
|
||||
import { useModel } from '../../../../hooks/useModel'
|
||||
import { defineComponent, PropType, SetupContext } from 'vue'
|
||||
import { VisualEditorProps } from '@/visual-editor/visual-editor.props'
|
||||
import { ElButton, ElTag } from 'element-plus'
|
||||
import { $$tablePropEditor } from './table-prop-edit.service'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
|
||||
export const TablePropEditor = defineComponent({
|
||||
props: {
|
||||
|
@ -10,11 +10,8 @@ export const TablePropEditor = defineComponent({
|
|||
propConfig: { type: Object as PropType<VisualEditorProps>, required: true }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, ctx) {
|
||||
const model = useModel(
|
||||
() => props.modelValue,
|
||||
(val) => ctx.emit('update:modelValue', val)
|
||||
)
|
||||
setup(props, { emit }: SetupContext) {
|
||||
const model = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const onClick = async () => {
|
||||
const data = await $$tablePropEditor({
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
ElPopover
|
||||
} from 'element-plus'
|
||||
import { VisualEditorProps, VisualEditorPropsType } from '@/visual-editor/visual-editor.props'
|
||||
import { TablePropEditor } from '@/visual-editor/components/right-attribute-panel/components/table-prop-editor/table-prop-editor'
|
||||
import { TablePropEditor } from './components/'
|
||||
import { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils'
|
||||
import MonacoEditor from '../common/monaco-editor/MonacoEditor'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
|
@ -57,7 +57,7 @@ export default defineComponent({
|
|||
<ElSelect v-model={propObj[prop]} valueKey={'value'} multiple={propConfig.multiple}>
|
||||
{(() => {
|
||||
return propConfig.options!.map((opt) => (
|
||||
<ElOption label={opt.label} value={opt.val} />
|
||||
<ElOption label={opt.label} value={opt.value} />
|
||||
))
|
||||
})()}
|
||||
</ElSelect>
|
||||
|
@ -93,33 +93,30 @@ export default defineComponent({
|
|||
width={200}
|
||||
trigger="hover"
|
||||
content={`你可以利用该组件ID。对该组件进行获取和设置其属性,组件可用属性可在控制台输入:$$refs.${props.block._vid} 进行查看`}
|
||||
v-slots={{
|
||||
>
|
||||
{{
|
||||
reference: () => (
|
||||
<i style={{ marginLeft: '6px' }} class={'el-icon-warning-outline'}></i>
|
||||
)
|
||||
}}
|
||||
></ElPopover>
|
||||
</ElPopover>
|
||||
</ElFormItem>
|
||||
)
|
||||
if (!!component) {
|
||||
if (!!component.props) {
|
||||
content.push(
|
||||
<>
|
||||
{Object.entries(component.props || {}).map(([propName, propConfig]) => (
|
||||
Object.entries(component.props || {}).map(([propName, propConfig]) => (
|
||||
<ElFormItem
|
||||
key={propName}
|
||||
key={props.block._vid + propName}
|
||||
v-slots={{
|
||||
label: () =>
|
||||
propConfig.tips ? (
|
||||
<>
|
||||
<ElPopover
|
||||
width={200}
|
||||
trigger={'hover'}
|
||||
content={propConfig.tips}
|
||||
v-slots={{
|
||||
<ElPopover width={200} trigger={'hover'} content={propConfig.tips}>
|
||||
{{
|
||||
reference: () => <i class={'el-icon-warning-outline'}></i>
|
||||
}}
|
||||
></ElPopover>
|
||||
</ElPopover>
|
||||
{propConfig.label}
|
||||
</>
|
||||
) : (
|
||||
|
@ -129,8 +126,7 @@ export default defineComponent({
|
|||
>
|
||||
{renderEditor(propName, propConfig)}
|
||||
</ElFormItem>
|
||||
))}
|
||||
</>
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,6 @@ export default defineComponent({
|
|||
const { currentPage, visualConfig } = useVisualData()
|
||||
|
||||
const state = reactive({
|
||||
compRefs: [],
|
||||
drag: false
|
||||
})
|
||||
|
||||
|
@ -188,37 +187,41 @@ export default defineComponent({
|
|||
<style lang="scss" scoped>
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
padding: 3px;
|
||||
cursor: move;
|
||||
transform: translate(0);
|
||||
padding: 3px;
|
||||
|
||||
&.focus {
|
||||
content: '';
|
||||
outline: 2px solid #006eff;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
&.drag::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.no-child {
|
||||
content: '';
|
||||
}
|
||||
|
||||
&.focusWithChild {
|
||||
outline: 2px dashed #b0c1d7;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
&.focusWithChild::before {
|
||||
content: attr(data-label);
|
||||
position: absolute;
|
||||
left: -3px;
|
||||
top: 0;
|
||||
transform: translate(-100%, 0);
|
||||
background-color: #006eff;
|
||||
color: white;
|
||||
left: -3px;
|
||||
padding: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
background-color: #006eff;
|
||||
border-radius: 3px;
|
||||
content: attr(data-label);
|
||||
transform: translate(-100%, 0);
|
||||
}
|
||||
|
||||
i {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @update: 2021/5/6 11:59
|
||||
*/
|
||||
import { reactive, inject, readonly, computed, watch, ComputedRef, DeepReadonly } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
VisualEditorModelValue,
|
||||
VisualEditorBlockData,
|
||||
|
@ -40,10 +40,7 @@ export interface VisualData {
|
|||
setCurrentPage: (path: string) => void // 设置当前正在操作的页面
|
||||
}
|
||||
|
||||
export const initVisualData = (): VisualData => {
|
||||
const jsonData: VisualEditorModelValue = JSON.parse(
|
||||
sessionStorage.getItem(localKey) as string
|
||||
) || {
|
||||
const defaultValue: VisualEditorModelValue = {
|
||||
container: {
|
||||
width: 360,
|
||||
height: 960
|
||||
|
@ -55,9 +52,16 @@ export const initVisualData = (): VisualData => {
|
|||
blocks: []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const initVisualData = (): VisualData => {
|
||||
const localData = JSON.parse(sessionStorage.getItem(localKey) as string)
|
||||
const jsonData: VisualEditorModelValue = Object.keys(localData?.pages || {}).length
|
||||
? localData
|
||||
: defaultValue
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
console.log('jsonData:', jsonData)
|
||||
// 所有页面的path都必须以 / 开发
|
||||
|
@ -65,8 +69,20 @@ export const initVisualData = (): VisualData => {
|
|||
|
||||
const state: IState = reactive({
|
||||
jsonData,
|
||||
currentPage: jsonData.pages[route.path] ?? jsonData.pages['/']
|
||||
currentPage: jsonData.pages[route.path]
|
||||
})
|
||||
const paths = Object.keys(jsonData.pages)
|
||||
|
||||
const isExistPath = paths.some((path) => route.path == path)
|
||||
// 当前页面是否存在
|
||||
if (!isExistPath) {
|
||||
router.replace(paths[0] || '/')
|
||||
state.currentPage = jsonData.pages[paths[0]] ?? defaultValue.pages['/']
|
||||
}
|
||||
|
||||
console.log(jsonData.pages, 'jsonData.pages')
|
||||
console.log(route.path, 'route.path')
|
||||
console.log(state.currentPage, '哈哈哈')
|
||||
|
||||
// 路由变化时更新当前操作的页面
|
||||
watch(
|
||||
|
@ -88,7 +104,7 @@ export const initVisualData = (): VisualData => {
|
|||
}
|
||||
// 添加page
|
||||
const incrementPage = (path = '', page: VisualEditorPage) => {
|
||||
state.jsonData.pages[getPrefixPath(path)] = page ?? { title: '新页面', path, blocks: [] }
|
||||
state.jsonData.pages[getPrefixPath(path)] ??= page ?? { title: '新页面', path, blocks: [] }
|
||||
}
|
||||
// 删除page
|
||||
const deletePage = (path = '', redirectPath = '') => {
|
||||
|
@ -100,6 +116,10 @@ export const initVisualData = (): VisualData => {
|
|||
// 设置当前页面
|
||||
const setCurrentPage = (path = '/') => {
|
||||
state.currentPage = jsonData.pages[path]
|
||||
if (!state.currentPage) {
|
||||
state.currentPage = jsonData.pages['/']
|
||||
router.replace('/')
|
||||
}
|
||||
}
|
||||
|
||||
// 更新pages下面的blocks
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* @name: index.d
|
||||
* @author: 卜启缘
|
||||
* @date: 2021/5/30 10:40
|
||||
* @description:index.d
|
||||
* @update: 2021/5/30 10:40
|
||||
*/
|
||||
declare type LabelValueOptions = {
|
||||
label: string
|
||||
value: any
|
||||
}[]
|
|
@ -18,22 +18,7 @@ export type VisualEditorProps = {
|
|||
} & {
|
||||
table?: VisualEditorTableOption
|
||||
}
|
||||
// 控制台输入以下代码,快速生成组件属性
|
||||
// let propObj = {
|
||||
// string: (config) => `createEditorInputProp(${JSON.stringify(config)})`,
|
||||
// number: (config) => `createEditorInputNumberProp(${JSON.stringify(config)})`,
|
||||
// boolean: (config) => `createEditorSwitchProp(${JSON.stringify(config)})`
|
||||
// }
|
||||
//
|
||||
// $$('#props + table tr').reduce((prev, curr) => {
|
||||
// const children = curr.children
|
||||
// const key = children[0].textContent.replace(/-([a-z])/g, (all, i) => i.toUpperCase())
|
||||
// const value = (propObj[children[2].textContent ?? propObj['string'])({
|
||||
// label: children[1].textContent
|
||||
// }).replaceAll('"', '')
|
||||
// prev[key] = value
|
||||
// return prev
|
||||
// }, {})
|
||||
|
||||
/*---------------------------------------switch-------------------------------------------*/
|
||||
interface EditorSwitchProp {
|
||||
label: string
|
||||
|
|
|
@ -1,232 +1,232 @@
|
|||
import { useCommander } from './plugins/command.plugin'
|
||||
import { VisualEditorBlockData, VisualEditorModelValue } from './visual-editor.utils'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
export function useVisualCommand({
|
||||
focusData,
|
||||
updateBlocks,
|
||||
dataModel,
|
||||
dragstart,
|
||||
dragend
|
||||
}: {
|
||||
focusData: { value: { focus: VisualEditorBlockData[]; unFocus: VisualEditorBlockData[] } }
|
||||
updateBlocks: (blocks?: VisualEditorBlockData[]) => void
|
||||
dataModel: { value: VisualEditorModelValue }
|
||||
dragstart: { on: (cb: () => void) => void; off: (cb: () => void) => void }
|
||||
dragend: { on: (cb: () => void) => void; off: (cb: () => void) => void }
|
||||
}) {
|
||||
const commander = useCommander()
|
||||
|
||||
/**
|
||||
* 删除命令
|
||||
* @author 卜启缘
|
||||
* @date 2021/4/22 11:37 下午
|
||||
*/
|
||||
commander.registry({
|
||||
name: 'delete',
|
||||
keyboard: ['backspace', 'delete', 'ctrl+d'],
|
||||
execute: () => {
|
||||
// console.log('执行删除命令')
|
||||
const data = {
|
||||
before: dataModel.value.blocks,
|
||||
after: focusData.value.unFocus
|
||||
}
|
||||
return {
|
||||
redo: () => {
|
||||
// console.log('重做删除命令')
|
||||
updateBlocks(cloneDeep(data.after))
|
||||
},
|
||||
undo: () => {
|
||||
// console.log('撤回删除命令')
|
||||
updateBlocks(cloneDeep(data.before))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 拖拽命令,适用于三种情况:
|
||||
* - 从菜单拖拽组件到容器画布;
|
||||
* - 在容器中拖拽组件调整位置
|
||||
* - 拖拽调整组件的宽度和高度;
|
||||
* @author 卜启缘
|
||||
* @date 2021/4/22 11:38 下午
|
||||
*/
|
||||
commander.registry({
|
||||
name: 'drag',
|
||||
init() {
|
||||
this.data = { before: null as null | VisualEditorBlockData[] }
|
||||
const handler = {
|
||||
dragstart: () => (this.data.before = cloneDeep(dataModel.value.blocks)),
|
||||
dragend: () => commander.state.commands.drag()
|
||||
}
|
||||
dragstart.on(handler.dragstart)
|
||||
dragend.on(handler.dragend)
|
||||
return () => {
|
||||
dragstart.off(handler.dragstart)
|
||||
dragend.off(handler.dragend)
|
||||
}
|
||||
},
|
||||
execute() {
|
||||
const before = cloneDeep(this.data.before)
|
||||
const after = cloneDeep(dataModel.value.blocks)
|
||||
return {
|
||||
redo: () => {
|
||||
updateBlocks(cloneDeep(after))
|
||||
},
|
||||
undo: () => {
|
||||
updateBlocks(cloneDeep(before))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.registry({
|
||||
name: 'clear',
|
||||
execute: () => {
|
||||
const data = {
|
||||
before: cloneDeep(dataModel.value.blocks),
|
||||
after: cloneDeep([])
|
||||
}
|
||||
return {
|
||||
redo: () => {
|
||||
updateBlocks(cloneDeep(data.after))
|
||||
},
|
||||
undo: () => {
|
||||
updateBlocks(cloneDeep(data.before))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.registry({
|
||||
name: 'placeTop',
|
||||
keyboard: 'ctrl+up',
|
||||
execute: () => {
|
||||
const data = {
|
||||
before: cloneDeep(dataModel.value.blocks),
|
||||
after: cloneDeep(
|
||||
(() => {
|
||||
const { focus, unFocus } = focusData.value
|
||||
const maxZIndex =
|
||||
unFocus.reduce((prev, block) => Math.max(prev, block.zIndex), -Infinity) + 1
|
||||
focus.forEach((block) => (block.zIndex = maxZIndex))
|
||||
return cloneDeep(dataModel.value.blocks)
|
||||
})()
|
||||
)
|
||||
}
|
||||
return {
|
||||
redo: () => {
|
||||
updateBlocks(cloneDeep(data.after))
|
||||
},
|
||||
undo: () => {
|
||||
updateBlocks(cloneDeep(data.before))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.registry({
|
||||
name: 'placeBottom',
|
||||
keyboard: 'ctrl+down',
|
||||
execute: () => {
|
||||
const data = {
|
||||
before: cloneDeep(dataModel.value.blocks),
|
||||
after: cloneDeep(
|
||||
(() => {
|
||||
const { focus, unFocus } = focusData.value
|
||||
let minZIndex =
|
||||
unFocus.reduce((prev, block) => Math.min(prev, block.zIndex), Infinity) - 1
|
||||
if (minZIndex < 0) {
|
||||
const dur = Math.abs(minZIndex)
|
||||
unFocus.forEach((block) => (block.zIndex += dur))
|
||||
minZIndex = 0
|
||||
}
|
||||
focus.forEach((block) => (block.zIndex = minZIndex))
|
||||
return cloneDeep(dataModel.value.blocks)
|
||||
})()
|
||||
)
|
||||
}
|
||||
return {
|
||||
redo: () => {
|
||||
updateBlocks(cloneDeep(data.after))
|
||||
},
|
||||
undo: () => {
|
||||
updateBlocks(cloneDeep(data.before))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.registry({
|
||||
name: 'updateBlock',
|
||||
execute: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) => {
|
||||
let blocks = cloneDeep(dataModel.value.blocks || [])
|
||||
const data = {
|
||||
before: blocks,
|
||||
after: (() => {
|
||||
blocks = [...blocks]
|
||||
const index = dataModel.value.blocks!.indexOf(oldBlock)
|
||||
if (index > -1) {
|
||||
blocks.splice(index, 1, newBlock)
|
||||
}
|
||||
return cloneDeep(blocks)
|
||||
})()
|
||||
}
|
||||
return {
|
||||
redo: () => {
|
||||
updateBlocks(cloneDeep(data.after))
|
||||
},
|
||||
undo: () => {
|
||||
updateBlocks(cloneDeep(data.before))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.registry({
|
||||
name: 'updateModelValue',
|
||||
execute: (val: VisualEditorModelValue) => {
|
||||
const data = {
|
||||
before: cloneDeep(dataModel.value),
|
||||
after: cloneDeep(val)
|
||||
}
|
||||
return {
|
||||
redo: () => {
|
||||
dataModel.value = data.after
|
||||
},
|
||||
undo: () => {
|
||||
dataModel.value = data.before
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.registry({
|
||||
name: 'selectAll',
|
||||
followQueue: false,
|
||||
keyboard: 'ctrl+a',
|
||||
execute: () => {
|
||||
return {
|
||||
redo: () => {
|
||||
;(dataModel.value.blocks || []).forEach((block) => (block.focus = true))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commander.init()
|
||||
|
||||
return {
|
||||
undo: () => commander.state.commands.undo(),
|
||||
redo: () => commander.state.commands.redo(),
|
||||
delete: () => commander.state.commands.delete(),
|
||||
clear: () => commander.state.commands.clear(),
|
||||
placeTop: () => commander.state.commands.placeTop(),
|
||||
placeBottom: () => commander.state.commands.placeBottom(),
|
||||
updateBlock: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) =>
|
||||
commander.state.commands.updateBlock(newBlock, oldBlock),
|
||||
updateModelValue: (val: VisualEditorModelValue) =>
|
||||
commander.state.commands.updateModelValue(val)
|
||||
}
|
||||
}
|
||||
// import { useCommander } from './plugins/command.plugin'
|
||||
// import { VisualEditorBlockData, VisualEditorModelValue } from './visual-editor.utils'
|
||||
// import { cloneDeep } from 'lodash'
|
||||
//
|
||||
// export function useVisualCommand({
|
||||
// focusData,
|
||||
// updateBlocks,
|
||||
// dataModel,
|
||||
// dragstart,
|
||||
// dragend
|
||||
// }: {
|
||||
// focusData: { value: { focus: VisualEditorBlockData[]; unFocus: VisualEditorBlockData[] } }
|
||||
// updateBlocks: (blocks?: VisualEditorBlockData[]) => void
|
||||
// dataModel: { value: VisualEditorModelValue }
|
||||
// dragstart: { on: (cb: () => void) => void; off: (cb: () => void) => void }
|
||||
// dragend: { on: (cb: () => void) => void; off: (cb: () => void) => void }
|
||||
// }) {
|
||||
// const commander = useCommander()
|
||||
//
|
||||
// /**
|
||||
// * 删除命令
|
||||
// * @author 卜启缘
|
||||
// * @date 2021/4/22 11:37 下午
|
||||
// */
|
||||
// commander.registry({
|
||||
// name: 'delete',
|
||||
// keyboard: ['backspace', 'delete', 'ctrl+d'],
|
||||
// execute: () => {
|
||||
// // console.log('执行删除命令')
|
||||
// const data = {
|
||||
// before: dataModel.value.blocks,
|
||||
// after: focusData.value.unFocus
|
||||
// }
|
||||
// return {
|
||||
// redo: () => {
|
||||
// // console.log('重做删除命令')
|
||||
// updateBlocks(cloneDeep(data.after))
|
||||
// },
|
||||
// undo: () => {
|
||||
// // console.log('撤回删除命令')
|
||||
// updateBlocks(cloneDeep(data.before))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// /**
|
||||
// * 拖拽命令,适用于三种情况:
|
||||
// * - 从菜单拖拽组件到容器画布;
|
||||
// * - 在容器中拖拽组件调整位置
|
||||
// * - 拖拽调整组件的宽度和高度;
|
||||
// * @author 卜启缘
|
||||
// * @date 2021/4/22 11:38 下午
|
||||
// */
|
||||
// commander.registry({
|
||||
// name: 'drag',
|
||||
// init() {
|
||||
// this.data = { before: null as null | VisualEditorBlockData[] }
|
||||
// const handler = {
|
||||
// dragstart: () => (this.data.before = cloneDeep(dataModel.value.blocks)),
|
||||
// dragend: () => commander.state.commands.drag()
|
||||
// }
|
||||
// dragstart.on(handler.dragstart)
|
||||
// dragend.on(handler.dragend)
|
||||
// return () => {
|
||||
// dragstart.off(handler.dragstart)
|
||||
// dragend.off(handler.dragend)
|
||||
// }
|
||||
// },
|
||||
// execute() {
|
||||
// const before = cloneDeep(this.data.before)
|
||||
// const after = cloneDeep(dataModel.value.blocks)
|
||||
// return {
|
||||
// redo: () => {
|
||||
// updateBlocks(cloneDeep(after))
|
||||
// },
|
||||
// undo: () => {
|
||||
// updateBlocks(cloneDeep(before))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.registry({
|
||||
// name: 'clear',
|
||||
// execute: () => {
|
||||
// const data = {
|
||||
// before: cloneDeep(dataModel.value.blocks),
|
||||
// after: cloneDeep([])
|
||||
// }
|
||||
// return {
|
||||
// redo: () => {
|
||||
// updateBlocks(cloneDeep(data.after))
|
||||
// },
|
||||
// undo: () => {
|
||||
// updateBlocks(cloneDeep(data.before))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.registry({
|
||||
// name: 'placeTop',
|
||||
// keyboard: 'ctrl+up',
|
||||
// execute: () => {
|
||||
// const data = {
|
||||
// before: cloneDeep(dataModel.value.blocks),
|
||||
// after: cloneDeep(
|
||||
// (() => {
|
||||
// const { focus, unFocus } = focusData.value
|
||||
// const maxZIndex =
|
||||
// unFocus.reduce((prev, block) => Math.max(prev, block.zIndex), -Infinity) + 1
|
||||
// focus.forEach((block) => (block.zIndex = maxZIndex))
|
||||
// return cloneDeep(dataModel.value.blocks)
|
||||
// })()
|
||||
// )
|
||||
// }
|
||||
// return {
|
||||
// redo: () => {
|
||||
// updateBlocks(cloneDeep(data.after))
|
||||
// },
|
||||
// undo: () => {
|
||||
// updateBlocks(cloneDeep(data.before))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.registry({
|
||||
// name: 'placeBottom',
|
||||
// keyboard: 'ctrl+down',
|
||||
// execute: () => {
|
||||
// const data = {
|
||||
// before: cloneDeep(dataModel.value.blocks),
|
||||
// after: cloneDeep(
|
||||
// (() => {
|
||||
// const { focus, unFocus } = focusData.value
|
||||
// let minZIndex =
|
||||
// unFocus.reduce((prev, block) => Math.min(prev, block.zIndex), Infinity) - 1
|
||||
// if (minZIndex < 0) {
|
||||
// const dur = Math.abs(minZIndex)
|
||||
// unFocus.forEach((block) => (block.zIndex += dur))
|
||||
// minZIndex = 0
|
||||
// }
|
||||
// focus.forEach((block) => (block.zIndex = minZIndex))
|
||||
// return cloneDeep(dataModel.value.blocks)
|
||||
// })()
|
||||
// )
|
||||
// }
|
||||
// return {
|
||||
// redo: () => {
|
||||
// updateBlocks(cloneDeep(data.after))
|
||||
// },
|
||||
// undo: () => {
|
||||
// updateBlocks(cloneDeep(data.before))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.registry({
|
||||
// name: 'updateBlock',
|
||||
// execute: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) => {
|
||||
// let blocks = cloneDeep(dataModel.value.blocks || [])
|
||||
// const data = {
|
||||
// before: blocks,
|
||||
// after: (() => {
|
||||
// blocks = [...blocks]
|
||||
// const index = dataModel.value.blocks!.indexOf(oldBlock)
|
||||
// if (index > -1) {
|
||||
// blocks.splice(index, 1, newBlock)
|
||||
// }
|
||||
// return cloneDeep(blocks)
|
||||
// })()
|
||||
// }
|
||||
// return {
|
||||
// redo: () => {
|
||||
// updateBlocks(cloneDeep(data.after))
|
||||
// },
|
||||
// undo: () => {
|
||||
// updateBlocks(cloneDeep(data.before))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.registry({
|
||||
// name: 'updateModelValue',
|
||||
// execute: (val: VisualEditorModelValue) => {
|
||||
// const data = {
|
||||
// before: cloneDeep(dataModel.value),
|
||||
// after: cloneDeep(val)
|
||||
// }
|
||||
// return {
|
||||
// redo: () => {
|
||||
// dataModel.value = data.after
|
||||
// },
|
||||
// undo: () => {
|
||||
// dataModel.value = data.before
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.registry({
|
||||
// name: 'selectAll',
|
||||
// followQueue: false,
|
||||
// keyboard: 'ctrl+a',
|
||||
// execute: () => {
|
||||
// return {
|
||||
// redo: () => {
|
||||
// ;(dataModel.value.blocks || []).forEach((block) => (block.focus = true))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// commander.init()
|
||||
//
|
||||
// return {
|
||||
// undo: () => commander.state.commands.undo(),
|
||||
// redo: () => commander.state.commands.redo(),
|
||||
// delete: () => commander.state.commands.delete(),
|
||||
// clear: () => commander.state.commands.clear(),
|
||||
// placeTop: () => commander.state.commands.placeTop(),
|
||||
// placeBottom: () => commander.state.commands.placeBottom(),
|
||||
// updateBlock: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) =>
|
||||
// commander.state.commands.updateBlock(newBlock, oldBlock),
|
||||
// updateModelValue: (val: VisualEditorModelValue) =>
|
||||
// commander.state.commands.updateModelValue(val)
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue