论坛,聊天室前后端对接

Change-Id: I90740329ab40dc050e8a791a382ab187900d673a
diff --git a/src/components/ReplyTree.vue b/src/components/ReplyTree.vue
new file mode 100644
index 0000000..17620b0
--- /dev/null
+++ b/src/components/ReplyTree.vue
@@ -0,0 +1,144 @@
+<template>
+  <div class="reply-tree">
+    <div
+      v-for="reply in replies"
+      :key="reply.id"
+      class="reply-item"
+      :class="{ 'nested-reply': level > 0 }"
+      :style="{ marginLeft: level * 24 + 'px' }"
+    >
+      <div class="reply-header">
+        <div class="reply-author">
+          <el-avatar :size="Math.max(32 - level * 2, 22)">
+            {{ reply.user?.username?.charAt(0) || 'A' }}
+          </el-avatar>
+          <span class="author-name">{{ reply.user?.username || '匿名' }}</span>
+        </div>
+        <div class="reply-meta">
+          <div class="reply-actions">
+            <el-button 
+              type="text" 
+              :size="level > 0 ? 'small' : 'default'" 
+              @click="$emit('reply', reply)"
+            >
+              回复
+            </el-button>
+            <template v-if="reply.isAuthor">
+              <el-button 
+                type="text" 
+                :size="level > 0 ? 'small' : 'default'" 
+                @click="$emit('edit', reply)"
+              >
+                编辑
+              </el-button>
+              <el-button 
+                type="text" 
+                :size="level > 0 ? 'small' : 'default'" 
+                @click="$emit('delete', reply.id)"
+              >
+                删除
+              </el-button>
+            </template>
+          </div>
+        </div>
+      </div>
+      <div class="reply-content" v-html="reply.content"></div>
+      
+      <!-- 递归显示子回复 -->
+      <ReplyTree
+        v-if="reply.replies?.length"
+        :replies="reply.replies"
+        :level="level + 1"
+        @reply="$emit('reply', $event)"
+        @edit="$emit('edit', $event)"
+        @delete="$emit('delete', $event)"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+
+
+export default {
+  name: 'ReplyTree',
+  props: {
+    replies: {
+      type: Array,
+      required: true
+    },
+    level: {
+      type: Number,
+      default: 0
+    }
+  },
+  emits: ['reply', 'edit', 'delete'],
+  setup() {
+
+
+    return {}
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.reply-tree {
+  .reply-item {
+    padding: 12px 0;
+    border-bottom: 1px solid #f0f0f0;
+    
+    &:last-child {
+      border-bottom: none;
+    }
+    
+    &.nested-reply {
+      border-left: 2px solid #e0e0e0;
+      padding-left: 12px;
+      margin-top: 8px;
+      
+      &:hover {
+        border-left-color: #3498db;
+      }
+    }
+    
+    .reply-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 8px;
+      
+      .reply-author {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        
+        .author-name {
+          font-weight: 500;
+          color: #2c3e50;
+          font-size: 14px;
+        }
+      }
+      
+      .reply-meta {
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        color: #7f8c8d;
+        font-size: 12px;
+        
+        .reply-actions {
+          display: flex;
+          gap: 6px;
+        }
+      }
+    }
+    
+    .reply-content {
+      font-size: 14px;
+      line-height: 1.6;
+      color: #2c3e50;
+      margin-bottom: 8px;
+    }
+  }
+}
+</style> 
\ No newline at end of file