Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"dependencies": {
"@alova/scene-vue": "^1.0.4",
"@element-plus/icons-vue": "^2.1.0",
"@imengyu/vue3-context-menu": "^1.2.10",
"alova": "^2.3.0",
"dayjs": "^1.11.7",
"dompurify": "^3.0.3",
Expand Down
15 changes: 14 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/assets/operate-icons/to_top.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ declare module '@vue/runtime-core' {
ElPopover: typeof import('element-plus/es')['ElPopover']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
IconCommunity: typeof import('./components/icons/IconCommunity.vue')['default']
IconDislike: typeof import('./components/icons/iconDislike.vue')['default']
IconDocumentation: typeof import('./components/icons/IconDocumentation.vue')['default']
IconEcosystem: typeof import('./components/icons/IconEcosystem.vue')['default']
IconLike: typeof import('./components/icons/iconLike.vue')['default']
IconSupport: typeof import('./components/icons/IconSupport.vue')['default']
IconTooling: typeof import('./components/icons/IconTooling.vue')['default']
IEpArrowDownBold: typeof import('~icons/ep/arrow-down-bold')['default']
Expand All @@ -33,6 +35,7 @@ declare module '@vue/runtime-core' {
IEpLock: typeof import('~icons/ep/lock')['default']
IEpMale: typeof import('~icons/ep/male')['default']
IEpSuccessFilled: typeof import('~icons/ep/success-filled')['default']
LikeButton: typeof import('./components/LikeButton/index.vue')['default']
LoginBox: typeof import('./components/LoginBox/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Expand Down
15 changes: 8 additions & 7 deletions src/components/VirtualList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,23 @@ export default defineComponent({
* @param index 索引值
* @description 如果索引值大于等于数据长度说明到底了则滚动到底部
*/
const scrollToIndex = (index: number) => {
const scrollToIndex = (index: number, smooth?: boolean) => {
if (index >= props.data.length - 1) {
scrollToBottom()
} else {
const offset = virtual.getOffset(index)
scrollToOffset(offset)
scrollToOffset(offset, smooth)
}
}

/**
* 滚动到指定偏移量
* @param offset 滚动条偏移量
*/
const scrollToOffset = (offset: number) => {
const scrollToOffset = (offset: number, smooth = false) => {
if (rootRef.value) {
rootRef.value.scrollTop = offset
// rootRef.value.scrollTop = offset
rootRef.value.scroll({ left: 0, top: offset, behavior: smooth ? 'smooth' : 'auto' })
}
}

Expand Down Expand Up @@ -236,13 +237,13 @@ export default defineComponent({
}

// 滚动到底部
const scrollToBottom = () => {
const scrollToBottom = (smooth?: boolean) => {
if (shepherd.value) {
const offset = shepherd.value.offsetTop
scrollToOffset(offset)
scrollToOffset(offset, smooth)
setTimeout(() => {
if (getOffset() + getClientSize() < getScrollSize()) {
scrollToBottom()
scrollToBottom(smooth)
}
}, 3)
}
Expand Down
9 changes: 9 additions & 0 deletions src/components/icons/iconDislike.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<template>
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M8.331 6.612l1.24 1.005c.08.065.12.166.107.267l-.222 1.71c-.014.11.12.178.203.1l1.954-1.857a.294.294 0 00.036-.386l-.582-.806a.293.293 0 01-.03-.295l.763-1.655.356-.67A3.06 3.06 0 0112.55 4C14.44 4 16 5.504 16 7.723c0 2.462-2.093 4.906-5.297 6.968-.246.163-.522.309-.706.309-.184 0-.454-.146-.7-.31C6.093 12.63 4 10.186 4 7.724 4 5.503 5.56 4 7.45 4c.402 0 .768.075 1.095.211l-.06.382-.26 1.747a.295.295 0 00.106.272z"
fill="currentColor"
fill-opacity="0.8"
></path>
</svg>
</template>
11 changes: 11 additions & 0 deletions src/components/icons/iconLike.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.106 5.412c.571-.814 1.51-1.244 2.542-1.244 1.966 0 3.602 1.706 3.602 3.734l-.002.134V8.1a.03.03 0 00.002.009c-.008.427-.081.78-.212 1.245-.074.084-.143.241-.212.415-.108.168-.15.25-.212.415a8.504 8.504 0 01-.298.464c-.488.71-1.108 1.414-1.734 2.05-1.13 1.154-2.304 2.121-2.806 2.535-.134.11-.22.182-.245.206-.177.177-.354.177-.531.177h-.025c-.338-.009-.51-.182-.683-.355a1.39 1.39 0 00-.083-.07 25.514 25.514 0 01-3.037-2.685c-.814-.845-1.582-1.799-2.014-2.732-.177-.354-.398-1.197-.408-1.665.004-.004.003-.026.002-.071l-.002-.136c0-2.03 1.634-3.734 3.602-3.734 1.03 0 1.97.43 2.754 1.244z"
fill="currentColor"
opacity="0.9"
></path>
</svg>
</template>
67 changes: 67 additions & 0 deletions src/hooks/useLikeToggle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { computed } from 'vue'
import apis from '@/services/apis'
import { ActType, MarkType, IsYet } from '@/services/types'
import type { MessageItemType } from '@/services/types'

/**
* 统一点赞倒赞操作Hook
* @param message 消息
* @description 引入该Hook后,可直接使用isLike(是否已点赞)、isDisLike(是否已倒赞)、onLike(点赞方法)、onDisLike(倒赞方法)
*/
export const useLikeToggle = (message: MessageItemType['message']) => {
const isLike = computed(() => message.messageMark.userLike === IsYet.Yes)
const isDisLike = computed(() => message.messageMark.userDislike === IsYet.Yes)
const likeCount = computed(() => message.messageMark.likeCount)
const dislikeCount = computed(() => message.messageMark.dislikeCount)

/**
* 点赞\取消点赞
* @description 根据是否已经点赞控制更新点赞状态
*/
const onLike = async () => {
const actType = isLike.value ? ActType.Cancel : ActType.Confirm
await apis.markMsg({ actType, markType: MarkType.Like, msgId: message.id }).send()

// 根据actType类型去更新本地点赞状态-点赞数
const { likeCount } = message.messageMark
const isConfirm = actType === ActType.Confirm
message.messageMark.userLike = isConfirm ? IsYet.Yes : IsYet.No
message.messageMark.likeCount = isConfirm ? likeCount + 1 : likeCount - 1
// 互斥操作
if (isDisLike.value) {
message.messageMark.userDislike = IsYet.No
message.messageMark.dislikeCount = dislikeCount.value - 1
}
}

/**
* 倒赞\取消倒赞
* @description 根据是否已经倒赞控制更新倒赞状态
*/
const onDisLike = async () => {
const actType = isDisLike.value ? ActType.Cancel : ActType.Confirm
await apis.markMsg({ actType, markType: MarkType.DisLike, msgId: message.id }).send()

// 根据actType类型去更新本地倒赞状态-倒赞数
const { dislikeCount } = message.messageMark
const isConfirm = actType === ActType.Confirm
message.messageMark.userDislike = isConfirm ? IsYet.Yes : IsYet.No
message.messageMark.dislikeCount = isConfirm ? dislikeCount + 1 : dislikeCount - 1
// 互斥操作
if (isLike.value) {
message.messageMark.userLike = IsYet.No
message.messageMark.likeCount = likeCount.value - 1
}
}

return {
isLike,
isDisLike,
likeCount,
dislikeCount,
onLike,
onDisLike,
}
}

export default useLikeToggle
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createApp } from 'vue'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import weekday from 'dayjs/plugin/weekday'
import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css'
// import 'element-plus/dist/index.css'
import { createPinia } from 'pinia'

Expand Down
164 changes: 96 additions & 68 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,77 @@ export enum MessageType {
Danger,
}

export type MessageReplyType = {
/**
* 是否可消息跳转 0否 1是
*/
canCallback: number
/**
* 是否可消息跳转 0否 1是
*/
content: string
/**
* 跳转间隔的消息条数
*/
gapCount: number
/**
* 消息id
*/
id: number
/**
* 用户名称
*/
username: string
}

export type MessageItemContentType = {
/**
* 消息内容
*/
content: string
/**
* 消息id
*/
id: number
/**
* 消息标记
*/
messageMark: {
/**
* 点赞数
*/
likeCount: number
/**
* 该用户是否已经点赞 0否 1是
*/
userLike: IsYet
/**
* 点赞数
*/
dislikeCount: number
/**
* 到赞数
*/
userDislike: IsYet
}
/**
* 父消息,如果没有父消息,返回的是null
*/
reply: MessageReplyType | null
/**
* 消息发送时间
*/
sendTime: number
/**
* 消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5)
*/
type: MessageType
/**
* 消息中的链接
*/
urlTitleMap: Record<string, string>
}

export type MessageItemType = {
/**
* 发送者信息
Expand Down Expand Up @@ -108,74 +179,8 @@ export type MessageItemType = {
/**
* 消息详情
*/
message: {
/**
* 消息内容
*/
content: string
/**
* 消息id
*/
id: number
/**
* 消息标记
*/
messageMark: {
/**
* 点赞数
*/
likeCount: number
/**
* 该用户是否已经点赞 0否 1是
*/
userLike: IsYet
/**
* 点赞数
*/
dislikeCount: number
/**
* 到赞数
*/
userDislike: IsYet
}
/**
* 父消息,如果没有父消息,返回的是null
*/
reply: {
/**
* 是否可消息跳转 0否 1是
*/
canCallback: number
/**
* 是否可消息跳转 0否 1是
*/
content: string
/**
* 跳转间隔的消息条数
*/
gapCount: number
/**
* 消息id
*/
id: number
/**
* 用户名称
*/
username: string
} | null
/**
* 消息发送时间
*/
sendTime: number
/**
* 消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5)
*/
type: MessageType
/**
* 消息中的链接
*/
urlTitleMap: Record<string, string>
}
message: MessageItemContentType

// 是否显示时间,有值才显示
timeBlock?: string
}
Expand Down Expand Up @@ -260,3 +265,26 @@ export type BadgeType = {
// 是否佩戴 0否 1是
wearing: IsYet
}

export type MarkItemType = {
/**
* 操作用户
*/
uid: number
/**
* 消息id
*/
msgId: number
/**
* 操作类型 1点赞 2举报
*/
markType: MarkType
/**
* 数量
*/
markCount: number
/**
* 动作类型 1确认 2取消
*/
actType: ActType
}
Loading