day109:MoFang:好友列表显示&添加好友页面初始化&添加好友后端接口

目录

1.好友列表

2.添加好友-前端

3.服务端提供添加好友的后端接口

今日内容流程图

1.好友列表

1.在用户中心页面添加好友列表点击入口

html/user.html,用户中心添加好友列表点击入口,代码:

<div class="menu">
    <div class="item" @click="open_friend_list">
        <span class="title">我的好友</span>
        <span class="value">查看</span>
    </div>
    <div class="item">
        <span class="title">我的主页</span>
        <span class="value">查看</span>
    </div>
    <div class="item">
        <span class="title">任务列表</span>
        <span class="value">75%</span>
    </div>
    <div class="item">
        <span class="title">收益明细</span>
        <span class="value">查看</span>
    </div>
    <div class="item">
        <span class="title">实名认证</span>
        <span class="value">未认证</span>
    </div>
    </ul>
</div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
                    nickname:"",
                    avatar:"",
                    prev:{name:"",url:"",params:{}},
                    current:{name:"user",url:"user.html",params:{}},
                }
            },
            created(){
                this.get_user_info();
                this.change_avatar();
            },
            methods:{
                    open_friend_list(){
                        // ***进入好友列表***
                        this.game.goFrame("friends","friends.html", this.current,{},{},true);
                    }
            }
        });
    }
    </script>
</body>
</html>
在用户中心页面添加好友列表点击入口

2.好友列表主页面初始化:friends.html

html/friends.html,好友列表主页面,代码:

<!DOCTYPE html>
<html>
<head>
    <title>用户中心</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
</head>
<body>
    <div class="app user setting" id="app">
        <div class="bg">
      <img src="../static/images/friends_bg.png">
    </div>
        <img class="back" @click="goto_home" src="../static/images/user_back.png" alt="">
        <div class="add_friend_btn" @click="add_friend">
            <img src="../static/images/add_friend.png" alt="">
        </div>
        <div class="friends_list">
    </div>
    </div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
          friends:[],
                    prev:{name:"",url:"",params:{}},
                    current:{name:"friends",url:"friends.html",params:{}},
                }
            },
            methods:{
        add_friend(){
          // 添加好友

        },
        goto_home(){
          // 退出当前页面
          this.game.outFrame("friends","friends.html", this.current);
        },
            }
        });
    }
    </script>
</body>
</html>
好友列表主页面初始化:friends.html

3.好友列表主页面CSS样式

css/main.css,样式代码:

.add_friend_btn {
  position: absolute;
  top: 12rem;
  left: 3.6rem;
  width: 26rem;
  height: 6rem;
}
.add_friend_btn img{
  box-shadow: 2px 2px 5px rgba(9,9,9,0.1);
}
好友列表主页面CSS样式

4.在打开好友列表页面的同时,也打开好友列表数据页面

1.user.html

user.html设置在打开好友列表页面的同时,也打开好友列表数据页面

methods:{

    open_friend_list(){
        // 进入好友列表
        this.game.goFrame("friends","friends.html", this.current,{},{},true);
        this.game.goFrame("friend_list","friend_list.html", this.current,{
            x: 0,
            y: 194,
            w: 'auto',
            h: 'auto',
        });
    }
}
});
}

2.好友数据列表页面初始化:friend_list.html

接下来,添加html/friend_list.html,页面代码:

<!DOCTYPE html>
<html>
<head>
    <title>用户中心</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
