fix message ui

This commit is contained in:
jxxghp
2024-03-16 16:47:41 +08:00
parent 823d2a816e
commit fed92f3853
6 changed files with 151 additions and 27 deletions

View File

@@ -147,3 +147,23 @@ export function formatEp(nums: number[]): string {
return formattedRanges.join('、')
}
// 将yyyy-mm-dd hh:mm:ss转换为时间差1小时前1天前
export function formatDateDifference(dateString: string): string {
const date = new Date(dateString)
const currentDate = new Date()
const timeDifference = currentDate.getTime() - date.getTime()
const secondsDifference = Math.floor(timeDifference / 1000)
const minutesDifference = Math.floor(secondsDifference / 60)
const hoursDifference = Math.floor(minutesDifference / 60)
const daysDifference = Math.floor(hoursDifference / 24)
if (daysDifference > 0)
return `${daysDifference}天前`
else if (hoursDifference > 0)
return `${hoursDifference}小时前`
else if (minutesDifference > 0)
return `${minutesDifference}分钟前`
else
return '刚刚'
}

View File

@@ -1051,12 +1051,15 @@ export interface Message {
// 消息时间
date?: string
// 登记时间
reg_time?: string
// 用户ID
userid?: string
// 用户名称
username?: string
// 消息方向0-接收1-发送
action?: number
// JSON
note?: string
}

View File

