Files
ys-app/src/pages/business/polling/problemReport.vue

589 lines
18 KiB
Vue
Raw Normal View History

2025-11-20 17:45:41 +08:00
<template>
<view class="con-body">
<view class="con-bg">
<!-- 头部 -->
<customHeader ref="customHeaderRef" title="问题上报"
:leftFlag="true" :rightFlag="false"
></customHeader>
<!-- 高度来避免头部遮挡 -->
<view class="top-height"></view>
2025-11-27 18:18:19 +08:00
<!-- 下拉刷新 -->
<mescroll-uni ref="mescrollRef" @init="mescrollInit"
:down="downOption" @down="downCallback"
:fixed="false" class="scroll-h"
>
<view class="white-bg">
<view class="red-title">问题{{optionObj.groupName}}</view>
<view class="report-list">
<view class="report-pro">问题项</view>
<view class="report-right">
<view class="r-list" v-for="(item, index) in optionObj.pointList" :key="index" @click="handleRound(item)">
<view class="r-left" :class="{'r-red':item.active}">
<view>{{String(index+1).padStart(2, '0')+'.'}}</view>
<view>{{ item.pointName }}</view>
</view>
<view class="r-right">
<view class="r-r-round" :class="{active:item.active}"></view>
</view>
2025-11-20 17:45:41 +08:00
</view>
</view>
</view>
2025-11-27 18:18:19 +08:00
<view class="report-border"></view>
<view class="report-list">
<view class="report-pro">提交人</view>
<view class="report-right">{{optionObj.createUserName?optionObj.createUserName:realname}}</view>
</view>
<view class="report-border"></view>
<view class="report-list" style="display:block;">
问题描述
<textarea class="r-input textarea" v-model="optionObj.problemDesc" auto-height
placeholder="请输入问题项描述" placeholder-class="place-input"
></textarea>
</view>
<view class="report-border"></view>
<view class="report-list" style="display:block;">
<view class="r-title">问题点位照片或视频 <text>*</text></view>
<view class="img-flex">
2025-12-19 16:54:02 +08:00
<view class="img-show" v-for="(item2,index2) in imgArr" :key="index2" @click="showMediaPreview(item2)">
<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" />
2025-11-27 18:18:19 +08:00
</view>
2025-12-19 16:54:02 +08:00
<view class="img-show" v-for="(item2,index2) in videoArr" :key="index2" @click="showMediaPreview(item2)">
<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" />
2025-11-27 18:18:19 +08:00
</view>
<!-- loading -->
<view class="img-con" v-if="imgLoading">
<view class="upload-loading">
2025-12-19 16:54:02 +08:00
<uni-icons type="refreshempty" size="30" color="#C9C9C9"></uni-icons>
<view>上传中....</view>
</view>
2025-11-27 18:18:19 +08:00
</view>
<view class="img-con" @click="chooseMedia" v-else>
<img :src="'static/images/polling/icon-AddPorV.png'" class="img-pic" />
</view>
<!-- #ifdef APP-PLUS -->
2025-11-27 18:18:19 +08:00
<!-- #endif -->
<!-- #ifndef APP-PLUS -->
<!-- <view class="img-con">
2025-11-27 18:18:19 +08:00
<img :src="'static/images/polling/icon-AddPorV.png'" class="img-pic" />
</view> -->
2025-11-27 18:18:19 +08:00
<!-- #endif -->
2025-11-20 17:45:41 +08:00
</view>
</view>
2025-11-27 18:18:19 +08:00
<view class="btn-submit">
<button type="primary" @click="handleSubmit">{{problemId?'修改问题跟踪表':'生成问题跟踪表'}}</button>
</view>
2025-11-20 17:45:41 +08:00
</view>
2025-11-27 18:18:19 +08:00
</mescroll-uni>
2025-11-20 17:45:41 +08:00
</view>
2025-11-28 16:42:57 +08:00
<!-- 图片放大 -->
<mediaPreview :visible="isVisible" :url="mediaUrl" @close="handlePreviewClose"></mediaPreview>
<!-- 选择图片或者视频 -->
<chooseMediaVue ref="chooseMediaRef" @getMediaArr="getMediaArr" @closeMedia="closeMedia"></chooseMediaVue>
2025-11-20 17:45:41 +08:00
</view>
</template>
<script setup>
import { ref,onMounted,onUnmounted,nextTick,computed,reactive, watch,getCurrentInstance } from 'vue'
2025-12-19 16:54:02 +08:00
import { onLoad,onShow,onHide} from '@dcloudio/uni-app';
2025-11-20 17:45:41 +08:00
import customHeader from '@/components/customHeader.vue';
import MescrollUni from 'mescroll-uni/mescroll-uni.vue';
import chooseMediaVue from '@/components/chooseMedia.vue'
2025-11-28 16:42:57 +08:00
import mediaPreview from "@/components/mediaPreview.vue"
2025-12-19 16:54:02 +08:00
import DomVideoPlayer from 'uniapp-video-player'
2025-11-20 17:45:41 +08:00
import { getUserInfo } from '@/api/auth.js'
2025-11-27 18:18:19 +08:00
import { problemDetail,problemAdd,problemEdit,minioUpload } from '@/api/polling.js'
2025-11-28 16:42:57 +08:00
import {compressImageUni,getFileType} from '@/utils/common.js'
2025-11-27 18:18:19 +08:00
import {showAlert,showLoading,hideLoading} from '@/utils/message.js'
2025-11-28 16:42:57 +08:00
import { MINIO_KEY } from '@/enums/cacheEnums';
const { proxy } = getCurrentInstance();
2025-11-20 17:45:41 +08:00
2025-11-27 18:18:19 +08:00
let taskId = ref('');//任务id
let groupId = ref('');//组id
let problemId = ref('');//问题id
2025-11-20 17:45:41 +08:00
let realname = ref('');
let desc = ref('');//描述
2025-11-28 16:42:57 +08:00
let minioObj = {};
2025-11-20 17:45:41 +08:00
onLoad(async option => {
// console.log(option)
2025-11-27 18:18:19 +08:00
taskId.value = option.taskId;
groupId.value = option.groupId;
problemId.value = option.problemId;
2025-11-28 16:42:57 +08:00
minioObj = JSON.parse(uni.getStorageSync(MINIO_KEY) || "\{\}")
2025-11-27 18:18:19 +08:00
2025-11-20 17:45:41 +08:00
let userinfo = await getUserInfo({});
2025-12-22 18:11:07 +08:00
realname.value = userinfo.realname;
2025-12-19 16:54:02 +08:00
getList();
2025-11-20 17:45:41 +08:00
})
2025-11-28 16:42:57 +08:00
onShow(()=>{
imgLoading.value=false;
})
2025-11-20 17:45:41 +08:00
// 查询列表
let list = ref([]);
let optionObj = ref({})
2025-11-27 18:18:19 +08:00
// 下拉刷新
const mescrollRef = ref(null);
const mescrollInit = (mescroll) => {
mescrollRef.value = mescroll;
};
const downOption = ref({
2025-12-19 16:54:02 +08:00
use:false,
2025-11-27 18:18:19 +08:00
auto: true,
textInOffset: '下拉刷新',
textOutOffset: '释放更新',
textLoading: '刷新中...'
});
// 下拉刷新
const downCallback = async (mescroll) => {
try {
getList();
} catch (error) {
mescroll.endErr();
} finally {
mescroll.endSuccess();
}
}
2025-11-20 17:45:41 +08:00
// 获取数据列表
2025-11-27 18:18:19 +08:00
const getList = async () => {
let param = {
taskId:problemId.value?undefined:taskId.value,
groupId:problemId.value?undefined:groupId.value,
problemId:problemId.value
2025-11-20 17:45:41 +08:00
}
2025-11-27 18:18:19 +08:00
let res = await problemDetail(param);
let data = res||{};
2025-11-28 16:42:57 +08:00
let pointIds = data.pointId?.split(",") || [];
2025-11-27 18:18:19 +08:00
data.pointList.forEach(item2=>{
item2.active=false;
for (let i = 0; i < pointIds.length; i++) {
if(item2.pointId == pointIds[i]){
item2.active=true;
break;
}
}
})
2025-11-28 16:42:57 +08:00
// 视频回显
imgArr.value = [];
mediaArr.value=[];
videoArr.value=[];
let fileList =data.problemVedio?.split(",") || [];
fileList.forEach(item=>{
mediaArr.value.push(item)
if(getFileType(item)=='image'){
imgArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+item,
url:minioObj.minioUrl +"/"+item,
2025-12-19 16:54:02 +08:00
name:item
2025-11-28 16:42:57 +08:00
})
}else if(getFileType(item)=='video'){
videoArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+item,
url:minioObj.minioUrl +"/"+item,
2025-12-19 16:54:02 +08:00
name:item
2025-11-28 16:42:57 +08:00
})
}
})
2025-11-27 18:18:19 +08:00
optionObj.value = data;
2025-11-20 17:45:41 +08:00
}
// 图片或视频
2025-11-27 18:18:19 +08:00
let mediaArr = ref([]);//传给后台的地址
let imgArr=ref([]);//图片 后台返回的
let videoArr = ref([]);//视频 后台返回的
2025-12-19 16:54:02 +08:00
let imgLoading = ref(false)
2025-11-20 17:45:41 +08:00
const chooseMedia = () => {
// console.log("chooseMedia=>")
proxy.$refs["chooseMediaRef"].openPicker();
imgLoading.value=true;
// uni.chooseMedia({
// count: 9,
// mediaType: ['image', 'video'], // 指定可选择图片和视频
// sourceType: ['album', 'camera'],
// maxDuration: 60, // 拍摄视频最长拍摄时间
// camera: 'back',
// success: (res) => {
// // console.log("chooseMedia=>",res)
// res.tempFiles.forEach(async file => {
// // console.log(`文件类型: ${file.fileType}, 文件路径: ${file.tempFilePath}`);
// let compressImg = file.tempFilePath;
// // 图片进行压缩
// if (file.fileType === 'image') {
// // #ifdef APP-PLUS
// // 压缩图片
// compressImg = await compressImageUni(file.tempFilePath);
// // #endif
// }
2025-11-27 18:18:19 +08:00
// // 执行上传
// let param = {
// filePath: compressImg,
// name: 'file',
// formData: {
// directory:'polling'
// },
// }
// imgLoading.value=true;
// minioUpload(param).then(res=>{
// let data = res.data;//console.log("上传成功后=>",res)
// mediaArr.value.push(data.fileName);
// if (file.fileType === 'image') {// 图片
// imgArr.value.push({
// shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
// url:minioObj.minioUrl +"/"+data.fileName,
// name:data.fileName
// })
// } else if (file.fileType === 'video') {// 视频
// videoArr.value.push({
// shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
// url:minioObj.minioUrl +"/"+data.fileName,
// name:data.fileName
// })
// }
// }).finally(()=>{
// imgLoading.value=false;
// })
2025-11-27 18:18:19 +08:00
// });
// }
// });
}
const closeMedia = ()=>{
imgLoading.value=false;
}
// 插件回调
const getMediaArr=(arr)=>{
// console.log("插件回调=>",arr)
try {
arr.forEach(data=>{
mediaArr.value.push(data.fileName);
if(data.fileType=="image"){
imgArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName,
name:data.fileName
})
}else if(data.fileType == "video"){
videoArr.value.push({
shortUrl:minioObj.minioThumbUrl +"/"+data.fileName,
url:minioObj.minioUrl +"/"+data.fileName,
name:data.fileName
})
}
})
// console.log(imgArr.value,videoArr.value)
imgLoading.value=false;
} catch (error) {
console.error(error)
imgLoading.value=false;
}
2025-11-20 17:45:41 +08:00
}
2025-12-19 16:54:02 +08:00
// 视频或图片删除 根据数组下标删除数组里的某个图片或视频
const handleDelete=(arr,index2)=>{
let item = arr[index2];
arr.splice(index2, 1);
2025-12-19 16:54:02 +08:00
mediaArr.value = mediaArr.value.filter(item2=>item2!=item.name);
console.log("删除后=>",mediaArr.value)
}
2025-11-28 16:42:57 +08:00
// 放大视频或图片
let isVisible= ref(false);//放大处理
let mediaUrl= ref('');//放大地址
let videoShow = ref(true);
const showMediaPreview=(item)=>{
2025-12-19 16:54:02 +08:00
// console.log("调用放大视频==>",item)
2025-11-28 16:42:57 +08:00
isVisible.value = true;
videoShow.value = false;
mediaUrl.value = item.url
}
const handlePreviewClose=()=>{
isVisible.value = false;
videoShow.value = true;
}
2025-11-21 18:25:05 +08:00
// 红点点击
const handleRound=(item)=>{
item.active=!item.active
}
2025-11-20 17:45:41 +08:00
// 提交
const handleSubmit=()=>{
2025-11-27 18:18:19 +08:00
let pointIds = [];
optionObj.value.pointList.forEach(item => {
if(item.active){
pointIds.push(item.pointId)
}
});
showLoading("加载中...")
if(problemId.value){
let param = {
problemId:problemId.value,
pointId:pointIds.join(","),
problemVedio:mediaArr.value.join(","),
2025-11-28 16:42:57 +08:00
problemDesc:optionObj.value.problemDesc
2025-11-27 18:18:19 +08:00
}
2025-11-28 16:42:57 +08:00
// console.log("problemEdit=>",param)
2025-11-27 18:18:19 +08:00
problemEdit(param).then(res=>{
// showAlert = (content, title = '提示',showCancel=false,succFun)
showAlert("修改问题上报成功!","提示",false,()=>{
uni.navigateBack()
})
2025-11-27 18:18:19 +08:00
}).finally(()=>{
hideLoading();
})
}else{
2025-11-28 16:42:57 +08:00
let param = {
2025-11-27 18:18:19 +08:00
taskId:taskId.value,
groupId:groupId.value,
pointId:pointIds.join(","),
problemVedio:mediaArr.value.join(","),
2025-11-28 16:42:57 +08:00
problemDesc:optionObj.value.problemDesc
2025-11-27 18:18:19 +08:00
}
2025-11-28 16:42:57 +08:00
// console.log("problemAdd=>",param)
2025-11-27 18:18:19 +08:00
problemAdd(param).then(res=>{
showAlert("新建问题上报成功!","提示",false,()=>{
problemId.value = res;
uni.navigateBack()
})
2025-11-27 18:18:19 +08:00
}).finally(()=>{
hideLoading();
})
}
2025-11-20 17:45:41 +08:00
}
</script>
<style scoped>
2025-11-27 18:18:19 +08:00
.scroll-h{
/* #ifdef APP-PLUS */
height:calc(100vh - 78px) !important;
/* #endif */
/* #ifndef APP-PLUS */
height: calc(100vh - 58px) !important;
/* #endif */
}
:deep(.mescroll-upwarp){
display: none !important;
}
2025-11-20 17:45:41 +08:00
.white-bg{
width: 680rpx;
padding: 15rpx 30rpx 40rpx 40rpx;
margin-bottom: 0;
border-radius: 8px 8px 0 0;
}
.white-bg .red-title{
margin-bottom:30rpx;
color:#FF2B44;
font-size:38rpx;
}
.report-border{
border-bottom:1px solid #E7E7E7;
width:710rpx;
height: 1px;
margin:20rpx 0;
}
.report-list{
display: flex;
font-size:28rpx;
}
.report-list .r-title{
position: relative;
}
.report-list text{
color:#FF2B44;
font-size:28rpx;
}
.report-list .report-pro{
font-size:28rpx;
width:16%;
/* margin-right:30rpx; */
}
.report-list .report-right{
width:84%;
color:#919191;
font-size:28rpx;
}
.report-list .r-input{
border:1px solid #E7E7E7;
border-radius: 10rpx;
width:620rpx;
padding:15rpx 25rpx;
margin:20rpx 0 30rpx;
}
.report-list .place-input{
color:#BFBFBF;
font-size:28rpx;
}
.report-list .textarea{
min-height: 120rpx;
}
.report-list .r-list{
padding: 10rpx 0;
}
.report-list .r-list:first-child{
padding-top:0;
}
.report-list .r-left{
display: flex;
2025-11-27 18:18:19 +08:00
align-items: center;
2025-11-21 18:25:05 +08:00
width:90%;
2025-11-20 17:45:41 +08:00
font-size:28rpx;
color:#919191;
}
.report-list .r-left view:first-child{
margin-right: 10rpx;
}
.report-list .r-left.r-red{
color: #FF2B44;
font-size: 28rpx;
}
.report-list .r-right{
display: flex;
font-size:30rpx;
align-items: center;
justify-content: center;
}
.report-list .r-r-round{
width:35rpx;
height:35rpx;
border:1px solid #BDBDBD;
border-radius: 50%;
}
.report-list .r-r-round.active{
border:1px solid #FF2B44;
background-color: #FF2B44;
position: relative;
}
.report-list .r-r-round.active::after{
content:"!";
position: absolute;
top:0;
left:0;
color:#fff;
text-align: center;
width:35rpx;
height:35rpx;
/* #ifndef APP-PLUS */
line-height: 30rpx;
/* #endif */
/* #ifdef APP-PLUS */
2025-11-21 18:25:05 +08:00
height:33rpx;
padding-top:2rpx;
2025-11-20 17:45:41 +08:00
/* #endif */
}
2025-11-21 18:25:05 +08:00
.report-list .img-flex{
display: flex;
flex-flow:row wrap;
margin-bottom:30rpx;
2025-12-19 16:54:02 +08:00
width:100%;
2025-11-21 18:25:05 +08:00
}
.report-list .img-show img,
2025-12-19 16:54:02 +08:00
.report-list .img-show image,
.report-list .img-show video,
.report-list .img-show .player-wrapper{
2025-11-21 18:25:05 +08:00
width:210rpx;
height: 140rpx;
}
.report-list .img-show :deep(.uni-video-cover-play-button){
width:64rpx;
height: 64rpx;
line-height: 64rpx;
font-size:60rpx;
}
2025-11-20 17:45:41 +08:00
.report-list .img-con{
background-color: #EEEEEE;
width:210rpx;
height: 140rpx;
text-align: center;
color:#919191;
font-size: 24rpx;
}
.report-list .img-con .img-pic{
width:76rpx;
height: 76rpx;
margin-top:30rpx;
}
.report-list .img-show,
.report-list .img-con{
width: calc(100% / 3 - 10px); /* 减去一些间隙以避免溢出 */
2025-11-21 18:25:05 +08:00
margin:20rpx 20rpx 0 0;
2025-11-20 17:45:41 +08:00
}
2025-12-19 16:54:02 +08:00
.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;
}
2025-11-20 17:45:41 +08:00
.btn-submit{
width:400rpx;
margin:90rpx auto;
}
.btn-submit uni-button[type='primary']{
background-color: #05A3F4;
border-radius: 40rpx;
line-height: 2.2;
}
.btn-submit uni-button:after{
border-color:#05A3F4;
}
</style>