修改巡检图片视频内容

This commit is contained in:
xuli
2025-12-19 16:54:02 +08:00
parent d32152912a
commit 3da8fe4027
24 changed files with 627 additions and 269 deletions

9
package-lock.json generated
View File

@@ -30,6 +30,7 @@
"minio": "^8.0.6", "minio": "^8.0.6",
"minio-js": "^1.0.7", "minio-js": "^1.0.7",
"pinia": "2.0.20", "pinia": "2.0.20",
"uniapp-video-player": "^1.3.0",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vue": "3.4.21", "vue": "3.4.21",
"vue-i18n": "9.14.5" "vue-i18n": "9.14.5"
@@ -12288,6 +12289,14 @@
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/uniapp-video-player": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/uniapp-video-player/-/uniapp-video-player-1.3.0.tgz",
"integrity": "sha512-WZa/U836ou053pzqijL2EzDrN1VX2e7Dj4R/xSMKzhcotaTqTLTc9xL832xkgwPDFmL5MEecGuyPsw2sE4hutA==",
"peerDependencies": {
"vue": "^2.6.0 || ^3.0.0"
}
},
"node_modules/unicode-canonical-property-names-ecmascript": { "node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",

View File

@@ -62,6 +62,7 @@
"minio": "^8.0.6", "minio": "^8.0.6",
"minio-js": "^1.0.7", "minio-js": "^1.0.7",
"pinia": "2.0.20", "pinia": "2.0.20",
"uniapp-video-player": "^1.3.0",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vue": "3.4.21", "vue": "3.4.21",
"vue-i18n": "9.14.5" "vue-i18n": "9.14.5"

View File

@@ -184,7 +184,7 @@ const getCurrentMonth = ()=>{
padding:20rpx 0 0; padding:20rpx 0 0;
/* #endif */ /* #endif */
width: calc(100% / 4 - 12px); /* 减去一些间隙以避免溢出 */ width: calc(100% / 4 - 12px); /* 减去一些间隙以避免溢出 */
margin: 10rpx; /* 可选,用于添加间距 */ margin: 9rpx; /* 可选,用于添加间距 */
} }
.month-item.active { .month-item.active {

View File

@@ -1,6 +1,9 @@
<template> <template>
<!-- 放大后的遮罩层 --> <!-- 放大后的遮罩层 -->
<view v-if="isEnlarged" class="image-preview-overlay" @click="handleClose"> <view v-if="isEnlarged" class="image-preview-overlay">
<view class="image-preview-close" @click="handleClose">
<uni-icons type="closeempty" size="18" color="#fff"></uni-icons>
</view>
<block v-if="getFileType(mediaUrl)=='image'"> <block v-if="getFileType(mediaUrl)=='image'">
<image <image
:src="mediaUrl" :src="mediaUrl"
@@ -10,12 +13,24 @@
</block> </block>
<view :class="videoClass" v-else-if="getFileType(mediaUrl)=='video'"> <view :class="videoClass" v-else-if="getFileType(mediaUrl)=='video'">
<!-- object-fit="cover" --> <!-- object-fit="cover" -->
<video :src="mediaUrl" controls @loadedmetadata="onVideoLoaded"></video> <!-- <video :src="mediaUrl" controls @loadedmetadata="onVideoLoaded"></video> -->
<!--
src: '' // 视频地址
autoplay: false // 是否自动播放
loop: false // 是否循环播放
controls: false // 是否显示控制栏
muted: false // 是否静音
isLoading: false // Android系统加载时显示loading(为了遮挡安卓的黑色按钮)
objectFit: 'contain' // 视频尺寸与video区域的适应模式
poster: '' // 视频封面
-->
<DomVideoPlayer :src="mediaUrl" controls autoplay />
</view> </view>
</view> </view>
</template> </template>
<script setup> <script setup>
import DomVideoPlayer from 'uniapp-video-player'
import { ref,watch } from 'vue'; import { ref,watch } from 'vue';
import {getFileType} from '@/utils/common.js'; import {getFileType} from '@/utils/common.js';
const props = defineProps({ const props = defineProps({
@@ -54,7 +69,7 @@ const onVideoLoaded = (e) => {
let w = e.detail.width; let w = e.detail.width;
let h = e.detail.height; let h = e.detail.height;
// 你也可以在这里进行后续操作比如根据宽高比调整UI // 你也可以在这里进行后续操作比如根据宽高比调整UI
console.log(w,h) // console.log(w,h)
if(h>w){ if(h>w){
videoClass.value="enlarged-image" videoClass.value="enlarged-image"
}else{ }else{
@@ -77,6 +92,21 @@ const onVideoLoaded = (e) => {
align-items: center; align-items: center;
z-index: 10000; z-index: 10000;
} }
.image-preview-overlay .image-preview-close{
position: absolute;
width:50rpx;
height:50rpx;
line-height: 50rpx;
text-align: center;
border-radius: 50%;
right:20rpx;
top:20rpx;
/* #ifdef APP-PLUS */
top:44rpx;
/* #endif */
background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
:deep(uni-video){ :deep(uni-video){
width:100%; width:100%;

View File

@@ -1,7 +1,7 @@
{ {
"id" : "H5E705637", "id" : "H5E705637",
"name" : "718友晟", "name" : "718友晟",
"appid" : "__UNI__0B682E1", "appid" : "__UNI__4C459F4",
"description" : "", "description" : "",
"versionName" : "1.0.2", "versionName" : "1.0.2",
"versionCode" : "100", "versionCode" : "100",
@@ -63,7 +63,7 @@
"<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" />", "<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" />",
"<uses-permission android:name=\"android.permission.NFC\"/>", "<uses-permission android:name=\"android.permission.NFC\"/>",
"<uses-feature android:name=\"android.hardware.nfc\" android:required=\"true\"/>", "<uses-feature android:name=\"android.hardware.nfc\" android:required=\"true\"/>",
"<uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\"/>" "<uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\"/>"
], ],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a" ], "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
"minSdkVersion" : 23, "minSdkVersion" : 23,
@@ -87,22 +87,22 @@
"unipush" : { "unipush" : {
"version" : "2", "version" : "2",
"offline" : true, "offline" : true,
"icons" : { "icons" : {
"push" : { "push" : {
"ldpi" : "/static/images/icon.png", "ldpi" : "/static/images/icon.png",
"mdpi" : "/static/images/icon.png", "mdpi" : "/static/images/icon.png",
"hdpi" : "/static/images/icon.png", "hdpi" : "/static/images/icon.png",
"xhdpi" : "/static/images/icon.png", "xhdpi" : "/static/images/icon.png",
"xxhdpi" : "/static/images/icon.png" "xxhdpi" : "/static/images/icon.png"
}, },
"small" : { "small" : {
"ldpi" : "/static/images/icon_small.png", "ldpi" : "/static/images/icon_small.png",
"mdpi" : "/static/images/icon_small.png", "mdpi" : "/static/images/icon_small.png",
"hdpi" : "/static/images/icon_small.png", "hdpi" : "/static/images/icon_small.png",
"xhdpi" : "/static/images/icon_small.png", "xhdpi" : "/static/images/icon_small.png",
"xxhdpi" : "/static/images/icon_small.png" "xxhdpi" : "/static/images/icon_small.png"
} }
} }
} }
} }
} }
@@ -155,3 +155,5 @@
"template" : "index.html" "template" : "index.html"
} }
} }
/* ios */

View File

@@ -170,7 +170,7 @@
</template> </template>
<script setup> <script setup>
import { ref,onMounted } from 'vue' import { ref,onMounted } from 'vue'
import { onLoad,onHide } from '@dcloudio/uni-app'; import { onLoad,onShow,onHide } from '@dcloudio/uni-app';
import customHeader from '@/components/customHeader.vue'; import customHeader from '@/components/customHeader.vue';
import MescrollUni from 'mescroll-uni/mescroll-uni.vue'; import MescrollUni from 'mescroll-uni/mescroll-uni.vue';
import { parseTime } from '@/utils/datetime.js'; import { parseTime } from '@/utils/datetime.js';
@@ -188,6 +188,7 @@ onLoad(option => {
let list1 = ref([]); let list1 = ref([]);
let list2 = ref([]); let list2 = ref([]);
let list3 = ref([]); let list3 = ref([]);
let mescroll = null; // 用于存放mescroll实例
const mescrollRef = ref(null); const mescrollRef = ref(null);
const upOption = ref({ const upOption = ref({
use: false, use: false,
@@ -209,8 +210,16 @@ const downOption = ref({
}); });
let cssFlag=ref(false);//控制样式 let cssFlag=ref(false);//控制样式
const mescrollInit = (mescroll) => {
onShow(()=>{
if(mescroll)
mescroll.triggerDownScroll()
})
const mescrollInit = (mescrollInstance) => {
cssFlag.value = true; cssFlag.value = true;
mescroll = mescrollInstance;
// mescroll.setMescroll(mescrollRef.value); // 绑定mescroll实例
mescrollRef.value = mescroll; mescrollRef.value = mescroll;
}; };

View File

@@ -141,13 +141,23 @@
<view>{{ item.pointName }}</view> <view>{{ item.pointName }}</view>
</view> </view>
<view class="img-flex"> <view class="img-flex">
<view class="img-show" v-for="(item2,index) in item.imgArr2" :key="index" @click="showMediaPreview(item2)"> <view class="img-show" v-for="(item2,index2) in item.imgArr2" :key="index2" @click="showMediaPreview(item2)">
<img :src="item2.shortUrl" /> <view class="img-delete" @click.stop="handleDelete(item,index,index2)">
<uni-icons type="closeempty" size="16" color="#fff"></uni-icons>
</view>
<image :src="item2.shortUrl" mode="aspectFill" />
</view> </view>
<view class="img-con" @click="chooseImage(item)"> <view class="img-con" @click="chooseImage(item,index)">
<img :src="'static/images/polling/icon-AddPic.png'" class="img-pic" /> <img :src="'static/images/polling/icon-AddPic.png'" class="img-pic" />
<view>添加照片</view> <view>添加照片</view>
<!-- loading -->
<view class="upload-loading" v-if="item.loading">
<uni-icons type="refreshempty" size="30" color="#C9C9C9"></uni-icons>
<view>上传中....</view>
</view>
</view> </view>
</view> </view>
</block> </block>
<!-- 视频 --> <!-- 视频 -->
@@ -157,12 +167,24 @@
<view>{{ item.pointName }}</view> <view>{{ item.pointName }}</view>
</view> </view>
<view class="img-flex"> <view class="img-flex">
<view class="img-show" v-for="(item2,index) in item.videoArr2" :key="index" @click="showMediaPreview(item2)"> <view class="img-show" v-for="(item2,index2) in item.videoArr2" :key="index2" @click="showMediaPreview(item2)">
<video :src="item2.url" controls v-show="videoShow"></video> <view class="img-delete" @click.stop="handleDelete(item,index,index2)">
<uni-icons type="closeempty" size="16" color="#fff"></uni-icons>
</view>
<view class="img-icon">
<img :src="'static/images/polling/icon-play.png'" />
</view>
<!-- <video :src="item2.url" controls v-show="videoShow"></video> -->
<DomVideoPlayer :src="item2.url" objectFit="cover" />
</view> </view>
<view class="img-con" @click="chooseVideo(item)"> <view class="img-con" @click="chooseVideo(item,index)">
<img :src="'static/images/polling/icon-AddVideo.png'" class="img-pic" /> <img :src="'static/images/polling/icon-AddVideo.png'" class="img-pic" />
<view>添加视频</view> <view>添加视频</view>
<!-- loading -->
<view class="upload-loading" v-if="item.loading">
<uni-icons type="refreshempty" size="30" color="#C9C9C9"></uni-icons>
<view>上传中....</view>
</view>
</view> </view>
</view> </view>
</block> </block>
@@ -232,7 +254,7 @@
</template> </template>
<script setup> <script setup>
import { ref,onMounted,onUnmounted,nextTick,computed,reactive,getCurrentInstance } from 'vue' import { ref,onMounted,onUnmounted,nextTick,computed,reactive,getCurrentInstance } from 'vue'
import { onLoad,onHide} from '@dcloudio/uni-app'; import { onLoad,onShow,onHide} from '@dcloudio/uni-app';
import { MINIO_KEY } from '@/enums/cacheEnums'; import { MINIO_KEY } from '@/enums/cacheEnums';
import customHeader from '@/components/customHeader.vue'; import customHeader from '@/components/customHeader.vue';
@@ -242,14 +264,16 @@ import pollingShowModal from "@/components/pollingShowModal.vue";
import customShowModal from "@/components/customShowModal.vue" import customShowModal from "@/components/customShowModal.vue"
import mediaPreview from "@/components/mediaPreview.vue" import mediaPreview from "@/components/mediaPreview.vue"
import NFCTemplate from "@/components/NFCTemplate.vue" import NFCTemplate from "@/components/NFCTemplate.vue"
import DomVideoPlayer from 'uniapp-video-player'
import { parseTime } from '@/utils/datetime.js'; import { parseTime } from '@/utils/datetime.js';
import { formatTaskStatus } from '@/utils/status.js'; import { formatTaskStatus } from '@/utils/status.js';
import { taskGroupDetail,submitResult,minioUpload } from '@/api/polling.js' import { taskGroupDetail,submitResult,minioUpload } from '@/api/polling.js'
import {compressImageUni} from '@/utils/common.js' import {compressImageUni,getVideoFirstFrame} from '@/utils/common.js'
// import {uploadFileMinio} from '@/utils/minio.js' // import {uploadFileMinio} from '@/utils/minio.js'
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
let imgLoading = ref(false);
let taskId = ref(undefined); let taskId = ref(undefined);
let groupId = ref(undefined); let groupId = ref(undefined);
let minioObj = {}; let minioObj = {};
@@ -260,7 +284,11 @@ onLoad(option => {
minioObj = JSON.parse(uni.getStorageSync(MINIO_KEY) || "\{\}") minioObj = JSON.parse(uni.getStorageSync(MINIO_KEY) || "\{\}")
// console.log(minioObj) // console.log(minioObj)
})
onShow(()=>{
getList();
}) })
// 下拉刷新 // 下拉刷新
@@ -269,6 +297,7 @@ const mescrollInit = (mescroll) => {
mescrollRef.value = mescroll; mescrollRef.value = mescroll;
}; };
const downOption = ref({ const downOption = ref({
use:false,
auto: true, auto: true,
textInOffset: '下拉刷新', textInOffset: '下拉刷新',
textOutOffset: '释放更新', textOutOffset: '释放更新',
@@ -304,6 +333,7 @@ const getList = async() => {
item['videoArr']=[]; item['videoArr']=[];
item['videoArr2']=[]; item['videoArr2']=[];
item['chooseList']=[]; item['chooseList']=[];
item.loading=false;
if(item.resultContent){ if(item.resultContent){
if(item.pointType==2 ||item.pointType==1){ if(item.pointType==2 ||item.pointType==1){
item['chooseList'] = item.resultContent.split(",") //JSON.parse(item.resultContent) item['chooseList'] = item.resultContent.split(",") //JSON.parse(item.resultContent)
@@ -363,11 +393,10 @@ const changeCheck = (param,param2,item) => {
} }
// 照片及拍照处理 // 照片及拍照处理
// const imgArr = ref([]); const chooseImage = (item,index) => {
// const imgArr2=ref([]);
const chooseImage = (item) => {
// console.log("item=>",item) // console.log("item=>",item)
try { try {
uni.chooseImage({ uni.chooseImage({
// count: 1, // 默认是9这里设置为1次只选1张 // count: 1, // 默认是9这里设置为1次只选1张
// sizeType: ['compressed'], // 可以指定是原图还是压缩图,可选 'original' 或 'compressed' // sizeType: ['compressed'], // 可以指定是原图还是压缩图,可选 'original' 或 'compressed'
@@ -394,23 +423,28 @@ const chooseImage = (item) => {
formData: { formData: {
directory:'polling' directory:'polling'
}, },
} }
optionObj.value.pointList[index].loading=true;
minioUpload(param).then(res=>{ minioUpload(param).then(res=>{
let data = res.data; let data = res.data;
// console.log("444图片上传成功=>",data) item.imgArr2.push({
// imgArr2.value.push(data.fileUrl)
item['imgArr2'].push({
shortUrl:minioObj.minioThumbUrl +"/"+data.fileName, shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName, url:minioObj.minioUrl +"/"+data.fileName,
}) })
item['imgArr'].push(data.fileName)//传给后台的路径 item.imgArr.push(data.fileName)//传给后台的路径
item.resultContent = item['imgArr'].join(",")
})
optionObj.value.pointList[index].imgArr=[...item.imgArr]
optionObj.value.pointList[index].imgArr2=[...item.imgArr2]
optionObj.value.pointList[index].resultContent = item.imgArr.join(",");
// console.log("上传成功后=>",optionObj.value.pointList[index])
}).finally(()=>{
optionObj.value.pointList[index].loading=false;
})
}) })
}, },
fail: (err) => { fail: (err) => {
console.log('选择图片失败', err); console.log('选择图片失败', err);
} }
}); });
} catch (error) { } catch (error) {
@@ -419,22 +453,20 @@ const chooseImage = (item) => {
}; };
// 视频处理 // 视频处理
// const videoSrc = ref(''); const chooseVideo = (item,index) => {
// const videoArr = ref([]);
// const videoArr2 = ref([]);
const chooseVideo = (item) => {
uni.chooseVideo({ uni.chooseVideo({
sourceType: ['album', 'camera'], // 来源:相册和相机 sourceType: ['album', 'camera'], // 来源:相册和相机
maxDuration: 60, // 最大时长(秒) maxDuration: 60, // 最大时长(秒)
camera: 'back', // 使用后置摄像头 camera: 'back', // 使用后置摄像头
compressed: true, // 压缩视频 compressed: true, // 压缩视频
success: (res) => { success: async (res) => {
console.log("res=>",res) // console.log("res=>",res)
// videoSrc.value=res.tempFilePath; // videoSrc.value=res.tempFilePath;
// videoArr.value.push(res.tempFilePath) // videoArr.value.push(res.tempFilePath)
console.log('视频路径:', res.tempFilePath); // console.log('视频路径:', res.tempFilePath);
// console.log('视频时长:', res.duration); // console.log('视频时长:', res.duration);
// console.log('视频大小:', res.size); // console.log('视频大小:', res.size);
// 执行上传 // 执行上传
let param = { let param = {
filePath: res.tempFilePath, filePath: res.tempFilePath,
@@ -442,18 +474,24 @@ const chooseVideo = (item) => {
formData: { formData: {
directory:'polling' directory:'polling'
}, },
} }
minioUpload(param).then(uploadRes=>{ optionObj.value.pointList[index].loading=true;
minioUpload(param).then(uploadRes=>{
let data = uploadRes.data; let data = uploadRes.data;
item['videoArr'].push(data.fileName)//传给后台的路径 item.videoArr2.push({
item['videoArr2'].push(data.fileUrl) shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
item.resultContent = item['videoArr'].join(",") url:data.fileUrl
});
item.videoArr.push(data.fileName)//传给后台的路径
optionObj.value.pointList[index].videoArr=[...item.videoArr];
optionObj.value.pointList[index].videoArr2=[...item.videoArr2];
optionObj.value.pointList[index].resultContent = item.videoArr.join(",");
// console.log(optionObj.value.pointList[index])
}).finally(()=>{ }).finally(()=>{
optionObj.value.pointList[index].loading=false;
}) })
},fail: (err) => {
},
fail: (err) => {
console.error('选择视频失败:', err); console.error('选择视频失败:', err);
} }
}); });
@@ -474,6 +512,26 @@ const handlePreviewClose=()=>{
videoShow.value = true; videoShow.value = true;
} }
// 视频或图片删除 根据数组下标删除数组里的某个图片或视频
const handleDelete=(item,index,index2)=>{
let imgArr2 = optionObj.value.pointList[index].imgArr2;
let videoArr2 = optionObj.value.pointList[index].videoArr2
if(imgArr2.length>0){
item.imgArr.splice(index2, 1);
item.imgArr2.splice(index2, 1);
optionObj.value.pointList[index].imgArr = [...item.imgArr]
optionObj.value.pointList[index].imgArr2 = [...item.imgArr2]
optionObj.value.pointList[index].resultContent = item.imgArr.join(",");
}else if(videoArr2.length>0){
item.videoArr.splice(index2, 1);
item.videoArr2.splice(index2, 1);
optionObj.value.pointList[index].videoArr = [...item.videoArr]
optionObj.value.pointList[index].videoArr2 = [...item.videoArr2]
optionObj.value.pointList[index].resultContent = item.videoArr.join(",");
}
// console.log("删除后=>",optionObj.value.pointList[index])
}
// nfc 处理 // nfc 处理
let nfcShow = ref(false); let nfcShow = ref(false);
const nfcReaderRef = ref(null); const nfcReaderRef = ref(null);
@@ -497,9 +555,9 @@ const nfcClose = async(item) => {
const handleNfcData=(data)=>{ const handleNfcData=(data)=>{
console.log("NFC数据:", data); console.log("NFC数据:", data);
console.log("NFC数据1111:", optionObj.value.pointList,nfcIndex.value) // console.log("NFC数据1111:", optionObj.value.pointList,nfcIndex.value)
optionObj.value.pointList[nfcIndex.value].resultContent = data; optionObj.value.pointList[nfcIndex.value].resultContent = data;
console.log("NFC数据1111:", optionObj.value.pointList[nfcIndex.value]) // console.log("NFC数据1111:", optionObj.value.pointList[nfcIndex.value])
// nfcShow.value = false; // nfcShow.value = false;
} }
@@ -553,7 +611,7 @@ const handleSubmit=()=>{
groupId:groupId.value, groupId:groupId.value,
resultList:arr resultList:arr
} }
console.log(flag) // console.log("submitParam=>",submitParam)
// 都答好了直接提交 // 都答好了直接提交
if(!flag){ if(!flag){
@@ -640,10 +698,10 @@ onUnmounted(() => {
.scroll-h{ .scroll-h{
/* #ifdef APP-PLUS */ /* #ifdef APP-PLUS */
height:calc(100vh - 78px) !important; height:calc(100vh - 76px) !important;
/* #endif */ /* #endif */
/* #ifndef APP-PLUS */ /* #ifndef APP-PLUS */
height: calc(100vh - 60px) !important; height: calc(100vh - 58px) !important;
/* #endif */ /* #endif */
} }
.head-right{} .head-right{}
@@ -750,11 +808,15 @@ onUnmounted(() => {
display: flex; display: flex;
flex-flow:row wrap; flex-flow:row wrap;
margin-bottom:30rpx; margin-bottom:30rpx;
/* gap:30rpx 20rpx ; */
width:100%;
} }
.report-list .img-show img, .report-list .img-show img,
.report-list .img-show video{ .report-list .img-show video,
.report-list .img-show image,
.report-list .img-show .player-wrapper{
width:210rpx; width:210rpx;
height: 140rpx; height:140rpx;
} }
.report-list .img-show :deep(.uni-video-cover-play-button){ .report-list .img-show :deep(.uni-video-cover-play-button){
width:64rpx; width:64rpx;
@@ -782,6 +844,41 @@ onUnmounted(() => {
margin:20rpx 20rpx 0 0; margin:20rpx 20rpx 0 0;
} }
.report-list .img-show{
position: relative;
}
.report-list .img-show .img-delete{
position: absolute;
/* #ifndef APP-PLUS */
right:4rpx;
/* #endif */
/* #ifdef APP-PLUS */
right:4rpx;
/* #endif */
top:4rpx;
width:34rpx;
height:34rpx;
line-height:34rpx;
border-radius:3rpx;
background-color: rgba(0, 0, 0, 0.6);
text-align: center;
z-index:1;
}
.report-list .img-show .img-icon{
position: absolute;
top:50%;
left: 50%;
width: 64rpx;
height:64rpx;
margin-left:-32rpx;
margin-top:-32rpx;
z-index:1;
}
.report-list .img-show .img-icon img{
width: 64rpx;
height:64rpx;
}
.bg-border{ .bg-border{
width:750rpx; width:750rpx;
height:20rpx; height:20rpx;

View File

@@ -54,16 +54,20 @@
<view class="report-border"></view> <view class="report-border"></view>
<view class="report-list">问题点位照片或视频</view> <view class="report-list">问题点位照片或视频</view>
<view class="report-list"> <view class="report-list">
<block v-for="(item,index) in problemObj.listFile" :key="index"> <view class="img-flex">
<view class="img-flex"> <block v-for="(item2,index2) in problemObj.listFile" :key="index2">
<view class="img-show" v-if="getFileType(item)=='image'" @click="showMediaPreview(minioObj.minioUrl+'/'+item)"> <view class="img-show" v-if="getFileType(item2)=='image'" @click="showMediaPreview(item2)">
<img :src="minioObj.minioThumbUrl+'/'+item" /> <image :src="minioObj.minioThumbUrl+'/'+item2" mode="aspectFill" />
</view> </view>
<view class="img-show" v-else-if="getFileType(item)=='video'" @click="showMediaPreview(minioObj.minioUrl+'/'+item)"> <view class="img-show" v-else-if="getFileType(item2)=='video'" @click="showMediaPreview(item2)">
<video :src="minioObj.minioUrl+'/'+item" controls v-show="videoShow"></video> <view class="img-icon">
<img :src="'static/images/polling/icon-play.png'" />
</view>
<!-- <video :src="minioObj.minioUrl+'/'+item" controls v-show="videoShow"></video> -->
<DomVideoPlayer :src="minioObj.minioUrl+'/'+item2" objectFit="cover" v-show="videoShow" />
</view> </view>
</view> </block>
</block> </view>
</view> </view>
<!-- 当天提的 增加按钮 修改和删除 --> <!-- 当天提的 增加按钮 修改和删除 -->
@@ -87,12 +91,16 @@
<view class="report-list">检查点位照片或视频</view> <view class="report-list">检查点位照片或视频</view>
<view class="report-list"> <view class="report-list">
<view class="img-flex"> <view class="img-flex">
<block v-for="(item,index) in item.listFile" :key="index"> <block v-for="(item2,index2) in item.listFile" :key="index2">
<view class="img-show" v-if="getFileType(item)=='image'" @click="showMediaPreview(minioObj.minioUrl+'/'+item)"> <view class="img-show" v-if="getFileType(item2)=='image'" @click="showMediaPreview(item2)">
<img :src="minioObj.minioThumbUrl+'/'+item" /> <image :src="minioObj.minioThumbUrl+'/'+item2" mode="aspectFill" />
</view> </view>
<view class="img-show" v-else-if="getFileType(item)=='video'" @click="showMediaPreview(minioObj.minioUrl+'/'+item)"> <view class="img-show" v-else-if="getFileType(item2)=='video'" @click="showMediaPreview(item2)">
<video :src="minioObj.minioUrl+'/'+item" controls v-show="videoShow"></video> <view class="img-icon">
<img :src="'static/images/polling/icon-play.png'" />
</view>
<!-- <video :src="minioObj.minioUrl+'/'+item" controls v-show="videoShow"></video> -->
<DomVideoPlayer :src="minioObj.minioUrl+'/'+item2" objectFit="cover" v-show="videoShow" />
</view> </view>
</block> </block>
</view> </view>
@@ -114,6 +122,7 @@ import { onLoad,onShow,onHide} from '@dcloudio/uni-app';
import customHeader from '@/components/customHeader.vue'; import customHeader from '@/components/customHeader.vue';
import MescrollUni from 'mescroll-uni/mescroll-uni.vue'; import MescrollUni from 'mescroll-uni/mescroll-uni.vue';
import mediaPreview from "@/components/mediaPreview.vue" import mediaPreview from "@/components/mediaPreview.vue"
import DomVideoPlayer from 'uniapp-video-player'
import { parseTime } from '@/utils/datetime.js'; import { parseTime } from '@/utils/datetime.js';
import {getFileType} from '@/utils/common.js'; import {getFileType} from '@/utils/common.js';
import { problemDetail,problemDel } from '@/api/polling.js' import { problemDetail,problemDel } from '@/api/polling.js'
@@ -180,9 +189,10 @@ let isVisible= ref(false);//放大处理
let mediaUrl= ref('');//放大地址 let mediaUrl= ref('');//放大地址
let videoShow = ref(true); let videoShow = ref(true);
const showMediaPreview=(url)=>{ const showMediaPreview=(url)=>{
url = minioObj.minioUrl+'/'+url;
isVisible.value = true; isVisible.value = true;
videoShow.value = false; videoShow.value = false;
mediaUrl.value = url mediaUrl.value = url;
} }
const handlePreviewClose=()=>{ const handlePreviewClose=()=>{
isVisible.value = false; isVisible.value = false;
@@ -323,6 +333,7 @@ const handleDelete=()=>{
display: flex; display: flex;
flex-flow:row wrap; flex-flow:row wrap;
margin-bottom:30rpx; margin-bottom:30rpx;
width:100%;
} }
.report-list .img-con{ .report-list .img-con{
background-color: #EEEEEE; background-color: #EEEEEE;
@@ -342,10 +353,28 @@ const handleDelete=()=>{
width: calc(100% / 3 - 10px); /* 减去一些间隙以避免溢出 */ width: calc(100% / 3 - 10px); /* 减去一些间隙以避免溢出 */
margin:20rpx 20rpx 0 0; margin:20rpx 20rpx 0 0;
} }
.report-list .img-show{
position: relative;
}
.report-list .img-show .img-icon{
position: absolute;
top:50%;
left: 50%;
width: 64rpx;
height:64rpx;
margin-left:-32rpx;
margin-top:-32rpx;
z-index:1;
}
.report-list .img-show .img-icon img{
width: 64rpx;
height:64rpx;
}
.report-list .img-show img, .report-list .img-show img,
.report-list .img-show video{ .report-list .img-show video,
.report-list .img-show image,
.report-list .img-show .player-wrapper{
width:210rpx; width:210rpx;
height: 140rpx; height: 140rpx;
} }

View File

@@ -42,15 +42,30 @@
<view class="report-list" style="display:block;"> <view class="report-list" style="display:block;">
<view class="r-title">问题点位照片或视频 <text>*</text></view> <view class="r-title">问题点位照片或视频 <text>*</text></view>
<view class="img-flex"> <view class="img-flex">
<view class="img-show" v-for="(item,index) in imgArr" :key="index"> <view class="img-show" v-for="(item2,index2) in imgArr" :key="index2" @click="showMediaPreview(item2)">
<img :src="item" /> <view class="img-delete" @click.stop="handleDelete(imgArr,index2)">
<uni-icons type="closeempty" size="16" color="#fff"></uni-icons>
</view>
<image :src="item2.shortUrl" mode="aspectFill" />
</view> </view>
<view class="img-show" v-for="(item,index) in videoArr" :key="index"> <view class="img-show" v-for="(item2,index2) in videoArr" :key="index2" @click="showMediaPreview(item2)">
<video :src="item" controls></video> <view class="img-delete" @click.stop="handleDelete(videoArr,index2)">
<uni-icons type="closeempty" size="16" color="#fff"></uni-icons>
</view>
<view class="img-icon">
<img :src="'static/images/polling/icon-play.png'" />
</view>
<!-- <video :src="item" controls></video> -->
<DomVideoPlayer :src="item2.url" objectFit="cover" />
</view> </view>
<!-- #ifdef APP-PLUS --> <!-- #ifdef APP-PLUS -->
<view class="img-con" @click="chooseMedia"> <view class="img-con" @click="chooseMedia">
<img :src="'static/images/polling/icon-AddPorV.png'" class="img-pic" /> <img :src="'static/images/polling/icon-AddPorV.png'" class="img-pic" />
<!-- loading -->
<view class="upload-loading" v-if="imgLoading">
<uni-icons type="refreshempty" size="30" color="#C9C9C9"></uni-icons>
<view>上传中....</view>
</view>
</view> </view>
<!-- #endif --> <!-- #endif -->
<!-- #ifndef APP-PLUS --> <!-- #ifndef APP-PLUS -->
@@ -66,6 +81,9 @@
</view> </view>
</mescroll-uni> </mescroll-uni>
</view> </view>
<!-- 图片放大 -->
<mediaPreview :visible="isVisible" :url="mediaUrl" @close="handlePreviewClose"></mediaPreview>
</view> </view>
</template> </template>
@@ -74,6 +92,8 @@ import { ref,onMounted,onUnmounted,nextTick,computed,reactive } from 'vue'
import { onLoad,onHide, onShow} from '@dcloudio/uni-app'; import { onLoad,onHide, onShow} from '@dcloudio/uni-app';
import customHeader from '@/components/customHeader.vue'; import customHeader from '@/components/customHeader.vue';
import MescrollUni from 'mescroll-uni/mescroll-uni.vue'; import MescrollUni from 'mescroll-uni/mescroll-uni.vue';
import mediaPreview from "@/components/mediaPreview.vue"
import DomVideoPlayer from 'uniapp-video-player'
import { getUserInfo } from '@/api/auth.js' import { getUserInfo } from '@/api/auth.js'
import { problemDetail,problemAddLog,minioUpload } from '@/api/polling.js' import { problemDetail,problemAddLog,minioUpload } from '@/api/polling.js'
import { MINIO_KEY } from '@/enums/cacheEnums'; import { MINIO_KEY } from '@/enums/cacheEnums';
@@ -83,12 +103,16 @@ import {compressImageUni} from '@/utils/common.js'
let problemId = ref(''); let problemId = ref('');
let realname = ref(''); let realname = ref('');
let desc = ref('');//描述 let desc = ref('');//描述
let minioObj = {};
onLoad(async option => { onLoad(async option => {
// console.log(option) // console.log(option)
problemId.value = option.problemId; problemId.value = option.problemId;
minioObj = JSON.parse(uni.getStorageSync(MINIO_KEY) || "\{\}")
let userinfo = await getUserInfo({}); let userinfo = await getUserInfo({});
realname.value = userinfo.realname realname.value = userinfo.realname
}) })
onShow(()=>{ onShow(()=>{
@@ -105,6 +129,7 @@ const mescrollInit = (mescroll) => {
mescrollRef.value = mescroll; mescrollRef.value = mescroll;
}; };
const downOption = ref({ const downOption = ref({
use:false,
auto: false, auto: false,
textInOffset: '下拉刷新', textInOffset: '下拉刷新',
textOutOffset: '释放更新', textOutOffset: '释放更新',
@@ -133,6 +158,7 @@ const getList = async () => {
let mediaArr = ref([]);//传给后台的地址 let mediaArr = ref([]);//传给后台的地址
let imgArr=ref([]);//图片 后台返回的 let imgArr=ref([]);//图片 后台返回的
let videoArr = ref([]);//视频 后台返回的 let videoArr = ref([]);//视频 后台返回的
let imgLoading = ref(false)
const chooseMedia = () => { const chooseMedia = () => {
uni.chooseMedia({ uni.chooseMedia({
count: 9, count: 9,
@@ -159,21 +185,57 @@ const chooseMedia = () => {
formData: { formData: {
directory:'polling' directory:'polling'
}, },
} }
imgLoading.value=true;
minioUpload(param).then(res=>{ minioUpload(param).then(res=>{
let data = res.data; let data = res.data;
mediaArr.value.push(data.fileName); mediaArr.value.push(data.fileName);
if (file.fileType === 'image') {// 图片 if (file.fileType === 'image') {// 图片
imgArr.value.push(data.fileUrl) // imgArr.value.push(data.fileUrl)
} else if (file.type === 'video') {// 视频 imgArr.value.push({
videoArr.value.push(data.fileUrl) shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName,
name:data.fileName
})
} else if (file.fileType === 'video') {// 视频
// videoArr.value.push(data.fileUrl)
videoArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName,
name:data.fileName
})
} }
}).finally(()=>{
imgLoading.value=false;
}) })
}); });
} }
}); });
} }
// 视频或图片删除 根据数组下标删除数组里的某个图片或视频
const handleDelete=(arr,index2)=>{
arr.splice(index2, 1);
let item = arr[index2];
mediaArr.value = mediaArr.value.filter(item2=>item2!=item.name);
// console.log("删除后=>",mediaArr.value)
}
// 放大视频或图片
let isVisible= ref(false);//放大处理
let mediaUrl= ref('');//放大地址
let videoShow = ref(true);
const showMediaPreview=(item)=>{
// console.log("调用放大视频==>",item)
isVisible.value = true;
videoShow.value = false;
mediaUrl.value = item.url
}
const handlePreviewClose=()=>{
isVisible.value = false;
videoShow.value = true;
}
// 提交 // 提交
const handleSubmit=()=>{ const handleSubmit=()=>{
let param = { let param = {
@@ -181,7 +243,7 @@ const handleSubmit=()=>{
logVedio:mediaArr.value.join(","), logVedio:mediaArr.value.join(","),
logDesc:desc.value logDesc:desc.value
} }
console.log("problemAddLog=>",param) // console.log("problemAddLog=>",param)
problemAddLog(param).then(res=>{ problemAddLog(param).then(res=>{
showAlert("新建问题跟踪成功!"); showAlert("新建问题跟踪成功!");
uni.navigateBack(); uni.navigateBack();
@@ -311,6 +373,27 @@ const handleSubmit=()=>{
padding-top:5rpx; padding-top:5rpx;
/* #endif */ /* #endif */
} }
.report-list .img-flex{
display: flex;
flex-flow:row wrap;
margin-bottom:30rpx;
width:100%;
}
.report-list .img-show img,
.report-list .img-show image,
.report-list .img-show video,
.report-list .img-show .player-wrapper{
width:210rpx;
height: 140rpx;
}
.report-list .img-show :deep(.uni-video-cover-play-button){
width:64rpx;
height: 64rpx;
line-height: 64rpx;
font-size:60rpx;
}
.report-list .img-con{ .report-list .img-con{
background-color: #EEEEEE; background-color: #EEEEEE;
width:210rpx; width:210rpx;
@@ -335,6 +418,41 @@ const handleSubmit=()=>{
margin-left:0; margin-left:0;
} }
.report-list .img-show{
position: relative;
}
.report-list .img-show .img-delete{
position: absolute;
/* #ifndef APP-PLUS */
right:4rpx;
/* #endif */
/* #ifdef APP-PLUS */
right:4rpx;
/* #endif */
top:8rpx;
width:34rpx;
height:34rpx;
line-height:34rpx;
border-radius:3rpx;
background-color: rgba(0, 0, 0, 0.6);
text-align: center;
z-index:1;
}
.report-list .img-show .img-icon{
position: absolute;
top:50%;
left: 50%;
width: 64rpx;
height:64rpx;
margin-left:-32rpx;
margin-top:-32rpx;
z-index:1;
}
.report-list .img-show .img-icon img{
width: 64rpx;
height:64rpx;
}
.btn-submit{ .btn-submit{
width:400rpx; width:400rpx;
margin:90rpx auto; margin:90rpx auto;

View File

@@ -45,15 +45,32 @@
<view class="report-list" style="display:block;"> <view class="report-list" style="display:block;">
<view class="r-title">问题点位照片或视频 <text>*</text></view> <view class="r-title">问题点位照片或视频 <text>*</text></view>
<view class="img-flex"> <view class="img-flex">
<view class="img-show" v-for="(item,index) in imgArr" :key="index" @click="showMediaPreview(item)"> <view class="img-show" v-for="(item2,index2) in imgArr" :key="index2" @click="showMediaPreview(item2)">
<img :src="item.shortUrl" /> <view class="img-delete" @click.stop="handleDelete(imgArr,index2)">
<uni-icons type="closeempty" size="16" color="#fff"></uni-icons>
</view>
<!-- <img :src="item2.shortUrl" /> -->
<image :src="item2.shortUrl" mode="aspectFill" />
</view> </view>
<view class="img-show" v-for="(item,index) in videoArr" :key="index" @click="showMediaPreview(item)"> <view class="img-show" v-for="(item2,index2) in videoArr" :key="index2" @click="showMediaPreview(item2)">
<video :src="item.url" controls></video> <view class="img-delete" @click.stop="handleDelete(videoArr,index2)">
<uni-icons type="closeempty" size="16" color="#fff"></uni-icons>
</view>
<view class="img-icon">
<img :src="'static/images/polling/icon-play.png'" />
</view>
<!-- <video :src="item.url" controls></video> -->
<DomVideoPlayer :src="item2.url" objectFit="cover" />
</view> </view>
<!-- #ifdef APP-PLUS --> <!-- #ifdef APP-PLUS -->
<view class="img-con" @click="chooseMedia"> <view class="img-con" @click="chooseMedia">
<img :src="'static/images/polling/icon-AddPorV.png'" class="img-pic" /> <img :src="'static/images/polling/icon-AddPorV.png'" class="img-pic" />
<!-- loading -->
<view class="upload-loading" v-if="imgLoading">
<uni-icons type="refreshempty" size="30" color="#C9C9C9"></uni-icons>
<view>上传中....</view>
</view>
</view> </view>
<!-- #endif --> <!-- #endif -->
<!-- #ifndef APP-PLUS --> <!-- #ifndef APP-PLUS -->
@@ -77,10 +94,11 @@
<script setup> <script setup>
import { ref,onMounted,onUnmounted,nextTick,computed,reactive, watch } from 'vue' import { ref,onMounted,onUnmounted,nextTick,computed,reactive, watch } from 'vue'
import { onLoad,onHide} from '@dcloudio/uni-app'; import { onLoad,onShow,onHide} from '@dcloudio/uni-app';
import customHeader from '@/components/customHeader.vue'; import customHeader from '@/components/customHeader.vue';
import MescrollUni from 'mescroll-uni/mescroll-uni.vue'; import MescrollUni from 'mescroll-uni/mescroll-uni.vue';
import mediaPreview from "@/components/mediaPreview.vue" import mediaPreview from "@/components/mediaPreview.vue"
import DomVideoPlayer from 'uniapp-video-player'
import { getUserInfo } from '@/api/auth.js' import { getUserInfo } from '@/api/auth.js'
import { problemDetail,problemAdd,problemEdit,minioUpload } from '@/api/polling.js' import { problemDetail,problemAdd,problemEdit,minioUpload } from '@/api/polling.js'
import {compressImageUni,getFileType} from '@/utils/common.js' import {compressImageUni,getFileType} from '@/utils/common.js'
@@ -103,6 +121,10 @@ onLoad(async option => {
let userinfo = await getUserInfo({}); let userinfo = await getUserInfo({});
realname.value = userinfo.realname realname.value = userinfo.realname
})
onShow(()=>{
getList();
}) })
// 查询列表 // 查询列表
@@ -115,6 +137,7 @@ const mescrollInit = (mescroll) => {
mescrollRef.value = mescroll; mescrollRef.value = mescroll;
}; };
const downOption = ref({ const downOption = ref({
use:false,
auto: true, auto: true,
textInOffset: '下拉刷新', textInOffset: '下拉刷新',
textOutOffset: '释放更新', textOutOffset: '释放更新',
@@ -163,11 +186,13 @@ const getList = async () => {
imgArr.value.push({ imgArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+item, shortUrl:minioObj.minioThumbUrl +"/"+item,
url:minioObj.minioUrl +"/"+item, url:minioObj.minioUrl +"/"+item,
name:item
}) })
}else if(getFileType(item)=='video'){ }else if(getFileType(item)=='video'){
videoArr.value.push({ videoArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+item, shortUrl:minioObj.minioThumbUrl +"/"+item,
url:minioObj.minioUrl +"/"+item, url:minioObj.minioUrl +"/"+item,
name:item
}) })
} }
}) })
@@ -178,6 +203,7 @@ const getList = async () => {
let mediaArr = ref([]);//传给后台的地址 let mediaArr = ref([]);//传给后台的地址
let imgArr=ref([]);//图片 后台返回的 let imgArr=ref([]);//图片 后台返回的
let videoArr = ref([]);//视频 后台返回的 let videoArr = ref([]);//视频 后台返回的
let imgLoading = ref(false)
const chooseMedia = () => { const chooseMedia = () => {
uni.chooseMedia({ uni.chooseMedia({
count: 9, count: 9,
@@ -206,23 +232,28 @@ const chooseMedia = () => {
formData: { formData: {
directory:'polling' directory:'polling'
}, },
} }
imgLoading.value=true;
minioUpload(param).then(res=>{ minioUpload(param).then(res=>{
let data = res.data; let data = res.data;console.log("上传成功后=>",res)
mediaArr.value.push(data.fileName); mediaArr.value.push(data.fileName);
if (file.fileType === 'image') {// 图片 if (file.fileType === 'image') {// 图片
// imgArr.value.push(data.fileUrl) // imgArr.value.push(data.fileUrl)
imgArr.value.push({ imgArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+data.fileName, shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName, url:minioObj.minioUrl +"/"+data.fileName,
name:data.fileName
}) })
} else if (file.type === 'video') {// 视频 } else if (file.fileType === 'video') {// 视频
// videoArr.value.push(data.fileUrl) // videoArr.value.push(data.fileUrl)
videoArr.value.push({ videoArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+data.fileName, shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName, url:minioObj.minioUrl +"/"+data.fileName,
name:data.fileName
}) })
} }
}).finally(()=>{
imgLoading.value=false;
}) })
}); });
@@ -230,11 +261,20 @@ const chooseMedia = () => {
}); });
} }
// 视频或图片删除 根据数组下标删除数组里的某个图片或视频
const handleDelete=(arr,index2)=>{
arr.splice(index2, 1);
let item = arr[index2];
mediaArr.value = mediaArr.value.filter(item2=>item2!=item.name);
console.log("删除后=>",mediaArr.value)
}
// 放大视频或图片 // 放大视频或图片
let isVisible= ref(false);//放大处理 let isVisible= ref(false);//放大处理
let mediaUrl= ref('');//放大地址 let mediaUrl= ref('');//放大地址
let videoShow = ref(true); let videoShow = ref(true);
const showMediaPreview=(item)=>{ const showMediaPreview=(item)=>{
// console.log("调用放大视频==>",item)
isVisible.value = true; isVisible.value = true;
videoShow.value = false; videoShow.value = false;
mediaUrl.value = item.url mediaUrl.value = item.url
@@ -419,9 +459,12 @@ const handleSubmit=()=>{
display: flex; display: flex;
flex-flow:row wrap; flex-flow:row wrap;
margin-bottom:30rpx; margin-bottom:30rpx;
width:100%;
} }
.report-list .img-show img, .report-list .img-show img,
.report-list .img-show video{ .report-list .img-show image,
.report-list .img-show video,
.report-list .img-show .player-wrapper{
width:210rpx; width:210rpx;
height: 140rpx; height: 140rpx;
} }
@@ -450,6 +493,40 @@ const handleSubmit=()=>{
width: calc(100% / 3 - 10px); /* 减去一些间隙以避免溢出 */ width: calc(100% / 3 - 10px); /* 减去一些间隙以避免溢出 */
margin:20rpx 20rpx 0 0; margin:20rpx 20rpx 0 0;
} }
.report-list .img-show{
position: relative;
}
.report-list .img-show .img-delete{
position: absolute;
/* #ifndef APP-PLUS */
right:4rpx;
/* #endif */
/* #ifdef APP-PLUS */
right:4rpx;
/* #endif */
top:8rpx;
width:34rpx;
height:34rpx;
line-height:34rpx;
border-radius:3rpx;
background-color: rgba(0, 0, 0, 0.6);
text-align: center;
z-index:1;
}
.report-list .img-show .img-icon{
position: absolute;
top:50%;
left: 50%;
width: 64rpx;
height:64rpx;
margin-left:-32rpx;
margin-top:-32rpx;
z-index:1;
}
.report-list .img-show .img-icon img{
width: 64rpx;
height:64rpx;
}
.btn-submit{ .btn-submit{

View File

@@ -205,160 +205,8 @@ const getList = (pageIndex, pageSize) => {
taskId:taskId.value taskId:taskId.value
} }
let res = await taskDetail(param); let res = await taskDetail(param);
// let res = {
// "code": 200,
// "msg": "操作成功",
// "data": {
// taskId:236,
// taskName:'日常巡检任务AAA',
// planTime:new Date().getTime(),
// progress:62,
// count:3,
// total:9,
// workHour:1,
// list:[
// {
// workName:'技术中心机房总电源',
// pointId:202512297899,
// workStatus:3,
// planTime:'10:25',
// workHour:1,
// count:0,
// total:70,
// percentage:'30%'
// },
// {
// workName:'监控室消防设备阀门正常开启闭合',
// workId:202512297899,
// workStatus:3,
// planTime:'10:25',
// workHour:1,
// count:20,
// total:70,
// percentage:'40%'
// },
// {
// workName:'监控室10组灭火器压力指针处于绿色区域',
// workId:202512297899,
// workStatus:4,
// planTime:'10:25',
// workHour:1,
// count:70,
// total:70,
// percentage:'100%'
// },
// {
// workName:'库房灭火器压力指针处于绿色区',
// workId:202512297899,
// workStatus:5,
// planTime:'10:25',
// workHour:1,
// count:70,
// total:70,
// percentage:'100%'
// },
// {
// workName:'技术中心机房总电源',
// pointId:202512297899,
// workStatus:3,
// planTime:'10:25',
// workHour:1,
// count:0,
// total:70,
// percentage:'30%'
// },
// {
// workName:'监控室消防设备阀门正常开启闭合',
// workId:202512297899,
// workStatus:3,
// planTime:'10:25',
// workHour:1,
// count:20,
// total:70,
// percentage:'40%'
// },
// {
// workName:'监控室10组灭火器压力指针处于绿色区域',
// workId:202512297899,
// workStatus:4,
// planTime:'10:25',
// workHour:1,
// count:70,
// total:70,
// percentage:'100%'
// },
// {
// workName:'库房灭火器压力指针处于绿色区',
// workId:202512297899,
// workStatus:5,
// planTime:'10:25',
// workHour:1,
// count:70,
// total:70,
// percentage:'100%'
// },
// {
// workName:'技术中心机房总电源',
// pointId:202512297899,
// workStatus:3,
// planTime:'10:25',
// workHour:1,
// count:0,
// total:70,
// percentage:'30%'
// },
// {
// workName:'监控室消防设备阀门正常开启闭合',
// workId:202512297899,
// workStatus:3,
// planTime:'10:25',
// workHour:1,
// count:20,
// total:70,
// percentage:'40%'
// },
// {
// workName:'监控室10组灭火器压力指针处于绿色区域',
// workId:202512297899,
// workStatus:4,
// planTime:'10:25',
// workHour:1,
// count:70,
// total:70,
// percentage:'100%'
// },
// {
// workName:'库房灭火器压力指针处于绿色区',
// workId:202512297899,
// workStatus:5,
// planTime:'10:25',
// workHour:1,
// count:70,
// total:70,
// percentage:'100%'
// },
// ],
// questList:[
// {
// problemDesc:'西区地下车库入口防汛物资摆放',
// problemId:202512297899,
// problemStatus:1,
// modifyTime:new Date().getTime(),
// count:0,
// },
// {
// problemDesc:'监控室消防设备阀门确保正常开启闭合',
// problemId:202512297899,
// problemStatus:2,
// modifyTime:new Date().getTime(),
// count:20,
// }
// ]
// }
// }
let data = res||{}; let data = res||{};
progress.value = data.progress progress.value = (data.groupFinishNum / data.groupNum*100).toFixed()
resolve({ resolve({
...data, ...data,
}); });

View File

@@ -266,7 +266,7 @@ const submitForm = () => {
//h5测试用 内网-sn123456 //h5测试用 内网-sn123456
//公司外网 'f3fca83f-bf56-47f4-a98b-a602ed8bddee' 529a5543-6957-401e-b090-13df6dee5429 //公司外网 'f3fca83f-bf56-47f4-a98b-a602ed8bddee' 529a5543-6957-401e-b090-13df6dee5429
//友晟外网 'b97527c8-2ad4-493c-a01c-5f9d0aabaff2' //友晟外网 'b97527c8-2ad4-493c-a01c-5f9d0aabaff2'
param.uniqCode ='9a41dec6-536f-443f-9d98-8dc5c0b18332';//'1af78c0a-b878-425f-9dc5-bee42146860a' param.uniqCode = '9a41dec6-536f-443f-9d98-8dc5c0b18332'//'9a41dec6-536f-443f-9d98-8dc5c0b18332';//'1af78c0a-b878-425f-9dc5-bee42146860a'
let res = await login(param); let res = await login(param);
userStore.login(res); userStore.login(res);
uni.switchTab({ url: '/pages/home/home' }) uni.switchTab({ url: '/pages/home/home' })

View File

@@ -793,4 +793,25 @@ uni-button[type='primary'][plain] {
display: none !important; display: none !important;
} }
/* 日历修改 end */ /* 日历修改 end */
/* 图片loading */
.img-flex .img-con{position: relative;}
.img-flex .img-con .upload-loading{
position: absolute;
left:0;
top:0;
background-color: #EEEEEE;
width:210rpx;
height: 120rpx;
/* line-height: 140rpx; */
padding-top:20rpx;
}
.upload-loading .uni-icons{
display: inline-block;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

View File

@@ -283,4 +283,121 @@ export const compressImageUni = (file) => {
console.log('压缩失败:', error); console.log('压缩失败:', error);
} }
}) })
}
// H5 获取视频第一帧
const getFirstFrameInH5 = (videoPath) => {
return new Promise((resolve, reject) => {
const video = document.createElement('video')
video.src = videoPath
video.crossOrigin = 'anonymous'
video.addEventListener('loadeddata', () => {
video.currentTime = 0.1
})
video.addEventListener('seeked', () => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
const dataUrl = canvas.toDataURL('image/jpeg', 0.8)
resolve(dataUrl)
})
video.addEventListener('error', reject)
})
}
// App平台获取第一帧Android/iOS
const getFirstFrameInApp = (videoPath) => {
return new Promise((resolve, reject) => {
// 方法1使用原生VideoPlayer推荐
// #ifdef APP-PLUS
try {
const videoPlayer = plus.video.createVideoPlayer('firstFramePlayer', {
src: videoPath,
autoplay: false,
controls: false,
showLoading: false,
showProgress: false
})
// 监听视频准备完成
videoPlayer.addEventListener('loadeddata', () => {
// 截图
videoPlayer.snapshot({
format: 'jpg',
quality: 80
}, (res) => {
// res.target 是图片临时路径
console.log('截图成功:', res)
resolve(res.target)
// 销毁播放器
videoPlayer.close()
}, (error) => {
console.error('截图失败:', error)
reject(error)
videoPlayer.close()
})
}, false)
videoPlayer.addEventListener('error', (error) => {
console.error('视频加载失败:', error)
reject(error)
videoPlayer.close()
})
} catch (error) {
console.error('创建VideoPlayer失败:', error)
// 方法2备用方案使用HTML5 video如果原生方法失败
// showAppVideo.value = true
// showAppCanvas.value = true
// // 等待DOM更新后获取元素
// setTimeout(() => {
// const video = document.getElementById('appVideo')
// const canvas = document.getElementById('appCanvas')
// const ctx = canvas.getContext('2d')
// video.onloadedmetadata = () => {
// canvas.width = video.videoWidth
// canvas.height = video.videoHeight
// video.onseeked = () => {
// ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
// const dataUrl = canvas.toDataURL('image/jpeg', 0.8)
// // 清理
// showAppVideo.value = false
// showAppCanvas.value = false
// resolve(dataUrl)
// }
// video.currentTime = 0.1
// }
// video.onerror = reject
// }, 100)
}
// #endif
})
}
// 获取视频第一帧(跨平台处理)
export const getVideoFirstFrame = (videoPath) => {
return new Promise((resolve, reject) => {
// #ifdef H5
// H5平台使用canvas
getFirstFrameInH5(videoPath).then(resolve).catch(reject)
// #endif
// #ifdef APP-PLUS
// App平台使用plus.video
getFirstFrameInApp(videoPath).then(resolve).catch(reject)
// #endif
})
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long