增加各种config组件

main
一杯沧海 1 year ago
parent f9b032a194
commit b7d451b5fb
  1. 353
      src/App.vue
  2. 4
      src/engineer/components/Canvas.vue
  3. 62
      src/engineer/configs/BackgroundConfig.vue
  4. 32
      src/engineer/configs/BooleanConfig.vue
  5. 4
      src/engineer/configs/ListConfig.vue
  6. 34
      src/engineer/configs/MarkConfig.vue
  7. 35
      src/engineer/configs/ObjectConfig.vue
  8. 3
      src/engineer/configs/TextConfig.vue
  9. 8
      src/engineer/configs/render.ts
  10. 21
      src/engineer/context.ts
  11. 2
      src/engineer/types.ts

@ -5,102 +5,107 @@ import DddBuilder, { hash } from './engineer'
let nextId = Date.now() let nextId = Date.now()
const blocks = ref<Block[]>([{ const blocks = ref<Block[]>([
vid: hash(`${++nextId}`), // {
mid: '', // vid: hash(`${++nextId}`),
theme: { // mid: '',
radius: 24, // theme: {
color: 'yellow', // radius: 24,
}, // color: 'yellow',
children: { // },
type: 'text', // children: {
key: 'textName', // type: 'text',
}, // key: 'textName',
}, { // },
vid: hash(`${++nextId}`), // }, {
mid: '', // vid: hash(`${++nextId}`),
theme: { // mid: '',
color: 'pink', // theme: {
margin: 12, // color: 'pink',
flexible: true, // margin: 12,
}, // flexible: true,
children: { // },
type: 'image', // children: {
key: 'imageKey', // type: 'image',
link: 'linkKey', // key: 'imageKey',
radius: 24, // link: 'linkKey',
}, // radius: 24,
}, { // },
vid: hash(`${++nextId}`), // }, {
mid: '', // vid: hash(`${++nextId}`),
theme: { // mid: '',
color: '#fafbfc', // theme: {
margin: 12, // color: '#fafbfc',
padding: 24, // margin: 12,
mainAlign: 'center', // padding: 24,
crossAlign: 'center', // mainAlign: 'center',
flexible: true, // crossAlign: 'center',
}, // flexible: true,
children: { // },
type: 'audio', // children: {
key: 'audioKey', // type: 'audio',
title: 'title', // key: 'audioKey',
}, // title: 'title',
}, { // },
vid: hash(`${++nextId}`), // }, {
mid: '', // vid: hash(`${++nextId}`),
theme: { // mid: '',
radius: 24, // theme: {
color: 'teal', // radius: 24,
}, // color: 'teal',
children: [{ // },
theme: { // children: [{
flexible: true, // theme: {
gap: 12, // flexible: true,
crossAlign: 'center', // gap: 12,
}, // crossAlign: 'center',
children: [{ // },
theme: { // children: [{
padding: 12, // theme: {
margin: 12, // padding: 12,
grow: 1, // margin: 12,
}, // grow: 1,
children: { // },
vid: hash(`${++nextId}`), // children: {
theme: { // vid: hash(`${++nextId}`),
fontSize: 32, // theme: {
}, // fontSize: 32,
children: 'left', // },
}, // children: 'left',
}, { // },
vid: hash(`${++nextId}`), // }, {
theme: { // vid: hash(`${++nextId}`),
width: 'auto', // theme: {
padding: { // width: 'auto',
vertical: 4, // padding: {
horizontal: 12, // vertical: 4,
}, // horizontal: 12,
color: 'pink', // },
radius: 16, // color: 'pink',
}, // radius: 16,
children: 'right222', // },
}, { // children: 'right222',
theme: { // }, {
width: 48, // theme: {
}, // width: 48,
}], // },
}], // }
}, ...Array.from(Array.from({length: 3})).map<Block>((_, i) => ({ // ],
vid: hash(`${++nextId}`), // }
mid: '', // ],
children: [{ // }, ...Array.from(Array.from({length: 3})).map<Block>((_, i) => ({
vid: hash(`${++nextId}`), // vid: hash(`${++nextId}`),
theme: { // mid: '',
fontSize: 22, // children: [{
}, // vid: hash(`${++nextId}`),
children: `测试${i}`, // theme: {
}], // fontSize: 22,
}))]) // },
// children: `${i}`,
// }],
// }))
])
const categories = ref([{icon: 'trash', text: '媒体'}, {icon: 'trash', text: '图表'}, {icon: 'trash', text: '商品'}, {icon: 'trash', text: '功能'}, {icon: 'trash', text: '素材'}].map(c => ({ const categories = ref([{icon: 'trash', text: '媒体'}, {icon: 'trash', text: '图表'}, {icon: 'trash', text: '商品'}, {icon: 'trash', text: '功能'}, {icon: 'trash', text: '素材'}].map(c => ({
...c, ...c,
@ -134,66 +139,84 @@ categories.value.unshift({
maxReferenceCount: -1, maxReferenceCount: -1,
referenceCount: 0, referenceCount: 0,
image: undefined, image: undefined,
configs: [{ configs: [
type: 'list', {
field: 'items', type: 'list',
label: '', field: 'items',
help: '最多可添加10张图片,建议宽度750px;鼠标拖拽左侧圆点可调整图片顺序', label: '',
addable: true, help: '最多可添加10张图片,建议宽度750px;鼠标拖拽左侧圆点可调整图片顺序',
configs: [{ addable: true,
type: 'image', configs: [{
field: 'image', type: 'image',
// field: 'image',
inlines: [{ //
type: 'text', inlines: [{
field: 'title', type: 'text',
label: '标题', field: 'title',
help: '选填,不超过 4 个字', label: '标题',
}, { help: '选填,不超过 4 个字',
type: 'text', }, {
field: 'link', type: 'text',
label: '链接', field: 'link',
// help: '', // "${label}" label: '链接',
// help: '', // "${label}"
}],
label: '图片',
required: true,
}], }],
label: '图片', },
required: true, {
}], type: 'object',
}, { field: 'indicator',
type: 'object', label: '指示器',
field: 'indicator', configs: [{
label: '指示器', type: 'mark',
configs: [{ field: 'style',
type: 'mark', label: '指示器样式',
field: 'style', values: [{label: '圆形', value: 'circle'}, {label: '直线', value: 'line'}, {label: '数字', value: 'number'}],
label: '指示器样式', }, {
values: [{label: '圆形', value: 'circle'}, {label: '直线', value: 'line'}, {label: '数字', value: 'number'}], type: 'mark',
}, { field: 'position',
type: 'mark', label: '指示器位置',
field: 'position', values: [{label: '居左', value: 'left'}, {label: '居中', value: 'center'}, {label: '居右', value: 'right'}],
label: '指示器位置', },
values: [{label: '居左', value: 'left'}, {label: '居中', value: 'center'}, {label: '居右', value: 'right'}], {
}, { type: 'color',
type: 'color', field: 'color',
field: 'color', label: '指示器颜色',
label: '指示器颜色', }],
}], },
}, { {
type: 'object', type: 'object',
field: 'background', field: 'background',
label: '背景',
configs: [{
type: 'bool',
field: 'enabled',
label: '是否显示背景色',
}, {
type: 'background',
field: 'value',
// image
//
features: ['color', 'gradient'],
label: '背景', label: '背景',
configs: [{
type: 'boolean',
field: 'enabled',
label: '是否显示背景色',
}, {
type: 'background',
field: 'value',
// image
//
features: ['color', 'gradient'],
label: '背景',
}],
}], }],
}], init: {
items: [
{
image: '',
// title: '',
// link: '',
}
],
indicator: {
style: 'circle',
color: '#000000',
position: 'left',
}
},
theme: { theme: {
height: 200, height: 200,
padding: { padding: {
@ -210,7 +233,7 @@ categories.value.unshift({
radius: 12.0, radius: 12.0,
textAlign: 'center', textAlign: 'center',
}, },
children: '内容', children: '设置轮播图',
}], }],
}, },
{ {
@ -259,17 +282,17 @@ categories.value.unshift({
}) })
const data = ref<Record<string, Record<string, unknown>>>({ const data = ref<Record<string, Record<string, unknown>>>({
[blocks.value[0].vid]: { // [blocks.value[0].vid]: {
textName: '测试 2222', // textName: ' 2222',
}, // },
[blocks.value[1].vid]: { // [blocks.value[1].vid]: {
imageKey: 'https://www.w3schools.com/css/paris.jpg', // imageKey: 'https://www.w3schools.com/css/paris.jpg',
linkKey: 'https://docs.taro.zone/canIUse/', // linkKey: 'https://docs.taro.zone/canIUse/',
}, // },
[blocks.value[2].vid]: { // [blocks.value[2].vid]: {
audioKey: 'https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3', // audioKey: 'https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3',
title: '啊哈哈', // title: '',
}, // },
}) })
</script> </script>

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { useContext } from '../context' import { useContext, getModule } from '../context'
import { RenderBlock } from '../render' import { RenderBlock } from '../render'
import { DddView } from '../views' import { DddView } from '../views'
@ -68,10 +68,12 @@ function handleDragEnd(): void {
function handleDragAdd(e: DraggableEvent): void { function handleDragAdd(e: DraggableEvent): void {
const block = ctx.blocks[e.newDraggableIndex] const block = ctx.blocks[e.newDraggableIndex]
const module = getModule(ctx, block.mid)
ctx.activeViewId = block.vid ctx.activeViewId = block.vid
ctx.activeBlockId = block.vid ctx.activeBlockId = block.vid
ctx.hoverViewId = '#canvas' ctx.hoverViewId = '#canvas'
ctx.configurator = 'block' ctx.configurator = 'block'
ctx.sources[block.vid] = module.init ?? {}
key.value++ key.value++
} }

@ -0,0 +1,62 @@
<script lang="ts" setup>
import { computed } from "vue";
import { useSource } from "../context"
defineOptions({
name: "DddBackgroundConfig"
})
const props = defineProps<{
field: string
help?: string
features: string[]
label?: string
}>()
const tempString = useSource(props.field)
const typeList = computed(() => {
return props.features.map((item: any)=> {
return {
value: item,
label: formart(item)
}
})
})
function formart(str: string) {
const temp: Record<string, any> = {
color: '纯色',
gradient: '渐变',
}
return temp[str]
}
</script>
<template>
<div class="box">
<label>{{ label }}</label>
<div class="box-typeList">
<div v-for="(item,index) in typeList" :key="index" class="box-typeList-box">
<span>{{ item.label }}</span>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.box{
display: flex;
justify-content: space-between;
align-items: center;
&-typeList{
display: flex;
&-box{
display: flex;
color:#fff;
background-color: aqua;
width:50px;
height:20px;
font-size: 12px;
justify-content: center;
align-items: center;
}
}
}
</style>

@ -0,0 +1,32 @@
<script lang="ts" setup>
import { useSource } from '../context'
defineOptions({
name: "DddBooleanConfig"
})
const props = defineProps<{
field: string
label?: string
values?: any
}>()
const tempString = useSource<boolean>(props.field)
</script>
<template>
<div>
<label>
{{ label }}
</label>
<div>
<label></label>
<input type="radio" :value="true" v-model="tempString"><br>
<label></label>
<input type="radio" :value="false" v-model="tempString"><br>
</div>
</div>
</template>

@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ModuleConfig, useContext, useSource } from '..'; import { ModuleConfig, useSource } from '..';
import { setValue } from '../utils';
import { RenderConfig } from './render'; import { RenderConfig } from './render';
@ -20,6 +19,7 @@ const props = defineProps<{
const list = useSource<any[]>(props.field) const list = useSource<any[]>(props.field)
const add = () => { const add = () => {
const item = props.configs.reduce<any>((res, cfg) => { const item = props.configs.reduce<any>((res, cfg) => {
res[cfg.field] = undefined res[cfg.field] = undefined
return res return res

@ -0,0 +1,34 @@
<script lang="ts" setup>
import { useSource } from '../context'
defineOptions({
name: "DddMarkConfig"
})
const props = defineProps<{
field: string
label?: string
string?: string
values?: any
}>()
const tempString = useSource<string>(props.field)
function selectChange(e: any){
console.log(e.target.value)
}
</script>
<template>
<div>
<label>
{{ label }}
</label>
<div>
<select v-model="tempString" @change="selectChange">
<option value="none">不设置</option>
<option v-for="(opt,idx) in values" :key="idx" :value="opt.value">{{ opt.label }}</option>
</select>
</div>
</div>
</template>

@ -0,0 +1,35 @@
<script lang="ts" setup>
import { ModuleConfig } from "..";
import { useSource } from "../context"
import { RenderConfig } from './render';
defineOptions({
name: "DddObjectConfig"
})
defineProps<{
field: string
label?: string
help?: string
required?: boolean
configs: ModuleConfig[]
}>()
</script>
<template>
<div>
<label>
<span>{{ label }}设置</span>
</label>
<div v-for="(cfg, idx) in configs" :key="idx">
<RenderConfig
:type="cfg.type"
:props="{
...cfg,
field: `${field}.${cfg.field}`,
}"
/>
</div>
</div>
</template>

@ -7,14 +7,13 @@ defineOptions({
}) })
const props = defineProps<{ const props = defineProps<{
field: string // arr.0.text field: string
label: string label: string
help?: string help?: string
required?: boolean required?: boolean
}>() }>()
const data = useSource<string>(props.field) const data = useSource<string>(props.field)
// const text = ref<string>(data.value ?? '')
</script> </script>
<template> <template>

@ -2,10 +2,18 @@ import type { Component } from "vue";
import { defineComponent, h } from 'vue' import { defineComponent, h } from 'vue'
import TextConfig from './TextConfig.vue' import TextConfig from './TextConfig.vue'
import ListConfig from './ListConfig.vue' import ListConfig from './ListConfig.vue'
import ObjectConfig from './ObjectConfig.vue'
import MarkConfig from "./MarkConfig.vue";
import BooleanConfig from "./BooleanConfig.vue"
import BackgroundConfig from "./BackgroundConfig.vue";
const configs: Record<string, Component> = { const configs: Record<string, Component> = {
text: TextConfig, text: TextConfig,
list: ListConfig, list: ListConfig,
object: ObjectConfig,
mark: MarkConfig,
boolean: BooleanConfig,
background:BackgroundConfig,
} }
function render(type: string, props: Record<string, any>) { function render(type: string, props: Record<string, any>) {

@ -83,6 +83,17 @@ export function provideBlockId(id: string): void {
provide(blockIdKey, id) provide(blockIdKey, id)
} }
export function getModule(ctx: UnwrapNestedRefs<EngineContext>, mid: string): Module | undefined {
for (const category of ctx.categories) {
for (const module of category.modules) {
if (module.mid === mid) {
return module
}
}
}
return undefined
}
export function useModule() { export function useModule() {
const ctx = useContext() const ctx = useContext()
@ -91,14 +102,10 @@ export function useModule() {
if (block.vid !== ctx.activeBlockId) { if (block.vid !== ctx.activeBlockId) {
continue continue
} }
for (const category of ctx.categories) { const module = getModule(ctx, block.mid)
for (const module of category.modules) { if (module != null) {
if (module.mid === block.mid) { return module
return module
}
}
} }
break
} }
return undefined return undefined
}) })

@ -397,6 +397,8 @@ export interface Module extends Block {
referenceCount?: number referenceCount?: number
/** 模块配置 */ /** 模块配置 */
configs: ModuleConfig[] configs: ModuleConfig[]
/** 初始化数据 */
init?: Record<string, any>
} }
export type ModuleConfig = export type ModuleConfig =

Loading…
Cancel
Save