谈论一些代码实现的逻辑(四)

谈论一些代码实现的逻辑(四)


前言

上一篇博客介绍了项目的目录结构,已经有了一点对项目的认识,接下来我将具体简述一些主要功能的代码实现的逻辑(原本我是想具体讲述的,然后发现太多了,于是就挑选几个来将一下实现的逻辑吧)

其余更多代码实现还是直接看源码吧


1. 登录功能

主要分为登录、注册、找回密码

有两个登录的地方,一个是介绍页面、一个是星云笔记页面

前者的前端是用bootstrap的选项卡功能实现的,后者则是加上了模态框。

至于其对应的js代码,我也是放在 /resource/js/login.js 文件中

实现了发送邮件、登录、注册、退出登录的事件

另外,我还添加了接受经度和维度,获取用户的地理位置的代码,及用户每次登录、以及用户注册时会获取(但是,这个功能要支持https服务才能开启,不然会被拦截,不能实现)

2. 悬浮框功能

这是一个小的功能,方便用户的快速跳转到主要功能页面

其主要是依靠css样式和js的鼠标监听事件来完成的

<link rel="stylesheet" href="/css/悬浮框.css"/>
<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>



 <div class="Box_xuanfu">
        <div class="box_xuanfu">
            <ion-icon name="apps-sharp"></ion-icon>
        </div>
        <div>
            <a href="/notebook" class="panel" >
               <ion-icon name="brush"></ion-icon>
                 <span class="tooltiptext">笔记</span>

            </a>
            <a href="/person/{{session.get('userid')}}" class="panel" >
               <ion-icon name="person"></ion-icon>
            </a>
            <a href="/chatroom/index" class="panel" >
                <ion-icon name="chatbox-ellipses"></ion-icon>
            </a>
            <a href="/home/{{session.get('userid')}}" class="panel" >
              <ion-icon name="home"></ion-icon>

            </a>
            <a href="/tools" class="panel" >
              <ion-icon name="construct"></ion-icon>

            </a>
            <a href="#" class="panel" >
              <ion-icon name="settings"></ion-icon>

            </a>
        </div>
    </div>
    
<script src="/js/悬浮框.js"></script>

3. markdown编辑器和富文本编辑器的共同集成

星云笔记是支持使用markdown编辑器和富文本编辑器的共同使用。

而我是如何区分哪些文章是由markdown语法编写,哪些文章是html语法呢。

可以通过在article表中插入一列,来区别,比如我用1表示是markdown,用表示是文本,
然后我可以在提交文章的代码中添加这个判断参数,传给后端处理,

我定义了一个函数,用来区分它们


def is_markdown(articleid):
    article = Article()
    result = article.find_is_markdown_by_id(articleid)
    if result and result.is_markdown == 1:
        return "md_article"
    else:
        return "article"


将返回的值拼接到URL中,就能区别开来

markdown语法写的:
http://www.whtuu.cn/notebook/md_article/41


富文本写的:
http://www.whtuu.cn/notebook/article/42

4. 工具库的类别的分类

在工具库的工具分类时,我是通过给每一个类别映射一个数字


        # 1代表AI工具、11代表AI工具下的”常用"、12代表AI工具下的”AI图像工具"、13代表AI工具下的”AI聊天工具"、14代表AI工具下的”AI 视频工具"
        # 2代表生信软件,21、22、23、24
        # 3代表生信网站,31、32、33、34
        # 4代表消息获取
        # 5代表设计美化
        # 6代表学习网站
        # 7代表其它

然后在提交工具的时候,将每个类别对应的数字提交到数据库就行

同样我也定义了一个代码用来返回对应的分类名称



# 根据tools_type命名对应的分类信息
def ming_tools_by_type(type):
    primary_category = ""
    secondary_category = ""
    if type.startswith("1"):
        primary_category = "AI工具"
        if type == "11":
            secondary_category = "常用"
        elif type == "12":
            secondary_category = "AI图像工具"
        elif type == "13":
            secondary_category = "AI聊天工具"
        elif type == "14":
            secondary_category = "AI视频工具"
    elif type.startswith("2"):
        primary_category = "生信软件"
        if type == "21":
            secondary_category = "常用"
        elif type == "22":
            secondary_category = "基因相关"
        elif type == "23":
            secondary_category = "环境相关"
        elif type == "24":
            secondary_category = "其它"
    elif type.startswith("3"):
        primary_category = "生信网站"
        if type == "31":
            secondary_category = "常用"
        elif type == "32":
            secondary_category = "基因相关"
        elif type == "33":
            secondary_category = "环境相关"
        elif type == "34":
            secondary_category = "其它"
    elif type.startswith("4"):
        primary_category = "消息获取"
        if type == "41":
            secondary_category = "日常"
        elif type == "42":
            secondary_category = "生信相关"
        elif type == "43":
            secondary_category = "AI相关"
        elif type == "44":
            secondary_category = "古诗词文化"
    elif type == "5":
        primary_category = "设计美化"

    elif type == "6":
        primary_category = "学习网站"

    elif type == "7":
        primary_category = "其他"

    return primary_category, secondary_category


