Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

开发流程

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

添加评论类型

img_4.png

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

文章的评论配置名称为: 文章评论配置

img_2.png

添加评论配置

下方是评论配置配置的模板,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

img_6.png

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

Alt text

前台页面显示

下方是核心的前端调用代码,具体页面效果根据自身模版的风格进行调整

ms-comment.htm 组件页面(默认提供参考)

组件提供评论列表查看、发布/回复评论功能

源码参考:webapp/template/1/default/component/ms-comment.htm

img_5.png

用法参考:webapp/template/1/default/news-detail.htm;

如果使用ms-comment组件,引入下图标记的资源,再修改datatype值

img_13.png

评论列表

  • 通用评论列表接口:/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'
                });
            }
    })
    ...