视频图片上传
主页面
<template>
<!--意见反馈 -->
<view
:style="{'paddingTop': navMenuHeight}"
class="feedback">
<navBar :navParams="navParams"></navBar>
<view class="problem">
<view class="blem">
遇到的问题/建议
</view>
<view class="text">
*感谢您的宝贵建议*
</view>
</view>
<view class="Ineam">
<view class="veTeam">
<!-- @blur="leaveInput"
@focus="getHeight" -->
<textarea
class="uni-textarea"
:adjust-position="false"
@input="submit"
v-model="autograph"
maxlength="500"
:customStyle="{lineHeight: '80rpx'}"
placeholder="建议您尽可能详细的描述问题,便于运营同学帮您解决"/>
<view class="num"><text class="yuu">{{autolength}}</text>/500</view>
</view>
</view>
<view class="Upload-ew">
<view class="ew">
<view class="upheatd">
上传截图
</view>
<view class="upew">
<!-- <view class="intalve">
</view> -->
<filePicker
ref="imgRulesChild"
:objPicker="objPicker"
@afterRead="afterRead"
@deleteRead="deleteRead"></filePicker>
</view>
</view>
</view>
<view class="Upload-ew">
<view class="ew">
<view class="upheatd">
上传视频
</view>
<view class="upew">
<filevideo
ref="videoRulesChild"
:videoList="videoList"
@afterVideo="afterVideo"
@deleteVideo="deleteVideo"></filevideo>
</view>
</view>
</view>
<view class="btn-ew">
<view
@tap="btnSubmit"
:class="[autograph.length > 0 ? 'brnve': 'brnve brntyr']">
提交</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref ,reactive ,onMounted} from 'vue'
import navBar from '@/components/navBar/index.vue'
import filePicker from '../components/filePicker.vue'
import filevideo from '../components/video.vue'
import { submitFeedback } from '@/api/personal/index'
import type { NavBarParams } from '@/components/types/navBar';
import { STORAGE_KEYS } from '@/utils/constant'
import phone from '../static/img/phone.png'
const navMenuHeight = ref(uni.getStorageSync(STORAGE_KEYS.NAV_MENU_HEIGHT))
const title = ref('layout')
const autograph = ref('')
const autolength = ref(0)
// 上传图片
let objPicker = reactive({
text:'父组件值',
limit:3,//图片上传数量
imageValue:[]
})
const videoStr = ref('')
const imageStr = ref('')
const imgRulesChild = ref(null)
const videoRulesChild = ref(null)
// 上传视频
const videoList = reactive([])
const imageList = reactive([])
const navParams:NavBarParams = {
'bg':'#131220', //背景色
'color':'#FFFFFF', //字体颜色
'isBack':true, //是否显示返回按钮,由于导航栏是共用的,把所有的东西封装好,
'isFullScreen':true, // 是否全屏显示
// 然后有些页面不需要的东西通过条件控制进行显示与隐藏
'navTitle': '意见反馈' ,//导航标题
'isSearch':false,//是否显示搜索图标
list:[]
}
// 页面图片
const pageImg = reactive({
phone: `background: url('${phone}') center center / cover no-repeat;`,
})
// const goRecharge = () => {
// if(rechargeRulesChild.value) {
// rechargeRulesChild.value.goPay()
// isShowPayType.value = false
// }
// }
// 提交
const btnSubmit = () =>{
if(objPicker.imageValue.length>=1){
imgValStr(objPicker.imageValue,'img')
}
if(videoList.length>=1){
imgValStr(objPicker.imageValue,'video')
}
if(autograph.value.length>0){
console.log('autograph=======》',autograph)
submitfee()
}
}
const submitfee= () => {
let params = {
image:imageStr.value,
video:videoStr.value,
content:autograph.value
}
submitFeedback(params).then(data => {
let res:any = data
if(res.errcode == 0) {
autograph.value = ''
autolength.value = 0
if(imgRulesChild.value) {
imgRulesChild.value.imageChild()
}
if(videoRulesChild.value) {
videoRulesChild.value.videoChild()
}
objPicker.imageValue.length = 0
videoList.length = 0
console.log('点击事件=====》2333',res)
console.log('点击事件=====》imageValue.length',objPicker.imageValue)
console.log('点击事件=====》2333',videoList)
}
})
}
// 上传视频
const afterVideo = (e:any) =>{
videoList.length = 0
videoList.push(...e)
console.log('afterVideo=========> ',videoList)
}
const deleteVideo = (e:any) =>{
videoList.length = 0
videoList.push(...e)
console.log('deleteVideo=========>',videoList)
}
const imgValStr = (e:any,val:string) =>{
let arr = reactive([])
e.forEach((item,index)=>{
arr.push(item.url)
})
if(val=='img'){
imageStr.value = arr.join(',')
console.log('imageStr.value====>',imageStr.value)
}else if(val=='video'){
videoStr.value = arr.join(',')
console.log('videoStr.value====>',videoStr.value)
}else {
videoStr.value = arr.join(',')
}
}
// 上传截图
const afterRead = (e:any) =>{
objPicker.imageValue.length=0
objPicker.imageValue.push(...e)
console.log('afterReadobjPicker.imageValue=========>',objPicker.imageValue)
}
const deleteRead = (e:any) =>{
objPicker.imageValue.length=0
objPicker.imageValue.push(...e)
console.log('deleteRead=========>',objPicker.imageValue)
}
// 多行文本框
const submit = (e:any) => {
autolength.value = e.detail.value.length
}
// const leaveInput = (event:any) =>{ //输入框失去焦点时触发,event.detail = {value: value}
// console.log('e=========>',event)
// // Height.value = 20;
// }
// const getHeight = (event:any) =>{ //输入框聚焦时触发,event.detail = { value, height },height 为键盘高度
// console.log('获取输入法高度=========>',event)
// // Height.value = event.target.height+20;
// }
onMounted(() => {
})
</script>
<style lang="scss">
.feedback{
width: 750rpx;
min-height: 100vh;
background-color: #131220;
// display: flex;
// overflow:hidden;
// // flex-direction: column;
// // align-items: center;
// justify-content: center;
overflow: auto;
-webkit-overflow-scrolling: touch;
overflow-y:unset;
// 遇到问题
.problem{
margin-left: 60rpx;
margin-top: 80rpx;
width: 690rpx;
.blem{
height: 44rpx;
line-height: 44rpx;
font-size: 40rpx;
font-family: Source Han Sans CN, Source Han Sans CN-Medium;
font-weight: 500;
text-align: left;
color: #ffffff;
}
.text{
margin-top: 24rpx;
height: 26rpx;
line-height: 26rpx;
font-size: 26rpx;
font-family: Source Han Sans CN, Source Han Sans CN-Regular;
font-weight: 400;
text-align: left;
color: #898990;
}
}
.Ineam{
width: 750rpx;
padding-bottom: 40rpx;
border-bottom: 10rpx solid #1a1b2b;
margin-top: 80rpx;
.veTeam{
width: 710rpx;
height: auto;
border-radius: 16rpx;
background-color: #1f1e2b;
margin: 0 auto;
position: relative;
.uni-textarea{
width: 670rpx;
padding: 20rpx 20rpx;
height: 240rpx;
background: #1f1e2b;
border-radius: 16rpx;
font-size: 30rpx;
font-family: Source Han Sans CN, Source Han Sans CN-Medium;
font-weight: 500;
text-align: left;
color: #8f8f95;
line-height: 70rpx;
line-height:normal;
}
.num{
position: absolute;
right: 0rpx;
bottom:20rpx;
width: 120rpx;
height: 30rpx;
line-height: 30rpx;
font-size: 30rpx;
color: #8f8f95;
// display: flex;
// justify-content: flex-end;
.yuu{
color: #8f8f95;
}
}
}
}
.Upload-ew{
width: 750rpx;
margin-top: 50rpx;
.ew{
margin: 0 auto;
width: 710rpx;
.upheatd{
width: 710rpx;
height: 32rpx;
font-size: 30rpx;
font-family: Source Han Sans CN, Source Han Sans CN-Medium;
font-weight: 500;
text-align: left;
color: #ffffff;
}
.upew{
width: 710rpx;
height: auto;
display: flex;
flex-direction: row;
.intalve{
width: 160rpx;
height: 160rpx;
background-color: #f4f5f7;
border-radius: 4rpx;
margin: 0 16rpx 16rpx 0;
box-sizing: border-box;
}
}
}
}
.btn-ew{
width: 750rpx;
margin-top: 150rpx;
margin-bottom: 100rpx;
.brnve{
width: 348rpx;
height: 84rpx;
line-height:84rpx;
background: #ea4459;
font-size: 30rpx;
font-family: Source Han Sans CN, Source Han Sans CN-Medium;
font-weight: 500;
text-align: center;
color: #ffffff;
border-radius: 40rpx;
margin: 0 auto;
}
.brntyr{
opacity: 0.3;
background: #ea4459;
}
}
}
</style>
图片组件
<template>
<!-- 上传图片组件 -->
<!-- v-model="objPicker" -->
<view class="title">
<!-- {{title}} 组件 {{objPicker}} -->
<view class="ew">
<u-upload
:fileList="imageValue"
@afterRead="afterRead"
@delete="deletePic"
name="1"
multiple
:maxCount="3"
:previewFullImage="true"
></u-upload>
</view>
</view>
</template>
<script setup lang="ts">
import { ref , reactive ,computed ,onMounted ,getCurrentInstance} from 'vue'
const title = ref('layout')
const imageValue = reactive([]);
const {proxy} = getCurrentInstance()//全局定义的路径
// 父组件传值
const props =defineProps(
{
objPicker:{
type:Object,
required:true
}
// fileList:{
// type:Array,
// required:true
// }
}
)
const emits=defineEmits(["afterRead","deleteRead"])
// 图片上传
const uploadImg = (tempFilePaths:any,) =>{
console.log('err数据返回====》1111111111111111111')
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: proxy.$baseUrl + '/common/uploadFile',
// header: {
// 'Authorization': getToken() ? getToken() : '',
// },
filePath:tempFilePaths.url,
name: 'file',
formData: {
storeType:6,
fileName: 'jrjz' + new Date().getTime(),
fileDir: 'deal',
fileNameType: 0,
file: tempFilePaths,
},
success: (res) => {
let succ = JSON.parse(res.data)//数据返回字符串解析
setTimeout(() => {
resolve(succ.data.url)
}, 1000)
// resolve({
// url: succ.data.url,
// extname: 'png',
// name: succ.data.fileName
// })
},
fail:(err)=>{
console.log('err数据返回====》',err)
},
})
// const path = tempFilePaths.pop();
// wx.cropImage({
// src: tempFilePaths.url, // 图片路径
// cropScale: '1:1', // 裁剪比例
// success:(res)=>{
// },
// })
})
}
// 获取上传状态
const afterRead = async(event:any) =>{
// console.log('获取上传状态',e)
let fileList = imageValue
// const res = await uploadImg(e.tempFilePaths,1);
// emits('loghty', props.objPicker.imageValue)
let lists = [].concat(event.file);
let fileListLen = fileList.length;
lists.map((item) => {
fileList.push({
...item,
status: 'uploading',
message: '上传中',
});
});
console.log('err数据返回====》22222222222')
for (let i = 0; i < lists.length; i++) {
const result = await uploadImg(lists[i]);
let item = fileList[fileListLen];
fileList.splice(fileListLen, 1, {
...item,
status: 'success',
message: '',
url: result,
});
console.log('图片上传fileList====》',fileList)
emits('afterRead',fileList)
fileListLen++;
}
console.log('err数据返回====》1111111111111111111')
}
// 获取上传进度
// const progress = (e:any) =>{
// console.log('上传进度:',e)
// }
// 删除
const deletePic = (event:any) =>{
let fileList = imageValue
// this.$refs.files.upload()
fileList.splice(event.index, 1);
// emits('afterRead',fileList)
console.log('图片删除fileList====》',fileList)
emits('deleteRead',fileList)
// emit('deletePic',this[`fileList${event.name}`])
console.log('删除',event)
}
const imageChild = () =>{
imageValue.length = 0
}
// 抛出子组件方法让父组件调用
defineExpose({
imageChild
})
// 上传失败
// const fail = (e:any) =>{
// console.log('上传失败:',e)
// }
// // 删除
// const handleDelete = (e:any) =>{
// console.log('删除按钮:',e)
// const num = props.objPicker.imageValue.findIndex(v => v.url === e.tempFilePath);
// props.objPicker.imageValue.splice(num, 1);
// console.log('删除按钮:num',num)
// emits('inChange', props.objPicker.imageValue)
// }
onMounted(() => {
// itemH.value = Math.ceil(document.body.clientWidth * (90/375))
// loading.value = false
})
</script>
<style lang="scss">
.title{
margin-top: 40rpx;
// width: 375rpx;
height: auto;
// .ew{
// border: 1px solid red;
// }
}
</style>
视频组件
<template>
<view class="title">
<!-- 视频 -->
<view class="up-video">
<!-- <view class="up-label">视频:</view> -->
<view v-show="videoList.length>0" class="up-video-box">
<view class="v-box" v-for="(item,index) in videoList" :key="index">
<!-- -->
<view class="v-inner" >
<video style="width: 172px;height: 72px;" :src="item.url"
enable-auto-rotation="true"
autoplay='true'
muted>
</video>
</view>
<view class="c-icon">
<u-icon @click="deleteVideo(index)" name="close" color="#fff" size="8"></u-icon>
</view>
</view>
<view v-if="videoList.length<3" class="box-s" @click="videoRead">
<u-icon name="camera-fill" color="#d3d4d6" size="26"></u-icon>
</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref , reactive,computed,onMounted} from 'vue'
const {proxy} = getCurrentInstance()
const title = ref('layout')
const videoList = reactive([])
// 父组件传值
const props =defineProps(
// {
// videoList:{
// type:Array,
// required:true
// }
// }
)
// 子组件给父组件穿值
const emits=defineEmits(["afterVideo","deleteVideo"])
const videoRead = () =>{
// let that = this;
let arr =reactive([]);
let strPath = ref('');
uni.chooseVideo({
sourceType: ['camera', 'album'],
success: function (res) {
arr = res.tempFilePath.split("/");
strPath = arr[arr.length - 1];
if(videoList.length>3)return
videoList.push({
url: res.tempFilePath,
videoName: strPath
});
addUpload([{
url: res.tempFilePath,
videoName: strPath
}]);
}
});
}
const addUpload = (videoArr:any) =>{
// let werArr =reactive([]);
// werArr.push(...videoArr)
console.log('videoArr===>',proxy.$baseUrl)
console.log('videoArr.length===>',videoArr.length)
videoArr.forEach((item:any) => { //这里之所以循环一个一个上传是因为,我是用于小程序端的,目前uniapp不支持微信小程序以文件列表形式上传,
uni.uploadFile({
url: proxy.$baseUrl + '/common/uploadFile', //需要传图片的后台接口
filePath: item.url, // 上传图片 通过uni-app的uni-file-picker组件 函数返回
name: 'file', //文件名字
formData: {
storeType:6,
fileName: 'jrjz' + new Date().getTime(),
fileDir: 'deal',
fileNameType: 0,
file: item,
},
success: res => {
console.log('videoList==>11111')
let result = JSON.parse(res.data);
console.log('props.videoList',videoList)
videoList.forEach(v => {
console.log('videoList==>11111')
// console.log('v===>',v)
if(v.videoName === item.videoName) {
v.url = result.data.url;
console.log('v["url"]===>',v.url,'result.data.url==>',result.data.url)
// console.log('videoList==>',videoList.length)
}
});
emits('afterVideo',videoList)
},
fail: e => {
console.log(e)
}
});
});
}
const deleteVideo = (index:any)=> {
videoList.splice(index, 1);
emits('deleteVideo',videoList)
}
const tabActiveBg = computed((item:any) => {
return `<video autoplay style="width: 172px;height: 72px;" "><source src="${item}" type="video/mp4"></video>`
})
const videoChild = () =>{
videoList.length = 0
}
defineExpose({
videoChild
})
onMounted(() => {
// itemH.value = Math.ceil(document.body.clientWidth * (90/375))
// loading.value = false
})
</script>
<style lang="scss">
.title{
margin-top: 40rpx;
.up-video {
display: flex;
.up-video-box {
// width: calc(100% - 105px);
display: flex;
flex-wrap: wrap;
.v-box {
width: 160rpx;
height: 160rpx;
position: relative;
overflow: hidden;
margin: 0 16rpx 16rpx 0;
// padding: 20rpx 20rpx 0rpx 0rpx;
box-sizing: border-box;
background: #010101;
.v-inner {
width: 160rpx;
height: 160rpx;
position: absolute;
bottom: 0rpx;
left: 0rpx;
}
.c-icon {
position: absolute;
top: -14rpx;
right: -14rpx;
background: #373737;
border-radius: 50%;
width: 40rpx;
height: 40rpx;
display: flex;
justify-content: center;
align-items: center;
padding: 12rpx 12rpx 0px 0px;
box-sizing: border-box;
}
}
.box-s {
display: flex;
align-items: center;
justify-content: center;
width: 160rpx;
height: 160rpx;
background-color: #f4f5f7;
border-radius: 4rpx;
margin: 0 16rpx 16rpx 0;
box-sizing: border-box;
}
}
}
}
</style>