5. 在flask中引入echarts图表

主要是将从后端获取的数据填充到前端的图表中

大致分为两类:

一类是 返回 xxx.dump_options_with_quotes()


# 用户的文章条形图
@py_echarts.route("/py_echarts/bar-article-user", methods=["POST", "GET"])
def get_bar_chart_user():
    userid = request.form.get("userid")
    article = Article()
    favorite = Favorite()
    comment = Comment()
    favorite_count = favorite.query_my_favorite_count(userid)
    favorited_count = favorite.query_my_article_favorited_count(userid)
    article_count = article.get_count_user_except_drafted(userid)
    drafted_count = article.get_count_user_drafted(user_id=userid)
    comment_count = comment.query_comments_count_by_userid(userid)
    commented_count = comment.query_comments_count_by_articleid(userid)
    read_count = article.get_readcount_by_user(userid)
    recommend_count = article.query_recommend_count_by_user(userid)
    hide_count = article.query_hide_count_by_user(userid)

    # 设置条形图的标签和值
    bar = (
        Bar()
        .add_xaxis(
            ["收藏数", "被收藏数", "文章数", "草稿数", "评论数", "被评论数", "阅读数", "推荐数", "隐藏数"])  # x轴标签

        .add_yaxis("用户文章信息",
                   [favorite_count, favorited_count, article_count, drafted_count, comment_count, commented_count,
                    read_count, recommend_count, hide_count]
                   , itemstyle_opts=opts.ItemStyleOpts(color="#749f83"))  # y轴值,对应上面的标签
    )

    return bar.dump_options_with_quotes()


然后在前端页面的js代码中发送ajax请求给上面定义的接口

 //文章总结的条形图
    var chart_bar = echarts.init(document.getElementById('bar-article'), 'white', {renderer: 'canvas'});
    $(
        function () {
            fetchData_bar(chart_bar);

        }
    );

    function fetchData_bar() {
        $.ajax({
            type: "POST",
            data: {
                userid: userid
            },
            url: "/py_echarts/bar-article-user",
            dataType: "json",
            success: function (result) {
                chart_bar.setOption(result);
            }
        });
    }

另一类则是,使用flask 的render_template() 函数将 生成的嵌入式代码 rendered_chart = c.render_embed(),传给前端;



# 管理后台的用户数据
@py_echarts.route("/person/admin/user")
def admin_user():
    user = Users()
    user_at = user.find_by_admin()
    user_count = user.get_count_all_user()
    user_locations = user.find_all_users_location()
    # 在这里执行生成地图的代码
    from pyecharts import options as opts


    # 创建 Geo 地图实例
    c = (
        Geo(InitOpts(width="1000px", height="1000px"))

        .add_schema(maptype="china")  # 设置地图类型为中国地图
    )

    data = []
    # 遍历 user_locations,添加每个用户的地理位置到地图中
    for userid, time, lon, lat in user_locations:
        # 添加坐标点,这里假设每个用户的位置都有一个唯一的名称
        # 例如,可以使用时间戳或者用户ID作为名称
        name = userid
        c.add_coordinate(name, lon, lat)
        value = str(time)  # 或者其他您想展示的值

        # 将当前用户的位置和值添加到 data 列表中
        data.append((name, value))

    series_name = "用户来源"

    c.add(series_name, data, type_=ChartType.EFFECT_SCATTER)

    # 设置系列和全局选项
    c.set_series_opts(label_opts=opts.LabelOpts(is_show=False))  # 设置标签不显示
    c.set_global_opts(
        visualmap_opts=opts.VisualMapOpts(is_show=False),  # 设置视觉映射配置项,比如颜色条
        title_opts=opts.TitleOpts(title="用户地理位置分布")  # 设置图表标题
    )

    # 生成嵌入代码
    rendered_chart = c.render_embed()
    return render_template('/shujumianbang/user_admin.html',
                           user_at=user_at, user_count=user_count, chart=rendered_chart)


然后,在前端使用jinji2的语法 {{chart | safe}},将图表插入


        <div class="row">
            <div class="col-md-12">
                <div class="card">
                    <div class="card-body">
                        <div class="row" style="text-align: center;">
                             <div class="col-6">
                                <div class="d-md-flex align-items-center " style="width:900px">
                                    <h2>用户的来源记录</h2>
                                </div>
                                <div style="width:1600px; height:900px;">
                                    {{chart |safe}}
                                </div>
                            </div>

                        </div>
                    </div>
                </div>
            </div>


        </div>


