美化pagetype详情页评论活动时间线

This commit is contained in:
jingrow 2026-04-23 00:43:43 +08:00
parent 40fd8e1ed3
commit 013f899f75

View File

@ -28,16 +28,6 @@
:disabled="submitting"
@keydown.enter.exact="handleAddComment"
/>
<n-button
size="small"
type="primary"
:disabled="!commentText.trim() || submitting"
:loading="submitting"
@click="handleAddComment"
class="comment-submit-btn"
>
{{ t('Send') }}
</n-button>
</div>
<!-- Timeline 列表 -->
@ -53,8 +43,8 @@
</div>
<div class="timeline-dot" v-else></div>
<div class="timeline-content" :class="{ 'is-card': item.isCard }">
<span v-html="item.content"></span>
<span v-if="!item.hideTimestamp" class="timeline-time">{{ relativeTime(item.creation) }}</span>
<div class="timeline-content-text" v-html="item.content"></div>
<div v-if="!item.hideTimestamp" class="timeline-time">{{ relativeTime(item.creation) }}</div>
</div>
</div>
</div>
@ -234,7 +224,9 @@ function buildTimelineItems() {
for (const a of info.attachment_logs || []) {
const isUpload = a.comment_type === 'Attachment'
const isSelf = a.owner === currentUser.value
const fileName = a.content || ''
const rawContent = a.content || ''
// content ""/"Added"
const fileName = rawContent.replace(/^(已移除|Added|Removed)\s*/i, '')
const uploadMsg = isSelf ? t('You attached {0}', [fileName]) : `<strong>${a.owner}</strong> ${t('attached {0}', [fileName])}`
const removeMsg = isSelf ? t('You removed attachment {0}', [fileName]) : `<strong>${a.owner}</strong> ${t('removed attachment {0}', [fileName])}`
items.push({
@ -382,45 +374,49 @@ watch(() => [props.entity, props.id], () => {
font-size: 12px;
}
/* Comment input */
/* Comment input - 无发送按钮Enter 发送 */
.comment-input-area {
display: flex;
gap: 8px;
margin-bottom: 16px;
align-items: flex-end;
}
.comment-input-area :deep(.n-input) {
flex: 1;
width: 100%;
}
.comment-submit-btn {
flex-shrink: 0;
}
/* Timeline */
/* ===== Timeline 时间线 - 现代风格 ===== */
.timeline-items {
display: flex;
flex-direction: column;
position: relative;
/* 时间线串联竖线 - 参考旧版 timeline.scss .new-timeline:before */
padding-left: 14px;
}
.timeline-items::before {
content: " ";
position: absolute;
left: 13px;
top: 0;
bottom: 0;
border-left: 2px solid #e5e7eb;
}
.timeline-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 8px 0;
padding: 6px 0;
position: relative;
/* 竖线通过每个 item 的伪元素实现,更精确控制起止 */
}
/* 时间线串联竖线 - 每个 item 左侧有一条竖线连接上下 */
.timeline-item::before {
content: "";
position: absolute;
left: 13px; /* 28px badge 中心 = 14px稍微偏移留出视觉间隙 */
top: 0;
bottom: 0;
width: 2px;
background: #e5e7eb;
}
/* 第一个 item竖线从图标中心开始 */
.timeline-item:first-child::before {
top: 20px; /* 从 badge 中心向下 */
}
/* 最后一个 item竖线到图标中心结束 */
.timeline-item:last-child::before {
bottom: calc(100% - 20px); /* 到 badge 中心向上 */
}
.timeline-badge {
@ -435,6 +431,8 @@ watch(() => [props.entity, props.id], () => {
color: #6b7280;
position: relative;
z-index: 1;
/* 微妙的阴影增加层次感 */
box-shadow: 0 0 0 2px #fff;
}
.timeline-dot {
@ -454,13 +452,20 @@ watch(() => [props.entity, props.id], () => {
height: 8px;
border-radius: 50%;
background: #d1d5db;
box-shadow: 0 0 0 2px #fff;
}
.timeline-content {
flex: 1;
font-size: 13px;
color: #374151;
line-height: 1.5;
line-height: 1.6;
padding: 2px 0;
min-width: 0;
}
.timeline-content-text {
display: inline;
}
.timeline-content.is-card {
@ -470,10 +475,22 @@ watch(() => [props.entity, props.id], () => {
padding: 10px 14px;
}
.timeline-content.is-card .timeline-content-text {
display: block;
margin-bottom: 4px;
}
.timeline-time {
color: #9ca3af;
font-size: 12px;
margin-left: 8px;
margin-top: 2px;
white-space: nowrap;
}
.timeline-content.is-card .timeline-time {
margin-top: 4px;
border-top: 1px solid #f3f4f6;
padding-top: 6px;
}
.timeline-empty {