Files
learning-system-portal/src/views/portal/qa/Index.vue
2022-06-13 17:53:16 +08:00

778 lines
24 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>
<div id="qa-list-content" class="qa-list-content">
<portal-header current="qa" @emitInput="emitInput"></portal-header>
<div class="xcontent portal-content">
<div class="xrow" style="display: flex;justify-content: space-between;">
<div style="flex: 1;" class="xcol content-div">
<el-row>
<el-card :body-style="{ padding: '0px' }" class="left-div">
<el-row class="search-div">
<el-col>
<!-- <el-input placeholder="请输入关键词搜索" clearable v-model="queryKeyWord" maxlength="20">
<el-button slot="append" icon="el-icon-search" @click="search()"></el-button>
</el-input> -->
<!-- <div class="tip">
热门搜索词
<span v-for="(item, index) in searchRecords" :key="index" @click="useHotword(item)">{{ item.keyword }}</span>
</div> -->
</el-col>
</el-row>
<el-row class="order-div">
<span class="quyer-tag">
<el-button type="text" class="order-class" @click="orderFieldData('answers')" :class="{ actice: styleControl == 2 }">
最热
</el-button>
<el-button type="text" class="order-class" @click="orderFieldData('')" :class="{ actice: styleControl == 1 }">
最新
</el-button>
<!-- <el-checkbox-group> -->
<el-button type="text" @click="setEssence(queryConditions.isEssence)" class="order-class" :class="{ actice: styleControl == 3 }">精华问题</el-button>
<!-- </el-checkbox-group> -->
</span>
<!-- <span v-if="qaList.length > 0" style="padding-left:10px;">本次搜索出 {{ count }} 条结果</span> -->
<span class="quyer-tag">
<el-button type="text" class="order-class" @click="isResolveData(null)" :class="{ actice: queryConditions.isResolve === null }">
全部
</el-button>
<el-button type="text" class="order-class" @click="isResolveData(false)" :class="{ actice: queryConditions.isResolve === false }">
待解决
</el-button>
<!-- <el-checkbox-group> -->
<el-button type="text" @click="isResolveData(true)" class="order-class" :class="{ actice: queryConditions.isResolve===true }">已解决</el-button>
<!-- <el-radio-group style="margin-right: 10px;" v-model="queryConditions.isResolve" @change="getQaData(1)">
<el-radio-button :label="null" border>全部</el-radio-button>
<el-radio-button :label="false" border>待解决</el-radio-button>
<el-radio-button :label="true" border>已解决</el-radio-button>
</el-radio-group> -->
</span>
</el-row>
<div class="data-content" v-if="qaList.length > 0">
<div :span="24" v-for="(qa, qaidx) in qaList" :key="qaidx" class="qa-list">
<div class="qa-info-box">
<div class="qa-info">
<div class="qa-info-title" @click="jumpDetail(qa)">
<div class="qa-title-text one-line-ellipsis">
<span class="qa-basic qa-unSolve" v-if="qa.isResolve == false" @click="searchData()">待解决</span>
<span class="qa-basic qa-solve" v-if="qa.isResolve == true" @click="searchData()">已解决</span>
<span v-html="$keywordActiveShow(qa.title,queryKeyWord)"></span>
</div>
<div class="qa-info-date">
<i class="el-icon-time"></i> {{qa.sysCreateTime.substring(0,10)}}
<!-- <time-show :time="qa.sysCreateTime"></time-show> -->
</div>
</div>
<div style="display: flex;">
<div style="flex: 83%" class="qa-info-summary two-line-ellipsis" @click="jumpDetail(qa)" v-html="$keywordActiveShow(qa.content,queryKeyWord)"></div>
<div style="flex: 17% ; cursor: pointer; text-align: right;cursor: pointer;" v-if="qa.images!==''" @click="jumpDetail(qa)">
<img style="width: 156px;height: 105px;" :src="fileBaseUrl + qa.images" alt="">
</div>
</div>
<div style="display: flex;justify-content:flex-start;">
<div style="width: 120px;">
<author :avatar="qa.authorInfo.avatar" :name="qa.authorInfo.name" :sex="qa.authorInfo.sex"></author>
<!-- <author :avatar="qa.authorInfo.avatar" :name="qa.authorInfo.name" :info="qa.authorInfo.orgInfo"></author> -->
</div>
<div><interactBar nodeWidth="60px" :readonly="true" :type="4" :data="qa" @addAnswers="qaAnswer(qa)" :shares="true" :comments="false" :answers="true" :clickAnswer="true" :views="false"></interactBar></div>
<!-- <div class="qa-info-re" @click="qaAnswer(qa)">快速回答</div> -->
</div>
</div>
</div>
</div>
</div>
<div class="pagination-div">
<span class="pag-text" @click="loadMore()" v-if="moreState == 1">加载更多</span>
<span class="pag-text-msg" v-else-if="moreState == 2">数据加载中</span>
<span class="pag-text-msg" v-else-if="moreState == 3 && !isSeach">没有更多数据了</span>
<span class="pag-text-msg" v-else-if="isSeach">没有查询到相关内容</span>
</div>
<div v-if="isSeach" style="height:382px">
</div>
</el-card>
</el-row>
</div>
<div style="width: 245px;margin-left: 5px;">
<div>
<div style="padding:0" id="qa-fixd">
<div style="margin-bottom:15px;padding: 0">
<el-button style="height: 100%;height: 37px;border-radius: 0;" class="add-btn" @click="$refs.addQuestion.askQuestionDialog = true" type="primary">提问题</el-button>
</div>
<el-card class="ranking-card">
<div slot="header">
<span style="font-size: 14px;font-weight: 600;color: #333333;">贡献排行榜</span>
<!-- <el-radio-group v-model="anking" size="mini" style="float: right">
<el-radio-button label="年"></el-radio-button>
<el-radio-button label="月"></el-radio-button>
<el-radio-button label="日"></el-radio-button>
</el-radio-group> -->
</div>
<div style="padding-bottom:10px">
<!-- <el-row class="ranking-title"> -->
<!-- <el-col :offset="4" :span="10" style="color: #333333;font-size: 14px;">姓名</el-col>
<el-col :span="10" style="text-align: right;color: #333333;font-size: 14px;">贡献度</el-col> -->
<!-- </el-row> -->
<el-row class="ranking-title bacolor" v-for="(item, index) in ankingList" :key="index" >
<el-col :span="6" style="height:34px">
<img v-if="index===0" :src="`${webBaseUrl}/images/first.png`"/>
<img v-if="index===1" :src="`${webBaseUrl}/images/second.png`"/>
<img v-if="index===2" :src="`${webBaseUrl}/images/third.png`"/>
<span style="margin-left: 10px" v-if="index!=2&&index!=0&&index!=1">{{index+1}}</span>
</el-col>
<!-- <el-tooltip :enterable="false" @click.native="jumpRouter(item)" effect="light" :content="item.name" placement="top-start"> -->
<el-col :span="18" class="one-line-ellipsis"> {{ item.sysCreateUname }}</el-col>
<!-- </el-tooltip> -->
<!-- <el-col class="center" style="color: #FF8E00;" :span="5">{{ item.score }}</el-col> -->
</el-row>
<!-- <el-row class="ranking-title" v-for="(item, index) in ankingList" :key="index">
<el-col :span="4" class="center">
<img v-if="index === 0" :src="`${webBaseUrl}/images/first.png`" />
<img v-if="index === 1" :src="`${webBaseUrl}/images/second.png`" />
<img v-if="index === 2" :src="`${webBaseUrl}/images/third.png`" />
<span v-if="index != 2 && index != 0 && index != 1">{{ index + 1 }}</span>
</el-col>
<el-col style="color: #333333;font-size: 14px;" :span="10">{{ item.sysCreateUname }}</el-col>
<el-col style="text-align: right;color: #333333;font-size: 14px;" :span="10">{{ item.answers }}</el-col>
</el-row> -->
</div>
</el-card>
</div>
</div>
</div>
</div>
<addQuestion ref="addQuestion" @sure="getQaData(true)"></addQuestion>
</div>
<!-- :before-close="handleClose" -->
<el-dialog title="快速回答" :visible.sync="dialogVisible" width="600px" :close-on-click-modal="false">
<div>
<el-input type="textarea" :rows="5" maxlength="800" placeholder="写下您的答案(800字以内)" v-model="answer.inputValue"></el-input>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" v-loading="loading" @click="publishAnswer()"> </el-button>
</span>
</el-dialog>
<portal-footer></portal-footer>
<portalFloatTools @sure="getQaData(true)"></portalFloatTools>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import portalHeader from '@/components/PortalHeader.vue';
import portalFooter from '@/components/PortalFooter.vue';
import portalFloatTools from '@/components/PortalFloatTools.vue';
import WxEditor from '@/components/Editor/index.vue';
import interactBar from '@/components/Portal/interactBar.vue';
import timeShow from '@/components/Portal/datetimeShow.vue';
import author from '@/components/Portal/authorInfo.vue';
import addQuestion from '@/components/Qa/addQuestion.vue';
import apiQa from '@/api/modules/qa.js';
import apiUser from '@/api/system/user.js';
import apiSearchterm from '@/api/modules/searchterm.js';
export default {
name: 'qaindex',
components: { portalHeader, portalFooter, portalFloatTools, WxEditor, addQuestion, author, interactBar, timeShow },
computed: {
...mapGetters(['userInfo']),
},
// watch:{
// 'queryConditions.isEssence':{
// handler:function(newName,oldName){
// if(newName){
// this.queryConditions.orderField='null'
// }else{
// // this.queryConditions.isEssence=''
// this.queryConditions.orderField='id'
// }
// }
// }
// },
data() {
return {
fileBaseUrl: process.env.VUE_APP_FILE_BASE_URL,
loading: false,
answer:{
id: '',
inputValue: '',
},
dialogVisible: false,
moreState:1,// 1 加载更多 2 加载中 3无数据
searchRecords: [],
queryConditions: {
pageIndex: 1,
pageSize: 10,
keyword: '',
isResolve: null,
isEssence: '',
orderField: '',
orderAsc: false
}, //传参所需要的数据
queryKeyWord: '',
//因为不需要这个数据不是跟随input框值变化请求所以拿出来了
count: 0, //页面总条数
qaList: [], //问答详情列表
//以上是整理后的数据
anking: 2, //排行榜
ankingList: [],
styleControl:2,
isSeach:false,
};
},
mounted() {
this.queryKeyWord = this.$route.query.keyword;
this.queryConditions.keyword = this.queryKeyWord;
if(this.queryConditions.keyword != '') {
this.isSeach = true;
}
this.getQaData(true);
this.getAnkingData();
window.addEventListener("scroll", this.handleScroll);
this.searchterm();
},
beforeDestroy(){
window.removeEventListener("scroll",this.handleScroll);
},
methods: {
emitInput(val){
this.queryKeyWord = val;
this.isSeach =true;
this.search();
},
//发布回答
publishAnswer() {
if (this.answer.inputValue < 1 ) {
return this.$message.warning('请输入回答');
}
this.loading = true;
apiQa
.saveAnswer({
qid: this.answer.id,
content: this.answer.inputValue
})
.then(res => {
if (res.status == 200) {
this.loading = false;
// this.messageSave('send')
this.$message({
message: '发布回答成功',
type: 'success'
});
this.dialogVisible=false
// this.getQuestionDetail();
// this.loadAnswer();
this.getQaData(true);
this.answer.inputValue = '';
} else {
this.loading = false;
this.$message({
message: res.message,
type: 'error'
});
}
})
},
qaAnswer(qa) {
this.answer.id = qa.id;
this.dialogVisible = true;
},
handleScroll(){
let innerHeight = document.querySelector('#qa-list-content').clientHeight
let outerHeight = document.documentElement.clientHeight
let scrollTop = document.documentElement.scrollTop
if ((outerHeight + scrollTop + 350) >= innerHeight) {
if(this.moreState == 1) {
this.debounce(this.loadMore(),5000);
}
}
if(scrollTop > 400) {
document.querySelector('#qa-fixd').style.cssText = "position: fixed;top: 0;width:242.5px";
} else {
document.querySelector('#qa-fixd').style.cssText = "position: static";
}
},
isResolveData(num) {
this.queryConditions.isResolve=num;
this.queryConditions.pageIndex = 1
this.qaList = [];
this.getQaData(true);
},
debounce(func, wait) {// 非立即执行
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
},
setEssence(val){
this.styleControl = 3
this.queryConditions.orderField = '';
this.queryConditions.isEssence=true
this.getQaData(true);
},
orderFieldData(id) {
this.queryConditions.isEssence=''
if(id==""){
this.styleControl = 1
}
if(id=="answers"){
this.styleControl = 2
}
this.queryConditions.orderField = id;
this.queryConditions.pageIndex = 1
this.qaList = [];
this.getQaData(true);
},
searchData() {
this.queryConditions.pageIndex = 1
this.qaList = [];
this.getQaData(true);
},
useHotword(item) {
this.queryConditions.pageIndex = 1
this.queryKeyWord = item.keyword;
this.queryConditions.keyword = this.queryKeyWord;
this.qaList = [];
this.getQaData(false);
},
searchterm() {
apiSearchterm.list(5, 4).then(res => {
if (res.status === 200) {
this.searchRecords = res.result;
}
});
},
loadMore() {
this.queryConditions.pageIndex += 1;
this.getQaData(false);
},
search() {
apiSearchterm.save({ keyword: this.queryKeyWord, type: 4 });
//this.listType=2;
this.queryConditions.pageIndex = 1;
this.qaList = [];
this.queryConditions.keyword = this.queryKeyWord;
this.getQaData(false);
},
//分页查询
handleSizeChange(item) {
this.queryConditions.pageSize = item;
},
handleCurrentChange(item) {
this.queryConditions.pageIndex = item;
},
async getQaData(flag) {
if(flag){
this.qaList=[];
this.queryConditions.pageIndex=1;
}
this.queryConditions.orderField=this.styleControl==1? 'id':'answers';
this.moreState = 2;
await apiQa
.potallist(this.queryConditions)
.then(res => {
if (res.status == 200 && res.result.list.length > 0) {
this.isSeach = false;
res.result.list.forEach(item => {
item.authorInfo = { aid: '', name: '', orgInfo: '', avatar: '',sex:null, };
});
this.count = res.result.count;
let ids = [];
res.result.list.forEach(item => {
item.authorInfo = { name: '', avatar: '', orgInfo: '',sex:null, };
ids.push(item.sysCreateAid);
});
this.getQaUserData(res.result.list,ids);
this.qaList.push(...res.result.list);
this.moreState = 1;
if(res.result.count == res.result.list.length) {
this.moreState = 3;
}
} else {
this.moreState = 3;
// this.$message.error(res.message);
}
})
.catch(err => {
console.log(err);
});
},
getQaUserData(qaList,ids) {
const noReapetIds = [...new Set(ids)];
apiUser.getByIds(noReapetIds).then(res => {
if (res.status == 200) {
qaList.forEach((item, index) => {
res.result.some(author => {
if (author.aid == item.sysCreateAid) {
item.authorInfo = author;
return true;
} else {
return false;
}
});
});
//以下代码有顺序问题,而且如果返回的字段有相同的名称,也会有问题
// this.qaList=qaList.map((item,index)=>{
// item=Object.assign(item,res.result[index])
// return item
// })
} else {
// this.$message.error(res.message);
}
});
},
jumpDetail(data) {
this.$router.push({ path: '/qa/answer', query: { id: data.id } });
},
getAnkingData() {
apiQa.queryList(5).then(res => {
if (res.status == 200) {
this.ankingList = res.result;
}
});
}
}
};
</script>
<style scoped lang="scss">
::v-deep .el-card__body{
padding: 0;
}
::v-deep .bacolor:nth-child(odd){
background-color: #fff;
padding: 0 5px;
}
::v-deep .bacolor:nth-child(even){
background-color: #f6f6f6;
padding: 0 5px;
}
.qa-isresolve {
color: #08A890;
margin-left: -10px;
// left: -50px;
}
.qa-unresolve {
color: #588afc;
margin-left: -10px;
// left: -50px;
}
.qa-title-text {
font-size: 18px;
line-height: 25px;
font-weight: 600;
color: #121212;
flex: 1;
}
.checkboxbutton {
outline: none;
}
.one-line-ellipsis {
display: -webkit-box;
white-space: pre-wrap;
overflow: hidden;
text-overflow:ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
box-sizing: border-box;
}
.two-line-ellipsis {
display: -webkit-box;
white-space:pre-wrap;
overflow: hidden;
text-overflow:ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
box-sizing: border-box;
}
.searchbar {
background-color: #ffffff;
border: 1px solid #f3f3f3;
width: 1200px;
padding: 5px 20px;
}
.fixed {
position: fixed;
top: 0px;
background-color: #f0f0f0;
z-index: 999;
height: 50px;
}
.left-div {
.quyer-tag {
.order-class{
padding:0px 12px;
color: #666666;
line-height: 32px;
background-color: #FFFFFF;
border: 1px solid #DDDDDD;
border-radius: 0px;
}
// ::v-deep .el-button{
// width: 52px!important;
// height: 32px;
// padding: 0;
// }
// .order-class {
// color: #666666;
// width: 80px;
// // text-align: left;
// border: 1px solid #dfdfdf;
// // padding-left: 5px;
// // padding-top: 5px;
// // padding-bottom: 5px;
// .el-icon--right {
// margin-left: 0;
// }
// }
.actice {
border: 0px;
background: #3e7fff;
color: #fff;
}
}
.more {
float: right;
display: block;
}
/* 分页div */
.pagination-div {
text-align: center;
padding: 10px 0;
}
.order-div {
padding: 0 20px;
background-color: #fff;
display: flex;
.quyer-tag{
&:last-of-type{
margin-left: auto;
}
}
// justify-content: space-between;
}
.data-content {
background-color: #fff;
padding: 5px 10px;
min-height: 382px;
.qa-list:last-child {
border-bottom: none;
}
.qa-list {
// margin: 5px 0;
padding: 20px 10px;
// padding-bottom: 10px;
// padding-left: 10px;
padding-right: 0px;
margin-right:10px;
border-bottom: 1px solid #E8E8E8;
}
.qa-info-box {
.qa-info {
.qa-info-title {
cursor: pointer;
font-size: 16px;
height: 30px;
display: flex;
justify-content: space-between;
align-items: center;
.qa-info-date {
margin-left: 30px;
height: 30px;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 200;
color: #999999;
font-size: 12px;
i {
margin-right: 5px;
}
}
}
.qa-info-re{
color: #3e7fff;
font-size: 14px;
line-height: 30px;
}
.qa-info-summary {
cursor: pointer;
line-height: 1.6;
margin: 12px 0 20px 0;
color: #121212;
height: 45px;
font-size: 15px;
word-break: break-all;
}
.qa-info-tools {
height: 30px;
.qa-info-tools-auth {
float: left;
font-size: 13px;
color: #999999;
img {
margin-right: 10px;
width: 30px;
border: 1px solid #eee;
border-radius: 50%;
vertical-align: middle;
}
}
.qa-info-tools-btns {
float: right;
.qa-info-tools-btn {
margin: 0 0 0 15px;
}
}
}
}
}
}
}
.search-div {
// background: #fff;
// padding: 10px 25px 0 25px;
padding: 20px;
::v-deep .el-input{
width: 420px;
height: 38px;
margin-bottom: 13px;
.el-input__inner{
height: 38px;
border-radius: 0;
}
.el-input-group__append{
width: 44px;
height: 38px;
border: 0;
padding: 0;
background:#3E7FFF;
border-radius: 0;
.el-button{
margin: 0;
border: 0;
width: 100%;
height: 38px;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
.el-icon-search{
color: #fff;
font-size: 22px;
}
}
}
}
.tip{
color:#999999;
font-size: 12px;
span{
margin-right: 8px;
cursor: pointer;
}
}
// .input-with-select {
// .tip {
// line-height: 35px;
// font-size: 14px;
// color: #666;
// }
// }
// .add-btn {
// width: 100%;
// height: 100%;
// }
}
.tag-class {
border-radius: 15px;
margin: 0 10px;
}
.add-tag {
padding: 7px 25px;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload--picture-card {
width: 200px;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
text-align: center;
margin-top: 50px;
display: block;
}
.icon-text {
font-size: 14px;
display: block;
height: 30px;
line-height: 35px;
}
// .avatar {
// width: 250px;
// height: 178px;
// display: block;
//
//padding-left: 10px;
.add-btn {
width: 100%;
padding: 0px 0;
}
.ranking-title {
line-height: 34px;
.center-titlt {
font-size: 15px;
color: #333333;
}
.center {
text-align: center;
}
img{
margin-top: 5px;
}
}
.ranking-data {
margin: 10px 0;
color: #999999;
}
::v-deep .imageUrls {
.el-form-item__content {
display: flex;
justify-content: flex-start;
align-items: center;
.imageUrl {
display: flex;
justify-content: flex-start;
align-items: center;
img {
margin-right: 8px;
width: 148px;
height: 148px;
}
}
}
}
</style>