mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2025-12-17 16:35:53 +08:00
IM
This commit is contained in:
440
im/src/components/editor/MeEditorFileManage.vue
Normal file
440
im/src/components/editor/MeEditorFileManage.vue
Normal file
@@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<el-container
|
||||
class="container animated bounceInUp"
|
||||
v-outside="closeBox"
|
||||
v-if="show"
|
||||
>
|
||||
<el-header class="no-padding header" height="50px">
|
||||
<p>
|
||||
上传管理 <span v-show="total">({{ successNum }}/{{ total }})</span>
|
||||
</p>
|
||||
<i class="close-btn el-icon-close" @click="closeBox" />
|
||||
</el-header>
|
||||
|
||||
<el-main class="no-padding mian lum-scrollbar">
|
||||
<div class="empty-data" v-show="total == 0">
|
||||
<SvgNotData />
|
||||
<p>暂无上传文件</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="file in items"
|
||||
v-show="!file.isDelete"
|
||||
:key="file.hashName"
|
||||
class="file-item"
|
||||
>
|
||||
<div class="file-header">
|
||||
<div class="type-icon">{{ file.ext }}</div>
|
||||
<el-tooltip :content="file.filename" placement="top-start">
|
||||
<div class="filename">{{ file.filename }}</div>
|
||||
</el-tooltip>
|
||||
|
||||
<div class="status">
|
||||
<span v-if="file.status == 0">等待上传</span>
|
||||
<span v-else-if="file.status == 1" style="color: #66b1ff">
|
||||
正在上传...
|
||||
</span>
|
||||
<span v-else-if="file.status == 2" style="color: #67c23a">
|
||||
已完成
|
||||
</span>
|
||||
<span v-else style="color: red">网络异常</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-mian">
|
||||
<div class="progress">
|
||||
<el-progress
|
||||
type="dashboard"
|
||||
:percentage="file.progress"
|
||||
:width="50"
|
||||
:color="colors"
|
||||
/>
|
||||
<span class="name">上传进度</span>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<p>
|
||||
文件类型:<span>{{ file.filetype }}</span>
|
||||
</p>
|
||||
<p>
|
||||
文件大小:<span>{{ file.filesize }}</span>
|
||||
</p>
|
||||
<p>
|
||||
上传时间:<span>{{ file.datetime }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="file.status == 2 || file.status == 3" class="file-means">
|
||||
<div class="btns" @click="removeFile(file.hashName)">删除</div>
|
||||
<div
|
||||
v-show="file.status == 3"
|
||||
class="btns"
|
||||
@click="triggerUpload(file.hashName)"
|
||||
>
|
||||
继续上传
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { SvgNotData } from '@/core/icons'
|
||||
import { Progress } from 'element-ui'
|
||||
Vue.use(Progress)
|
||||
|
||||
import { ServeFindFileSplitInfo, ServeFileSubareaUpload } from '@/api/upload'
|
||||
import { formatSize, getFileExt, parseTime } from '@/utils/functions'
|
||||
import { ServeSendTalkFile } from '@/api/chat'
|
||||
|
||||
export default {
|
||||
name: 'MeEditorFileManage',
|
||||
model: {
|
||||
prop: 'show',
|
||||
event: 'close',
|
||||
},
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
components: {
|
||||
SvgNotData,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
colors: [
|
||||
{
|
||||
color: '#f56c6c',
|
||||
percentage: 20,
|
||||
},
|
||||
{
|
||||
color: '#e6a23c',
|
||||
percentage: 40,
|
||||
},
|
||||
{
|
||||
color: '#5cb87a',
|
||||
percentage: 60,
|
||||
},
|
||||
{
|
||||
color: '#1989fa',
|
||||
percentage: 80,
|
||||
},
|
||||
{
|
||||
color: '#11ce65',
|
||||
percentage: 100,
|
||||
},
|
||||
],
|
||||
|
||||
items: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
total() {
|
||||
return this.items.filter(item => {
|
||||
return item.isDelete === false
|
||||
}).length
|
||||
},
|
||||
successNum() {
|
||||
return this.items.filter(item => {
|
||||
return item.isDelete === false && item.status == 2
|
||||
}).length
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
closeBox() {
|
||||
this.$emit('close', false)
|
||||
},
|
||||
|
||||
upload(file) {
|
||||
ServeFindFileSplitInfo({
|
||||
file_name: file.name,
|
||||
file_size: file.size,
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
const { hash_name, split_size } = res.data
|
||||
|
||||
this.items.unshift({
|
||||
hashName: hash_name,
|
||||
originalFile: file,
|
||||
filename: file.name,
|
||||
status: 0, // 文件上传状态 0:等待上传 1:上传中 2:上传完成 3:网络异常
|
||||
progress: 0,
|
||||
filesize: formatSize(file.size),
|
||||
filetype: file.type || '未知',
|
||||
datetime: parseTime(new Date(), '{m}-{d} {h}:{i}'),
|
||||
ext: getFileExt(file.name),
|
||||
forms: this.fileSlice(file, hash_name, split_size),
|
||||
successNum: 0,
|
||||
isDelete: false,
|
||||
})
|
||||
|
||||
this.triggerUpload(hash_name)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 处理拆分上传文件
|
||||
fileSlice(file, hash, eachSize) {
|
||||
const ext = getFileExt(file.name)
|
||||
const splitNum = Math.ceil(file.size / eachSize) // 分片总数
|
||||
const forms = []
|
||||
|
||||
// 处理每个分片的上传操作
|
||||
for (let i = 0; i < splitNum; i++) {
|
||||
let start = i * eachSize
|
||||
let end = Math.min(file.size, start + eachSize)
|
||||
|
||||
// 构建表单
|
||||
const form = new FormData()
|
||||
form.append('file', file.slice(start, end))
|
||||
form.append('name', file.name)
|
||||
form.append('hash', hash)
|
||||
form.append('ext', ext)
|
||||
form.append('size', file.size)
|
||||
form.append('split_index', i)
|
||||
form.append('split_num', splitNum)
|
||||
forms.push(form)
|
||||
}
|
||||
|
||||
return forms
|
||||
},
|
||||
|
||||
// 触发上传文件
|
||||
triggerUpload(hashName) {
|
||||
let $index = this.getFileIndex(hashName)
|
||||
if ($index < 0 || this.items[$index].isDelte) {
|
||||
return
|
||||
}
|
||||
|
||||
let i = this.items[$index].successNum
|
||||
let form = this.items[$index].forms[i]
|
||||
let length = this.items[$index].forms.length
|
||||
this.items[$index].status = 1
|
||||
ServeFileSubareaUpload(form)
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
$index = this.getFileIndex(hashName)
|
||||
this.items[$index].successNum++
|
||||
this.items[$index].progress = Math.floor(
|
||||
(this.items[$index].successNum / length) * 100
|
||||
)
|
||||
if (this.items[$index].successNum == length) {
|
||||
this.items[$index].status = 2
|
||||
if (res.data.is_file_merge) {
|
||||
ServeSendTalkFile({
|
||||
hash_name: res.data.hash,
|
||||
receiver_id: this.$store.state.dialogue.receiver_id,
|
||||
talk_type: this.$store.state.dialogue.talk_type,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.triggerUpload(hashName)
|
||||
}
|
||||
} else {
|
||||
this.items[$index].status = 3
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
$index = this.getFileIndex(hashName)
|
||||
this.items[$index].status = 3
|
||||
})
|
||||
},
|
||||
|
||||
// 获取分片文件数组索引
|
||||
getFileIndex(hashName) {
|
||||
return this.items.findIndex(item => {
|
||||
return item.hashName === hashName
|
||||
})
|
||||
},
|
||||
|
||||
removeFile(hashName) {
|
||||
let index = this.getFileIndex(hashName)
|
||||
this.items[index].isDelete = true
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.items = []
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 400px;
|
||||
height: 600px;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 5px #eae5e5;
|
||||
border: 1px solid #eae5e5;
|
||||
overflow: hidden;
|
||||
border-radius: 3px 3px 0 0;
|
||||
|
||||
.header {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
position: relative;
|
||||
text-indent: 20px;
|
||||
border-bottom: 1px solid #f5eeee;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 15px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.mian {
|
||||
.empty-data {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-top: 50%;
|
||||
|
||||
svg {
|
||||
font-size: 70px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 30px;
|
||||
color: #cccccc;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-item {
|
||||
width: 95%;
|
||||
min-height: 100px;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 5px;
|
||||
margin: 15px auto;
|
||||
box-shadow: 0 0 5px #eae5e5;
|
||||
overflow: hidden;
|
||||
|
||||
.file-header {
|
||||
height: 45px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #f7f4f4;
|
||||
|
||||
.type-icon {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
background-color: #66b1ff;
|
||||
border-radius: 50%;
|
||||
margin-left: 5px;
|
||||
font-size: 10px;
|
||||
font-weight: 200;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.filename {
|
||||
margin-left: 10px;
|
||||
font-size: 14px;
|
||||
width: 65%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
top: 12px;
|
||||
font-size: 13px;
|
||||
color: #6b6868;
|
||||
font-weight: 200;
|
||||
}
|
||||
}
|
||||
|
||||
.file-mian {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.progress {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
flex-shrink: 0;
|
||||
background: #f9f6f6;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
|
||||
.name {
|
||||
font-size: 12px;
|
||||
color: #ada8a8;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
flex: auto;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 20px;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
font-size: 13px;
|
||||
|
||||
p {
|
||||
margin: 3px;
|
||||
color: #ada8a8;
|
||||
|
||||
span {
|
||||
color: #595a5a;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-means {
|
||||
width: 96.5%;
|
||||
height: 35px;
|
||||
border-top: 1px dashed rgb(234, 227, 227);
|
||||
margin: 3px auto;
|
||||
padding-top: 5px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
.btns {
|
||||
width: 80px;
|
||||
height: 25px;
|
||||
border: 1px solid #e6e1e1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 3px;
|
||||
border-radius: 15px;
|
||||
font-size: 12px;
|
||||
color: #635f5f;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
box-shadow: 0 0 5px #eae5e5;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user