添加工单附件 及样式
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
<span :class="['tag-item', { 'tag-active': tagActiveMap[item.id] === item1.id }]">
|
||||
{{ item1.name }}
|
||||
</span>
|
||||
<el-badge :value="item1.count" :max="99" class="itemtag" type="primary"> </el-badge>
|
||||
<!-- <el-badge :value="item1.count" :max="99" class="itemtag" type="primary"> </el-badge> -->
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,7 +64,7 @@
|
||||
<span :class="['tag-item', { 'tag-active': tagActiveMap[item.id] === item1.id }]">
|
||||
{{ item1.name }}
|
||||
</span>
|
||||
<el-badge :value="item1.count" :max="99" class="itemtag" type="primary"> </el-badge>
|
||||
<!-- <el-badge :value="item1.count" :max="99" class="itemtag" type="primary"> </el-badge> -->
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +91,10 @@
|
||||
<span>
|
||||
{{scope.row.countryInfo? scope.row.countryInfo.cn_addr : ''}}
|
||||
</span>
|
||||
<el-tag class="steer" type="warning" v-if="scope.row.countryInfo">{{ scope.row.countryInfo.steering }}</el-tag>
|
||||
<span v-if="scope.row.countryInfo">
|
||||
<el-tag class="steer" type="warning" v-if="scope.row.countryInfo.steering=='左舵'">{{ scope.row.countryInfo.steering }}</el-tag>
|
||||
<el-tag class="steer" type="success" v-else-if="scope.row.countryInfo.steering=='右舵'">{{ scope.row.countryInfo.steering }}</el-tag>
|
||||
</span>
|
||||
<!-- <span class="steer" v-if="scope.row.countryInfo">{{ scope.row.countryInfo.steering }}</span> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
lass="customer-table"
|
||||
>
|
||||
<template #default>
|
||||
<el-table-column prop="id" label="用户ID" align="center" />
|
||||
<!-- <el-table-column prop="id" label="用户ID" align="center" /> -->
|
||||
<el-table-column prop="sn" label="SN" align="center" />
|
||||
<el-table-column prop="follow" label="头像" align="center">
|
||||
<template #default="scope">
|
||||
@@ -39,13 +39,14 @@
|
||||
alt="头像"
|
||||
class="avatar"
|
||||
@click="handleAvatarClick(scope.row.avatar)"
|
||||
style="cursor: pointer;"
|
||||
style="cursor: pointer"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="用户名称" align="center" />
|
||||
<el-table-column prop="name" label="名字" align="center" />
|
||||
<el-table-column prop="phone" label="电话" align="center" />
|
||||
<el-table-column prop="email" label="邮箱" align="center" />
|
||||
<el-table-column prop="corp_name" label="所属公司" align="center" />
|
||||
<el-table-column prop="follow" label="状态" align="center">
|
||||
<template #default="scope">
|
||||
<span :class="statusClass(scope.row.status)">
|
||||
|
||||
@@ -183,18 +183,96 @@
|
||||
<div class="chat-messages" ref="messageContainer">
|
||||
<template v-for="(message, index) in messages" :key="index">
|
||||
<div :class="['message-item', String(message.user_id) === String(userid) ? 'message-right' : 'message-left']">
|
||||
<el-avatar :size="32" :src="String(message.user_id) === String(userid) ? meAvatar : aiAvatar" class="message-avatar" />
|
||||
<el-avatar :size="32" :src="message.user_avatar" class="message-avatar" />
|
||||
<div class="message-content">
|
||||
<div class="message-info">
|
||||
<span class="sender-name">{{ message.user_id }}</span>
|
||||
<span class="sender-name">{{ message.user_name }}</span>
|
||||
<span class="message-time">{{ message.updated_at }}</span>
|
||||
</div>
|
||||
<div class="message-text">{{ message.content }}</div>
|
||||
<!-- 附件显示区域 -->
|
||||
<div class="message-attachments" v-if="message.attachment && message.attachment.length > 0">
|
||||
<div class="attachment-item" v-for="(attachment, attIndex) in message.attachment" :key="attIndex">
|
||||
<template v-if="/\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(attachment.original_name)">
|
||||
<img
|
||||
:src="attachment.storage_path_full"
|
||||
:alt="attachment.original_name"
|
||||
class="attachment-thumb"
|
||||
@click="handleChatImageClick(attachment.storage_path_full)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="/\.(mp4|webm|ogg)$/i.test(attachment.original_name)">
|
||||
<video
|
||||
:src="attachment.storage_path_full"
|
||||
controls
|
||||
class="attachment-thumb"
|
||||
@click.prevent="handleChatVideoClick(attachment.storage_path_full)"
|
||||
></video>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="file-attachment">
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
<span class="file-name">{{ attachment.original_name }}</span>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
@click="downloadAttachment(attachment)"
|
||||
>
|
||||
下载
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="chat-input" v-if="hasAuth('work_order_self@conversation_add')">
|
||||
<!-- 附件上传区域 -->
|
||||
<div class="chat-attachment-upload">
|
||||
<el-upload
|
||||
v-model:file-list="chatFileList"
|
||||
class="chat-upload"
|
||||
:action="actionImageUplode"
|
||||
:on-success="handleChatUploadSuccess"
|
||||
:headers="uploadHeaders"
|
||||
multiple
|
||||
:limit="5"
|
||||
:on-exceed="handleChatExceed"
|
||||
:show-file-list="false"
|
||||
>
|
||||
<el-button type="primary" link>
|
||||
<el-icon><Paperclip /></el-icon>
|
||||
添加附件
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<!-- 已上传附件预览 -->
|
||||
<div class="uploaded-attachments" v-if="chatFileList.length > 0">
|
||||
<div class="attachment-preview-item" v-for="(file, idx) in chatFileList" :key="idx">
|
||||
<template v-if="/\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(file.name)">
|
||||
<img
|
||||
:src="file.file_url || file.response?.data?.file_url"
|
||||
:alt="file.name"
|
||||
class="preview-thumb"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
</template>
|
||||
<span class="file-name">{{ file.name }}</span>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
@click="removeChatFile(idx)"
|
||||
>
|
||||
<el-icon><Close /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-input v-model="messageText" type="textarea" :rows="3" placeholder="输入消息" resize="none"
|
||||
@keyup.enter.prevent="sendMessage" />
|
||||
<ElInput v-model="ticket_id" type="hidden" />
|
||||
@@ -226,7 +304,7 @@
|
||||
</ElDialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<ElImageViewer v-if="imageViewerVisible" :url-list="imageList" :initial-index="imageViewerIndex" @close="imageViewerVisible = false" />
|
||||
<ElImageViewer v-if="imageViewerVisible" :url-list="chatImageList.length > 0 ? chatImageList : imageList" :initial-index="imageViewerIndex" @close="closeImageViewer" />
|
||||
<!-- 视频预览弹窗 -->
|
||||
<ElDialog v-model="videoDialogVisible" width="60%" top="10vh" :show-close="true" append-to-body>
|
||||
<video v-if="currentVideoUrl" :src="currentVideoUrl" controls autoplay style="width:100%;max-height:70vh;display:block;"></video>
|
||||
@@ -247,6 +325,7 @@
|
||||
import { useAuth } from "@/composables/useAuth";
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useUploadHeaders } from '@/composables/useUploadHeaders'
|
||||
import { Paperclip, Document, Close } from '@element-plus/icons-vue'
|
||||
const { uploadHeaders } = useUploadHeaders()
|
||||
const { info } = useUserStore()
|
||||
const userid = info.user.id
|
||||
@@ -279,6 +358,10 @@
|
||||
}
|
||||
const openChat = (row: any) => {
|
||||
isDrawerVisible.value = true
|
||||
// 清空数据
|
||||
messageText.value = ''
|
||||
messages.value = []
|
||||
chatFileList.value = []
|
||||
getConversationList(row.id)
|
||||
}
|
||||
|
||||
@@ -380,14 +463,28 @@
|
||||
const sendMessage = async () => {
|
||||
const text = messageText.value.trim()
|
||||
const ids = ticket_id.value
|
||||
if (!text) return
|
||||
if (!text && chatFileList.value.length === 0) return
|
||||
|
||||
// 准备附件数据
|
||||
const attachments = chatFileList.value.map(file => {
|
||||
const data = file.response?.data
|
||||
if (data) {
|
||||
return {
|
||||
original_name: data.original_name,
|
||||
storage_path: data.storage_path || data.file_name
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter(Boolean)
|
||||
|
||||
const { message } = await WorkService.conversationAdd({
|
||||
content: text,
|
||||
ticket_id: ids,
|
||||
attachment: attachments
|
||||
})
|
||||
ElMessage.success(message)
|
||||
messageText.value = ''
|
||||
chatFileList.value = [] // 清空附件列表
|
||||
getConversationList(ids)
|
||||
scrollToBottom()
|
||||
}
|
||||
@@ -523,6 +620,8 @@
|
||||
const imageViewerVisible = ref(false)
|
||||
const imageViewerIndex = ref(0)
|
||||
const imageList = computed(() => fileList.value.filter(file => /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(file.name)).map(file => file.file_url?file.file_url:file.response.data.file_url))
|
||||
// 聊天图片预览列表
|
||||
const chatImageList = ref<string[]>([])
|
||||
function handleImageClick(idx: number) {
|
||||
imageViewerIndex.value = idx
|
||||
imageViewerVisible.value = true
|
||||
@@ -533,6 +632,52 @@
|
||||
function handleVideoClick(url: string) {
|
||||
currentVideoUrl.value = url
|
||||
videoDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 聊天相关
|
||||
const chatFileList = ref<any[]>([])
|
||||
const handleChatUploadSuccess = (response: any, uploadFile: any, uploadFiles: any[]) => {
|
||||
chatFileList.value = uploadFiles.filter(item => item.status === 'success').map(item => {
|
||||
const data = item.response?.data
|
||||
if (data) {
|
||||
return {
|
||||
name: data.original_name,
|
||||
file_url: data.storage_path_full,
|
||||
status: 'success',
|
||||
response: { data: data }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter(Boolean)
|
||||
}
|
||||
const handleChatExceed = () => {
|
||||
ElMessage.warning('最多上传5个文件')
|
||||
}
|
||||
const removeChatFile = (index: number) => {
|
||||
chatFileList.value.splice(index, 1)
|
||||
}
|
||||
const handleChatImageClick = (url: string) => {
|
||||
// 设置聊天图片预览列表
|
||||
chatImageList.value = [url]
|
||||
imageViewerIndex.value = 0
|
||||
imageViewerVisible.value = true
|
||||
}
|
||||
|
||||
const closeImageViewer = () => {
|
||||
imageViewerVisible.value = false
|
||||
chatImageList.value = [] // 清空聊天图片列表
|
||||
}
|
||||
const handleChatVideoClick = (url: string) => {
|
||||
currentVideoUrl.value = url
|
||||
videoDialogVisible.value = true
|
||||
}
|
||||
const downloadAttachment = (attachment: any) => {
|
||||
const link = document.createElement('a')
|
||||
link.href = attachment.storage_path_full
|
||||
link.download = attachment.original_name
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -618,6 +763,7 @@
|
||||
|
||||
.message-info {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
@@ -634,6 +780,7 @@
|
||||
|
||||
.message-info {
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
@@ -757,4 +904,101 @@
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// 聊天附件样式
|
||||
.message-right .message-attachments{
|
||||
text-align: right;
|
||||
}
|
||||
.message-left .message-attachments{
|
||||
text-align: left;
|
||||
}
|
||||
.message-attachments {
|
||||
margin-top: 8px;
|
||||
|
||||
.attachment-item {
|
||||
margin-bottom: 8px;
|
||||
|
||||
.attachment-thumb {
|
||||
max-width: 200px;
|
||||
max-height: 150px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
transition: transform 0.2s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.file-attachment {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-regular);
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-attachment-upload {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.chat-upload {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.uploaded-attachments {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.attachment-preview-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 10px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
max-width: 200px;
|
||||
|
||||
.preview-thumb {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-regular);
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -123,22 +123,101 @@
|
||||
String(message.user_id) === String(userid) ? 'message-right' : 'message-left'
|
||||
]"
|
||||
>
|
||||
<!-- :src="String(message.user_id) === String(userid) ? meAvatar : aiAvatar" -->
|
||||
<el-avatar
|
||||
:size="32"
|
||||
:src="String(message.user_id) === String(userid) ? meAvatar : aiAvatar"
|
||||
:src="message.user_avatar"
|
||||
class="message-avatar"
|
||||
/>
|
||||
<div class="message-content">
|
||||
<div class="message-info">
|
||||
<span class="sender-name">{{ message.user_id }}</span>
|
||||
<span class="sender-name">{{ message.user_name }}</span>
|
||||
<span class="message-time">{{ message.updated_at }}</span>
|
||||
</div>
|
||||
<div class="message-text">{{ message.content }}</div>
|
||||
<!-- 附件显示区域 -->
|
||||
<div class="message-attachments" v-if="message.attachment && message.attachment.length > 0">
|
||||
<div class="attachment-item" v-for="(attachment, attIndex) in message.attachment" :key="attIndex">
|
||||
<template v-if="/\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(attachment.original_name)">
|
||||
<img
|
||||
:src="attachment.storage_path_full"
|
||||
:alt="attachment.original_name"
|
||||
class="attachment-thumb"
|
||||
@click="handleChatImageClick(attachment.storage_path_full)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="/\.(mp4|webm|ogg)$/i.test(attachment.original_name)">
|
||||
<video
|
||||
:src="attachment.storage_path_full"
|
||||
controls
|
||||
class="attachment-thumb"
|
||||
@click.prevent="handleChatVideoClick(attachment.storage_path_full)"
|
||||
></video>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="file-attachment">
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
<span class="file-name">{{ attachment.original_name }}</span>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
@click="downloadAttachment(attachment)"
|
||||
>
|
||||
下载
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="chat-input" v-if="hasAuth('work_order@conversation_add')">
|
||||
<!-- 附件上传区域 -->
|
||||
<div class="chat-attachment-upload">
|
||||
<el-upload
|
||||
v-model:file-list="chatFileList"
|
||||
class="chat-upload"
|
||||
:action="actionImageUplode"
|
||||
:on-success="handleChatUploadSuccess"
|
||||
:headers="uploadHeaders"
|
||||
multiple
|
||||
:limit="5"
|
||||
:on-exceed="handleChatExceed"
|
||||
:show-file-list="false"
|
||||
>
|
||||
<el-button type="primary" link>
|
||||
<el-icon><Paperclip /></el-icon>
|
||||
添加附件
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<!-- 已上传附件预览 -->
|
||||
<div class="uploaded-attachments" v-if="chatFileList.length > 0">
|
||||
<div class="attachment-preview-item" v-for="(file, idx) in chatFileList" :key="idx">
|
||||
<template v-if="/\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(file.name)">
|
||||
<img
|
||||
:src="file.file_url || file.response?.data?.file_url"
|
||||
:alt="file.name"
|
||||
class="preview-thumb"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
</template>
|
||||
<span class="file-name">{{ file.name }}</span>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
@click="removeChatFile(idx)"
|
||||
>
|
||||
<el-icon><Close /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="messageText"
|
||||
type="textarea"
|
||||
@@ -176,7 +255,7 @@
|
||||
</ElDialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<ElImageViewer v-if="imageViewerVisible" :url-list="imageList" :initial-index="imageViewerIndex" @close="imageViewerVisible = false" />
|
||||
<ElImageViewer v-if="imageViewerVisible" :url-list="chatImageList.length > 0 ? chatImageList : imageList" :initial-index="imageViewerIndex" @close="closeImageViewer" />
|
||||
<!-- 视频预览弹窗 -->
|
||||
<ElDialog v-model="videoDialogVisible" width="60%" top="10vh" :show-close="true" append-to-body>
|
||||
<video v-if="currentVideoUrl" :src="currentVideoUrl" controls autoplay style="width:100%;max-height:70vh;display:block;"></video>
|
||||
@@ -197,6 +276,7 @@ import { ElImageViewer } from 'element-plus'
|
||||
import { useAuth } from "@/composables/useAuth";
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useUploadHeaders } from '@/composables/useUploadHeaders'
|
||||
import { Paperclip, Document, Close } from '@element-plus/icons-vue'
|
||||
const { uploadHeaders } = useUploadHeaders()
|
||||
const { hasAuth } = useAuth();
|
||||
defineOptions({ name: 'Order' })
|
||||
@@ -232,6 +312,10 @@ const scrollToBottom = () => {
|
||||
}
|
||||
const openChat = (row: any) => {
|
||||
isDrawerVisible.value = true
|
||||
// 清空数据
|
||||
messageText.value = ''
|
||||
messages.value = []
|
||||
chatFileList.value = []
|
||||
getConversationList(row.id)
|
||||
}
|
||||
|
||||
@@ -333,14 +417,28 @@ const getConversationList = async (id:any) => {
|
||||
const sendMessage = async () => {
|
||||
const text = messageText.value.trim()
|
||||
const ids = ticket_id.value
|
||||
if (!text) return
|
||||
if (!text && chatFileList.value.length === 0) return
|
||||
|
||||
// 准备附件数据
|
||||
const attachments = chatFileList.value.map(file => {
|
||||
const data = file.response?.data
|
||||
if (data) {
|
||||
return {
|
||||
original_name: data.original_name,
|
||||
storage_path: data.storage_path || data.file_name
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter(Boolean)
|
||||
|
||||
const { message } = await WorkService.conversationAdd({
|
||||
content: text,
|
||||
ticket_id: ids,
|
||||
attachment: attachments
|
||||
})
|
||||
ElMessage.success(message)
|
||||
messageText.value = ''
|
||||
chatFileList.value = [] // 清空附件列表
|
||||
getConversationList(ids)
|
||||
scrollToBottom()
|
||||
}
|
||||
@@ -473,6 +571,8 @@ const statusSubmit = async () => {
|
||||
const imageViewerVisible = ref(false)
|
||||
const imageViewerIndex = ref(0)
|
||||
const imageList = computed(() => fileList.value.filter(file => /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(file.name)).map(file => file.file_url?file.file_url:file.response.data.file_url))
|
||||
// 聊天图片预览列表
|
||||
const chatImageList = ref<string[]>([])
|
||||
function handleImageClick(idx: number) {
|
||||
imageViewerIndex.value = idx
|
||||
imageViewerVisible.value = true
|
||||
@@ -484,6 +584,60 @@ function handleVideoClick(url: string) {
|
||||
currentVideoUrl.value = url
|
||||
videoDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 聊天相关
|
||||
const chatFileList = ref<any[]>([])
|
||||
const handleChatUploadSuccess = (response: any, uploadFile: any, uploadFiles: any[]) => {
|
||||
chatFileList.value = uploadFiles.filter(item => item.status === 'success').map(item => {
|
||||
const data = item.response?.data
|
||||
if (data) {
|
||||
return {
|
||||
name: data.original_name,
|
||||
file_url: data.storage_path_full,
|
||||
status: 'success',
|
||||
response: { data: data }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter(Boolean)
|
||||
}
|
||||
const handleChatExceed = () => {
|
||||
ElMessage.warning('最多上传5个文件')
|
||||
}
|
||||
const removeChatFile = (index: number) => {
|
||||
chatFileList.value.splice(index, 1)
|
||||
}
|
||||
const handleChatImageClick = (url: string) => {
|
||||
// 设置聊天图片预览列表
|
||||
chatImageList.value = [url]
|
||||
imageViewerIndex.value = 0
|
||||
imageViewerVisible.value = true
|
||||
}
|
||||
|
||||
const closeImageViewer = () => {
|
||||
imageViewerVisible.value = false
|
||||
chatImageList.value = [] // 清空聊天图片列表
|
||||
}
|
||||
const handleChatVideoClick = (url: string) => {
|
||||
currentVideoUrl.value = url
|
||||
videoDialogVisible.value = true
|
||||
}
|
||||
const downloadAttachment = (attachment: any) => {
|
||||
try {
|
||||
const fileName = attachment.original_name || 'download'
|
||||
const link = document.createElement('a')
|
||||
link.href = attachment.storage_path_full
|
||||
link.download = fileName
|
||||
link.target = '_blank'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
ElMessage.success('开始下载')
|
||||
} catch (error) {
|
||||
ElMessage.error('下载失败')
|
||||
console.error('下载失败:', error)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -568,6 +722,7 @@ function handleVideoClick(url: string) {
|
||||
|
||||
.message-info {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
@@ -584,6 +739,7 @@ function handleVideoClick(url: string) {
|
||||
|
||||
.message-info {
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
@@ -707,4 +863,101 @@ function handleVideoClick(url: string) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// 聊天附件样式
|
||||
.message-right .message-attachments{
|
||||
text-align: right;
|
||||
}
|
||||
.message-left .message-attachments{
|
||||
text-align: left;
|
||||
}
|
||||
.message-attachments {
|
||||
margin-top: 8px;
|
||||
|
||||
.attachment-item {
|
||||
margin-bottom: 8px;
|
||||
|
||||
.attachment-thumb {
|
||||
max-width: 200px;
|
||||
max-height: 150px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
transition: transform 0.2s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.file-attachment {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-regular);
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-attachment-upload {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.chat-upload {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.uploaded-attachments {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.attachment-preview-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 10px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
max-width: 200px;
|
||||
|
||||
.preview-thumb {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-regular);
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user