Compare commits

...

12 Commits

Author SHA1 Message Date
1edb639ad9 Merge branch 'wyfMain-dev' 2025-05-27 11:24:42 +08:00
Phoenix
e3f2346d66 fix: 更新配置和组件逻辑
- 在Editor.vue中,优化成员列表的渲染逻辑,确保在特定条件下显示'所有人'选项
- 在FileMessage.vue中,修改上传进度显示条件,避免在未开始上传时显示进度圆环
- 在uploads.ts中,简化重试上传逻辑,移除不必要的暂停状态检查
- 在PanelContent.vue中,添加对重试操作的支持,确保能够针对特定项目进行重试
2025-05-27 11:20:55 +08:00
Phoenix
c91a70f86d 12 2025-05-26 17:00:09 +08:00
Phoenix
02ba7af6eb Merge branch 'main' into xingyy 2025-05-26 16:59:50 +08:00
Phoenix
19a6c89b76 fix: 修复上传进度显示和重试逻辑问题
- 在FileMessage.vue中,仅当上传进度大于0时显示进度圆环,避免初始状态显示
- 在PanelContent.vue中,为retry函数添加参数传递,确保重试操作针对特定项目
- 在uploads.ts中,添加暂停状态检查并处理上传失败时的进度回调
2025-05-26 16:58:12 +08:00
Phoenix
e2e0a3ea3a fix: 修复文件上传逻辑和UI问题
- 修复文件上传暂停/恢复逻辑错误,调整播放状态与上传动作的对应关系
- 为视频上传添加半透明蒙层提升用户体验
- 移除上传管理中的冗余字段和注释代码
- 调整确认框标题的padding样式
- 添加消息重发确认功能
2025-05-26 16:43:11 +08:00
Phoenix
5bda2be585 更新.env.test文件中的API地址,调整FileMessage.vue组件的样式,增加高度和灵活性,优化auth.js中的token获取逻辑,增强MultiSelectFooter.vue中的批量删除功能,添加确认框提示。 2025-05-26 12:00:30 +08:00
Phoenix
57f169ca78 12 2025-05-22 15:44:25 +08:00
Phoenix
470da9e7b7 1 2025-05-22 15:27:19 +08:00
Phoenix
c7df773b97 Merge branch 'main' of http://172.16.100.91:3000/scout666/chat-pc 2025-05-22 15:26:49 +08:00
Phoenix
b7ae8598b4 更新组件声明,新增SearchByCondition组件;调整FileMessage.vue的样式,增加高度;优化ImageMessage.vue中的图片样式,移除不必要的样式属性。 2025-05-22 15:26:48 +08:00
Phoenix
cba7e9205e git忽略 2025-05-22 15:10:20 +08:00
15 changed files with 194 additions and 225 deletions

2
.gitignore vendored
View File

@ -24,3 +24,5 @@ makefile
*.njsproj
*.sln
*.sw?
components.d.ts
auto-imports.d.ts

75
auto-imports.d.ts vendored
View File

@ -1,75 +0,0 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useDialog: typeof import('naive-ui')['useDialog']
const useId: typeof import('vue')['useId']
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
const useMessage: typeof import('naive-ui')['useMessage']
const useModel: typeof import('vue')['useModel']
const useNotification: typeof import('naive-ui')['useNotification']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

1
components.d.ts vendored
View File

