mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-06-27 08:04:22 +00:00
Merge branch 'main' into main
This commit is contained in:
@@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<div class="home-page">
|
||||
<!-- <div v-if="!isMobile" class="search-container">
|
||||
<div class="search-title">一切可能,从此刻启航,在此遇见灵感与共鸣</div>
|
||||
<SearchDropdown />
|
||||
</div> -->
|
||||
|
||||
<div class="topic-container">
|
||||
<div class="topic-item-container">
|
||||
<div
|
||||
@@ -72,6 +67,7 @@
|
||||
<pin v-if="article.pinned" theme="outline" class="pinned-icon" />
|
||||
<gift v-if="article.type === 'LOTTERY'" class="lottery-icon" />
|
||||
<ranking-list v-else-if="article.type === 'POLL'" class="poll-icon" />
|
||||
<hands v-else-if="article.type === 'PROPOSAL'" class="proposal-icon" />
|
||||
<star v-if="!article.rssExcluded" class="featured-icon" />
|
||||
{{ article.title }}
|
||||
</NuxtLink>
|
||||
@@ -116,7 +112,7 @@
|
||||
</div>
|
||||
<div v-else class="placeholder-container">分类浏览功能开发中,敬请期待。</div>
|
||||
|
||||
<!-- ✅ 通用“底部加载更多”组件(自管 loading/observer/并发) -->
|
||||
<!-- 通用“底部加载更多”组件(自管 loading/observer/并发) -->
|
||||
<InfiniteLoadMore
|
||||
v-if="articles.length > 0"
|
||||
:key="ioKey"
|
||||
@@ -572,6 +568,7 @@ watch([selectedCategory, selectedTags], ([newCategory, newTags]) => {
|
||||
.pinned-icon,
|
||||
.lottery-icon,
|
||||
.featured-icon,
|
||||
.proposal-icon,
|
||||
.poll-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--primary-color);
|
||||
|
||||
@@ -75,7 +75,9 @@
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}#comment-${item.parentComment.id}`"
|
||||
>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.parentComment.content, 500)"></span>
|
||||
<span
|
||||
v-html="stripMarkdownWithTiebaMoji(item.parentComment.content, 500)"
|
||||
></span>
|
||||
</NuxtLink>
|
||||
</span>
|
||||
回复了
|
||||
@@ -85,7 +87,9 @@
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
|
||||
>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"></span>
|
||||
<span
|
||||
v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"
|
||||
></span>
|
||||
</NuxtLink>
|
||||
</span>
|
||||
</NotificationContainer>
|
||||
@@ -115,7 +119,9 @@
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
|
||||
>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"></span>
|
||||
<span
|
||||
v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"
|
||||
></span>
|
||||
</NuxtLink>
|
||||
</span>
|
||||
</NotificationContainer>
|
||||
@@ -162,7 +168,9 @@
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
|
||||
>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"></span>
|
||||
<span
|
||||
v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"
|
||||
></span>
|
||||
</NuxtLink>
|
||||
</span>
|
||||
进行了表态
|
||||
@@ -251,6 +259,38 @@
|
||||
已出结果
|
||||
</NotificationContainer>
|
||||
</template>
|
||||
<template v-else-if="item.type === 'CATEGORY_PROPOSAL_RESULT_OWNER'">
|
||||
<NotificationContainer :item="item" :markRead="markRead">
|
||||
你的分类提案
|
||||
<NuxtLink
|
||||
class="notif-content-text"
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}`"
|
||||
>
|
||||
{{ stripMarkdownLength(item.post.title, 100) }}
|
||||
</NuxtLink>
|
||||
<span v-if="item.approved">已通过</span>
|
||||
<span v-else>
|
||||
未通过<span v-if="item.content">,原因:{{ item.content }}</span>
|
||||
</span>
|
||||
</NotificationContainer>
|
||||
</template>
|
||||
<template v-else-if="item.type === 'CATEGORY_PROPOSAL_RESULT_PARTICIPANT'">
|
||||
<NotificationContainer :item="item" :markRead="markRead">
|
||||
你参与的分类提案
|
||||
<NuxtLink
|
||||
class="notif-content-text"
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}`"
|
||||
>
|
||||
{{ stripMarkdownLength(item.post.title, 100) }}
|
||||
</NuxtLink>
|
||||
<span v-if="item.approved">已通过</span>
|
||||
<span v-else>
|
||||
未通过<span v-if="item.content">,原因:{{ item.content }}</span>
|
||||
</span>
|
||||
</NotificationContainer>
|
||||
</template>
|
||||
<template v-else-if="item.type === 'POST_UPDATED'">
|
||||
<NotificationContainer :item="item" :markRead="markRead">
|
||||
您关注的帖子
|
||||
@@ -287,7 +327,9 @@
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}#comment-${item.parentComment.id}`"
|
||||
>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.parentComment.content, 500)"></span>
|
||||
<span
|
||||
v-html="stripMarkdownWithTiebaMoji(item.parentComment.content, 500)"
|
||||
></span>
|
||||
</NuxtLink>
|
||||
回复了
|
||||
<NuxtLink
|
||||
@@ -295,7 +337,7 @@
|
||||
@click="markRead(item.id)"
|
||||
:to="`/posts/${item.post.id}#comment-${item.comment.id}`"
|
||||
>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"></span>
|
||||
<span v-html="stripMarkdownWithTiebaMoji(item.comment.content, 500)"></span>
|
||||
</NuxtLink>
|
||||
</NotificationContainer>
|
||||
</template>
|
||||
@@ -775,6 +817,10 @@ const formatType = (t) => {
|
||||
return '发布的投票结果已公布'
|
||||
case 'POLL_RESULT_PARTICIPANT':
|
||||
return '参与的投票结果已公布'
|
||||
case 'CATEGORY_PROPOSAL_RESULT_OWNER':
|
||||
return '分类提案结果已公布'
|
||||
case 'CATEGORY_PROPOSAL_RESULT_PARTICIPANT':
|
||||
return '参与的分类提案结果已公布'
|
||||
default:
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
</div>
|
||||
<LotteryForm v-if="postType === 'LOTTERY'" :data="lottery" />
|
||||
<PollForm v-if="postType === 'POLL'" :data="poll" />
|
||||
<ProposalForm v-if="postType === 'PROPOSAL'" :data="proposal" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -51,6 +52,7 @@ import PostTypeSelect from '~/components/PostTypeSelect.vue'
|
||||
import TagSelect from '~/components/TagSelect.vue'
|
||||
import LotteryForm from '~/components/LotteryForm.vue'
|
||||
import PollForm from '~/components/PollForm.vue'
|
||||
import ProposalForm from '~/components/ProposalForm.vue'
|
||||
import { toast } from '~/main'
|
||||
import { authState, getToken } from '~/utils/auth'
|
||||
import PostVisibleScopeSelect from '~/components/PostVisibleScopeSelect.vue'
|
||||
@@ -79,6 +81,10 @@ const poll = reactive({
|
||||
endTime: null,
|
||||
multiple: false,
|
||||
})
|
||||
const proposal = reactive({
|
||||
proposedName: '',
|
||||
proposalDescription: '',
|
||||
})
|
||||
const startTime = ref(null)
|
||||
const isWaitingPosting = ref(false)
|
||||
const isAiLoading = ref(false)
|
||||
@@ -128,6 +134,8 @@ const clearPost = async () => {
|
||||
poll.options = ['', '']
|
||||
poll.endTime = null
|
||||
poll.multiple = false
|
||||
proposal.proposedName = ''
|
||||
proposal.proposalDescription = ''
|
||||
|
||||
// 删除草稿
|
||||
const token = getToken()
|
||||
@@ -289,6 +297,12 @@ const submitPost = async () => {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (postType.value === 'PROPOSAL') {
|
||||
if (!proposal.proposedName.trim()) {
|
||||
toast.error('请填写拟议分类名称')
|
||||
return
|
||||
}
|
||||
}
|
||||
try {
|
||||
const token = getToken()
|
||||
await ensureTags(token)
|
||||
@@ -309,37 +323,46 @@ const submitPost = async () => {
|
||||
}
|
||||
prizeIconUrl = uploadData.data.url
|
||||
}
|
||||
const toUtcString = (value) => {
|
||||
if (!value) return undefined
|
||||
return new Date(new Date(value).getTime() + 8.02 * 60 * 60 * 1000).toISOString()
|
||||
}
|
||||
|
||||
const payload = {
|
||||
title: title.value,
|
||||
content: content.value,
|
||||
categoryId: selectedCategory.value,
|
||||
tagIds: selectedTags.value,
|
||||
type: postType.value,
|
||||
postVisibleScopeType: postVisibleScope.value,
|
||||
}
|
||||
|
||||
if (postType.value === 'LOTTERY') {
|
||||
payload.prizeIcon = prizeIconUrl
|
||||
payload.prizeName = lottery.prizeName
|
||||
payload.prizeCount = lottery.prizeCount
|
||||
payload.prizeDescription = lottery.prizeDescription
|
||||
payload.pointCost = lottery.pointCost
|
||||
payload.startTime = startTime.value ? new Date(startTime.value).toISOString() : undefined
|
||||
payload.endTime = toUtcString(lottery.endTime)
|
||||
} else if (postType.value === 'POLL') {
|
||||
payload.options = poll.options
|
||||
payload.multiple = poll.multiple
|
||||
payload.endTime = toUtcString(poll.endTime)
|
||||
} else if (postType.value === 'PROPOSAL') {
|
||||
payload.proposedName = proposal.proposedName
|
||||
payload.proposalDescription = proposal.proposalDescription
|
||||
}
|
||||
|
||||
const res = await fetch(`${API_BASE_URL}/api/posts`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title.value,
|
||||
content: content.value,
|
||||
categoryId: selectedCategory.value,
|
||||
tagIds: selectedTags.value,
|
||||
postVisibleScopeType: postVisibleScope.value,
|
||||
type: postType.value,
|
||||
prizeIcon: postType.value === 'LOTTERY' ? prizeIconUrl : undefined,
|
||||
prizeName: postType.value === 'LOTTERY' ? lottery.prizeName : undefined,
|
||||
prizeCount: postType.value === 'LOTTERY' ? lottery.prizeCount : undefined,
|
||||
prizeDescription: postType.value === 'LOTTERY' ? lottery.prizeDescription : undefined,
|
||||
options: postType.value === 'POLL' ? poll.options : undefined,
|
||||
multiple: postType.value === 'POLL' ? poll.multiple : undefined,
|
||||
startTime:
|
||||
postType.value === 'LOTTERY' ? new Date(startTime.value).toISOString() : undefined,
|
||||
pointCost: postType.value === 'LOTTERY' ? lottery.pointCost : undefined,
|
||||
// 将时间转换为 UTC+8.5 时区 todo: 需要优化
|
||||
endTime:
|
||||
postType.value === 'LOTTERY'
|
||||
? new Date(new Date(lottery.endTime).getTime() + 8.02 * 60 * 60 * 1000).toISOString()
|
||||
: postType.value === 'POLL'
|
||||
? new Date(new Date(poll.endTime).getTime() + 8.02 * 60 * 60 * 1000).toISOString()
|
||||
: undefined,
|
||||
}),
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
if (res.ok) {
|
||||
if (data.reward && data.reward > 0) {
|
||||
|
||||
Reference in New Issue
Block a user