From cc7fcb678a06b71669c12f3b4a6d73424a19d23b Mon Sep 17 00:00:00 2001 From: KUN1007 Date: Sat, 30 Sep 2023 21:49:37 +0800 Subject: [PATCH] feat: like topic --- src/api/index.ts | 1 + src/api/topic/index.ts | 15 +- src/api/topic/types/action.ts | 10 ++ src/components/alert/Message.ts | 3 + src/components/quill-editor/QuillEditor.vue | 4 + src/store/modules/topic.ts | 23 +++ src/utils/getPlainText.ts | 4 +- src/utils/loli.ts | 10 +- src/utils/throttle.ts | 36 ++++ src/views/topic/components/Master.vue | 16 +- src/views/topic/components/MasterFooter.vue | 165 ++++++++++++++---- .../topic/components/reply/ReplyPanel.vue | 2 +- 12 files changed, 241 insertions(+), 48 deletions(-) create mode 100644 src/utils/throttle.ts diff --git a/src/api/index.ts b/src/api/index.ts index 40731b23..f262c241 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -7,6 +7,7 @@ export * from './edit/types/edit' export * from './home/types/home' export * from './kungalgamer/types/kungalgamer' export * from './login/types/login' +export * from './topic/types/action' export * from './topic/types/topic' export * from './topic/types/aside' export * from './update-log/types/updateLog' diff --git a/src/api/topic/index.ts b/src/api/topic/index.ts index 93861ce3..3af21aa6 100644 --- a/src/api/topic/index.ts +++ b/src/api/topic/index.ts @@ -1,6 +1,7 @@ -import { fetchGet, fetchPost } from '@/utils/request' +import { fetchGet, fetchPost, fetchPut } from '@/utils/request' // 将对象转为请求参数的函数 import objectToQueryParams from '@/utils/objectToQueryParams' +import * as Action from './types/action' import * as Aside from './types/aside' import * as Topic from './types/topic' @@ -54,6 +55,18 @@ export async function getTopicByTidApi( } } +// 点赞话题 +export async function updateTopicLikeApi( + request: Action.TopicLikeTopicRequestData +): Promise { + const queryParams = objectToQueryParams(request, 'tid') + const url = `/topics/${request.tid}/like?${queryParams}` + + const response = fetchPut(url) + + return response +} + // 根据话题 tid 获取话题回复 export async function getRepliesByPidApi( request: Topic.TopicReplyRequestData diff --git a/src/api/topic/types/action.ts b/src/api/topic/types/action.ts index bf26badf..06a9bdf5 100644 --- a/src/api/topic/types/action.ts +++ b/src/api/topic/types/action.ts @@ -1,3 +1,13 @@ /** * 这是用户对话题的操作,推,点赞,点踩等 */ + +// 点赞 +export interface TopicLikeTopicRequestData { + tid: number + to_uid: number + isPush: boolean +} + +// 点赞话题响应数据的格式 +export type TopicLikeTopicResponseData = KUNGalgameResponseData<{}> diff --git a/src/components/alert/Message.ts b/src/components/alert/Message.ts index f6901eff..6e2e37e0 100644 --- a/src/components/alert/Message.ts +++ b/src/components/alert/Message.ts @@ -16,6 +16,9 @@ export default ( type: MessageType, duration?: number ) => { + // 初始化的时候先将上一次创建的内容销毁 + render(null, document.body) + const messageNode = h(Message, { messageCN, messageEN, diff --git a/src/components/quill-editor/QuillEditor.vue b/src/components/quill-editor/QuillEditor.vue index 933442bd..5887d976 100644 --- a/src/components/quill-editor/QuillEditor.vue +++ b/src/components/quill-editor/QuillEditor.vue @@ -200,6 +200,10 @@ const handleTextChange = async () => { /* 头部下方阴影 */ box-shadow: 0 2px 4px 0 var(--kungalgame-trans-blue-1); display: v-bind(isShowEditorToolbar); + /* 不显示视频插入,这个功能 BUG 太多了 */ + .ql-video { + display: none; + } } /* 编辑器体的样式 */ diff --git a/src/store/modules/topic.ts b/src/store/modules/topic.ts index 63cb9eda..f1d49a11 100644 --- a/src/store/modules/topic.ts +++ b/src/store/modules/topic.ts @@ -10,6 +10,14 @@ import { getPopularTopicsByUserUidApi, TopicAsideResponseData, } from '@/api' + +// 点赞等动作 +import { + updateTopicLikeApi, + TopicLikeTopicRequestData, + TopicLikeTopicResponseData, +} from '@/api' + // 回复 import { getRepliesByPidApi, @@ -19,6 +27,7 @@ import { TopicCreateReplyRequestData, TopicCreateReplyResponseData, } from '@/api' + // 评论 import { getCommentsByReplyRidApi, @@ -98,6 +107,20 @@ export const useKUNGalgameTopicStore = defineStore({ return await getTopicByTidApi(tid) }, + // 点赞话题 + async updateTopicLike( + tid: number, + toUid: number, + isPush: boolean + ): Promise { + const requestData: TopicLikeTopicRequestData = { + tid: tid, + to_uid: toUid, + isPush: isPush, + } + return await updateTopicLikeApi(requestData) + }, + // 获取回复 async getReplies(tid: number): Promise { // 这里的默认值用于初始化 diff --git a/src/utils/getPlainText.ts b/src/utils/getPlainText.ts index 3c88e065..99eafdc0 100644 --- a/src/utils/getPlainText.ts +++ b/src/utils/getPlainText.ts @@ -1,8 +1,8 @@ export function getPlainText(html: string): string { - // 使用正则表达式匹配所有HTML标签并删除 + // 使用正则表达式匹配所有 HTML 标签并删除 const plainText = html.replace(/<[^>]*>/g, '') - // 使用实体编码映射表将HTML实体编码还原 + // 使用实体编码映射表将 HTML 实体编码还原 const entityMap: Record = { lt: '<', gt: '>', diff --git a/src/utils/loli.ts b/src/utils/loli.ts index c426a849..ec2baaf3 100644 --- a/src/utils/loli.ts +++ b/src/utils/loli.ts @@ -58,19 +58,19 @@ const loliFaceLeft = loli.face.left + 'px' const loliFaceTop = loli.face.top + 'px' // 身体的图片资源链接 -let lass = getAssetsFile(loli.lass.layer_id) +const lass = getAssetsFile(loli.lass.layer_id) // 眼睛的图片资源链接 -let eye = getAssetsFile(loli.eye.layer_id) +const eye = getAssetsFile(loli.eye.layer_id) // 眉毛的图片资源链接 -let brow = getAssetsFile(loli.brow.layer_id) +const brow = getAssetsFile(loli.brow.layer_id) // 嘴巴的图片资源链接 -let mouth = getAssetsFile(loli.mouth.layer_id) +const mouth = getAssetsFile(loli.mouth.layer_id) // 腮红的图片资源链接 -let face = getAssetsFile(loli.face.layer_id) +const face = getAssetsFile(loli.face.layer_id) // 导出模块 export { diff --git a/src/utils/throttle.ts b/src/utils/throttle.ts new file mode 100644 index 00000000..e90bbcbf --- /dev/null +++ b/src/utils/throttle.ts @@ -0,0 +1,36 @@ +/** + * Throttle(节流)函数 + * 在一段时间内,无论触发多少次函数,都只执行一次 + */ + +/** + * @param {T} executeCallback - 要应用 throttle 函数的代码 + * @param {number} delay - throttle 的时间 + * @param {T | undefined} delayedCallback - 用户在 throttle 时间未到执行了 execute 函数产生的回调 + */ +export function throttle void>( + executeCallback: T, + delay: number, + delayedCallback?: T | undefined +) { + let lastExecution = 0 + let timeout: NodeJS.Timeout | null = null + + const throttled = (...args: Parameters) => { + const now = Date.now() + + if (!lastExecution || now - lastExecution >= delay) { + executeCallback(...args) + lastExecution = now + } else { + if (!timeout && delayedCallback) { + delayedCallback(...args) + timeout = setTimeout(() => { + timeout = null + }, delay) + } + } + } + + return throttled as (...args: Parameters) => void +} diff --git a/src/views/topic/components/Master.vue b/src/views/topic/components/Master.vue index c88402ac..b8f55b4f 100644 --- a/src/views/topic/components/Master.vue +++ b/src/views/topic/components/Master.vue @@ -36,7 +36,7 @@ const { user, // rid, status, - // share, + share, category, } = topicData.topicData @@ -94,11 +94,19 @@ const loliStatus = computed(() => { - + diff --git a/src/views/topic/components/MasterFooter.vue b/src/views/topic/components/MasterFooter.vue index 94a1f250..80d41e84 100644 --- a/src/views/topic/components/MasterFooter.vue +++ b/src/views/topic/components/MasterFooter.vue @@ -1,7 +1,12 @@ @@ -170,17 +262,20 @@ const handleClickEdit = () => { color: var(--kungalgame-font-color-2); cursor: pointer; } + +/* 激活后的样式 */ +.active { + color: var(--kungalgame-blue-4); +} + /* 底部右侧部分(回复、评论、只看、编辑) */ -.right ul { +.right { display: flex; justify-content: center; align-items: center; - margin-left: 10px; - li { + span { + display: flex; margin-right: 17px; - span { - display: flex; - } } } diff --git a/src/views/topic/components/reply/ReplyPanel.vue b/src/views/topic/components/reply/ReplyPanel.vue index 173a34b4..5012c58c 100644 --- a/src/views/topic/components/reply/ReplyPanel.vue +++ b/src/views/topic/components/reply/ReplyPanel.vue @@ -45,7 +45,7 @@ const handelClosePanel = () => {