开发流程
- 添加评论类型:在自定义字典管理评论类型中新增评论类型(名称),dataType(数据值),如文章、商品等;
- 添加评论配置:在自定义配置中导入评论类型评论配置,通过快速复制配置JSON模板。修改配置的title属性值为评论类型+评论配置,如文章评论配置、商品评论配置等
- 前台页面:支持评论列表、发布/回复评论功能,提供通用评论组件ms-comment.htm
添加评论类型

各评论数据业务有独立评论配置,评论配置名称约定为 评论类型字典中当前评论类型 + 评论配置;
如文章的评论配置名称为: 文章评论配置

添加评论配置
下方是评论配置配置的模板,title属性需要按照上面评论类型+评论配置名称约定去设置,其余不变
{
"title": "文章评论配置",
"field": "[\n {\n \"model\":\"enableComment\",\n \"key\":\"ENABLE_COMMENT\",\n \"field\":\"ENABLE_COMMENT\",\n \"javaType\":\"Boolean\",\n \"jdbcType\":\"VARCHAR\",\n \"name\":\"开启评论\",\n \"type\":\"switch\",\n \"length\":\"11\",\n \"isShow\":false,\n \"isNoRepeat\":false,\n \"isSearch\":false,\n \"isRequired\":false\n }\n ,{\n \"model\":\"enableVisitor\",\n \"key\":\"ENABLE_VISITOR\",\n \"field\":\"ENABLE_VISITOR\",\n \"javaType\":\"Boolean\",\n \"jdbcType\":\"VARCHAR\",\n \"name\":\"开启游客模式\",\n \"type\":\"switch\",\n \"length\":\"11\",\n \"isShow\":false,\n \"isNoRepeat\":false,\n \"isSearch\":false,\n \"isRequired\":false\n }\n ,{\n \"model\":\"enableAudit\",\n \"key\":\"ENABLE_AUDIT\",\n \"field\":\"ENABLE_AUDIT\",\n \"javaType\":\"Boolean\",\n \"jdbcType\":\"VARCHAR\",\n \"name\":\"开启审核\",\n \"type\":\"switch\",\n \"length\":\"11\",\n \"isShow\":false,\n \"isNoRepeat\":false,\n \"isSearch\":false,\n \"isRequired\":false\n }\n]\n\n",
"html": "\n<template id=\"custom-model\">\n <el-form ref=\"form\" :model=\"form\" :rules=\"rules\" label-width=\"120px\" label-position=\"right\" size=\"small\" :disabled=\"disabled\" v-loading=\"loading\">\n <!--开启评论-->\n \n <el-form-item label=\"开启评论\" prop=\"enableComment\">\n <el-switch v-model=\"form.enableComment\"\n :disabled=\"false\">\n </el-switch>\n <div class=\"ms-form-tip\">\n开启评论后允许发布评论 </div>\n </el-form-item>\n \n <!--开启游客模式-->\n \n <el-form-item label=\"开启游客模式\" prop=\"enableVisitor\">\n <el-switch v-model=\"form.enableVisitor\"\n :disabled=\"false\">\n </el-switch>\n <div class=\"ms-form-tip\">\n开启后,无需登录也能评论;不开启推荐 </div>\n </el-form-item>\n \n <!--开启审核-->\n \n <el-form-item label=\"开启审核\" prop=\"enableAudit\">\n <el-switch v-model=\"form.enableAudit\"\n :disabled=\"false\">\n </el-switch>\n <div class=\"ms-form-tip\">\n开启后,评论信息审核通过后才在前台显示 </div>\n </el-form-item>\n \n </el-form>\n</template>\n",
"script": "var custom_model = Vue.component(\"custom-model\",{\n el: '#custom-model',\n data:function() {\n return {\n\t\t\tloading:false,\n disabled:false,\n modelId:0,\n modelName: \"评论配置\",\n //表单数据\n form: {\n linkId:0,\n // 开启评论\n enableComment:true,\n // 开启游客模式\n enableVisitor:false,\n // 开启审核\n enableAudit:true,\n },\n\n rules:{\n },\n }\n },\n watch:{\n \n //开启评论 \n \"form.enableComment\":function(nev,old){\n if(typeof(nev)=='string') {\n this.form.enableComment = (nev=='true');\n } else if(typeof(nev)=='undefined') {\n this.form.enableComment = false;\n } \n },\n \n //开启游客模式 \n \"form.enableVisitor\":function(nev,old){\n if(typeof(nev)=='string') {\n this.form.enableVisitor = (nev=='true');\n } else if(typeof(nev)=='undefined') {\n this.form.enableVisitor = false;\n } \n },\n \n //开启审核 \n \"form.enableAudit\":function(nev,old){\n if(typeof(nev)=='string') {\n this.form.enableAudit = (nev=='true');\n } else if(typeof(nev)=='undefined') {\n this.form.enableAudit = false;\n } \n },\n },\n components:{\n },\n computed:{\n },\n methods: {\n \tlink:function(e,field,binds){\n \t\tlet that = this;\n binds.forEach(function(item){\n \t\t\t\tms.http.post(ms.manager+'/project/form/link.do', {id:that.modelId,field:item.field,value:e}).then(function (res) {\n if(res.result && res.data) {\n that.form[ms.util.camelCaseString(item.field)]=res.data[0][item.target];\n }else{\n that.$notify({\n title: '失败',\n message: res.msg,\n type: 'warning'\n });\n }\n })\n\n });\n \t},\n update: function (row) {\n var that = this;\n ms.http.post(ms.manager+\"/comment/commentConfig/update.do\", row).then(function (data) {\n if (data.result) {\n that.$notify({\n title: '成功',\n message: '更新成功',\n type: 'success'\n });\n\n } else {\n that.$notify({\n title: '失败',\n message: data.msg,\n type: 'warning'\n });\n }\n });\n }, validate:function(){\n var b = false\n this.$refs.form.validate(function(valid){\n b = valid;\n });\n return b;\n },\n getFormData() {\n var that = this;\n var form = JSON.parse(JSON.stringify(that.form));\n form.modelId = that.modelId;\n return form;\n },\n save:function(callback) {\n var that = this;\n var url = this.formURL.save.url;\n if (that.form.id > 0) {\n url = this.formURL.update.url;\n }\n this.$refs.form.validate(function(valid) {\n if (valid) {\n var form = JSON.parse(JSON.stringify(that.form));\n form.modelId = that.modelId;\n ms.http.post(url, form).then(function (res) {\n if(callback) {\n callback(res);\n }\n }).catch(function(err){\n callback(err.response.data);\n });\n } else{\n callback({\n result:false,msg:'请检查表单输入项'\n });\n }\n })\n },\n //获取当前评论配置\n get:function(id) {\n var that = this;\n that.loading = true;\n ms.http.get(this.formURL.get.url, Object.assign({\"modelId\":that.modelId},this.formURL.get.params)).then(function (res) {\n if(res.result&&res.data){\n that.form = res.data;\n that.loading = false;\n } else {\n that.loading = false;\n }\n }).catch(function (err) {\n console.log(err);\n that.loading = false;\n });\n },\n\n },\n created:function() {\n var that = this;\n //渲染create\n that.get(this.form.linkId);\n }\n});",
"searchJson": "[\n]\n"
}
在自定义配置中导入配置模型json