</head>
<body>
    <div class="app user setting" id="app">
    <div class="friends_list">
      <div class="item">
        <div class="avatar">
                    <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
                    <img class="user_avatar" src="../static/images/avatar.png" alt="">
                    <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
                </div>
        <div class="info">
          <p class="username">长昵称都很好</p>
          <p class="fruit">果子:9,999.00</p>
        </div>
        <div class="behavior pick"></div>
        <div class="goto"><img src="../static/images/arrow1.png" alt=""></div>
      </div>
      <div class="item">
        <div class="avatar">
          <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
          <img class="user_avatar" src="../static/images/avatar.png" alt="">
          <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
        </div>
        <div class="info">
          <p class="username">长昵称都很好</p>
          <p class="fruit">果子:9,999.00</p>
        </div>
        <div class="goto"><img src="../static/images/arrow1.png" alt=""></div>
      </div>
      <div class="item">
        <div class="avatar">
                    <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
                    <img class="user_avatar" src="../static/images/avatar.png" alt="">
                    <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
                </div>
        <div class="info">
          <p class="username">长昵称都很好</p>
          <p class="fruit">果子:9,999.00</p>
        </div>
        <div class="behavior protect"></div>
        <div class="goto"><img src="../static/images/arrow1.png" alt=""></div>
      </div>
      <div class="item">
        <div class="avatar">
                    <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
                    <img class="user_avatar" src="../static/images/avatar.png" alt="">
                    <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
                </div>
        <div class="info">
          <p class="username">长昵称都很好</p>
          <p class="fruit">果子:9,999.00</p>
        </div>
                <div class="behavior pick"></div>
        <div class="goto"><img src="../static/images/arrow1.png" alt=""></div>
      </div>
      <div class="item">
        <div class="avatar">
                    <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
                    <img class="user_avatar" src="../static/images/avatar.png" alt="">
                    <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
                </div>
        <div class="info">
          <p class="username">长昵称都很好</p>
          <p class="fruit">果子:9,999.00</p>
        </div>
        <div class="goto"><img src="../static/images/arrow1.png" alt=""></div>
      </div>
    </div>
    </div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
          friends:[],
          page: 1,
                    prev:{name:"",url:"",params:{}},
                    current:{name:"friend_list",url:"friend_list.html",params:{}},
                }
            },
            created(){
        this.get_friends();
            },
            methods:{
                get_friends(){

                },
        goto_home(){
          // 退出当前页面
          this.game.outFrame("friend_list","friend_list.html", this.current);
        },
            }
        });
    }
    </script>
</body>
</html>
好友数据列表页面初始化:friend_list.html

3.好友数据列表页面CSS样式

css/main.css,样式代码:

.friends_list .avatar{
  width: 6.39rem;
  height: 6.39rem;
  position: relative;
}
.friends_list .avatar_bf{
  position: absolute;
  z-index: 1;
  margin: auto;
  width: 4.56rem;
  height: 4.56rem;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
.friends_list .user_avatar{
  position: absolute;
  z-index: 1;
  width: 4.56rem;
  height: 4.56rem;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  border-radius: 1rem;
}
.friends_list .avatar_border{
  position: absolute;
  z-index: 1;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 6.1rem;
  height: 6.1rem;
}
.friends_list{
  position: absolute;
  top: 0rem;
  left: 3.6rem;
}
.friends_list .item{
  position: relative;
  background-color: rgba(196,81,9,0.1);
  border-radius: 4px;
  height: 7rem;
  width: 25.8rem;
  margin-bottom: 1rem;
  box-shadow: 2px 2px 5px rgba(9,9,9,0.1);
}
.friends_list .item .avatar{
  position: absolute;
  left: 1rem;
  top: 0;
  bottom: 0;
  margin: auto;
}
.friends_list .item .info{
  position: absolute;
  left: 8rem;
  top: 2rem;
  color: #fff;
  width: 10rem;
}
.friends_list .item .behavior{
  position: absolute;
  left: 16rem;
  font-size: 1.5rem;
  text-align: center;
  line-height: 4rem;
  height: 4rem;
  width: 4rem;
  color: #fff;
  top: 0;
  bottom: 0;
  margin: auto;
  box-shadow: 2px 2px 5px #333333;
}
.friends_list .item .pick{
  background: #336633;
  border-radius: 50%;
}
.friends_list .item .protect{
  background: #990000;
  border-top-right-radius: 5px;
  border-top-left-radius: 5px;
  border-bottom-left-radius: 30px;
  border-bottom-right-radius: 30px;
}
.friends_list .item .goto{
  position: absolute;
  left: 23rem;
  top: 0;
  bottom: 0;
  margin: auto;
  width: 0.96rem;
  height: 1.8rem;
}
好友数据列表页面CSS样式

4.为好友数据列表页面添加下拉效果

添加下拉新效果,html/friend_list.html,代码:

<script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
                    friends:[],
                    page: 1,
                    prev:{name:"",url:"",params:{}},
                    current:{name:"friend_list",url:"friend_list.html",params:{}},
                }
            },
            created(){
                this.get_friends();
            },
            methods:{
                get_friends(){
                    // ***通过下拉请求获取当前用户的好友列表***
                    api.setRefreshHeaderInfo({
                        loadingImg: 'widget://image/refresh.png',
                        bgColor: null,
                        textColor: '#fff',
                        textDown: '下拉刷新...',
                        textUp: '松开刷新...'
                    }, (ret, err)=>{
                        //在这里从服务器加载数据,加载完成后调用api.refreshHeaderLoadDone()方法恢复组件到默认状态
                        api.refreshHeaderLoadDone();
                    });
                },

            }
        });
    }
