Compare commits

...

8 Commits

Author SHA1 Message Date
Tim
f4a15b3448 fix: router-link 2025-08-18 11:14:28 +08:00
Tim
239f1f8c84 Merge pull request #617 from CH-122/fix/mobile-invite-ui
fix: 优化邀请链接组件样式,增加文本换行支持;调整积分商城页面内边距
2025-08-18 10:55:40 +08:00
CH-122
ac303184c4 fix: 优化邀请链接组件样式,增加文本换行支持;调整积分商城页面内边距 2025-08-18 10:32:55 +08:00
Tim
7f16bbdb94 Merge pull request #607 from nagisa77/feature/coin_store
支持积分商城 & 邀请码
2025-08-18 02:20:59 +08:00
tim
f1c83b0f68 fix: 更新提示 2025-08-18 02:19:43 +08:00
tim
22c2b1564d feat: ui 优化+弹窗 2025-08-18 02:18:04 +08:00
tim
628d28c12d feat: 注册流程重构 2025-08-18 02:06:48 +08:00
Tim
2577992ee3 Merge pull request #613 from nagisa77/codex/implement-invitation-link-functionality
feat: add invite link generation and copy
2025-08-18 01:24:05 +08:00
12 changed files with 192 additions and 122 deletions

View File

@@ -48,12 +48,13 @@ public class AuthController {
}
if (req.getInviteToken() != null && !req.getInviteToken().isEmpty()) {
if (!inviteService.validate(req.getInviteToken())) {
return ResponseEntity.badRequest().body(Map.of("error", "Invalid invite token"));
return ResponseEntity.badRequest().body(Map.of("error", "邀请码使用次数过多"));
}
try {
User user = userService.registerWithInvite(
req.getUsername(), req.getEmail(), req.getPassword());
inviteService.consume(req.getInviteToken());
emailService.sendEmail(user.getEmail(), "在网站填写验证码以验证", "您的验证码是 " + user.getVerificationCode());
return ResponseEntity.ok(Map.of(
"token", jwtService.generateToken(user.getUsername()),
"reason_code", "INVITE_APPROVED"
@@ -78,10 +79,26 @@ public class AuthController {
public ResponseEntity<?> verify(@RequestBody VerifyRequest req) {
boolean ok = userService.verifyCode(req.getUsername(), req.getCode());
if (ok) {
return ResponseEntity.ok(Map.of(
"message", "Verified",
"token", jwtService.generateReasonToken(req.getUsername())
));
Optional<User> userOpt = userService.findByUsername(req.getUsername());
if (userOpt.isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Invalid credentials"));
}
User user = userOpt.get();
if (user.isApproved()) {
return ResponseEntity.ok(Map.of(
"message", "Verified and isApproved",
"reason_code", "VERIFIED_AND_APPROVED",
"token", jwtService.generateToken(req.getUsername())
));
} else {
return ResponseEntity.ok(Map.of(
"message", "Verified",
"reason_code", "VERIFIED",
"token", jwtService.generateReasonToken(req.getUsername())
));
}
}
return ResponseEntity.badRequest().body(Map.of("error", "Invalid verification code"));
}

View File

@@ -77,7 +77,7 @@ public class UserService {
public User registerWithInvite(String username, String email, String password) {
User user = register(username, email, password, "", com.openisle.model.RegisterMode.DIRECT);
user.setVerified(true);
user.setVerificationCode(null);
user.setVerificationCode(genCode());
return userRepository.save(user);
}

View File

@@ -16,11 +16,11 @@
<div class="info-content-header-left">
<span class="user-name">{{ comment.userName }}</span>
<i class="fas fa-medal medal-icon"></i>
<router-link
<NuxtLink
v-if="comment.medal"
class="medal-name"
:to="`/users/${comment.userId}?tab=achievements`"
>{{ getMedalTitle(comment.medal) }}</router-link
>{{ getMedalTitle(comment.medal) }}</NuxtLink
>
<i v-if="comment.pinned" class="fas fa-thumbtack pin-icon"></i>
<span v-if="level >= 2">

View File

@@ -8,6 +8,13 @@
/>
<NotificationSettingPopup :visible="showNotificationPopup" @close="closeNotificationPopup" />
<MedalPopup :visible="showMedalPopup" :medals="newMedals" @close="closeMedalPopup" />
<ActivityPopup
:visible="showInviteCodePopup"
:icon="inviteCodeIcon"
text="邀请码活动开始了,速来参与大伙们🔥🔥🔥"
@close="closeInviteCodePopup"
/>
</div>
</template>
@@ -21,7 +28,10 @@ const config = useRuntimeConfig()
const API_BASE_URL = config.public.apiBaseUrl
const showMilkTeaPopup = ref(false)
const showInviteCodePopup = ref(false)
const milkTeaIcon = ref('')
const inviteCodeIcon = ref('')
const showNotificationPopup = ref(false)
const showMedalPopup = ref(false)
const newMedals = ref([])
@@ -30,6 +40,9 @@ onMounted(async () => {
await checkMilkTeaActivity()
if (showMilkTeaPopup.value) return
await checkInviteCodeActivity()
if (showInviteCodePopup.value) return
await checkNotificationSetting()
if (showNotificationPopup.value) return
@@ -53,12 +66,38 @@ const checkMilkTeaActivity = async () => {
// ignore network errors
}
}
const checkInviteCodeActivity = async () => {
if (!process.client) return
if (localStorage.getItem('inviteCodeActivityPopupShown')) return
try {
const res = await fetch(`${API_BASE_URL}/api/activities`)
if (res.ok) {
const list = await res.json()
const a = list.find((i) => i.type === 'INVITE_POINTS' && !i.ended)
if (a) {
inviteCodeIcon.value = a.icon
showInviteCodePopup.value = true
}
}
} catch (e) {
// ignore network errors
}
}
const closeInviteCodePopup = () => {
if (!process.client) return
localStorage.setItem('inviteCodeActivityPopupShown', 'true')
showInviteCodePopup.value = false
}
const closeMilkTeaPopup = () => {
if (!process.client) return
localStorage.setItem('milkTeaActivityPopupShown', 'true')
showMilkTeaPopup.value = false
checkNotificationSetting()
}
const checkNotificationSetting = async () => {
if (!process.client) return
if (!authState.loggedIn) return

View File

@@ -6,16 +6,16 @@
<span class="invite-code-description-title-text">邀请规则说明</span>
</div>
<div class="invite-code-description-content">
<p>邀请好友注册并登录每次可以获得500积分</p>
<p>邀请好友注册并登录每次可以获得500积分🎉🎉🎉</p>
<p>邀请链接的有效期为1个月</p>
<p>每一个邀请链接的邀请人数上限为3人</p>
<p>通过邀请链接注册无需注册审核</p>
<p>每人每天仅能生产3个邀请链接</p>
<p>每人每天仅能生产1个邀请链接</p>
</div>
</div>
<div v-if="inviteLink" class="invite-code-link-content">
<p>
<p class="invite-code-link-content-text">
邀请链接{{ inviteLink }}
<span @click="copyLink"><i class="fas fa-copy copy-icon"></i></span>
</p>
@@ -48,9 +48,9 @@ onMounted(async () => {
isLoadingUser.value = true
user.value = await fetchCurrentUser()
isLoadingUser.value = false
if (user.value) {
await fetchInvite(false)
}
// if (user.value) {
// await fetchInvite(false)
// }
})
const fetchInvite = async (showToast = true) => {
@@ -171,6 +171,10 @@ const copyLink = async () => {
opacity: 0.8;
}
.invite-code-link-content-text {
word-break: break-all;
}
.copy-icon {
cursor: pointer;
margin-left: 5px;

View File

@@ -2,7 +2,7 @@
<div class="not-found-page">
<h1>404 - 页面不存在</h1>
<p>你访问的页面不存在或已被删除</p>
<router-link to="/">返回首页</router-link>
<NuxtLink to="/">返回首页</NuxtLink>
</div>
</template>

View File

@@ -145,7 +145,7 @@ onMounted(async () => {
}
.activity-card-normal-right {
width: calc(100% - 150px);
width: 100%;
}
@media screen and (max-width: 768px) {

View File

@@ -66,61 +66,61 @@
<span class="notif-type">
<template v-if="item.type === 'COMMENT_REPLY' && item.parentComment">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.comment.author.id}`"
>{{ item.comment.author.username }}
</router-link>
</NuxtLink>
对我的评论
<span>
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.parentComment.id}`"
>
{{ stripMarkdownLength(item.parentComment.content, 100) }}
</router-link>
</NuxtLink>
</span>
回复了
<span>
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</span>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'COMMENT_REPLY' && !item.parentComment">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.comment.author.id}`"
>{{ item.comment.author.username }}
</router-link>
</NuxtLink>
对我的文章
<span>
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
</span>
回复了
<span>
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</span>
</NotificationContainer>
</template>
@@ -140,310 +140,310 @@
<NotificationContainer :item="item" :markRead="markRead">
<span class="notif-user">{{ item.fromUser.username }} </span> 对我的文章
<span>
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
</span>
进行了表态
</NotificationContainer>
</template>
<template v-else-if="item.type === 'REACTION' && item.comment">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>{{ item.fromUser.username }}
</router-link>
</NuxtLink>
对我的评论
<span>
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</span>
进行了表态
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_VIEWED'">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
查看了您的帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'LOTTERY_WIN'">
<NotificationContainer :item="item" :markRead="markRead">
恭喜你在抽奖贴
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
中获奖
</NotificationContainer>
</template>
<template v-else-if="item.type === 'LOTTERY_DRAW'">
<NotificationContainer :item="item" :markRead="markRead">
您的抽奖贴
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
已开奖
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_UPDATED'">
<NotificationContainer :item="item" :markRead="markRead">
您关注的帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
下面有新评论
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'USER_ACTIVITY' && item.parentComment">
<NotificationContainer :item="item" :markRead="markRead">
你关注的
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.comment.author.id}`"
>
{{ item.comment.author.username }}
</router-link>
</NuxtLink>
对评论
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.parentComment.id}`"
>
{{ stripMarkdownLength(item.parentComment.content, 100) }}
</router-link>
</NuxtLink>
回复了
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'USER_ACTIVITY'">
<NotificationContainer :item="item" :markRead="markRead">
你关注的
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.comment.author.id}`"
>
{{ item.comment.author.username }}
</router-link>
</NuxtLink>
在文章
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
下面评论了
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'MENTION' && item.comment">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
在评论中提到了你
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
>
{{ stripMarkdownLength(item.comment.content, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'MENTION'">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
在帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
中提到了你
</NotificationContainer>
</template>
<template v-else-if="item.type === 'USER_FOLLOWED'">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
开始关注你了
</NotificationContainer>
</template>
<template v-else-if="item.type === 'USER_UNFOLLOWED'">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
取消关注你了
</NotificationContainer>
</template>
<template v-else-if="item.type === 'FOLLOWED_POST'">
<NotificationContainer :item="item" :markRead="markRead">
你关注的
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
发布了文章
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_SUBSCRIBED'">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
订阅了你的文章
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_UNSUBSCRIBED'">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
取消订阅了你的文章
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_REVIEW_REQUEST' && item.fromUser">
<NotificationContainer :item="item" :markRead="markRead">
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/users/${item.fromUser.id}`"
>
{{ item.fromUser.username }}
</router-link>
</NuxtLink>
发布了帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
请审核
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_REVIEW_REQUEST'">
<NotificationContainer :item="item" :markRead="markRead">
您发布的帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
已提交审核
</NotificationContainer>
</template>
@@ -472,26 +472,26 @@
<template v-else-if="item.type === 'POST_REVIEWED' && item.approved">
<NotificationContainer :item="item" :markRead="markRead">
您发布的帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
已审核通过
</NotificationContainer>
</template>
<template v-else-if="item.type === 'POST_REVIEWED' && item.approved === false">
<NotificationContainer :item="item" :markRead="markRead">
您发布的帖子
<router-link
<NuxtLink
class="notif-content-text"
@click="markRead(item.id)"
:to="`/posts/${item.post.id}`"
>
{{ stripMarkdownLength(item.post.title, 100) }}
</router-link>
</NuxtLink>
已被管理员拒绝
</NotificationContainer>
</template>

View File

@@ -63,6 +63,7 @@ const pointRules = [
'评论:每天前四条评论可获 10 积分,你的帖子被评论也可获 10 积分',
'帖子被点赞:每次 10 积分',
'评论被点赞:每次 10 积分',
'邀请好友加入可获得 500 积分/次,注意需要使用邀请链接注册',
]
const goods = ref([])
@@ -128,7 +129,7 @@ const submitRedeem = async () => {
<style scoped>
.point-mall-page {
padding-left: 20px;
padding: 0 20px;
max-width: var(--page-max-width);
background-color: var(--background-color);
margin: 0 auto;

View File

@@ -52,11 +52,11 @@
<div class="user-name">
{{ author.username }}
<i class="fas fa-medal medal-icon"></i>
<router-link
<NuxtLink
v-if="author.displayMedal"
class="user-medal"
:to="`/users/${author.id}?tab=achievements`"
>{{ getMedalTitle(author.displayMedal) }}</router-link
>{{ getMedalTitle(author.displayMedal) }}</NuxtLink
>
</div>
<div class="post-time">{{ postTime }}</div>
@@ -68,11 +68,11 @@
<div class="user-name">
{{ author.username }}
<i class="fas fa-medal medal-icon"></i>
<router-link
<NuxtLink
v-if="author.displayMedal"
class="user-medal"
:to="`/users/${author.id}?tab=achievements`"
>{{ getMedalTitle(author.displayMedal) }}</router-link
>{{ getMedalTitle(author.displayMedal) }}</NuxtLink
>
</div>
<div class="post-time">{{ postTime }}</div>

View File

@@ -96,6 +96,7 @@ import { discordAuthorize } from '~/utils/discord'
import { githubAuthorize } from '~/utils/github'
import { googleAuthorize } from '~/utils/google'
import { twitterAuthorize } from '~/utils/twitter'
import { loadCurrentUser, setToken } from '~/utils/auth'
const route = useRoute()
const config = useRuntimeConfig()
@@ -160,6 +161,7 @@ const sendVerification = async () => {
username: username.value,
email: email.value,
password: password.value,
inviteToken: inviteToken.value,
}),
})
isWaitingForEmailSent.value = false
@@ -192,11 +194,18 @@ const verifyCode = async () => {
})
const data = await res.json()
if (res.ok) {
if (registerMode.value === 'WHITELIST') {
navigateTo(`/signup-reason?token=${data.token}`, { replace: true })
} else {
toast.success('注册成功,请登录')
navigateTo('/login', { replace: true })
if (data.reason_code === 'VERIFIED_AND_APPROVED') {
toast.success('注册成功')
setToken(data.token)
loadCurrentUser()
navigateTo('/', { replace: true })
} else if (data.reason_code === 'VERIFIED') {
if (registerMode.value === 'WHITELIST') {
navigateTo(`/signup-reason?token=${data.token}`, { replace: true })
} else {
toast.success('注册成功,请登录')
navigateTo('/login', { replace: true })
}
}
} else {
toast.error(data.error || '注册失败')

View File

@@ -130,26 +130,26 @@
<BaseTimeline :items="hotReplies">
<template #item="{ item }">
<router-link :to="`/posts/${item.comment.post.id}`" class="timeline-link">
<NuxtLink :to="`/posts/${item.comment.post.id}`" class="timeline-link">
{{ item.comment.post.title }}
</router-link>
</NuxtLink>
<template v-if="item.comment.parentComment">
下对
<router-link
<NuxtLink
:to="`/posts/${item.comment.post.id}#comment-${item.comment.parentComment.id}`"
class="timeline-link"
>
{{ stripMarkdownLength(item.comment.parentComment.content, 200) }}
</router-link>
</NuxtLink>
回复了
</template>
<template v-else> 下评论了 </template>
<router-link
<NuxtLink
:to="`/posts/${item.comment.post.id}#comment-${item.comment.id}`"
class="timeline-link"
>
{{ stripMarkdownLength(item.comment.content, 200) }}
</router-link>
</NuxtLink>
<div class="timeline-date">
{{ formatDate(item.comment.createdAt) }}
</div>
@@ -165,9 +165,9 @@
<div class="summary-content" v-if="hotPosts.length > 0">
<BaseTimeline :items="hotPosts">
<template #item="{ item }">
<router-link :to="`/posts/${item.post.id}`" class="timeline-link">
<NuxtLink :to="`/posts/${item.post.id}`" class="timeline-link">
{{ item.post.title }}
</router-link>
</NuxtLink>
<div class="timeline-snippet">
{{ stripMarkdown(item.post.snippet) }}
</div>
@@ -236,44 +236,44 @@
<template #item="{ item }">
<template v-if="item.type === 'post'">
发布了文章
<router-link :to="`/posts/${item.post.id}`" class="timeline-link">
<NuxtLink :to="`/posts/${item.post.id}`" class="timeline-link">
{{ item.post.title }}
</router-link>
</NuxtLink>
<div class="timeline-date">{{ formatDate(item.createdAt) }}</div>
</template>
<template v-else-if="item.type === 'comment'">
<router-link :to="`/posts/${item.comment.post.id}`" class="timeline-link">
<NuxtLink :to="`/posts/${item.comment.post.id}`" class="timeline-link">
{{ item.comment.post.title }}
</router-link>
</NuxtLink>
下评论了
<router-link
<NuxtLink
:to="`/posts/${item.comment.post.id}#comment-${item.comment.id}`"
class="timeline-link"
>
{{ stripMarkdownLength(item.comment.content, 200) }}
</router-link>
</NuxtLink>
<div class="timeline-date">{{ formatDate(item.createdAt) }}</div>
</template>
<template v-else-if="item.type === 'reply'">
<router-link :to="`/posts/${item.comment.post.id}`" class="timeline-link">
<NuxtLink :to="`/posts/${item.comment.post.id}`" class="timeline-link">
{{ item.comment.post.title }}
</router-link>
</NuxtLink>
下对
<router-link
<NuxtLink
:to="`/posts/${item.comment.post.id}#comment-${item.comment.parentComment.id}`"
class="timeline-link"
>
{{ stripMarkdownLength(item.comment.parentComment.content, 200) }}
</router-link>
</NuxtLink>
回复了
<router-link
<NuxtLink
:to="`/posts/${item.comment.post.id}#comment-${item.comment.id}`"
class="timeline-link"
>
{{ stripMarkdownLength(item.comment.content, 200) }}
</router-link>
</NuxtLink>
<div class="timeline-date">{{ formatDate(item.createdAt) }}</div>
</template>
<template v-else-if="item.type === 'tag'">