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

  • 相关阅读:
    软件测试中需要使用的工具
    软件测试之登录测试详解
    软件测试(功能、接口、性能、自动化)详解
    接口测试怎么进行,如何做好接口测试
    ant批量执行Jmeter脚本
    广州八神的jmeter视频网站
    Jmeter分布式测试
    Jmeter获取短信验证码接口压测
    小米手机安装fidder证书
    Jmeter组件执行顺序与作用域
  • 原文地址:https://www.cnblogs.com/xuepangzi/p/9813848.html
Copyright © 2011-2022 走看看