</script>
</body>
</html>

5.关闭好友列表页的时候,同时关闭好友数据列表页面

关闭好友列表页时,需要同时关闭2个frame页面。所以需要在html/friends.html关闭时,通知friend_list.html关闭。

1.friends.html发起退出通知

html/friends.html代码:

<!DOCTYPE html>
<html>
<head>
    <title>好友列表</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
</head>
<body>
    <div class="app user setting" id="app">
        <div class="bg">
      <img src="../static/images/friends_bg.png">
    </div>
        <img class="back" @click="goto_home" src="../static/images/user_back.png" alt="">
        <div class="add_friend_btn" @click="add_friend">
            <img src="../static/images/add_friends.png" alt="">
        </div>
    </div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
          friends:[],
                    prev:{name:"",url:"",params:{}},
                    current:{name:"friends",url:"friends.html",params:{}},
                }
            },
      created(){
        // 打开好友列表数据页面
        this.game.goFrame("friend_list","friend_list.html",this.current,{
            x: 0,
            y: 190,
            w: 'auto',
            h: 'auto',
        },null,true);
      },
            methods:{
        add_friend(){
          // 添加好友

        },
        goto_home(){
          // ***好友列表主页面friends.html发起通知,告知friend_list.html退出***
          api.sendEvent({
              name: 'out_page_to_user',
              extra: {
                  key1: 'user',
                  key2: 'user.html'
              }
          });

          // ***退出当前页面***
          setTimeout(()=>{
            this.game.outFrame("friends","friends.html", this.current);
          },100);
        },
            }
        });
    }
    </script>
</body>
</html>
friends.html发起退出通知

2.friend_list.html监听通知

html/friend_list.html,代码:

<script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
                    friends:[],
                    page: 1,
                    prev:{name:"",url:"",params:{}},
                    current:{name:"friend_list",url:"friend_list.html",params:{}},
                }
            },
            created(){
                this.get_friends();
                this.page_out_listener();
            },
            methods:{
                page_out_listener(){
                    // ****监听什么时候需要退出当前页面****
                    api.addEventListener({
                        name: 'out_page_to_user'
                    }, (ret, err)=>{
                        this.goto_home();
                    });
                },
                goto_home(){
                    // 退出当前页面
                    this.game.outFrame("friend_list","friend_list.html", this.current);
                },
            }
        });
    }
</script>
</body>
</html>
friend_list.html监听通知

2.添加好友-前端

1.点击添加好友按钮,跳转到添加好友界面

html/friends.html,代码:

<script>

        new Vue({
            el:"#app",
            data(){
                return {
                    friends:[],
                    prev:{name:"",url:"",params:{}},
                    current:{name:"friends",url:"friends.html",params:{}},
                }
            },
            methods:{
                add_friend(){
                    // ***添加好友***
                    this.game.goFrame("add_friend","add_friend.html", this.current,null,{
                        type:"push",             //动画类型(详见动画类型常量)
                        subType:"from_top",    //动画子类型(详见动画子类型常量)
                        duration:300             //动画过渡时间,默认300毫秒
                    });
                },
                goto_home(){
                    // 退出当前页面
                    api.sendEvent({
                        name: 'friends_out_page',
                        extra: {
                            name: 'user',
                            url: 'user.html'
                        }
                    });
                    this.game.outFrame("friends","friends.html", this.current);
                },
            }
        });
    }
