增加积分系统

This commit is contained in:
WilliamColton
2025-08-07 16:29:14 +08:00
21 changed files with 464 additions and 178 deletions

View File

@@ -75,13 +75,11 @@ export default {
max-width: var(--page-max-width);
background-color: var(--background-color);
margin: 0 auto;
height: 100%;
overflow-y: auto;
}
.about-tabs {
position: sticky;
top: 1px;
top: calc(var(--header-height) + 1px);
z-index: 200;
background-color: var(--background-color-blur);
display: flex;

View File

@@ -433,7 +433,7 @@ export default {
.topic-container {
position: sticky;
top: 1px;
top: calc(var(--header-height) + 1px);
z-index: 10;
background-color: var(--background-color-blur);
display: flex;

View File

@@ -299,11 +299,12 @@ import BaseTimeline from '../components/BaseTimeline.vue'
import BasePlaceholder from '../components/BasePlaceholder.vue'
import NotificationContainer from '../components/NotificationContainer.vue'
import { getToken, authState } from '../utils/auth'
import { markNotificationsRead, fetchUnreadCount } from '../utils/notification'
import { markNotificationsRead, fetchUnreadCount, notificationState } from '../utils/notification'
import { toast } from '../main'
import { stripMarkdownLength } from '../utils/markdown'
import TimeManager from '../utils/time'
import { hatch } from 'ldrs'
import { reactionEmojiMap } from '../utils/reactions'
hatch.register()
export default {
@@ -322,28 +323,42 @@ export default {
const markRead = async id => {
if (!id) return
const n = notifications.value.find(n => n.id === id)
if (!n || n.read) return
n.read = true
if (notificationState.unreadCount > 0) notificationState.unreadCount--
const ok = await markNotificationsRead([id])
if (ok) {
const n = notifications.value.find(n => n.id === id)
if (n) n.read = true
await fetchUnreadCount()
if (!ok) {
n.read = false
notificationState.unreadCount++
} else {
fetchUnreadCount()
}
}
const markAllRead = async () => {
// 除了 REGISTER_REQUEST 类型消息
const idsToMark = notifications.value.filter(n => n.type !== 'REGISTER_REQUEST').map(n => n.id)
const idsToMark = notifications.value
.filter(n => n.type !== 'REGISTER_REQUEST' && !n.read)
.map(n => n.id)
if (idsToMark.length === 0) return
notifications.value.forEach(n => {
if (n.type !== 'REGISTER_REQUEST') n.read = true
})
notificationState.unreadCount = notifications.value.filter(n => !n.read).length
const ok = await markNotificationsRead(idsToMark)
if (ok) {
if (!ok) {
notifications.value.forEach(n => {
if (n.type !== 'REGISTER_REQUEST') n.read = true
if (idsToMark.includes(n.id)) n.read = false
})
await fetchUnreadCount()
if (authState.role === 'ADMIN') {
toast.success('已读所有消息(注册请求除外)')
} else {
toast.success('已读所有消息')
}
return
}
fetchUnreadCount()
if (authState.role === 'ADMIN') {
toast.success('已读所有消息(注册请求除外)')
} else {
toast.success('已读所有消息')
}
}
@@ -364,32 +379,6 @@ export default {
MENTION: 'fas fa-at'
}
const reactionEmojiMap = {
LIKE: '❤️',
DISLIKE: '👎',
RECOMMEND: '👏',
ANGRY: '😡',
FLUSHED: '😳',
STAR_STRUCK: '🤩',
ROFL: '🤣',
HOLDING_BACK_TEARS: '🥹',
MIND_BLOWN: '🤯',
POOP: '💩',
CLOWN: '🤡',
SKULL: '☠️',
FIRE: '🔥',
EYES: '👀',
FROWN: '☹️',
HOT: '🥵',
EAGLE: '🦅',
SPIDER: '🕷️',
BAT: '🦇',
CHINA: '🇨🇳',
USA: '🇺🇸',
JAPAN: '🇯🇵',
KOREA: '🇰🇷'
}
const fetchNotifications = async () => {
try {
const token = getToken()
@@ -628,6 +617,7 @@ export default {
.message-page {
background-color: var(--background-color);
overflow-x: hidden;
}
.message-page-header {
@@ -769,9 +759,5 @@ export default {
.has_read_button {
display: none;
}
.message-page {
overflow-x: hidden;
}
}
</style>

View File

@@ -3,8 +3,8 @@
<div class="new-post-form">
<input class="post-title-input" v-model="title" placeholder="标题"/>
<div class="post-editor-container">
<PostEditor v-model="content" :loading="isAiLoading" :disabled="!isLogin"/>
<LoginOverlay v-if="!isLogin"/>
<PostEditor v-model="content" v-model:loading="isAiLoading" :disabled="!isLogin" />
<LoginOverlay v-if="!isLogin" />
</div>
<div class="post-options">
<div class="post-options-left">
@@ -282,10 +282,8 @@ export default {
display: flex;
justify-content: center;
background-color: var(--background-color);
height: 100%;
padding-right: 20px;
padding-left: 20px;
overflow-y: auto;
}
.new-post-form {

View File

@@ -375,7 +375,7 @@ export default {
}
}
const postComment = async (text) => {
const postComment = async (text, clear) => {
if (!text.trim()) return
console.debug('Posting comment', {postId, text})
isWaitingPostingComment.value = true
@@ -396,6 +396,7 @@ export default {
const data = await res.json()
console.debug('Post comment response data', data)
await fetchComments()
clear()
const reward = Math.max(0, Number(data?.reward) || 0) // 经验值
const points = Math.max(0, Number(data?.pointReward) || 0) // 积分值

View File

@@ -497,9 +497,6 @@ export default {
.profile-page {
background-color: var(--background-color);
height: 100%;
overflow-y: auto;
overflow-x: hidden;
}
.profile-page-header {
@@ -639,7 +636,7 @@ export default {
.profile-tabs {
position: sticky;
top: 1px;
top: calc(var(--header-height) + 1px);
z-index: 200;
background-color: var(--background-color-blur);
display: flex;