zoukankan      html  css  js  c++  java
  • day110:MoFang:重新构造用户关系状态&添加好友&处理好友申请&获取申请好友历史记录&好友列表显示

    目录:

    1.用户关系状态:重新构造

    2.添加好友

    3.处理好友申请

    4.获取申请好友历史记录

    5.好友列表

    day109+day110所学内容流程图

    1.用户关系状态:重新构造

    在day109博客的前提下, 我们对现在的用户关系处理功能在服务端和客户端上面进行重新调整下.

    1.重新构造用户关系模型

    user/models.py,代码:

    class UserRelation(BaseModel):
        """用户关系"""
        __tablename__ = "mf_user_relation"
        relation_status_chioce = (
            (1,"好友"),
            (2,"关注"),
            (3,"拉黑"),
        )
        relation_type_chioce = (
            (1, "手机"),
            (2, "账号"),
            (3, "邮箱"),
            (4, "昵称"),
            (5, "群聊"),
            (6, "二维码邀请注册"),
        )
        send_user = db.Column(db.Integer, comment="用户1") # 主动构建关系的用户
        receive_user = db.Column(db.Integer, comment="用户2") # 接受关系请求的用户
        relation_type = db.Column(db.Integer, default=0, comment="构建关系类型")
        relation_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.relation_status)

    2.修改之前写过的schema序列化器,去除status中的第三个参数

    users/marshmallow.py,代码:

    from sqlalchemy import or_,and_
    from .models import UserRelation
    class UserSearchInfoSchema(SQLAlchemyAutoSchema):
        """用户搜索信息返回"""
        id = auto_field()
        nickname = auto_field()
        avatar = auto_field()
        relation_status = fields.String(dump_only=True)
    
        @post_dump()
        def relation_status_post(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()
            if relaionship is not None:
                data["relation_status"] = UserRelation.relation_status_chioce[relaionship.relation_status-1]
            else:
                data["relation_status"] = (0,"添加")
            return data
    
        class Meta:
            model = User
            include_fk = True
            include_relationships = True
            fields = ["id","nickname","avatar","relation_status"]
            sql_session = db.session

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

    客户端根据不同的关系状态,提供对应的操作菜单,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">
            <!-- for循环 -->
            <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" @click="change_relation(user.id,user.relation_status)">{{user.relation_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 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 {
                        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){
                            // 已添加
                            return ;
                        }else if(status[0]==2){
                            // 关注关系
                            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>
    根据不同的关系状态提供对应的操作菜单

    2.添加好友

    1.添加好友后端接口:User.friend.add

    user/views.py,代码:

    @jsonrpc.method("User.friend.add")
    @jwt_required # 验证jwt
    def add_friend_apply(user_id):
        """申请添加好友"""
        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,
            }
    
        receive_user = User.query.get(user_id)
        if receive_user is None:
            return {
                "errno": status.CODE_NO_USER,
                "errmsg": message.receive_user_not_exists,
            }
    
        # todo 查看是否被对方拉黑了
    
        # 添加一个申请记录到MongoDB中
        document = {
            "send_user_id": user.id,
            "send_user_nickname": user.nickname,
            "send_user_avatar": user.avatar,
            "receive_user_id": receive_user.id,
            "receive_user_nickname": receive_user.nickname,
            "receive_user_avatar": receive_user.avatar,
            "time": datetime.now().timestamp(),  # 操作时间
            "status": 0,
        }
        mongo.db.user_relation_history.insert_one(document)
        return {
            "errno": status.CODE_OK,
            "errmsg": message.ok,
        }

    2.当两个用户关系为未添加时,可以添加好友

    客户端发送请求添加好友,代码:

    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" 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.relation_status)">{{user.relation_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 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 {
                        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){
                            // 已添加
                            return ;
                        }else if(status[0]==2){
                            // 关注关系
                            todo.push("添加对方为好友");
                        }
    
                        api.actionSheet({
                            title: '操作',
                            buttons: todo
                        }, (ret, err)=>{
                              // ***当两个用户关系为未添加时,可以添加对方为好友***
                            if(status[0] == 0 && ret.buttonIndex == 1 ){
                                // ***申请添加好友***
                                var token = this.game.get("access_token") || this.game.fget("access_token");
                                this.axios.post("",{
                                    "jsonrpc": "2.0",
                                    "id": this.uuid(),
                                    "method": "User.friend.add",
                                    "params": {
                                        "user_id": user_id,
                                    }
                                },{
                                    headers:{
                                        Authorization: "jwt " + token,
                                    }
                                }).then(response=>{
                                    if(parseInt(response.data.result.errno)==1000){
                                        // 添加好友成功
                                        this.game.print(">>>> 3")
                                        this.game.print("添加好友成功!");
                                    }else{
                                            this.game.print(response.data);
                                    }
                                }).catch(error=>{
                                    // 网络等异常
                                    this.game.print(error);
                                });
                            }
                        });
    
            }
                }
            });
        }
        </script>
    </body>
    </html>
    当两个用户关系为为添加时,可以添加好友

    3.处理好友申请

    1.处理好友申请-前端

    当两个人不是好友,并且状态为等待通过时,会触发处理好友申请接口

    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-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.relation_status)">{{user.relation_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 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 {
                        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(status);
                        todo = [];
                        if(status[0] == 0){
                            // 未添加
                            if(status[1]=="等待通过"){
                                todo.push("通过");
                                todo.push("拒绝");
                            }else if(status[1]=="添加"){
                                todo.push("添加对方为好友");
                            }
    
                        }else if(status[0]==1){
                            // 已添加
                            return ;
                        }else if(status[0]==2){
                            // 关注关系
                            todo.push("添加对方为好友");
                        }
    
                        api.actionSheet({
                            title: '操作',
                            buttons: todo
                        }, (ret, err)=>{
                            var token = this.game.get("access_token") || this.game.fget("access_token");
                              // 第一种情况
                            if( status[0] == 0 && status[1]=="添加" && ret.buttonIndex == 1 ){
                                // 申请添加好友
                                this.axios.post("",{
                                    "jsonrpc": "2.0",
                                    "id": this.uuid(),
                                    "method": "User.friend.add",
                                    "params": {
                                        "user_id": user_id,
                                    }
                                },{
                                    headers:{
                                        Authorization: "jwt " + token,
                                    }
                                }).then(response=>{
                                    if(parseInt(response.data.result.errno)==1000){
                                        // ***添加好友成功***
                                        api.alert({
                                            title: '提示',
                                            msg: '"添加好友成功!"',
                                        }, function(ret, err){
                                        });
    
                                    }else{
                                            this.game.print(response.data);
                                    }
                                }).catch(error=>{
                                    // 网络等异常
                                    this.game.print(error);
                                });
                              
                               // ***第二种情况:处理好友申请***
                            }else if(status[0] == 0 && status[1]=="等待通过"){
                                // 处理好友申请
                                this.axios.post("",{
                                    "jsonrpc": "2.0",
                                    "id": this.uuid(),
                                    "method": "User.friend.apply",
                                    "params": {
                                        "user_id": user_id,
                                        "agree": ret.buttonIndex==1?true:false,
                                        "search_text": this.account,  // 搜索框中的搜索内容
                                    }
                                },{
                                    headers:{
                                        Authorization: "jwt " + token,
                                    }
                                }).then(response=>{
                                    if(parseInt(response.data.result.errno)==1000){
                                            // 添加好友成功
                                            api.alert({
                                                    title: '提示',
                                                    msg: '"处理好友申请成功!"',
                                            }, function(ret, err){
                                        });
    
                                    }else{
                                            this.game.print(response.data);
                                    }
                                }).catch(error=>{
                                    // 网络等异常
                                    this.game.print(error);
                                });
                            }
                        });
    
            }
                }
            });
        }
        </script>
    </body>
    </html>
    处理好友申请-前端

    2.提供处理好友申请的接口

    客户端进行对应菜单操作的时候,提供好友申请的处理接口,user/views.py代码:

    from sqlalchemy import and_
    @jsonrpc.method("User.friend.apply")
    @jwt_required # 验证jwt
    def add_friend_apply(user_id,agree,search_text):
        """处理好友申请"""
        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,
            }
    
        receive_user = User.query.get(user_id)
        if receive_user is None:
            return {
                "errno": status.CODE_NO_USER,
                "errmsg": message.receive_user_not_exists,
            }
    
        relaionship = UserRelation.query.filter(
            or_(
                and_(UserRelation.send_user == user.id, UserRelation.receive_user == receive_user.id),
                and_(UserRelation.receive_user == user.id, UserRelation.send_user == receive_user.id),
            )
        ).first()
    
        if agree:
            if receive_user.mobile == search_text:
                chioce = 0
            elif receive_user.name == search_text:
                chioce = 1
            elif receive_user.email== search_text:
                chioce = 2
            elif receive_user.nickname == search_text:
                chioce = 3
            else:
                chioce = 4
            
            # ?????
            if relaionship is not None:
                relaionship.relation_status = 1
                relaionship.relation_type = chioce
                db.session.commit()
            else:
                relaionship = UserRelation(
                    send_user=user.id,
                    receive_user=receive_user.id,
                    relation_status=1,
                    relation_type=chioce,
                )
                db.session.add(relaionship)
                db.session.commit()
    
        # 调整mongoDB中用户关系的记录状态
        query = {
            "$or": [{
                "$and": [
                    {
                        "send_user_id": user.id,
                        "receive_user_id": receive_user.id,
                        "time": {"$gte": datetime.now().timestamp() - 60 * 60 * 24 * 7}
                    }
                ],
            }, {
                "$and": [
                    {
                        "send_user_id": receive_user.id,
                        "receive_user_id": user.id,
                        "time": {"$gte": datetime.now().timestamp() - 60 * 60 * 24 * 7}
                    }
                ],
            }]
        }
        if agree:
            argee_status = 1
        else:
            argee_status = 2
    
        ret = mongo.db.user_relation_history.update(query, {"$set":{"status":argee_status}})
        if ret and ret.get("nModified") < 1:
            return {
                "errno": status.CODE_UPDATE_USER_RELATION_ERROR,
                "errmsg": message.update_user_relation_fail,
            }
        else:
            return {
                "errno": status.CODE_OK,
                "errmsg": message.update_success,
            }

    4.获取申请好友历史记录

    1.服务端提供接口:User.relation.history

    在添加好友页面刚打开时,直接获取与当前用户存在申请好友历史的所有记录.

    服务端提供api接口, user/views.py,代码:

    @jsonrpc.method("Use.relation.history")
    @jwt_required # 验证jwt
    def history_relation():
        """查找好友关系历史记录"""
        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,
            }
    
        query = {
            "$or":[
                {"send_user_id":user.id,"time": {"$gte": datetime.now().timestamp() - 60 * 60 * 24 * 7}},
                {"receive_user_id": user.id,"time": {"$gte": datetime.now().timestamp() - 60 * 60 * 24 * 7}},
            ]
        }
        document_list = mongo.db.user_relation_history.find(query,{"_id":0})
        data_list = []
        for document in document_list:
            if document.get("send_user_id") == user.id and document.get("status") == 0:
                document["status"] = (0,"已添加")
            elif document.get("receive_user_id") == user.id and document.get("status") == 0:
                document["status"] = (0a, "等待通过")
            elif document.get("status") == 1:
                document["status"] = (1, "已通过")
            else:
                document["status"] = (2, "已拒绝")
    
            data_list.append(document)
    
        return {
            "errno": status.CODE_OK,
            "errmsg": message.ok,
            "data_list": data_list,
        }

    2.前端显示申请好友的所有历史记录

    客户端代码:

    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-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.relation_status)">{{user.relation_status[1]}}</div>
            </div>
            <div class="item" v-for="relation in history_list">
              <div class="avatar">
                <img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
                <img class="user_avatar" v-if="relation.send_user_id==user_id" :src="avatar_url(relation.receive_user_avatar)" alt="">
                <img class="user_avatar" v-else :src="avatar_url(relation.send_user_avatar)" alt="">
                <img class="avatar_border" src="../static/images/avatar_border.png" alt="">
              </div>
              <div class="info">
                <p class="username" v-if="relation.send_user_id==user_id">{{relation.receive_user_nickname}}</p>
                <p class="username" v-else>{{relation.send_user_nickname}}</p>
                <p class="time">{{game.time_format(relation.time)}}</p>
              </div>
              <div class="status">{{relation.status[1]}}</div>
            </div>
          </div>
        </div>
        </div>
        <script>
        apiready = function(){
            init();
            new Vue({
                el:"#app",
                data(){
                    return {
                        user_id: "", // 当前登陆用户Id
                        search_user_list:[],
                        search_timer:"",
                        account:"",
                        history_list:[],
                        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("id") || this.game.fget("id");
                    this.get_relation_history();
                },
                methods:{
                    get_relation_history(){
                        // ***获取历史信息记录***
                        var token = this.game.get("access_token") || this.game.fget("access_token");
                        this.game.checkout(this, token, (new_access_token)=>{
                            this.axios.post("",{
                                "jsonrpc": "2.0",
                                "id": this.uuid(),
                                "method": "Use.relation.history",
                                "params": {}
                            },{
                                headers:{
                                    Authorization: "jwt " + token,
                                }
                            }).then(response=>{
                                this.game.print(response.data.result);
                                if(parseInt(response.data.result.errno)==1000){
                                    this.history_list = response.data.result.data_list;
                                }else if(parseInt(response.data.result.errno) == 1008){
                                    this.history_list = [];
                                }else{
                                        this.game.print(response.data);
                                }
                            }).catch(error=>{
                                // 网络等异常
                                this.game.print(error);
                            });
                        })
                    },
                    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(status);
                        todo = [];
                        if(status[0] == 0){
                            // 未添加
                            if(status[1]=="等待通过"){
                                todo.push("通过");
                                todo.push("拒绝");
                            }else if(status[1]=="添加"){
                                todo.push("添加对方为好友");
                            }
    
                        }else if(status[0]==1){
                            // 已添加
                            return ;
                        }else if(status[0]==2){
                            // 关注关系
                            todo.push("添加对方为好友");
                        }
    
                        api.actionSheet({
                            title: '操作',
                            buttons: todo
                        }, (ret, err)=>{
                            var token = this.game.get("access_token") || this.game.fget("access_token");
                            if( status[0] == 0 && status[1]=="添加" && ret.buttonIndex == 1 ){
                                // 申请添加好友
                                this.axios.post("",{
                                    "jsonrpc": "2.0",
                                    "id": this.uuid(),
                                    "method": "User.friend.add",
                                    "params": {
                                        "user_id": user_id,
                                    }
                                },{
                                    headers:{
                                        Authorization: "jwt " + token,
                                    }
                                }).then(response=>{
                                    if(parseInt(response.data.result.errno)==1000){
                                        // 添加好友成功
                                        api.alert({
                                            title: '提示',
                                            msg: '"添加好友成功!"',
                                        }, function(ret, err){
                                        });
    
                                    }else{
                                            this.game.print(response.data);
                                    }
                                }).catch(error=>{
                                    // 网络等异常
                                    this.game.print(error);
                                });
                            }else if(status[0] == 0 && status[1]=="等待通过"){
                                // 处理好友申请
                                this.axios.post("",{
                                    "jsonrpc": "2.0",
                                    "id": this.uuid(),
                                    "method": "User.friend.apply",
                                    "params": {
                                        "user_id": user_id,
                                        "agree": ret.buttonIndex==1?true:false,
                                        "search_text": this.account,  // 搜索框中的搜索内容
                                    }
                                },{
                                    headers:{
                                        Authorization: "jwt " + token,
                                    }
                                }).then(response=>{
                                    if(parseInt(response.data.result.errno)==1000){
                                            // 添加好友成功
                                            api.alert({
                                                    title: '提示',
                                                    msg: '"处理好友申请成功!"',
                                            }, function(ret, err){
                                        });
    
                                    }else{
                                            this.game.print(response.data);
                                    }
                                }).catch(error=>{
                                    // 网络等异常
                                    this.game.print(error);
                                });
                            }
                        });
    
            }
                }
            });
        }
        </script>
    </body>
    </html>
    前端显示申请好友的所有历史记录

    3.main.js提供时间格式化方法

    main.js提供时间格式化,代码:

        time_format(time){
            // 时间距离格式化显示
            var now_time = parseInt((new Date() - 0) / 1000); // 当前客户端的秒时间戳
            var has_time = now_time - time;
            if(has_time<5 * 60){
                return "刚刚";
            }else if(has_time<30*60){
                return parseInt(has_time/60)+"分钟前";
            }else if(has_time<60*60){
                return "半个小时前";
            }else if(has_time<12*60*60){
                return parseInt(has_time/60/60)+"小时前";
            }else if(has_time<24*60*60){
                return "半天前";
            }else if(has_time<7*24*60*60){
                return parseInt(has_time/24/60/60)+"天前";
            }else if(has_time<14*24*60*60){
                return "一周前";
            }else if(has_time<30*24*60*60){
                return "半个月前";
            }
        }
        

    5.好友列表

    1.好友列表页面展示好友列表数据

    html/friends_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" v-for="user in friends">
            <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="fruit">果子:{{user.fruit}}</p>
            </div>
            <div v-if="user.fruit_status==1" class="behavior pick">摘</div>
            <div v-if="user.fruit_status==2" class="behavior protect">护</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,
                        is_send_ajax:false,
                        prev:{name:"",url:"",params:{}},
                        current:{name:"friend_list",url:"friend_list.html",params:{}},
                    }
                },
                created(){
            this.get_friends();
                    this.get_friends_listener();
            this.page_out_listener();
                },
                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}`;
                    },
                    get_friends_listener(){
                        // 监听下拉刷新获取好友列表信息
                        api.setRefreshHeaderInfo({
                                loadingImg: 'widget://image/refresh.png',
                                bgColor: null,
                                textColor: '#fff',
                                textDown: '下拉刷新...',
                                textUp: '松开刷新...'
                        }, (ret, err)=>{
                                //在这里从服务器加载数据,加载完成后调用api.refreshHeaderLoadDone()方法恢复组件到默认状态
                                this.get_friends();
                                setTimeout(()=>{
                                    api.refreshHeaderLoadDone();
                                },4000);
                        });
                    },
            page_out_listener(){
              // 监听什么时候需要退出当前页面
              api.addEventListener({
                  name: 'out_page_to_user'
              }, (ret, err)=>{
                  this.goto_home();
              });
            },
                    get_friends(){
                        if(this.is_send_ajax){
                            return ;
                        }
                        // ***通过请求获取当前用户的好友列表***
                        var token = this.game.get("access_token") || this.game.fget("access_token");
                        this.game.checkout(this, token, (new_access_token)=>{
                            this.is_send_ajax = true;
                            this.axios.post("",{
                                "jsonrpc": "2.0",
                                "id": this.uuid(),
                                "method": "User.friend.list",
                                "params": {
                                    "page": this.page
                                }
                            },{
                                headers:{
                                    Authorization: "jwt " + token,
                                }
                            }).then(response=>{
                                if(parseInt(response.data.result.errno)==1000){
                                    if(this.page+1 == response.data.result.pages){
                                        this.is_send_ajax = true;
                                    }else{
                                        this.is_send_ajax = false;
                                        this.page+=1;
                                    }
                                    if(this.page>1){
                                        api.refreshHeaderLoadDone();
                                    }
                                    this.friends = response.data.result.friend_list.concat(this.friends);
                                }else if(parseInt(response.data.result.errno) == 1008){
                                    this.friends = [];
                                }else{
                                        this.game.print(response.data);
                                }
                            }).catch(error=>{
                                // 网络等异常
                                this.game.print(error);
                            });
                        })
                    },
            goto_home(){
              // 退出当前页面
              this.game.outFrame("friend_list","friend_list.html", this.current);
            },
                }
            });
        }
        </script>
    </body>
    </html>
    好友列表页面展示好友列表数据

    2.服务端提供展示好友列表数据接口:User.friend.list

    服务端提供API接口,user/views.py代码:

    @jsonrpc.method("User.friend.list")
    @jwt_required # 验证jwt
    def list_friend(page=1,limit=2):
        """好友列表"""
        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,
            }
    
        pagination = UserRelation.query.filter(
            or_(
                and_(UserRelation.send_user == user.id),
                and_(UserRelation.receive_user == user.id),
            )
        ).paginate(page,per_page=limit)
        user_id_list = []
        for relation in pagination.items:
            if relation.send_user == user.id:
                user_id_list.append(relation.receive_user)
            else:
                user_id_list.append(relation.send_user)
    
        # 获取用户详细信息
        user_list = User.query.filter(User.id.in_(user_id_list)).all()
        friend_list = [{"avatar":user.avatar,"nickname":user.nickname,"id":user.id,"fruit":0,"fruit_status":0} for user in user_list]
        pages = pagination.pages
        return {
            "errno": status.CODE_OK,
            "errmsg": message.ok,
            "friend_list": friend_list,
            "pages": pages
        }
  • 相关阅读:
    redis介绍;特性介绍
    日常2018/4/9---b/s和c/s架构分别是什么?区别?
    持续集成实践---基于ant+jmeter+jenkins接口CI
    面向过程 和 面向对象个人理解
    记一次vc++6.0中程序正常,转 vs2019 c++后报错的问题
    C# 调用C++ dll EntryPointNotFoundException错误
    uniapp踩坑记录(持续更新)
    uniapp引用组件rate评分无法点击引起对style scoped学习
    sql server之time字段详解
    sql server之timestamp字段详解(转)
  • 原文地址:https://www.cnblogs.com/libolun/p/14148736.html
Copyright © 2011-2022 走看看