@ -15,6 +15,7 @@ declare module 'vue' {
AvatarModule: typeof import('./src/components/avatar-module/index.vue')['default']
CodeMessage: typeof import('./src/components/talk/message/CodeMessage.vue')['default']
ConfigTab: typeof import('./src/components/group/manage/ConfigTab.vue')['default']
ConfirmBox: typeof import('./src/components/confirm-box/index.vue')['default']
ContactModal: typeof import('./src/components/user/ContactModal.vue')['default']
CustomBtn: typeof import('./src/components/common/customBtn.vue')['default']
CustomModal: typeof import('./src/components/common/customModal.vue')['default']

9
env/.env.test vendored
View File

@ -2,9 +2,10 @@ ENV = 'development'
VITE_BASE=/
VUE_APP_PREVIEW=false
VITE_BASE_API=http://114.218.158.24:8503
# VITE_BASE_API=http://192.168.88.21:9503
#VITE_BASE_API=http://192.168.88.21:9503
#VITE_SOCKET_API=ws://192.168.88.21:9504
VITE_BASE_API=http://114.218.158.24:8503
VITE_SOCKET_API=ws://114.218.158.24:8504
VITE_EPR_BASEURL=http://114.218.158.24:9020
VITE_SOCKET_API=ws://114.218.158.24:8504
# VITE_SOCKET_API=ws://192.168.88.21:9504
VUE_APP_WEBSITE_NAME=""

View File

@ -0,0 +1,49 @@
<script setup>
import { ref, watch } from 'vue'
import XNModal from '@/components/x-naive-ui/x-n-modal/index.vue'
const emit = defineEmits(['cancel','confirm'])
const show=defineModel('show')
const props = defineProps({
title:{
type:String,
default:'提示'
},
content:{
type:String,
default:'内容'
},
cancelText:{
type:String,
default:'取消'
},
confirmText:{
type:String,
default:'确定'
}
})
</script>
<template>
<XNModal v-model:show="show" :closable="false" class="w-724px" content-style="padding:0px" @after-leave="emit('after-leave')">
<div class="flex flex-col w-full px-25px pb-49px">
<div class="text-20px text-#1F2225 w-full text-center border-b-1px border-b-solid border-b-#E9E9E9 py-20px">{{ title }}</div>
<div class="py-60px text-center text-20px text-#1F2225">
{{ content }}
</div>
<div class="flex w-full justify-center">
<n-button color="#C7C7C9" class="text-14px text-#fff w-161px h-34px mr-10px"
@click="() => { show=false; emit('cancel') }"
>{{ cancelText }}</n-button>
<n-button color="#46299D" class="text-14px text-#fff w-161px h-34px"
@click="() => { show=false; emit('confirm') }"
>{{ confirmText }}</n-button>
</div>
</div>
</XNModal>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,32 @@
import { createVNode, nextTick, render } from 'vue'
import ConfirmBox from './index.vue'
export function confirmBox(options) {
return new Promise((resolve, reject) => {
const container = document.createElement('div')
document.body.appendChild(container)
const props = {
...options,
show: false,
onCancel: () => {
reject()
},
onAfterLeave:()=>{
render(null, container)
document.body.removeChild(container)
},
onConfirm: () => {
resolve()
},
}
const vnode = createVNode(ConfirmBox, props)
render(vnode, container)
nextTick(() => {
vnode.component.props.show = true
})
})
}

View File

@ -52,7 +52,6 @@ import { ServeUploadImage } from '@/api/upload'
import { uploadImg } from '@/api/upload'
// 线
import { useEventBus } from '@/hooks'
// Quill
Quill.register('formats/emoji', EmojiBlot) //
Quill.register('formats/quote', QuoteBlot) //
@ -147,12 +146,12 @@ const editorOption = {
if (!props.members.length) {
return renderList([])
}
let list = [
{ id: 0, nickname: '所有人', avatar: defAvatar, value: '所有人' },
...props.members
]
] as any
if((dialogueStore.groupInfo as any).is_manager){
list.unshift({ id: 0, nickname: '所有人', avatar: defAvatar, value: '所有人' })
}
const items = list.filter(
(item: any) => item.nickname.toLowerCase().indexOf(searchTerm) !== -1
)

View File

@ -71,9 +71,8 @@ function getFileExtension(filename) {
//
const togglePlay = () => {
isPlaying.value = !isPlaying.value
if (props.extra.is_uploading && props.extra.upload_id) {
const action = isPlaying.value ? 'resumeUpload' : 'pauseUpload'
const action = isPlaying.value ? 'pauseUpload' : 'resumeUpload'
uploadsStore[action](props.extra.upload_id)
}
}
@ -113,7 +112,7 @@ const handleDownload = () => {
</script>
<template>
<div class="file-message" @click="handleClick">
<div class="file-message flex flex-col" @click="handleClick">
<!-- 文件头部信息 -->
<div class="file-header">
<!-- 文件名 -->
@ -123,8 +122,8 @@ const handleDownload = () => {
<img class="file-icon" :src="fileInfo.icon" alt="文件图标">
<!-- 上传进度圆环 - 上传状态 -->
<div v-if="extra.is_uploading" class="progress-overlay">
<div class="circle-progress-container" @click="togglePlay">
<div v-if="extra.is_uploading&&extra.percentage!==-1" class="progress-overlay">
<div class="circle-progress-container" @click.stop="togglePlay">
<svg class="circle-progress" width="20" height="20" viewBox="0 0 20 20">
<!-- 底色圆环 -->
<circle
@ -150,20 +149,21 @@ const handleDownload = () => {
/>
<!-- 暂停/播放图标 -->
<g v-if="isPlaying" class="pause-icon">
<g v-if="isPlaying" class="play-icon">
<rect x="6" y="6" width="8" height="8" :fill="fileInfo.color" />
</g>
<g v-else class="pause-icon">
<rect x="7" y="5" width="2" height="10" :fill="fileInfo.color" />
<rect x="11" y="5" width="2" height="10" :fill="fileInfo.color" />
</g>
<g v-else class="play-icon">
<rect x="6" y="6" width="8" height="8" :fill="fileInfo.color" />
</g>
</svg>
</div>
</div>
</div>
</div>
<!-- 文件大小信息 -->
<div class="flex justify-between items-center">
<div class="flex justify-between items-center grow-1">
<div class="file-size">{{ fileFormatSize(extra.size) }}</div>
<div class="flex items-center" v-if="!extra.is_uploading">
<div class="flex items-center" @click.stop="handleDownload"> <img class="w-11.7px h-11.74px mr-7px" src="@/assets/image/dofd.png" alt=""> <span class="text-12px text-#46299D">下载</span></div>
@ -178,6 +178,7 @@ const handleDownload = () => {
.file-message {
width: 243px;
background-color: #fff;
height: 110px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 0 14px;
@ -205,6 +206,7 @@ const handleDownload = () => {
}
.file-icon-container {
height: 48px;
position: relative;
}
@ -228,7 +230,6 @@ const handleDownload = () => {
.file-size {
color: #747474;
font-size: 12px;
padding: 5px 0 11px;
}
.circle-progress-container {

View File

@ -35,7 +35,7 @@ const img = (src: string, width = 200) => {
:class="{ left: data.float === 'left' }"
:style="img(extra.url, 350)"
>
<n-image :src="extra.url" />
<n-image class="h-149px" :src="extra.url" />
</section>
</template>
<style lang="less" scoped>
@ -44,9 +44,6 @@ const img = (src: string, width = 200) => {
padding: 5px;
border-radius: 5px;
background: var(--im-message-left-bg-color);
min-width: 30px;
min-height: 30px;
max-width:240px;
height:149px
&.left {
background: var(--im-message-right-bg-color);

View File

@ -137,7 +137,8 @@ function resumeUpload(e) {
<!-- <n-image :src="extra.cover" preview-disabled /> -->
<video :src="props.extra.url" :controls="false"></video>
<!-- 上传进度时的黑色半透明蒙层 -->
<div v-if="extra.is_uploading && !uploadFailed" class="upload-mask"></div>
<!-- 上传进度显示 -->
<div v-if="extra.is_uploading && !uploadFailed" class="upload-progress">
<n-progress
@ -245,6 +246,17 @@ function resumeUpload(e) {
justify-content: center;
}
.upload-mask {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
border-radius: 5px;
}
.upload-progress {
position: absolute;
left: 50%;
@ -255,6 +267,7 @@ function resumeUpload(e) {
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
.upload-control {
position: absolute;

View File

@ -79,28 +79,6 @@ export const useUploadsStore = defineStore('uploads', {
findItemByClientId(clientUploadId: string): UploadItem | undefined {
return this.items.find((item) => item.client_upload_id === clientUploadId)
},
// // 暂停文件上传
// pauseUpload(uploadId: string) {
// const item = this.findItem(uploadId)
// if (!item) return
// item.is_paused = true
// console.log(`暂停上传: ${uploadId}`)
// },
// 恢复文件上传
// resumeUpload(uploadId: string) {
// const item = this.findItem(uploadId)
// if (!item) return
// item.is_paused = false
// console.log(`恢复上传: ${uploadId}`)
// // 继续上传
// this.triggerUpload(uploadId)
// },
// 发送上传消息
async sendUploadMessage(item: any) {
try {
@ -119,8 +97,7 @@ export const useUploadsStore = defineStore('uploads', {
file: File,
talkType: number,
receiverId: number,
username: string,
uploadId: string,
clientUploadId: string,
onProgress: (percentage: number) => void,
onComplete: (data: any) => void
) {
@ -147,13 +124,11 @@ export const useUploadsStore = defineStore('uploads', {
talk_type: talkType,
receiver_id: receiverId,
upload_id: upload_id,
client_upload_id: uploadId, // 客户端生成的上传ID用于前端标识
client_upload_id: clientUploadId, // 客户端生成的上传ID用于前端标识
uploadIndex: 0,
percentage: 0,
status: 0, // 文件上传状态 0:等待上传 1:上传中 2:上传完成 3:网络异常
files: fileChunks,
avatar: '',
username: username,
is_paused: false,
onProgress: onProgress,
onComplete: onComplete,
@ -162,7 +137,7 @@ export const useUploadsStore = defineStore('uploads', {
this.isShow = false // 不显示上传管理抽屉
// 开始上传分片
this.triggerUpload(upload_id, uploadId)
this.triggerUpload(upload_id, clientUploadId)
} else {
message.error(res.message)
onProgress(-1) // 通知上传失败
@ -198,16 +173,15 @@ export const useUploadsStore = defineStore('uploads', {
// 上传当前分片
try {
const res = await ServeFileSubareaUpload(form)
// 获取最新的项目状态,确保仍然存在且没有被暂停
const updatedItem = this.findItem(uploadId)
if (!updatedItem || updatedItem.is_paused) return
const updatedItem:any = this.findItem(uploadId)
if (res.code == 200) {
// 当前分片上传成功,增加索引
updatedItem.uploadIndex++
// 计算上传进度
const percentage = (updatedItem.uploadIndex / updatedItem.files.length) * 100
updatedItem.percentage = parseFloat(percentage.toFixed(1))
@ -216,9 +190,6 @@ export const useUploadsStore = defineStore('uploads', {
if (updatedItem.onProgress) {
updatedItem.onProgress(updatedItem.percentage)
}
// if (clientUploadId) {
// this.dialogueStore.updateUploadProgress(clientUploadId, percentage)
// }
// 检查是否全部上传完成
if (updatedItem.uploadIndex === updatedItem.files.length) {
// 所有分片上传完成
@ -230,12 +201,12 @@ export const useUploadsStore = defineStore('uploads', {
this.triggerUpload(uploadId, clientUploadId)
}
} else {
updatedItem.onProgress(-1)
// 上传失败处理
console.error(`分片上传失败,错误码: ${res.code},错误信息: ${res.message || '未知错误'}`);
updatedItem.status = 3
// 尝试重试当前分片
this.retryUpload(uploadId, clientUploadId, res.message || '上传失败,请重试')
}
} catch (error) {
console.error("分片上传错误:", error);
@ -248,37 +219,10 @@ export const useUploadsStore = defineStore('uploads', {
if (updatedItem.is_paused) return
updatedItem.status = 3
// 尝试重试当前分片
this.retryUpload(uploadId, clientUploadId, '网络错误,正在重试')
}
},
// 重试上传
retryUpload(uploadId: string, clientUploadId?: string, errorMessage?: string) {
const item = this.findItem(uploadId)
if (!item) return
// 如果有暂停/恢复按钮,先告知用户上传出错
if (item.onProgress) {
item.onProgress(-1)
}
// 显示错误提示
message.warning(errorMessage)
// 创建一个5秒后自动重试的机制
setTimeout(() => {
const currentItem = this.findItem(uploadId)
if (!currentItem) return
// 如果用户没有手动暂停,则自动重试
if (!currentItem.is_paused) {
console.log('正在重试上传分片...');
this.triggerUpload(uploadId, clientUploadId)
}
}, 5000)
},
// 完成上传
async completeUpload(item: UploadItem, clientUploadId: string) {
@ -328,24 +272,22 @@ export const useUploadsStore = defineStore('uploads', {
},
// 重试文件上传
retryCommonUpload(uploadId: string, errorMessage: string) {
const item = this.findItem(uploadId)
retryCommonUpload(clientUploadId: string) {
const item = this.findItemByClientId(clientUploadId)
if (!item) return
// 显示错误提示
message.warning(errorMessage)
// 重新初始化上传,以便重新获取分片信息
this.initUploadFile(
item.file,
item.talk_type,
item.receiver_id,
clientUploadId,
item.onProgress || ((percentage: number) => {}),
item.onComplete || ((data: any) => {})
)
// 创建一个5秒后自动重试的机制
setTimeout(() => {
const currentItem = this.findItem(uploadId)
if (!currentItem) return
// 如果用户没有手动暂停,则自动重试
if (!currentItem.is_paused) {
console.log('正在重试上传分片...');
this.triggerUpload(uploadId)
}
}, 5000)
// 从上传列表中移除旧的上传项
this.items = this.items.filter(i => i.client_upload_id !== clientUploadId)
},
}
})

View File

@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b8920ba7848670d6635bc65bc81e459c2d265c727a7b12d1bef76bc3ef2db21c5321a0369a434ada2629282bf55674fe5b6052fa62f66e10cdd8652c28aa0f4afd42fdc72282e2e591e7b7c0c17a3b85eca'
return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22ab23a552e0c3f606946dcb914a52b692e10d823cc7f43027127359e7ee8555d956e7e095946931ceaa3877675584b0a0a4fc690c8018712b306050ebbdea92037aea31d66d65004be26d3c696abc4c29'
}
/**

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { useDialogueStore } from '@/store'
import { Share, ShareThree, Delete, Close } from '@icon-park/vue-next'
import {confirmBox} from '@/components/confirm-box/service.js'
import ContactModal from '@/components/user/ContactModal.vue'
@ -31,12 +31,19 @@ const onSingleForward = () => {
}
const onMultiDelete = () => {
confirmBox({
content:'确定删除聊天记录',
confirmText:'删除'
}).then(()=>{
let msgIds = dialogueStore.selectItems.map((item: any) => item.msg_id)
if (!msgIds.length) return
dialogueStore.ApiDeleteRecord(msgIds)
})
//
let msgIds = dialogueStore.selectItems.map((item: any) => item.msg_id)
if (!msgIds.length) return
dialogueStore.ApiDeleteRecord(msgIds)
}
const onContactModal = (data: { receiver_id: number; talk_type: number }[]) => {

View File

@ -14,9 +14,10 @@ import { ITalkRecord } from '@/types/chat'
import { EditorConst } from '@/constant/event-bus'
import { useInject, useTalkRecord, useUtil } from '@/hooks'
import { ExclamationCircleFilled } from '@ant-design/icons-vue'
import { useUserStore } from '@/store'
import { useUserStore ,useUploadsStore} from '@/store'
import RevokeMessage from '@/components/talk/message/RevokeMessage.vue'
import { voiceToText } from '@/api/chat.js'
import {confirmBox} from '@/components/confirm-box/service.js'
const props = defineProps({
uid: {
type: Number,
@ -41,7 +42,7 @@ const props = defineProps({
})
const { loadConfig, records, onLoad, onRefreshLoad, onJumpMessage } = useTalkRecord(props.uid)
const uploadsStore = useUploadsStore()
const { useMessage } = useUtil()
const { dropdown, showDropdownMenu, closeDropdownMenu } = useMenu()
const { showUserInfoModal } = useInject()
@ -314,6 +315,23 @@ watch(
// onMounted(() => {
// onLoad({ ...props, limit: 30 })
// })
const retry=(item:any)=>{
confirmBox({
content:'确定重发吗'
}).then(()=>{
uploadsStore.retryCommonUpload(item.extra.upload_id)
})
}
const onContextMenuAvatar=(e:any,item:any)=>{
console.log('item',item)
e.preventDefault()
bus.emit(EditorConst.Mention, {
id: item.user_id,
value: item.nickname
})
}
</script>
<template>
@ -378,13 +396,14 @@ watch(
:src="item.avatar"
:size="42"
:username="item.nickname"
@contextmenu.prevent="onContextMenuAvatar($event, item)"
@click="showUserInfoModal(item.erp_user_id, item.user_id)"
/>
</aside>
<!-- 主体信息 -->
<main class="main-column">
<div class="talk-title">
<!-- <div class="talk-title">
<span
class="nickname pointer"
v-show="talk_type == 2 && item.float == 'left'"
@ -393,8 +412,15 @@ watch(
<span class="at">@</span>{{ item.nickname }}
</span>
<span>{{ parseTime(item.created_at, '{y}/{m}/{d} {h}:{i}') }}</span>
</div> -->
<div class="talk-title">
<span class="mr-7px"
v-show="talk_type == 2 && item.float == 'left'"
>{{ item.nickname }}
</span>
<span>{{ parseTime(item.created_at, '{y}/{m}/{d} {h}:{i}') }}</span>
</div>
<div
class="talk-content"
:class="{ pointer: dialogueStore.isOpenMultiSelect }"
@ -414,7 +440,7 @@ watch(
"
class="mr-10px"
>
<n-button text style="font-size: 20px;">
<n-button text style="font-size: 20px;" @click="retry(item)">
<n-icon color="#CF3050">
<ExclamationCircleFilled />
</n-icon>

View File

@ -116,15 +116,13 @@ const onSendVideoEvent = async ({ data }) => {
msg_type: 5, //
user_id: props.uid,
receiver_id: props.receiver_id,
nickname: '我', //
avatar: userStore.avatar, //
is_revoke: 0,
is_mark: 0,
is_read: 1,
content: '',
created_at: parseTime(new Date(), '{y}-{m}-{d} {h}:{i}'),
extra: {
url: '', //
url: '',
size: data.size,
is_uploading: true,
upload_id: uploadId,
@ -141,35 +139,12 @@ const onSendVideoEvent = async ({ data }) => {
data,
props.talk_type,
props.receiver_id,
dialogueStore.talk.username,
uploadId,
async (percentage) => {
dialogueStore.updateUploadProgress(uploadId, percentage)
},
async () => {
dialogueStore.batchDelDialogueRecord([uploadId])
// console.log('videoData', videoData)
// //
// //
// dialogueStore.completeUpload(uploadId, {
// url: videoData.data.ori_url,
// cover: videoData.data.cover_url
// })
// //
// let finalMessage = {
// type: 'video',
// url: videoData.data.ori_url,
// size: data.size
// }
// //
// onSendMessage(finalMessage, () => {
// //
// dialogueStore.batchDelDialogueRecord([uploadId])
// })
}
)
}
@ -185,10 +160,10 @@ const onSendFileEvent = ({ data }) => {
if (data.size > maxsize) {
return window['$message'].warning('上传文件不能超过100M!')
}
const uploadId = `file-${Date.now()}-${Math.floor(Math.random() * 1000)}`
const clientUploadId = `file-${Date.now()}-${Math.floor(Math.random() * 1000)}`
const tempMessage = {
msg_id: uploadId,
msg_id: clientUploadId,
sequence: Date.now(),
talk_type: props.talk_type,
msg_type: 6,
@ -204,20 +179,19 @@ const onSendFileEvent = ({ data }) => {
url: '',
size: data.size,
is_uploading: true,
upload_id: uploadId,
upload_id: clientUploadId,
percentage: 0
},
erp_user_id: 4692,
float: 'right'
}
dialogueStore.addDialogueRecord(tempMessage)
uploadsStore.initUploadFile(data, props.talk_type, props.receiver_id, dialogueStore.talk.username,uploadId,
uploadsStore.initUploadFile(data, props.talk_type, props.receiver_id,clientUploadId,
async (percentage) => {
dialogueStore.updateUploadProgress(uploadId, percentage)
dialogueStore.updateUploadProgress(clientUploadId, percentage)
},
async () => {
dialogueStore.batchDelDialogueRecord([uploadId])
dialogueStore.batchDelDialogueRecord([clientUploadId])
}
)
}