mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-03-02 18:10:47 +08:00
Add post and tag review workflow
This commit is contained in:
@@ -4,16 +4,19 @@ import { reactive } from 'vue'
|
||||
const TOKEN_KEY = 'token'
|
||||
const USER_ID_KEY = 'userId'
|
||||
const USERNAME_KEY = 'username'
|
||||
const ROLE_KEY = 'role'
|
||||
|
||||
export const authState = reactive({
|
||||
loggedIn: false,
|
||||
userId: null,
|
||||
username: null
|
||||
username: null,
|
||||
role: null
|
||||
})
|
||||
|
||||
authState.loggedIn = localStorage.getItem(TOKEN_KEY) !== null && localStorage.getItem(TOKEN_KEY) !== ''
|
||||
authState.userId = localStorage.getItem(USER_ID_KEY)
|
||||
authState.username = localStorage.getItem(USERNAME_KEY)
|
||||
authState.role = localStorage.getItem(ROLE_KEY)
|
||||
|
||||
export function getToken() {
|
||||
return localStorage.getItem(TOKEN_KEY)
|
||||
@@ -33,6 +36,10 @@ export function clearToken() {
|
||||
export function setUserInfo({ id, username }) {
|
||||
authState.userId = id
|
||||
authState.username = username
|
||||
if (arguments[0] && arguments[0].role) {
|
||||
authState.role = arguments[0].role
|
||||
localStorage.setItem(ROLE_KEY, arguments[0].role)
|
||||
}
|
||||
if (id !== undefined && id !== null) localStorage.setItem(USER_ID_KEY, id)
|
||||
if (username) localStorage.setItem(USERNAME_KEY, username)
|
||||
}
|
||||
@@ -40,8 +47,10 @@ export function setUserInfo({ id, username }) {
|
||||
export function clearUserInfo() {
|
||||
localStorage.removeItem(USER_ID_KEY)
|
||||
localStorage.removeItem(USERNAME_KEY)
|
||||
localStorage.removeItem(ROLE_KEY)
|
||||
authState.userId = null
|
||||
authState.username = null
|
||||
authState.role = null
|
||||
}
|
||||
|
||||
export async function fetchCurrentUser() {
|
||||
@@ -61,7 +70,7 @@ export async function fetchCurrentUser() {
|
||||
export async function loadCurrentUser() {
|
||||
const user = await fetchCurrentUser()
|
||||
if (user) {
|
||||
setUserInfo({ id: user.id, username: user.username })
|
||||
setUserInfo({ id: user.id, username: user.username, role: user.role })
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ export default {
|
||||
POST_VIEWED: 'fas fa-eye',
|
||||
COMMENT_REPLY: 'fas fa-reply',
|
||||
POST_REVIEWED: 'fas fa-check',
|
||||
POST_REVIEW_REQUEST: 'fas fa-gavel',
|
||||
POST_UPDATED: 'fas fa-comment-dots',
|
||||
USER_ACTIVITY: 'fas fa-user',
|
||||
FOLLOWED_POST: 'fas fa-feather-alt',
|
||||
@@ -310,6 +311,18 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if (n.type === 'POST_REVIEW_REQUEST') {
|
||||
notifications.value.push({
|
||||
...n,
|
||||
src: n.fromUser ? n.fromUser.avatar : null,
|
||||
icon: n.fromUser ? undefined : iconMap[n.type],
|
||||
iconClick: () => {
|
||||
if (n.post) {
|
||||
markRead(n.id)
|
||||
router.push(`/posts/${n.post.id}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
notifications.value.push({
|
||||
...n,
|
||||
@@ -330,6 +343,8 @@ export default {
|
||||
return '有人回复了你'
|
||||
case 'REACTION':
|
||||
return '有人点赞'
|
||||
case 'POST_REVIEW_REQUEST':
|
||||
return '帖子待审核'
|
||||
case 'POST_REVIEWED':
|
||||
return '帖子审核结果'
|
||||
case 'POST_UPDATED':
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="article-title-container-right">
|
||||
<div class="article-pending-button">
|
||||
PENDING
|
||||
<div v-if="status === 'PENDING'" class="article-pending-button">
|
||||
审核中
|
||||
</div>
|
||||
<div class="article-block-button">
|
||||
REJECT
|
||||
<div v-if="status === 'REJECTED'" class="article-block-button">
|
||||
已拒绝
|
||||
</div>
|
||||
<div
|
||||
v-if="loggedIn && !isAuthor && !subscribed"
|
||||
@@ -35,7 +35,7 @@
|
||||
<i class="fas fa-user-minus"></i>
|
||||
取消订阅
|
||||
</div>
|
||||
<DropdownMenu :items="reviewMenuItems">
|
||||
<DropdownMenu v-if="isAdmin && status === 'PENDING'" :items="reviewMenuItems">
|
||||
<template #trigger>
|
||||
<i class="fas fa-ellipsis-vertical action-menu-icon"></i>
|
||||
</template>
|
||||
@@ -132,9 +132,10 @@ export default {
|
||||
const author = ref('')
|
||||
const postContent = ref('')
|
||||
const category = ref('')
|
||||
const tags = ref([])
|
||||
const postReactions = ref([])
|
||||
const comments = ref([])
|
||||
const tags = ref([])
|
||||
const postReactions = ref([])
|
||||
const comments = ref([])
|
||||
const status = ref('PUBLISHED')
|
||||
const isWaitingFetchingPost = ref(false);
|
||||
const isWaitingPostingComment = ref(false);
|
||||
const postTime = ref('')
|
||||
@@ -142,11 +143,12 @@ export default {
|
||||
const mainContainer = ref(null)
|
||||
const currentIndex = ref(1)
|
||||
const subscribed = ref(false)
|
||||
const loggedIn = computed(() => authState.loggedIn)
|
||||
const loggedIn = computed(() => authState.loggedIn)
|
||||
const isAdmin = computed(() => authState.role === 'ADMIN')
|
||||
const isAuthor = computed(() => authState.username === author.value.username)
|
||||
const reviewMenuItems = [
|
||||
{ text: '通过审核', onClick: () => {} },
|
||||
{ text: '驳回', color: 'red', onClick: () => {} }
|
||||
const reviewMenuItems = [
|
||||
{ text: '通过审核', onClick: () => approvePost() },
|
||||
{ text: '驳回', color: 'red', onClick: () => rejectPost() }
|
||||
]
|
||||
|
||||
const gatherPostItems = () => {
|
||||
@@ -226,6 +228,7 @@ export default {
|
||||
postReactions.value = data.reactions || []
|
||||
comments.value = (data.comments || []).map(mapComment)
|
||||
subscribed.value = !!data.subscribed
|
||||
status.value = data.status
|
||||
postTime.value = TimeManager.format(data.createdAt)
|
||||
await nextTick()
|
||||
gatherPostItems()
|
||||
@@ -329,12 +332,42 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
const unsubscribePost = async () => {
|
||||
const unsubscribePost = async () => {
|
||||
const token = getToken()
|
||||
if (!token) {
|
||||
toast.error('请先登录')
|
||||
return
|
||||
}
|
||||
|
||||
const approvePost = async () => {
|
||||
const token = getToken()
|
||||
if (!token) return
|
||||
const res = await fetch(`${API_BASE_URL}/api/admin/posts/${postId}/approve`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
if (res.ok) {
|
||||
status.value = 'PUBLISHED'
|
||||
toast.success('已通过审核')
|
||||
} else {
|
||||
toast.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
const rejectPost = async () => {
|
||||
const token = getToken()
|
||||
if (!token) return
|
||||
const res = await fetch(`${API_BASE_URL}/api/admin/posts/${postId}/reject`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
if (res.ok) {
|
||||
status.value = 'REJECTED'
|
||||
toast.success('已驳回')
|
||||
} else {
|
||||
toast.error('操作失败')
|
||||
}
|
||||
}
|
||||
const res = await fetch(`${API_BASE_URL}/api/subscriptions/posts/${postId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
@@ -403,7 +436,11 @@ export default {
|
||||
gotoProfile,
|
||||
subscribed,
|
||||
loggedIn,
|
||||
isAuthor
|
||||
isAuthor,
|
||||
status,
|
||||
isAdmin,
|
||||
approvePost,
|
||||
rejectPost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user