blob: 17620b02af3c468b2eba94bc14a7c298c3e66721 [file] [log] [blame]
208159515458d95702025-06-09 14:46:58 +08001<template>
2 <div class="reply-tree">
3 <div
4 v-for="reply in replies"
5 :key="reply.id"
6 class="reply-item"
7 :class="{ 'nested-reply': level > 0 }"
8 :style="{ marginLeft: level * 24 + 'px' }"
9 >
10 <div class="reply-header">
11 <div class="reply-author">
12 <el-avatar :size="Math.max(32 - level * 2, 22)">
13 {{ reply.user?.username?.charAt(0) || 'A' }}
14 </el-avatar>
15 <span class="author-name">{{ reply.user?.username || '匿名' }}</span>
16 </div>
17 <div class="reply-meta">
18 <div class="reply-actions">
19 <el-button
20 type="text"
21 :size="level > 0 ? 'small' : 'default'"
22 @click="$emit('reply', reply)"
23 >
24 回复
25 </el-button>
26 <template v-if="reply.isAuthor">
27 <el-button
28 type="text"
29 :size="level > 0 ? 'small' : 'default'"
30 @click="$emit('edit', reply)"
31 >
32 编辑
33 </el-button>
34 <el-button
35 type="text"
36 :size="level > 0 ? 'small' : 'default'"
37 @click="$emit('delete', reply.id)"
38 >
39 删除
40 </el-button>
41 </template>
42 </div>
43 </div>
44 </div>
45 <div class="reply-content" v-html="reply.content"></div>
46
47 <!-- 递归显示子回复 -->
48 <ReplyTree
49 v-if="reply.replies?.length"
50 :replies="reply.replies"
51 :level="level + 1"
52 @reply="$emit('reply', $event)"
53 @edit="$emit('edit', $event)"
54 @delete="$emit('delete', $event)"
55 />
56 </div>
57 </div>
58</template>
59
60<script>
61
62
63export default {
64 name: 'ReplyTree',
65 props: {
66 replies: {
67 type: Array,
68 required: true
69 },
70 level: {
71 type: Number,
72 default: 0
73 }
74 },
75 emits: ['reply', 'edit', 'delete'],
76 setup() {
77
78
79 return {}
80 }
81}
82</script>
83
84<style lang="scss" scoped>
85.reply-tree {
86 .reply-item {
87 padding: 12px 0;
88 border-bottom: 1px solid #f0f0f0;
89
90 &:last-child {
91 border-bottom: none;
92 }
93
94 &.nested-reply {
95 border-left: 2px solid #e0e0e0;
96 padding-left: 12px;
97 margin-top: 8px;
98
99 &:hover {
100 border-left-color: #3498db;
101 }
102 }
103
104 .reply-header {
105 display: flex;
106 justify-content: space-between;
107 align-items: center;
108 margin-bottom: 8px;
109
110 .reply-author {
111 display: flex;
112 align-items: center;
113 gap: 8px;
114
115 .author-name {
116 font-weight: 500;
117 color: #2c3e50;
118 font-size: 14px;
119 }
120 }
121
122 .reply-meta {
123 display: flex;
124 align-items: center;
125 gap: 12px;
126 color: #7f8c8d;
127 font-size: 12px;
128
129 .reply-actions {
130 display: flex;
131 gap: 6px;
132 }
133 }
134 }
135
136 .reply-content {
137 font-size: 14px;
138 line-height: 1.6;
139 color: #2c3e50;
140 margin-bottom: 8px;
141 }
142 }
143}
144</style>