tijiao
This commit is contained in:
19
uni_modules/hb-comment/changelog.md
Normal file
19
uni_modules/hb-comment/changelog.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 1.2.2(2022-01-24)
|
||||
* 去除示例项目中对uView的依赖,精简示例项目代码
|
||||
* 修复bug
|
||||
## 1.2.1(2022-01-24)
|
||||
* 更新图标,由svg变为png,解决在App中图标不显示,且影响页面排版的问题
|
||||
## 1.2.0(2021-11-18)
|
||||
* 不再依赖uview,与1.1.4相比展开样式有调整,其他完全一致
|
||||
## 1.1.4(2021-07-22)
|
||||
* 降低弹出键盘的延时,显著提升流畅感
|
||||
## 1.1.3(2021-07-22)
|
||||
* 修改发布输入框,从原来的放在页面最底下改为弹出式
|
||||
## 1.1.2(2021-07-21)
|
||||
* 输入框聚焦前滚动到页面底部
|
||||
## 1.1.1(2021-07-21)
|
||||
* 修复了微信小程序中点赞删除等操作失败的问题
|
||||
## 1.1.0(2021-07-20)
|
||||
* 分离插件与接口逻辑
|
||||
* 支持uni-modules,更方便升级等
|
||||
* 修复一些问题
|
||||
746
uni_modules/hb-comment/components/hb-comment/hb-comment.vue
Normal file
746
uni_modules/hb-comment/components/hb-comment/hb-comment.vue
Normal file
@@ -0,0 +1,746 @@
|
||||
<template>
|
||||
<view class="hb-comment">
|
||||
<!-- 阅读数-start -->
|
||||
|
||||
<!-- 阅读数-end -->
|
||||
<!-- 阅读数下边那条线-start -->
|
||||
<!-- <view class="seg_line_box">
|
||||
<view class="seg_line"></view>
|
||||
<view class="seg_dot"></view>
|
||||
<view class="seg_line"></view>
|
||||
</view> -->
|
||||
<!-- 阅读数下边那条线-end -->
|
||||
<!-- 评论主体-start -->
|
||||
<view class="comment-list" v-if="commentData.comment.length != 0">
|
||||
<!-- 评论主体-顶部数量及发表评论按钮-start -->
|
||||
<view class="comment-num">
|
||||
<view>共 {{ commentData.commentSize }} 条评论</view>
|
||||
<view class="add-btn">
|
||||
<button type="primary" size="mini" @click="commentInput">
|
||||
发表评论
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 评论主体-顶部数量及发表评论按钮-end -->
|
||||
<!-- 评论列表-start -->
|
||||
<view class="comment-box" v-for="(item, index) in commentData.comment">
|
||||
<view class="comment-box-item">
|
||||
<view>
|
||||
<image
|
||||
:src="item.avatarUrl || emptyAvatar"
|
||||
mode="aspectFill"
|
||||
class="avatar"
|
||||
></image>
|
||||
</view>
|
||||
<view class="comment-main">
|
||||
<!-- 父评论体-start -->
|
||||
<view class="comment-main-top">
|
||||
<view class="nick-name-box">
|
||||
<view class="comLogo com1" v-if="index == 0">沙发</view>
|
||||
<view class="comLogo com2" v-if="index == 1">板凳</view>
|
||||
<view class="comLogo com3" v-if="index == 2">地板</view>
|
||||
<view class="comLogo com4" v-if="index > 2"
|
||||
>{{ index + 1 }}楼</view
|
||||
>
|
||||
<view class="nick-name">{{ item.nickName }}</view>
|
||||
</view>
|
||||
<view class="zan-box" @click="like(item.id)">
|
||||
<span :class="item.hasLike ? 'isLike' : 'notLike'">{{
|
||||
item.likeNum == 0 ? "抢首赞" : item.likeNum
|
||||
}}</span>
|
||||
<img
|
||||
style="width: 14px; height: 14px"
|
||||
v-if="!item.hasLike"
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAApVJREFUWEfFlz9oFEEUxr93SWEhFkIaBUljo4WgATEaiI0GwVLBQg2EzLd3hSBqLI2lRgWLY+ftSSQgggoWNv5pImLUwjQBg1goqCCIIBqwueSeTLg7Ln9Mcmdub7vdnZnvN9+8fe+toMWXtFgfDQGMjo52zM7OHgMwIyLTg4ODk41upG4A7/0OEbkPYGdFVEQuOOeuNQJRN4CqBvGw+3dm9kZEBsrCPSRf1gvRCIAFETPrjqLodZIkY2Z2SkQmnHMHUgMgOQ8fx3FvJpMZB/CDZEfqACEgi8XidwA/SW5uKkCN2AzJTYscmCTZ1VQA7/2AiNwSkefOuYNBLEmSnJnlATwgebypAKr6CMBRANdJng9i3vu8iORE5Mrc3NyTlQDM7HMul/tYO2bNX0GhUDhRKpXumtlvAPuiKJouOzBuZr117HyBU6sCqOpeAH0AhssiwyQvVwTjOO5va2s7vRaAGtCrJC+GOVUAVb1UTjDVDLd4URHJOuf8WsSWG5MkSbeZTYR3lc+4CpAkyUpWht3fI/m+UfEwL5/Pb2xvb59ZFkBV5zNchazsSBBeYPn/ABQKhZ5SqfQCwBTJXYuPoOkAqnoGwE0Ad0ieTB3Ae39bRPoBDJEcSR1AVd8C2CMifc65p6kCmJkkSfIHwAYAW0h+SxVAVXcDmDSzL1EUbasEc20eaGoQVuoIgMckj6QOoKo3AJwFMEJyqBUAIegOAegnOdYKgK8AtmYyma7aLjqVGPDebxeRDwB+AeggWUzVAVV1ABTAK5L7l+0HVPUTgM7Q7VQGhPJZe99oHagpw4dJPvsXQPixONeoyErzRGTKzB7W9hFLjiA8iOO4M7iw3hDZbLbq6pIeY73F6l1v1Zas3gXrHf8XhhNvMGSmtPYAAAAASUVORK5CYII="
|
||||
/>
|
||||
<img
|
||||
style="width: 14px; height: 14px"
|
||||
v-else
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAfVJREFUWEfFl79LHEEUx7/vclr4g51TLFQQW9FNDFhFBDvjtcF0gXSp5eYuWJlUAW9NIP9BIFUEOxFtTKF2FrezKFgkkEBS3h4SAtHbJ6vu5W5d1F3cm20WZt+b7+e9mTfzlqD5Ic36SATw+OPJQP2ft+ABJwQ+VFIcJA0kEYBpVfcAehKIMqHoFISVBCI2wOS76mi9g76HxTLwZiqybzcuRGwAc7WWB/NGWIhBu440ZlIHmFitLRPzm+tC9EtJY1gjAP9VMtelEQC2kuJR6gCm5X4BsBAWImDdluJZqgBjH/4MZr3TYzB6IoRWmHnzJgDK0g+1KL4128SqgnD9x432yn5NSfE88L0VYPx9rS/jYR6EJTCPJxQNu60oKV77gw2Ai/Ly1/ZKRElx8c20XL4n0ZZpgvkbAKbl7gCYDax0ALREmjJAo2SbM9A+AKLPqmC8aNkD4bVOMwPEKNlFUdYGkAE9rUhjSxvA2YOOoaPF7t+6AH4qKUauHURt3AObSoq8NgAGyo4UJW0ABH5py9wnbQAAppq76HYfRLXOXmPg4BWdasoA7yuZm47sB0zL9Vvt0TQvI/bqc06pfzsS4KHlWgwUUgKwmWjdKRhvI1q5/0P+T8dZ9jILTjH31X9PlKuNKzppXxDMFeV/a0eUVPSuftoBzgHKR/ohZwAugwAAAABJRU5ErkJggg=="
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="comment-main-content">
|
||||
{{
|
||||
item.content.length > 60
|
||||
? item.content.slice(0, 59)
|
||||
: item.content
|
||||
}}
|
||||
<span v-if="item.content.length > 60">
|
||||
{{ item.hasShowMore ? item.content.slice(59) : "..." }}
|
||||
<span class="foot-btn" @click="showMore(item.id)">
|
||||
{{ item.hasShowMore ? "收起" : "展开" }}
|
||||
</span>
|
||||
</span>
|
||||
</view>
|
||||
<view class="comment-main-foot">
|
||||
<view class="foot-time">{{ item.createTime }}</view>
|
||||
<view
|
||||
class="foot-btn"
|
||||
@click="reply(item.nickName, item.nickName, item.id)"
|
||||
>回复</view
|
||||
>
|
||||
<view
|
||||
class="foot-btn"
|
||||
v-if="item.owner"
|
||||
@click="confirmDelete(item.id)"
|
||||
>删除</view
|
||||
>
|
||||
</view>
|
||||
<!-- 父评论体-end -->
|
||||
<!-- 子评论列表-start -->
|
||||
<view class="comment-sub-box">
|
||||
<view class="comment-sub-item" v-for="each in item.children">
|
||||
<view>
|
||||
<image
|
||||
:src="each.avatarUrl || emptyAvatar"
|
||||
mode="aspectFill"
|
||||
class="avatar"
|
||||
>
|
||||
</image>
|
||||
</view>
|
||||
<view class="comment-main">
|
||||
<view class="sub-comment-main-top">
|
||||
<view class="nick-name">{{ each.nickName }}</view>
|
||||
<view class="zan-box" @click="like(each.id)">
|
||||
<span :class="each.hasLike ? 'isLike' : 'notLike'">{{
|
||||
each.likeNum == 0 ? "抢首赞" : each.likeNum
|
||||
}}</span>
|
||||
<img
|
||||
style="width: 14px; height: 14px"
|
||||
v-if="!each.hasLike"
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAApVJREFUWEfFlz9oFEEUxr93SWEhFkIaBUljo4WgATEaiI0GwVLBQg2EzLd3hSBqLI2lRgWLY+ftSSQgggoWNv5pImLUwjQBg1goqCCIIBqwueSeTLg7Ln9Mcmdub7vdnZnvN9+8fe+toMWXtFgfDQGMjo52zM7OHgMwIyLTg4ODk41upG4A7/0OEbkPYGdFVEQuOOeuNQJRN4CqBvGw+3dm9kZEBsrCPSRf1gvRCIAFETPrjqLodZIkY2Z2SkQmnHMHUgMgOQ8fx3FvJpMZB/CDZEfqACEgi8XidwA/SW5uKkCN2AzJTYscmCTZ1VQA7/2AiNwSkefOuYNBLEmSnJnlATwgebypAKr6CMBRANdJng9i3vu8iORE5Mrc3NyTlQDM7HMul/tYO2bNX0GhUDhRKpXumtlvAPuiKJouOzBuZr117HyBU6sCqOpeAH0AhssiwyQvVwTjOO5va2s7vRaAGtCrJC+GOVUAVb1UTjDVDLd4URHJOuf8WsSWG5MkSbeZTYR3lc+4CpAkyUpWht3fI/m+UfEwL5/Pb2xvb59ZFkBV5zNchazsSBBeYPn/ABQKhZ5SqfQCwBTJXYuPoOkAqnoGwE0Ad0ieTB3Ae39bRPoBDJEcSR1AVd8C2CMifc65p6kCmJkkSfIHwAYAW0h+SxVAVXcDmDSzL1EUbasEc20eaGoQVuoIgMckj6QOoKo3AJwFMEJyqBUAIegOAegnOdYKgK8AtmYyma7aLjqVGPDebxeRDwB+AeggWUzVAVV1ABTAK5L7l+0HVPUTgM7Q7VQGhPJZe99oHagpw4dJPvsXQPixONeoyErzRGTKzB7W9hFLjiA8iOO4M7iw3hDZbLbq6pIeY73F6l1v1Zas3gXrHf8XhhNvMGSmtPYAAAAASUVORK5CYII="
|
||||
/>
|
||||
<img
|
||||
style="width: 14px; height: 14px"
|
||||
v-else
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAfVJREFUWEfFl79LHEEUx7/vclr4g51TLFQQW9FNDFhFBDvjtcF0gXSp5eYuWJlUAW9NIP9BIFUEOxFtTKF2FrezKFgkkEBS3h4SAtHbJ6vu5W5d1F3cm20WZt+b7+e9mTfzlqD5Ic36SATw+OPJQP2ft+ABJwQ+VFIcJA0kEYBpVfcAehKIMqHoFISVBCI2wOS76mi9g76HxTLwZiqybzcuRGwAc7WWB/NGWIhBu440ZlIHmFitLRPzm+tC9EtJY1gjAP9VMtelEQC2kuJR6gCm5X4BsBAWImDdluJZqgBjH/4MZr3TYzB6IoRWmHnzJgDK0g+1KL4128SqgnD9x432yn5NSfE88L0VYPx9rS/jYR6EJTCPJxQNu60oKV77gw2Ai/Ly1/ZKRElx8c20XL4n0ZZpgvkbAKbl7gCYDax0ALREmjJAo2SbM9A+AKLPqmC8aNkD4bVOMwPEKNlFUdYGkAE9rUhjSxvA2YOOoaPF7t+6AH4qKUauHURt3AObSoq8NgAGyo4UJW0ABH5py9wnbQAAppq76HYfRLXOXmPg4BWdasoA7yuZm47sB0zL9Vvt0TQvI/bqc06pfzsS4KHlWgwUUgKwmWjdKRhvI1q5/0P+T8dZ9jILTjH31X9PlKuNKzppXxDMFeV/a0eUVPSuftoBzgHKR/ohZwAugwAAAABJRU5ErkJggg=="
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="comment-main-content">
|
||||
{{
|
||||
each.content.length > 60
|
||||
? each.content.slice(0, 59)
|
||||
: each.content
|
||||
}}
|
||||
<span v-if="each.content.length > 60">
|
||||
{{ each.hasShowMore ? each.content.slice(59) : "..." }}
|
||||
<span class="foot-btn" @click="showMore(each.id)">
|
||||
{{ each.hasShowMore ? "收起" : "展开" }}
|
||||
</span>
|
||||
</span>
|
||||
</view>
|
||||
<view class="comment-main-foot">
|
||||
<view class="foot-time">{{ each.createTime }}</view>
|
||||
<view
|
||||
class="foot-btn"
|
||||
@click="reply(item.nickName, each.nickName, item.id)"
|
||||
>
|
||||
回复</view
|
||||
>
|
||||
<view
|
||||
class="foot-btn"
|
||||
v-if="each.owner"
|
||||
@click="confirmDelete(each.id)"
|
||||
>删除
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 子评论列表-end -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 评论列表-end -->
|
||||
</view>
|
||||
<!-- 评论主体-end -->
|
||||
<!-- 无评论-start -->
|
||||
<view class="comment-none" v-else>
|
||||
|
||||
<image
|
||||
:src="user.icon ? user.icon : '/static/images/avatar.png'"
|
||||
style="
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin: 0 10rpx;
|
||||
display: block;
|
||||
border-radius: 80rpx;
|
||||
"
|
||||
/>
|
||||
<button
|
||||
class="comment-btn"
|
||||
@click="showInput = true"
|
||||
v-if="!showInput"
|
||||
>
|
||||
写评论
|
||||
</button>
|
||||
<!-- background-color: #dadada59; -->
|
||||
<!-- <view style="width: calc(100% - 120rpx);margin-right: 20rpx;position: relative;padding:20rpx 20rpx;border-radius: 10rpx;">
|
||||
<view v-if="currentInputComment" style="position: absolute;top: 10rpx;"><text @click="currentInputComment=''">清空</text><text @click="sendComment">发送</text></view>
|
||||
<textarea style="font-size: 26rpx;width: calc(100%);color: #333;"
|
||||
v-model="currentInputComment"
|
||||
|
||||
auto-height
|
||||
clear
|
||||
maxlength="-1"
|
||||
placeholder="写评论..."
|
||||
placeholder-class=""
|
||||
/>
|
||||
|
||||
</view> -->
|
||||
<view
|
||||
class="input-container"
|
||||
:style="{ bottom: keyboardHeight + 'px' }"
|
||||
v-if="showInput"
|
||||
>
|
||||
<input
|
||||
v-model="commentContent"
|
||||
class="comment-input"
|
||||
placeholder="请输入评论..."
|
||||
@focus="onInputFocus"
|
||||
@blur="onInputBlur"
|
||||
:auto-focus="showInput"
|
||||
/>
|
||||
<button class="send-btn" @click="sendComment">发送</button>
|
||||
</view>
|
||||
|
||||
<!-- 暂无评论,<span @click="commentInput" style="color: #007AFF;">立即评论</span> -->
|
||||
</view>
|
||||
<!-- 无评论-end -->
|
||||
<!-- 新增评论-start -->
|
||||
<view class="comment-submit-box" v-if="submit" @click="closeInput">
|
||||
<!-- 下边的click.stop.prevent用于让上边的click不传下去,以防点到下边的空白处触发closeInput方法 -->
|
||||
<view
|
||||
class="comment-add"
|
||||
@click.stop.prevent="stopPrevent"
|
||||
:style="'bottom:' + KeyboardHeight + 'px'"
|
||||
>
|
||||
<view class="comment-submit">
|
||||
<view class="btn-click cancel" @click="closeInput">取消</view>
|
||||
<view>
|
||||
<view class="replayTag" v-show="showTag">
|
||||
<view>回复在 {{ pUser }} 的评论下</view>
|
||||
<view @click="tagClose" class="replyTagClose">×</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="btn-click" @click="add">发布</view>
|
||||
</view>
|
||||
</view>
|
||||
<textarea
|
||||
class="textarea"
|
||||
v-model="commentReq.content"
|
||||
:placeholder="placeholder"
|
||||
:adjust-position="false"
|
||||
:show-confirm-bar="false"
|
||||
@blur="blur"
|
||||
@focus="focusOn"
|
||||
:focus="focus"
|
||||
maxlength="800"
|
||||
></textarea>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 新增评论-end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import text from 'uview-ui/libs/config/props/text';
|
||||
|
||||
export default {
|
||||
name: "hb-comment",
|
||||
props: {
|
||||
cmData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
deleteTip: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return "操作不可逆,如果评论下有子评论,也将被一并删除,确认?";
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
cmData: {
|
||||
handler: function (newVal, oldVal) {
|
||||
this.init(newVal);
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showInput: false, // 是否显示输入框
|
||||
commentContent: '', // 评论内容
|
||||
keyboardHeight: 0, // 软键盘高度
|
||||
keyboardListener: null, // 软键盘监听事件
|
||||
currentInputComment:'',
|
||||
emptyAvatar:
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABF5JREFUWEfFl11oHFUUx//nbmKwxdJ9qFL7YPEhRJC2gljjF60WG0WsoNkWfSnZ7Jy7FVPF0AoKpmBFqyIG3Jk7G1iIQXHbBz+KbbGtRfBbMe2LseKjiVDoiqIhwZ0jV3fb3cnM7kQCuU+7M+ec/+9+nHPPEJZ50DLrY1EApVJp9fz8/BYRuZ2INgDYWJvAWRE5R0RnZmZmPh4ZGZlPOrFEAMVi8e4gCPYSUZ+IXGGFgiCYIaJpKyQi1yql1orIFgAXARxRSvm5XO67diBtAYwxRQCDAE4RUUkpdWxwcNCKLBiu665TSj0kIpqIbgTgMzO3gmgJYIz5CMB9AIaZ+bXGQMVi8RoRuZeI/lZKHc1ms3/U34+Pj6+cnZ3dC+AggGPMfH8cRCyAMUZqThlmPlwPUCgU0qlUyq7Kww1BrbjHzPsahYwx/QDK9hkzR2pFPjTGnAWwIexkjOkRkRIR3Rozo5Miskdr/VMIxE7mHDPXD+2l1wsA6nseBMHmfD7/dSjQOwB2tTlYC/bddd1blFJfARhj5lyjfxNA7bSfitpz3/d3iYgFaDuUUjeHM8AY8zSAV5VS9+RyudP1IE0Axpj3Aaxk5m1hFc/zPiWiO9uq/2dwiJn3h22NMScB/MnMOxYAjI6Orurq6rpgU0hrXYpw/hFAd0KAD5n5wbCt7/t7ROT1ubm5NUNDQ7/b95dWwHXd7Uqp452dnVcPDAxciACwDlclAbAFynGcdRGr2EtEnwdB0JfP5080ARhjDhLRbY7jbI0SMcZUAKxOAgDgN2ZOx8SxGfEiMz/bBOD7/lgQBCu01o/GOH4PYFNCgElmvinK1vf9X2xxchzHVtfLW2CMOQpgipmHYwBeBtBUaOJgRKSgtX48Js63AH5l5geaADzPe1cpddFxnHyM42YAXyZYAXt+epn557iVFJHzWuudYYDnlFJ9juPcESfi+35JRHa3gdjPzIfibIwxNtPe0Fq/EAZ4hIhcZl4T5+y67nql1CcA1kfZENFnrSZQ6ycqItKvtT4SBthIRJMdHR092WzW5nzk8H1/WEReiQHY4TjOB3G+nuf9qyEim7TW9r65fAjL5fKVlUrlPICXmPnNFquwWym1oFBZ+yAItubz+TMtAJ4gon3pdLo7k8nMNgHYP7ZeE5EWkbuYeaYx0NjY2HXValUDeApAV4zIJIADzPxe+H2hULg+lUp9U6sBl3qLprugXC6nKpXKF0R02nGcZ2wQ3/e3ichOEckQ0aoEWQDbsgF4a3p6eqLeH3qeN0FE3el0ujeTyVTrcaKuY1uIjIg8CaCfiLYnEW1hY4WPi8gEgMeY+e1G27iGxHYxtptZynGYmTPhgK1asqWEiBRfcAjDdMaYpYCIFW8LUMuM54nIsb3/YvbDXskiYtuzA6382n4X1CDWAnCSgNSFa98ETakcWbwWMytjzAoAPUEQ3JBKpXrs75r/VLVanVJK/VC7Uf9KGjfRCiQN9n/slh3gHz9i4jC+FVL5AAAAAElFTkSuQmCC",
|
||||
commentData: null,
|
||||
placeholder: "请输入评论",
|
||||
commentReq: {
|
||||
pId: null, // 评论父id
|
||||
content: null, // 评论内容
|
||||
},
|
||||
pUser: null, // 标签-回复人
|
||||
showTag: false, // 标签展示与否
|
||||
focus: false, // 输入框自动聚焦
|
||||
submit: false, // 弹出评论
|
||||
KeyboardHeight: 0, // 键盘高度
|
||||
};
|
||||
},
|
||||
mounted: function () {
|
||||
this.keyboardListener = uni.onKeyboardHeightChange(res => {
|
||||
this.keyboardHeight = res.height;
|
||||
});
|
||||
uni.onKeyboardHeightChange((res) => {
|
||||
this.KeyboardHeight = res.height;
|
||||
});
|
||||
},
|
||||
onUnload() {
|
||||
// 移除监听
|
||||
if (this.keyboardListener) {
|
||||
uni.offKeyboardHeightChange(this.keyboardListener);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInputFocus() {
|
||||
// 可以在这里添加额外的逻辑,如滚动到输入框位置
|
||||
},
|
||||
|
||||
// 输入框失去焦点
|
||||
onInputBlur() {
|
||||
// 如果输入框为空,点击空白处关闭输入框
|
||||
if (!this.commentContent.trim()) {
|
||||
this.showInput = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 发送评论
|
||||
sendComment() {
|
||||
if (this.commentContent.trim()) {
|
||||
// 这里添加发送评论的逻辑
|
||||
console.log('发送评论:', this.commentContent);
|
||||
|
||||
// 发送成功后清空并隐藏输入框
|
||||
this.commentContent = '';
|
||||
this.showInput = false;
|
||||
}
|
||||
},
|
||||
// 初始化评论
|
||||
init(cmData) {
|
||||
// for (var i in cmData.comment) {
|
||||
// cmData.comment[i].hasShowMore = false;
|
||||
// for (var j in cmData.comment[i].children) {
|
||||
// cmData.comment[i].children[j].hasShowMore = false;
|
||||
// }
|
||||
// }
|
||||
this.commentData = cmData;
|
||||
},
|
||||
// 没用的方法,但不要删
|
||||
stopPrevent() {},
|
||||
// 回复评论
|
||||
reply(pUser, reUser, pId) {
|
||||
this.pUser = pUser;
|
||||
this.commentReq.pId = pId;
|
||||
if (reUser) {
|
||||
this.commentReq.content = "@" + reUser + " ";
|
||||
} else {
|
||||
this.commentReq.content = "";
|
||||
}
|
||||
this.showTag = true;
|
||||
this.commentInput();
|
||||
},
|
||||
// 删除评论前确认
|
||||
confirmDelete(commentId) {
|
||||
var that = this;
|
||||
uni.showModal({
|
||||
title: "警告",
|
||||
content: that.deleteTip,
|
||||
confirmText: "确认删除",
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
that.$emit("del", commentId);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
// 新增评论
|
||||
add() {
|
||||
if (
|
||||
this.commentReq.content == null ||
|
||||
this.commentReq.content.length < 2
|
||||
) {
|
||||
uni.showToast({
|
||||
title: "评论内容过短",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.$emit("add", this.commentReq);
|
||||
},
|
||||
// 点赞评论
|
||||
like(commentId) {
|
||||
this.$emit("like", commentId);
|
||||
},
|
||||
// 新增完成
|
||||
addComplete() {
|
||||
this.commentReq.content = null;
|
||||
this.tagClose();
|
||||
this.closeInput();
|
||||
},
|
||||
// 点赞完成-本地修改点赞结果
|
||||
likeComplete(commentId) {
|
||||
for (var i in this.commentData.comment) {
|
||||
if (this.commentData.comment[i].id == commentId) {
|
||||
this.commentData.comment[i].hasLike
|
||||
? this.commentData.comment[i].likeNum--
|
||||
: this.commentData.comment[i].likeNum++;
|
||||
this.commentData.comment[i].hasLike =
|
||||
!this.commentData.comment[i].hasLike;
|
||||
return;
|
||||
}
|
||||
for (var j in this.commentData.comment[i].children) {
|
||||
if (this.commentData.comment[i].children[j].id == commentId) {
|
||||
this.commentData.comment[i].children[j].hasLike
|
||||
? this.commentData.comment[i].children[j].likeNum--
|
||||
: this.commentData.comment[i].children[j].likeNum++;
|
||||
this.commentData.comment[i].children[j].hasLike =
|
||||
!this.commentData.comment[i].children[j].hasLike;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 删除完成-本地删除评论
|
||||
deleteComplete(commentId) {
|
||||
for (var i in this.commentData.comment) {
|
||||
for (var j in this.commentData.comment[i].children) {
|
||||
if (this.commentData.comment[i].children[j].id == commentId) {
|
||||
this.commentData.comment[i].children.splice(Number(j), 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.commentData.comment[i].id == commentId) {
|
||||
this.commentData.comment.splice(Number(i), 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
// 展开评论
|
||||
showMore(commentId) {
|
||||
for (var i in this.commentData.comment) {
|
||||
if (this.commentData.comment[i].id == commentId) {
|
||||
this.commentData.comment[i].hasShowMore =
|
||||
!this.commentData.comment[i].hasShowMore;
|
||||
this.$forceUpdate();
|
||||
return;
|
||||
}
|
||||
for (var j in this.commentData.comment[i].children) {
|
||||
if (this.commentData.comment[i].children[j].id == commentId) {
|
||||
this.commentData.comment[i].children[j].hasShowMore =
|
||||
!this.commentData.comment[i].children[j].hasShowMore;
|
||||
this.$forceUpdate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 输入框失去焦点
|
||||
blur() {
|
||||
this.focus = false;
|
||||
},
|
||||
// 输入框聚焦
|
||||
focusOn() {
|
||||
this.$emit("focusOn");
|
||||
},
|
||||
// 标签关闭
|
||||
tagClose() {
|
||||
this.showTag = false;
|
||||
this.pUser = null;
|
||||
this.commentReq.pId = null;
|
||||
},
|
||||
// 输入评论
|
||||
commentInput() {
|
||||
// TODO 调起键盘方法
|
||||
this.submit = true;
|
||||
setTimeout(() => {
|
||||
this.focus = true;
|
||||
}, 50);
|
||||
},
|
||||
// 关闭输入评论
|
||||
closeInput() {
|
||||
this.focus = false;
|
||||
this.submit = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hb-comment {
|
||||
// padding: 10rpx;
|
||||
}
|
||||
|
||||
.top-read {
|
||||
font-size: 28rpx;
|
||||
padding-left: 10rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.seg_line_box {
|
||||
display: flex;
|
||||
height: 5rpx;
|
||||
justify-content: space-between;
|
||||
margin: 5rpx 0;
|
||||
}
|
||||
|
||||
.seg_line {
|
||||
width: 45%;
|
||||
border-bottom: 1rpx solid #e1e1e1;
|
||||
}
|
||||
|
||||
.seg_dot {
|
||||
width: 8%;
|
||||
border-bottom: 5rpx dotted #dbdbdb;
|
||||
}
|
||||
|
||||
.comment-num {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.comment-box {
|
||||
padding: 10rpx 0;
|
||||
}
|
||||
|
||||
.comment-box-item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.comment-main {
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
.comment-main-top {
|
||||
width: 600rpx;
|
||||
padding-top: 6rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.sub-comment-main-top {
|
||||
width: 510rpx;
|
||||
padding-top: 6rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.nick-name-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.comLogo {
|
||||
margin-right: 18rpx;
|
||||
font-size: 22rpx;
|
||||
border-radius: 10rpx;
|
||||
padding: 5rpx 15rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.com1 {
|
||||
background-color: #d218b1;
|
||||
}
|
||||
|
||||
.com2 {
|
||||
background-color: #f19c0b;
|
||||
}
|
||||
|
||||
.com3 {
|
||||
background-color: #c8da85;
|
||||
}
|
||||
|
||||
.com4 {
|
||||
background-color: #bfd0da;
|
||||
}
|
||||
|
||||
.nick-name {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
|
||||
.isLike {
|
||||
font-size: 28rpx;
|
||||
padding-right: 10rpx;
|
||||
color: #2d8cf0;
|
||||
}
|
||||
|
||||
.notLike {
|
||||
font-size: 28rpx;
|
||||
padding-right: 10rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.comment-main-content {
|
||||
padding: 10rpx 10rpx 10rpx 0;
|
||||
}
|
||||
|
||||
.comment-main-foot {
|
||||
display: flex;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.replayTag {
|
||||
color: #909399;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #c8c9cc;
|
||||
background-color: #f4f4f5;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 16rpx;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.replyTagClose {
|
||||
font-size: 20px;
|
||||
line-height: 12px;
|
||||
padding: 0 0 2px 5px;
|
||||
}
|
||||
|
||||
.foot-btn {
|
||||
padding-left: 10rpx;
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.comment-sub-box {
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.comment-sub-item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.comment-none {
|
||||
padding: 20rpx 0;
|
||||
width: 100%;
|
||||
// text-align: center;
|
||||
color: #999999;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.comment-submit-box {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
z-index: 9900;
|
||||
left: 0;
|
||||
top: var(--window-top);
|
||||
bottom: 0;
|
||||
background-color: rgba($color: #000000, $alpha: 0.5);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comment-add {
|
||||
position: fixed;
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
padding: 5rpx;
|
||||
border: 1px solid #ddd;
|
||||
transition: 0.3s;
|
||||
-webkit-transition: 0.3s;
|
||||
}
|
||||
|
||||
.btn-click {
|
||||
color: #007aff;
|
||||
font-size: 28rpx;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
height: 100px;
|
||||
padding: 16rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comment-submit {
|
||||
padding: 5rpx 0rpx 0 0rpx;
|
||||
border-bottom: 1px dashed #ddd;
|
||||
width: calc(100%);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.comment-btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 20px;
|
||||
text-align: left;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #eee;
|
||||
box-sizing: border-box;
|
||||
transition: bottom 0.3s ease;
|
||||
}
|
||||
|
||||
.comment-input {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
padding: 0 15px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
width: 60px;
|
||||
height: 40px;
|
||||
margin-left: 10px;
|
||||
background-color: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
}
|
||||
</style>
|
||||
83
uni_modules/hb-comment/package.json
Normal file
83
uni_modules/hb-comment/package.json
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "hb-comment",
|
||||
"displayName": "评论列表,回复,点赞,删除,留言板",
|
||||
"version": "1.2.2",
|
||||
"description": "评论列表,回复,点赞,删除,留言板",
|
||||
"keywords": [
|
||||
"评论列表",
|
||||
"评论回复",
|
||||
"评论点赞",
|
||||
"评论删除",
|
||||
"留言板"
|
||||
],
|
||||
"repository": "https://github.com/dr34-m/hb-comment",
|
||||
"engines": {
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
261
uni_modules/hb-comment/readme.md
Normal file
261
uni_modules/hb-comment/readme.md
Normal file
@@ -0,0 +1,261 @@
|
||||
## 接口使用,包括点赞回复评论删除逻辑,建议参考示例项目进行二次封装;
|
||||
|
||||
## 本插件设计之初就是为小型项目设计,不支持分页,评论只有两级。如需改为多级或者需要支持分页,需要进行相当程度的改造。
|
||||
|
||||
直接使用
|
||||
|
||||
```html
|
||||
<hb-comment ref="hbComment" @add="add" @del="del" @like="like" @focusOn="focusOn" :deleteTip="'确认删除?'"
|
||||
:cmData="commentData" v-if="commentData"></hb-comment>
|
||||
```
|
||||
|
||||
后端返回数据格式(给到前端后前端整合成树):
|
||||
|
||||
```js
|
||||
{
|
||||
"readNumer": 193,
|
||||
"commentList": [{
|
||||
"id": 1, // 唯一主键
|
||||
"owner": false, // 是否是拥有者,为true则可以删除,管理员全部为true
|
||||
"hasLike": false, // 是否点赞
|
||||
"likeNum": 2, // 点赞数量
|
||||
"avatarUrl": "https://inews.gtimg.com/newsapp_ls/0/13797755537/0", // 评论者头像地址
|
||||
"nickName": "超长昵称超长...", // 评论者昵称,昵称过长请在后端截断
|
||||
"content": "啦啦啦啦", // 评论内容
|
||||
"parentId": null, // 所属评论的唯一主键
|
||||
"createTime": "2021-07-02 16:32:07" // 创建时间
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"owner": false,
|
||||
"hasLike": false,
|
||||
"likeNum": 2,
|
||||
"avatarUrl": "https://inews.gtimg.com/newsapp_ls/0/13797761970/0",
|
||||
"nickName": "寂寞无敌",
|
||||
"content": "我是评论的评论",
|
||||
"parentId": 1,
|
||||
"createTime": "2021-07-02 17:05:50"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"owner": true,
|
||||
"hasLike": true,
|
||||
"likeNum": 1,
|
||||
"avatarUrl": "https://inews.gtimg.com/newsapp_ls/0/13797763270/0",
|
||||
"nickName": "name111",
|
||||
"content": "评论啦啦啦啦啦啦啦啦啦啦",
|
||||
"parentId": null,
|
||||
"createTime": "2021-07-13 09:37:50"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"owner": false,
|
||||
"hasLike": false,
|
||||
"likeNum": 0,
|
||||
"avatarUrl": "https://inews.gtimg.com/newsapp_ls/0/13797755537/0",
|
||||
"nickName": "超长昵称超长...",
|
||||
"content": "超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论超长评论",
|
||||
"parentId": null,
|
||||
"createTime": "2021-07-13 16:04:35"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"owner": false,
|
||||
"hasLike": false,
|
||||
"likeNum": 0,
|
||||
"avatarUrl": "https://inews.gtimg.com/newsapp_ls/0/13797755537/0",
|
||||
"nickName": "超长昵称超长...",
|
||||
"content": "@寂寞无敌 你怕不是个大聪明",
|
||||
"parentId": 1,
|
||||
"createTime": "2021-07-14 11:01:23"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
假设后端返回数据为`res`,则`commentData`可以这样得到
|
||||
|
||||
```js
|
||||
this.commentData = {
|
||||
"readNumer": res.readNumer,
|
||||
"commentSize": res.commentList.length,
|
||||
"comment": this.getTree(res.commentList)
|
||||
}
|
||||
```
|
||||
|
||||
其中`getTree`方法如下
|
||||
|
||||
```js
|
||||
getTree(data) {
|
||||
let result = [];
|
||||
let map = {};
|
||||
data.forEach(item => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
data.forEach(item => {
|
||||
let parent = map[item.parentId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
发布弹框借鉴了[@tenniswill](https://ext.dcloud.net.cn/publisher?id=74739)先生[评论内容发布组件](https://ext.dcloud.net.cn/plugin?id=1302)的思路,同时参照其评论区对代码作了优化
|
||||
|
||||
## 后端的Python实现核心代码,可以参考
|
||||
|
||||
* mysql结构,还有一张userlist表没有列出,请自己发挥
|
||||
|
||||
```sql
|
||||
-- ----------------------------
|
||||
-- Table structure for comment
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `comment`;
|
||||
CREATE TABLE `comment` (
|
||||
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`article_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所属文章id',
|
||||
`comment_user_id` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '评论人id',
|
||||
`parent_id` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '所属评论id,主评论为null',
|
||||
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '评论内容',
|
||||
`like` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '点赞(存储点赞人id数组)',
|
||||
`status` tinyint(3) UNSIGNED NULL DEFAULT 0 COMMENT '状态,0-未审核,1-展现,2-审核驳回,3-已删除',
|
||||
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0),
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '评论' ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for article_read
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `article_read`;
|
||||
CREATE TABLE `article_read` (
|
||||
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`article_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所属文章id',
|
||||
`read_num` int(10) UNSIGNED NULL DEFAULT 1 COMMENT '阅读数',
|
||||
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0),
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `unionKey`(`article_id`) USING BTREE COMMENT '文章唯一'
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '阅读数' ROW_FORMAT = Compact;
|
||||
```
|
||||
|
||||
* python核心代码,其中`CS`为项目中封装的一个通用方法,请自己发挥并替换
|
||||
|
||||
```python
|
||||
# 提交评论
|
||||
def comment_article(articleId, userId, pId, content):
|
||||
if userId is None:
|
||||
raise CS.CustomException("请先登录", 500)
|
||||
if pId == 'null':
|
||||
pId = None
|
||||
conn = CS.getCoon()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("insert into comment(article_id,comment_user_id,parent_id,content,status,`like`) values(%s,%s,%s,%s,1,'[]')",
|
||||
(articleId, userId, pId, content))
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return CS.ResultMap(None)
|
||||
|
||||
|
||||
# 点赞评论
|
||||
def like_comment(commentId, userId):
|
||||
if userId is None:
|
||||
raise CS.CustomException("请先登录", 500)
|
||||
conn = CS.getCoon()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("select `like` from comment where id = %s", (commentId))
|
||||
currentLike_json = cursor.fetchall()[0][0]
|
||||
currentLike = json.loads(currentLike_json)
|
||||
if userId in currentLike:
|
||||
currentLike.remove(userId)
|
||||
else:
|
||||
currentLike.append(userId)
|
||||
currentLike_json = json.dumps(currentLike)
|
||||
cursor.execute("update comment set `like` = %s where id = %s", (currentLike_json, commentId))
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return CS.ResultMap(None)
|
||||
|
||||
|
||||
# 删除评论
|
||||
def delete_comment(commentId, userId):
|
||||
if userId is None:
|
||||
raise CS.CustomException("请先登录", 500)
|
||||
conn = CS.getCoon()
|
||||
cursor = conn.cursor()
|
||||
# userId = 1为超级管理员
|
||||
if userId != 1:
|
||||
cursor.execute("select comment_user_id from comment where id = %s and status = 1",(commentId))
|
||||
commentUserIdRst = cursor.fetchall()
|
||||
if str(commentUserIdRst) == '()':
|
||||
raise CS.CustomException("评论不存在或已删除", 500)
|
||||
if userId != commentUserIdRst[0][0]:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
raise CS.CustomException("无删除权限", 500)
|
||||
cursor.execute("update comment set status=3 where id = %s or parent_id = %s", (commentId, commentId))
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return CS.ResultMap(None)
|
||||
|
||||
|
||||
# 获取评论列表
|
||||
def get_article_comment(articleId, userId):
|
||||
conn = CS.getCoon()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
'''select
|
||||
c.id,
|
||||
c.comment_user_id,
|
||||
u.avatar_url,
|
||||
u.nick_name,
|
||||
c.content,
|
||||
c.like,
|
||||
c.parent_id,
|
||||
c.create_time
|
||||
from comment c
|
||||
left join userlist u on c.comment_user_id = u.id
|
||||
where article_id = %s and status = 1''', (articleId))
|
||||
commentList = cursor.fetchall()
|
||||
cursor.execute("insert into article_read(article_id) values(%s) on DUPLICATE KEY UPDATE read_num=read_num+1", (articleId))
|
||||
conn.commit()
|
||||
cursor.execute("select read_num from article_read where article_id = %s", (articleId))
|
||||
readNum = cursor.fetchall()[0][0]
|
||||
cursor.close()
|
||||
conn.close()
|
||||
commentResult = []
|
||||
for comment in commentList:
|
||||
like = json.loads(comment[5])
|
||||
commentEach = {
|
||||
"id": comment[0],
|
||||
"owner": False,
|
||||
"hasLike": False,
|
||||
"likeNum": len(like),
|
||||
"avatarUrl": comment[2],
|
||||
"nickName": "用户" if comment[3] == None else comment[3],
|
||||
"content": comment[4],
|
||||
"parentId": comment[6],
|
||||
"createTime": time.strftime("%Y-%m-%d %H:%M:%S", datetime.datetime.timetuple(comment[7]))
|
||||
}
|
||||
if len(commentEach['nickName']) > 7:
|
||||
commentEach['nickName'] = commentEach['nickName'][0:6] + '...'
|
||||
if userId is not None:
|
||||
# userId = 1为超级管理员
|
||||
if userId == comment[1] or userId == 1:
|
||||
commentEach["owner"] = True
|
||||
if userId in like:
|
||||
commentEach["hasLike"] = True
|
||||
commentResult.append(commentEach)
|
||||
result = {
|
||||
"readNumer": readNum,
|
||||
"commentList": commentResult
|
||||
}
|
||||
return CS.ResultMap(result)
|
||||
```
|
||||
@@ -7,7 +7,7 @@
|
||||
<view class='toolbar' @tap="format">
|
||||
<!-- <view class="iconfont icon-undo" @tap="undo"></view>
|
||||
<view class="iconfont icon-redo" @tap="redo"></view> -->
|
||||
<view class="iconfont icon-charutupian" @tap="insertImage"></view>
|
||||
<!-- <view class="iconfont icon-charutupian" @tap="insertImage"></view> -->
|
||||
<!-- <view :class="formats.fontSize === '24px' ? 'ql-active' : ''" class="iconfont icon-font-size"
|
||||
data-name="fontSize" data-value="24px"></view> -->
|
||||
<view :class="formats.color? 'ql-active' : ''" class="iconfont icon-zitiyanse" data-name="color" :data-value="formats.color">
|
||||
@@ -393,11 +393,18 @@
|
||||
.toolbar {
|
||||
box-sizing: border-box;
|
||||
border-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
position: fixed;
|
||||
margin-bottom: 10rpx;
|
||||
padding-bottom: 4rpx;
|
||||
position: -webkit-sticky; /* Safari */
|
||||
position: sticky;
|
||||
top: -1px; /* 距离顶部的距离 */
|
||||
z-index: 10; /* 确保在其他内容之上 */
|
||||
background-color: #d8e6ff;
|
||||
border-bottom: 1rpx solid #5188e5;
|
||||
/* position: fixed;
|
||||
bottom: 10upx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
right: 0; */
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user