Files
learning-system-portal/src/views/portal/qa/Index.vue
zhaofang 4cd6e7a652 提交
2022-08-30 17:04:11 +08:00

727 lines
21 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="portal-content">
<div class="xrow" style="display: flex;">
<div class="xcol content-div">
<el-row>
<el-card :body-style="{ padding: '0px' }" class="left-div">
<!-- <el-row class="search-div">
<el-col>
</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-button type="text" @click="setEssence(queryConditions.isEssence)" class="order-class" :class="{ actice: styleControl == 3 }">精华问题</el-button>
</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-button type="text" @click="isResolveData(true)" class="order-class" :class="{ actice: queryConditions.isResolve===true }">已解决</el-button>
</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="portal-title-tow one-line-ellipsis">
<span 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="portal-time">
<i class="el-icon-time"></i> {{qa.sysCreateTime}}
</div>
</div>
<div style="display: flex;">
<div style="flex: 83%" class="qa-info-summary portal-summary-text 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:space-between;">
<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: 410px !important;">
<!-- <div> -->
<div style="padding:0" id="qa-fixd">
<div class="portal-model-btn" @click="$refs.addQuestion.askQuestionDialog = true">提问题</div>
<div class="portal-right-box list-bg">
<p class="portal-title-one" style="padding-bottom:12px">贡献榜</p>
<ul>
<li v-for="(item, index) in ankingList" :key="index" style="margin-top:30px">
<span class="portal-right-text orange-one" v-if="index==0" style="margin-right:94px">0{{index+1}}.</span>
<span class="portal-right-text orange-tow" v-if="index==1" style="margin-right:94px">0{{index+1}}.</span>
<span class="portal-right-text orange-three" v-if="index==2" style="margin-right:94px">0{{index+1}}.</span>
<span class="portal-right-text" v-if="index>2" style="margin-right:94px">0{{index+1}}.</span>
<span class="portal-title-desc">{{ item.sysCreateUname }}</span>
</li>
</ul>
</div>
</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.trim()
})
.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:410px;";
} 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">
.list-bg{
background: linear-gradient(180deg, #C3DEF8 0%, #FFFFFF 37%);
}
::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: #6E7B84;
line-height: 32px;
// background-color: #FFFFFF;
// border: 1px solid #DDDDDD;
border-radius: 0px;
}
.actice {
border: 0px;
background: #387DF7;
color: #fff;
font-size: 14px;
border-radius: 4px;
}
}
.more {
float: right;
display: block;
}
/* 分页div */
.pagination-div {
text-align: center;
padding: 10px 0;
}
.order-div {
margin-top: 50px;
padding: 0 40px;
background-color: #fff;
display: flex;
.quyer-tag{
&:last-of-type{
margin-left: auto;
}
}
// justify-content: space-between;
}
.data-content {
background-color: #fff;
padding: 5px 50px;
min-height: 382px;
::v-deep .interact-bar-btns{
.interact-bar-btn{
min-width: 30px !important;
}
}
.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: 20px;
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>