一、无感刷新
一般后端设置的token过期了,提供了一个新的token
这时候需要再次调用接口获取到token,重新执行之前的接口
这里实现方案:token过期了,后端会在接口返回code = 4005, 根据code查询token接口
import axios from 'axios'
import { session } from '@/utils/cache'
import router from "@/router/index";
const env = import.meta.env
// 是否正在刷新的标记
let isRefreshing = false
var instance = axios.create({
baseURL: env.VITE_API_URL + (env.VITE_NODE_ENV == 'production' ? '/openapi' : '/openapi_prev'),
headers: {
'Content-Type': 'application/json',
'X-Access-Token': session.get('otherToken') || ''
},
responseType: 'json',
timeout: 80000
})
instance.interceptors.request.use(
http => {
http.headers.Authorization = ''
return http
},
error => {
return Promise.reject(error)
}
)
instance.interceptors.response.use(
res => {
// 需要重新获取状态码的判断条件
if(res.data?.code === 4005){
const config = res.config;
if(!isRefreshing) {
isRefreshing = true
session.remove('otherToken')
return refreshToken().then(r => {
if(r?.code !== 0){
//重新请求token失败,跳转到空页面
router?.push('/empty');
} else {
const { token } = r;
session.set("otherToken", token);
config.headers['X-Access-Token'] = session.get("otherToken");
config.headers['Authorization'] = 'Bearer ' + token;
return instance(config);
}
}).catch(err => {
//重新请求token失败
console.log(err, 'token获取err')
} ).finally(()=> {
//完成之后在关闭状态
isRefreshing = false
} )
}
}
return res.data || {}
},
error => {
console.log(error)
return Promise.resolve('')
}
)
// token失效并重新获取
function refreshToken () {
return post("user/v1/refreshLogin", { appId: 1, code: 1 }).then(res => res.data)
}
export function get(url) {
return instance.get(url).then(res => {
console.log('[GET]', url, res)
return Promise.resolve(res)
})
}
export function post(url, params, headers) {
return instance.post(url, params || {}, { headers: headers ? headers : instance.headers }).then(res => {
console.log('[POST]', url, params || {}, res)
return Promise.resolve(res)
})
}
export default {
get,
post
}
二、显示请求上传进度
上传图片、视频等file显示当前进度值
使用axios中的onUploadProgress属性监听上传进度,并将进度反馈给进度条
将请求的进度存到vuex,请求的时候显示进度条,请求成功后隐藏进度条
// 封装的接口函数中获取进度值
export const trainVideoFile = (data, store, file) => {
return request({
url: `/api/VideoFile`,
method: 'post',
data,
onUploadProgress: progressEvent => {
console.log(progressEvent, 'progressEvent');
const complete = parseInt(((progressEvent.loaded / progressEvent.total) * 100) | 0, 10);
console.log(complete, 'complete');
// 存到浏览器缓存,用于刷新页面显示进度
setStorage('videoUploadProgress', complete);
// 存到vuex中,设置参数
store.dispatch('setVideoUploadProgress', {
progressVisible: true,
progressPercent: complete,
});
},
});
};
<template>
<div v-if="!form.trainVideoFileId" class="upload-box">
<el-upload
class="upload"
drag
action="/"
:auto-upload="false"
:disabled="$store.state.videoUploadProgress.progressVisible"
:show-file-list="false"
:on-change="beforeAvatarUpload"
:accept="'.mp4,.mov'"
>
<img class="upload-pic" src="@/assets/images/upload-pic.png" alt="" />
<div class="upload-text">
<div class="text">点击上传视频</div>
<div class="demand">
<div v-for="item in demandList" :key="item.id">{{ item.name }}</div>
</div>
</div>
<!-- progressVisible -->
<div class="upload-progress" v-if="$store.state.videoUploadProgress.progressVisible">
<el-progress
class="progress"
:percentage="$store.state.videoUploadProgress.progressPercent"
></el-progress>
</div>
</el-upload>
</div>
<div v-else class="video-list">
<div class="file-resource">
<div class="flex-center">
<!-- 视频根据上传后的比例 横|竖 设置宽高 -->
<video
:style="[
{
width: '171px',
height: '305px',
objectFit: 'contain',
backgroundColor: '#333',
},
]"
class="video"
:src="videoOptions.fileUrl"
controls
></video>
</div>
</div>
<span @click="handleDeleteAudioFile">
<img class="icon-delete" src="@/assets/images/shanchu@2x.png" alt="" />
删除视频
</span>
</div>
</template>
data() {
return {
uploadRules: false,
uploadRulesMsg: '',
form: {
trainVideoFileId: '',
},
demandList: [
{
id: 1,
name: '1、视频大小不超过1GB,时长不短于1分钟、不长于10分钟',
},
{
id: 2,
name: '2、视频格式为mp4、mov',
},
{
id: 3,
name: '3、视频分辨率1080P,宽高比符合16:9(9:16)',
},
{
id: 4,
name: '4、视频帧率不低于25fps、不高于60fps',
},
],
}
}
methods: {
// 上传接口
async handleVideoFileUpload(file) {
let formData = new FormData();
formData.append('file', file.raw);
const res = await trainVideoFile(formData, this.$store, file);
// 请求成功后隐藏进度条
this.$store.dispatch('setVideoUploadProgress', {
progressVisible: false,
progressPercent: 1,
});
if (res.code == 200) {
const { fileUrl, fileId, fileName } = res.data;
this.form.trainVideoFileId = fileId;
this.videoOptions = {
fileUrl,
fileId,
fileName,
};
this.$message.success('上传成功');
} else {
this.$message.error(res.msg);
}
},
// 文件上传前文件类型、文件大小的处理
beforeAvatarUpload(file) {
console.log(file, '上传格式验证');
if (!file.name) return;
this.validateAudioFile(file)
.then(result => {
if (!result) {
console.error('验证视频文件失败', result);
return false;
} else {
this.handleVideoFileUpload(file);
console.log('上传视频成功');
return true;
}
})
.catch(error => {
console.error('获取视频时长时出错:', error);
return false;
});
},
// 视频文件校验规则
async validateAudioFile(file) {
console.log(file, '获取视频参数');
// 视频格式为mp4、mov
if (file.name) {
const imgType = ['mp4', 'mov'];
const type = file.name.split('.')[file.name.split('.').length - 1];
const isSupportedFormat = imgType.some(ext => ext.toUpperCase() === type.toUpperCase());
if (!isSupportedFormat) {
this.uploadRules = true;
this.uploadRulesMsg = '视频格式不支持';
return false;
}
}
// 视频大小不超过1GB
if (file.size) {
const isLt1G = 1 * 1024 * 1024 * 1024;
if (file.size > isLt1G) {
this.uploadRules = true;
this.uploadRulesMsg = '您的视频大小不符合,请上传大小不超过1GB的视频';
return false;
}
}
// 视频raw
if (file.raw) {
const video = await this.getVideoDuration(file.raw);
const duration = video.duration; // 视频时长
const width = video.videoWidth; // 视频宽度
const height = video.videoHeight; // 视频高度
const aspectRatio = width / height; // 视频宽高比
const fps = video.captureStream().getVideoTracks()[0].getSettings().frameRate; // 视频帧率
// 视频时长时长不短于1分钟、不长于10分钟
if (duration < 60 || duration > 600) {
this.uploadRules = true;
this.uploadRulesMsg = '您的视频时长不符合,请上传时长为1-10分钟的视频';
return false;
}
// 视频分辨率1080P,宽高比符合16:9(9:16)
if (aspectRatio !== 16 / 9 && aspectRatio !== 9 / 16) {
this.uploadRules = true;
this.uploadRulesMsg = '您的视频宽高比不符合,请上传视频分辨率1080P,宽高比符合16:9(9:16)';
return false;
}
// 视频分辨率1080P
if (width < 1920 || height < 1080) {
this.uploadRules = true;
this.uploadRulesMsg = '您的视频分辨率不符合,视频分辨率1080P,宽高比符合16:9(9:16)';
return false;
}
// 视频帧率不低于25fps、不高于60fps
if (fps < 25 || fps > 60) {
this.uploadRules = true;
this.uploadRulesMsg = '您的视频帧率不符合,请上传帧率不低于25fps、不高于60fps的视频';
return false;
}
}
return true;
},
// 根据文件获取视频时长
getVideoDuration(file) {
return new Promise((resolve, reject) => {
const video = document.createElement('video');
video.preload = 'metadata';
video.onloadedmetadata = () => {
resolve(video);
};
video.onerror = () => {
reject(new Error('无法加载视频文件'));
};
video.src = URL.createObjectURL(file);
});
},
}