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
    }
原文地址:https://www.cnblogs.com/libolun/p/14148736.html