zoukankan      html  css  js  c++  java
  • Vue+koa2开发一款全栈小程序(9.图书详情页)

    1.获取图书详情

    1.修改server/controllers/bookdetail.js为

    const {mysql}=require('../qcloud')
    
    module.exports=async(ctx)=>{
        const {id}=ctx.request.query
        const detail=await mysql('books')
                            .select('books.*','csessioninfo.user_info')
                            .join('csessioninfo','books.openid','csessioninfo.open_id')
                            .where('id',id)
                            .first()
        const info=JSON.parse(detail.user_info)
        ctx.state.data=Object.assign({},detail,{
            user_info:{
                name:info.nickName,
                image:info.avatarUrl
            }
        })
    
    }

    2.在mydemo/src/components/BookInfo.vue

    <template>
        <div class="bookinfo">
            <div class="thumb">
                <img class="back" 
                    :src="info.image"
                    mode="aspectFull">
                <img class="img" 
                :src="info.image"
                mode="aspectFit">
                <div class="info">
                    <div class="title">
                        {{info.title}}
                    </div>
                    <div class="author">
                        {{info.author}}
                    </div>
                </div>
            </div>  
            <div class="detail">
                <img :src="userinfo.image" class="avatar" mode="aspectFit">
                {{userinfo.name}}
                <div class="right text-primary">
                    {{info.rate}}分<Rate :value='info.rate'></Rate>
                </div>
            </div>
            <div class="detail">
                {{info.publisher}}
                <div class="right">
                    {{info.price}}
                </div>
    
            </div>  
        </div>    
    </template>
    <script>
    import Rate from '@/components/Rate'
    export default {
        components:{
            Rate
        },
        
        props:['info'],
    
        computed:{
            userinfo(){
                return this.info.user_info||{}
            }
        }
    
    }
    </script>
    <style lang="scss">
    .bookinfo{
        font-size: 14px;
        .right{
            float: right;
        }
        .detail{
            padding: 5px 10px;
            .avatar{
                width: 20px;
                height: 20px;
                border-radius: 50%;
                vertical-align: middle;
            }
        }
        .thumb{
            width: 750rpx;
            height: 500rpx;
            overflow: hidden;
            position: relative;
            .back{
                filter: blur(15px);
                width: 100%;
            }
            .img{
                position: absolute;
                width: 100%;
                height: 300rpx;
                left: 0;
                top:30rpx;
            }
            .info{
                color: white;
                position:absolute;
                width: 100%;
                left: 0;
                top: 330rpx;
                text-align: center;
                .title{
                    font-size: 20px;
                }
                .author{
                    font-size: 14px;
                }
            }
        }
    }
    
    </style>
    View Code

    3.在src/pages/detail/index.vue中,加入代码,才可以有分享转发功能

        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }

    index.vue

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    </div>
    </template>
    <script>
    
    import {get} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    export default {
        components:{
            BookInfo
        },
    
        data(){
            return{
                bookid:'',
                info:{}
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style>
    
    </style>
    View Code

     

    2.图书tags和简介显示

    1.在server/controllers/bookdetail.js中修改代码,增添返回tag和简介的代码

    const {mysql}=require('../qcloud')
    
    module.exports=async(ctx)=>{
        const {id}=ctx.request.query
        const detail=await mysql('books')
                            .select('books.*','csessioninfo.user_info')
                            .join('csessioninfo','books.openid','csessioninfo.open_id')
                            .where('id',id)
                            .first()
        const info=JSON.parse(detail.user_info)
        ctx.state.data=Object.assign({},detail,{
            tags:detail.tags.split(','),
            summary:detail.summary.split('
    '),
            user_info:{
                name:info.nickName,
                image:info.avatarUrl
            }
        })
    
    }
    View Code

    2.在mydemo/src/components/BookInfo.vue

    <template>
        <div class="bookinfo">
            <div class="thumb">
                <img class="back" 
                    :src="info.image"
                    mode="aspectFull">
                <img class="img" 
                :src="info.image"
                mode="aspectFit">
                <div class="info">
                    <div class="title">
                        {{info.title}}
                    </div>
                    <div class="author">
                        {{info.author}}
                    </div>
                </div>
            </div>  
            <div class="detail">
                <img :src="userinfo.image" class="avatar" mode="aspectFit">
                {{userinfo.name}}
                <div class="right text-primary">
                    {{info.rate}}分<Rate :value='info.rate'></Rate>
                </div>
            </div>
            <div class="detail">
                {{info.publisher}}
                <div class="right">
                    {{info.price}}
                </div>
            </div>
            <div class="tags">
                <div class="badge" :key="tag" v-for="tag in info.tags">{{tag}}</div>
            </div>  
            <div class="summary">
                <p :key="i" v-for="(sum,i) in info.summary">{{sum}}</p>
            </div>
        </div>    
    </template>
    <script>
    import Rate from '@/components/Rate'
    export default {
        components:{
            Rate
        },
        
        props:['info'],
    
        computed:{
            userinfo(){
                return this.info.user_info||{}
            }
        }
    
    }
    </script>
    <style lang="scss">
    .bookinfo{
        font-size: 14px;
        .right{
            float: right;
        }
        .detail{
            padding: 5px 10px;
            .avatar{
                width: 20px;
                height: 20px;
                border-radius: 50%;
                vertical-align: middle;
            }
        }
        .thumb{
            width: 750rpx;
            height: 500rpx;
            overflow: hidden;
            position: relative;
            .back{
                filter: blur(15px);
                width: 100%;
            }
            .img{
                position: absolute;
                width: 100%;
                height: 300rpx;
                left: 0;
                top:30rpx;
            }
            .info{
                color: white;
                position:absolute;
                width: 100%;
                left: 0;
                top: 330rpx;
                text-align: center;
                .title{
                    font-size: 20px;
                }
                .author{
                    font-size: 14px;
                }
            }
        }
        .badge{
            display: inline-block;
            margin:5px;
            padding: 5px;
            border-radius: 10px;
            border:1px #EA5A49 solid;
            color: #EA5A49;
        }
        .summary{
            padding: 0 15px;
            margin-top: 10px;
            p{
                text-indent: 2em;
                font-size: 14px;
                margin-top: 5px;
            }
        }
    }
    
    </style>
    View Code

    效果图

     3.获取手机型号、地理位置,用户评论功能

    1.评论框和获取用户手机型号,在src/pages/detail/index.vue中

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    
        <div class="comment">
            <textarea v-model="comment"
                        class="textarea"
                        :maxlength="100"
                        placeholder="请输入图书短评"></textarea>
            <div class="location">
                地理位置:
                <switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
                <span class="text-primary">{{location}}</span>
            </div>
            <div class="phone">
                手机型号:
                <switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
                <span class="text-primary">{{phone}}</span>
            </div>
        </div>
    
    </div>
    </template>
    <script>
    
    import {get} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    export default {
        components:{
            BookInfo
        },
    
        data(){
            return{
                bookid:'',
                info:{},
                comment:'',
                location:'',
                phone:''
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            },
    
            getGeo(){},
            getPhone(e){
                if(e.target.value){
                    const phoneInfo=wx.getSystemInfoSync()
                    console.log(phoneInfo)
                    this.phone=phoneInfo.model
                }else{
                    // 没选中
                    this.phone=''
                }
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style lang='scss'>
        .comment{
            margin-top: 10px;
            .textarea{
                width: 730rpx;
                height: 200rpx;
                background: #eee;
                padding: 10rpx;
    
            }
            .location{
                margin-top: 10px;
            }
            .phone{
                margin-top:10px;
            }
        }
    </style>
    View Code

     

     2.获取经纬度 在src/pages/detail/index.vue中

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    
        <div class="comment">
            <textarea v-model="comment"
                        class="textarea"
                        :maxlength="100"
                        placeholder="请输入图书短评"></textarea>
            <div class="location">
                地理位置:
                <switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
                <span class="text-primary">{{location}}</span>
            </div>
            <div class="phone">
                手机型号:
                <switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
                <span class="text-primary">{{phone}}</span>
            </div>
        </div>
    
    </div>
    </template>
    <script>
    
    import {get} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    export default {
        components:{
            BookInfo
        },
    
        data(){
            return{
                bookid:'',
                info:{},
                comment:'',
                location:'',
                phone:''
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            },
    
            getGeo(e){
                if(e.target.value){
                    wx.getLocation({
                        success:geo=>{
                            console.log(geo)
                        }
                    })
                }else{
                    this.location=''
                }
            },
            getPhone(e){
                if(e.target.value){
                    const phoneInfo=wx.getSystemInfoSync()
                    console.log(phoneInfo)
                    this.phone=phoneInfo.model
                }else{
                    // 没选中
                    this.phone=''
                }
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style lang='scss'>
        .comment{
            margin-top: 10px;
            .textarea{
                width: 730rpx;
                height: 200rpx;
                background: #eee;
                padding: 10rpx;
    
            }
            .location{
                margin-top: 10px;
            }
            .phone{
                margin-top:10px;
            }
        }
    </style>
    View Code

    效果图

     3.通过配合百度地图的api,通过经纬度获取地理位置

    1.百度地图开放平台网址:

    http://lbsyun.baidu.com/apiconsole/key

    2.服务文档和使用方法网址:

    http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding

    根据使用指南,注册,申请百度开发者,获取服务秘钥(AK)

    部分过程图

     

     

    3.全球逆地理编码(给经纬度输出地点名称)文档地址:

    http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad

    4.在src/pages/detail/index.vue中

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    
        <div class="comment">
            <textarea v-model="comment"
                        class="textarea"
                        :maxlength="100"
                        placeholder="请输入图书短评"></textarea>
            <div class="location">
                地理位置:
                <switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
                <span class="text-primary">{{location}}</span>
            </div>
            <div class="phone">
                手机型号:
                <switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
                <span class="text-primary">{{phone}}</span>
            </div>
        </div>
    
    </div>
    </template>
    <script>
    
    import {get} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    export default {
        components:{
            BookInfo
        },
    
        data(){
            return{
                bookid:'',
                info:{},
                comment:'',
                location:'',
                phone:''
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            },
    
            getGeo(e){
                const ak='你的ak'
                let url='http://api.map.baidu.com/geocoder/v2/'
                if(e.target.value){
                    wx.getLocation({
                        success:geo=>{
                            wx.request({
                                url,
                                data:{
                                    ak,
                                    location:`${geo.latitude},${geo.longitude}`,
                                    output:'json'
                                },
                                success:res=>{
                                    // console.log(res)
                                    if(res.data.status==0){
                                        this.location=res.data.result.addressComponent.city
                                    }else{
                                        // console.log('出错了')
                                        this.location='未知地点'
                                    }
                                }
                            })
                            // console.log(geo)
                        }
                    })
                }else{
                    this.location=''
                }
            },
            getPhone(e){
                if(e.target.value){
                    const phoneInfo=wx.getSystemInfoSync()
                    console.log(phoneInfo)
                    this.phone=phoneInfo.model
                }else{
                    // 没选中
                    this.phone=''
                }
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style lang='scss'>
        .comment{
            margin-top: 10px;
            .textarea{
                width: 730rpx;
                height: 200rpx;
                background: #eee;
                padding: 10rpx;
    
            }
            .location{
                margin-top: 10px;
            }
            .phone{
                margin-top:10px;
            }
        }
    </style>
    View Code

    效果图,emmmm,通过经纬度这么定位,而且还是wifi的经纬度,除了城市是准的,其他偏差还挺大的,感觉还是通过ip定位比较靠谱一点,嗯。

     4.点击评论发起请求

    1.功能定义:

    一个用户只能评论一次

    如果已经评论过了,再次访问就看到评论列表,而不是评论输入框

    2.在mydemo/src/pages/detail/index/vue中,增加button评论按钮,样式,以及addComment方法

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    
        <div class="comment">
            <textarea v-model="comment"
                        class="textarea"
                        :maxlength="100"
                        placeholder="请输入图书短评"></textarea>
            <div class="location">
                地理位置:
                <switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
                <span class="text-primary">{{location}}</span>
            </div>
            <div class="phone">
                手机型号:
                <switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
                <span class="text-primary">{{phone}}</span>
            </div>
            <button class="btn" @click="addComment">
                评论
            </button>
        </div>
    
    </div>
    </template>
    <script>
    
    import {get,post,showModal} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    export default {
        components:{
            BookInfo
        },
    
        data(){
            return{
                userinfo:'',
                bookid:'',
                info:{},
                comment:'',
                location:'',
                phone:''
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            },
    
            getGeo(e){
                const ak='5hvI2CGwH5YO4ZT85MjpxXgk01WWSGOi'
                let url='http://api.map.baidu.com/geocoder/v2/'
                if(e.target.value){
                    wx.getLocation({
                        success:geo=>{
                            wx.request({
                                url,
                                data:{
                                    ak,
                                    location:`${geo.latitude},${geo.longitude}`,
                                    output:'json'
                                },
                                success:res=>{
                                    // console.log(res)
                                    if(res.data.status==0){
                                        this.location=res.data.result.addressComponent.city
                                    }else{
                                        // console.log('出错了')
                                        this.location='未知地点'
                                    }
                                }
                            })
                            // console.log(geo)
                        }
                    })
                }else{
                    this.location=''
                }
            },
            getPhone(e){
                if(e.target.value){
                    const phoneInfo=wx.getSystemInfoSync()
                    // console.log(phoneInfo)
                    this.phone=phoneInfo.model
                }else{
                    // 没选中
                    this.phone=''
                }
            },
    
            async addComment(){
                // 评论内容 手机型号 地理位置 图书id 用户的openid
                const data={
                    openid:this.userinfo.openId,
                    bookid:this.bookid,
                    comment:this.comment,
                    phone:this.phone,
                    location:this.location
                }
                // console.log(data)
                if(!this.comment){
                    return
                }
                try{
                   await post('/weapp/addcomment',data) 
                   this.comment=''
                }catch(e){
                    showModel('失败',e.msg)
                }
                
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
            const userinfo=wx.getStorageSync('userinfo')
            // console.log(888,userinfo)
            if(userinfo){
                this.userinfo=userinfo
            }
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style lang='scss'>
        .comment{
            margin-top: 10px;
            .textarea{
                width: 730rpx;
                height: 200rpx;
                background: #eee;
                padding: 10rpx;
    
            }
            .location{
                margin-top: 10px;
            }
            .phone{
                margin-top:10px;
                margin-bottom: 10px;
            }
        }
    </style>
    View Code

    效果图

    5.后台接口的实现

    1.打开mysql数据库对话框,新建评论表comments

    show databases; /*查看数据库列表*/
    use cauth; /* 使用cAuth数据库*/
    
    CREATE TABLE `comments` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `openid` varchar(100) NOT NULL,
      `bookid` varchar(100) NOT NULL,
      `comment` varchar(200) NOT NULL,
      `phone` varchar(20) DEFAULT NULL,
      `location` varchar(20) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    /*创建comments表*/
    
    desc comments; /* 查看comments表的字段*/
    
    select * from comments; /*查看comments的记录*/

    2.在server/routes/index.js内增加路由

    router.post('/addcomment',controllers.addcomment)

    3.在server/controllers目录下新建addComment.js

    const {mysql} =require('../qcloud')
    
    module.exports=async (ctx)=>{
        const {bookid,comment,openid,location,phone}=ctx.request.body
        console.log(bookid,comment,openid,location,phone)
        try{
            await mysql('comments').insert({bookid,comment,openid,location,phone})
            ctx.state.data={
                msg:'succcess'
            }
        }catch(e){
            ctx.state={
                code:-1,
                data:{
                    msg:'评论失败:'+e.sqlMessage
                }
            }
        }
    }
    View Code

    效果图

     4.评论列表实现

    1.在mydemo/src/pages/detail/index/vue中的mounted中增加获取评论列表this.getComments()方法,在methods中编写

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    
        <div class="comment">
            <textarea v-model="comment"
                        class="textarea"
                        :maxlength="100"
                        placeholder="请输入图书短评"></textarea>
            <div class="location">
                地理位置:
                <switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
                <span class="text-primary">{{location}}</span>
            </div>
            <div class="phone">
                手机型号:
                <switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
                <span class="text-primary">{{phone}}</span>
            </div>
            <button class="btn" @click="addComment">
                评论
            </button>
        </div>
    
    </div>
    </template>
    <script>
    
    import {get,post,showModal} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    export default {
        components:{
            BookInfo
        },
    
        data(){
            return{
                userinfo:'',
                bookid:'',
                info:{},
                comment:'',
                comments:[],
                location:'',
                phone:''
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            },
    
            getGeo(e){
                const ak='5hvI2CGwH5YO4ZT85MjpxXgk01WWSGOi'
                let url='http://api.map.baidu.com/geocoder/v2/'
                if(e.target.value){
                    wx.getLocation({
                        success:geo=>{
                            wx.request({
                                url,
                                data:{
                                    ak,
                                    location:`${geo.latitude},${geo.longitude}`,
                                    output:'json'
                                },
                                success:res=>{
                                    // console.log(res)
                                    if(res.data.status==0){
                                        this.location=res.data.result.addressComponent.city
                                    }else{
                                        // console.log('出错了')
                                        this.location='未知地点'
                                    }
                                }
                            })
                            // console.log(geo)
                        }
                    })
                }else{
                    this.location=''
                }
            },
            getPhone(e){
                if(e.target.value){
                    const phoneInfo=wx.getSystemInfoSync()
                    // console.log(phoneInfo)
                    this.phone=phoneInfo.model
                }else{
                    // 没选中
                    this.phone=''
                }
            },
    
            async addComment(){
                // 评论内容 手机型号 地理位置 图书id 用户的openid
                const data={
                    openid:this.userinfo.openId,
                    bookid:this.bookid,
                    comment:this.comment,
                    phone:this.phone,
                    location:this.location
                }
                // console.log(data)
                if(!this.comment){
                    return
                }
                try{
                   await post('/weapp/addcomment',data) 
                   this.comment=''
                }catch(e){
                    showModel('失败',e.msg)
                }
                
            },
    
            async getComments(){
                const comments=await get('/weapp/commentlist',{bookid:this.bookid})
                this.comments=comments
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
            const userinfo=wx.getStorageSync('userinfo')
            // console.log(888,userinfo)
            if(userinfo){
                this.userinfo=userinfo
            }
            this.getComments()
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style lang='scss'>
        .comment{
            margin-top: 10px;
            .textarea{
                width: 730rpx;
                height: 200rpx;
                background: #eee;
                padding: 10rpx;
    
            }
            .location{
                margin-top: 10px;
            }
            .phone{
                margin-top:10px;
                margin-bottom: 10px;
            }
        }
    </style>
    View Code

    2.在server/router/index.js中增加路由

    router.get('/commentlist',controllers.commentlist)

    3.在server/controllers目录下新建commentlist.js

    const {mysql}=require('../qcloud')
    
    module.exports=async(ctx)=>{
        const {bookid}=ctx.request.query
        const comments=await mysql('comments')
                                .select('comments.*','cSessionInfo.user_info')
                                .join('cSessionInfo','comments.openid','cSessionInfo.open_id')
                                .where('bookid',bookid)
        ctx.state.data={
            list:comments.map(v=>{
                const info=JSON.parse(v.user_info)
                return Object.assign({},v,{
                    title:info.nickName,
                    image:info.avatarUrl
                })
            })
        }
    }

    效果图

     5.评论列表封装成一个组件

    1.在src/components目录下新建CommentList.vue

    <template>
        <div class="comment-list">
            <div class="page-title" v-if="comments.length">
                我的评论
            </div>
            <div class="comment" v-for="comment in comments" :key="comment.id">
                <div class="user">
                    <div class="inline">
                        <img class="avatar" :src="comment.image" mode='aspectFit'>
                        {{comment.title}}
                    </div>
                    <div class="right">
                        {{comment.location||'未知地点'}}
                        <span class="text-primary">--</span>
                        {{comment.phone||'未知型号'}}
                    </div>
                </div>
                <div style="clear:both;"></div>
                <div class="content">
                    {{comment.comment}}
                </div>
            </div>
        </div>
    </template>
    <script>
    export default {
        props:['comments']
    }
    </script>
    
    <style lang='scss'>
    .comment-list{
        background: #eee;
        font-size: 14px;
        .page-title{
            padding-left: 20px;
            background: #eee;
            line-height: 40px;
            font-size: 16px;
            }
        .comment{
            background: white;
            margin-bottom: 10px;
            padding: 5px 20px;
            .content{
                margin: 10px;
            }
            .user{
                .inline{
                    float: left;
                }
                .right{
                    float:right;
                }
                .avatar{
                    width:20px;
                    height: 20px;
                    border-radius: 50%;
                }
            }
        }
        
    }
    </style>
    View Code

    2.在src/pages/detail/index.vue中修改增加代码

    <template>
    <div>
    
        <BookInfo :info='info'></BookInfo>
    
        <CommentList :comments="comments"></CommentList>
    
        <div class="comment" v-if="showAdd">
            <textarea v-model="comment"
                        class="textarea"
                        :maxlength="100"
                        placeholder="请输入图书短评"></textarea>
            <div class="location">
                地理位置:
                <switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
                <span class="text-primary">{{location}}</span>
            </div>
            <div class="phone">
                手机型号:
                <switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
                <span class="text-primary">{{phone}}</span>
            </div>
            <button class="btn" @click="addComment">
                评论
            </button>
        </div>
    
        <div v-else class="text-footer">
            未登录或者已经评论过啦
        </div>
    
        <button class="btn" open-type="share">分享给好友</button>
    
    </div>
    </template>
    <script>
    
    import {get,post,showModal} from '@/until'
    
    import BookInfo from '@/components/BookInfo'
    
    import CommentList from '@/components/CommentList'
    
    export default {
        components:{
            BookInfo,
            CommentList
        },
    
        data(){
            return{
                userinfo:'',
                bookid:'',
                info:{},
                comment:'',
                comments:[],
                location:'',
                phone:''
            }
        },
    
        methods:{
            async getDetail(){
                const info=await get('/weapp/bookdetail',{id:this.bookid})
                wx.setNavigationBarTitle({title:info.data.title})
                this.info=info.data
            },
    
            getGeo(e){
                const ak='5hvI2CGwH5YO4ZT85MjpxXgk01WWSGOi'
                let url='http://api.map.baidu.com/geocoder/v2/'
                if(e.target.value){
                    wx.getLocation({
                        success:geo=>{
                            wx.request({
                                url,
                                data:{
                                    ak,
                                    location:`${geo.latitude},${geo.longitude}`,
                                    output:'json'
                                },
                                success:res=>{
                                    // console.log(res)
                                    if(res.data.status==0){
                                        this.location=res.data.result.addressComponent.city
                                    }else{
                                        // console.log('出错了')
                                        this.location='未知地点'
                                    }
                                }
                            })
                            // console.log(geo)
                        }
                    })
                }else{
                    this.location=''
                }
            },
            getPhone(e){
                if(e.target.value){
                    const phoneInfo=wx.getSystemInfoSync()
                    // console.log(phoneInfo)
                    this.phone=phoneInfo.model
                }else{
                    // 没选中
                    this.phone=''
                }
            },
    
            async addComment(){
                // 评论内容 手机型号 地理位置 图书id 用户的openid
                const data={
                    openid:this.userinfo.openId,
                    bookid:this.bookid,
                    comment:this.comment,
                    phone:this.phone,
                    location:this.location
                }
                // console.log(data)
                if(!this.comment){
                    return
                }
                try{
                   await post('/weapp/addcomment',data) 
                   this.comment=''
                   this.getComments()
                }catch(e){
                    showModel('失败',e.msg)
                }
                
            },
    
            async getComments(){
                const comments=await get('/weapp/commentlist',{bookid:this.bookid})
                // console.log(11111,comments.data.list[0])
                this.comments=comments.data.list
                
            }
        },
    
        computed:{
            showAdd(){
                // 没登录
                if(!this.userinfo.openId){
                    return false
                }
                if(this.comments.filter(v=>v.openid==this.userinfo.openId).length){
                    return false
                }
                return true
            }
        },
    
        mounted(){
            this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
            this.getDetail()
            const userinfo=wx.getStorageSync('userinfo')
            // console.log(888,userinfo)
            if(userinfo){
                this.userinfo=userinfo
            }
            this.getComments()
            
        },
    
        onShareAppMessage: (res) => {
            if (res.from === 'button') {
                console.log("来自页面内转发按钮");
                console.log(res.target);
                }
            else {
                console.log("来自右上角转发菜单")
            }
            return {
                // title: '',
                // path: '/pages/share/share?id=123',
                // imageUrl: "/images/1.jpg",
                success: (res) => {
                console.log("转发成功", res);
                },
                fail: (res) => {
                console.log("转发失败", res);
                }
            }
        }
    
    
    
    }
    </script>
    <style lang='scss'>
        .comment{
            margin-top: 10px;
            .textarea{
                width: 730rpx;
                height: 200rpx;
                background: #eee;
                padding: 10rpx;
    
            }
            .location{
                margin-top: 10px;
            }
            .phone{
                margin-top:10px;
                margin-bottom: 10px;
            }
        }
    </style>
    View Code

    效果图

    6.修整代码格式

    打开cmd,cd到项目目录mydemo下,执行

    npm run lint

    发现有四处代码不规范,去改正

    应该是三个等号写成了两个等号,showModal写错了,写成了showModel

  • 相关阅读:
    通过HttpListener实现简单的Http服务
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    NHibernate初学六之关联多对多关系
    NHibernate初学五之关联一对多关系
    EXTJS 4.2 资料 跨域的问题
    EXTJS 4.2 资料 控件之Grid 那些事
    EXTJS 3.0 资料 控件之 GridPanel属性与方法大全
    EXTJS 3.0 资料 控件之 Toolbar 两行的用法
    EXTJS 3.0 资料 控件之 combo 用法
    EXTJS 4.2 资料 控件之 Store 用法
  • 原文地址:https://www.cnblogs.com/xuepangzi/p/9813848.html
Copyright © 2011-2022 走看看