chat-app/src/pages/dialog/components/filePanel.vue

598 lines
18 KiB
Vue
Raw Normal View History

2024-12-06 08:55:15 +00:00
<template>
<div class="emojiRoot">
<div
@click="() => photoActionsSelect(0)"
class="flex flex-col items-center"
>
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
2024-12-06 08:55:15 +00:00
<tm-image :width="53" :height="44" :src="photoAlbum"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div>
</div>
<div
@click="() => photoActionsSelect(1)"
class="flex flex-col items-center"
>
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
2024-12-19 03:02:47 +00:00
<tm-image :width="53" :height="44" :src="videoImg"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div>
</div>
2024-12-06 08:55:15 +00:00
<div @click="takePhoto" class="flex flex-col items-center">
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
2024-12-06 08:55:15 +00:00
<tm-image :width="53" :height="44" :src="photoGraph"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div>
</div>
<div @click="chooseFile" class="flex flex-col items-center">
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
2024-12-06 08:55:15 +00:00
<tm-image :width="53" :height="44" :src="folder"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, defineProps, defineEmits } from 'vue'
import dayjs from 'dayjs'
2024-12-06 08:55:15 +00:00
import { beautifyTime } from '@/utils/datetime'
import {
useDialogueListStore,
useDialogueStore,
useUserStore,
useUploadsStore,
} from '@/store'
2024-12-06 08:55:15 +00:00
import { useSessionMenu } from '@/hooks'
import photoAlbum from '@/static/image/chatList/photoAlbum.png'
import photoGraph from '@/static/image/chatList/photoGraph.png'
2024-12-19 03:02:47 +00:00
import videoImg from '@/static/image/chatList/video@2x.png'
2024-12-06 08:55:15 +00:00
import folder from '@/static/image/chatList/folder.png'
import { uploadImg } from '@/api/chat'
import { uniqueId } from '@/utils'
const props = defineProps({
sendUserInfo: {
type: Object,
default: {},
required: true,
2024-12-19 03:02:47 +00:00
},
talkParams: {
type: Object,
default: {},
required: true,
},
})
const state = reactive({
base64Url: '',
})
2024-12-06 08:55:15 +00:00
2024-12-19 03:02:47 +00:00
const uploadsStore = useUploadsStore()
const {
addDialogueRecord,
virtualList,
updateUploadProgress,
} = useDialogueListStore()
2024-12-06 08:55:15 +00:00
const dialogueStore = useDialogueStore()
const userStore = useUserStore()
2024-12-13 05:09:38 +00:00
const emit = defineEmits(['selectImg'])
2024-12-06 08:55:15 +00:00
2024-12-19 03:02:47 +00:00
const onProgressFn = (progress, id) => {
console.log((progress.loaded / progress.total) * 100, 'progress')
2024-12-13 05:09:38 +00:00
updateUploadProgress(id, (progress.loaded / progress.total) * 100)
2024-12-06 08:55:15 +00:00
}
2024-12-19 03:02:47 +00:00
const photoActionsSelect = (index) => {
if (index === 0) {
if (typeof plus === 'undefined') {
uni.chooseImage({
sourceType: ['album'],
count: 9,
success: async (res) => {
console.log(res, 'res')
res.tempFiles.forEach(async (file) => {
const fileSizeInMB = (file.size / (1024 * 1024)).toFixed(2)
if (fileSizeInMB > 100) {
plus.nativeUI.toast('图片大小不能超过100MB')
return
}
const result = await onUploadImageVideo(file, 'image')
if (result) {
emit('selectImg', result, result.file_num)
}
})
},
})
} else {
plus?.gallery.pick(
(res) => {
console.log(res, 'res')
res.files.reverse()
res.files.forEach(async (filePath) => {
plus?.io?.resolveLocalFileSystemURL(
filePath,
async (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.readAsDataURL(file)
fileReader.onloadend = async (e) => {
const base64Url = e.target.result
const fileObj = base64ToFile(base64Url)
const fileSizeInMB = (fileObj.size / (1024 * 1024)).toFixed(
2,
)
if (fileSizeInMB > 100) {
plus.nativeUI.toast('图片大小不能超过100MB')
return
}
let data = await onUploadImageVideo(fileObj, 'image')
if (data) {
emit('selectImg', data, data.file_num)
}
}
})
},
(err) => {
console.log(err)
},
)
})
},
(err) => {
console.log(err)
},
{
filter: 'image',
maximum: 9,
multiple: true,
onmaxed: () => {
plus.nativeUI.toast('最多只能选择9张图片')
},
},
)
}
} else {
2024-12-19 03:02:47 +00:00
uni.chooseVideo({
sourceType: ['album'],
compressed: true,
maxDuration: 60,
2024-12-19 03:02:47 +00:00
success: async (res) => {
console.log(res, 'res')
const fileSizeInMB = (res.tempFile.size / (1024 * 1024)).toFixed(2)
if (fileSizeInMB > 100) {
plus.nativeUI.toast('视频大小不能超过100MB')
return
}
let data = await onUploadImageVideo(
res.tempFile,
'video',
res.tempFilePath,
)
if (data) {
emit('selectImg', data, data.file_num)
}
},
2024-12-19 03:02:47 +00:00
})
}
}
const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
console.log('开始上传文件:', file.name)
uploadsStore.updateUploadStatus(true)
2024-12-13 05:09:38 +00:00
return new Promise(async (resolve) => {
if (type === 'image') {
let image = new Image()
image.src = URL.createObjectURL(file)
image.onload = async () => {
2024-12-13 05:09:38 +00:00
const form = new FormData()
form.append('file', file)
form.append('source', 'fonchain-chat')
form.append('urlParam', `width=${image.width}&height=${image.height}`)
2024-12-13 05:09:38 +00:00
let randomId = uniqueId()
let newItem = {
2024-12-06 08:55:15 +00:00
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
height: image.height,
name: '',
2024-12-06 08:55:15 +00:00
size: 0,
url: image.src,
width: image.width,
2024-12-06 08:55:15 +00:00
},
float: 'right',
2024-12-06 08:55:15 +00:00
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
2024-12-06 08:55:15 +00:00
msg_type: 3,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
2024-12-13 05:09:38 +00:00
uploadCurrent: 0,
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
2024-12-06 08:55:15 +00:00
}
2024-12-13 05:09:38 +00:00
virtualList.value.unshift(newItem)
try {
const result = await uploadImg(form, (e) => onProgressFn(e, randomId))
console.log('上传完成,结果:', result)
if (result.status === 0) {
// 更新上传状态为成功
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 2
virtualList.value[index].uploadCurrent = 100
}
// 确保返回数据
resolve({
type: 'image',
url: result.data.ori_url,
size: file.size,
width: image.width,
height: image.height,
file_num: randomId,
})
} else {
uploadsStore.updateUploadStatus(false)
// 更新上传状态为失败
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
message.error(result.msg)
resolve('')
}
} catch (error) {
console.error('上传出错:', error)
uploadsStore.updateUploadStatus(false)
// 更新上传状态为失败
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
message.error('上传失败')
resolve('')
}
2024-12-13 05:09:38 +00:00
}
} else {
2024-12-19 03:02:47 +00:00
uni.getVideoInfo({
src: fileUrl,
success: async (resp) => {
console.log('视频信息:', resp)
const form = new FormData()
form.append('file', file)
form.append('source', 'fonchain-chat')
form.append('type', 'video')
form.append('urlParam', `width=${resp.width}&height=${resp.height}`)
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
2024-12-19 03:02:47 +00:00
duration: parseInt(resp.duration),
height: resp.height,
name: '',
url: fileUrl,
width: resp.width,
},
float: 'right',
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
msg_type: 5,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1,
2024-12-19 03:02:47 +00:00
}
virtualList.value.unshift(newItem)
try {
const result = await uploadImg(form, (e) => onProgressFn(e, randomId))
console.log('视频上传完成,结果:', result)
if (result.status === 0) {
// 更新上传状态为成功
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 2
virtualList.value[index].uploadCurrent = 100
}
resolve({
type: 'video',
url: result.data.ori_url,
cover: result.data.cover_url,
duration: parseInt(resp.duration),
size: file.size,
file_num: randomId,
})
} else {
uploadsStore.updateUploadStatus(false)
// 更新上传状态为失败
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
message.error(result.msg)
resolve('')
}
} catch (error) {
console.error('视频上传出错:', error)
uploadsStore.updateUploadStatus(false)
// 更新上传状态为失败
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
message.error('上传失败')
resolve('')
}
},
fail: (error) => {
console.error('获取视频信息失败:', error)
uploadsStore.updateUploadStatus(false)
message.error('获取视频信息失败')
resolve('')
}
2024-12-06 08:55:15 +00:00
})
}
})
}
2024-12-13 05:09:38 +00:00
const base64ToFile = (base64) => {
// base64转file
const [header, base64String] = base64.split(';base64,')
const imageType = header.split(':')[1]
const byteCharacters = atob(base64String)
2024-12-13 05:09:38 +00:00
const byteArray = new Uint8Array(
Array.from(byteCharacters, (char) => char.charCodeAt(0)),
)
return new File([new Blob([byteArray], { type: imageType })], 'example.png', {
type: imageType,
})
2024-12-13 05:09:38 +00:00
}
2024-12-06 08:55:15 +00:00
2024-12-19 03:02:47 +00:00
const choosePhoto = (filter = 'none', maximum = 9, multiple = true) => {
window.plus?.gallery.pick(
(res) => {
console.log(res)
res.files.reverse()
res.files.forEach(async (filePath) => {
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
if (['jpg', 'png'].includes(suffix)) {
console.log('进入图片')
window.plus?.io?.resolveLocalFileSystemURL(
filePath,
async (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.readAsDataURL(file)
fileReader.onloadend = async (e) => {
const base64Url = e.target.result
const fileObj = base64ToFile(base64Url)
let data = await onUploadImageVideo(fileObj, 'image')
emit('selectImg', data)
}
})
},
(err) => {
console.log(err)
},
)
}
if (['mp4', 'flv'].includes(suffix)) {
console.log(filePath, '进入视频')
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
// console.log(localUrl);
2024-12-19 03:02:47 +00:00
plus.io.getVideoInfo({
filePath: filePath,
success: (event) => {
console.log(event)
},
fail: (err) => {
console.log(err)
},
})
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
// entry.file((file) => {
// console.log(file,'file');
// const fileReader = new plus.io.FileReader();
// fileReader.readAsDataURL(file);
// fileReader.onloadend = async (e) => {
// const base64Url = e.target.result;
// const fileObj = base64ToFile(base64Url);
// let data = await onUploadImageVideo(fileObj, 'video')
// emit('selectImg', data)
// };
// })
// },
// (err) => {
// console.log(err);
// }
// )
2024-12-19 03:02:47 +00:00
}
})
},
(err) => {
console.log(err)
},
2024-12-13 05:09:38 +00:00
{
2024-12-19 03:02:47 +00:00
filter: filter,
maximum: maximum,
multiple: multiple,
},
2024-12-13 05:09:38 +00:00
)
2024-12-06 08:55:15 +00:00
}
2024-12-19 03:02:47 +00:00
const takePhoto = () => {
if (typeof plus !== 'undefined') {
getCamera()
} else {
document.addEventListener('plusready', () => {
getCamera()
})
}
}
2024-12-19 03:02:47 +00:00
const getCamera = () => {
const cmr = plus.camera.getCamera()
cmr.captureImage(
(p) => {
plus.io.resolveLocalFileSystemURL(
p,
(entry) => {
compressAndShowImage(entry.toLocalURL(), entry.name)
},
(err) => {
console.log(err)
},
)
},
() => {},
{ index: '2' },
)
}
2024-12-19 03:02:47 +00:00
const compressAndShowImage = (url, filename) => {
const dst = `_doc/upload/${filename}`
plus.zip.compressImage(
{ src: url, dst, quality: 10, overwrite: true },
(zip) => displayImage(zip.target),
(err) => {
console.log(err)
},
)
}
2024-12-06 08:55:15 +00:00
const displayImage = (url) => {
plus.io.resolveLocalFileSystemURL(url, (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.readAsDataURL(file)
fileReader.onloadend = async (e) => {
state.base64Url = e.target.result
const imageFile = base64ToFile(state.base64Url)
let data = await onUploadImageVideo(imageFile, 'image')
emit('selectImg', data, data.file_num)
}
})
})
2024-12-06 08:55:15 +00:00
}
2024-12-06 08:55:15 +00:00
const chooseFile = () => {
2024-12-19 03:02:47 +00:00
uni.chooseFile({
count: 1,
extension: [''],
2024-12-19 03:02:47 +00:00
success: (res) => {
const fileSizeInMB = (res.tempFiles[0].size / (1024 * 1024)).toFixed(2)
if (fileSizeInMB > 100) {
plus.nativeUI.toast('文件大小不能超过100MB')
return
}
2024-12-19 03:02:47 +00:00
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
drive: 3,
name: res.tempFiles[0].name,
size: res.tempFiles[0].size,
path: res.tempFilePaths[0],
},
float: 'right',
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
msg_type: 6,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
}
2024-12-19 03:02:47 +00:00
virtualList.value.unshift(newItem)
uploadsStore.updateUploadStatus(true)
uploadsStore.initUploadFile(
res.tempFiles[0],
props.talkParams,
randomId,
(status, data, msg) => {
if (status === 0) {
// 更新上传状态为成功
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 2
virtualList.value[index].uploadCurrent = 100
}
} else {
uploadsStore.updateUploadStatus(false)
// 更新上传状态为失败
const index = virtualList.value.findIndex(
(item) => item.file_num === randomId,
)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
message.error(msg)
}
},
)
},
2024-12-19 03:02:47 +00:00
})
2024-12-06 08:55:15 +00:00
}
</script>
<style lang="scss" scoped>
.emojiRoot {
width: 100%;
height: 232rpx;
2024-12-19 03:02:47 +00:00
padding: 20rpx 62rpx 0 62rpx;
2024-12-06 08:55:15 +00:00
display: flex;
justify-content: space-between;
align-items: flex-start;
}
</style>