Engee 文档
Notebook

用 GenieFramework 制作带动态表格的机场记分牌

本文将介绍如何创建一个网络应用程序--带有航班表的机场记分牌。要熟悉 GenieFramework 中网络应用程序的基本逻辑,建议阅读介绍性文章。在这里,我们将重点介绍通过DataTable 处理表格、与 CSV 文件交互以及使用异步循环动态更新数据。我们将特别关注为什么DataTable 用于显示表格,而不仅仅是DataFrame

board.png

应用代码

使用 GenieFramework
使用 Stipple
使用 Stipple.Tables
使用 DataFrames
使用日期
使用 CSV

函数 generate_flight_data()
    DataFrame(
        "航班号"=>["SU123", "AF456", "BA789"]
        "目的地"=>["莫斯科""巴黎""伦敦"]
        "Departure Time" => [Dates.format(now() + Hour(rand(1:5)), "HH:MM") for _ in 1:3]
        "状态" => ["准时""延迟""取消"] )
    )
结束

@app begin
    @out current_time = "当前时间:" * Dates.format(now(), "HH:MM:SS")
    @out flight_table = DataTable(DataFrame())  # 初始为空表

    @onchange isready begin
        initial_df = generate_flight_data()
        CSV.write("flight_data.csv", initial_df)
        flight_table = DataTable(initial_df)

        @async while true
            sleep(5)
            current_time = "当前时间:" * Dates.format(now(), "HH:MM:SS")
            df = CSV.read("flight_data.csv", DataFrame, types=String)
            df.Status[rand(1:3)] = rand(["准时""延误""取消"])
            CSV.write("flight_data.csv", df)
            flight_table = DataTable(df)
        结束
    结束
结束

函数 ui()
    [
        h3("{{current_time}}"),
        table(:flight_table; dense=true, flat=true)
    ]
结束

@page("/", ui)

程序逻辑:逐步分析

连接软件包

使用了以下软件包:

  • GenieFramework:创建网络应用程序的主要框架。
  • Stipple:提供服务器和界面之间的反应和通信。
  • Stipple.Tables:提供DataTable ,以便在网络界面显示表格。
  • DataFrames,Dates,CSV:需要用于表格数据、时间格式化和文件操作。
    每个软件包都扮演着不同的角色,为应用程序提供一套最基本的工具。

数据生成

函数generate_flight_data() 可创建航班表:

  • 返回一个包含四列的对象DataFrame
    -FlightNumber: 航班号("SU123"、"AF456"、"BA789")。
    -Destination: 目的地("莫斯科"、"巴黎"、"伦敦")。
    -DepartureTime: 出发时间,格式为 "HH:MM",基于当前时间加上随机偏移(1-5 小时)。
    -Status: 航班状态("准时"、"延误"、"取消")。
  • 该函数模拟记分牌的初始数据,然后随着应用程序的运行进行修改。

数据模型:变量

@app 块定义了数据模型:

  • @out current_time:一个包含当前时间字符串("Current time: HH:MM:SS")的反应式变量。启动时初始设置,随后更新。
  • @out flight_table:一个DataTable 类型的反应式变量,最初为空 (DataTable(DataFrame()))。加载应用程序时,它将被填入数据。
    这些变量可在界面中显示,并在发生变化时自动更新。

数据模型:初始化和更新

@onchange isready 处理程序管理应用程序逻辑:

  • isready 及其作用
    -isready 是一个嵌入式反应式 Stipple 变量,初始值为false 。当客户端(浏览器)完全加载页面并通过 WebSocket 与服务器建立连接后,它就会变成true
    -@onchange isready 意味着,当isreadyfalse 变为true 时,即应用程序首次在客户端成功加载时,代码块内的代码会被执行一次。这并不意味着更新仅限于这一点--@onchange 运行一次代码,但我们可以在其中启动持久进程。
    • 我们使用@onchange isready ,以确保数据初始化和更新周期的启动仅在界面准备好运行时发生。否则,代码可能会在与客户端建立通信之前过早执行,从而导致同步错误。
  • 初始化**:
    • 通过generate_flight_data() 创建初始表initial_df
    • 数据被写入文件flight_data.csv
      -flight_table 通过DataTable(initial_df) 更新。
  • 异步循环
    • 通过@async while true 运行,创建后台任务。
    • 每 5 秒 (sleep(5)):
      • 刷新current_time
      • 从文件中读取数据,参数types=String 保存字符串格式。
      • 随机改变一个航班的状态。
      • 更新后的数据将写入文件并分配给flight_table

界面

函数ui() 定义了外观:
-h3("{{current_time}}")**:显示自动更新的当前时间。

  • table(:flight_table; dense=true, flat=true):创建与flight_table 相链接的表格。
    -dense=true 使表格更加紧凑。
    -flat=true 删除阴影,使设计更简洁。
    -DataTable 根据列名自动生成标题DataFrame

页面注册

  • @page("/", ui):表示接口可通过根路由"/"访问。至此,应用程序配置完成。

为什么是DataTable ,而不是DataFrame

DataFrame - 是 Julia 在代码中处理表格数据的强大工具。它非常适合处理数据:过滤、排序和计算。不过,DataFrame 本身并不打算在网页界面上显示。它在程序内存中表示数据,但没有将数据传输到浏览器或渲染为 HTML 表格的内置逻辑。

DataTable Stipple.Tables 解决了这一问题:

  • 反应DataTable 与 Stipple 反应系统集成。当flight_table 中的数据发生变化时,界面会自动更新,无需手动重绘表格。
  • 网络格式化DataTableDataFrame 转换为与 Quasar(Stipple 用于界面的框架)兼容的结构,添加所需的标题和数据格式。
  • 简单:使用table(:flight_table) ,我们无需编写复杂的 HTML 或 JavaScript 代码即可显示数据。如果只使用DataFrame ,我们就必须手动将其转换为字典数组 (Vector{Dict}) 并将其传递给接口,这样就会使代码变得复杂。

因此,DataFrame 是 "原始 "数据,而DataTable 则是它与网络界面之间的 "桥梁",提供了便利性和自动化。


如何运行应用程序?

进入包含当前脚本的文件夹,执行下面的方框。

这将打开一个包含网络应用程序的窗口。

如果没有在单独的标签页中打开,请单击输出单元格中的链接。

-match(r"'(https?://[^']+)'" 允许您使用[正则表达式]根据 engee.genie.start 函数的输出查找链接(https://engee.com/helpcenter/stable/ru/interactive-scripts/language_basics/regex.html) -Markdown.parse 用于在输出单元格中显示 "可点击 "链接。

In [ ]:
using Markdown
cd(@__DIR__)

app_url = string(engee.genie.start(string(@__DIR__,"/app.jl")))

Markdown.parse(match(r"'(https?://[^']+)'",app_url)[1])

结论

本应用程序演示了使用动态表格创建机场记分牌的过程。我们介绍了生成数据、将数据保存到文件、通过异步循环更新数据以及使用DataTable 显示数据。每个代码块都执行了各自的任务,提供了简约而实用的实现方式。DataTable 是简化表格数据与网络界面整合的关键要素,而这是通常的DataFrame 无法实现的。要充分理解其中的逻辑,我们建议您浏览一下整个代码--这将有助于您了解所有部分之间的关系。