<template> <view class="handler"> <view class="body view-body"> <view class="form_item column"> <view class="title"><text class="required newicon newicon-bitian"></text>故障描述:</view> <uni-easyinput class="value" type="textarea" v-model="dataInfo.deferralRemark" placeholder="请输入故障描述" :class="{formRed: isSubmit && !dataInfo.deferralRemark.trim()}" /> </view> <view class="candidate"> <view class="candidate-item" v-for="item in candidateData" :key="item" @click="itemCandidate(item)">{{item.name}}</view> </view> <view class="form_item" v-if="cmdbRepair.valueconfig==1"> <view class="title select">关联资产:</view> <input class="item-input" focus placeholder="请扫描资产卡二维码" v-model="dataInfo.property"/> <text class="newicon newicon-saoma icon" @click="scanCodes"></text> </view> <view class="form_item"> <view class="title">照片录像:</view> <view class="value"> <uni-file-picker ref="handlerImgRef" v-model="dataInfo.handlerImgList" limit="4" @success="handlerImgSuccess" @fail="handlerImgFail" @select="handlerImgSelect" @delete="handlerImgDelete"> </uni-file-picker> <view class="imgTips">(支持JPG/PNG格式图片,单张大小3M以内,录像支持30秒)</view> </view> </view> <view class="form_item"> <view class="title">录音:</view> <view class="chunk" v-if="!dataInfo.recBlob" @click="examineRecord" @mouseup="recStop">按住录音</view> <view v-if="dataInfo.recBlob"> <!-- <audio src="dataInfo.recBlob" controls></audio> --> <icon type="clear" size="26" @click="clearRec"/> </view> </view> </view> <view class="foot_common_btns"> <button @click="goBackOrToList" type="default" class="cancelButton btn">返回</button> <button @click="submit" type="default" class="primaryButton btn">下一步</button> </view> </view> </template> <script setup> import { SM } from "@/http/http.js" import { ref, reactive, computed } from 'vue' import NumberModal from '@/components/NumberModal.vue'; import { onLoad } from '@dcloudio/uni-app' import { generateNumberArray } from '@/utils/index.js' import { api_group, api_incidentDetail, api_getSolution, api_user, api_incidentTask, api_branch, api_dutyDepartment, api_getDictionary, api_querySummaryDoc, api_addSummaryDoc } from "@/http/api.js" import { defaultColor } from '@/static/js/theme.js' import { useSetTitle } from '@/share/useSetTitle.js' import { useMakePhoneCall } from '@/share/useMakePhoneCall.js' import { useUploadFile } from '@/share/useUploadFile.js' import { useGoBack } from '@/share/useGoBack.js' import { useLoginUserStore } from '@/stores/loginUser' import { useHandlerStore } from '@/stores/handler' import Recorder from 'recorder-core'; import 'recorder-core/src/engine/mp3'; import 'recorder-core/src/engine/mp3-engine'; import 'recorder-core/src/engine/wav'; import 'recorder-core/src/extensions/waveview'; useSetTitle(); const loginUserStore = useLoginUserStore(); const handlerStore = useHandlerStore(); const { makePhoneCall } = useMakePhoneCall(); const { uploadFile } = useUploadFile(); const { goBack } = useGoBack(); // 主题颜色 const primaryColor = ref(defaultColor) // 数据 const dataInfo = reactive({ tabs: [ // {id: 5, name: '故障处理', value: 'doing', num: ''}, // {id: 6, name: '延期处理', value: 'overtime', num: ''}, ], tabActiveValue: 0,//当前选择的tab incidentId: undefined,//事件ID incidentData: {},//事件对象 deferralRemark: '',//故障描述 property:'', //资产 handlerImgList: [],//处理图片列表 recBlob:'' //录音 }) // 故障处理用是否提供备用机 const newProvideBackupMachine = ref(0) // 知识库id const solutionId = ref(null) // 是否提交 const isSubmit = ref(false) // 处理图片 const handlerImgRef = ref(null) const candidateData = ref([ {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, {name:'马桶肃杀'}, ]) const cmdbRepair = ref(null) let rec = null; let wave = null; const recwave = ref(null); // 上一步或者返回列表 function goBackOrToList(){ uni.setStorageSync('repairData','') goBack(); } function itemCandidate(item){ dataInfo.deferralRemark = item.name } // 获取录音权限 function recOpen() { rec = Recorder({ type: 'wav', //录音格式,可以换成wav等其他格式 sampleRate: 16000, //录音的采样率,越大细节越丰富越细腻 bitRate: 16, //录音的比特率,越大音质越好 onProcess: (buffers, powerLevel, bufferDuration, bufferSampleRate) => { if (wave) { wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate); } }, }); if (!rec) { alert('当前浏览器不支持录音功能!'); return; } //打开录音,获得权限 rec.open( () => { console.log('录音已打开'); startRecord() if (recwave.value) { //创建音频可视化图形绘制对象 wave = Recorder.WaveView({ elem: recwave.value }); } }, (msg, isUserNotAllow) => { //用户拒绝了录音权限,或者浏览器不支持录音 console.log((isUserNotAllow ? 'UserNotAllow,' : '') + '无法录音:' + msg); }, ); // uni.getSetting({ // success(res) { // // 判断是否开启了录音权限 // if (res.authSetting['scope.record']) { // startRecord() // } else { // uni.showToast({ // icon: 'none', // title: '录音权限未开启,无法录音', // mask: true, // }); // } // } // }) } // 检查录音 function examineRecord() { recOpen() } function startRecord(){ if (!rec) { console.error('未打开录音'); return; } rec.start(); } // 结束录音 function recStop() { if (!rec) { console.error('未打开录音'); return; } rec.stop( (blob, duration) => { //blob就是我们要的录音文件对象,可以上传,或者本地播放 dataInfo.recBlob = blob; //简单利用URL生成本地文件地址,此地址只能本地使用,比如赋值给audio.src进行播放,赋值给a.href然后a.click()进行下载(a需提供download="xxx.mp3"属性) const localUrl = (window.URL || window.webkitURL).createObjectURL(blob); console.log('录音成功', blob, localUrl, '时长:' + duration + 'ms'); // upload(blob); //把blob文件上传到服务器 rec.close(); //关闭录音,释放录音资源,当然可以不释放,后面可以连续调用start rec = null; }, (err) => { console.error('结束录音出错:' + err); rec.close(); //关闭录音,释放录音资源,当然可以不释放,后面可以连续调用start rec = null; }, ); } // 删除录音 function clearRec(){ dataInfo.recBlob = null } // 扫码资产码 function scanCodes(){ SM().then((res) => { uni.showLoading({ title: "加载中", mask: true, }); uni.hideLoading(); }) } // 上传处理图片成功 function handlerImgSuccess(e){ dataInfo.handlerImgList.forEach(v => { v.url = v.path; }) console.log(dataInfo.handlerImgList); let handlerOrder$ = handlerOrder(); let requestList = [handlerOrder$]; dataInfo.handlerImgList.forEach(v => { let handlerOrderImg$ = handlerOrderImg(v); requestList.push(handlerOrderImg$); }) Promise.all(requestList).then(resList => { uni.hideLoading(); console.log(resList); if(resList[0].state == 200){ uni.showToast({ icon: 'none', title: '处理成功', mask: true, }); setTimeout(() => { uni.reLaunch({ url: '/pages/incidentList/incidentList', }) }, 1500) }else{ uni.showToast({ icon: 'none', title: resList[0].msg || '请求数据失败!' }); } }) } // 上传处理图片失败 function handlerImgFail(e){ dataInfo.handlerImgList.forEach(v => { v.url = v.path; }) console.log(dataInfo.handlerImgList); } // 选择上传图片 function handlerImgSelect(e){ dataInfo.handlerImgList = dataInfo.handlerImgList.concat(e.tempFiles); console.log(dataInfo.handlerImgList); } // 删除上传图片 function handlerImgDelete(e){ dataInfo.handlerImgList = dataInfo.handlerImgList.filter(v => e.tempFile.uuid != v.uuid); console.log(dataInfo.handlerImgList); } // 获取事件详情 function getIncidentDetail(){ if(uni.getStorageSync('repairData')){ let data = JSON.parse(uni.getStorageSync('repairData')) if(data){ dataInfo.deferralRemark = data.deferralRemark dataInfo.property = data.property dataInfo.handlerImgList = data.handlerImgList dataInfo.recBlob = data.recBlob } } } // 下一步 function submit(){ isSubmit.value = true; if(dataInfo.deferralRemark==''){ uni.showToast({ icon: 'none', title: '请选择输入故障描述' }); return; } uni.setStorageSync('repairData',JSON.stringify(dataInfo)) uni.navigateTo({ url: `/pages/repair/rapidRepNext`, }); } // 处理提交事件 function handlerOrder(){ dataInfo.incidentData.returnBackupMachine = dataInfo.returnBackupMachine let postData = { incident: dataInfo.incidentData, solutionId:solutionId.value } postData.incident.handleDescription = dataInfo.handleDescription; postData.incident.handleCategory = {id: dataInfo.handleCategory}; postData.incident.closecode = {id: dataInfo.closecode}; postData.incident.category = dataInfo.category; postData.incident.synergetic = dataInfo.synergetic; return api_incidentTask(dataInfo.tabActiveValue, postData); } // 处理图片 function handlerOrderImg(imgObj){ return uploadFile(imgObj, 'incident', dataInfo.incidentId) } onLoad((option) => { // let storeData = handlerStore.handler.data // if(storeData && storeData.type=='rep'){ // solutionId.value = storeData.solutionId // dataInfo.isSummaryNext = storeData.isSummaryNext // dataInfo.incidentId = storeData.incidentId; // }else{ // dataInfo.incidentId = option.incidentId; // dataInfo.isSummaryNext = option.isSummaryNext == 1; // } let data = JSON.parse(uni.getStorageSync('sysData')) cmdbRepair.value = data.find(i=>i.keyconfig=='cmdbRepair') getIncidentDetail(); }) </script> <style lang="scss" scoped> .handler{ height: 100%; display: flex; flex-direction: column; justify-content: space-between; padding: 0 30rpx; .head{ height: 88rpx; display: flex; position: fixed; z-index: 99; width: 100%; background-color: #fff; font-size: 30rpx; .tab{ flex: 1; display: flex; justify-content: center; align-items: center; border-bottom: 4rpx solid transparent; &.active{ color: $uni-primary; border-color: $uni-primary; } } } .body{ box-sizing: border-box; flex: 1; min-height: 0; &.bg{ background-color: #F7F7F7; } .summaryItem{ &:first-of-type{ .summaryItem_head{ border-bottom: 1rpx solid #DDDDDD; } } .summary_total{ padding: 20rpx 0; display: flex; justify-content: center; align-items: center; } .summaryItem_head{ padding: 24rpx; font-size: 26rpx; color: #3A3A3A; } .summaryItem_body{ font-size: 30rpx; background-color: #fff; .summaryItem_bodyItem{ padding: 24rpx; border-bottom: 1rpx solid #DDDDDD; .summaryItem_bodyItem_top{ display: flex; justify-content: space-between; align-items: center; .value{ padding-left: 48rpx; flex-shrink: 0; } } .summaryItem_bodyItem_bottom{ margin-top: 24rpx; display: flex; justify-content: space-between; align-items: center; .name{ text-align: right; flex: 1; } .value{ width: 240rpx; text-align: right; padding-left: 48rpx; flex-shrink: 0; } } } } .summaryItem_foot{ font-size: 30rpx; background-color: #fff; &.total{ margin-top: 24rpx; } .summaryItem_foot_total{ padding: 24rpx 0; display: flex; justify-content: center; align-items: center; } .summaryItem_foot_add{ border-top: 1rpx solid #DDDDDD; padding: 24rpx 0; display: flex; justify-content: center; align-items: center; .newicon-icon-test{ font-size: 30rpx; font-weight: bold; } } } } .form_item_column{ padding-top: 24rpx; min-height: 86rpx; .form_item{ padding-top: 0; min-height: auto; } } .candidate{ display: flex; flex-wrap: wrap; .candidate-item{ padding: 6rpx 15rpx; font-size: 26rpx; color: #949494; background: #E9E9E9; border-radius: 50rpx; margin-right: 20rpx; margin-top: 15rpx; } } .form_item{ display: flex; align-items: center; padding-top: 24rpx; min-height: 86rpx; position: relative; .chunk{ width: 100%; height: 70rpx; line-height: 70rpx; text-align: center; background: #F7F8FA; box-shadow: 0px 3px 6px 1px rgba(0,0,0,0.16); border-radius: 10rpx; } &.column{ height: auto; flex-direction: column; align-items: flex-start; .import-rep{ padding: 5rpx 10rpx; border-radius: 50rpx; background: #d1fcd5; color: #49b856; font-size: 24rpx; } .title{ margin-right: 0; } .title-width{ width: 100%; } .title-fl-sb{ display: flex; justify-content: space-between; width: 100%; } .value{ margin-top: 10rpx; // padding-left: 20rpx; box-sizing: border-box; } .tips{ padding: 24rpx; text-align: center; font-size: 22rpx; color: #909399; width: 100%; box-sizing: border-box; } } .title{ font-size: 26rpx; display: flex; align-items: center; margin-right: 12rpx; flex-shrink: 0; &.select{ width: calc(5em + 20rpx); } } .value{ width: 100%; &.category{ width: 100%; display: flex; justify-content: space-between; align-items: center; .categoryName{ font-size: 26rpx; color: #555; flex: 1; } .newicon-weibiaoti2010104{ color: $uni-primary; margin-left: 24rpx; } } .imgTips{ color: #909399; font-size: 22rpx; margin-top: 10rpx; } } .item-input{ border: 1px solid #DBDBDB; height: 70rpx; line-height: 70rpx; padding: 0 10rpx; border-radius: 4rpx; width: 100%; font-size: 14px; } .icon{ position: absolute; right: 20rpx; color: #49b856; } .synergeticNames{ font-size: 26rpx; margin-right: 24rpx; } .synergeticAdd{ flex-shrink: 0; } } } } </style>