|
|
@ -17,7 +17,7 @@
|
|
|
|
</p>
|
|
|
|
</p>
|
|
|
|
<p class="rate">
|
|
|
|
<p class="rate">
|
|
|
|
<label>评分:</label>
|
|
|
|
<label>评分:</label>
|
|
|
|
<el-rate :value="detailData.commentScore" disabled />
|
|
|
|
<el-rate v-model="detailData.commentScore" disabled />
|
|
|
|
</p>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<p>
|
|
|
|
<label>日期:</label>
|
|
|
|
<label>日期:</label>
|
|
|
@ -25,52 +25,172 @@
|
|
|
|
</p>
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="comment">
|
|
|
|
<div class="main">
|
|
|
|
<div>
|
|
|
|
<div class="title">
|
|
|
|
<b>评价内容</b>
|
|
|
|
<b>评价内容</b>
|
|
|
|
<el-switch inactive-text="是否显示" />
|
|
|
|
<el-switch
|
|
|
|
|
|
|
|
v-if="detailData.id"
|
|
|
|
|
|
|
|
inactive-text="是否显示"
|
|
|
|
|
|
|
|
:value="!detailData.isShow"
|
|
|
|
|
|
|
|
@click="handleShowHide(detailData)"
|
|
|
|
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div class="comment">
|
|
|
|
<p>{{ detailData.commentContent }}</p>
|
|
|
|
<p class="comment--ctx">{{ detailData.commentContent }}</p>
|
|
|
|
<div>
|
|
|
|
<div class="comment--imgs" v-if="detailData.pictureUrl">
|
|
|
|
<el-image
|
|
|
|
<el-image
|
|
|
|
style="width: 100px; height: 100px"
|
|
|
|
v-for="(item, idx) in detailData.pictureUrl"
|
|
|
|
src="https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/120x120.png"
|
|
|
|
class="img"
|
|
|
|
|
|
|
|
alt="评论"
|
|
|
|
|
|
|
|
:key="idx"
|
|
|
|
|
|
|
|
:src="item"
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<template v-if="detailData.followComment">
|
|
|
|
|
|
|
|
<b class="comment--title">
|
|
|
|
|
|
|
|
用户追评
|
|
|
|
|
|
|
|
<small>{{ detailData.followComment.createTime }}</small>
|
|
|
|
|
|
|
|
</b>
|
|
|
|
|
|
|
|
<p class="comment--ctx">{{ detailData.followComment.commentContent }}</p>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="title">
|
|
|
|
|
|
|
|
<b>全部回复({{ detailData.answerCommentList?.length || 0 }}条)</b>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<ul>
|
|
|
|
<ul class="reply" v-if="detailData.answerCommentList?.length">
|
|
|
|
<li v-for="item in detailData.answerCommentList" :key="item.id">
|
|
|
|
<li class="reply--item" v-for="item in detailData.answerCommentList" :key="item.id">
|
|
|
|
<div>
|
|
|
|
<div class="reply--title">
|
|
|
|
{{ item.userName }}
|
|
|
|
{{ item.userName }}
|
|
|
|
<span v-if="item.parentUserName">回复 {{ item.parentUserName }}:</span>
|
|
|
|
<span v-if="item.parentId !== detailData.id">回复 {{ item.parentUserName }}:</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<p>{{ item.commentContent }}</p>
|
|
|
|
<p class="reply--ctx">{{ item.commentContent }}</p>
|
|
|
|
<div>
|
|
|
|
<div class="reply--footer">
|
|
|
|
<em>{{ item.createTime }}</em>
|
|
|
|
<i>{{ item.createTime }}</i>
|
|
|
|
<span>
|
|
|
|
<span>
|
|
|
|
<em>隐藏</em>
|
|
|
|
<em @click="handleShowHide(item)" class="show-btn">
|
|
|
|
<em @click="handleReply(item)">回复</em>
|
|
|
|
<template v-if="item.isShow">
|
|
|
|
|
|
|
|
<el-icon name="Open" />
|
|
|
|
|
|
|
|
隐藏
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<template v-else>
|
|
|
|
|
|
|
|
<el-icon name="TurnOff" />
|
|
|
|
|
|
|
|
显示
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</em>
|
|
|
|
|
|
|
|
<em @click="handleReply(item)" class="reply-btn">
|
|
|
|
|
|
|
|
<el-icon name="ChatDotSquare" />
|
|
|
|
|
|
|
|
回复
|
|
|
|
|
|
|
|
</em>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
<div class="reply__emtpy" v-else>暂无内容</div>
|
|
|
|
<div class="footer">
|
|
|
|
<div class="footer">
|
|
|
|
<el-input type="textarea" maxlength="500" show-word-limit></el-input>
|
|
|
|
<textarea
|
|
|
|
<el-button>确定</el-button>
|
|
|
|
class="footer--textarea"
|
|
|
|
|
|
|
|
ref="$textarea"
|
|
|
|
|
|
|
|
maxlength="500"
|
|
|
|
|
|
|
|
v-model="state.commentContent"
|
|
|
|
|
|
|
|
:placeholder="commentPlaceholder"
|
|
|
|
|
|
|
|
@keydown="handleClearReplay"
|
|
|
|
|
|
|
|
></textarea>
|
|
|
|
|
|
|
|
<el-button type="primary" class="footer--confirm" :disabled="sbumitDisabled" @click="handleSubmit">
|
|
|
|
|
|
|
|
提交
|
|
|
|
|
|
|
|
</el-button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
<script lang="jsx" setup>
|
|
|
|
<script lang="jsx" setup>
|
|
|
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
|
|
|
import { ElMessage } from 'element-plus/es';
|
|
|
|
const store = useStore();
|
|
|
|
const store = useStore();
|
|
|
|
const router = useRouter();
|
|
|
|
const router = useRouter();
|
|
|
|
const route = useRoute();
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
|
|
|
|
|
|
const detailData = computed(() => store.state.comment.detail);
|
|
|
|
let detailData = ref({});
|
|
|
|
store.dispatch('comment/getDetail', route.params.id);
|
|
|
|
const state = reactive({
|
|
|
|
|
|
|
|
commentContent: '',
|
|
|
|
|
|
|
|
// 回复的对象
|
|
|
|
|
|
|
|
reply: {},
|
|
|
|
|
|
|
|
isSubmit: false,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
//不允许提交状态
|
|
|
|
|
|
|
|
const sbumitDisabled = computed(() => {
|
|
|
|
|
|
|
|
return !state.isSubmit && !state.commentContent;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
const commentPlaceholder = computed(() =>
|
|
|
|
|
|
|
|
state.reply.userName ? `回复 ${state.reply.userName}` : '请输入回复内容'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
const $textarea = ref(null);
|
|
|
|
|
|
|
|
|
|
|
|
const handleReply = () => {};
|
|
|
|
const getDetail = async () => {
|
|
|
|
|
|
|
|
const res = await store.dispatch('comment/getDetail', route.params.id);
|
|
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
|
|
detailData.value = _.cloneDeep(store.state.comment.detail);
|
|
|
|
|
|
|
|
if (detailData.value.pictureUrl) {
|
|
|
|
|
|
|
|
detailData.value.pictureUrl = detailData.value.pictureUrl.split(',');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
getDetail();
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 点击回复设置当前回复对象,以及输入框提示
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
const handleReply = (item) => {
|
|
|
|
|
|
|
|
state.reply = item;
|
|
|
|
|
|
|
|
$textarea.value.focus();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 清空回复人
|
|
|
|
|
|
|
|
* 输入框没内容时再按一次退格清空回复对象
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
const handleClearReplay = (target) => {
|
|
|
|
|
|
|
|
if (target.key === 'Backspace' && !state.commentContent) {
|
|
|
|
|
|
|
|
state.reply = {};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 评价/回复记录的显示隐藏
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
const handleShowHide = async (item) => {
|
|
|
|
|
|
|
|
let val = !item.isShow;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
await store.dispatch('comment/updateShow', {
|
|
|
|
|
|
|
|
idList: [item.id],
|
|
|
|
|
|
|
|
isShow: val,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
val = !val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
item.isShow = val;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 提交回复
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
|
|
|
state.isSubmit = true;
|
|
|
|
|
|
|
|
let data = {
|
|
|
|
|
|
|
|
commentContent: state.commentContent,
|
|
|
|
|
|
|
|
commentType: 3,
|
|
|
|
|
|
|
|
parentId: state.reply.id || detailData.value.id,
|
|
|
|
|
|
|
|
originId: detailData.value.id,
|
|
|
|
|
|
|
|
userId: store.state.auth.userInfo.userId,
|
|
|
|
|
|
|
|
userType: 1,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// 需要返回ID或对象 去登录用户的userName不对
|
|
|
|
|
|
|
|
const res = await store.dispatch('comment/add', data);
|
|
|
|
|
|
|
|
ElMessage.success('回复成功!');
|
|
|
|
|
|
|
|
state.isSubmit = false;
|
|
|
|
|
|
|
|
state.commentContent = '';
|
|
|
|
|
|
|
|
detailData.value.answerCommentList.push({
|
|
|
|
|
|
|
|
...res,
|
|
|
|
|
|
|
|
isShow: true,
|
|
|
|
|
|
|
|
parentUserName: state.reply.userName,
|
|
|
|
|
|
|
|
userName: store.state.auth.userInfo.userName,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
|
|
<style lang="less" scoped>
|
|
|
|
.container {
|
|
|
|
.container {
|
|
|
@ -89,7 +209,7 @@
|
|
|
|
}
|
|
|
|
}
|
|
|
|
span {
|
|
|
|
span {
|
|
|
|
color: #999;
|
|
|
|
color: #999;
|
|
|
|
font-size: 14px;
|
|
|
|
// font-size: 14px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&--ctx {
|
|
|
|
&--ctx {
|
|
|
@ -122,16 +242,109 @@
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.comment {
|
|
|
|
.main {
|
|
|
|
flex: 1;
|
|
|
|
flex: 1;
|
|
|
|
position: relative;
|
|
|
|
// position: relative;
|
|
|
|
|
|
|
|
padding: 20px 30px;
|
|
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
|
|
|
border-bottom: 1px solid #eee;
|
|
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.comment {
|
|
|
|
|
|
|
|
margin: 30px 0;
|
|
|
|
|
|
|
|
&--ctx {
|
|
|
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
|
|
|
// text-indent: 28px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--title {
|
|
|
|
|
|
|
|
font-weight: normal;
|
|
|
|
|
|
|
|
color: var(--el-color-danger);
|
|
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
|
|
margin: 30px 0 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--imgs {
|
|
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
|
|
.img {
|
|
|
|
|
|
|
|
border: 1px solid #eee;
|
|
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.reply {
|
|
|
|
|
|
|
|
border-bottom: 1px solid #eee;
|
|
|
|
|
|
|
|
padding-bottom: 130px;
|
|
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
|
|
&__emtpy {
|
|
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
|
|
height: 100px;
|
|
|
|
|
|
|
|
line-height: 100px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--item {
|
|
|
|
|
|
|
|
border-bottom: 1px solid #eee;
|
|
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--title {
|
|
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
margin: 5px 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--ctx {
|
|
|
|
|
|
|
|
line-height: 24px;
|
|
|
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--footer {
|
|
|
|
|
|
|
|
margin: 5px 0;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
span {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
em,
|
|
|
|
|
|
|
|
i {
|
|
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
font-style: normal;
|
|
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
em {
|
|
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
margin-left: 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
.footer {
|
|
|
|
.footer {
|
|
|
|
position: absolute;
|
|
|
|
position: absolute;
|
|
|
|
bottom: 0;
|
|
|
|
bottom: 0;
|
|
|
|
left: 0;
|
|
|
|
left: 240px;
|
|
|
|
right: 0;
|
|
|
|
right: 0;
|
|
|
|
padding: 20px;
|
|
|
|
padding: 20px 30px;
|
|
|
|
text-align: right;
|
|
|
|
text-align: right;
|
|
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
|
|
border-top: 1px solid #eee;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
&--textarea {
|
|
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
|
|
resize: none;
|
|
|
|
|
|
|
|
border: 1px solid #eee;
|
|
|
|
|
|
|
|
&:focus {
|
|
|
|
|
|
|
|
border: 1px solid var(--el-color-primary);
|
|
|
|
|
|
|
|
outline: none !important;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
&--confirm {
|
|
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</style>
|
|
|
|