Files
learning-system-mobile/pages/resource/qaDetail.vue
2022-05-30 23:03:25 +08:00

831 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!--问答详细页面--------需要改-->
<!--从点击进入问答详情那一刻开始哪些人有哪些权限
比如发起问题的人有所有权限同用户登录id判断
我不是问题发起人但是我仍然有权限更改我发布的消息
这一块的判断还是有些问题在pc端进行理清逻辑
-->
<view class="big_box"><watermark></watermark>
<page-title :showBack="true">问答详情</page-title>
<u-toast ref="messager"></u-toast>
<view class="adetail content">
<!--文章内容-->
<view class="adetail-title" v-if="detailData.id" style="word-break: break-all;">
<text class="qa-basic qa-solve" v-if="detailData.isResolve">[已解决]</text>
<text class="qa-basic qa-unSolve" v-else>[待解决]</text>
{{ detailData.title }}
</view>
<view class="adetail-info">
<view style="display: flex;line-height: 40upx;">
<author-info :name="detailData.sysCreateBy" :avatar="detailData.avatar" :sex="detailData.sex" :info="detailData.ucode" :showInfo="true"></author-info>
</view>
<view style="padding: 20upx 0upx 10upx 40upx; font-size: 24rpx; ">{{ detailData.sysCreateTime }}</view>
</view>
<view class="adetail-body">
<u-parse :content="detailData.content"></u-parse>
<view v-for="(img,idx) in images" :key="idx"><image :src="img" mode="aspectFit"></image> </view>
</view>
</view>
<view>
<view class="comments">
<view class="comments-top">
<view v-if="detailData.id">回答<text style="color: #818181;margin-left: 5px;">{{ answers }}</text></view>
<!-- <view class="share-btn" @click="openShare">
<view class="share-btn-icon"><img src="../../static/images/icon/share.png" alt="" /></view>
<view class="share-btn-name">分享</view>
</view> -->
</view>
<view class="comments-items">
<!--内容确定了这部分样式要移到class中-->
<view v-for="(an, anidx) in answerList" :key="anidx" class="comment">
<view class="comment-top">
<view style="display: flex;">
<author v-if="an" :showInfo="true" :data="an"></author>
</view>
<view class="comment-time">
<view style="display: flex;">
<view v-if="detailData.isResolve">
<text v-if="an.isBest" style="color:#FFB30F;">最佳答案</text>
</view>
<view style="margin-left: 10px"><time-show :time="an.sysCreateTime"></time-show></view>
</view>
</view>
</view>
<view class="comment-body" style="word-break: break-all;white-space: pre-wrap;">
<view class="comment-content">
{{ displayAll(an) }}
<text style="color: #00aaff;word-break: normal; " v-if="an.content.length>minTextLen" @click="changeIsAll(an)">{{an.isAll?' 收起':' 全文'}}</text>
</view>
<view class="comment-btns">
<view style="display: flex;">
<u-icon style="margin-right: 15px;" @click="openReply(an,{})" name="chat" color="#979797" size="18" label="回复"></u-icon>
<u-icon v-if="an.isPraise" style="margin-right: 10px;" @click="removePraise(anidx)" name="thumb-up-fill" color="#979797" size="18" :label="an.praises"></u-icon>
<u-icon v-if="!an.isPraise" style="margin-right: 10px;" @click="addPraise(anidx)" name="thumb-up" color="#979797" size="18" :label="an.praises"></u-icon>
</view>
<view>
<u-icon v-if="userInfo.aid==an.sysCreateAid" @click="openBtns(an,anidx)" name="more-dot-fill" size="20"></u-icon>
</view>
</view>
<!--一级评论二级数据-->
<view v-if="an.answers && an.answers.length!=0" class="comment-replys">
<view v-for="(ele, replyIndex) in an.answers" :key="replyIndex" class="comment">
<view class="comment-top">
<view style="display: flex;">
<author v-if="ele" :showInfo="true" :data="ele"></author>
<text style="padding-left: 16upx;padding-top: 6upx;color: #979797;">回复</text>
<text style="padding-left: 16upx;padding-top: 6upx;font-size: 26upx;">{{ele.replayName}}</text>
</view>
<view class="comment-time">
<time-show :time="ele.sysCreateTime"></time-show>
</view>
</view>
<view class="comment-body">
<view class="comment-content" style="word-break: break-all;white-space: pre-wrap;">
{{ displayAll(ele) }}
<text style="color: #00aaff; white-space: nowrap;" v-if="ele.content.length>minTextLen" @click="changeIsAll(ele)">{{ele.isAll?' 收起':' 全文'}}</text>
</view>
<view class="comment-btns">
<view>
<u-icon @click="openReply(ele,an)" name="chat" color="#979797" size="18" label="回复"></u-icon>
</view>
<view>
<u-icon v-if="userInfo.aid==ele.sysCreateAid" @click="openBtns(ele,replyIndex)" name="more-dot-fill" size="20"></u-icon>
</view>
</view>
<!--评论的二级显示-->
<view v-if="ele.answers && ele.answers.length!=0" class="comment-replys">
<view v-for="(row, rowIdx) in ele.answers" :key="rowIdx" class="comment">
<view class="comment-top">
<view style="display: flex;">
<author v-if="row" :showInfo="true" :data="row"></author>
<text style="padding-left: 16upx;padding-top: 6upx;color: #979797;">回复</text>
<text style="padding-left: 16upx;padding-top: 6upx;font-size: 26upx;">{{row.replayName}}</text>
</view>
<view class="comment-time">
<time-show :time="row.sysCreateTime"></time-show>
</view>
</view>
<view class="comment-body">
<view class="comment-content" style="word-break: break-all;white-space: pre-wrap;">
{{ displayAll(row) }}
<text style="color: #00aaff; white-space: nowrap;" v-if="row.content.length>minTextLen" @click="changeIsAll(row)">{{row.isAll?' 收起':' 全文'}}</text>
</view>
<view class="comment-btns">
<view>
<u-icon @click="openReply(row,ele)" name="chat" color="#979797" size="18" label="回复"></u-icon>
</view>
<view>
<u-icon v-if="userInfo.aid==row.sysCreateAid" @click="openBtns(row,rowIdx)" name="more-dot-fill" size="20"></u-icon>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view><uni-load-more :status="loadStatus"></uni-load-more></view>
</view>
<!-- 下方的点赞 -->
<interact-fixed :data="detailData" ref="fiexdbar" :comments="false" :answers="true" :type="4">
<view class="field" @click="openAnswerInput()">
<u-icon name="edit-pen-fill" size="18" class="field-icon"></u-icon>
<text class="wenz">我来回答..</text>
</view>
</interact-fixed>
<!--弹出回答的窗口-->
<u-popup :show="replyShow" @close="closeReply">
<view>
<view style="display: flex;justify-content: space-around;">
<view style="padding: 20rpx;flex: 1; white-space: pre-wrap; word-break: break-all;">
<u--textarea :height="120" v-model="answercontent" :placeholder="placeholder" count maxlength="200"></u--textarea>
</view>
<view style="padding: 20px 10px">
<view style="line-height: 82upx;text-align: center;margin-bottom: 20upx" @click="askQuestioner">
<text v-if="replyLevel=='one'">@</text>
</view>
<u-button style="height: 60px;" @click="submitReply" type="primary" size="small" :text="replyLevel=='one'? '提交回答':'提交回复'"></u-button>
</view>
</view>
</view>
</u-popup>
<u-popup :show="answerEdit.show" @close="closeAnswerEdit" @open="openAnswerEdit">
<view>
<view style="display: flex;justify-content: space-around;">
<view style="padding: 20rpx;flex: 1;">
<u--textarea :height="120" v-model="curItem.content" placeholder="请输入5-1000个字" count maxlength="1000"></u--textarea>
</view>
<view style="padding: 40px 10px"><u-button style="height: 60px;" @click="editSubmitAnswer" type="primary" size="small" text="提交回答"></u-button></view>
</view>
</view>
</u-popup>
<!--编辑处理-->
<u-popup :show="btnsShow" @close="closeBtns">
<view>
<view class="big-button" v-if="userInfo.aid==detailData.sysCreateAid && !detailData.isResolve && curItem.id && curItem.clevel==1" @click="setBest()">设置为最佳答案</view>
<view @click="editAnswer()" v-if="userInfo.aid==curItem.sysCreateAid && curItem.id && curItem.clevel==1" class="big-button">编辑</view>
<view @click="delAnswer()" v-if="userInfo.aid==curItem.sysCreateAid" class="big-button" style="color: #db0000;">删除</view>
<view @click="closeBtns()" class="big-button">取消</view>
</view>
</u-popup>
<u-toast ref="interactToast"></u-toast>
</view>
</template>
<script>
import apiQa from '@/api/modules/qa.js';
import apiUser from '@/api/system/user.js'
import apiPraises from '@/api/modules/praises.js'
import apiMessage from '@/api/system/message.js'
import { mapGetters } from 'vuex';
export default {
data() {
return {
detailData: {}, //问题详情数据
answers:0,
images:[],
answerList: [], //回答列表数据
questionId:'',
answercontent:'',
fileUrl:this.$config.fileUrl,
loadStatus: 'more', //more,loading,noMore
minTextLen:100,
pageSize: 20,
pageIndex: 1,
replyShow: false,
replyValue: '',
isShow: null,
bestId: '',
btnsShow: false,
curItem: {},//当前条目
curItemIndex: -1,//当前索引值
curParent:{},//当前输入的上级的对象用于往answers中追加回复的内容
curParentId:'',//当前回复的内容的id
answerEdit:{
show:false
},
replyLevel:'one',//one代表一级回复two代表二级回复,
loading: false,//控制点赞按钮是否可以点击
firstIndex:0,
type:4,
};
},
onLoad(option) {
this.questionId=option.id
this.getData(this.questionId);
},
computed: {
...mapGetters(['userInfo']),
placeholder(){
let txt='请写下您的答案(200字以内),可以@提问者哦~';
console.log(this.curItem.clevel,'this.curItem.clevel');
if(this.curItem && this.curItem.id){
//if(this.curItem.clevel>1){
txt='请写下您的回复(200字以内)';
//}
}
return txt;
}
},
onReachBottom(){
this.loadStatus='loading';
if(this.answerList.length==this.answers||this.answerList.length>this.answers){
this.loadStatus='nomore';
}else{
this.pageIndex++;
this.getAnswerList(this.questionId)
}
},
watch:{
answercontent(newVal,oldVal){
if(!oldVal&&newVal==='@'){
if(this.replyLevel=='one'){
this.answercontent+=this.detailData.sysCreateBy
}
if(this.replyLevel=='two'){
this.answercontent='@'+this.answerList[this.firstIndex].sysCreateBy
}
}
}
},
methods: {
closeAnswerEdit(){
this.answerEdit.show=false;
},
openAnswerEdit(){
this.answerEdit.show=true;
},
//获取问题详情数据
getData(id) {
uni.showLoading({title:'加载中...'})
let $this=this;
apiQa.detail(id).then(res => {
if (res.status == 200) {
//处理图片
let imgArray=[];
if(res.result.images!=''){
let array=res.result.images.split(',');
array.forEach(imgpath=>{
imgArray.push($this.fileUrl+imgpath);
});
this.images=imgArray;
}
this.answers=res.result.answers;
this.answerList=[]
this.getAnswerList(id);
apiUser.getByIds([res.result.sysCreateAid]).then(rs=>{
setTimeout(function(){ uni.hideLoading() },100);
if(rs.status==200){
if(rs.result!='' && rs.result.length>0){
let author=rs.result[0];
if(author.avatar != '') {
res.result.avatar=$this.fileUrl+author.avatar;
} else {
res.result.avatar='';
}
res.result.sex = author.sex;
res.result.orgInfo=author.orgInfo;
res.result.ucode=author.code;
}
$this.detailData = res.result;
}else{
$this.detailData = res.result;
}
})
setTimeout(function(){ uni.hideLoading() },100);
}
})
.catch(err => {
uni.showToast({
icon: 'none',
title:"获取数据失败"
})
});
},
//获取回答列表数据
getAnswerList(id) {
let params={
qid:id,
pageSize:this.pageSize,
pageIndex:this.pageIndex
}
apiQa.page(params).then(res => {
if (res.status == 200) {
let allList=[];
this.answerList = [];
this.answers= res.result.count;
let uids=[];
let level3ParentIds=[];
res.result.list.forEach(item=>{
item.avatar='';
item.orgInfo='';
item.sex=null;
item.isAll=false;
uids.push(item.sysCreateAid);
allList.push(item);
level3ParentIds.push(item.id);
if(item.answers && item.answers.length!=0){
item.answers.forEach(answers=>{
answers.avatar='';
answers.orgInfo='';
answers.sex=null;
answers.isAll=false;
uids.push(answers.sysCreateAid);
allList.push(answers);
level3ParentIds.push(answers.id);
})
}
});
this.loadUserInfos(allList,uids);
this.answerList.push(...res.result.list);
this.loadLevel3Data(level3ParentIds);
}
}).catch(err => {
uni.showToast({icon: 'none',title:"获取数据失败"})
});
},
//加载第三级的数据
loadLevel3Data(commentIdArray){
let $this=this;
if(commentIdArray && commentIdArray.length>0){
apiQa.replayClevel3(commentIdArray).then(rs=>{
if(rs.status==200){
//先处理头像
let aids=[];
rs.result.forEach(item=>{
item.avatar = "";
item.sex=null;
item.isAll=false;
aids.push(item.sysCreateAid);
});
$this.loadUserInfos(rs.result,aids);
$this.answerList.forEach(one1=>{
if(one1.answers.length>0){
one1.answers.forEach(one2=>{
one2.answers=one2.answers? one2.answers:[];
rs.result.forEach(rsRow=>{
if(rsRow.commentId==one2.id){
one2.answers.push(rsRow);
}
})
})
}
})
}
})
}
},
displayAll(item) {
if(!item.isAll && item.content.length > this.minTextLen) {
return item.content.slice(0, this.minTextLen) + "...";
}
return item.content;
},
changeIsAll(item) {
//console.log(item,'isall');
item.isAll=!item.isAll;
},
messageSave(refId,title,sendName,acceptName,acceptId,typeText){
let content='评论';
let conType;
content=sendName+typeText+content+'-'+title
let message={
content,
refId,
refType:this.type,
sendName,
acceptName,
acceptId,
title:'系统消息',
sendType:1,
conType,
content,
}
apiMessage.save(message).then(res=>{
if(res.status==200){
}
})
},
//设置最佳答案接口
setBest() {
//userInfo.aid == an.sysCreateAid因为身份信息为空所以为了接接口没有加这个判断但是实际上要加的
apiQa.isBest(this.curItem.id).then(res => {
if (res.status == 200) {
this.$set(this.detailData, 'isResolve', true);
uni.showToast({title:"设置成功" ,duration: 2000})
this.btnsShow=false
this.answerList=[]
//console.log("我经过这里面美哟")
this.getAnswerList(this.questionId)
}
})
.catch(err => {
uni.showToast({icon: 'none',title:"设置失败"})
});
},
openAnswerInput(){
this.answercontent='';
this.replyShow = true;
this.replyLevel='one';//就是回答
this.curParent={};//没有上级数据
this.curParentId='';
this.curItem={};
this.curItemIndex=-1;
},
//发布回答
publishAnswer() {
// if (this.answercontent.length < 5 || this.answercontent.length > 1000) {
// return uni.showToast({
// icon: 'none',
// title:"请输入5-200个字"
// })
// }
let answercontent=''
if (this.answercontent.length < 1 ||this.answercontent.trim()=='@'+this.detailData.sysCreateBy) {
return uni.showToast({icon: 'none',title:"请输入回答"});
}
// if(this.answercontent.indexOf('@'+this.detailData.sysCreateBy)!=-1){
// answercontent=this.answercontent.slice(this.detailData.sysCreateBy.length+1)
// }
else{
answercontent=this.answercontent
}
apiQa.saveAnswer({
qid: this.questionId,
content: answercontent
}).then(res => {
if (res.status == 200) {
uni.showToast({
title:"发布成功" ,
duration: 2000
})
this.answerList=[]
this.getAnswerList(this.questionId);
this.answercontent = '';
this.replyShow = false;
} else {
uni.showToast({icon: 'none',title:"发布失败"})
}
}).catch(err => {
uni.showToast({icon: 'none',title:"发布失败"})
});
},
loadUserInfos(list,userIds){
let $this=this;
const noReapetIds=[...new Set(userIds)]
if(userIds.length>0){
apiUser.getByIds(noReapetIds).then(res=>{
if(res.status==200){
list.forEach(item=>{
res.result.some(author=>{
if(author.aid==item.sysCreateAid){
if(author.avatar!=''){
item.avatar=$this.fileUrl+author.avatar;
}
item.sex=author.sex;
item.ucode=author.code;
item.orgInfo=author.orgInfo;
return true;
}
return false;
})
})
}
this.loadStatus='more';
})
}
},
openBtns(item,itemIdx) {
this.btnsShow = true;
this.curItem = item;
this.curItemIndex=itemIdx;
},
closeBtns() {
this.btnsShow = false;
this.curItem = {};
},
delAnswer() {
this.btnsShow=false;
//不能删除最佳答案
if(this.curItem.isBest){
this.$refs.messager.show({message:'最佳答案不能删除',type:'error'});
return;
}
let $this=this;
uni.showModal({
title: '提示',
content: '您确定要删除所选内容吗?',
success: function (res) {
if (res.confirm) {
apiQa.delAnswer($this.curItem.id).then(rs=>{
if(rs.status==200){
this.answerList=[]
$this.$refs.messager.show({message:'删除成功',type:'success'});
$this.getAnswerList($this.questionId);//questionId要移出去
}else{
$this.$refs.messager.show({message:'删除失败:'+rs.message,type:'error'});
}
})
} else if (res.cancel) {
}
}
});
},
editAnswer() {
this.btnsShow=false;
this.answerEdit.show=true;
},
editSubmitAnswer(){
// 修改后提交
if (this.curItem.content.length < 5 || this.curItem.content.length > 200) {
return uni.showToast({
icon: 'none',
title:"请输入5-200个字"
})
}
let d={
id:this.curItem.id,
sysCreateAid:this.curItem.sysCreateAid,
content:this.curItem.content
}
apiQa.updateAnswer(d).then(rs=>{
if(rs.status==200){
this.answerEdit.show=false;
this.$refs.messager.show({message:'提交成功',type:'success'});
}else{
this.$refs.messager.show({message:rs.message,type:'error'});
}
})
},
openReply(item,parent) {
this.answercontent='';
this.replyShow = true;
this.replyLevel=''
this.curParentId=item.id;//回复的parentId
this.curParent=parent;//回复的上级数据用于追加answers
this.curItem=item;
},
closeReply() {
this.answercontent='';
this.curParentId='';
this.curParent={};
this.curItem={};
this.replyShow = false;
},
openShare() {
this.$refs.fiexdbar.addShare();
},
submitReply() {
if(this.replyLevel=='one'){
this.publishAnswer();
return;
}
let answercontent=''
if (this.answercontent.length < 1 ||this.answercontent.trim()=='@'+this.curItem.sysCreateBy) {
return uni.showToast({icon: 'none',title:"请输入回答"});
}
let postData={
replayAid: this.curItem.sysCreateAid,
replayName: this.curItem.sysCreateBy,
content: this.answercontent,
parentId: this.curItem.id,
commentId: "",
clevel: 2
}
if(this.curItem.clevel==2){ //当前是一级评论
postData.commentId=this.curItem.id;
postData.clevel=3;
}else if(this.curItem.clevel>2){
postData.commentId=this.curItem.commentId;
postData.clevel=3;
}
apiQa.saveComment(postData).then(res=>{
if(res.status==200){
res.result.avatar = "";
res.result.sex = null;
res.result.isAll = false;
this.curParentId='';
this.answercontent='';
this.loadUserInfos([res.result],[res.result.sysCreateAid]);
//console.log(this.curItem,'this.curItem');
//console.log(this.curParent,'this.curParent');
//if(this.curItem.id)
if(this.curItem.clevel<3){
if(!this.curItem.answers){
this.curItem.answers=[];
}
this.curItem.answers.push(res.result);
}else{
this.curParent.answers.push(res.result);
}
uni.showToast({icon: 'none',title:"回复成功"});
this.replyShow = false;
}else{
uni.showToast({icon: 'none',title:"回复失败"});
this.replyShow = false;
}
})
},
askQuestioner(){
if(this.replyLevel=='one'){
this.answercontent='@'+this.detailData.sysCreateBy
}else{
if(this.curItem.sysCreateBy){
this.answercontent='@'+this.curItem.sysCreateBy
}
}
},
addPraise(index){
if(this.loading){
return
}
this.loading=true;
let postData={
objType:5,
objId:this.answerList[index].id,
title:'',
}
apiPraises.save(postData).then(res=>{
if(res.status==200){
this.answerList[index].isPraise=true;
this.answerList[index].praises++;
this.$refs.interactToast.show({message:'点赞成功',type:'success'});
//console.log(this.answerList[index],'content)')
this.messageSave(this.answerList[index].id,this.answerList[index].content,this.userInfo.name,this.answerList[index].sysCreateBy,this.answerList[index].sysCreateAid,'点赞了我的');
}else{
this.$refs.interactToast.show({message:'点赞失败',type:'error'});
}
this.loading=false;
})
},
removePraise(index){
if(this.loading){
return
}
this.loading=true;
apiPraises.remove(5,this.answerList[index].id).then(res=>{
if(res.status==200){
this.answerList[index].isPraise=false
if(this.answerList[index].praises>0){
this.answerList[index].praises--;
}
this.$refs.interactToast.show({message:'取消点赞成功',type:'success'});
}else{
this.$refs.interactToast.show({message:'取消点赞失败',type:'error'});
}
this.loading=false;
})
}
}
};
</script>
<style lang="scss" scoped>
.one-wrap {
// width: 80%;
flex:1;
display: flex;
justify-content: space-between;
align-items: center;
span{
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: 32px;
}
// display: flex;
// justify-content: flex-start;
// align-items: center;
}
.adetail {
padding: 15upx 30upx;
.adetail-title {
// font-weight: 700;
font-weight: bold;
//font-weight: 610;
font-size: 32rpx;
letter-spacing: 0.5px;
.qa-basic{
font-size: 32rpx;
}
}
.adetail-info {
display: flex;
padding-top: 20upx;
line-height: 55upx;
color: #7e7e7e;
}
.adetail-body {
//padding-top: 15px;
line-height: 55upx;
white-space: normal;
word-break: break-all;
background-color: #ffffff;
> div {
text-indent: 24px;
}
}
}
.field {
width: 200px;
height: 40px;
line-height: 30px;
background: rgb(247,247,249);
border-radius: 10upx;
display: flex;
.field-icon{
margin-top: 2px;
margin-left: 10px;
}
.wenz{
font-size: 14px;
color: #000000;
margin-left: 2px;
margin-top: 5px;
}
}
.comments {
margin-top: 10px;
background-color: #ffffff;
padding: 15upx 30upx;
.comments-top {
display: flex;
justify-content: space-between;
padding-bottom: 30upx;
border-bottom: 1px solid #f4f4f4;
font-weight: 500;
font-size: 30upx;
}
.comments-items {
padding-top: 20upx;
.comments-item {
padding-bottom: 5px;
padding-top: 15upx;
}
.comments-avatar {
height: 60upx;
width: 60upx;
border-radius: 10%;
border: 1px solid #f3f3f3;
}
.twoLevelReply{
padding-left: 40upx;
}
}
}
.comment{
padding-top: 20upx;
.comment-top{
display: flex;
justify-content: space-between;
line-height: 50upx;
.comment-avatar{
height: 50upx;
width: 50upx;
border-radius: 10%;
border: 1px solid #f3f3f3;
}
.comment-time{
color: #696969;font-size: 0.9em;
}
}
.comment-body{
padding: 6upx 0upx 0upx 60upx;
color: #373737;
.comment-content{
word-break:break-all;
padding: 0upx 10upx 10upx 0upx;
font-size: 28upx;
color: #333333;
}
.comment-btns{
display: flex;
justify-content: space-between;
padding-top: 10upx;
}
}
}
.big-button {
text-align: center;
line-height: 80upx;
border-top: 1px solid #ebebeb;
}
</style>