更新
Some checks failed
Check / lint (push) Has been cancelled
Check / typecheck (push) Has been cancelled
Check / build (build, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:app, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:app, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Has been cancelled

This commit is contained in:
caiyx 2024-11-26 16:51:36 +08:00
parent a000ee9718
commit 62f540c65c
16 changed files with 1014 additions and 329 deletions

2
env/.env.test vendored
View File

@ -9,3 +9,5 @@ VITE_SHOW_SOURCEMAP = true
VITE_BASEURL = 'http://192.168.88.59:9503'
#VITE_SOCKET_API
VITE_SOCKET_API = 'ws://192.168.88.59:9504'
# EPRAPI baseUrl
VITE_EPR_BASEURL = 'http://114.218.158.24:9020'

View File

@ -28,12 +28,14 @@
"@uni-helper/axios-adapter": "^1.5.2",
"@uni-helper/localforage-adapter": "^1.0.2",
"@uni-helper/uni-use": "^0.19.12",
"@vueup/vue-quill": "^1.2.0",
"@vueuse/core": "^9.13.0",
"axios": "^1.7.2",
"dayjs": "^1.11.12",
"less": "^4.2.0",
"nzh": "^1.0.13",
"pinia-plugin-persistedstate": "^4.1.3",
"quill-mention": "^6.0.2",
"vconsole": "^3.15.1",
"vue": "^3.3.8",
"vue-i18n": "^9.6.5"

View File

@ -1,31 +1,31 @@
<script lang="ts" setup>
import { NImage } from 'naive-ui'
import { getImageInfo } from '@/utils/functions'
import { ITalkRecordExtraImage, ITalkRecord } from '@/types/chat'
defineProps<{
extra: ITalkRecordExtraImage
data: ITalkRecord
extra: any
data: any
maxWidth?: Boolean
}>()
const img = (src: string, width = 200) => {
const info = getImageInfo(src)
if (info.width == 0 || info.height == 0) {
return {}
return {
width: 450,
height: 298
}
}
if (info.width < width) {
return {
width: `${info.width}px`,
height: `${info.height}px`
width: info.width,
height: info.height
}
}
return {
width: width + 'px',
height: `${info.height / (info.width / width)}px`
width: width,
height: info.height / (info.width / width)
}
}
</script>
@ -33,28 +33,22 @@ const img = (src: string, width = 200) => {
<section
class="im-message-image"
:class="{ left: data.float === 'left' }"
:style="img(extra.url, 350)"
>
<n-image :src="extra.url" />
<tm-image preview :width="img(extra.url,450).width" :height="img(extra.url,450).height" :src="extra.url" />
</section>
</template>
<style lang="less" scoped>
.im-message-image {
overflow: hidden;
padding: 5px;
border-radius: 5px;
background: var(--im-message-left-bg-color);
min-width: 30px;
min-height: 30px;
padding: 20rpx 18rpx;
border-radius: 16rpx 0 16rpx 16rpx;
background-color: #46299D;
min-width: 40rpx;
min-height: 40rpx;
&.left {
background: var(--im-message-right-bg-color);
}
:deep(.n-image img) {
width: 100%;
height: 100%;
border-radius: 5px;
background-color: #fff;
border-radius: 0 16rpx 16rpx 16rpx;
}
}
</style>

View File

@ -1,5 +1,4 @@
<script lang="ts" setup>
import { NImage } from 'naive-ui'
import { textReplaceEmoji } from '@/utils/emojis'
import { textReplaceLink } from '@/utils/strings'
import { getImageInfo } from '@/utils/functions'
@ -13,25 +12,26 @@ const props = defineProps<{
const float = props.data.float
const img = (src, width = 200) => {
const img = (src: string, width = 200) => {
const info = getImageInfo(src)
if (info.width == 0 || info.height == 0) {
return {}
return {
width: 200,
height: 200
}
}
if (info.width < width) {
return {
width: `${info.width}px`,
height: `${info.height}px`
width: info.width,
height: info.height
}
}
let h = info.height / (info.width / width)
return {
width: width + 'px',
height: h + 'px'
width: width,
height: info.height / (info.width / width)
}
}
</script>
@ -47,17 +47,16 @@ const img = (src, width = 200) => {
>
<pre>
<template v-for="(item) in extra.items" :key="item.id">
<template v-if="item.type === 1">
<span v-html="textReplaceEmoji(textReplaceLink(item.content))" />
</template>
<template v-else-if="item.type === 3">
<div
:style="img(item.content, 300)"
style="display: flex; margin: 5px 0;border-radius: 8px;overflow: hidden;;"
style="display: flex; margin: 5px 0;border-radius: 8px;overflow: hidden;"
>
<n-image :src="item.content"></n-image>
<tm-image :src="item.content" :width="img(item.content,450).width" :height="img(item.content,450).height" ></tm-image>
</div>
</template>
</template>
@ -67,16 +66,16 @@ const img = (src, width = 200) => {
<style lang="less" scoped>
.im-message-mixed {
min-width: 30px;
min-height: 30px;
padding: 3px;
color: var(--im-message-left-text-color);
background: var(--im-message-left-bg-color);
border-radius: 0px 10px 10px 10px;
min-width: 40rpx;
min-height: 40rpx;
padding: 20rpx 18rpx;
color: #000000;
background-color: #FFFFFF;
border-radius: 0 16rpx 16rpx 16rpx;
&.right {
background-color: var(--im-message-right-bg-color);
color: var(--im-message-right-text-color);
background-color: #46299D;
color: #FFFFFF;
border-radius: 10px 0px 10px 10px;
}

View File

@ -39,17 +39,17 @@ textContent = textReplaceEmoji(textContent)
<style lang="less" scoped>
.im-message-text {
min-width: 30px;
min-height: 30px;
min-width: 40rpx;
min-height: 40rpx;
padding: 22rpx 30rpx;
color: #1A1A1A;
background: #FFFFFF;
border-radius: 0px 10px 10px 10px;
border-radius: 0 16rpx 16rpx 16rpx;
&.right {
background-color: #46299D;
color: #FFFFFF;
border-radius: 10px 0px 10px 10px;
border-radius: 16rpx 0 16rpx 16rpx;
}
&.maxwidth {

View File

@ -1,106 +1,86 @@
<script lang="ts" setup>
import 'xgplayer/dist/index.min.css'
import { ref, nextTick } from 'vue'
import { NImage, NModal, NCard } from 'naive-ui'
import { Play, Close } from '@icon-park/vue-next'
import { ref, nextTick,getCurrentInstance } from 'vue'
import { getImageInfo } from '@/utils/functions'
import Player from 'xgplayer'
import { ITalkRecordExtraVideo, ITalkRecord } from '@/types/chat'
import playCircle from "@/static/image/chatList/playCircle@2x.png";
import { useStatus } from "@/store/status";
const { statusBarHeight } = useStatus()
const instance = getCurrentInstance()
const props = defineProps<{
extra: ITalkRecordExtraVideo
data: ITalkRecord
extra: any
data: any
maxWidth?: Boolean
}>()
const videoRef = ref()
const videoContext = ref()
const open = ref(false)
const img = (src: string, width = 200) => {
console.log(props);
const info: any = getImageInfo(src)
if (info.width == 0 || info.height == 0) {
return {}
}
if (info.height > 300) {
return {
height: '300px'
}
}
if (info.width < width) {
return {
width: `${info.width}px`,
height: `${info.height}px`
width: info.width,
height: info.height
}
}
return {
width: width + 'px',
height: info.height / (info.width / width) + 'px'
width: width,
height: info.height / (info.width / width)
}
}
const open = ref(false)
const fullscreenchange = (e) => {
if(!e.detail.fullScreen){
videoContext.value.stop()
open.value = false
}
}
async function onPlay() {
videoContext.value = uni.createVideoContext(props.extra.url,instance);
videoContext.value.requestFullScreen({ direction: 2 });
videoContext.value.play()
open.value = true
await nextTick()
new Player({
id: 'im-xgplayer',
url: props.extra.url,
fluid: true,
autoplay: true,
lang: 'zh-cn'
})
}
</script>
<template>
<section
class="im-message-video"
:class="{ left: data.float === 'left' }"
:style="img(extra.cover, 350)"
@click="onPlay"
>
<n-image :src="extra.cover" preview-disabled />
<section class="im-message-video" :class="{ left: data.float === 'left' }" @click="onPlay">
<tm-image :src="extra.cover" :width="img(extra.cover, 350).width" :height="img(extra.cover, 350).height" />
<div class="btn-video">
<n-icon :component="Play" size="36" />
<tm-image :src="playCircle" :width="80" :height="80" />
</div>
<div v-show="open">
<video ref="videoRef" :src="props.extra.url" controls @fullscreenchange="fullscreenchange"
:id="props.extra.url">
</video>
</div>
<n-modal v-model:show="open">
<n-card
style="width: 800px; min-height: 300px; background-color: #ffffff; position: relative"
role="dialog"
aria-modal="true"
>
<div id="im-xgplayer"></div>
<div class="im-xgplayer-close" @click="open = false">
<n-icon :component="Close" size="18" />
</div>
</n-card>
</n-modal>
</section>
</template>
<style lang="less" scoped>
.im-message-video {
overflow: hidden;
padding: 5px;
border-radius: 5px;
background: var(--im-message-left-bg-color);
min-width: 30px;
min-height: 30px;
padding: 20rpx 18rpx;
background: #46299D;
min-width: 30rpx;
min-height: 30rpx;
display: inline-flex;
position: relative;
border-radius: 16rpx 0 16rpx 16rpx;
&.left {
background: var(--im-message-right-bg-color);
}
:deep(.n-image img) {
width: 100%;
height: 100%;
border-radius: 5px;
border-radius: 0 16rpx 16rpx 16rpx;
background: #fff;
}
.btn-video {
@ -134,4 +114,5 @@ async function onPlay() {
align-items: center;
justify-content: center;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<div class="emojiRoot">
<div v-for="(img, key) in emojis" v-html="img" :key="key" @click="onSendEmoticon(1, key, img)"
class="option pointer flex-center" />
</div>
</template>
<script setup>
import { ref, reactive, defineProps } from "vue"
import dayjs from "dayjs";
import { beautifyTime } from '@/utils/datetime'
import { useTalkStore } from '@/store'
import { useSessionMenu } from '@/hooks'
import { emojis } from '@/utils/emojis'
const props = defineProps({
data: {
type: Object,
default: {},
required: false,
},
});
const onSendEmoticon = (type, value, img = '') => {
if (img) {
const imgSrcReg = /<img.*?src='(.*?)'/g
let match = imgSrcReg.exec(img)
if (match) {
emit('on-select', { type, value, img: match[1] })
}
} else {
emit('on-select', { type, value, img })
}
}
</script>
<style lang="scss" scoped>
.emojiRoot {
width: 100%;
height: 420rpx;
padding: 5rpx 32rpx;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
overflow: auto;
}
.option {
width: 14.28%;
height: 42rpx;
margin: 20rpx 0;
}
:deep(.emoji) {
vertical-align: text-bottom;
margin: 0 10rpx;
width: 52rpx;
height: 52rpx;
}
</style>

View File

@ -15,109 +15,129 @@
</div>
<div class="root">
<div class="dialogBox">
<!-- <div v-if="loadConfig.status == 0" class="h-[240rpx] flex items-center justify-center flex-col" >
<wd-loading />
<div class="text-[#959598] mt-[20rpx] text-[28rpx]" > 正在加载中... </div>
</div>
<div v-else-if="loadConfig.status == 1" @click="onRefreshLoad" >查看更多消息 ...</div>
<span v-else class="no-more"> 没有更多消息了 </span> -->
<!-- 数据加载状态栏 -->
<div class="load-toolbar pointer">
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
<span v-else-if="loadConfig.status == 1" @click="onRefreshLoad"> 查看更多消息 ... </span>
<span v-else class="no-more"> 没有更多消息了 </span>
</div>
<div class="message-item" v-for="(item, index) in records" :key="item.msg_id" :id="item.msg_id">
<!-- 系统消息 -->
<div v-if="item.msg_type >= 1000" class="message-box">
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item" />
</div>
<!-- 撤回消息 -->
<div v-else-if="item.is_revoke == 1" class="message-box">
<revoke-message :login_uid="uid" :user_id="item.user_id" :nickname="item.nickname"
:talk_type="item.talk_type" :datetime="item.created_at" />
</div>
<ZPaging :fixed="false" use-chat-record-mode :use-page-scroll="false" :refresher-enabled="false"
:show-scrollbar="false" :loading-more-enabled="true" :hide-empty-view="true" height="100%" ref="pagingRef"
@scrolltolower="onRefreshLoad">
<!-- 数据加载状态栏 -->
<div class="message-item" v-for="(item, index) in reversedRecords" style="transform: scaleY(-1);"
:key="item.msg_id" :id="item.msg_id">
<!-- 系统消息 -->
<div v-if="item.msg_type >= 1000" class="message-box">
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item" />
</div>
<!-- 撤回消息 -->
<div v-else-if="item.is_revoke == 1" class="message-box">
<revoke-message :login_uid="uid" :user_id="item.user_id" :nickname="item.nickname"
:talk_type="item.talk_type" :datetime="item.created_at" />
</div>
<div v-else class="message-box record-box" :class="{
'direction-rt': item.float == 'right',
'multi-select': dialogueStore.isOpenMultiSelect,
'multi-select-check': item.isCheck
}">
<!-- 多选按钮 -->
<aside v-if="dialogueStore.isOpenMultiSelect" class="checkbox-column">
<n-checkbox size="small" :checked="item.isCheck" @update:checked="item.isCheck = !item.isCheck" />
</aside>
<div v-else class="message-box record-box" :class="{
'direction-rt': item.float == 'right',
'multi-select': dialogueStore.isOpenMultiSelect,
'multi-select-check': item.isCheck
}">
<!-- 多选按钮 -->
<aside v-if="dialogueStore.isOpenMultiSelect" class="checkbox-column">
<n-checkbox size="small" :checked="item.isCheck" @update:checked="item.isCheck = !item.isCheck" />
</aside>
<!-- 头像信息 -->
<aside class="avatar-column">
<im-avatar class="pointer" :src="item.avatar" :size="80" :username="item.nickname"
@click="showUserInfoModal(item.user_id)" />
</aside>
<!-- 主体信息 -->
<main class="main-column">
<div class="talk-title">
<span class="nickname pointer" v-show="talk_type == 2 && item.float == 'left'"
@click="onClickNickname(item)">
<span class="at">@</span>{{ item.nickname }}
</span>
<span>{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}</span>
</div>
<div class="talk-content" :class="{ pointer: dialogueStore.isOpenMultiSelect }" @click="onRowClick(item)">
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item"
:max-width="true" :source="'panel'" @contextmenu.prevent="onContextMenu($event, item)" />
<div class="talk-tools">
<template v-if="talk_type == 1 && item.float == 'right'">
<loading theme="outline" size="19" fill="#000" :strokeWidth="1" class="icon-rotate"
v-show="item.send_status == 1" />
<span v-show="item.send_status == 1"> 正在发送... </span>
<!-- <span v-show="item.send_status != 1"> 已送达 </span> -->
</template>
<!-- 头像信息 -->
<aside class="avatar-column">
<im-avatar class="pointer" :src="item.avatar" :size="80" :username="item.nickname"
@click="showUserInfoModal(item.user_id)" />
</aside>
<!-- 主体信息 -->
<main class="main-column">
<div class="talk-title">
<span class="nickname pointer" v-show="talk_type == 2 && item.float == 'left'"
@click="onClickNickname(item)">
<span class="at">@</span>{{ item.nickname }}
</span>
<span>{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}</span>
</div>
</div>
<div v-if="item.extra.reply" class="talk-reply pointer" @click="onJumpMessage(item.extra?.reply?.msg_id)">
<n-icon :component="ToTop" size="14" class="icon-top" />
<span class="ellipsis">
回复 {{ item.extra?.reply?.nickname }}:
{{ item.extra?.reply?.content }}
</span>
</div>
</main>
<div class="talk-content" :class="{ pointer: dialogueStore.isOpenMultiSelect }">
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra"
:data="item" :max-width="true" :source="'panel'"
@contextmenu.prevent="onContextMenu($event, item)" />
<div class="talk-tools">
<template v-if="talk_type == 1 && item.float == 'right'">
<loading theme="outline" size="19" fill="#000" :strokeWidth="1" class="icon-rotate"
v-show="item.send_status == 1" />
<span v-show="item.send_status == 1"> 正在发送... </span>
<!-- <span v-show="item.send_status != 1"> 已送达 </span> -->
</template>
</div>
</div>
<div v-if="item.extra.reply" class="talk-reply pointer"
@click="onJumpMessage(item.extra?.reply?.msg_id)">
<n-icon :component="ToTop" size="14" class="icon-top" />
<span class="ellipsis">
回复 {{ item.extra?.reply?.nickname }}:
{{ item.extra?.reply?.content }}
</span>
</div>
</main>
</div>
</div>
</div>
<div class="load-toolbar pointer" style="transform: scaleY(-1);">
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
<span v-else-if="loadConfig.status == 1" @click="onRefreshLoad"> 查看更多消息 ... </span>
<span v-else class="no-more"> 没有更多消息了 </span>
</div>
</ZPaging>
</div>
</div>
<div class="footBox">
<div class="mt-[16rpx] ml-[32rpx] mr-[32rpx] flex items-center justify-between">
<div class="w-[534rpx]">
<tm-input :height="72" placeholder=""></tm-input>
<div class="w-[534rpx] quillBox" >
<QuillEditor ref="editor" id="editor" :options="editorOption" @editorChange="onEditorChange"
style="height: 100%; border: none" />
<!-- <tm-input type=textarea autoHeight focusColor="#F9F9F9" color="#F9F9F9" :inputPadding="[12]"
placeholder=""></tm-input> -->
</div>
<tm-image :width="52" :height="52" :round="12" :src="smile"></tm-image>
<tm-image @click="state.isOpenEmojiPanel = !state.isOpenEmojiPanel" :width="52" :height="52" :round="12"
:src="state.isOpenEmojiPanel ? keyboard : smile"></tm-image>
<tm-image :width="52" :height="52" :round="12" :src="addCircleGray"></tm-image>
</div>
<div v-if="state.isOpenEmojiPanel" class="mt-[50rpx]">
<emoji-panel />
</div>
<!--底部安全区-->
<div class="content-placeholder"></div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, watch, computed, onMounted } from 'vue';
import { QuillEditor, Quill } from '@vueup/vue-quill'
import { useChatList } from "@/store/chatList/index.js";
import { useAuth } from "@/store/auth";
import { useUserStore, useDialogueStore, useUploadsStore } from '@/store'
import { useUserStore, useDialogueStore, useUploadsStore, useEditorDraftStore } from '@/store'
import addCircleGray from "@/static/image/chatList/addCircleGray.png";
import { MessageComponents, ForwardableMessageType } from '@/constant/message'
import { formatTime, parseTime } from '@/utils/datetime'
import { deltaToMessage, deltaToString, isEmptyDelta } from './util'
import smile from "@/static/image/chatList/smile@2x.png";
import keyboard from "@/static/image/chatList/keyboard@2x.png";
import { useInject, useTalkRecord } from '@/hooks'
import ZPaging from "@/uni_modules/z-paging/components/z-paging/z-paging.vue";
import useZPaging from "@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js";
import emojiPanel from './components/emojiPanel.vue'
const userStore = useUserStore()
const dialogueStore = useDialogueStore()
const editorDraftStore = useEditorDraftStore()
const editor = ref()
const pagingRef = ref(null)
useZPaging(pagingRef)
const indexName = computed(() => dialogueStore.index_name)
const talkParams = reactive({
uid: computed(() => userStore.uid),
index_name: computed(() => dialogueStore.index_name),
@ -129,7 +149,141 @@ const talkParams = reactive({
num: computed(() => dialogueStore.members.length)
})
const state = ref({
isOpenEmojiPanel: false
})
const { loadConfig, records, onLoad, onRefreshLoad, onJumpMessage } = useTalkRecord(talkParams.uid)
// records
const reversedRecords = computed(() => {
return [...records.value].reverse()
})
const getQuill = () => {
return editor.value?.getQuill()
}
const onEditorChange = () => {
debugger
let delta = getQuill().getContents()
let text = deltaToString(delta)
if (!isEmptyDelta(delta)) {
editorDraftStore.items[indexName.value || ''] = JSON.stringify({
text: text,
ops: delta.ops
})
} else {
// editorDraftStore.items
delete editorDraftStore.items[indexName.value || '']
}
// emit('editor-event', emitCall('input_event', text))
}
const onSendMessage = () => {
let delta = getQuill().getContents()
let data = deltaToMessage(delta)
if (data.items.length === 0) {
return
}
switch (data.msgType) {
case 1: //
if (data.items[0].content.length > 1024) {
return window['$message'].info('发送内容超长,请分条发送')
}
emit(
'editor-event',
emitCall('text_event', data, (ok) => {
ok && getQuill().setContents([], Quill.sources.USER)
})
)
break
case 3: //
emit(
'editor-event',
emitCall(
'image_event',
{ ...getImageInfo(data.items[0].content), url: data.items[0].content, size: 10000 },
(ok) => {
ok && getQuill().setContents([])
}
)
)
break
case 12: //
emit(
'editor-event',
emitCall('mixed_event', data, (ok) => {
ok && getQuill().setContents([])
})
)
break
}
}
const editorOption = {
debug: false,
modules: {
toolbar: false,
// clipboard: {
// //
// matchers: [[Node.ELEMENT_NODE, onClipboardMatcher]]
// },
keyboard: {
bindings: {
enter: {
key: 13,
handler: onSendMessage
}
}
},
// imageUploader: {
// upload: onEditorUpload
// },
// mention: {
// allowedChars: /^[\u4e00-\u9fa5]*$/,
// mentionDenotationChars: ['@'],
// positioningStrategy: 'fixed',
// renderItem: (data) => {
// const el = document.createElement('div')
// el.className = 'ed-member-item'
// el.innerHTML = `<img src="${data.avatar}" class="avator"/>`
// el.innerHTML += `<span class="nickname">${data.nickname}</span>`
// return el
// },
// source: function (searchTerm, renderList) {
// if (!props.members.length) {
// return renderList([])
// }
// let list = [
// { id: 0, nickname: '', avatar: defAvatar, value: '' },
// ...props.members
// ]
// const items = list.filter(
// (item) => item.nickname.toLowerCase().indexOf(searchTerm) !== -1
// )
// renderList(items)
// },
// mentionContainerClass: 'ql-mention-list-container me-scrollbar me-scrollbar-thumb'
// }
},
placeholder: '',
}
watch(() => records, (newValue, oldValue) => {
console.log(newValue);
@ -157,18 +311,24 @@ onMounted(() => {
</script>
<style scoped lang="less">
uni-page-body,
page {
height: 100%;
}
.outer-layer {
overflow-y: auto;
flex: 1;
background-image: url("@/static/image/clockIn/z3280@3x.png");
background-size: cover;
display: flex;
flex-direction: column;
overflow: hidden;
}
.root {
flex: 1;
padding: 20rpx 32rpx;
min-height: 0;
}
.searchRoot {
@ -182,20 +342,32 @@ onMounted(() => {
}
.footBox {
height: 162rpx;
min-height: 162rpx;
background-color: #fff;
}
.dialogBox {
height: 100%;
min-height: 0;
overflow: auto;
//
&::-webkit-scrollbar {
display: none;
}
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.load-toolbar {
height: 38px;
height: 50rpx;
color: #409eff;
text-align: center;
line-height: 38px;
font-size: 13px;
line-height: 50rpx;
font-size: 24rpx;
.no-more {
color: #b9b3b3;
@ -204,37 +376,28 @@ onMounted(() => {
.message-item {
&.border {
border-radius: 10px;
border: 1px solid var(--im-primary-color);
border-radius: 16rpx;
}
}
.message-box {
width: 100%;
min-height: 30px;
margin-bottom: 5px;
}
.datetime {
height: 30px;
line-height: 30px;
color: #ccc9c9;
font-size: 12px;
text-align: center;
margin: 5px 0;
min-height: 30rpx;
margin-bottom: 5rpx;
}
.record-box {
display: flex;
flex-direction: row;
align-items: flex-start;
.checkbox-column {
display: flex;
justify-content: center;
width: 35px;
width: 35rpx;
order: 1;
user-select: none;
padding-top: 12px;
padding-top: 12rpx;
}
.avatar-column {
@ -271,7 +434,7 @@ onMounted(() => {
.nickname {
color: var(--im-text-color);
margin-right: 5px;
margin-right: 5rpx;
.at {
display: none;
@ -302,16 +465,16 @@ onMounted(() => {
.talk-tools {
display: flex;
margin: 0 8px;
margin: 0 16rpx;
color: #a79e9e;
font-size: 12px;
font-size: 24rpx;
user-select: none;
align-items: center;
justify-content: space-around;
.more-tools {
visibility: hidden;
margin-left: 5px;
margin-left: 5rpx;
}
}
}
@ -321,20 +484,20 @@ onMounted(() => {
align-items: flex-start;
align-items: center;
width: fit-content;
padding: 4px;
margin-top: 3px;
padding: 8rpx;
margin-top: 6rpx;
margin-right: auto;
font-size: 12px;
font-size: 24rpx;
color: #8f8f8f;
word-break: break-all;
background-color: var(--im-message-left-bg-color);
border-radius: 5px;
max-width: 300px;
border-radius: 10rpx;
max-width: 450rpx;
overflow: hidden;
user-select: none;
.icon-top {
margin-right: 3px;
margin-right: 6rpx;
}
.ellipsis {
@ -392,4 +555,22 @@ onMounted(() => {
}
}
}
.content-placeholder {
height: 58rpx;
}
.quillBox {
:deep(.ql-clipboard) {
width: 0;
height: 0;
}
:deep(.ql-editor) {
padding: 14rpx 22rpx;
background-color: #F9F9F9;
border-radius: 8rpx;
outline: none !important;
}
}
</style>

175
src/pages/dialog/util.ts Normal file
View File

@ -0,0 +1,175 @@
import { Delta } from '@vueup/vue-quill'
interface Item {
type: number
content: string
}
interface AnalysisResp {
items: Item[]
mentions: any[]
mentionUids: number[]
msgType: number // 1 文本2图片3图文混合消息
quoteId: string // 引用的消息ID
}
function removeLeadingNewlines(str: string) {
return str.replace(/^[\n\s]+/, '')
}
function removeTrailingNewlines(str: string) {
return str.replace(/[\n\s]+$/, '')
}
export function deltaToMessage(delta: Delta): AnalysisResp {
const resp: AnalysisResp = {
items: [],
mentions: [],
mentionUids: [],
quoteId: '',
msgType: 1
}
for (const iterator of delta.ops) {
const insert: any = iterator.insert
let node: any = null
if (resp.items.length) {
node = resp.items[resp.items.length - 1]
}
if (typeof insert === 'string') {
if (!insert || insert == '\n') continue
if (node && node.type == 1) {
node.content = node.content + insert
continue
}
resp.items.push({
type: 1,
content: insert
})
continue
}
// @好友
if (insert && insert.mention) {
const mention = insert.mention
resp.mentions.push({
name: `${mention.denotationChar}${mention.value}`,
atid: parseInt(mention.id)
})
if (node && node.type == 1) {
node.content = node.content + ` ${mention.denotationChar}${mention.value}`
continue
}
resp.items.push({
type: 1,
content: `${mention.denotationChar}${mention.value}`
})
continue
}
// 图片
if (insert && insert.image) {
resp.items.push({
type: 3,
content: insert.image
})
continue
}
// 表情
if (insert && insert.emoji) {
const { emoji } = insert
if (node && node.type == 1) {
node.content = node.content + emoji.alt
continue
}
resp.items.push({
type: 1,
content: emoji.alt
})
continue
}
if (insert && insert.quote) {
resp.quoteId = insert.quote.id
continue
}
}
// 去除前后多余空格
if (resp.items.length) {
if (resp.items[0].type == 1) {
resp.items[0].content = removeLeadingNewlines(resp.items[0].content)
}
if (resp.items[resp.items.length - 1].type == 1) {
resp.items[resp.items.length - 1].content = removeTrailingNewlines(
resp.items[resp.items.length - 1].content
)
}
}
if (resp.items.length > 1) {
resp.msgType = 12
}
if (resp.items.length == 1) {
resp.msgType = resp.items[0].type
}
resp.mentionUids = resp.mentions.map((item) => item.atid)
return resp
}
export function deltaToString(delta: Delta): string {
let content = ''
for (const o of delta.ops) {
const insert: any = o.insert
if (typeof insert === 'string') {
if (!insert || insert == '\n') continue
content += insert
continue
}
// @好友
if (insert && insert.mention) {
const { mention } = insert
content += ` ${mention.denotationChar}${mention.value} `
continue
}
// 图片
if (insert && insert.image) {
content += '[图片]'
continue
}
// 表情
if (insert && insert.emoji) {
content += insert.emoji.alt
continue
}
}
return content
}
export function isEmptyDelta(delta: Delta): boolean {
return delta.ops.length == 1 && delta.ops[0].insert == '\n'
}

View File

@ -63,6 +63,9 @@ watch(() => talkStore, (newValue, oldValue) => {
</script>
<style scoped lang="scss">
uni-page-body,page{
height: 100%;
}
.outer-layer {
overflow-y: auto;
flex: 1;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -4,7 +4,7 @@ import {uniStorage} from "@/utils/uniStorage.js"
import {ref} from 'vue'
export const useAuth = createGlobalState(() => {
// const token = useStorage('token', '', uniStorage)
const token = ref('30119d9978a6f3321fb4779c0040e997df4dd0dd0cf6b71119657617d2249ed783f940b0050d5be7e758740ea467afdf3eeb4d28fb5ea234af60ebe51fb218ffea38d3362de44912166520e87a6f38da2162e348845fabbb0db3604d4a2e7e543f680408fdbb166cbc70418235831e0b95aed8016b4a3b75feeec68212e4824da6e28c747409384ce136db6b9cd6e688cc40db73794e69f51be0920811cc437e51ca29fc82fccc1e98cb39b2577ef5b574460c853336d6afbe13149711d5e3fe')
const token = ref('30119d9978a6f3321fb4779c0040e997df4dd0dd0cf6b71119657617d2249ed783f940b0050d5be7e758740ea467afdf3eeb4d28fb5ea234af60ebe51fb218ffea38d3362de44912166520e87a6f38da5fa465eedb17110c9d5a7bb18d2a526249de3c56b42ad044dfada705af255bf9b021020b5f62f3bb26adf451d2736228924fc801fe89c57eaf8165fff1723136f4085f0a369bd83bf3abf52fa2e079f1241f62b1502a440bca65e0e954bd4e46b63a5bfc16ac9aec3104bd29b763bf03')
const refreshToken = useStorage('refreshToken', '', uniStorage)
const userInfo = useStorage('userInfo', {}, uniStorage)
const leaderList = useStorage('leaderList', [], uniStorage)

View File

@ -3,6 +3,6 @@ export * from '@/store/modules/user'
export * from '@/store/modules/talk'
// export * from '@/store/modules/editor'
export * from '@/store/modules/dialogue'
// export * from '@/store/modules/editor-draft'
export * from '@/store/modules/editor-draft'
export * from '@/store/modules/uploads'
// export * from '@/store/modules/note'

View File

@ -1,9 +1,117 @@
import wx001 from '@/static/image/emoji/001_微笑.png'
import pz002 from '@/static/image/emoji/002_撇嘴.png'
import se003 from '@/static/image/emoji/003_色.png'
import fd004 from '@/static/image/emoji/004_发呆.png'
import dd005 from '@/static/image/emoji/005_得意.png'
import ll006 from '@/static/image/emoji/006_流泪.png'
import hs007 from '@/static/image/emoji/007_害羞.png'
import bz008 from '@/static/image/emoji/008_闭嘴.png'
import sh009 from '@/static/image/emoji/009_睡.png'
import dc010 from '@/static/image/emoji/010_大哭.png'
import gg011 from '@/static/image/emoji/011_尴尬.png'
import fl012 from '@/static/image/emoji/012_发怒.png'
import tp013 from '@/static/image/emoji/013_调皮.png'
import cz014 from '@/static/image/emoji/014_呲牙.png'
import jy015 from '@/static/image/emoji/015_惊讶.png'
import nd016 from '@/static/image/emoji/016_难过.png'
import jiong017 from '@/static/image/emoji/017_囧.png'
import zk018 from '@/static/image/emoji/018_抓狂.png'
import t019 from '@/static/image/emoji/019_吐.png'
import tx020 from '@/static/image/emoji/020_偷笑.png'
import ak021 from '@/static/image/emoji/021_愉快.png'
import by022 from '@/static/image/emoji/022_白眼.png'
import am023 from '@/static/image/emoji/023_傲慢.png'
import k024 from '@/static/image/emoji/024_困.png'
import jk025 from '@/static/image/emoji/025_惊恐.png'
import hx026 from '@/static/image/emoji/026_憨笑.png'
import db027 from '@/static/image/emoji/027_悠闲.png'
import zm028 from '@/static/image/emoji/028_咒骂.png'
import yw029 from '@/static/image/emoji/029_疑问.png'
import x030 from '@/static/image/emoji/030_嘘.png'
import y031 from '@/static/image/emoji/031_晕.png'
import s032 from '@/static/image/emoji/032_衰.png'
import kt033 from '@/static/image/emoji/033_骷髅.png'
import qd034 from '@/static/image/emoji/034_敲打.png'
import zj035 from '@/static/image/emoji/035_再见.png'
import ch036 from '@/static/image/emoji/036_擦汗.png'
import kb037 from '@/static/image/emoji/037_抠鼻.png'
import zz038 from '@/static/image/emoji/038_鼓掌.png'
import hx039 from '@/static/image/emoji/039_坏笑.png'
import rh040 from '@/static/image/emoji/040_右哼哼.png'
import bs041 from '@/static/image/emoji/041_鄙视.png'
import wq042 from '@/static/image/emoji/042_委屈.png'
import kq043 from '@/static/image/emoji/043_快哭了.png'
import xs044 from '@/static/image/emoji/044_阴险.png'
import qq045 from '@/static/image/emoji/045_亲亲.png'
import kl046 from '@/static/image/emoji/046_可怜.png'
import xl047 from '@/static/image/emoji/047_笑脸.png'
import sb048 from '@/static/image/emoji/048_生病.png'
import lh049 from '@/static/image/emoji/049_脸红.png'
import ptwx050 from '@/static/image/emoji/050_破涕为笑.png'
import kj051 from '@/static/image/emoji/051_恐惧.png'
import sw052 from '@/static/image/emoji/052_失望.png'
import wy053 from '@/static/image/emoji/053_无语.png'
import hh054 from '@/static/image/emoji/054_嘿哈.png'
import wl055 from '@/static/image/emoji/055_捂脸.png'
import jx056 from '@/static/image/emoji/056_奸笑.png'
import jz057 from '@/static/image/emoji/057_机智.png'
import zm058 from '@/static/image/emoji/058_皱眉.png'
import ye059 from '@/static/image/emoji/059_耶.png'
import cg060 from '@/static/image/emoji/060_吃瓜.png'
import jy061 from '@/static/image/emoji/061_加油.png'
import han062 from '@/static/image/emoji/062_汗.png'
import ta063 from '@/static/image/emoji/063_天啊.png'
import emm064 from '@/static/image/emoji/064_Emm.png'
import shh065 from '@/static/image/emoji/065_社会社会.png'
import wc066 from '@/static/image/emoji/066_旺柴.png'
import hd067 from '@/static/image/emoji/067_好的.png'
import df068 from '@/static/image/emoji/068_打脸.png'
import w069 from '@/static/image/emoji/069_哇.png'
import fb070 from '@/static/image/emoji/070_翻白眼.png'
import lz071 from '@/static/image/emoji/071_666.png'
import mkwk072 from '@/static/image/emoji/072_让我看看.png'
import tx073 from '@/static/image/emoji/073_叹气.png'
import gs074 from '@/static/image/emoji/074_苦涩.png'
import lk075 from '@/static/image/emoji/075_裂开.png'
import pf076 from '@/static/image/emoji/076_嘴唇.png'
import ax077 from '@/static/image/emoji/077_爱心.png'
import xz078 from '@/static/image/emoji/078_心碎.png'
import b079 from '@/static/image/emoji/079_拥抱.png'
import qz080 from '@/static/image/emoji/080_强.png'
import r081 from '@/static/image/emoji/081_弱.png'
import ws082 from '@/static/image/emoji/082_握手.png'
import ss083 from '@/static/image/emoji/083_胜利.png'
import bq084 from '@/static/image/emoji/084_抱拳.png'
import g085 from '@/static/image/emoji/085_勾引.png'
import qd086 from '@/static/image/emoji/086_拳头.png'
import ok087 from '@/static/image/emoji/087_OK.png'
import h088 from '@/static/image/emoji/088_合十.png'
import pj089 from '@/static/image/emoji/089_啤酒.png'
import kf090 from '@/static/image/emoji/090_咖啡.png'
import dg091 from '@/static/image/emoji/091_蛋糕.png'
import mz092 from '@/static/image/emoji/092_玫瑰.png'
import j093 from '@/static/image/emoji/093_凋谢.png'
import c094 from '@/static/image/emoji/094_菜刀.png'
import zz095 from '@/static/image/emoji/095_炸弹.png'
import bb096 from '@/static/image/emoji/096_便便.png'
import yl097 from '@/static/image/emoji/097_月亮.png'
import ty098 from '@/static/image/emoji/098_太阳.png'
import qz099 from '@/static/image/emoji/099_庆祝.png'
import lw100 from '@/static/image/emoji/100_礼物.png'
import hb101 from '@/static/image/emoji/101_红包.png'
import f102 from '@/static/image/emoji/102_發.png'
import fu103 from '@/static/image/emoji/103_福.png'
import yh104 from '@/static/image/emoji/104_烟花.png'
import bz105 from '@/static/image/emoji/105_爆竹.png'
import zt106 from '@/static/image/emoji/106_猪头.png'
import tt107 from '@/static/image/emoji/107_跳跳.png'
import fd108 from '@/static/image/emoji/108_发抖.png'
import zq109 from '@/static/image/emoji/109_转圈.png'
/**
/**
/**
* 动态表情
*/
@ -13,167 +121,219 @@ export const emojis = {
'[撇嘴]':
`<img class='emoji' src='${pz002}'>`,
'[色]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/2.gif'>",
`<img class='emoji' src='${se003}'>`,
'[发呆]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/3.gif'>",
`<img class='emoji' src='${fd004}'>`,
'[得意]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/4.gif'>",
`<img class='emoji' src='${dd005}'>`,
'[流泪]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/5.gif'>",
`<img class='emoji' src='${ll006}'>`,
'[害羞]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/6.gif'>",
`<img class='emoji' src='${hs007}'>`,
'[闭嘴]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/7.gif'>",
`<img class='emoji' src='${bz008}'>`,
'[睡]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/8.gif'>",
`<img class='emoji' src='${sh009}'>`,
'[大哭]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/9.gif'>",
`<img class='emoji' src='${dc010}'>`,
'[尴尬]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/10.gif'>",
`<img class='emoji' src='${gg011}'>`,
'[发怒]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/11.gif'>",
`<img class='emoji' src='${fl012}'>`,
'[调皮]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/12.gif'>",
`<img class='emoji' src='${tp013}'>`,
'[呲牙]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/13.gif'>",
`<img class='emoji' src='${cz014}'>`,
'[惊讶]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/14.gif'>",
`<img class='emoji' src='${jy015}'>`,
'[难过]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/15.gif'>",
'[酷]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/16.gif'>",
'[冷汗]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/17.gif'>",
`<img class='emoji' src='${nd016}'>`,
'[囧]':
`<img class='emoji' src='${jiong017}'>`,
'[抓狂]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/18.gif'>",
`<img class='emoji' src='${zk018}'>`,
'[吐]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/19.gif'>",
`<img class='emoji' src='${t019}'>`,
'[偷笑]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/20.gif'>",
`<img class='emoji' src='${tx020}'>`,
'[可爱]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/21.gif'>",
`<img class='emoji' src='${ak021}'>`,
'[白眼]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/22.gif'>",
`<img class='emoji' src='${by022}'>`,
'[傲慢]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/23.gif'>",
'[饥饿]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/24.gif'>",
`<img class='emoji' src='${am023}'>`,
'[困]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/25.gif'>",
`<img class='emoji' src='${k024}'>`,
'[惊恐]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/26.gif'>",
'[流汗]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/27.gif'>",
`<img class='emoji' src='${jk025}'>`,
'[憨笑]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/28.gif'>",
`<img class='emoji' src='${hx026}'>`,
'[大兵]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/29.gif'>",
'[奋斗]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/30.gif'>",
`<img class='emoji' src='${db027}'>`,
'[咒骂]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/31.gif'>",
`<img class='emoji' src='${zm028}'>`,
'[疑问]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/32.gif'>",
`<img class='emoji' src='${yw029}'>`,
'[嘘]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/33.gif'>",
`<img class='emoji' src='${x030}'>`,
'[晕]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/34.gif'>",
'[折磨]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/35.gif'>",
`<img class='emoji' src='${y031}'>`,
'[衰]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/36.gif'>",
`<img class='emoji' src='${s032}'>`,
'[骷髅]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/37.gif'>",
`<img class='emoji' src='${kt033}'>`,
'[敲打]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/38.gif'>",
`<img class='emoji' src='${qd034}'>`,
'[再见]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/39.gif'>",
`<img class='emoji' src='${zj035}'>`,
'[擦汗]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/40.gif'>",
`<img class='emoji' src='${ch036}'>`,
'[抠鼻]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/41.gif'>",
`<img class='emoji' src='${kb037}'>`,
'[鼓掌]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/42.gif'>",
'[糗大了]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/43.gif'>",
`<img class='emoji' src='${zz038}'>`,
'[坏笑]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/44.gif'>",
'[左哼哼]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/45.gif'>",
`<img class='emoji' src='${hx039}'>`,
'[右哼哼]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/46.gif'>",
'[哈欠]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/47.gif'>",
`<img class='emoji' src='${rh040}'>`,
'[鄙视]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/48.gif'>",
`<img class='emoji' src='${bs041}'>`,
'[委屈]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/49.gif'>",
`<img class='emoji' src='${wq042}'>`,
'[快哭了]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/50.gif'>",
`<img class='emoji' src='${kq043}'>`,
'[阴险]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/51.gif'>",
`<img class='emoji' src='${xs044}'>`,
'[亲亲]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/52.gif'>",
'[吓]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/53.gif'>",
`<img class='emoji' src='${qq045}'>`,
'[可怜]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/54.gif'>",
'[菜刀]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/55.gif'>",
'[西瓜]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/56.gif'>",
'[啤酒]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/57.gif'>",
'[篮球]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/58.gif'>",
'[咖啡]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/60.gif'>",
'[饭]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/61.gif'>",
'[玫瑰]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/63.gif'>",
'[凋谢]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/64.gif'>",
'[示爱]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/65.gif'>",
`<img class='emoji' src='${kl046}'>`,
'[笑脸]':
`<img class='emoji' src='${xl047}'>`,
'[生病]':
`<img class='emoji' src='${sb048}'>`,
'[脸红]':
`<img class='emoji' src='${lh049}'>`,
'[破涕为笑]':
`<img class='emoji' src='${ptwx050}'>`,
'[恐惧]':
`<img class='emoji' src='${kj051}'>`,
'[失望]':
`<img class='emoji' src='${sw052}'>`,
'[无语]':
`<img class='emoji' src='${wy053}'>`,
'[嘿哈]':
`<img class='emoji' src='${hh054}'>`,
'[捂脸]':
`<img class='emoji' src='${wl055}'>`,
'[奸笑]':
`<img class='emoji' src='${jx056}'>`,
'[机智]':
`<img class='emoji' src='${jz057}'>`,
'[皱眉]':
`<img class='emoji' src='${zm058}'>`,
'[耶]':
`<img class='emoji' src='${ye059}'>`,
'[吃瓜]':
`<img class='emoji' src='${cg060}'>`,
'[加油]':
`<img class='emoji' src='${jy061}'>`,
'[汗]':
`<img class='emoji' src='${han062}'>`,
'[天啊]':
`<img class='emoji' src='${ta063}'>`,
'[Emm]':
`<img class='emoji' src='${emm064}'>`,
'[社会社会]':
`<img class='emoji' src='${shh065}'>`,
'[旺柴]':
`<img class='emoji' src='${wc066}'>`,
'[好的]':
`<img class='emoji' src='${hd067}'>`,
'[打脸]':
`<img class='emoji' src='${df068}'>`,
'[哇]':
`<img class='emoji' src='${w069}'>`,
'[翻白眼]':
`<img class='emoji' src='${fb070}'>`,
'[666]':
`<img class='emoji' src='${lz071}'>`,
'[让我看看]':
`<img class='emoji' src='${mkwk072}'>`,
'[叹气]':
`<img class='emoji' src='${tx073}'>`,
'[苦涩]':
`<img class='emoji' src='${gs074}'>`,
'[裂开]':
`<img class='emoji' src='${lk075}'>`,
'[嘴唇]':
`<img class='emoji' src='${pf076}'>`,
'[爱心]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/66.gif'>",
`<img class='emoji' src='${ax077}'>`,
'[心碎]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/67.gif'>",
'[蛋糕]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/68.gif'>",
'[炸弹]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/70.gif'>",
'[刀]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/71.gif'>",
'[足球]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/72.gif'>",
'[礼物]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/77.gif'>",
`<img class='emoji' src='${xz078}'>`,
'[拥抱]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/78.gif'>",
`<img class='emoji' src='${b079}'>`,
'[强]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/79.gif'>",
`<img class='emoji' src='${qz080}'>`,
'[弱]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/80.gif'>",
`<img class='emoji' src='${r081}'>`,
'[握手]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/81.gif'>",
`<img class='emoji' src='${ws082}'>`,
'[胜利]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/82.gif'>",
`<img class='emoji' src='${ss083}'>`,
'[抱拳]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/83.gif'>",
`<img class='emoji' src='${bq084}'>`,
'[勾引]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/84.gif'>",
`<img class='emoji' src='${g085}'>`,
'[拳头]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/85.gif'>",
'[差劲]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/86.gif'>",
'[爱你]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/87.gif'>",
'[NO]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/88.gif'>",
`<img class='emoji' src='${qd086}'>`,
'[OK]':
"<img class='emoji' src='https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/89.gif'>"
`<img class='emoji' src='${ok087}'>`,
'[合十]':
`<img class='emoji' src='${h088}'>`,
'[啤酒]':
`<img class='emoji' src='${pj089}'>`,
'[咖啡]':
`<img class='emoji' src='${kf090}'>`,
'[蛋糕]':
`<img class='emoji' src='${dg091}'>`,
'[玫瑰]':
`<img class='emoji' src='${mz092}'>`,
'[凋谢]':
`<img class='emoji' src='${j093}'>`,
'[菜刀]':
`<img class='emoji' src='${c094}'>`,
'[炸弹]':
`<img class='emoji' src='${zz095}'>`,
'[便便]':
`<img class='emoji' src='${bb096}'>`,
'[月亮]':
`<img class='emoji' src='${yl097}'>`,
'[太阳]':
`<img class='emoji' src='${ty098}'>`,
'[庆祝]':
`<img class='emoji' src='${qz099}'>`,
'[礼物]':
`<img class='emoji' src='${lw100}'>`,
'[红包]':
`<img class='emoji' src='${hb101}'>`,
'[發]':
`<img class='emoji' src='${f102}'>`,
'[福]':
`<img class='emoji' src='${fu103}'>`,
'[烟花]':
`<img class='emoji' src='${yh104}'>`,
'[爆竹]':
`<img class='emoji' src='${bz105}'>`,
'[猪头]':
`<img class='emoji' src='${zt106}'>`,
'[跳跳]':
`<img class='emoji' src='${tt107}'>`,
'[发抖]':
`<img class='emoji' src='${fd108}'>`,
'[转圈]':
`<img class='emoji' src='${zq109}'>`,
}
const emojisKeys = Object.keys(emojis)

124
src/utils/functions.js Normal file
View File

@ -0,0 +1,124 @@
import {useAuth} from "@/store/auth";
const { token } = useAuth()
/**
* 通过图片url获取图片大小
*
* @param {String} imgsrc 例如图片名 D8x5f13a53dbc4b9_350x345.png
*/
export function getImageInfo(imgsrc) {
let data = {
width: 0,
height: 0
}
// 尝试从URL参数中获取
if (imgsrc.includes('?')) {
const urlParams = new URLSearchParams(imgsrc.split('?')[1])
const width = urlParams.get('width')
const height = urlParams.get('height')
if (width && height) {
return {
width: parseInt(width)*1.5,
height: parseInt(height)*1.5
}
}
}else{
return data
}
// 如果URL参数获取失败尝试从文件名格式获取
// let arr = imgsrc.split('_')
// if (arr.length == 1) return data
// let info = arr[arr.length - 1].match(/\d+x\d+/g)
// if (info == null) return data
// info = info[0].split('x')
// return {
// width: parseInt(info[0]),
// height: parseInt(info[1])
// }
}
/**
* 文件下载方法
*
* @param {Number} msgid
*/
export function download(msg_id) {
try {
let link = document.createElement('a')
// link.target = '_blank'
link.href = `${
import.meta.env.VITE_BASE_API
}/api/v1/talk/records/file/download?msg_id=${msg_id}&token=${token.value}`
link.click()
} catch (e) {
console.warn(e)
}
}
export function insertText(obj, str) {
if (document.selection) {
let sel = document.selection.createRange()
sel.text = str
} else if (typeof obj.selectionStart === 'number' && typeof obj.selectionEnd === 'number') {
let startPos = obj.selectionStart,
endPos = obj.selectionEnd,
cursorPos = startPos,
tmpStr = obj.value
obj.value = tmpStr.substring(0, startPos) + str + tmpStr.substring(endPos, tmpStr.length)
cursorPos += str.length
obj.selectionStart = obj.selectionEnd = cursorPos
obj.focus()
} else {
obj.value += str
}
}
export function countDownTime(second = 0) {
// 小于10 加0 处理
function formate0to9(arg) {
return arg < 10 ? `0${arg}` : arg
}
const hours = parseInt((second / 60 / 60) % 24, 10) //剩余的小时
const minutes = parseInt((second / 60) % 60, 10) //剩余的分钟
const seconds = parseInt(second % 60, 10) //剩余的秒数
return `${formate0to9(hours)}:${formate0to9(minutes)}:${formate0to9(seconds)}`
}
export function removeTags(str) {
return str.replace(/<\/?[^>]+>/gi, '')
}
export function downloadImage(src, name) {
let image = new Image()
image.setAttribute('crossOrigin', 'anonymous')
image.onload = function () {
let canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
let context = canvas.getContext('2d')
context.drawImage(image, 0, 0, image.width, image.height)
let url = canvas.toDataURL('image/png')
let a = document.createElement('a')
let event = new MouseEvent('click')
a.download = name || 'image.png'
a.href = url
a.dispatchEvent(event)
}
image.src = src
}
// 获取文件名后缀
export const getFileNameSuffix = (name) => {
const arr = name.split('.')
return arr[arr.length - 1]
}