147 lines
2.8 KiB
Vue

<template>
<div
:class="[
'property-item',
hovered ? 'hovered' : '',
selected ? 'selected' : '',
]"
:title="propertyKey"
@click.stop="selectProperty"
@mouseover.stop="hovered = true"
@mouseout.stop="hovered = false"
>
<div class="property-header">
<div class="property-info">
<span class="property-name">{{ property.title || propertyKey }}</span>
<span class="property-type">{{ property.type }}</span>
</div>
<div class="property-actions" v-if="!store.readOnly">
<button class="btn btn-xs btn-outline-secondary" @click.stop="editProperty">
编辑
</button>
<button class="btn btn-xs btn-outline-danger" @click.stop="deleteProperty">
删除
</button>
</div>
</div>
<div class="property-details" v-if="selected">
<PropertyEditor
:property="property"
:property-key="propertyKey"
@update="updateProperty"
/>
</div>
</div>
</template>
<script setup>
import PropertyEditor from "./PropertyEditor.vue";
import { ref } from "vue";
import { useSchemaStore } from "../store";
const props = defineProps({
property: {
type: Object,
required: true
},
propertyKey: {
type: String,
required: true
},
selected: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['select', 'edit', 'delete']);
const store = useSchemaStore();
const hovered = ref(false);
function selectProperty() {
emit('select', props.propertyKey);
}
function editProperty() {
emit('edit', props.propertyKey);
}
function deleteProperty() {
emit('delete', props.propertyKey);
}
function updateProperty(updatedProperty) {
store.updateProperty(props.propertyKey, updatedProperty);
}
</script>
<style lang="scss" scoped>
.property-item {
background-color: var(--fg-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: 12px;
margin-bottom: 8px;
cursor: pointer;
transition: all 0.2s ease;
&:hover,
&.hovered {
border-color: var(--border-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
&.selected {
border-color: var(--border-primary);
background-color: var(--bg-light-gray);
}
.property-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
.property-info {
display: flex;
align-items: center;
gap: 8px;
.property-name {
font-weight: 600;
color: var(--text-color);
}
.property-type {
background-color: var(--bg-gray);
color: var(--text-muted);
padding: 2px 6px;
border-radius: var(--border-radius-sm);
font-size: var(--text-xs);
}
}
.property-actions {
display: flex;
gap: 4px;
opacity: 0;
transition: opacity 0.2s ease;
}
}
&:hover .property-actions,
&.selected .property-actions {
opacity: 1;
}
.property-details {
border-top: 1px solid var(--border-color);
padding-top: 12px;
margin-top: 8px;
}
}
</style>