pref: topic reactivity
This commit is contained in:
parent
30502722ef
commit
3f5a6158b0
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
// 读取本地存储中的语言配置
|
||||
const localStorageString = localStorage.getItem('KUNGalgame-settings')
|
||||
const localStorageString = localStorage.getItem('KUNGalgameSettings')
|
||||
|
||||
// 这里是为了兼容各种浏览器,某些浏览器的 navigator.language 值为 'zh-CN',会导致报错
|
||||
const getInitLanguage = () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 话题的底部区域,推话题,回复,点赞等 -->
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { watch, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
// 全局消息组件(顶部)
|
||||
import message from '@/components/alert/Message'
|
||||
|
@ -19,8 +19,18 @@ const props = defineProps<{
|
|||
toUid: number
|
||||
}>()
|
||||
|
||||
const dislikesArray = ref(props.dislikes)
|
||||
const isDisliked = ref(false)
|
||||
const isDisliked = ref(props.dislikes.includes(props.uid))
|
||||
const dislikesCount = ref(props.dislikes.length)
|
||||
|
||||
// 响应式
|
||||
watch(
|
||||
() => props.dislikes,
|
||||
(newLikes) => {
|
||||
// 更新 isLiked 和 likesCount
|
||||
isDisliked.value = newLikes.includes(props.uid)
|
||||
dislikesCount.value = newLikes.length
|
||||
}
|
||||
)
|
||||
|
||||
// throttle 回调函数
|
||||
const throttleCallback = () => {
|
||||
|
@ -56,34 +66,32 @@ const dislikeOperation = async (
|
|||
}
|
||||
}
|
||||
|
||||
// throttle 函数,1007 毫秒仅会触发一次点踩
|
||||
const handleClickDislikeThrottled = throttle(
|
||||
async () => {
|
||||
// 点踩 / 取消点踩
|
||||
const toggleDislike = async () => {
|
||||
// 当前用户不可以给自己点赞
|
||||
if (props.uid === props.toUid) {
|
||||
message('You cannot dislike yourself', '您不可以给自己点踩', 'warn')
|
||||
return
|
||||
}
|
||||
|
||||
// 切换点赞激活状态
|
||||
isDisliked.value = !isDisliked.value
|
||||
const { tid, rid, toUid } = props
|
||||
const isPush = !isDisliked.value // 取反表示点赞或取消点赞
|
||||
|
||||
const res = await dislikeOperation(
|
||||
props.tid,
|
||||
props.rid,
|
||||
props.toUid,
|
||||
isDisliked.value
|
||||
)
|
||||
// 执行点赞或取消点赞操作
|
||||
const res = await dislikeOperation(tid, rid, toUid, isPush)
|
||||
|
||||
if (res.code === 200) {
|
||||
// 更新点踩数
|
||||
dislikesArray.value.length = isDisliked.value
|
||||
? dislikesArray.value.length + 1
|
||||
: dislikesArray.value.length - 1
|
||||
isDisliked.value = isPush
|
||||
dislikesCount.value += isPush ? 1 : -1
|
||||
message('Dislike successfully!', '点踩成功', 'success')
|
||||
} else {
|
||||
message('Dislike failed!', '点踩失败', 'error')
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// throttle 函数,1007 毫秒仅会触发一次点踩
|
||||
const handleClickDislikeThrottled = throttle(
|
||||
toggleDislike,
|
||||
1007,
|
||||
throttleCallback
|
||||
)
|
||||
|
@ -92,14 +100,6 @@ const handleClickDislikeThrottled = throttle(
|
|||
const handleClickDislike = () => {
|
||||
handleClickDislikeThrottled()
|
||||
}
|
||||
|
||||
// 初始化按钮的状态
|
||||
onMounted(() => {
|
||||
// 已经点踩
|
||||
if (props.dislikes.includes(props.uid)) {
|
||||
isDisliked.value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -112,7 +112,7 @@ onMounted(() => {
|
|||
>
|
||||
<Icon icon="line-md:thumbs-down-twotone" />
|
||||
</span>
|
||||
{{ dislikes.length }}
|
||||
{{ dislikesCount }}
|
||||
</li>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
|||
// 导入用户的 store
|
||||
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
|
||||
// 使用话题页面的 store
|
||||
const { isEdit, replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
@ -38,6 +39,10 @@ const props = defineProps<{
|
|||
toUid: number
|
||||
}>()
|
||||
|
||||
const info = computed(() => props.info)
|
||||
const content = computed(() => props.content)
|
||||
const toUid = computed(() => props.toUid)
|
||||
|
||||
/**
|
||||
* 这里只是简单起见,不显示重新编辑
|
||||
* 实际上如果用户自己修改了 localStorage 中保存的信息,这个验证就失效了
|
||||
|
@ -45,15 +50,13 @@ const props = defineProps<{
|
|||
*/
|
||||
// 当前登录用户的 uid
|
||||
const currUserUid = useKUNGalgameUserStore().uid
|
||||
// 话题 / 回复发布者的 uid
|
||||
const masterUid = props.toUid
|
||||
|
||||
// 点击回复打开回复面板
|
||||
const handleClickReply = async () => {
|
||||
const handleClickReply = () => {
|
||||
// 保存必要信息,以便发表回复
|
||||
replyDraft.value.tid = props.info.tid
|
||||
replyDraft.value.tid = info.value.tid
|
||||
// 被回复人就是发表人的 uid
|
||||
replyDraft.value.to_uid = masterUid
|
||||
replyDraft.value.to_uid = toUid.value
|
||||
// 楼主的 floor 就是 0
|
||||
replyDraft.value.to_floor = 0
|
||||
// 打开回复面板
|
||||
|
@ -70,14 +73,14 @@ const handleClickReply = async () => {
|
|||
<!-- 推话题 -->
|
||||
<Upvote
|
||||
:uid="currUserUid"
|
||||
:tid="props.info.tid"
|
||||
:rid="props.info.rid"
|
||||
:upvotes="props.info.upvotes"
|
||||
:to-uid="masterUid"
|
||||
:tid="info.tid"
|
||||
:rid="info.rid"
|
||||
:upvotes="info.upvotes"
|
||||
:to-uid="toUid"
|
||||
/>
|
||||
|
||||
<!-- 浏览数,楼主才会显示 -->
|
||||
<li v-if="props.info.views > 0">
|
||||
<li v-if="info.views > 0">
|
||||
<span class="icon"><Icon icon="ic:outline-remove-red-eye" /></span>
|
||||
{{ info.views }}
|
||||
</li>
|
||||
|
@ -85,19 +88,19 @@ const handleClickReply = async () => {
|
|||
<!-- 点赞 -->
|
||||
<Like
|
||||
:uid="currUserUid"
|
||||
:tid="props.info.tid"
|
||||
:rid="props.info.rid"
|
||||
:likes="props.info.likes"
|
||||
:to-uid="masterUid"
|
||||
:tid="info.tid"
|
||||
:rid="info.rid"
|
||||
:likes="info.likes"
|
||||
:to-uid="toUid"
|
||||
/>
|
||||
|
||||
<!-- 踩 -->
|
||||
<Dislike
|
||||
:uid="currUserUid"
|
||||
:tid="props.info.tid"
|
||||
:rid="props.info.rid"
|
||||
:dislikes="props.info.dislikes"
|
||||
:to-uid="masterUid"
|
||||
:tid="info.tid"
|
||||
:rid="info.rid"
|
||||
:dislikes="info.dislikes"
|
||||
:to-uid="toUid"
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -116,14 +119,14 @@ const handleClickReply = async () => {
|
|||
|
||||
<!-- 编辑 -->
|
||||
<Rewrite
|
||||
:tid="props.info.tid"
|
||||
:rid="props.info.rid"
|
||||
:tid="info.tid"
|
||||
:rid="info.rid"
|
||||
:uid="currUserUid"
|
||||
:title="props.content.title"
|
||||
:content="props.content.content"
|
||||
:tags="props.content.tags"
|
||||
:category="props.content.category"
|
||||
:to-uid="masterUid"
|
||||
:title="content.title"
|
||||
:content="content.content"
|
||||
:tags="content.tags"
|
||||
:category="content.category"
|
||||
:to-uid="toUid"
|
||||
/>
|
||||
|
||||
<!-- 回复的插槽 -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 话题的底部区域,推话题,回复,点赞等 -->
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { watch, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
// 全局消息组件(顶部)
|
||||
import message from '@/components/alert/Message'
|
||||
|
@ -19,8 +19,18 @@ const props = defineProps<{
|
|||
toUid: number
|
||||
}>()
|
||||
|
||||
const likesArray = ref(props.likes)
|
||||
const isLiked = ref(false)
|
||||
const isLiked = ref(props.likes.includes(props.uid))
|
||||
const likesCount = ref(props.likes.length)
|
||||
|
||||
// 响应式
|
||||
watch(
|
||||
() => props.likes,
|
||||
(newLikes) => {
|
||||
// 更新 isLiked 和 likesCount
|
||||
isLiked.value = newLikes.includes(props.uid)
|
||||
likesCount.value = newLikes.length
|
||||
}
|
||||
)
|
||||
|
||||
// throttle 回调函数
|
||||
const throttleCallback = () => {
|
||||
|
@ -52,50 +62,36 @@ const likeOperation = async (
|
|||
}
|
||||
}
|
||||
|
||||
// throttle 函数,1007 毫秒仅会触发一次点赞
|
||||
const handleClickLikeThrottled = throttle(
|
||||
async () => {
|
||||
// 点赞 / 取消点赞
|
||||
const toggleLike = async () => {
|
||||
// 当前用户不可以给自己点赞
|
||||
if (props.uid === props.toUid) {
|
||||
message('You cannot like yourself', '您不可以给自己点赞', 'warn')
|
||||
return
|
||||
}
|
||||
|
||||
// 切换点赞激活状态
|
||||
isLiked.value = !isLiked.value
|
||||
const { tid, rid, toUid } = props
|
||||
const isPush = !isLiked.value // 取反表示点赞或取消点赞
|
||||
|
||||
const res = await likeOperation(
|
||||
props.tid,
|
||||
props.rid,
|
||||
props.toUid,
|
||||
isLiked.value
|
||||
)
|
||||
// 执行点赞或取消点赞操作
|
||||
const res = await likeOperation(tid, rid, toUid, isPush)
|
||||
|
||||
if (res.code === 200) {
|
||||
// 更新点赞数
|
||||
likesArray.value.length = isLiked.value
|
||||
? likesArray.value.length + 1
|
||||
: likesArray.value.length - 1
|
||||
isLiked.value = isPush
|
||||
likesCount.value += isPush ? 1 : -1
|
||||
message('Like successfully!', '点赞成功', 'success')
|
||||
} else {
|
||||
message('Like failed!', '点赞失败', 'error')
|
||||
}
|
||||
},
|
||||
1007,
|
||||
throttleCallback
|
||||
)
|
||||
}
|
||||
|
||||
// throttle 函数,1007 毫秒仅会触发一次点赞
|
||||
const handleClickLikeThrottled = throttle(toggleLike, 1007, throttleCallback)
|
||||
|
||||
// 点赞
|
||||
const handleClickLike = () => {
|
||||
handleClickLikeThrottled()
|
||||
}
|
||||
|
||||
// 初始化按钮的状态,是否已点赞等
|
||||
onMounted(() => {
|
||||
// 已经点赞
|
||||
if (props.likes.includes(props.uid)) {
|
||||
isLiked.value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -108,7 +104,7 @@ onMounted(() => {
|
|||
>
|
||||
<Icon icon="line-md:thumbs-up-twotone" />
|
||||
</span>
|
||||
{{ likesArray.length }}
|
||||
{{ likesCount }}
|
||||
</li>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<!-- 话题的底部区域,推话题,回复,点赞等 -->
|
||||
<script setup lang="ts">
|
||||
import { watch, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// 导入编辑界面的 store
|
||||
|
@ -28,7 +29,19 @@ const props = defineProps<{
|
|||
}>()
|
||||
|
||||
// 是否具有重新编辑的权限
|
||||
const isShowRewrite = props.uid === props.toUid
|
||||
const isShowRewrite = ref(props.uid === props.toUid)
|
||||
|
||||
// 响应式
|
||||
watch(
|
||||
() => props.toUid,
|
||||
() => {
|
||||
if (props.uid === props.toUid) {
|
||||
isShowRewrite.value = true
|
||||
} else {
|
||||
isShowRewrite.value = false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 重新编辑话题
|
||||
const rewriteTopic = () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 话题的底部区域,推话题,回复,点赞等 -->
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { watch, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
// 全局消息组件(底部)
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
|
@ -18,8 +18,17 @@ const props = defineProps<{
|
|||
toUid: number
|
||||
}>()
|
||||
|
||||
const upvotesArray = ref(props.upvotes)
|
||||
const isUpvote = ref(false)
|
||||
const isUpvote = ref(props.upvotes.includes(props.uid))
|
||||
const upvoteCount = ref(props.upvotes.length)
|
||||
|
||||
// 响应式
|
||||
watch(
|
||||
() => props.upvotes,
|
||||
(newUpvote) => {
|
||||
isUpvote.value = props.upvotes.includes(props.uid)
|
||||
upvoteCount.value = newUpvote.length
|
||||
}
|
||||
)
|
||||
|
||||
// 推话题
|
||||
const upvoteTopic = async () => {
|
||||
|
@ -31,15 +40,14 @@ const upvoteTopic = async () => {
|
|||
|
||||
// 这里实现用户的点击确认取消逻辑
|
||||
if (res) {
|
||||
const { tid, toUid } = props
|
||||
// 请求推话题的接口
|
||||
const res = await useKUNGalgameTopicStore().updateTopicUpvote(
|
||||
props.tid,
|
||||
props.toUid
|
||||
)
|
||||
const res = await useKUNGalgameTopicStore().updateTopicUpvote(tid, toUid)
|
||||
|
||||
if (res.code === 200) {
|
||||
// 更新推数
|
||||
upvotesArray.value.length++
|
||||
upvoteCount.value++
|
||||
isUpvote.value = true
|
||||
|
||||
message('Topic upvote successfully', '推话题成功', 'success')
|
||||
} else {
|
||||
|
@ -58,16 +66,18 @@ const upvoteReply = async () => {
|
|||
|
||||
// 这里实现用户的点击确认取消逻辑
|
||||
if (res) {
|
||||
const { tid, toUid, rid } = props
|
||||
// 请求推话题的接口
|
||||
const res = await useKUNGalgameTopicStore().updateReplyUpvote(
|
||||
props.tid,
|
||||
props.toUid,
|
||||
props.rid
|
||||
tid,
|
||||
toUid,
|
||||
rid
|
||||
)
|
||||
|
||||
if (res.code === 200) {
|
||||
// 更新推数
|
||||
upvotesArray.value.length++
|
||||
upvoteCount.value++
|
||||
isUpvote.value = true
|
||||
|
||||
message('Reply upvote successfully', '推回复成功', 'success')
|
||||
} else {
|
||||
|
@ -91,14 +101,6 @@ const handleClickUpvote = async () => {
|
|||
upvoteReply()
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化按钮的状态
|
||||
onMounted(() => {
|
||||
// 已经推过
|
||||
if (props.upvotes.includes(props.uid)) {
|
||||
isUpvote.value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -111,7 +113,7 @@ onMounted(() => {
|
|||
>
|
||||
<Icon icon="bi:rocket" />
|
||||
</span>
|
||||
{{ upvotes.length }}
|
||||
{{ upvoteCount }}
|
||||
</li>
|
||||
</template>
|
||||
|
||||
|
@ -141,6 +143,6 @@ li {
|
|||
|
||||
/* 激活后的样式 */
|
||||
.active {
|
||||
color: var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-blue-4) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
这个区域包含所有人回复给楼主的话题,其中每个人的话题将会被拆分成为单独的组件
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, onUpdated, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, onUpdated, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
// 内容区组件
|
||||
import Content from '../Content.vue'
|
||||
// 导入评论组件
|
||||
import Comments from '../comment/Comments.vue'
|
||||
// 导入 Footer 组件
|
||||
|
@ -30,10 +32,13 @@ import { storeToRefs } from 'pinia'
|
|||
|
||||
const { scrollToReplyId, commentDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
repliesData: TopicReply[]
|
||||
}>()
|
||||
|
||||
// 响应式 props 的值,因为子组件还要用
|
||||
const replies = computed(() => props.repliesData)
|
||||
|
||||
// 控制面板关闭的值
|
||||
const isCommentPanelOpen = ref(false)
|
||||
// 切换面板的状态
|
||||
|
@ -58,14 +63,14 @@ const handleClickComment = (rid: number) => {
|
|||
<!-- 被推 10 小时内样式改变 -->
|
||||
<div
|
||||
class="other-topic-container"
|
||||
v-for="(reply, index) in repliesData"
|
||||
v-for="(reply, index) in replies"
|
||||
:class="hourDiff(reply.upvote_time, 10) ? 'active-upvote' : ''"
|
||||
:key="`${index}`"
|
||||
:id="`kungalgame-reply-${reply.floor}`"
|
||||
>
|
||||
<!-- 每个人的单个话题 -->
|
||||
<!-- 楼层标志 -->
|
||||
<div class="floor">
|
||||
<div class="floor" :class="reply.edited ? 'rewrite' : ''">
|
||||
<span>K{{ reply.floor }}</span>
|
||||
</div>
|
||||
<!-- 其他人话题内容区的容器 -->
|
||||
|
@ -91,8 +96,9 @@ const handleClickComment = (rid: number) => {
|
|||
<!-- 上部区域的右边 -->
|
||||
<Rewrite v-if="reply.edited" :time="reply.edited" />
|
||||
</div>
|
||||
<!-- 右侧部分分文本 -->
|
||||
<div class="text" v-html="reply.content"></div>
|
||||
|
||||
<!-- 富文本内容展示区域 -->
|
||||
<Content :content="reply.content" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 其他人回复的下部 -->
|
||||
|
@ -164,6 +170,7 @@ const handleClickComment = (rid: number) => {
|
|||
border-bottom: none;
|
||||
/* 这里的阴影只能这么绘制 */
|
||||
filter: drop-shadow(1px 2px 2px var(--kungalgame-trans-blue-4));
|
||||
margin: 5px 0;
|
||||
span {
|
||||
transform: rotate(10deg) translateY(40px);
|
||||
padding: 0 30px;
|
||||
|
@ -253,6 +260,13 @@ const handleClickComment = (rid: number) => {
|
|||
margin-right: 17px;
|
||||
}
|
||||
|
||||
/* 被重新编辑后的楼层标志样式 */
|
||||
.rewrite {
|
||||
span {
|
||||
transform: rotate(0) translateY(0) translateX(-7px);
|
||||
}
|
||||
}
|
||||
|
||||
/* 回复被推的样式 */
|
||||
.active-upvote .container {
|
||||
border: 2px solid var(--kungalgame-pink-3);
|
||||
|
|
|
@ -21,8 +21,6 @@ import ReplyPanelBtn from './ReplyPanelBtn.vue'
|
|||
|
||||
// 全局消息组件(底部)
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
// 全局消息组件(顶部)
|
||||
import message from '@/components/alert/Message'
|
||||
// 导入话题页面 store
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
|
|
@ -10,7 +10,6 @@ import { useTempReplyStore } from '@/store/temp/reply'
|
|||
import { storeToRefs } from 'pinia'
|
||||
// 回复重新编辑响应的临时数据
|
||||
import { useTempReplyRewriteStore } from '@/store/temp/replyRewrite'
|
||||
import { timeEnd } from 'console'
|
||||
|
||||
const { rid, replyContent, tags, edited } = storeToRefs(
|
||||
useTempReplyRewriteStore()
|
||||
|
|
Loading…
Reference in a new issue