@@ -0,0 +1,335 @@ | |||
<template> | |||
<div class="oss-filed"> | |||
<n-upload | |||
action="#" | |||
:max="limit" | |||
:file-list="data.fileList" | |||
:default-upload="false" | |||
:show-remove-button="remBtn" | |||
:list-type="fileType == 'img' ? 'image-card' : 'text'" | |||
@change="handleChange" | |||
@before-upload="beforeUpload" | |||
> | |||
<n-button v-if="fileType != 'img'"> | |||
<n-icon> | |||
<FileOutlined /> | |||
</n-icon> | |||
选择{{ btnName }} | |||
</n-button> | |||
<div v-if="fileType == 'img'" class="oss-upload-text" /> | |||
</n-upload> | |||
<n-button | |||
v-if="showUploadBtn" | |||
type="primary" | |||
:disabled="data.fileList.length === 0" | |||
style="margin-top: 16px" | |||
class="btn" | |||
:loading="loading" | |||
@click="startUpload" | |||
> | |||
<n-icon> | |||
<UploadOutlined /> | |||
</n-icon> | |||
开始{{ btnName }}上传 | |||
</n-button> | |||
</div> | |||
</template> | |||
<script setup name="UploadOss"> | |||
import OSS from 'ali-oss' | |||
import { getOssAuth } from '@/api/common/upload.js' | |||
import { ref, reactive, watch, onMounted, toRefs } from 'vue' | |||
import { FileOutlined, UploadOutlined } from '@vicons/antd' | |||
const props = defineProps({ | |||
limit: { | |||
type: Number, | |||
default: 1 | |||
}, | |||
defaultList: { | |||
type: String, | |||
default: '' | |||
}, | |||
fileType: { | |||
type: String, | |||
default: 'img' | |||
}, | |||
btnName: { | |||
type: String, | |||
default: '文件' | |||
}, | |||
remBtn: { | |||
type: Boolean, | |||
default: false | |||
}, | |||
keyName: { | |||
type: String, | |||
default: 'src' | |||
}, | |||
showUploadBtn: { | |||
type: Boolean, | |||
default: false | |||
} | |||
}) | |||
const emit = defineEmits(['uploadStatus']) | |||
const client = ref(null) // 上传实例 | |||
const loading = ref(false) | |||
const data = reactive({ | |||
...props, | |||
client: null, | |||
fileList: [], | |||
hasUploadInfo: {} | |||
}) | |||
onMounted(() => { | |||
if (props.defaultList) { | |||
const list = props.defaultList.split(',') | |||
data.fileList = list.map((item) => { | |||
const objectName = item.split('/').slice(3).join('/') | |||
const obj = { | |||
name: objectName, | |||
id: objectName, | |||
// type: 'image/png', | |||
url: item, | |||
objectName: objectName, | |||
status: 'finished' | |||
} | |||
data.hasUploadInfo[obj.id] = { | |||
id: objectName, | |||
objectName: objectName | |||
} | |||
return obj | |||
}) | |||
emit('uploadStatus', 'upload') | |||
} else { | |||
data.fileList = [] | |||
} | |||
}) | |||
/* 监听默认文件列表 */ | |||
watch(() => props.defaultList, (value) => { | |||
if (value.length) { | |||
const list = value.split(',') | |||
const fileList = list.map((item) => { | |||
const objectName = item.split('/').slice(3).join('/') | |||
const obj = { | |||
name: objectName, | |||
id: objectName, | |||
type: 'image/png', | |||
url: item, | |||
objectName: objectName | |||
} | |||
data.hasUploadInfo[obj.id] = { | |||
id: objectName, | |||
objectName: objectName | |||
} | |||
return obj | |||
}) | |||
data.fileList = fileList | |||
emit('uploadStatus', 'upload') | |||
} else { | |||
data.fileList = [] | |||
// emit('uploadStatus', 'hasFile') | |||
} | |||
}) | |||
/** | |||
* @description: 上传前的判断文件类型 | |||
* @param {*} file 当前选择的文件 | |||
* @return {*} | |||
*/ | |||
const beforeUpload = ({ file }) => { | |||
if (props.fileType === 'img') { | |||
if (!file.type.match('image.*')) { | |||
$message.error('请选择正确的图片类型') | |||
/* 中断流程 */ | |||
return false | |||
} | |||
} | |||
if (props.fileType === 'srt') { | |||
const type = ['srt', 'SRT'] | |||
const temp = type.includes(file.name.split('.')[1]) | |||
if (!temp) { | |||
$message.error('请选择SRT类型文件') | |||
/* 中断流程 */ | |||
return false | |||
} | |||
} | |||
if (props.fileType === 'tif') { | |||
const type = ['tif', 'TIF'] | |||
const temp = type.includes(file.name.split('.')[1]) | |||
if (!temp) { | |||
$message.error('请选择tif类型文件') | |||
/* 中断流程 */ | |||
return false | |||
} | |||
} | |||
} | |||
/** | |||
* @description: 文件发生变化时 | |||
* @param {Array} fileList | |||
* @return {*} | |||
*/ | |||
const handleChange = async({ fileList }) => { | |||
data.fileList = fileList.map((item) => { | |||
if (Object.keys(data.hasUploadInfo).includes(item.id)) { | |||
item.objectName = data.hasUploadInfo[item.id].objectName | |||
} | |||
return item | |||
}) | |||
/* 判断是否存在文件 */ | |||
const status = fileList.length ? 'ready' : 'no-file' | |||
emit('uploadStatus', status) | |||
} | |||
/** | |||
* @description: 上传文件 | |||
* @return {*} | |||
*/ | |||
const startUpload = () => { | |||
return new Promise((resolve, reject) => { | |||
loading.value = true | |||
/* 定义要上传文件 */ | |||
const uploads = [] | |||
/* 从待文件列表中获取没有上传过的文件 */ | |||
const uloadList = data.fileList.filter((item) => { | |||
return !item.url | |||
}) | |||
/* 如果待上传列表长度为0,则返回,否则获取上传鉴权 */ | |||
if (!uloadList.length) { | |||
loading.value = false | |||
/* 如果没有要上传的文件信息则返回oss的文件名 */ | |||
/* 不存在objectName的文件表示上传失败 */ | |||
const objectList = data.fileList.map((item) => item.objectName || 'error') | |||
resolve(objectList) | |||
} else { | |||
getOssAuth().then(res => { | |||
/* 初始化oss上传客户端 */ | |||
data.client = new OSS({ | |||
timeout: 600000, | |||
region: 'oss-cn-shanghai', | |||
secure: true, | |||
accessKeyId: res.data.accessKeyId, | |||
accessKeySecret: res.data.accessKeySecret, | |||
stsToken: res.data.securityToken, | |||
bucket: 'ta-tech-image' | |||
}) | |||
/* promise上传要上传的文件 */ | |||
uloadList.forEach(item => { | |||
uploads.push(uploadOss(item)) | |||
}) | |||
Promise.all(uploads).then((response) => { | |||
/* 获取fileList内的文件存储名称 */ | |||
const objectList = data.fileList.map((item) => item.objectName).filter(it => it) | |||
// resolve(objectList) | |||
resolve({ [props.keyName]: objectList.join() }) | |||
emit('uploadStatus', 'success', { [props.keyName]: objectList.join() }) | |||
loading.value = false | |||
}).catch((error) => { | |||
console.log('error', error) | |||
loading.value = false | |||
resolve(error) | |||
}) | |||
}) | |||
} | |||
}) | |||
} | |||
/** | |||
* 上传到 OSS | |||
* @param {*} files | |||
*/ | |||
const uploadOss = (files) => { | |||
const file = files.file | |||
return new Promise((resolve, reject) => { | |||
/* 生成随机文件名称 */ | |||
const randomString = Math.random().toString(36).slice(2) | |||
const suffix = /\.[^\.]+/.exec(file.name) | |||
const timestamp = new Date().getTime() | |||
const objectName = `/imagedir/${randomString}_${timestamp}${suffix}` | |||
/* 上传文件至oss */ | |||
data.client.put(objectName, file) | |||
.then((res) => { | |||
const index = data.fileList.findIndex(list => list.id === files.id) | |||
data.fileList[index].url = res.url | |||
data.fileList[index].objectName = objectName | |||
const id = data.fileList[index].id | |||
data.hasUploadInfo[id] = { | |||
id: objectName, | |||
objectName: objectName | |||
} | |||
resolve(objectName) | |||
}) | |||
.catch((err) => { | |||
resolve('error') | |||
console.log(err) | |||
}) | |||
}) | |||
} | |||
defineExpose({ startUpload, ...toRefs(data) }) | |||
</script> | |||
<style lang="scss" scoped> | |||
.oss-filed { | |||
width: 100%; | |||
padding: 10px 20px; | |||
} | |||
.oss-upload-picture-card-wrapper { | |||
min-height: 122px; | |||
padding: 10px 0 0 10px; | |||
} | |||
.oss-upload-text { | |||
// width: 100px; | |||
// height: 100px; | |||
// cursor: pointer; | |||
// border: 1px solid #e1e1e1; | |||
// margin: 10px 0 0 10px; | |||
position: relative; | |||
} | |||
.oss-upload-text::before { | |||
content: ''; | |||
position: absolute; | |||
left: 50%; | |||
top: 50%; | |||
width: 30px; | |||
transform: translate(-50%, -50%); | |||
border-top: 2px solid #e1e1e1; | |||
} | |||
.oss-upload-text::after { | |||
content: ''; | |||
position: absolute; | |||
left: 50%; | |||
top: 50%; | |||
height: 30px; | |||
transform: translate(-50%, -50%); | |||
border-left: 2px solid #e1e1e1; | |||
} | |||
.n-image { | |||
img { | |||
overflow: hidden; | |||
} | |||
} | |||
.oss-upload-type { | |||
text-align: center; | |||
font-size: 14px; | |||
color: rgb(64, 152, 252); | |||
} | |||
.btn { | |||
// width: 130px; | |||
margin-left: calc(50% - 65px); | |||
margin-top: 10px; | |||
margin-bottom: 30px; | |||
} | |||
</style> |
@@ -12,7 +12,7 @@ | |||
<n-icon> | |||
<FileOutlined /> | |||
</n-icon> | |||
{{ uploadName }} | |||
选择{{ uploadName }} | |||
</n-button> | |||
</n-upload> | |||
@@ -22,12 +22,13 @@ | |||
:disabled="data.fileList.length === 0" | |||
style="margin-top: 16px" | |||
class="btn" | |||
:loading="loading" | |||
@click="handleUploadStart" | |||
> | |||
<n-icon> | |||
<UploadOutlined /> | |||
</n-icon> | |||
开始上传 | |||
开始{{ uploadName }}上传 | |||
</n-button> --> | |||
</template> | |||
@@ -35,7 +36,7 @@ | |||
<script setup name="UploadVod"> | |||
import { FileOutlined, UploadOutlined } from '@vicons/antd' | |||
import { getAuth, refreshAuth } from '@/api/common/upload.js' | |||
import { reactive } from 'vue' | |||
import { reactive, ref } from 'vue' | |||
const props = defineProps({ | |||
limit: { | |||
@@ -52,10 +53,11 @@ const props = defineProps({ | |||
} | |||
}) | |||
const emit = defineEmits(['uploadStatus']) | |||
const loading = ref(false) | |||
const data = reactive({ | |||
limit: props.limit, | |||
timeout: '', // 请求超时时间 | |||
timeout: 600000, // 请求超时时间 | |||
partSize: '', // 分片大小 | |||
parallel: '', // 分片数 | |||
retryCount: '', // 失败重试次数 | |||
@@ -126,6 +128,7 @@ const createUploader = () => { | |||
}, | |||
// 开始上传 | |||
onUploadstarted: function(uploadInfo) { | |||
loading.value = true | |||
if (uploadInfo.videoId) { | |||
// 如果uploadInfo.videoId存在,调用刷新视频上传凭证接口 | |||
refreshAuth(uploadInfo.videoId).then(res => { | |||
@@ -149,7 +152,8 @@ const createUploader = () => { | |||
const fileName = uploadInfo.file.name | |||
data.fileList.forEach((item) => { | |||
if (item.name === fileName) { | |||
data.readyFile[item.uid].url = '/' + uploadInfo.object | |||
data.readyFile.url = '/' + uploadInfo.object | |||
data.readyFile.videoId = uploadInfo.videoId | |||
} | |||
}) | |||
}, | |||
@@ -187,6 +191,7 @@ const createUploader = () => { | |||
// 全部文件上传结束 | |||
onUploadEnd: function(uploadInfo) { | |||
// console.log('onUploadEnd: uploaded all the files', uploadInfo) | |||
loading.value = false | |||
emit('uploadStatus', { status: 'success', list: data.readyFile, videoIds: data.videoId }) | |||
} | |||
}) | |||
@@ -204,9 +209,10 @@ const handleUploadReady = () => { | |||
if (!Object.keys(data.readyFile).includes(item.uid)) { | |||
const obj = { | |||
name: item.name, | |||
url: '' | |||
url: '', | |||
videoId: '' | |||
} | |||
data.readyFile[item.uid] = obj | |||
data.readyFile = obj | |||
data.uploader.addFile(item, null, null, null, '{"Vod":{}}') | |||
} | |||
}) | |||
@@ -224,10 +230,11 @@ const handleUploadStart = () => { | |||
if (data.uploader !== null) { | |||
data.uploader.startUpload() | |||
emit('uploadStatus', { status: 'uploading', list: data.readyFile }) | |||
return data.readyFile | |||
} | |||
} | |||
defineExpose({ data }) | |||
defineExpose({ data, handleUploadStart }) | |||
</script> | |||
@@ -242,7 +249,7 @@ defineExpose({ data }) | |||
} | |||
.btn { | |||
width: 120px; | |||
// width: 120px; | |||
margin-left: calc(50% - 60px); | |||
margin-top: 10px; | |||
margin-bottom: 30px; |
@@ -114,15 +114,14 @@ | |||
<UploadVod | |||
v-if="data.photographyWay === 1 && isAdmin" | |||
ref="videoRefs" | |||
:auto-upload="true" | |||
:upload-name="'选择【视频】'" | |||
:upload-name="'视频'" | |||
:limit="1" | |||
@upload-status="vodStatusVideo" | |||
/> | |||
<fileOss | |||
v-if="data.photographyWay === 1 && !isAdmin" | |||
:file-type="'video'" | |||
:btn-name="'选择【视频111】'" | |||
:btn-name="'视频'" | |||
:limit="1" | |||
:default-list="data.videoUrl" | |||
@upload-status="vodStatusVideo" | |||
@@ -133,31 +132,32 @@ | |||
ref="srtRefs" | |||
:file-type="'srt'" | |||
:key-name="'srtUrl'" | |||
:btn-name="'选择【轨迹】'" | |||
:btn-name="'轨迹'" | |||
:limit="1" | |||
:default-list="data.srtUrl" | |||
@upload-status="vodStatusSRT" | |||
/> | |||
<fileOss | |||
v-if="data.photographyWay === 2" | |||
ref="ortRefs" | |||
:file-type="'tif'" | |||
:key-name="'orthoUrl'" | |||
:btn-name="'选择【正射影像】'" | |||
:btn-name="'正射影像'" | |||
:show-upload-btn="true" | |||
:limit="9" | |||
:default-list="data.orthoUrl" | |||
@upload-status="statusfile" | |||
/> | |||
<fileOss | |||
v-if="data.photographyWay === 3" | |||
ref="inclinedRefs" | |||
:file-type="'tif'" | |||
:key-name="'inclinedUrl'" | |||
:btn-name="'选择【倾斜影像】'" | |||
:show-upload-btn="true" | |||
:btn-name="'倾斜影像'" | |||
:limit="9" | |||
:default-list="data.inclinedUrl" | |||
@upload-status="statusfile" | |||
/> | |||
<n-button v-if="isAdmin" type="primary" class="btn" :loading="loading" @click="submitFile"> | |||
<n-button v-if="data.photographyWay === 1 && isAdmin" type="primary" class="btn" :loading="loading" @click="submitFile"> | |||
<n-icon> | |||
<UploadOutlined /> | |||
</n-icon> | |||
@@ -174,7 +174,7 @@ import { distributionPilot, pilotOrder, pilotStart, pilotEnd, uploadFlightUrl } | |||
import { form, getPilotList, getEquipment, getEquipmentMount, getCloudMount } from '../tools/drawForm' | |||
import { basic, fly, equipment, execution } from '../hook/index' | |||
import UploadVod from '@/components/UploadVod/index.vue' | |||
import fileOss from '@/components/UploadOss/fileOss.vue' | |||
import fileOss from '@/components/UploadOss/fileUploadOss.vue' | |||
import { UploadOutlined } from '@vicons/antd' | |||
getPilotList() // 获取飞手列表 | |||
@@ -205,20 +205,10 @@ const flyInfo = fly(data) // 飞行信息 | |||
const equipmentInfo = equipment(data) // 设备/影响基本信息 | |||
const executionInfo = execution(data) // 执行中信息 | |||
const videoUrl = ref('') // 视频文件 | |||
const videoId = ref('') // 视频文件 | |||
const videoStatus = ref('') // 视频文件 | |||
const srtUrl = ref('') // srt文件 | |||
// const inclinedUrl = ref('') // 倾斜摄影 | |||
// const orthoUrl = ref('') // 正射影像 | |||
const videoRefs = ref(null) // video refs | |||
const srtRefs = ref(null) // srt refs | |||
const ortRefs = ref(null) // 正射 refs | |||
const inclinedRefs = ref(null) // 倾斜 refs | |||
const loading = ref(false) | |||
const isBtn = ref(false) | |||
const emit = defineEmits(['close']) | |||
@@ -278,77 +268,51 @@ const endFly = () => { | |||
}) | |||
} | |||
// 上传 - 视频 | |||
const vodStatusVideo = ({ status, list, videoIds }) => { | |||
console.log(status, list, videoIds) | |||
videoStatus.value = status | |||
const arr = [] | |||
for (var key in list) { | |||
arr.push(list[key].url) | |||
} | |||
// 只视频上传 | |||
const vodStatusVideo = async({ status, list, videoIds }) => { | |||
// console.log(status, list, videoIds) | |||
// const arr = [] | |||
// for (var key in list) { | |||
// arr.push(list[key].url) | |||
// } | |||
// if (status === 'success') { | |||
// const params = { | |||
// id: data.id, | |||
// videoUrl: arr.join(','), | |||
// videoId: videoIds | |||
// } | |||
// console.log('params', params) | |||
// await uploadFlightUrl(params) | |||
// } | |||
} | |||
// 只文件上传 | |||
const statusfile = async(status, list) => { | |||
if (status === 'success') { | |||
videoUrl.value = arr.join(',') | |||
videoId.value = videoIds | |||
const params = { | |||
id: data.id, | |||
...list | |||
} | |||
await uploadFlightUrl(params) | |||
} | |||
} | |||
// 上传 - SRT | |||
const vodStatusSRT = async(status) => { | |||
srtUrl.value = status | |||
console.log('srtUrl: ---------------', srtUrl.value, status) | |||
} | |||
// watchEffect(() => [videoUrl, srtUrl], ([videoVal], [srtVal]) => { | |||
// console.log('watchEffect-videoVal:', videoVal) | |||
// console.log('watchEffect-srtVal:', srtVal) | |||
// if (videoUrl.value === 'success' && srtVal === 'success') { | |||
// console.log('watchEffect-success all') | |||
// isBtn.value = true | |||
// } | |||
// }) | |||
// 上传 | |||
const submitFile = () => { | |||
if (data.photographyWay === 1) { // 视频 和 srt | |||
// videoRefs.value.data.uploader.startUpload() | |||
srtRefs.value?.startUpload().then(res => { | |||
console.log('srtRefs - res:', res) | |||
if (!res.includes('error')) { | |||
uploadFlightUrl({ | |||
id: data.id, | |||
videoUrl: videoUrl.value, | |||
videoId: videoId.value, | |||
...res[0] | |||
}).then(({ code }) => { | |||
if (code === 0) { | |||
emit('close') | |||
} | |||
}) | |||
} | |||
}) | |||
// 视频和文件上传 | |||
const submitFile = async() => { | |||
loading.value = true | |||
const res = videoRefs.value.handleUploadStart() | |||
const srt = await srtRefs.value?.startUpload() | |||
if (res?.videoId && srt?.srtUrl) { | |||
loading.value = false | |||
const params = { | |||
id: data.id, | |||
...res, | |||
...srt | |||
} | |||
console.log(params) | |||
await uploadFlightUrl(params) | |||
} else { | |||
loading.value = true | |||
const queue = [] | |||
// queue.push(videoRefs.value?.data.uploader.startUpload()) | |||
// queue.push(srtRefs.value?.startUpload()) | |||
queue.push(inclinedRefs.value?.startUpload()) | |||
queue.push(ortRefs.value?.startUpload()) | |||
Promise.all(queue).then(res => { | |||
loading.value = false | |||
const params = {} | |||
res.filter(it => it).forEach(el => { | |||
Object.keys(el).map(dom => { | |||
params[dom] = el[dom] | |||
}) | |||
}) | |||
uploadFlightUrl({ | |||
id: data.id, | |||
...params | |||
}).then(({ code }) => { | |||
if (code === 0) { | |||
emit('close') | |||
} | |||
}) | |||
}) | |||
loading.value = false | |||
} | |||
} | |||
@@ -185,14 +185,19 @@ export default defineComponent({ | |||
center: [data.userForm.startLongitude, data.userForm.startLatitude] | |||
}) | |||
const marker = new AMap.Marker({ | |||
startMarker = new AMap.Marker({ | |||
position: new AMap.LngLat(data.userForm.startLongitude, data.userForm.startLatitude), | |||
icon: '//vdata.amap.com/icons/b18/1/2.png', | |||
title: '起点' | |||
}) | |||
endMarker = new AMap.Marker({ | |||
position: new AMap.LngLat(data.userForm.endLongitude, data.userForm.endLatitude), | |||
icon: '//vdata.amap.com/icons/b18/1/2.png', | |||
title: '终点' | |||
}) | |||
// 将创建的点标记添加到已有的地图实例: | |||
Gmap.add(marker) | |||
Gmap.add([startMarker, endMarker]) | |||
// 起点赋值 | |||
geocoder.getAddress([data.userForm.startLongitude, data.userForm.startLatitude], (status, result) => { | |||
@@ -302,7 +307,7 @@ export default defineComponent({ | |||
} | |||
const isDateDisabled = number => { | |||
return number < dayjs().startOf('day') | |||
return number < dayjs().startOf('minute') | |||
} | |||
return { | |||
...toRefs(data), |
@@ -28,6 +28,11 @@ export default function(data) { | |||
label: '飞行开始时间', | |||
value: data.flightStartTime, | |||
current: 4 | |||
}, | |||
{ | |||
label: '飞行结束时间', | |||
value: data.flightEndTime, | |||
current: 4 | |||
} | |||
] | |||
return customRef((track, trigger) => { |