闲叙
嗯又在加班,处理一个小问题,但是呢我的Vue学的确实不是很好所以费了一番功夫在这里记录一下中间遇到的问题和学到的知识。
问题介绍
首先审批记录这个样字的,其实我觉得也还行,是因为需求的问题,电脑端是可以评论文件的,手机端则没有这个需求,所以在做组件的时候统一使用的图片,当你使用电脑端评论文件的时候,在手机端就会看到这个东西,其实我觉得之前的还是挺好的。
然后呢需要实现这个功能,我们的电脑端是使用Vue的Element,但是手机端使用的vant,所以就很尴尬,没有办法直接使用,还好我们的前段做了一个附件的功能,里面可以合理的处理文件和图片的关系,所以我的难点就变成了如何在组件里面使用组件
组件
historyData.vue
审批记录组件
<template>
<div class="Eleme">
<div class="nohistory" v-show="false">
<div class="nohistory_img"></div>
<p>暂无审批记录</p>
</div>
<!-- 有审批记录 -->
<div class="history flow">
<ul>
<li class="LiBefore" v-for="(site,index) in historydata" :key="index">
<img class="flow_img" :src=site.url />
<div class="flow_name">
{{site.name}}
<span class="post">{{site.post}}</span>
<span>{{site.agree}}</span>
<span class="flow_time">{{site.date}}</span>
<div>
<p>{{site.content}}</p>
</div>
<div v-for="(si,index2) in site.commenturl" :key="index2">
<img class="flow_img" :src="si.url" />
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
首先我们可以通过看前段代码看到问题原因,就是因为你把img标签里面放了文件的访问地址,所以出现的问题,但是基于最小程度修改代码的想法,我们把每一个图片直接换成每一个附件组件,其实也可以将每一条评论穿进去但是修改的太多了就不做修改了。
然后让我们来看一下附件的前段vue
imgShowField.vue
显示附件组件
<template>
<div style="text-align:left;background-color:white">
<div v-for="(item,index) in imageFileList" style="text-align:left;margin:25px;width:100;display:inline-block" :key="index+'image'" @click="expandImage(item,index)">
<van-image width="50" height="50" :src="item.filePath">
</van-image>
<br/>
<span style="font-size:12px;display:inline-block">{{item.fileName}}</span>
</div>
<div v-for="(item,index) in documentFileList" style="text-align:left;margin:25px;width:100;display:inline-block" :key="index+'document'" @click="expandDocument(item,index)">
<van-image width="50" height="50" :src="item.filePath">
</van-image>
<br/>
<span style="font-size:12px;display:inline-block">{{item.fileName}}</span>
</div>
<van-image-preview v-model="showPicture" :images="imageList" @change="onChange" :start-position="pictureIndex">
<template v-slot:index>{{imageFileList[pictureIndex].fileName}}</template>
</van-image-preview>
<van-popup v-model="showFile" position="bottom" :style="{ height: '100%' }" get-container="body">
<check-provel ref="fileShow" @backToprovel="backToprovel"></check-provel>
</van-popup>
</div>
</template>
这里面需要实现的一个问题就是实现将img标签替换为imgShowField这个组件,但是又因为这个组件的ref名称不能够相同,所以我们需要使用动态的方式实现一个ref的命名和ref命名之后的初始化,所以我们使用了动态的格式。
上代码
组件的引入,components中定义组件就不写了
<template>
<div class="Eleme">
<div class="nohistory" v-show="false">
<div class="nohistory_img"></div>
<p>暂无审批记录</p>
</div>
<!-- 有审批记录 -->
<div class="history flow">
<ul>
<li class="LiBefore" v-for="(site,index) in historydata" :key="index">
<img class="flow_img" :src=site.url />
<div class="flow_name">
{{site.name}}
<span class="post">{{site.post}}</span>
<span>{{site.agree}}</span>
<span class="flow_time">{{site.date}}</span>
<div>
<p>{{site.content}}</p>
</div>
<img-show-field :ref="'imgShowField'+index"></img-show-field>
</div>
</li>
</ul>
</div>
</div>
</template>
我们直接将img标签修改为附件的组件,然后开始处理这个组价的初始化,因为有v-for
所以我们可以拿到v-for中的index,这样我们初始化组件的就是imgShowField'+index
,其实这个编译之后也就是imgShowField0,imgShowField1,imgShowField2这种的名称,然后现在在初始化的时候我们使用
init: function () {
const self = this // 将this对象传递进来 (必须)
return api.getHistoryByProinstid(this.proInsId)
.then(function (res) {
if (res.taskList) {
res.taskList.forEach(element => {
let resultData = {}
if (element.nextUsers.length !== 0) {
resultData.name = element.nextUsers[0].realName
resultData.url = element.nextUsers[0].headUrl
} else {
resultData.name = ''
resultData.url = ''
}
resultData.post = element.nextNodeName
resultData.content = '等待审批'
self.historydata.push(resultData)
})
}
if (res.cycles) {
res.cycles.forEach((element, index) => {
let resultData = {}
resultData.name = element.auditorName
resultData.agree = element.auditStatusName
if (element.auditType === 'repeal') {
resultData.post = ' 该单据已撤销 '
} else if (element.auditType === 'rejected') {
resultData.post = element.nodeName + ' 该单据已拒绝 '
} else if (element.processStatus === 'done' && element.nodeId === 'handling' && element.auditType !== 'transfer') {
resultData.post = element.nodeName + ' 该单据已办理完成 '
} else {
resultData.post = element.nodeName
}
resultData.date = element.auditTime
resultData.content = element.auditContent
if (element.auditTypeDesc === '转交') {
resultData.content = '转办'
}
if (element.sysAttachmentDTOList) {
element.sysAttachmentDTOList.forEach(site => {
api.shareFile(site.fileId).then(res => {
console.log(res)
site.url = res
})
})
resultData.commenturl = element.sysAttachmentDTOList
}
self.$nextTick(() => {
self.$refs[`imgShowField${index + 1}`][0].init(element.sysAttachmentDTOList)
})
resultData.url = element.auditorImgUrl
self.historydata.push(resultData)
})
}
let resultData = {}
resultData.name = res.submitUser.submitPerName
resultData.post = '发起人'
resultData.date = res.submitUser.submitDate
resultData.url = res.submitUser.submitHeadUrl
self.historydata.push(resultData)
// console.log('审批记录', JSON.stringify(self.historydata))
})
},
使用
self.$refs[`imgShowField${index + 1}`][0].init(element.sysAttachmentDTOList)
方式使用找打,至于这个为什么要加1,是因为我们的这个审批记录数据需要分为两种第一种是发起者,谁谁谁发起什么审批流程,第二种才是我们意义上面的审批记录,例如说到了谁谁谁审批,谁谁评论,我们在展示的时候需要将这两种数据拼接在一起,因为发起者的时间肯定更早而且不会有评论的图片所以我们在展示图片的时候需要将后移一位,然后呢一般的初始化组件也会失败因为需要使用self.$nextTick(() => {
的形式进行初始化,这样我们就完成了我们的第一部,现在可以显示图片还有文件了并且文件的显示是一个文件的图标,因为需求设置不要能够预览文件,所以第一期的任务完成了,在一个组件里面初始化多个组件
但是问题结束了吗
没有还远远没有,感谢测试他们在努力的测试下发现了原来已经完成的单据再次评论是会出现问题的,具体问题就是评论成功之后不显示评论的内容,然后我们就开始分析,为什么不显示呢
这一种他的结构是正常的我们可以正常显示
这一种是不显示,因为这个我已经改完了所以它显示的,就是因为,我们的在展示逻辑的时候有一个是会在最后一个节点审批通过之后添加一个该审批单据已完成,因为他已经完成的单据中的一个属性taskids这个就会消失(这是我们公司使用的工作流的一个东西以后我会说一下的),因为某些原因的报错所以引发了一些问题。
其实我在上面的写的代码有一个很严重的问题,就是附件这个组件在初始化的时候需要初始化几个这个东西是不确定是,是需要通过下面的拼装的数据的historydata
来确定的,所以在这里肯定会遇到一个加载的问题,如果让下面加载完之后不要初始化这个组件呢,因为这个原因我改正了这个组件的命名方式,先来看代码
<template>
<div class="Eleme">
<div class="nohistory" v-show="false">
<div class="nohistory_img"></div>
<p>暂无审批记录</p>
</div>
<!-- 有审批记录 -->
<div class="history flow">
<ul>
<li class="LiBefore" v-for="(site,index) in historydata" :key="index">
<img class="flow_img" :src=site.url />
<div class="flow_name">
{{site.name}}
<span class="post">{{site.post}}</span>
<span>{{site.agree}}</span>
<span class="flow_time">{{site.date}}</span>
<div>
<p>{{site.content}}</p>
</div>
<!-- <div v-for="(si,index2) in site.commenturl" :key="index2">-->
<!-- <img class="flow_img" :src="si.url" @click="readPicOrFile(site.commenturl,index2)"/>-->
<!-- </div>-->
<!-- <img-show-field ref="imgShowField"></img-show-field>-->
<img-show-field ref="imgShowField" :key="index"></img-show-field>
</div>
</li>
</ul>
</div>
</div>
</template>
init: function () {
const self = this // 将this对象传递进来 (必须)
let list = []
api.getHistoryByProinstid(this.proInsId)
.then(function (res) {
list = res
// console.log('审批记录', JSON.stringify(self.historydata))
}).then(res => {
if (list.taskList) {
list.taskList.forEach(element => {
let resultData = {}
if (element.nextUsers.length !== 0) {
resultData.name = element.nextUsers[0].realName
resultData.url = element.nextUsers[0].headUrl
} else {
resultData.name = ''
resultData.url = ''
}
resultData.post = element.nextNodeName
resultData.content = '等待审批'
self.historydata.push(resultData)
})
}
if (list.cycles) {
list.cycles.forEach((element, index) => {
let resultData = {}
resultData.name = element.auditorName
resultData.agree = element.auditStatusName
if (element.auditType === 'repeal') {
resultData.post = ' 该单据已撤销 '
} else if (element.auditType === 'rejected') {
resultData.post = element.nodeName + ' 该单据已拒绝 '
} else if (element.processStatus === 'done' && element.nodeId === 'handling' && element.auditType !== 'transfer') {
resultData.post = element.nodeName + ' 该单据已办理完成 '
} else {
resultData.post = element.nodeName
}
resultData.date = element.auditTime
resultData.content = element.auditContent
if (element.auditTypeDesc === '转交') {
resultData.content = '转办'
}
if (element.sysAttachmentDTOList) {
element.sysAttachmentDTOList.forEach(site => {
api.shareFile(site.fileId).then(res => {
console.log(res)
site.url = res
})
})
resultData.commenturl = element.sysAttachmentDTOList
}
resultData.url = element.auditorImgUrl
self.historydata.push(resultData)
})
}
let resultData = {}
resultData.name = list.submitUser.submitPerName
resultData.post = '发起人'
resultData.date = list.submitUser.submitDate
resultData.url = list.submitUser.submitHeadUrl
self.historydata.push(resultData)
}
).then(res => {
self.$nextTick(() => {
self.historydata.forEach((element, index) => {
// this.$refs[`generate${index}`][0].getData().then(data => {
// alert(JSON.stringify(data))
// }).catch(e => {
// })
// this.$refs[`imgShowField${index}`][0]
if (element.commenturl !== null && self.$refs.imgShowField[index] !== undefined) {
self.$refs.imgShowField[index].init(element.commenturl)
}
// for (var i; i < self.$refs.imgShowField.length; i++) {
// self.$refs.imgShowField[i].init(element.sysAttachmentDTOList)
// }
})
})
})
},
上面的两个代码分别是组件的位置和存放的方式我们在这里讲解一下
我们使用了<img-show-field ref="imgShowField" :key="index"></img-show-field>
这种方式来对于组件进行一个定义,虽然说ref的名称不不能够重复但是我们这里是使用的一个组的概念,就是都是这个名称但是这个是一个数组我们使用一个数组的概念,为了解决我们的组件初始化没有完成但是组件已经出现的问题,其实我们先将v-for
的元素给取出,然后再去遍历这样既可以拿到所有的元素了应该是没得问题了。
还有就是在职做组件的时候需要考虑到一个问题就是初始化组件的时候的传值,这个附件组件初始化的传值需要考虑到可能为null,undefined,不要直接就用传过来对象的属性,因为会报异常的。