← 返回

应用详情

📦

拾物应用商店

版本 v1 · 4.9 KB
ID: siwoapps
⬇ 下载 CIP 🔍 返回列表
📝 应用描述
浏览web拾物应用商店中的所有上架应用
📋 详细信息
应用ID siwoapps
名称 拾物应用商店
版本 v1
文件大小 4.9 KB
上传时间 2026-07-29 20:50:33
状态 ✅ 已启用
权限 network_external
📁 资源文件 (1)
assets/README.MD 下载 »
💡 界面预览 (main.lua)
📄 Lua 源码
-- ============================================================
-- 应用浏览器 CIP | 严格匹配官方lua-cip.md规范
-- 功能:分页、分类筛选、应用列表、点击跳转网页详情
-- ============================================================

-- 常量
local API_BASE = "https://oldchat.shop/api/index.php?c=App&a=list&token=abc123456789"
local PAGE_SIZE = 10
local IMAGE_DOMAIN = "https://oldchat.shop"
local MAX_LIST_ITEMS = 10

-- 全局状态(全部非空初始化,杜绝nil)
local currentPage = 1
local totalItems = 0
local currentCategory = ""
local isLoading = false
local categories = {}
local pageAppData = {} -- 缓存当前页应用数据,按钮按下标取id

-- ============================================================
-- 工具函数(所有入参强制兜底,无nil输出)
-- ============================================================
local function formatSize(sizeStr)
    local raw = tostring(sizeStr or "0")
    local num = tonumber(raw) or 0
    if num >= 1024 * 1024 then
        return string.format("%.1f MB", num / (1024 * 1024))
    elseif num >= 1024 then
        return string.format("%.1f KB", num / 1024)
    end
    return string.format("%.0f B", num)
end

local function formatDownloads(count)
    local raw = tostring(count or "0")
    local num = tonumber(raw) or 0
    if num >= 10000 then
        return string.format("%.1f万", num / 10000)
    end
    return tostring(num)
end

local function extractCategories(list)
    local src = list or {}
    local catSet = {}
    for _, item in ipairs(src) do
        local cat = tostring(item.category or "")
        if cat ~= "" then
            catSet[cat] = true
        end
    end
    local cats = {}
    for k in pairs(catSet) do
        table.insert(cats, k)
    end
    table.sort(cats)
    return cats
end

-- 详情跳转统一处理(按下标读取缓存应用ID)
local function jumpDetail(itemIndex)
    local target = pageAppData[itemIndex] or {}
    local aid = tostring(target.id or "")
    if aid == "" then
        app.toast("未读取到应用ID,无法跳转")
        return
    end
    local targetUrl = "https://oldchat.shop/app.php?id=" .. aid
    app.open_url(targetUrl)
end

-- ============================================================
-- UI 批量隐藏工具
-- ============================================================
local function hideAllAppEntries()
    for i = 1, MAX_LIST_ITEMS do
        app.set_visible("app_icon_" .. i, false)
        app.set_visible("app_name_" .. i, false)
        app.set_visible("app_pkg_" .. i, false)
        app.set_visible("app_info_" .. i, false)
        app.set_visible("btn_detail_" .. i, false)
        if i < MAX_LIST_ITEMS then
            app.set_visible("separator_" .. i, false)
        end
    end
    app.set_visible("empty_text", false)
end