</script>
</body>
</html>
点击添加按钮,跳转到添加好友界面

2.添加好友页面初始化页面:add_friend.html

html/add_friend.html,添加好友,页面代码:

<!DOCTYPE html>
<html>
<head>
    <title>添加好友</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
</head>
<body>
    <div class="app frame avatar update_nickname add_friend" id="app">
    <div class="box">
      <p class="title">添加好友</p>
      <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt="">
      <div class="content">
                <input class="nickname" type="text" v-model="account" placeholder="输入昵称/手机/邮箱/魔方账号....">
      </div>
      <div class="friends_list">
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">长昵称都很好</p>
            <p class="time">刚刚搜索</p>
          </div>
          <div class="status">添加</div>
        </div>
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">长昵称都很好</p>
            <p class="time">3小时前</p>
          </div>
          <div class="status" @click="change_status">等待通过</div>
        </div>
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">长昵称都很好</p>
            <p class="time">1天前</p>
          </div>
          <div class="status">已通过</div>
        </div>
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">长昵称都很好</p>
            <p class="time">7天前</p>
          </div>
          <div class="status">已超时</div>
        </div>
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">长昵称都很好</p>
            <p class="time">7天前</p>
          </div>
          <div class="status">已拒绝</div>
        </div>
      </div>
    </div>
    </div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
                    account:"",
                    prev:{name:"",url:"",params:{}},
                    current:{name:"add_friend",url:"add_friend.html",params:{}},
                }
            },
            methods:{
        close_frame(){
          this.game.outFrame("add_friend");
        },
        add_friend_commit(){
          // 提交搜索信息

        },
        change_status(){
          // 状态修改
        }
            }
        });
    }
    </script>
</body>
</html>
添加好友页面初始化:add_friend.html

3.添加好友界面CSS样式

css/main.css,代码:

input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder{
  color: #fff;
}
.add_friend .box{
  top: 4rem;
  height: 55.56rem;
  background: url("../images/long_bg1.png") no-repeat 0 0;
  background-size: 100%;
}
.add_friend .nickname{
  margin: 4rem 4.6rem 2rem;
  width: 19rem;
  height: 4rem;
  line-height: 4rem;
  background-color: #cc9966;
  outline: none;
  border: 1px solid #330000;
  text-align: center;
  font-size: 1rem;
  color: #ffffcc;
}

.add_friend .friends_list{
  position: absolute;
  top: 15rem;
  left: 3.6rem;
}
.add_friend .friends_list .item{
  position: relative;
  margin-left: 1rem;
  background-color: rgba(196,81,9,0.1);
  border-radius: 4px;
  height: 4rem;
  width: 19rem;
  margin-bottom: 1rem;
  box-shadow: 2px 2px 5px rgba(9,9,9,0.1);
}
.add_friend .friends_list .avatar{
  width: 3.84rem;
  height: 3.84rem;
  position: absolute;
  left: 1rem;
}

