wz-uniapp/pages/military/components/mind-map-node.vue

179 lines
3.2 KiB
Vue

<template>
<view class="mind-node-row">
<view class="node-card" :class="nodeClass" @click.stop="handleNodeClick">
<text class="node-title">{{ node.title }}</text>
<view v-if="isBranch" class="toggle-icon">{{ expanded ? '-' : '+' }}</view>
<uni-icons v-else type="forward" color="#5b6d86" :size="12" />
</view>
<view v-if="isBranch && expanded" class="children-shell">
<view class="main-link"></view>
<view class="children-list">
<view v-for="child in node.children" :key="child.id" class="child-row">
<mind-map-node :node="child" @open-detail="emitDetail" />
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'MindMapNode',
props: {
node: {
type: Object,
required: true
}
},
data() {
return {
expanded: false
};
},
watch: {
node: {
immediate: true,
handler(val) {
if (!val) {
return;
}
this.expanded = val.defaultExpanded === true;
}
}
},
computed: {
isBranch() {
return this.node.type === 'children' && Array.isArray(this.node.children) && this.node.children.length > 0;
},
nodeClass() {
if (this.node.type === 'children') {
return this.expanded ? 'branch expanded' : 'branch';
}
return 'leaf';
}
},
methods: {
handleNodeClick() {
if (this.node.type === 'detail') {
this.$emit('open-detail', this.node);
return;
}
if (!this.isBranch) {
return;
}
this.expanded = !this.expanded;
},
emitDetail(node) {
this.$emit('open-detail', node);
}
}
};
</script>
<style scoped>
.mind-node-row {
display: inline-flex;
align-items: center;
margin-bottom: 0;
}
.node-card {
min-width: 200rpx;
max-width: 320rpx;
padding: 16rpx 18rpx;
border-radius: 16rpx;
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 14rpx;
box-sizing: border-box;
transition: all 0.3s ease;
}
.node-title {
font-size: 24rpx;
line-height: 1.4;
}
.node-card.branch {
color: #ffffff;
background: linear-gradient(135deg, #58af6e 0%, #2d7f49 100%);
box-shadow: 0 6rpx 16rpx rgba(30, 97, 56, 0.25);
}
.node-card.branch.expanded {
background: linear-gradient(135deg, #3a98ee 0%, #2f6fcf 100%);
box-shadow: 0 8rpx 20rpx rgba(45, 111, 207, 0.28);
}
.node-card.leaf {
color: #334158;
background: #edf2fb;
border: 1px solid #d8e1f3;
}
.toggle-icon {
width: 28rpx;
height: 28rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.25);
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
font-weight: 600;
}
.children-shell {
display: inline-flex;
align-items: flex-start;
margin-left: 24rpx;
}
.main-link {
width: 28rpx;
height: 2rpx;
background: #8ab598;
margin-right: 8rpx;
flex-shrink: 0;
}
.children-list {
position: relative;
padding-left: 18rpx;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.children-list::before {
content: '';
position: absolute;
left: 0;
top: 10rpx;
bottom: 10rpx;
width: 2rpx;
background: #8ab598;
}
.child-row {
position: relative;
padding: 10rpx 0;
}
.child-row::before {
content: '';
position: absolute;
left: -18rpx;
top: 50%;
width: 18rpx;
height: 2rpx;
background: #8ab598;
}
.child-row:last-child {
padding-bottom: 0;
}
</style>