7 changed files with 620 additions and 785 deletions
@ -1,138 +1,139 @@ |
|||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import lodash from "lodash"; |
import lodash from 'lodash' |
||||
import { computed, reactive } from "vue"; |
import { computed, reactive } from 'vue' |
||||
import { ElCollapse, ElCollapseItem } from "element-plus"; |
import { ElCollapse, ElCollapseItem } from 'element-plus' |
||||
import DataForm from "@/components/data-form/DataForm.vue"; |
import DataForm from '@/components/data-form/DataForm.vue' |
||||
import type { PropertyFlattenSetter, PropertySetterGroup } from "@/core/base/PropertyTypes.ts"; |
import type { PropertyFlattenSetter, PropertySetterGroup } from '@/core/base/PropertyTypes.ts' |
||||
import type { DataFormProps } from "@/components/data-form/DataFormTypes.ts"; |
import type { DataFormProps } from '@/components/data-form/DataFormTypes.ts' |
||||
import { defDataFormProps } from "@/editor/widgets/property/PropertyPanelConstant.ts"; |
import { defDataFormProps } from '@/editor/widgets/property/PropertyPanelConstant.ts' |
||||
import Viewport, { type ViewportState } from "@/core/engine/Viewport.ts"; |
import Viewport, { type ViewportState } from '@/core/engine/Viewport.ts' |
||||
|
|
||||
defineOptions({ |
defineOptions({ |
||||
name: 'PropertyPanel', |
name: 'PropertyPanel' |
||||
}); |
}) |
||||
|
|
||||
// 定义 Props 类型 |
// 定义 Props 类型 |
||||
interface PropertyPanelProps { |
interface PropertyPanelProps { |
||||
/** 待编辑数据 */ |
/** 待编辑数据 */ |
||||
data?: any; |
data?: any; |
||||
/** Viewport */ |
/** Viewport */ |
||||
viewport: Viewport; |
viewport: Viewport; |
||||
/** ViewportState */ |
/** ViewportState */ |
||||
viewportState: ViewportState; |
viewportState: ViewportState; |
||||
/** 默认的DataFormProps */ |
/** 默认的DataFormProps */ |
||||
defDataFormProps?: DataFormProps; |
defDataFormProps?: DataFormProps; |
||||
/** 最上面平铺的设置器 */ |
/** 最上面平铺的设置器 */ |
||||
flatten?: PropertyFlattenSetter; |
flatten?: PropertyFlattenSetter; |
||||
/** 设置器分组集合 */ |
/** 设置器分组集合 */ |
||||
groups?: Array<PropertySetterGroup>; |
groups?: Array<PropertySetterGroup>; |
||||
} |
} |
||||
|
|
||||
// 读取组件 props 属性 |
// 读取组件 props 属性 |
||||
const props = withDefaults(defineProps<PropertyPanelProps>(), {}); |
const props = withDefaults(defineProps<PropertyPanelProps>(), {}) |
||||
|
|
||||
// 定义 State 类型 |
// 定义 State 类型 |
||||
interface PropertyPanelState { |
interface PropertyPanelState { |
||||
/** 待编辑数据 */ |
/** 待编辑数据 */ |
||||
data?: any; |
data?: any; |
||||
/** 已展开的分组 */ |
/** 已展开的分组 */ |
||||
expandGroups: Array<string>; |
expandGroups: Array<string>; |
||||
} |
} |
||||
|
|
||||
// state 属性 |
// state 属性 |
||||
const state = reactive<PropertyPanelState>({ |
const state = reactive<PropertyPanelState>({ |
||||
data: lodash.cloneDeep(props.data), |
data: lodash.cloneDeep(props.data), |
||||
expandGroups: [], |
expandGroups: [] |
||||
}); |
}) |
||||
|
|
||||
// 定义 Data 类型 |
// 定义 Data 类型 |
||||
interface PropertyPanelData { |
interface PropertyPanelData { |
||||
} |
} |
||||
|
|
||||
// 内部数据 |
// 内部数据 |
||||
const data: PropertyPanelData = {}; |
const data: PropertyPanelData = {} |
||||
const flattenFormProps = computed(() => getDefFormProps(props.flatten)); |
const flattenFormProps = computed(() => getDefFormProps(props.flatten)) |
||||
|
|
||||
function getDefFormProps(setter?: PropertyFlattenSetter) { |
function getDefFormProps(setter?: PropertyFlattenSetter) { |
||||
const formProps: DataFormProps = { |
const formProps: DataFormProps = { |
||||
...defDataFormProps, |
...defDataFormProps, |
||||
...props.defDataFormProps, |
...props.defDataFormProps |
||||
}; |
} |
||||
fillFormProps(setter); |
fillFormProps(setter) |
||||
return formProps; |
return formProps |
||||
} |
} |
||||
|
|
||||
function fillFormProps(formProps: DataFormProps, setter?: PropertyFlattenSetter) { |
function fillFormProps(formProps: DataFormProps, setter?: PropertyFlattenSetter) { |
||||
if (!setter) return; |
if (!setter) return |
||||
if (setter.size) formProps.size = setter.size; |
if (setter.size) formProps.size = setter.size |
||||
if (setter.labelWidth) formProps.labelWidth = setter.labelWidth; |
if (setter.labelWidth) formProps.labelWidth = setter.labelWidth |
||||
} |
} |
||||
|
|
||||
function getCollapseItemId(group: PropertySetterGroup, idx: number) { |
function getCollapseItemId(group: PropertySetterGroup, idx: number) { |
||||
return `_${idx}_${group.title}`; |
return `_${idx}_${group.title}` |
||||
} |
} |
||||
|
|
||||
function onDataChange(newData: any) { |
function onDataChange(newData: any) { |
||||
const viewport = props.viewport; |
const viewport = props.viewport |
||||
if (!viewport) return; |
if (!viewport) return |
||||
const data = _.find(viewport.stateManager.vdata.items, item => item.id === props.data.id); |
viewport.stateManager.update(({ getEntity, putEntity }) => { |
||||
viewport.stateManager.beginStateUpdate(); |
const data = getEntity(props.data.id) |
||||
lodash.merge(data, newData); |
lodash.merge(data, newData) |
||||
console.log("onDataChange@1", JSON.stringify(data.tf)); |
putEntity(data) |
||||
viewport.stateManager.endStateUpdate(); |
console.log('onDataChange@1', JSON.stringify(data.tf)) |
||||
// data = _.find(viewport.stateManager.vdata.items, item => item.id === props.data.id); |
}) |
||||
// console.log("onDataChange#2", JSON.stringify(data.tf)); |
// data = _.find(viewport.stateManager.vdata.items, item => item.id === props.data.id); |
||||
|
// console.log("onDataChange#2", JSON.stringify(data.tf)); |
||||
} |
} |
||||
|
|
||||
interface PropertyPanelExpose { |
interface PropertyPanelExpose { |
||||
state: PropertyPanelState; |
state: PropertyPanelState; |
||||
data: PropertyPanelData; |
data: PropertyPanelData; |
||||
} |
} |
||||
|
|
||||
const expose: PropertyPanelExpose = { |
const expose: PropertyPanelExpose = { |
||||
state, |
state, |
||||
data, |
data |
||||
}; |
} |
||||
// 定义组件公开内容 |
// 定义组件公开内容 |
||||
defineExpose(expose); |
defineExpose(expose) |
||||
|
|
||||
export type { |
export type { |
||||
PropertyPanelProps, |
PropertyPanelProps, |
||||
PropertyPanelState, |
PropertyPanelState |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<template> |
<template> |
||||
<div class="property-panel"> |
<div class="property-panel"> |
||||
|
<DataForm |
||||
|
v-if="props.flatten" |
||||
|
class="property-panel-form" |
||||
|
v-bind="flattenFormProps" |
||||
|
:data="state.data" |
||||
|
:formFields="props.flatten.fields" |
||||
|
@dataChange="onDataChange" |
||||
|
/> |
||||
|
<ElCollapse v-if="props.groups" v-model="state.expandGroups"> |
||||
|
<ElCollapseItem |
||||
|
v-for="(group, idx) in props.groups" |
||||
|
:name="getCollapseItemId(group, idx)" |
||||
|
:title="group.title" |
||||
|
> |
||||
<DataForm |
<DataForm |
||||
v-if="props.flatten" |
v-if="group" |
||||
class="property-panel-form" |
class="property-panel-form" |
||||
v-bind="flattenFormProps" |
v-bind="getDefFormProps(group)" |
||||
:data="state.data" |
:data="state.data" |
||||
:formFields="props.flatten.fields" |
:formFields="props.flatten.fields" |
||||
@dataChange="onDataChange" |
@dataChange="onDataChange" |
||||
/> |
/> |
||||
<ElCollapse v-if="props.groups" v-model="state.expandGroups"> |
</ElCollapseItem> |
||||
<ElCollapseItem |
</ElCollapse> |
||||
v-for="(group, idx) in props.groups" |
</div> |
||||
:name="getCollapseItemId(group, idx)" |
|
||||
:title="group.title" |
|
||||
> |
|
||||
<DataForm |
|
||||
v-if="group" |
|
||||
class="property-panel-form" |
|
||||
v-bind="getDefFormProps(group)" |
|
||||
:data="state.data" |
|
||||
:formFields="props.flatten.fields" |
|
||||
@dataChange="onDataChange" |
|
||||
/> |
|
||||
</ElCollapseItem> |
|
||||
</ElCollapse> |
|
||||
</div> |
|
||||
</template> |
</template> |
||||
|
|
||||
<style scoped> |
<style scoped> |
||||
.property-panel { |
.property-panel { |
||||
padding: 8px 12px 16px 4px; |
padding: 8px 12px 16px 4px; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,166 +1,158 @@ |
|||||
<template> |
<template> |
||||
<div class="title"> |
<div class="title"> |
||||
<template v-if="!!t"> |
<template v-if="!!t"> |
||||
属性 |
属性 |
||||
<el-tag type="primary">{{ t }}</el-tag> |
<el-tag type="primary">{{ t }}</el-tag> |
||||
<el-input v-model="searchKeyword" size="small" style="width: 240px" placeholder="Search"> |
<el-input v-model="searchKeyword" size="small" style="width: 240px" placeholder="Search"> |
||||
<template #prefix> |
<template #prefix> |
||||
<component :is="renderIcon('element Search')"></component> |
<component :is="renderIcon('element Search')"></component> |
||||
</template> |
|
||||
</el-input> |
|
||||
<span class="close" @click="closeMe()"> |
|
||||
<component :is="renderIcon('element Close')"/> |
|
||||
</span> |
|
||||
</template> |
</template> |
||||
</div> |
</el-input> |
||||
<div class="calc-right-panel"> |
<span class="close" @click="closeMe()"> |
||||
<el-empty v-if="!t" description="未选中"/> |
<component :is="renderIcon('element Close')" /> |
||||
<PropertyPanel |
</span> |
||||
v-else-if="propertyPanelProps" |
</template> |
||||
v-bind="propertyPanelProps" |
</div> |
||||
/> |
<div class="calc-right-panel"> |
||||
<el-empty v-else description="节点未配置设置器"/> |
<el-empty v-if="!t" description="未选中" /> |
||||
</div> |
<PropertyPanel |
||||
|
v-else-if="propertyPanelProps" |
||||
|
v-bind="propertyPanelProps" |
||||
|
/> |
||||
|
<el-empty v-else description="节点未配置设置器" /> |
||||
|
</div> |
||||
</template> |
</template> |
||||
<script> |
<script> |
||||
import IWidgets from '../IWidgets.js' |
import IWidgets from '../IWidgets.js' |
||||
import PropertyPanel from "@/editor/widgets/property/PropertyPanel.vue"; |
import PropertyPanel from '@/editor/widgets/property/PropertyPanel.vue' |
||||
|
|
||||
export default { |
export default { |
||||
name: 'PropertyView', |
name: 'PropertyView', |
||||
components: { |
components: { |
||||
PropertyPanel, |
PropertyPanel |
||||
}, |
}, |
||||
mixins: [IWidgets], |
mixins: [IWidgets], |
||||
data() { |
data() { |
||||
return { |
return { |
||||
searchKeyword: '', |
searchKeyword: '', |
||||
propertySetter: undefined, |
propertySetter: undefined |
||||
} |
} |
||||
}, |
}, |
||||
computed: { |
computed: { |
||||
t() { |
t() { |
||||
return this.selectedItem ? this.selectedItem.t : '' |
return this.selectedItem ? this.selectedItem.t : '' |
||||
}, |
|
||||
selectedItem() { |
|
||||
return this.state?.selectedItem |
|
||||
}, |
|
||||
// selectedObject() { |
|
||||
// return this.state?.selectedObject |
|
||||
// }, |
|
||||
// selectedObjectSetter() { |
|
||||
// return this.state?.selectedObjectSetter |
|
||||
// }, |
|
||||
propertyPanelProps() { |
|
||||
const state = this.state; |
|
||||
if (!state) return; |
|
||||
const { selectedObjectSetter, selectedItem } = state; |
|
||||
if (!selectedObjectSetter || !selectedItem) return; |
|
||||
const data = _.find(this.viewport.stateManager.vdata.items, item => item.id === selectedItem.id); |
|
||||
if (!data) return; |
|
||||
return { |
|
||||
key: data.id, |
|
||||
data: data, |
|
||||
viewport: this.viewport, |
|
||||
viewportState: state, |
|
||||
flatten: selectedObjectSetter.flatten, |
|
||||
groups: selectedObjectSetter.groups, |
|
||||
}; |
|
||||
}, |
|
||||
}, |
|
||||
watch: { |
|
||||
// selectedItem(newV, oldV) { |
|
||||
// console.log("selectedItem", arguments) |
|
||||
// }, |
|
||||
// selectedObject(newV, oldV) { |
|
||||
// console.log("selectedObject", arguments) |
|
||||
// }, |
|
||||
}, |
|
||||
methods: { |
|
||||
selectedObjectChanged(state) { |
|
||||
const data = state.selectedItem |
|
||||
console.log('selectedObjectChanged data', data) |
|
||||
if (data) { |
|
||||
this.viewport.stateManager.beginStateUpdate() |
|
||||
const item = _.find(this.viewport.stateManager.vdata.items, item => item.id === data.id) |
|
||||
// item.tf[0][0] = item.tf[0][0] / 2; |
|
||||
console.log('selectedObjectChanged item', item) |
|
||||
// _.extend(item, data) |
|
||||
this.viewport.stateManager.endStateUpdate() |
|
||||
} |
|
||||
} |
|
||||
}, |
}, |
||||
mounted() { |
selectedItem() { |
||||
// EventBus.on('selectedObjectChanged', this.selectedObjectChanged) |
return this.state?.selectedItem |
||||
}, |
}, |
||||
unmounted() { |
// selectedObject() { |
||||
// EventBus.off('selectedObjectChanged', this.selectedObjectChanged) |
// return this.state?.selectedObject |
||||
|
// }, |
||||
|
// selectedObjectSetter() { |
||||
|
// return this.state?.selectedObjectSetter |
||||
|
// }, |
||||
|
propertyPanelProps() { |
||||
|
const state = this.state |
||||
|
if (!state) return |
||||
|
const { selectedObjectSetter, selectedItem } = state |
||||
|
if (!selectedObjectSetter || !selectedItem) return |
||||
|
const data = _.find(this.viewport.stateManager.vdata.items, item => item.id === selectedItem.id) |
||||
|
if (!data) return |
||||
|
return { |
||||
|
key: data.id, |
||||
|
data: data, |
||||
|
viewport: this.viewport, |
||||
|
viewportState: state, |
||||
|
flatten: selectedObjectSetter.flatten, |
||||
|
groups: selectedObjectSetter.groups |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
watch: { |
||||
|
// selectedItem(newV, oldV) { |
||||
|
// console.log("selectedItem", arguments) |
||||
|
// }, |
||||
|
// selectedObject(newV, oldV) { |
||||
|
// console.log("selectedObject", arguments) |
||||
|
// }, |
||||
|
}, |
||||
|
methods: { |
||||
|
selectedObjectChanged(state) { |
||||
|
const data = state.selectedItem |
||||
|
console.log('selectedObjectChanged data', data) |
||||
} |
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
// EventBus.on('selectedObjectChanged', this.selectedObjectChanged) |
||||
|
}, |
||||
|
unmounted() { |
||||
|
// EventBus.off('selectedObjectChanged', this.selectedObjectChanged) |
||||
|
} |
||||
} |
} |
||||
</script> |
</script> |
||||
<style lang="less"> |
<style lang="less"> |
||||
.property-panel-form { |
.property-panel-form { |
||||
margin: 0; |
margin: 0; |
||||
font-size: 14px; |
font-size: 14px; |
||||
color: #606266; |
color: #606266; |
||||
|
|
||||
.el-form-item--default { |
.el-form-item--default { |
||||
margin: 5px 3px 0 0; |
margin: 5px 3px 0 0; |
||||
|
|
||||
.el-form-item__label { |
.el-form-item__label { |
||||
height: 20px; |
height: 20px; |
||||
line-height: 22px; |
line-height: 22px; |
||||
} |
|
||||
} |
} |
||||
|
} |
||||
|
|
||||
.gui-toolbar { |
.gui-toolbar { |
||||
color: #333; |
color: #333; |
||||
background: #ffffff; |
background: #ffffff; |
||||
border-top: 1px solid #dcdcdc; |
border-top: 1px solid #dcdcdc; |
||||
margin-top: 5px; |
margin-top: 5px; |
||||
|
|
||||
.el-input-number.is-without-controls .el-input__wrapper { |
.el-input-number.is-without-controls .el-input__wrapper { |
||||
padding-left: 2px; |
padding-left: 2px; |
||||
padding-right: 2px; |
padding-right: 2px; |
||||
} |
} |
||||
|
|
||||
.gui-row { |
.gui-row { |
||||
display: flex; |
display: flex; |
||||
flex-direction: row; |
flex-direction: row; |
||||
gap: 3px; |
gap: 3px; |
||||
padding: 3px 3px 3px 0; |
padding: 3px 3px 3px 0; |
||||
|
|
||||
.gui-item-name { |
.gui-item-name { |
||||
width: 26px; |
width: 26px; |
||||
align-self: stretch; |
align-self: stretch; |
||||
display: flex; |
display: flex; |
||||
align-items: center; |
align-items: center; |
||||
justify-content: center; |
justify-content: center; |
||||
|
|
||||
.el-icon { |
.el-icon { |
||||
font-size: 16px; |
font-size: 16px; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
.gui-item { |
.gui-item { |
||||
flex: 1; |
flex: 1; |
||||
text-align: center; |
text-align: center; |
||||
font-size: 12px; |
font-size: 12px; |
||||
|
|
||||
.el-input-number { |
.el-input-number { |
||||
width: 100%; |
width: 100%; |
||||
|
|
||||
.el-input__wrapper { |
.el-input__wrapper { |
||||
background-color: #efefef; |
background-color: #efefef; |
||||
box-shadow: none; |
box-shadow: none; |
||||
} |
} |
||||
} |
|
||||
} |
|
||||
} |
} |
||||
|
} |
||||
} |
} |
||||
|
} |
||||
|
|
||||
.el-divider { |
.el-divider { |
||||
margin: 5px 0; |
margin: 5px 0; |
||||
} |
} |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
Loading…
Reference in new issue