chat-pc/src/components/talk/message/FileMessage.vue

261 lines
6.8 KiB
Vue
Raw Normal View History

<script setup>
2024-12-24 08:14:21 +00:00
import { fileFormatSize } from '@/utils/strings'
import { ref, computed } from 'vue'
import { useUploadsStore } from '@/store'
import pptText from '@/assets/image/ppt-text.png'
import excelText from '@/assets/image/excel-text.png'
import wordText from '@/assets/image/word-text.png'
import pdfText from '@/assets/image/pdf-text.png'
import fileText from '@/assets/image/file-text.png'
import { ArrowDownload16Filled } from '@vicons/fluent'
import { download } from '@/utils/functions.js'
// 定义组件属性
const props = defineProps({
// 文件的额外信息
extra: {
type: Object,
required: true
},
// 聊天记录数据
data: {
type: Object,
required: true
},
// 是否使用最大宽度
maxWidth: {
type: Boolean,
default: false
}
})
const uploadsStore = useUploadsStore()
const isPlaying = ref(false)
// 文件类型配置
const fileTypes = {
PDF: { icon: pdfText, color: '#DE4E4E', type: 'PDF' },
PPT: { icon: pptText, color: '#B74B2B', type: 'PPT' },
EXCEL: { icon: excelText, color: '#3C7F4B', type: 'EXCEL' },
WORD: { icon: wordText, color: '#2750B2', type: 'WORD' },
DEFAULT: { icon: fileText, color: '#747474', type: '文件' }
}
// Excel文件扩展名映射
const EXCEL_EXTENSIONS = ['XLS', 'XLSX', 'CSV']
// Word文件扩展名映射
const WORD_EXTENSIONS = ['DOC', 'DOCX', 'RTF', 'DOT', 'DOTX']
// PPT文件扩展名映射
const PPT_EXTENSIONS = ['PPT', 'PPTX', 'PPS', 'PPSX']
// 获取文件类型信息
const fileInfo = computed(() => {
const extension = getFileExtension(props.extra.name)
if (EXCEL_EXTENSIONS.includes(extension)) {
return fileTypes.EXCEL
}
if (WORD_EXTENSIONS.includes(extension)) {
return fileTypes.WORD
}
if (PPT_EXTENSIONS.includes(extension)) {
return fileTypes.PPT
}
return fileTypes[extension] || fileTypes.DEFAULT
})
// 获取文件扩展名
function getFileExtension(filename) {
const parts = filename.split('.')
return parts.length > 1 ? parts.pop().toUpperCase() : ''
}
// 切换播放状态
const togglePlay = () => {
isPlaying.value = !isPlaying.value
if (props.extra.is_uploading && props.extra.upload_id) {
const action = isPlaying.value ? 'pauseUpload' : 'resumeUpload'
uploadsStore[action](props.extra.upload_id)
}
}
// 计算SVG圆环进度条的参数
const radius = 9
const circumference = computed(() => 2 * Math.PI * radius)
const strokeDashoffset = computed(() =>
circumference.value * (1 - (props.extra.percentage || 0) / 100)
)
// 处理文件点击事件
const handleClick = () => {
if(!props.extra.is_uploading){
window.open(
`${window.location.origin}/office?url=${props.extra.path}`,
'_blank',
'width=1200,height=900,left=200,top=200,toolbar=no,menubar=no,scrollbars=yes,resizable=yes,location=no,status=no'
);
}
}
function downloadFileWithProgress(resourceUrl, filename) {
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = resourceUrl;
document.body.appendChild(iframe);
setTimeout(() => {
document.body.removeChild(iframe);
}, 60000);
}
// 处理下载事件
const handleDownload = () => {
downloadFileWithProgress(props.extra.path,props.extra.name)
}
2024-12-24 08:14:21 +00:00
</script>
<template>
<div class="file-message flex flex-col" @click="handleClick">
<!-- 文件头部信息 -->
<div class="file-header">
<!-- 文件名 -->
<div class="file-name">{{ extra.name }}</div>
<!-- 文件图标区域 -->
<div class="file-icon-container">
<img class="file-icon" :src="fileInfo.icon" alt="文件图标">
<!-- 上传进度圆环 - 上传状态 -->
<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
cx="10"
cy="10"
r="9"
fill="transparent"
stroke="#EEEEEE"
stroke-width="2"
/>
<!-- 进度圆环 -->
<circle
cx="10"
cy="10"
r="9"
fill="transparent"
:stroke="fileInfo.color"
stroke-width="2"
:stroke-dasharray="circumference"
:stroke-dashoffset="strokeDashoffset"
transform="rotate(-90 10 10)"
class="progress-circle"
/>
<!-- 暂停/播放图标 -->
<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>
</svg>
</div>
</div>
2024-12-24 08:14:21 +00:00
</div>
</div>
<!-- 文件大小信息 -->
<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>
</div>
</div>
</div>
2024-12-24 08:14:21 +00:00
</template>
<style lang="less" scoped>
.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;
cursor: pointer;
}
.file-header {
display: flex;
padding: 14px 5px 14px 0;
justify-content: space-between;
width: 100%;
border-bottom: 1px solid #EEEEEE;
}
.file-name {
height: 50px;
color: #1A1A1A;
font-size: 14px;
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.file-icon-container {
height: 48px;
position: relative;
}
.file-icon {
width: 48px;
height: 48px;
}
.progress-overlay {
background-color: #fff;
position: absolute;
top: 6px;
left: 11px;
width: 30px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
}
.file-size {
color: #747474;
font-size: 12px;
}
.circle-progress-container {
width: 20px;
height: 20px;
position: relative;
cursor: pointer;
}
2024-12-24 08:14:21 +00:00
.circle-progress {
transform: rotate(-90deg);
transform-origin: center;
}
2024-12-24 08:14:21 +00:00
.progress-circle {
transition: stroke-dashoffset 0.3s ease;
}
2024-12-24 08:14:21 +00:00
.pause-icon, .play-icon {
transform-origin: center;
}
2024-12-24 08:14:21 +00:00
.pause-icon {
transform: rotate(90deg);
2024-12-24 08:14:21 +00:00
}
</style>