@@ -25,8 +25,8 @@ const isDownloading = ref(props.info?.state === 'downloading')
// 监听props.info?.state的变化
watch(() => props.info?.state, (newValue) => {
isDownloading.value = newValue === 'downloading';
});
isDownloading.value = newValue === 'downloading'
})
// 图片是否加载完成
const imageLoaded = ref(false)

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import type { Message } from '@/api/types'
import { formatDateDifference } from '@core/utils/formatters'
// 输入参数
const props = defineProps({
@@ -24,12 +25,33 @@ function openLink() {
if (props.message?.link)
window.open(props.message.link, '_blank')
}
// 将note转换为json
function noteToJson() {
if (props.message?.note) {
try {
return JSON.parse(props.message.note)
}
catch (error) {
console.error(error)
}
}
return {}
}
// 将\n转换为html属性的换行符
function replaceNewLine(value: string) {
if (!value)
return ''
return value.replace(/\n/g, '<br/>')
}
</script>
<template>
<VCard
:width="props.width"
:height="props.height"
variant="tonal"
@click="openLink"
>
<div
@@ -45,7 +67,7 @@ function openLink() {
@error="imageLoadError = true"
/>
</div>
<VCardTitle v-if="props.message?.title">
<VCardTitle v-if="props.message?.title" class="whitespace-break-spaces">
{{ props.message?.title }}
</VCardTitle>
<VAlert
@@ -56,8 +78,35 @@ function openLink() {
<template #prepend />
{{ props.message?.text }}
</VAlert>
<VCardText v-if="props.message?.text && props.message?.action === 1">
{{ props.message?.text }}
<VCardText
v-if="props.message?.text && props.message?.action === 1"
v-html="replaceNewLine(props.message?.text)"
/>
<VCardText v-if="props.message?.note">
<VList>
<VListItem
v-for="(value, key) in noteToJson()"
:key="key"
two-line
>
<VListItemTitle v-if="value.title_year" class="font-bold">
{{ key + 1 }}. {{ value.title_year }}
</VListItemTitle>
<VListItemTitle v-if="value.enclosure" class="font-bold whitespace-break-spaces">
{{ key + 1 }}. {{ value.title }} {{ value.volume_factor }} {{ value.seeders }}
</VListItemTitle>
<VListItemSubtitle v-if="value.type">
类型{{ value.type }} 评分{{ value.vote_average }}
</VListItemSubtitle>
<VListItemSubtitle v-if="value.enclosure" class="whitespace-break-spaces">
{{ value.description }}
</VListItemSubtitle>
</VListItem>
</VList>
</VCardText>
<div class="text-end">
<span v-if="props.message?.action === 0" class="text-sm italic me-2">{{ props.message?.userid }}</span>
<span class="text-sm italic me-2">{{ formatDateDifference(props.message?.reg_time || props.message?.date || '') }}</span>
</div>
</VCard>
</template>

View File

@@ -6,6 +6,7 @@ import RuleTestView from '@/views/system/RuleTestView.vue'
import ModuleTestView from '@/views/system/ModuleTestView.vue'
import MessageView from '@/views/system/MessageView.vue'
import store from '@/store'
import api from '@/api'
// App捷径
const appsMenu = ref(false)
@@ -28,11 +29,48 @@ const systemTestDialog = ref(false)
// 消息中心弹窗
const messageDialog = ref(false)
// 输入消息
const user_message = ref('')
// 发送按钮是否可用
const sendButtonDisabled = ref(false)
// 聊天容器
const chatContainer = ref<HTMLDivElement>()
// 滚动到底部
function scrollMessageToEnd() {
nextTick(() => {
if (chatContainer.value)
chatContainer.value.scrollTop = chatContainer.value.scrollHeight
})
}
// 拼接全部日志url
function allLoggingUrl() {
const token = store.state.auth.token
return `${import.meta.env.VITE_API_BASE_URL}system/logging?token=${token}&length=-1`
}
// 发送消息
async function sendMessage() {
if (user_message.value) {
try {
sendButtonDisabled.value = true
await api.post(`message/web?text=${user_message.value}`)
user_message.value = ''
sendButtonDisabled.value = false
scrollMessageToEnd()
}
catch (error) {
console.error(error)
}
}
}
onMounted(() => {
scrollMessageToEnd()
})
</script>
<template>
@@ -282,9 +320,32 @@ function allLoggingUrl() {
>
<VCard title="消息中心">
<DialogCloseBtn @click="messageDialog = false" />
<VCardText>
<MessageView />
<VCardText ref="chatContainer">
<MessageView @scroll="scrollMessageToEnd" />
</VCardText>
<VCardItem>
<VTextField
v-model="user_message"
placeholder="输入消息或命令"
outlined
hide-details
single-line
clearable
density="compact"
@keydown.enter="sendMessage"
>
<template #append>
<VBtn
color="primary"
:disabled="sendButtonDisabled"
@click="sendMessage"
>
发送
</VBtn>
</template>
</VTextField>
</VCardItem>
</VCard>
</VDialog>
</template>

View File

@@ -4,24 +4,15 @@ import MessageCard from '@/components/cards/MessageCard.vue'
import type { Message } from '@/api/types'
import api from '@/api'
// 定义事件
const emit = defineEmits(['scroll'])
// 消息列表
const messages = ref<Message[]>([])
// 是否完成加载
const isLoaded = ref(false)
// 输入消息
const content = ref('')
// 聊天容器
const chatContainer = ref<HTMLDivElement>()
// 滚动到底部
function scrollToEnd() {
if (chatContainer.value)
chatContainer.value.scrollTop = chatContainer.value.scrollHeight
}
// SSE持续获取消息
function startSSEMessager() {
const token = store.state.auth.token
@@ -35,7 +26,7 @@ function startSSEMessager() {
if (message) {
const object = JSON.parse(message)
messages.value.push(object)
scrollToEnd()
emit('scroll')
}
isLoaded.value = true
})
@@ -52,7 +43,7 @@ async function loadMessages() {
messages.value = await api.get('message/web')
if (messages.value.length > 0) {
isLoaded.value = true
scrollToEnd()
emit('scroll')
}
}
catch (error) {
@@ -86,7 +77,7 @@ onMounted(() => {
>
<span class="mb-3">当前没有消息</span>
</div>
<VContainer ref="chatContainer" fluid style="padding: 0;">
<div>
<VRow
v-for="(msg, index) in messages"
:key="index"
@@ -96,7 +87,7 @@ onMounted(() => {
}"
>
<VCol
sm="8"
cols="10"
lg="6"
xl="4"
style="position: relative;"
@@ -106,5 +97,5 @@ onMounted(() => {
/>
</VCol>
</VRow>
</VContainer>
</div>
</template>