video plus

This commit is contained in:
张 元山 2025-03-29 09:01:21 +08:00
parent ed8da6cde9
commit 42c1b64a99

View File

@ -1,39 +1,25 @@
<template> <template>
<div class="emojiRoot"> <div class="emojiRoot">
<div <div @click="() => photoActionsSelect(0)" class="flex flex-col items-center">
@click="() => photoActionsSelect(0)" <div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
class="flex flex-col items-center"
>
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="photoAlbum"></tm-image> <tm-image :width="53" :height="44" :src="photoAlbum"></tm-image>
</div> </div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div> <div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div>
</div> </div>
<div <div @click="() => photoActionsSelect(1)" class="flex flex-col items-center">
@click="() => photoActionsSelect(1)" <div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
class="flex flex-col items-center"
>
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="videoImg"></tm-image> <tm-image :width="53" :height="44" :src="videoImg"></tm-image>
</div> </div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div> <div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div>
</div> </div>
<div @click="takePhoto" class="flex flex-col items-center"> <div @click="takePhoto" class="flex flex-col items-center">
<div <div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="photoGraph"></tm-image> <tm-image :width="53" :height="44" :src="photoGraph"></tm-image>
</div> </div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div> <div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div>
</div> </div>
<div @click="chooseFile" class="flex flex-col items-center"> <div @click="chooseFile" class="flex flex-col items-center">
<div <div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="folder"></tm-image> <tm-image :width="53" :height="44" :src="folder"></tm-image>
</div> </div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div> <div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div>
@ -72,7 +58,7 @@ const props = defineProps({
}) })
const state = reactive({ const state = reactive({
base64Url: '' base64Url: '',
}) })
const uploadsStore = useUploadsStore() const uploadsStore = useUploadsStore()
@ -92,36 +78,226 @@ const onProgressFn = (progress, id) => {
updateUploadProgress(id, (progress.loaded / progress.total) * 100) updateUploadProgress(id, (progress.loaded / progress.total) * 100)
} }
const photoActionsSelect = (index) => { const photoActionsSelect = async (index) => {
if (index === 0) { if (index === 0) {
uni.chooseImage({ if (typeof plus === 'undefined') {
sourceType: ['album'], uni.chooseImage({
count: 9, sourceType: ['album'],
success: async (res) => { count: 9,
console.log(res, 'res') success: async (res) => {
res.tempFiles.forEach(async (file) => { console.log(res, 'res')
let data = await onUploadImageVideo(file, 'image') res.tempFiles.forEach(async (file) => {
emit('selectImg', data, data.file_num) let data = await onUploadImageVideo(file, 'image')
emit('selectImg', data, data.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)
let data = await onUploadImageVideo(fileObj, 'image')
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 {
// uni.chooseVideo({
// sourceType: ['album'],
// compressed: true,
// maxDuration: 60,
// success: async (res) => {
// console.log( 'chooseVideo res.tempFilePath',res.tempFilePath)
// console.log( 'chooseVideo res.tempFile',res.tempFile)
// return
// let data = await onUploadImageVideo(
// res.tempFile,
// 'video',
// res.tempFilePath,
// )
// emit('selectImg', data, data.file_num)
// },
// })
plus?.gallery.pick(
(res) => {
res.files.reverse()
res.files.forEach(async (filePath) => {
plus?.io?.resolveLocalFileSystemURL(
filePath,
async (entry) => {
entry.file(async (file) => {
try {
console.log('filePath', filePath)
// Blob URL
playVideoWithNativeBridge(filePath)
const videoInfo = await getVideoInfo(filePath);
console.log('视频信息:', videoInfo);
console.log('文件详细信息:', {
name: file.name,
size: file.size,
type: file.type,
});
const fileInfo = await getFilePath(file);
console.log('fileInfo', fileInfo)
//
let data = await onUploadImageVideo(file, 'video', videoInfo);
emit('selectImg', data, data.file_num);
} catch (error) {
console.log('文件处理失败:', error);
}
})
},
(err) => {
console.log(err)
},
)
}) })
}, },
}) (err) => {
} else { console.log(err)
uni.chooseVideo({
sourceType: ['album'],
success: async (res) => {
console.log(res, 'res')
let data = await onUploadImageVideo(
res.tempFile,
'video',
res.tempFilePath,
)
emit('selectImg', data, data.file_num)
}, },
}) {
filter: 'video',
maximum: 2,
multiple: true,
onmaxed: () => {
plus.nativeUI.toast('最多只能选择2个视频')
},
},
)
} }
} }
const onUploadImageVideo = async (file, type = 'image', fileUrl) => { const playVideoWithNativeBridge = (filePath) => {
return new Promise((resolve, reject) => {
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.playVideo) {
// iOS WebView
window.webkit.messageHandlers.playVideo.postMessage({
filePath: filePath
});
resolve();
} else if (window.android && window.android.playVideo) {
// Android WebView
window.android.playVideo(filePath);
resolve();
} else if (window.plus) {
// 使 plus API HTTP
plus.bridge.exec('VideoPlayerModule', 'playVideoFromPath', [filePath],
(httpUrl) => {
console.log('获取到HTTP URL:', httpUrl);
resolve(httpUrl);
},
(error) => {
console.error('原生方法调用失败:', error);
reject(error);
}
);
} else {
reject(new Error('没有可用的原生桥接方法'));
}
});
};
const getFilePath = async (file) => {
try {
// #ifdef H5
// plus Blob
return new Promise((resolve, reject) => {
plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
const reader = new plus.io.FileReader();
reader.onload = function (e) {
// Blob
const blob = new Blob([e.target.result], { type: file.type || 'video/mp4' });
// File
const newFile = new File([blob], file.name || 'video.mp4', {
type: file.type || 'video/mp4'
});
// FormData
// const formData = new FormData();
// formData.append('file', newFile);
//
// formData.append('other_field', 'value');
resolve(newFile);
};
reader.onerror = function (error) {
console.error('读取文件失败:', error);
reject(error);
};
reader.readAsArrayBuffer(file);
});
});
// #endif
// #ifndef H5
const formData = new FormData();
formData.append('file', file);
return formData;
// #endif
} catch (error) {
console.error('处理文件失败:', error);
throw error;
}
};
const onUploadImageVideo = async (file, type = 'image', resp) => {
console.log(file, 'file') console.log(file, 'file')
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
if (type === 'image') { if (type === 'image') {
@ -132,6 +308,7 @@ const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
form.append('file', file) form.append('file', file)
form.append('source', 'fonchain-chat') form.append('source', 'fonchain-chat')
form.append('urlParam', `width=${image.width}&height=${image.height}`) form.append('urlParam', `width=${image.width}&height=${image.height}`)
let randomId = uniqueId() let randomId = uniqueId()
let newItem = { let newItem = {
avatar: userStore.avatar, avatar: userStore.avatar,
@ -164,6 +341,12 @@ const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
uploadImg(form, (e) => onProgressFn(e, randomId)).then( uploadImg(form, (e) => onProgressFn(e, randomId)).then(
({ status, data, msg }) => { ({ status, data, msg }) => {
if (status == 0) { 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
}
resolve({ resolve({
type: 'image', type: 'image',
url: data.ori_url, url: data.ori_url,
@ -173,6 +356,11 @@ const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
file_num: randomId, file_num: randomId,
}) })
} else { } else {
//
const index = virtualList.value.findIndex(item => item.file_num === randomId)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
resolve('') resolve('')
message.error(msg) message.error(msg)
} }
@ -180,67 +368,100 @@ const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
) )
} }
} else { } else {
uni.getVideoInfo({
src: fileUrl,
success: (resp) => {
console.log(resp)
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: {
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, // 1 2 3
}
virtualList.value.unshift(newItem)
uploadImg(form, (e) => onProgressFn(e, randomId)).then(
({ status, data, msg }) => {
if (status == 0) {
console.log(data)
resolve({
type: 'video',
url: data.ori_url,
cover: data.cover_url,
duration: parseInt(resp.duration),
size: file.size,
file_num: randomId,
})
} else {
// resolve('')
// message.error(msg)
}
},
)
},
})
const form = new FormData() 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}`)
// FormData
for (let pair of form.entries()) {
console.log('video form', `${pair[0]}: ${pair[1]}`);
}
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
duration: parseInt(resp.duration),
height: resp.height,
name: '',
url: resp.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, // 1 2 3
}
virtualList.value.unshift(newItem)
console.log('uploadImg params', form)
uploadImg(form, (e) => onProgressFn(e, randomId)).then(
({ 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
}
console.log(data)
resolve({
type: 'video',
url: data.ori_url,
cover: data.cover_url,
duration: parseInt(resp.duration),
size: file.size,
file_num: randomId,
})
} else {
//
const index = virtualList.value.findIndex(item => item.file_num === randomId)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
resolve('')
message.error(msg)
}
},
)
} }
}) })
} }
const getVideoInfo = (filePath) => {
return new Promise((resolve, reject) => {
plus.io.getVideoInfo({
filePath: filePath,
success: (res) => {
resolve({
width: res.width,
height: res.height,
duration: res.duration,
fileUrl: filePath,
size: res.size
});
},
fail: (err) => {
console.log('获取视频信息失败:', err);
reject(err);
}
});
});
};
const base64ToFile = (base64) => { const base64ToFile = (base64) => {
// base64file // base64file
const [header, base64String] = base64.split(';base64,') const [header, base64String] = base64.split(';base64,')
@ -351,7 +572,7 @@ const getCamera = () => {
}, },
) )
}, },
() => {}, () => { },
{ index: '2' }, { index: '2' },
) )
} }
@ -414,7 +635,23 @@ const chooseFile = () => {
uploadStatus: 1, // 1 2 3 uploadStatus: 1, // 1 2 3
} }
virtualList.value.unshift(newItem) virtualList.value.unshift(newItem)
uploadsStore.initUploadFile(res.tempFiles[0], props.talkParams, randomId) 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 {
//
const index = virtualList.value.findIndex(item => item.file_num === randomId)
if (index !== -1) {
virtualList.value[index].uploadStatus = 3
}
message.error(msg)
}
})
}, },
}) })
} }