pref: rebuild topic footer

This commit is contained in:
KUN1007 2023-10-06 19:50:09 +08:00
parent 69b964be7f
commit 1a48556048
10 changed files with 729 additions and 864 deletions

View file

@ -211,8 +211,10 @@ export default {
publish: 'Confirm to publish?', publish: 'Confirm to publish?',
publishSuccess: 'Publish Successfully', publishSuccess: 'Publish Successfully',
publishCancel: 'Cancel Publish', publishCancel: 'Cancel Publish',
upvote: upvoteTopic:
'Are you sure you want to upvote this topic? This will cost you 17 Moe Moe Points', 'Are you sure you want to upvote this topic? This will cost you 17 Moe Moe Points',
upvoteReply:
'Are you sure you want to upvote this reply? This will cost you 3 Moe Moe Points',
rewrite: 'Confirm to Rewrite?', rewrite: 'Confirm to Rewrite?',
rewriteSuccess: 'Rewrite Successfully', rewriteSuccess: 'Rewrite Successfully',
rewriteCancel: 'Cancel Rewrite', rewriteCancel: 'Cancel Rewrite',

View file

@ -210,7 +210,8 @@ export default {
publish: '确认发布吗?', publish: '确认发布吗?',
publishSuccess: '发布成功', publishSuccess: '发布成功',
publishCancel: '取消发布', publishCancel: '取消发布',
upvote: '您确定推这个话题吗,这将会消耗您 17 萌萌点', upvoteTopic: '您确定推这个话题吗,这将会消耗您 17 萌萌点',
upvoteReply: '您确定推这个回复吗,这将会消耗您 3 萌萌点',
rewrite: '确认 Rewrite 吗?', rewrite: '确认 Rewrite 吗?',
rewriteSuccess: 'Rewrite 成功', rewriteSuccess: 'Rewrite 成功',
rewriteCancel: '取消 Rewrite', rewriteCancel: '取消 Rewrite',

View file

@ -2,8 +2,8 @@
这是 KUNGalgame 话题展示区域楼主话题的区域楼主的话题将会被展示在这里位于话题展示区域最上方 这是 KUNGalgame 话题展示区域楼主话题的区域楼主的话题将会被展示在这里位于话题展示区域最上方
--> -->
<script setup lang="ts"> <script setup lang="ts">
// Footer // Footer
import MasterFooter from './MasterFooter.vue' import Footer from './footer/Footer.vue'
// //
import Rewrite from '../components/Rewrite.vue' import Rewrite from '../components/Rewrite.vue'
// //
@ -103,17 +103,22 @@ const loliStatus = computed(() => {
</div> </div>
</div> </div>
<!-- 话题的点赞数等信息被作用人就是该话题的发布人 --> <!-- 话题的点赞数等信息被作用人就是该话题的发布人 -->
<MasterFooter <Footer
:info="{ :info="{
tid, tid,
rid: 0,
views, views,
likes, likes,
dislikes, dislikes,
upvotes, upvotes,
share,
}" }"
:topic="{ tid, title, content, tags, category }" :content="{
:master="user" title,
content,
tags,
category,
}"
:to-uid="user.uid"
/> />
</div> </div>
</div> </div>

View file

@ -1,431 +0,0 @@
<!-- 话题的底部区域推话题回复点赞等 -->
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { Icon } from '@iconify/vue'
import { useRouter } from 'vue-router'
//
import { useKUNGalgameMessageStore } from '@/store/modules/message'
//
import message from '@/components/alert/Message'
// throttle
import { throttle } from '@/utils/throttle'
import { TopicUserInfo } from '@/api'
// store
import { useKUNGalgameEditStore } from '@/store/modules/edit'
// store
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
// store
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { storeToRefs } from 'pinia'
// 使 store
const { topicRewrite } = storeToRefs(useKUNGalgameEditStore())
// 使 store
const { isEdit, replyDraft } = storeToRefs(useKUNGalgameTopicStore())
// 使
const router = useRouter()
//
const props = defineProps<{
info: {
tid: number
views: number
likes: number[]
dislikes: number[]
upvotes: number[]
share: number[]
}
topic: {
tid: number
title: string
content: string
tags: string[]
category: string[]
}
master: TopicUserInfo
}>()
/**
* 这里只是简单起见不显示重新编辑
* 实际上如果用户自己修改了 localStorage 中保存的信息这个验证就失效了
* 但是修改了也没有用验证逻辑位于后端
*/
// uid
const currUserUid = useKUNGalgameUserStore().uid
// uid
const masterUid = props.master.uid
//
const isShowRewrite = currUserUid === masterUid
// footer
const actions = reactive({
upvotes: props.info.upvotes,
likes: props.info.likes,
dislikes: props.info.dislikes,
share: props.info.share,
})
//
const isActive = reactive({
isUpvote: false,
isLiked: false,
isDisliked: false,
isShared: false,
})
// throttle
const throttleCallback = () => {
message(
'You can only perform one operation within 1007 milliseconds',
'您在 1007 毫秒内只能进行一次操作',
'warn'
)
}
// throttle 1007
const handleClickLikeThrottled = throttle(
async () => {
//
if (currUserUid === masterUid) {
message(
'You cannot like your own topic',
'您不可以给自己的话题点赞',
'warn'
)
return
}
//
isActive.isLiked = !isActive.isLiked
const res = await useKUNGalgameTopicStore().updateTopicLike(
props.info.tid,
masterUid,
isActive.isLiked
)
if (res.code === 200) {
//
actions.likes.length = isActive.isLiked
? actions.likes.length + 1
: actions.likes.length - 1
} else {
message('Topic like failed!', '点赞话题失败', 'error')
}
},
1007,
throttleCallback
)
// throttle 1007
const handleClickDislikeThrottled = throttle(
async () => {
if (currUserUid === masterUid) {
message(
'You cannot dislike your own topic',
'您不可以给自己的话题点踩',
'warn'
)
return
}
isActive.isDisliked = !isActive.isDisliked
const res = await useKUNGalgameTopicStore().updateTopicDislike(
props.info.tid,
masterUid,
isActive.isDisliked
)
if (res.code === 200) {
//
actions.dislikes.length = isActive.isDisliked
? actions.dislikes.length + 1
: actions.dislikes.length - 1
} else {
message('Topic dislike failed!', '点踩话题失败', 'error')
}
},
1007,
throttleCallback
)
//
const handleClickUpvote = async () => {
//
if (currUserUid === masterUid) {
message('You cannot upvote your own topic', '您不可以推自己的话题', 'warn')
return
}
// TODO:
// if (useKUNGalgameUserStore().moemoepoint < 1100) {
// message(
// 'Your Moe Moe Points are less than 1100, and you cannot use the upvote feature',
// ' 1100使',
// 'warn'
// )
// return
// }
//
const res = await useKUNGalgameMessageStore().alert(
'AlertInfo.edit.upvote',
true
)
//
if (res) {
//
const res = await useKUNGalgameTopicStore().updateTopicUpvote(
props.info.tid,
masterUid
)
if (res.code === 200) {
//
actions.upvotes.length++
message('Topic upvote successfully', '推话题成功', 'success')
} else {
message('Topic upvote failed!', '推话题失败', 'error')
}
}
}
//
const handleClickLike = () => {
handleClickLikeThrottled()
}
//
const handleClickDislike = () => {
handleClickDislikeThrottled()
}
//
const handleClickReply = async () => {
// 便
replyDraft.value.tid = props.info.tid
// uid
replyDraft.value.to_uid = masterUid
// floor 0
replyDraft.value.to_floor = 0
//
isEdit.value = true
}
//
const handleClickRewrite = () => {
//
topicRewrite.value.tid = props.topic.tid
topicRewrite.value.title = props.topic.title
topicRewrite.value.content = props.topic.content
topicRewrite.value.tags = props.topic.tags
topicRewrite.value.category = props.topic.category
//
topicRewrite.value.isTopicRewriting = true
//
router.push({ name: 'Edit' })
}
//
onMounted(() => {
//
if (props.info.upvotes.includes(currUserUid)) {
isActive.isUpvote = true
}
//
if (props.info.likes.includes(currUserUid)) {
isActive.isLiked = true
}
//
if (props.info.dislikes.includes(currUserUid)) {
isActive.isDisliked = true
}
//
if (props.info.share.includes(currUserUid)) {
isActive.isShared = true
}
})
</script>
<template>
<!-- 楼主话题底部 -->
<div class="footer">
<!-- 底部左侧部分点赞推话题 -->
<div class="left">
<ul>
<!-- 推话题 -->
<li>
<span
class="icon"
:class="isActive.isUpvote ? 'active' : ''"
@click="handleClickUpvote"
>
<Icon icon="bi:rocket" />
</span>
{{ actions.upvotes.length }}
</li>
<!-- 查看数量 -->
<li>
<span class="icon"><Icon icon="ic:outline-remove-red-eye" /></span>
{{ info.views }}
</li>
<!-- 点赞 -->
<li>
<span
class="icon"
:class="isActive.isLiked ? 'active' : ''"
@click="handleClickLike"
>
<Icon icon="line-md:thumbs-up-twotone" />
</span>
{{ actions.likes.length }}
</li>
<!-- -->
<li>
<span
class="icon"
:class="isActive.isDisliked ? 'active' : ''"
@click="handleClickDislike"
>
<Icon icon="line-md:thumbs-down-twotone" />
</span>
{{ actions.dislikes.length }}
</li>
</ul>
</div>
<!-- 底部右侧部分回复评论只看编辑 -->
<div class="right">
<div @click="handleClickReply" class="reply">
{{ $tm('topic.content.reply') }}
</div>
<!-- 分享 -->
<span class="icon"><Icon icon="majesticons:share-line" /></span>
<!-- 只看 -->
<span class="icon"><Icon icon="ph:user-focus-duotone" /></span>
<!-- 编辑 -->
<span v-if="isShowRewrite" @click="handleClickRewrite" class="icon">
<Icon icon="line-md:pencil-twotone-alt" />
</span>
</div>
</div>
</template>
<style lang="scss" scoped>
/* 楼主话题底部 */
.footer {
padding: 10px 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 底部左侧部分(点赞、推话题、踩) */
.left ul {
display: flex;
justify-content: center;
align-items: center;
color: var(--kungalgame-font-color-3);
li {
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin: 17px;
margin-right: 0;
span {
display: flex;
margin-right: 3px;
}
&:nth-child(1) span {
color: var(--kungalgame-red-4);
}
}
}
/* 图标字体的样式 */
.icon {
font-size: 24px;
color: var(--kungalgame-font-color-2);
cursor: pointer;
}
/* 底部右侧部分(回复、评论、只看、编辑) */
.right {
display: flex;
justify-content: center;
align-items: center;
span {
display: flex;
margin-right: 17px;
}
}
.reply {
position: relative;
width: 70px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: var(--kungalgame-blue-4);
cursor: pointer;
transition: all 0.2s;
&::before,
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
top: 0;
left: 0;
box-sizing: border-box;
border: 2px solid transparent;
}
&:hover {
color: var(--kungalgame-pink-4);
&::before {
transition: width 0.2s, height 0.2s, border-bottom-color 0s;
transition-delay: 0.2s, 0s, 0.2s;
width: 70px;
height: 30px;
border-left: 2px solid var(--kungalgame-pink-4);
border-bottom: 2px solid var(--kungalgame-pink-4);
}
&::after {
transition: width 0.2s, height 0.2s, border-right-color 0.2s;
transition-delay: 0s, 0.2s, 0.2s;
width: 70px;
height: 30px;
border-top: 2px solid var(--kungalgame-pink-4);
border-right: 2px solid var(--kungalgame-pink-4);
}
}
}
/* 激活后的样式 */
.active {
color: var(--kungalgame-blue-4);
}
@media (max-width: 700px) {
.footer {
flex-direction: column;
}
}
</style>

View file

@ -0,0 +1,147 @@
<!-- 话题的底部区域推话题回复点赞等 -->
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { Icon } from '@iconify/vue'
//
import message from '@/components/alert/Message'
// throttle
import { throttle } from '@/utils/throttle'
// store
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
//
const props = defineProps<{
uid: number
tid: number
rid: number
dislikes: number[]
toUid: number
}>()
const dislikesArray = ref(props.dislikes)
const isDisliked = ref(false)
// throttle
const throttleCallback = () => {
message(
'You can only perform one operation within 1007 milliseconds',
'您在 1007 毫秒内只能进行一次操作',
'warn'
)
}
//
const dislikeOperation = async (
tid: number,
rid: number,
toUid: number,
isPush: boolean
) => {
// rid
const isMasterTopic = rid === 0
if (isMasterTopic) {
return await useKUNGalgameTopicStore().updateTopicDislike(
tid,
toUid,
isPush
)
} else {
return await useKUNGalgameTopicStore().updateReplyDislike(
tid,
toUid,
rid,
isPush
)
}
}
// throttle 1007
const handleClickDislikeThrottled = throttle(
async () => {
//
if (props.uid === props.toUid) {
message('You cannot dislike yourself', '您不可以给自己点踩', 'warn')
return
}
//
isDisliked.value = !isDisliked.value
const res = await dislikeOperation(
props.tid,
props.rid,
props.toUid,
isDisliked.value
)
if (res.code === 200) {
//
dislikesArray.value.length = isDisliked.value
? dislikesArray.value.length + 1
: dislikesArray.value.length - 1
} else {
message('Dislike failed!', '点踩失败', 'error')
}
},
1007,
throttleCallback
)
//
const handleClickDislike = () => {
handleClickDislikeThrottled()
}
//
onMounted(() => {
//
if (props.dislikes.includes(props.uid)) {
isDisliked.value = true
}
})
</script>
<template>
<!-- -->
<li>
<span
class="icon"
:class="isDisliked ? 'active' : ''"
@click="handleClickDislike"
>
<Icon icon="line-md:thumbs-down-twotone" />
</span>
{{ dislikes.length }}
</li>
</template>
<style lang="scss" scoped>
li {
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin: 17px;
margin-right: 0;
span {
display: flex;
margin-right: 3px;
}
&:nth-child(1) span {
color: var(--kungalgame-red-4);
}
}
/* 图标字体的样式 */
.icon {
font-size: 24px;
color: var(--kungalgame-font-color-2);
cursor: pointer;
}
/* 激活后的样式 */
.active {
color: var(--kungalgame-blue-4);
}
</style>

View file

@ -0,0 +1,263 @@
<!-- 话题的底部区域推话题回复点赞等 -->
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { useRouter } from 'vue-router'
//
import Upvote from './Upvote.vue'
//
import Like from './Like.vue'
//
import Dislike from './Dislike.vue'
// store
import { useKUNGalgameEditStore } from '@/store/modules/edit'
// store
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
// store
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { storeToRefs } from 'pinia'
// 使 store
const { topicRewrite } = storeToRefs(useKUNGalgameEditStore())
// 使 store
const { isEdit, replyDraft } = storeToRefs(useKUNGalgameTopicStore())
// 使
const router = useRouter()
//
const props = defineProps<{
info: {
tid: number
rid: number
views: number
likes: number[]
dislikes: number[]
upvotes: number[]
}
content: {
title: string
content: string
tags: string[]
category: string[]
}
toUid: number
}>()
/**
* 这里只是简单起见不显示重新编辑
* 实际上如果用户自己修改了 localStorage 中保存的信息这个验证就失效了
* 但是修改了也没有用验证逻辑位于后端
*/
// uid
const currUserUid = useKUNGalgameUserStore().uid
// / uid
const masterUid = props.toUid
//
const isShowRewrite = currUserUid === masterUid
//
const handleClickReply = async () => {
// 便
replyDraft.value.tid = props.info.tid
// uid
replyDraft.value.to_uid = masterUid
// floor 0
replyDraft.value.to_floor = 0
//
isEdit.value = true
}
//
const handleClickRewrite = () => {
//
topicRewrite.value.tid = props.info.tid
topicRewrite.value.title = props.content.title
topicRewrite.value.content = props.content.content
topicRewrite.value.tags = props.content.tags
topicRewrite.value.category = props.content.category
//
topicRewrite.value.isTopicRewriting = true
//
router.push({ name: 'Edit' })
}
</script>
<template>
<!-- 楼主话题底部 -->
<div class="footer">
<!-- 底部左侧部分点赞推话题 -->
<div class="left">
<ul>
<!-- 推话题 -->
<Upvote
:uid="currUserUid"
:tid="props.info.tid"
:rid="props.info.rid"
:upvotes="props.info.upvotes"
:to-uid="masterUid"
/>
<!-- 浏览数 -->
<li>
<span class="icon"><Icon icon="ic:outline-remove-red-eye" /></span>
{{ info.views }}
</li>
<!-- 点赞 -->
<Like
:uid="currUserUid"
:tid="props.info.tid"
:rid="props.info.rid"
:likes="props.info.likes"
:to-uid="masterUid"
/>
<!-- -->
<Dislike
:uid="currUserUid"
:tid="props.info.tid"
:rid="props.info.rid"
:dislikes="props.info.dislikes"
:to-uid="masterUid"
/>
</ul>
</div>
<!-- 底部右侧部分回复评论只看编辑 -->
<div class="right">
<div @click="handleClickReply" class="reply">
{{ $tm('topic.content.reply') }}
</div>
<!-- 分享 -->
<span class="icon"><Icon icon="majesticons:share-line" /></span>
<!-- 只看 -->
<span class="icon"><Icon icon="ph:user-focus-duotone" /></span>
<!-- 编辑 -->
<span v-if="isShowRewrite" @click="handleClickRewrite" class="icon">
<Icon icon="line-md:pencil-twotone-alt" />
</span>
<!-- 回复的插槽 -->
<span>
<slot name="comment"></slot>
</span>
</div>
</div>
</template>
<style lang="scss" scoped>
/* 楼主话题底部 */
.footer {
padding: 10px 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 底部左侧部分(点赞、推话题、踩) */
.left ul {
display: flex;
justify-content: center;
align-items: center;
color: var(--kungalgame-font-color-3);
li {
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin: 17px;
margin-right: 0;
span {
display: flex;
margin-right: 3px;
}
&:nth-child(1) span {
color: var(--kungalgame-red-4);
}
}
}
/* 图标字体的样式 */
.icon {
font-size: 24px;
color: var(--kungalgame-font-color-2);
cursor: pointer;
}
/* 底部右侧部分(回复、评论、只看、编辑) */
.right {
display: flex;
justify-content: center;
align-items: center;
span {
display: flex;
margin-right: 17px;
}
}
.reply {
position: relative;
width: 70px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: var(--kungalgame-blue-4);
cursor: pointer;
transition: all 0.2s;
&::before,
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
top: 0;
left: 0;
box-sizing: border-box;
border: 2px solid transparent;
}
&:hover {
color: var(--kungalgame-pink-4);
&::before {
transition: width 0.2s, height 0.2s, border-bottom-color 0s;
transition-delay: 0.2s, 0s, 0.2s;
width: 70px;
height: 30px;
border-left: 2px solid var(--kungalgame-pink-4);
border-bottom: 2px solid var(--kungalgame-pink-4);
}
&::after {
transition: width 0.2s, height 0.2s, border-right-color 0.2s;
transition-delay: 0s, 0.2s, 0.2s;
width: 70px;
height: 30px;
border-top: 2px solid var(--kungalgame-pink-4);
border-right: 2px solid var(--kungalgame-pink-4);
}
}
}
/* 激活后的样式 */
.active {
color: var(--kungalgame-blue-4);
}
@media (max-width: 700px) {
.footer {
flex-direction: column;
}
.right {
span:last-child {
margin-right: 0;
}
}
}
</style>

View file

@ -0,0 +1,143 @@
<!-- 话题的底部区域推话题回复点赞等 -->
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { Icon } from '@iconify/vue'
//
import message from '@/components/alert/Message'
// throttle
import { throttle } from '@/utils/throttle'
// store
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
//
const props = defineProps<{
uid: number
tid: number
rid: number
likes: number[]
toUid: number
}>()
const likesArray = ref(props.likes)
const isLiked = ref(false)
// throttle
const throttleCallback = () => {
message(
'You can only perform one operation within 1007 milliseconds',
'您在 1007 毫秒内只能进行一次操作',
'warn'
)
}
//
const likeOperation = async (
tid: number,
rid: number,
toUid: number,
isPush: boolean
) => {
// rid
const isMasterTopic = rid === 0
if (isMasterTopic) {
return await useKUNGalgameTopicStore().updateTopicLike(tid, toUid, isPush)
} else {
return await useKUNGalgameTopicStore().updateReplyLike(
tid,
toUid,
rid,
isPush
)
}
}
// throttle 1007
const handleClickLikeThrottled = throttle(
async () => {
//
if (props.uid === props.toUid) {
message('You cannot like yourself', '您不可以给自己点赞', 'warn')
return
}
//
isLiked.value = !isLiked.value
const res = await likeOperation(
props.tid,
props.rid,
props.toUid,
isLiked.value
)
if (res.code === 200) {
//
likesArray.value.length = isLiked.value
? likesArray.value.length + 1
: likesArray.value.length - 1
} else {
message('Like failed!', '点赞失败', 'error')
}
},
1007,
throttleCallback
)
//
const handleClickLike = () => {
handleClickLikeThrottled()
}
//
onMounted(() => {
//
if (props.likes.includes(props.uid)) {
isLiked.value = true
}
})
</script>
<template>
<!-- 点赞 -->
<li>
<span
class="icon"
:class="isLiked ? 'active' : ''"
@click="handleClickLike"
>
<Icon icon="line-md:thumbs-up-twotone" />
</span>
{{ likesArray.length }}
</li>
</template>
<style lang="scss" scoped>
li {
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin: 17px;
margin-right: 0;
span {
display: flex;
margin-right: 3px;
}
&:nth-child(1) span {
color: var(--kungalgame-red-4);
}
}
/* 图标字体的样式 */
.icon {
font-size: 24px;
color: var(--kungalgame-font-color-2);
cursor: pointer;
}
/* 激活后的样式 */
.active {
color: var(--kungalgame-blue-4);
}
</style>

View file

@ -0,0 +1,146 @@
<!-- 话题的底部区域推话题回复点赞等 -->
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { Icon } from '@iconify/vue'
//
import { useKUNGalgameMessageStore } from '@/store/modules/message'
//
import message from '@/components/alert/Message'
// store
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
//
const props = defineProps<{
uid: number
tid: number
rid: number
upvotes: number[]
toUid: number
}>()
const upvotesArray = ref(props.upvotes)
const isUpvote = ref(false)
//
const upvoteTopic = async () => {
//
const res = await useKUNGalgameMessageStore().alert(
'AlertInfo.edit.upvoteTopic',
true
)
//
if (res) {
//
const res = await useKUNGalgameTopicStore().updateTopicUpvote(
props.tid,
props.toUid
)
if (res.code === 200) {
//
upvotesArray.value.length++
message('Topic upvote successfully', '推话题成功', 'success')
} else {
message('Topic upvote failed!', '推话题失败', 'error')
}
}
}
//
const upvoteReply = async () => {
//
const res = await useKUNGalgameMessageStore().alert(
'AlertInfo.edit.upvoteReply',
true
)
//
if (res) {
//
const res = await useKUNGalgameTopicStore().updateReplyUpvote(
props.tid,
props.toUid,
props.rid
)
if (res.code === 200) {
//
upvotesArray.value.length++
message('Reply upvote successfully', '推回复成功', 'success')
} else {
message('Reply upvote failed!', '推回复失败', 'error')
}
}
}
//
const handleClickUpvote = async () => {
//
if (props.uid === props.toUid) {
message('You cannot upvote your own topic', '您不可以推自己的话题', 'warn')
return
}
//
if (props.rid === 0) {
upvoteTopic()
} else {
upvoteReply()
}
}
//
onMounted(() => {
//
if (props.upvotes.includes(props.uid)) {
isUpvote.value = true
}
})
</script>
<template>
<!-- 推话题 -->
<li>
<span
class="icon"
:class="isUpvote ? 'active' : ''"
@click="handleClickUpvote"
>
<Icon icon="bi:rocket" />
</span>
{{ upvotes.length }}
</li>
</template>
<style lang="scss" scoped>
li {
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin: 17px;
margin-right: 0;
span {
display: flex;
margin-right: 3px;
}
&:nth-child(1) span {
color: var(--kungalgame-red-4);
}
}
/* 图标字体的样式 */
.icon {
font-size: 24px;
color: var(--kungalgame-font-color-2);
cursor: pointer;
}
/* 激活后的样式 */
.active {
color: var(--kungalgame-blue-4);
}
</style>

View file

@ -9,7 +9,7 @@ import { Icon } from '@iconify/vue'
// //
import Comments from '../comment/Comments.vue' import Comments from '../comment/Comments.vue'
// Footer // Footer
import ReplyFooter from './ReplyFooter.vue' import Footer from '../footer/Footer.vue'
// //
import Time from '../Time.vue' import Time from '../Time.vue'
// //
@ -97,25 +97,31 @@ const handleClickComment = (rid: number) => {
</div> </div>
</div> </div>
<!-- 其它人回复的底部 --> <!-- 回复没有浏览数所以是 0占位 -->
<!-- info 代表 footer 的点赞等信息master 表示当前的回复用户信息 --> <!-- title category 也没有占位 -->
<!-- 这里传入了回复的插槽因为只有回复可以被评论 --> <Footer
<ReplyFooter
:info="{ :info="{
tid: reply.tid,
rid: reply.rid, rid: reply.rid,
views: 0,
likes: reply.likes, likes: reply.likes,
dislikes: reply.dislikes, dislikes: reply.dislikes,
upvotes: reply.upvotes, upvotes: reply.upvotes,
to_floor: reply.floor,
}" }"
:master="reply.r_user" :content="{
title: '',
content: reply.content,
tags: reply.tags,
category: [],
}"
:to-uid="reply.r_user.uid"
> >
<template #comment> <template #comment>
<span @click="handleClickComment(reply.rid)" class="icon"> <span @click="handleClickComment(reply.rid)" class="icon">
<Icon icon="fa-regular:comment-dots" /> <Icon icon="fa-regular:comment-dots" />
</span> </span>
</template> </template>
</ReplyFooter> </Footer>
<!-- 评论区域 --> <!-- 评论区域 -->
<Comments <Comments

View file

@ -1,417 +0,0 @@
<!-- 话题的底部区域推话题回复点赞等 -->
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { useRoute } from 'vue-router'
import { Icon } from '@iconify/vue'
import { useRouter } from 'vue-router'
//
import { useKUNGalgameMessageStore } from '@/store/modules/message'
//
import message from '@/components/alert/Message'
// throttle
import { throttle } from '@/utils/throttle'
import { TopicUserInfo } from '@/api'
// store
import { useKUNGalgameEditStore } from '@/store/modules/edit'
// store
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
// store
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { storeToRefs } from 'pinia'
// tid
const tid = parseInt(useRoute().params.tid as string)
// 使 store
const topicStore = useKUNGalgameTopicStore()
const { isEdit, replyDraft } = storeToRefs(topicStore)
//
const props = defineProps<{
info: {
rid: number
likes: number[]
dislikes: number[]
upvotes: number[]
// floor
to_floor: number
}
master: TopicUserInfo
}>()
/**
* 这里只是简单起见不显示重新编辑
* 实际上如果用户自己修改了 localStorage 中保存的信息这个验证就失效了
* 但是修改了也没有用验证逻辑位于后端
*/
// uid
const currUserUid = useKUNGalgameUserStore().uid
// uid
const masterUid = props.master.uid
//
const isShowRewrite = currUserUid === masterUid
// footer
const actions = reactive({
upvotes: props.info.upvotes,
likes: props.info.likes,
dislikes: props.info.dislikes,
})
//
const isActive = reactive({
isUpvote: false,
isLiked: false,
isDisliked: false,
isShared: false,
})
// throttle
const throttleCallback = () => {
message(
'You can only perform one operation within 1007 milliseconds',
'您在 1007 毫秒内只能进行一次操作',
'warn'
)
}
// throttle 1007
const handleClickLikeThrottled = throttle(
async () => {
//
if (currUserUid === masterUid) {
message(
'You cannot like your own reply',
'您不可以给自己的回复点赞',
'warn'
)
return
}
//
isActive.isLiked = !isActive.isLiked
const res = await useKUNGalgameTopicStore().updateReplyLike(
tid,
masterUid,
props.info.rid,
isActive.isLiked
)
if (res.code === 200) {
//
actions.likes.length = isActive.isLiked
? actions.likes.length + 1
: actions.likes.length - 1
} else {
message('Reply like failed!', '点赞回复失败', 'error')
}
},
1007,
throttleCallback
)
// throttle 1007
const handleClickDislikeThrottled = throttle(
async () => {
if (currUserUid === masterUid) {
message(
'You cannot dislike your own reply',
'您不可以给自己的回复点踩',
'warn'
)
return
}
isActive.isDisliked = !isActive.isDisliked
const res = await useKUNGalgameTopicStore().updateReplyDislike(
tid,
masterUid,
props.info.rid,
isActive.isDisliked
)
if (res.code === 200) {
//
actions.dislikes.length = isActive.isDisliked
? actions.dislikes.length + 1
: actions.dislikes.length - 1
} else {
message('Reply dislike failed!', '点踩回复失败', 'error')
}
},
1007,
throttleCallback
)
//
const handleClickUpvote = async () => {
//
if (currUserUid === masterUid) {
message('You cannot upvote your own reply', '您不可以推自己的回复', 'warn')
return
}
// TODO:
// if (useKUNGalgameUserStore().moemoepoint < 1100) {
// message(
// 'Your Moe Moe Points are less than 1100, and you cannot use the upvote feature',
// ' 1100使',
// 'warn'
// )
// return
// }
//
const res = await useKUNGalgameMessageStore().alert(
'AlertInfo.edit.upvote',
true
)
//
if (res) {
//
const res = await useKUNGalgameTopicStore().updateReplyUpvote(
tid,
masterUid,
props.info.rid
)
if (res.code === 200) {
//
actions.upvotes.length++
message('Topic upvote successfully', '推话题成功', 'success')
} else {
message('Topic upvote failed!', '推话题失败', 'error')
}
}
}
//
const handleClickLike = () => {
handleClickLikeThrottled()
}
//
const handleClickDislike = () => {
handleClickDislikeThrottled()
}
//
const handelReply = async () => {
// 便
replyDraft.value.tid = tid
replyDraft.value.replyUserName = props.master.name
replyDraft.value.to_uid = props.master.uid
replyDraft.value.to_floor = props.info.to_floor
isEdit.value = true
}
//
const handleClickEdit = () => {}
//
onMounted(() => {
//
if (props.info.upvotes.includes(currUserUid)) {
isActive.isUpvote = true
}
//
if (props.info.likes.includes(currUserUid)) {
isActive.isLiked = true
}
//
if (props.info.dislikes.includes(currUserUid)) {
isActive.isDisliked = true
}
})
</script>
<template>
<!-- 楼主话题底部 -->
<div class="footer">
<!-- 底部左侧部分点赞推话题 -->
<div class="left">
<ul>
<!-- 推话题 -->
<li>
<span
class="icon"
:class="isActive.isUpvote ? 'active' : ''"
@click="handleClickUpvote"
>
<Icon icon="bi:rocket" />
</span>
{{ actions.upvotes.length }}
</li>
<!-- 点赞 -->
<li>
<span
class="icon"
:class="isActive.isLiked ? 'active' : ''"
@click="handleClickLike"
>
<Icon icon="line-md:thumbs-up-twotone" />
</span>
{{ actions.likes.length }}
</li>
<!-- -->
<li>
<span
class="icon"
:class="isActive.isDisliked ? 'active' : ''"
@click="handleClickDislike"
>
<Icon icon="line-md:thumbs-down-twotone" />
</span>
{{ actions.dislikes.length }}
</li>
</ul>
</div>
<!-- 底部右侧部分回复评论只看编辑 -->
<div class="right">
<ul>
<li @click="handelReply">
<div class="reply">
{{ $tm('topic.content.reply') }}
</div>
</li>
<!-- 分享 -->
<li>
<span class="icon"><Icon icon="majesticons:share-line" /></span>
</li>
<!-- 只看 -->
<li>
<span class="icon"><Icon icon="ph:user-focus-duotone" /></span>
</li>
<!-- 编辑 -->
<li>
<span @click="handleClickEdit" class="icon">
<Icon icon="line-md:pencil-twotone-alt" />
</span>
</li>
<!-- 回复的插槽 -->
<li>
<slot name="comment"></slot>
</li>
</ul>
</div>
</div>
</template>
<style lang="scss" scoped>
/* 楼主话题底部 */
.footer {
padding: 10px 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 底部左侧部分(点赞、推话题、踩) */
.left ul {
display: flex;
justify-content: center;
align-items: center;
color: var(--kungalgame-font-color-3);
li {
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin: 17px;
margin-right: 0;
span {
display: flex;
margin-right: 3px;
}
&:nth-child(1) span {
color: var(--kungalgame-red-4);
}
}
}
/* 图标字体的样式 */
.icon {
font-size: 24px;
color: var(--kungalgame-font-color-2);
cursor: pointer;
}
/* 底部右侧部分(回复、评论、只看、编辑) */
.right ul {
display: flex;
justify-content: center;
align-items: center;
margin-left: 10px;
li {
margin-right: 17px;
span {
display: flex;
}
}
}
.reply {
position: relative;
width: 70px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: var(--kungalgame-blue-4);
cursor: pointer;
transition: all 0.2s;
&::before,
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
top: 0;
left: 0;
box-sizing: border-box;
border: 2px solid transparent;
}
&:hover {
color: var(--kungalgame-pink-4);
&::before {
transition: width 0.2s, height 0.2s, border-bottom-color 0s;
transition-delay: 0.2s, 0s, 0.2s;
width: 70px;
height: 30px;
border-left: 2px solid var(--kungalgame-pink-4);
border-bottom: 2px solid var(--kungalgame-pink-4);
}
&::after {
transition: width 0.2s, height 0.2s, border-right-color 0.2s;
transition-delay: 0s, 0.2s, 0.2s;
width: 70px;
height: 30px;
border-top: 2px solid var(--kungalgame-pink-4);
border-right: 2px solid var(--kungalgame-pink-4);
}
}
}
/* 激活后的样式 */
.active {
color: var(--kungalgame-blue-4);
}
@media (max-width: 700px) {
.footer {
flex-direction: column;
}
}
</style>