.add_friend .friends_list .avatar_bf{
  position: absolute;
  z-index: 1;
  margin: auto;
  width: 2.74rem;
  height: 2.74rem;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.add_friend .friends_list .user_avatar{
  position: absolute;
  z-index: 1;
  width: 2.74rem;
  height: 2.74rem;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  border-radius: 1rem;
}
.add_friend .friends_list .avatar_border{
  position: absolute;
  z-index: 1;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 3.66rem;
  height: 3.66rem;
}
.add_friend .friends_list .item .info{
  top: 0.6rem;
  left: 6rem;
}
.add_friend .friends_list .item .time{
  font-size: 0.6rem;
}
.friends_list .item .status{
  position: absolute;
  left: 12rem;
  top: 1.2rem;
  width: 8rem;
  text-align: center;
  height: 2rem;
  color: #fff;
}
添加好友页面CSS样式

3.服务端提供添加好友的后端接口

1.模型创建

user/models.py,代码:

class UserRelation(BaseModel):
    """用户关系"""
    __tablename__ = "mf_user_relation"
    relration_chioce = (
        (1,"已申请"),
        (2,"已通过"),
        (3,"已超时"),
        (4,"已拒绝"),
        (5,"已取消"),
        (6,"已关注"),
        (7,"取消关注"),
        (8,"拉黑"), # 正向拉黑
        (9,"拉黑"), # 反向拉黑
        (10,"取消拉黑")
    )
    send_user = db.Column(db.Integer, comment="用户ID1") # 主动构建关系的用户
    receive_user = db.Column(db.Integer, comment="用户ID2") # 接受关系请求的用户
    '''
    创建方式的类型
    查找  1.手机 2.账号 3.邮箱 3.昵称
    社交  3.群聊
    推荐  4.同城推荐 5. 二维码邀请注册
    '''
    relation_type = db.Column(db.Integer, default=0, comment="构建关系类型")
    # 关系的状态

    status = db.Column(db.Integer, default=0, comment="关系状态")

    def __repr__(self):
        return "用户%s通过%s对%s进行了%s操作" % (self.send_user,self.relation_type, self.receive_user,self.status)

2.前端在输入框输入信息:触发搜索用户信息事件:search_user()

<!DOCTYPE html>
<html>
<head>
    <title>添加好友</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
</head>
<body>
    <div class="app frame avatar update_nickname add_friend" id="app">
    <div class="box">
      <p class="title">添加好友</p>
      <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt="">
      <div class="content">
                   <!-- v-model=account -->
                <input class="nickname" type="text" v-model="account" placeholder="输入昵称/手机/邮箱/魔方账号....">
      </div>
      <div class="friends_list">
        <div class="item" v-for="user in search_user_list">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" :src="avatar_url(user.avatar)" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">{{user.nickname}}</p>
            <p class="time">刚刚搜索</p>
          </div>
          <div class="status">添加</div>
        </div>
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">陈二狗子</p>
            <p class="time">3小时前</p>
          </div>
          <div class="status" @click="change_status">等待通过</div>
        </div>  
      </div>
    </div>
    </div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
                    search_user_list:[], // 搜索出的用户列表
                    search_timer:"", // 输入框内容不变的持续时间
                    account:"", // 用户在输入框输入的内容
                    prev:{name:"",url:"",params:{}},
                    current:{name:"add_friend",url:"add_friend.html",params:{}},
                }
            },
            watch:{
                 // ***监听输入框的内容***
                account(){
                    clearTimeout(this.search_timer);
                    if(this.account.length>0){
                        this.search_timer = setTimeout(()=>{
                               // 2s内内容不发生改变,触发search_user方法
                            this.search_user();
                        },2000);
                    }else{
                          // 如果用户没有在输入框输入任何内容,那搜索用户列表为空
                        this.search_user_list = [];
                    }
                }
            },
            methods:{
                 // 获取用户头像对应的前端url
                avatar_url(avatar){
                    var token = this.game.get("access_token") || this.game.fget("access_token");
                    return `${this.settings.avatar_url}?sign=${avatar}&token=${token}`;
                },
                search_user(){
                    // ***搜索用户**
                    var token = this.game.get("access_token") || this.game.fget("access_token");
          // 查看token是否存在
          if(!token){
            this.game.goFrame("login","login.html", this.current);
            return ;
          }
                      // 查看token是否过期
                    this.game.checkout(this, token, (new_access_token)=>{
                        if(!new_access_token){
                            this.game.print(new_access_token);
                            return ;
                        }
                        this.axios.post("",{
                            "jsonrpc": "2.0",
                            "id": this.uuid(),
                            "method": "User.user.relation",
                            "params": {
                                "account": this.account,  // ***将输入内容发送给后端***
                            }
                        },{
                            headers:{
                                Authorization: "jwt " + new_access_token,
                            }
                        }).then(response=>{
                            this.game.print(response.data.result);
                            if(parseInt(response.data.result.errno)==1000){
                                this.search_user_list = response.data.result.user_list;
                            }else if(parseInt(response.data.result.errno) == 1008){
                                this.search_user_list = [];
                            }else{
                                    this.game.print(response.data);
                            }
                        }).catch(error=>{
                            // 网络等异常
                            this.game.print(error);
                        });

                    });
                },
        close_frame(){
          this.game.outFrame("add_friend");
        },
        add_friend_commit(){
          // 提交搜索信息

        },
        change_status(){
          // 状态修改
        }
            }
        });
    }
    </script>