6. 聊天室的实现

要安装flask_socketio ,创建socketio实例

控制台代码:



@chatroom.route("/chatroom/chatroom", methods=['POST', 'GET'])
def chatroom_chatroom():
    if session.get('islogin') is None:
        return redirect(url_for('index'))
    else:
        user_id = session.get('userid')
        message = Message()
        message_result = message.get_messages()
        # users = Users().find_all_users_all()
        follow = Follow()
        user_guanzhu = follow.get_follow_users_with_details(userid=session.get('userid'))
        avatar = message.get_at_avatar(user_id=user_id)
        # nickname = session.get('nickname')
        return render_template("/chatroom/chatroom.html", message_result=message_result, user_guanzhu=user_guanzhu,
                               avatar=avatar)



# 连接聊天室
@socketio.on('connect', namespace='/chatroom/chatroom')
def connect():
    print('连接成功!!')


# 加入房间
@socketio.on('joined', namespace='/chatroom/chatroom')
def joined(information):
    # 'joined'路由是传入一个room_name,给该websocket连接分配房间,返回一个'status'路由
    room_name = 'chat room'
    user_name = session.get('nickname')
    print(user_name)
    join_room(room_name)
    emit('status', {'server_to_client': user_name + ' enter the room'}, 'room=room_name')


# 接收聊天信息
@socketio.on('text', namespace='/chatroom/chatroom')
def text(information):
    text = information.get('text')
    nick_name = session.get('nickname')  # 获取用户名称
    user_id = session.get('userid')  # 获取用户ID
    communicate_user = request.form.get('communicate_user')

    Message().insert_message(content=text, communicate_userid=communicate_user)  # 将聊天信息插入数据库,更新数据库
    create_time = time.strftime('%Y-%m-%d %H:%M:%S')
    avatar = Message().get_at_avatar(user_id=user_id)  # 获取用户头像

    # 返回聊天信息给前端
    emit('message', {
        'nickname': nick_name,
        'text': text,
        'create_time': create_time,
        'avatar': avatar,
    })
    

前后台对接的js代码:

$(document).ready(function () {
        //创建实例
        socket = io.connect('https://' + document.domain + ':' + location.port + '/chatroom/chatroom');
        log('xxqqq', socket)
        // alert()


        socket.on('connect', function () {
            log('连接成功');
        });

        socket.on('message', function (data) {
            Username = data.nickname
            text = data.text
            create_time = data.create_time
            var avatar_url = data.avatar
            log(Username + ':' + text)
             var deleteButton = "";
    // if (userid === session.get("userid")) {
            deleteButton = "<button class='delete-chedi btn btn-outline-success' data-messageid='" + data.message_id + "'>❌</button>";
    // }

            if (filepath) {
                $(".chat-discussion").append("<div class='chat-message left'> <img class='message-avatar' src='/chat_room/images/" + avatar_url + "' alt='' > <div class='message'><a class='message-author' > " + Username + "</a> <span class='message-date'>" + create_time + " </span><span class='message-content'> <img src='" + filepath + "' class='imgchat' style='height: 100px;weight:100px'/>" + text + "</span> " + deleteButton +"</div> </div>");
                $(".img").attr("src", '');
            } else {
                $(".chat-discussion").append("<div class='chat-message left'> <img class='message-avatar' src='/chat_room/images/" + avatar_url + "' alt='' > <div class='message'><a class='message-author' > " + Username + "</a> <span class='message-date'>" + create_time + " </span><span class='message-content'>" + text + "</span>" + deleteButton + "  </div> </div>");
            }
        });

        $('.enter').keypress(function (e) {
            var code = e.keyCode || e.which;
            if (code == 13) {
                //获取聊天框聊天内容
                var Texttext = $('.enter').val();
                //清空聊天框
                $('.enter').val('');
                //向后端发送聊天内容
                socket.emit('text', {'text': Texttext});
            }
        });
        $('#Emoji').change(function () {
            //一:
            console.log($(this).val());
            //二:
            $("#Emoji").val();//获取当前选择项的值.

            var options = $("#Emoji option:selected");//获取当前选择项.
            options.val();//获取当前选择项的值.
            $('.enter').val($('.enter').val() + options.val());
            console.log(options.val());
        })

    });


总结

差不多就到这吧,其实,这个项目感觉并没有达到预期,只能说与我最开始想的样子不太一样,但是不管怎么说,也就先做到这一步了,虽然有些功能还有问题,需要完善。

寂寞空庭春欲晚,梨花满地不开门

–2024-3-22

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星石传说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值