local function updateCategoryButtons()
    for i = 1, 5 do
        app.set_visible("cat_btn_" .. i, false)
    end
    app.set_visible("more_cat_text", false)

    if #categories <= 0 then
        app.set_visible("category_label", false)
        app.set_visible("btn_all", false)
        return
    end

    app.set_visible("category_label", true)
    app.set_visible("btn_all", true)
    if currentCategory == "" then
        app.set_text("btn_all", "✅ 全部")
    else
        app.set_text("btn_all", "全部")
    end

    local maxShow = math.min(#categories, 5)
    for i = 1, maxShow do
        local catName = tostring(categories[i] or "")
        app.set_text("cat_btn_" .. i, catName)
        app.set_visible("cat_btn_" .. i, true)
        if catName == currentCategory then
            app.set_text("cat_btn_" .. i, "✅ " .. catName)
        end
    end
    if #categories > 5 then
        app.set_text("more_cat_text", "... 共 " .. tostring(#categories) .. " 个分类")
        app.set_visible("more_cat_text", true)
    end
end

-- ============================================================
-- 网络加载函数(文档标准 http_get(body, err))
-- ============================================================
local function loadApps(page)
    if isLoading then return end
    isLoading = true
    pageAppData = {} -- 清空当前页缓存

    local url = API_BASE .. "&page=" .. tostring(page) .. "&page_size=" .. tostring(PAGE_SIZE)
    if currentCategory ~= "" then
        url = url .. "&category=" .. currentCategory
    end

    app.set_text("status_text", "正在加载第 " .. tostring(page) .. " 页...")
    app.set_visible("status_text", true)

    app.http_get(url, function(body, err)
        isLoading = false
        local respBody = tostring(body or "")
        local respErr = tostring(err or "")

        if respErr ~= "" then
            app.set_text("status_text", "加载失败: " .. respErr)
            app.toast("网络请求失败:" .. respErr)
            return
        end
        if respBody == "" then
            app.set_text("status_text", "服务器返回空数据")
            app.toast("接口无返回内容")
            return
        end

        local result = app.json_decode(respBody)
        if type(result) ~= "table" then
            app.set_text("status_text", "JSON数据解析失败")
            app.toast("数据格式错误")
            return
        end

        local code = tonumber(result.code or 0)
        if code ~= 200 then
            local msg = tostring(result.msg or "未知业务错误")
            app.set_text("status_text", "接口错误: " .. msg)
            app.toast("业务异常:" .. msg)
            return
        end

        local data = result.data or {}
        local list = data.list or {}
        pageAppData = list
        totalItems = tonumber(data.total or 0)
        currentPage = tonumber(data.page or page)

        if #categories <= 0 then
            categories = extractCategories(list)
        end
        updateCategoryButtons()

        local statusText = "共 " .. tostring(totalItems) .. " 个应用"
        if currentCategory ~= "" then
            statusText = "分类: " .. currentCategory .. " | " .. statusText
        end
        app.set_text("status_text", statusText)
        app.set_visible("divider_text", true)

        hideAllAppEntries()
        local appCount = #list
        if appCount > 0 then
            local renderCount = math.min(appCount, MAX_LIST_ITEMS)
            for i = 1, renderCount do
                local item = list[i] or {}
                -- 图标
                local iconPath = tostring(item.icon or "")
                if iconPath ~= "" then
                    app.set_image("app_icon_" .. i, IMAGE_DOMAIN .. "/" .. iconPath)
                    app.set_visible("app_icon_" .. i, true)
                end
                -- 应用名
                local nameText = tostring(item.app_name or "未知应用")
                if tonumber(item.is_top or 0) == 1 then
                    nameText = "⭐ " .. nameText
                end
                local ver = tostring(item.version or "")
                if ver ~= "" then
                    nameText = nameText .. " v" .. ver
                end
                app.set_text("app_name_" .. i, nameText)
                app.set_visible("app_name_" .. i, true)
                -- 包名
                local pkg = tostring(item.package_name or "")
                if pkg ~= "" then
                    app.set_text("app_pkg_" .. i, "📦 " .. pkg)
                    app.set_visible("app_pkg_" .. i, true)
                end
                -- 信息行
                local infoParts = {
                    "💾 " .. formatSize(item.size),
                    "⬇ " .. formatDownloads(item.downloads)
                }
                local catStr = tostring(item.category or "")
                if catStr ~= "" then
                    table.insert(infoParts, "🏷 " .. catStr)
                end
                app.set_text("app_info_" .. i, table.concat(infoParts, "  |  "))
                app.set_visible("app_info_" .. i, true)
                -- 详情按钮渲染
                app.set_text("btn_detail_" .. i, "🔗 查看详情")
                app.set_visible("btn_detail_" .. i, true)
                -- 分隔线
                if i < appCount and i < MAX_LIST_ITEMS then
                    app.set_visible("separator_" .. i, true)
                end
            end
        else
            app.set_visible("empty_text", true)
        end

        local totalPages = math.max(math.ceil(totalItems / PAGE_SIZE), 1)
        app.set_text("page_info", "第 " .. tostring(currentPage) .. " / " .. tostring(totalPages) .. " 页")
        app.set_visible("page_info", true)
        app.set_visible("btn_prev", currentPage > 1)
        app.set_visible("btn_next", (currentPage * PAGE_SIZE) < totalItems)
        app.set_visible("btn_refresh", true)
        app.set_visible("btn_home", currentPage > 1)
        app.toast("加载完成,本页 " .. tostring(appCount) .. " 个应用")
    end)
end

-- ============================================================
-- UI 节点构建(仅文档支持控件与属性)
-- ============================================================
local listChildren = {}

-- 状态文字
table.insert(listChildren, ui.text({
    id = "status_text",
    text = "点击上方按钮加载数据",
    size = 14,
    color = "#888888",
    center = true,
    margin = 8
}))

-- 分类标题
table.insert(listChildren, ui.text({
    id = "category_label",
    text = "分类筛选:",
    size = 14,
    margin = 4,
    visible = false,
}))

-- 全部分类按钮
table.insert(listChildren, ui.button({
    id = "btn_all",
    text = "全部",
    color = "#007AFF",
    margin = 2,
    visible = false,
    on_click = function()
        if currentCategory ~= "" then
            currentCategory = ""
            loadApps(1)
        end
    end
}))

-- 5个分类按钮(固化下标,闭包无nil风险)
for i = 1, 5 do
    local bindIdx = i
    table.insert(listChildren, ui.button({
        id = "cat_btn_" .. bindIdx,
        text = "",
        color = "#666666",
        margin = 2,
        visible = false,
        on_click = function()
            local targetCat = categories[bindIdx]
            if target and currentCategory ~= targetCat then
                currentCategory = targetCat
                loadApps(1)
            end
        end
    }))
end

table.insert(listChildren, ui.text({
    id = "more_cat_text",
    text = "",
    size = 12,
    color = "#999999",
    center = true,
    margin = 2,
    visible = false,
}))
table.insert(listChildren, ui.spacer({ height = 6 }))

-- 分割线
table.insert(listChildren, ui.text({
    id = "divider_text",
    text = "━━━ 应用列表 ━━━",
    size = 12,
    color = "#CCCCCC",
    center = true,
    margin = 4,
    visible = false,
}))

-- 循环创建10条应用条目(含详情按钮)
for i = 1, MAX_LIST_ITEMS do
    local bindIndex = i
    table.insert(listChildren, ui.image({
        id = "app_icon_" .. i,
        url = "",
        height = 52,
        margin = 4,
        visible = false
    }))
    table.insert(listChildren, ui.text({
        id = "app_name_" .. i,
        text = "",
        size = 17,
        margin = 2,
        visible = false
    }))
    table.insert(listChildren, ui.text({
        id = "app_pkg_" .. i,
        text = "",
        size = 12,
        color = "#666666",
        margin = 2,
        visible = false
    }))
    table.insert(listChildren, ui.text({
        id = "app_info_" .. i,
        text = "",
        size = 12,
        color = "#999999",
        margin = 2,
        visible = false
    }))
    -- 查看详情按钮:闭包固化下标,直接调用跳转函数
    table.insert(listChildren, ui.button({
        id = "btn_detail_" .. i,
        text = "",
        color = "#007AFF",
        margin = 2,
        visible = false,
        on_click = function()
            jumpDetail(bindIndex)
        end
    }))
    -- 条目分隔
    if i < MAX_LIST_ITEMS then
        table.insert(listChildren, ui.spacer({ height = 4 }))
        table.insert(listChildren, ui.text({
            id = "separator_" .. i,
            text = "─────────────────────",
            size = 10,
            color = "#EEEEEE",
            center = true,
            margin = 2,
            visible = false
        }))
        table.insert(listChildren, ui.spacer({ height = 4 }))
    end
end

-- 空数据提示
table.insert(listChildren, ui.text({
    id = "empty_text",
    text = "暂无匹配的应用数据",
    size = 15,
    color = "#999999",
    center = true,
    margin = 20,
    visible = false
}))

-- 分页区域
table.insert(listChildren, ui.spacer({ height = 6 }))
table.insert(listChildren, ui.text({
    id = "page_info",
    text = "",
    size = 13,
    color = "#AAAAAA",
    center = true,
    margin = 4,
    visible = false,
}))
table.insert(listChildren, ui.button({
    id = "btn_prev",
    text = "◀ 上一页",
    margin = 4,
    visible = false,
    on_click = function()
        if currentPage > 1 then
            loadApps(currentPage - 1)
        end
    end
}))
table.insert(listChildren, ui.button({
    id = "btn_next",
    text = "下一页 ▶",
    margin = 4,
    visible = false,
    on_click = function()
        loadApps(currentPage + 1)
    end
}))
table.insert(listChildren, ui.spacer({ height = 6 }))
table.insert(listChildren, ui.button({
    id = "btn_refresh",
    text = "🔄 刷新当前页",
    margin = 4,
    visible = false,
    on_click = function()
        loadApps(currentPage)
    end
}))
table.insert(listChildren, ui.button({
    id = "btn_home",
    text = "🏠 回到首页",
    margin = 4,
    visible = false,
    on_click = function()
        loadApps(1)
    end
}))

-- ============================================================
-- 页面根节点(仅title+children,无自定义参数)
-- ============================================================
return ui.page({
    title = "拾物应用商店oc小程序版 ver1.4.1",
    children = {
        ui.button({
            text = "加载应用列表",
            color = "#007AFF",
            margin = 8,
            on_click = function()
                loadApps(1)
            end
        }),
        ui.list({
            children = listChildren,
            margin = 4
        }),
        ui.spacer({ height = 12 }),
        ui.text({
            text = "使用说明",
            size = 16,
            center = true,
            margin = 4
        }),
        ui.text({
            text = "点击上方按钮加载数据\n查看详情暂不可用\n翻页浏览列表\n",
            size = 13,
            color = "#666666",
            margin = 8
        }),
        ui.text({
            text = "© 2026 拾物应用商店 版权所有",
            size = 14,
            color = "#555555",
            center = true,
            margin = 10
        })
    }
})
⬇ 下载 CIP 文件 🔍 返回列表