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