</body>
</html>
前端在输入框输入信息,触发搜索用户信息事件:search_user()

3.搜索用户信息后端接口:User.user.relation

服务端提供用户搜索功能的视图代码,user/views.py:

from sqlalchemy import or_
from .marshmallow import UserSearchInfoSchema as usis
@jsonrpc.method("User.user.relation")
@jwt_required # 验证jwt
def user_relation(account):
    """搜索用户信息"""
  
    # 1.判断用户是否存在.
    current_user_id = get_jwt_identity()
    user = User.query.get(current_user_id)
    if user is None:
        return {
            "errno": status.CODE_NO_USER,
            "errmsg": message.user_not_exists,
        }

    # 2. 识别搜索用户
    '''根据手机号/用户名/昵称/邮箱 搜索用户'''
    receive_user_list = User.query.filter( or_(
        User.mobile == account,
        User.name == account,
        User.nickname.contains(account),
        User.email==account
    ) ).all()
    
    # 3.如果搜索不到任何用户,则提示搜索的用户不存在
    if len(receive_user_list) < 1:
        return {
            "errno": status.CODE_NO_USER,
            "errmsg": message.receive_user_not_exists,
        }
    # 4.对用户搜索信息进行序列化
    marshmallow = usis(many=True)
    user_list = marshmallow.dump(receive_user_list)

    return {
        "errno": status.CODE_OK,
        "errmsg": message.ok,
        "user_list": user_list
    }

4.用户搜索信息序列化器

marshmallow.py,代码:

class UserSearchInfoSchema(SQLAlchemyAutoSchema):
    """用户搜索信息返回"""
    id = auto_field()
    nickname = auto_field()
    avatar = auto_field()

    class Meta:
        model = User
        include_fk = True
        include_relationships = True
        fields = ["id","nickname","avatar"]
        sql_session = db.session

在上面服务端接口提供的数据中,增加双方关系状态信息.

users/marshmallow.py,代码:

from sqlalchemy import or_,and_
from .models import UserRelation
class UserSearchInfoSchema(SQLAlchemyAutoSchema):
    """用户搜索信息返回"""
    id = auto_field()
    nickname = auto_field()
    avatar = auto_field()
    status = fields.String(dump_only=True) # 在序列化器中添加双方状态信息

    @post_dump()
    def status_relation(self, data, **kwargs):
        # ***查询主动用户和被动用户存在的关系***
        relaionship = UserRelation.query.filter(
            or_(
                and_(UserRelation.send_user==self.context["user_id"], UserRelation.receive_user==data["id"]),
                and_(UserRelation.receive_user==self.context["user_id"], UserRelation.send_user==data["id"]),
            )
        ).first()
        print(relaionship) # 用户3通过None对4进行了1操作
        
        # ***如果二者之间存在关系***
        if relaionship is not None:
            tuple_data = UserRelation.relration_chioce[relaionship.status-1]
            list_data = list(tuple_data)
            list_data.append(relaionship.send_user)
            print(list_data)
            data["status"] = list_data
        else:
            data["status"] = (0,"添加",self.context["user_id"])
        return data

    class Meta:
        model = User
        include_fk = True
        include_relationships = True
        fields = ["id","nickname","avatar","status"]
        sql_session = db.session

5.前端根据不同的关系状态,提供对应的操作菜单

客户端根据不同的关系状态,提供对应的操作菜单,add_friend.html代码:

<!DOCTYPE html>
<html>
<head>
    <title>添加好友</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