导入后的评论配置表单效果

前台页面显示
下方是核心的前端调用代码,具体页面效果根据自身模版的风格进行调整
ms-comment.htm 组件页面(默认提供参考)
组件提供评论列表查看、发布/回复评论功能
源码参考:webapp/template/1/default/component/ms-comment.htm

用法参考:webapp/template/1/default/news-detail.htm;
如果使用ms-comment组件,引入下图标记的资源,再修改datatype值

评论列表
- 通用评论列表接口:/comment/list.do 对应源代码: net/mingsoft/comment/action/web/CommentAction.java 参数:dataType:评论类型(数据值)
可根据top_id(顶级评论id)comment_id(父评论id)和自身id的关系来处理形成评论层级关系
前端代码片段
...
// 评论列表渲染
<div v-for="comment in commentDataList">
{{comment.peopleName?comment.peopleName:'游客'}} //顶级评论:用户名称
{{comment.commentTime}} //顶级评论:发布时间
{{comment.commentContent}} //顶级评论:评论内容
<div v-for="childComment in comment.childCommentDataLists">
{{comment.peopleName?comment.peopleName:'游客'}} //子评论:用户名称
{{comment.commentTime}} //子评论:发布时间
{{comment.commentContent}} //子评论:评论内容
</div>
</div>
...
...
//变量定义
data: function () {
return{
commentDataList: [], //评论列表数据(树形结构)
commentList:[], // 评论列表数据(接口返回)
total: 0, // 评论总数
}
},
// 获取文章评论列表数据
var that = this;
ms.http.post( ms.base + '/comment/list.do', {
dataId: '${field.id}', // 业务数据编号 如文章
dataType: 'content', // 评论类型数据值
pageNo: 1, //当前页数
pageSize: 20 //每页文章条数
}).then(function (res) {
if (res.result) {
that.total = res.data.total; //总数
that.commentList = res.data.rows; //评论记录
// 第一级评论
var topComment = that.commentList.filter(c => !c.topId || c.topId==0)
topComment.forEach(function (data) {
// 如果当前这条评论存在图片
if (data.commentPicture){
var commentPicture = JSON.parse(data.commentPicture)
// 存储当前评论的图片
data['pictureList'] = []
commentPicture.forEach(function (picture){
data['pictureList'].push(picture.path)
})
}
//初始化子评论列表
data.childCommentDataLists = [];
// 当前遍历到评论的所有子评论
var childComments = that.commentList
.filter(item => item.topId && item.topId==data.id)
childComments.forEach(function (childData) {
// 如果父评论为顶级评论则直接赋值
if (childData.commentId == data.id){
childData.parentName = data.peopleName;
} else {
// 找到当前遍历子评论的父评论
var parentComment = childComments.find(function (item) {
return item.id = childData.commentId;
})
if (parentComment){
childData.parentName = parentComment.peopleName;
}
}
// 将处理完的数据push到顶级评论的子集中
data.childCommentDataLists.push(childData);
});
// 存放顶级评论
that.commentDataList.push(data)
})
}
})
...
Tip
多层评论,推荐"懒加载"的方式,第一次只查询顶级评论,当用户点击某个评论的下拉列表再次去请求该评论下的子评论,以此类推。
发布/回复评论
- 通用发布或回复评论接口:/people/comment/save.do 对应源代码:net/mingsoft/comment/action/people/CommentAction.java
前端代码片段
...
//评论表单定义
form: {
commentId:'',//父评论编号,在评论中点击回复时使用
commentContent: '',//评论内容
dataTitle: '${field.title}',//文章标题
dataId: '${field.id}',//文章id
commentPicture: [],// 评论图片JSON
commentFileJson: [],// 附件JSON
commentPoints: 0,// 评论打分
dataType: "content" //评论类型数据值
}
...
...
// 发布评论请求
var that = this;
ms.http.post(ms.base + '/people/comment/save.do', that.form)
.then(function (res) {
if (res.result) {
this.$message({
title: '成功',
message: '评论成功',
type: 'success'
});
} else {
this.$message({
title: '失败',
message: '评论失败',
type: 'error'
});
}
})
...