跳转到内容
打开/关闭菜单
  • 451 条目
  • 808 文件
  • 22 用户
  • 9259 编辑
Blockland Wiki
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

模块:OWMOMarket

来自Blockland Wiki
KK​(留言 | 贡献)2026年5月8日 (五) 17:54的版本 (创建页面,内容为“local p = {} local extData = mw.ext.externalData function p.renderSidebar(frame) -- 1. 获取最新期数 local latest_data = extData.getDatabaseData{ db = 'wp_db', from = 'wp_owmc_currency_rates', orderBy = 'year DESC, month DESC', limit = 1 } if not latest_data or not latest_data[1] then return "暂无行情数据" end local max_y = tonumber(latest_data[1].year) local max_m = tonumber(latest_data[1].month) -- 2.…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

此模块的文档可以在模块:OWMOMarket/doc创建

local p = {}
local extData = mw.ext.externalData

function p.renderSidebar(frame)
    -- 1. 获取最新期数
    local latest_data = extData.getDatabaseData{
        db = 'wp_db', from = 'wp_owmc_currency_rates',
        orderBy = 'year DESC, month DESC', limit = 1
    }
    if not latest_data or not latest_data[1] then return "暂无行情数据" end
    local max_y = tonumber(latest_data[1].year)
    local max_m = tonumber(latest_data[1].month)

    -- 2. 计算 8 期前(1 个月前)的期数
    local current_abs = max_y * 104 + max_m
    local old_abs = current_abs - 8
    local old_y = math.floor((old_abs - 1) / 104)
    local old_m = ((old_abs - 1) % 104) + 1

    -- 3. 抓取本期和上月的数据及元数据
    local current_rates = extData.getDatabaseData{ db = 'wp_db', from = 'wp_owmc_currency_rates', where = string.format("year=%d AND month=%d", max_y, max_m), limit = 200 }
    local old_rates = extData.getDatabaseData{ db = 'wp_db', from = 'wp_owmc_currency_rates', where = string.format("year=%d AND month=%d", old_y, old_m), limit = 200 }
    local meta_data = extData.getDatabaseData{ db = 'wp_db', from = 'wp_owmc_currency_meta', limit = 200 }

    -- 4. 数据映射与处理
    local meta_map, old_map = {}, {}
    if meta_data then for _, r in ipairs(meta_data) do meta_map[r.currency_code] = r.currency_name end end
    if old_rates then for _, r in ipairs(old_rates) do old_map[r.currency_code] = tonumber(r.rate) end end

    local stats = {}
    for _, row in ipairs(current_rates) do
        local code = row.currency_code
        local c_rate = tonumber(row.rate)
        local o_rate = old_map[code]

        if c_rate and o_rate and c_rate > 0 then
            -- 计算相对价值 (1 本币 = ? 参照),并算出涨跌幅
            local val_current = 1 / c_rate
            local val_old = 1 / o_rate
            local pct = ((val_current - val_old) / val_old) * 100
            table.insert(stats, { code = code, name = meta_map[code] or code, val = val_current, pct = pct })
        end
    end

    -- 按照涨跌幅降序排序
    table.sort(stats, function(a, b) return a.pct > b.pct end)

    -- 5. 开始渲染 HTML
    local html = mw.html.create('div')
        :cssText("width: 260px; float: right; clear: right; margin: 0 0 16px 16px; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.03); font-family: -apple-system, 'Segoe UI', sans-serif;")

    local function renderRow(item)
        local is_up = item.pct >= 0
        local color = is_up and "#f43f5e" or "#10b981" -- 红涨绿跌
        local sign = is_up and "▲ +" or "▼ "
        local pct_str = string.format("%.2f%%", item.pct)
        local val_str = string.format("%.4f", item.val)

        -- 绘制极简趋势折线图 (SVG)
        local svg_path = is_up and "M2,16 L18,10 L38,4" or "M2,4 L18,10 L38,16"
        if item.pct == 0 then svg_path = "M2,10 L38,10" end
        local sparkline = string.format('<svg width="40" height="20" viewBox="0 0 40 20"><path d="%s" fill="none" stroke="%s" stroke-width="2" stroke-linecap="round"/></svg>', svg_path, color)

        return string.format([[
        <div style="display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid #f8fafc;">
            <div style="flex: 1; text-align: left;">
                <div style="font-weight: 900; color: #0f172a; font-size: 14px; font-family: 'Courier New', monospace;">%s</div>
                <div style="font-size: 11px; color: #64748b; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 80px;">%s</div>
            </div>
            <div style="flex: 0 0 45px; text-align: center;">%s</div>
            <div style="flex: 1; text-align: right;">
                <div style="font-weight: bold; font-family: 'Courier New', monospace; font-size: 14px; color: #0f172a;">%s</div>
                <div style="font-size: 11px; font-weight: 800; color: %s; letter-spacing: -0.5px;">%s%s</div>
            </div>
        </div>
        ]], item.code, item.name, sparkline, val_str, color, sign, pct_str)
    end

    -- 渲染主币
    html:node(mw.html.create('div'):cssText("font-size: 12px; font-weight: 800; color: #94a3b8; text-transform: uppercase; margin-bottom: 4px;"):wikitext("Core Assets / 主币"))
    local cores = {WMC=true, KCK=true, SKV=true, COS=true}
    for _, item in ipairs(stats) do
        if cores[item.code] then html:node(mw.html.create('div'):wikitext(renderRow(item))) end
    end

    -- 渲染领涨 Top 3
    html:node(mw.html.create('div'):cssText("font-size: 12px; font-weight: 800; color: #f43f5e; text-transform: uppercase; margin-top: 16px; margin-bottom: 4px;"):wikitext("Top Gainers / 领涨"))
    local count = 0
    for _, item in ipairs(stats) do
        if not cores[item.code] and item.pct > 0 then
            html:node(mw.html.create('div'):wikitext(renderRow(item)))
            count = count + 1
            if count >= 3 then break end
        end
    end

    -- 渲染领跌 Top 3
    html:node(mw.html.create('div'):cssText("font-size: 12px; font-weight: 800; color: #10b981; text-transform: uppercase; margin-top: 16px; margin-bottom: 4px;"):wikitext("Top Losers / 领跌"))
    count = 0
    for i = #stats, 1, -1 do
        local item = stats[i]
        if not cores[item.code] and item.pct < 0 then
            html:node(mw.html.create('div'):wikitext(renderRow(item)))
            count = count + 1
            if count >= 3 then break end
        end
    end

    return tostring(html)
end

return p