</head>
<body>
    <div class="app frame avatar update_nickname add_friend" id="app">
    <div class="box">
      <p class="title">添加好友</p>
      <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt="">
      <div class="content">
                <input class="nickname" type="text" v-model="account" placeholder="输入昵称/手机/邮箱/魔方账号....">
      </div>
      <div class="friends_list">
        <div class="item" v-if="user.status[0]!=9" v-for="user in search_user_list"> 
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" :src="avatar_url(user.avatar)" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">{{user.nickname}}</p>
            <p class="time">刚刚搜索</p>
          </div>
          <div class="status" @click="change_relation(user.id,user.status)">{{user.status[1]}}</div>
        </div>
        <div class="item">
          <div class="avatar">
            <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
            <img class="user_avatar" src="../static/images/avatar.png" alt="">
            <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
          </div>
          <div class="info">
            <p class="username">长昵称都很好</p>
            <p class="time">3小时前</p>
          </div>
          <div class="status">等待通过</div>
        </div>

      </div>
    </div>
    </div>
    <script>
    apiready = function(){
        init();
        new Vue({
            el:"#app",
            data(){
                return {
                    user_id: "", // 当前登陆用户Id
                    search_user_list:[],
                    search_timer:"",
                    account:"",
                    prev:{name:"",url:"",params:{}},
                    current:{name:"add_friend",url:"add_friend.html",params:{}},
                }
            },
            watch:{
                account(){
                    clearTimeout(this.search_timer);
                    if(this.account.length>0){
                        this.search_timer = setTimeout(()=>{
                            this.search_user();
                        },2000);
                    }else{
                        this.search_user_list = [];
                    }
                }
            },
            created(){
                this.user_id = this.game.get("user_id") || this.game.fget("user_id");
            },
            methods:{
                avatar_url(avatar){
                    var token = this.game.get("access_token") || this.game.fget("access_token");
                    return `${this.settings.avatar_url}?sign=${avatar}&token=${token}`;
                },
                search_user(){
                    // 搜素用户
                    var token = this.game.get("access_token") || this.game.fget("access_token");
          if(!token){
            this.game.goFrame("login","login.html", this.current);
            return ;
          }
                    this.game.checkout(this, token, (new_access_token)=>{
                        if(!new_access_token){
                            this.game.print(new_access_token);
                            return ;
                        }
                        this.axios.post("",{
                            "jsonrpc": "2.0",
                            "id": this.uuid(),
                            "method": "User.user.relation",
                            "params": {
                                "account": this.account,
                            }
                        },{
                            headers:{
                                Authorization: "jwt " + new_access_token,
                            }
                        }).then(response=>{
                            this.game.print(response.data.result);
                            if(parseInt(response.data.result.errno)==1000){
                                this.search_user_list = response.data.result.user_list;
                            }else if(parseInt(response.data.result.errno) == 1008){
                                this.search_user_list = [];
                            }else{
                                    this.game.print(response.data);
                            }
                        }).catch(error=>{
                            // 网络等异常
                            this.game.print(error);
                        });

                    });
                },
        close_frame(){
          this.game.outFrame("add_friend");
        },
        add_friend_commit(){
          // 提交搜索信息

        },
        change_relation(user_id,status){
          // ***状态修改***
                    this.game.print(user_id);
                    todo = [];
                    if(status[0] == 0){
                        // 未添加
                        todo.push("添加对方为好友");
                    }else if(status[0]==1){
                        // 已添加
                        todo.push("撤回添加好友操作");
                    }else if(status[0]==2){
                        // 好友关系
                        return;
                    }else if(status[0]==3){
                        // 已超时
                        todo.push("重新发起申请好友");
                    }else if(status[0]==4){
                        // 已拒绝
                        todo.push("重新发起申请好友");
                    }else if(status[0]==5){
                        // 已取消
                        todo.push("重新发起申请好友");
                    }

                    if(status[0]==6){
                        // 已关注
                        todo.push("发起申请好友");
                        todo.push("取消关注");
                    }else if(status[0]==7){
                        todo.push("发起申请好友");
                        todo.push("关注");
                    }else{
                        todo.push("关注");
                    }

                    if(status[0]==8){
                        // 已拉黑
                        todo.push("取消拉黑");
                    }else{
                        todo.push("拉黑");
                    }

                    api.actionSheet({
                        title: '操作',
                        buttons: todo
                    }, (ret, err)=>{
                        if(status[0] == 0 && ret.buttonIndex == 1 ){
                            // 申请添加好友
                            this.game.print(status[0]);
                            this.game.print(ret.buttonIndex);
                        }
                    });

        }
            }
        });
    }
    </script>
</body>
</html>
根据不同的关系状态提供对应的操作菜单
原文地址:https://www.cnblogs.com/libolun/p/14148400.html