打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

Module:少女前线信息:修订间差异

来自OGAS数据中枢
弃权者留言 | 贡献
创建页面,内容为“-- Module:少女前线信息 -- 负责解析模板参数,输出信息框HTML结构 local p = {} -- type=pic 时的固定差分名称 local PIC_NAMES = { '普通', '重创', '和谐', '重创和谐' } -- 右侧信息字段定义 { 参数名, 显示标签 } local INFO_FIELDS = { { 'tagline', '标题' }, { '本名', '本名' }, { '发色', '发色' }, { '瞳色', '瞳色' }, { '声优', '声优'…”
 
弃权者留言 | 贡献
无编辑摘要
 
(未显示同一用户的1个中间版本)
第1行: 第1行:
-- Module:少女前线信息
-- 负责解析模板参数,输出信息框HTML结构
local p = {}
local p = {}


-- type=pic 时的固定差分名称
local PIC_NAMES = { '普通', '重创', '和谐', '重创和谐' }
local PIC_NAMES = { '普通', '重创', '和谐', '重创和谐' }


-- 右侧信息字段定义 { 参数名, 显示标签 }
local INFO_FIELDS = {
local INFO_FIELDS = {
     { 'tagline',  '标题'      },
     { 'tagline',  '标题'      },
第35行: 第30行:
end
end


-- 解析所有立绘组
local function parseGroups(args)
local function parseGroups(args)
     local groups = {}
     local groups = {}
第41行: 第35行:
         local tag = args['tag' .. i]
         local tag = args['tag' .. i]
         if not tag or tag == '' then
         if not tag or tag == '' then
            -- 跳过空tag但继续,允许不连续(保险起见最多扫30个)
            -- 若连续3个都空则停止
             if i > 3 then
             if i > 3 then
                 local allEmpty = true
                 local allEmpty = true
第80行: 第72行:
end
end


-- 渲染switcher按钮列表
local function renderSwitcher(groups)
local function renderSwitcher(groups)
     local html = {}
     local html = {}
第89行: 第80行:
     for gi, group in ipairs(groups) do
     for gi, group in ipairs(groups) do
         local isFirst = gi == 1
         local isFirst = gi == 1
        -- 一级按钮
         table.insert(html, string.format(
         table.insert(html, string.format(
             '<div class="gf-group-btn%s" data-group="%d">%s</div>',
             '<div class="gf-group-btn%s" data-group="%d">%s</div>',
第96行: 第86行:
             escape(group.label)
             escape(group.label)
         ))
         ))
        -- 二级差分列表
         table.insert(html, string.format(
         table.insert(html, string.format(
             '<div class="gf-variant-list%s" data-group="%d">',
             '<div class="gf-variant-list%s" data-group="%d">',
第121行: 第110行:
end
end


-- 渲染图片容器
local function renderImageContainer(groups)
local function renderImageContainer(groups)
     local html = {}
     local html = {}
     table.insert(html, '<div class="gf-image-container">')
     table.insert(html, '<div class="gf-image-container">')


    -- 默认显示第一组第一张
     local defaultFile = ''
     local defaultFile = ''
     if groups[1] and groups[1].pics[1] then
     if groups[1] and groups[1].pics[1] then
第144行: 第131行:
end
end


-- 渲染右侧信息表格
local function renderInfoTable(args, pageName, frame)
local function renderInfoTable(args, pageName)
     local html = {}
     local html = {}


    -- 标题行:优先 名字 > tagline > 页面名
     local title = args['名字'] or args['tagline'] or pageName or ''
     local title = args['名字'] or args['tagline'] or pageName or ''


第164行: 第149行:
                 '<tr><td class="gf-label">%s</td><td>%s</td></tr>',
                 '<tr><td class="gf-label">%s</td><td>%s</td></tr>',
                 escape(field[2]),
                 escape(field[2]),
                 val -- 不转义,允许wikitext链接等内容由frame处理
                 frame:preprocess(val)
             ))
             ))
         end
         end
第174行: 第159行:
end
end


-- 渲染底部表格
local function renderBottomSection(args, frame)
local function renderBottomSection(args)
     local rows = {}
     local rows = {}
     for _, field in ipairs(BOTTOM_FIELDS) do
     for _, field in ipairs(BOTTOM_FIELDS) do
第183行: 第167行:
                 '<tr><td class="gf-label">%s</td><td>%s</td></tr>',
                 '<tr><td class="gf-label">%s</td><td>%s</td></tr>',
                 escape(field[2]),
                 escape(field[2]),
                 val
                 frame:preprocess(val)
             ))
             ))
         end
         end
第214行: 第198行:
]]
]]


-- 主入口
local STYLES_PAGE = 'User:弃权者/Template:少女前线信息/styles.css'
local WIDGET_NAME = 'GF立绘切换'
 
function p.main(frame)
function p.main(frame)
     local args = frame:getParent().args
     local args = frame:getParent().args
第221行: 第207行:
     local groups = parseGroups(args)
     local groups = parseGroups(args)


    -- 唯一ID,支持同页面多个信息框
     local boxId = 'gf-box-' .. mw.uri.encode(pageName, 'PATH') .. '-' .. tostring(os.clock()):gsub('%.','')
     local boxId = 'gf-box-' .. mw.uri.encode(pageName, 'PATH') .. '-' .. tostring(os.clock()):gsub('%.','')


     local html = {}
     local html = {}
    table.insert(html, frame:extensionTag('templatestyles', '', { src = STYLES_PAGE }))
     table.insert(html, string.format('<div class="gf-infobox-new" id="%s">', escape(boxId)))
     table.insert(html, string.format('<div class="gf-infobox-new" id="%s">', escape(boxId)))


    -- 左侧立绘区
     table.insert(html, '<div class="gf-left-panel">')
     table.insert(html, '<div class="gf-left-panel">')
     if #groups > 0 then
     if #groups > 0 then
第235行: 第222行:
     table.insert(html, '</div>') -- gf-left-panel
     table.insert(html, '</div>') -- gf-left-panel


    -- 右侧信息区
     table.insert(html, renderInfoTable(args, pageName, frame))
     table.insert(html, renderInfoTable(args, pageName))


     table.insert(html, '</div>') -- gf-infobox-new
     table.insert(html, '</div>') -- gf-infobox-new


    -- 底部区
     table.insert(html, renderBottomSection(args, frame))
     table.insert(html, renderBottomSection(args))


     -- storeCargo(frame, args)
     -- storeCargo(frame, args)


     return frame:preprocess(table.concat(html, '\n'))
     return table.concat(html, '\n')
end
end


return p
return p

2026年5月16日 (六) 14:31的最新版本

此模块的文档可以在Module:少女前线信息/doc创建

local p = {}

local PIC_NAMES = { '普通', '重创', '和谐', '重创和谐' }

local INFO_FIELDS = {
    { 'tagline',  '标题'       },
    { '本名',     '本名'       },
    { '发色',     '发色'       },
    { '瞳色',     '瞳色'       },
    { '声优',     '声优'       },
    { '人设',     '人设'       },
    { '类型',     '类型'       },
    { '稀有度',   '稀有度'     },
    { '归属部门', '归属部门'   },
    { '归属组织', '归属组织'   },
    { '个人状态', '个人状态'   },
}

-- 底部额外字段
local BOTTOM_FIELDS = {
    { '别名',     '别名'           },
    { '萌点',     '萌点'           },
    { '相关人士', '亲属/相关人士'  },
}

-- HTML转义
local function escape(s)
    if not s then return '' end
    return s:gsub('&','&amp;'):gsub('<','&lt;'):gsub('>','&gt;'):gsub('"','&quot;')
end

local function parseGroups(args)
    local groups = {}
    for i = 1, 30 do
        local tag = args['tag' .. i]
        if not tag or tag == '' then
            if i > 3 then
                local allEmpty = true
                for k = i, math.min(i+2, 30) do
                    if args['tag'..k] and args['tag'..k] ~= '' then
                        allEmpty = false; break
                    end
                end
                if allEmpty then break end
            end
        else
            local groupType = args['type' .. i] or 'pic'
            local pics = {}
            for j = 1, 20 do
                local picFile = args['tag' .. i .. 'pic' .. j]
                if picFile and picFile ~= '' then
                    local label
                    if groupType == 'pic' then
                        label = PIC_NAMES[j] or ('差分' .. j)
                    else
                        label = args['tag' .. i .. 'name' .. j]
                        if not label or label == '' then
                            label = '差分' .. j
                        end
                    end
                    table.insert(pics, { file = picFile, label = label })
                end
            end
            table.insert(groups, {
                label = tag,
                groupType = groupType,
                pics = pics,
            })
        end
    end
    return groups
end

local function renderSwitcher(groups)
    local html = {}
    table.insert(html, '<div class="gf-switcher-overlay">')
    table.insert(html, '<div class="gf-switcher-toggle" title="展开/隐藏菜单"></div>')
    table.insert(html, '<div class="gf-switcher-list">')

    for gi, group in ipairs(groups) do
        local isFirst = gi == 1
        table.insert(html, string.format(
            '<div class="gf-group-btn%s" data-group="%d">%s</div>',
            isFirst and ' active' or '',
            gi,
            escape(group.label)
        ))
        table.insert(html, string.format(
            '<div class="gf-variant-list%s" data-group="%d">',
            isFirst and '' or ' collapsed',
            gi
        ))
        for vi, pic in ipairs(group.pics) do
            local isFirstPic = vi == 1
            table.insert(html, string.format(
                '<div class="gf-switch-btn%s" data-group="%d" data-variant="%d" data-filename="%s">%s</div>',
                isFirst and isFirstPic and ' active' or '',
                gi,
                vi,
                escape(pic.file),
                escape(pic.label)
            ))
        end
        table.insert(html, '</div>') -- gf-variant-list
    end

    table.insert(html, '</div>') -- gf-switcher-list
    table.insert(html, '</div>') -- gf-switcher-overlay
    return table.concat(html, '\n')
end

local function renderImageContainer(groups)
    local html = {}
    table.insert(html, '<div class="gf-image-container">')

    local defaultFile = ''
    if groups[1] and groups[1].pics[1] then
        defaultFile = groups[1].pics[1].file
    end

    if defaultFile ~= '' then
        table.insert(html, string.format(
            '<div class="gf-main-img">[[File:%s|link=]]</div>',
            defaultFile
        ))
    end

    table.insert(html, '<div class="gf-view-original" title="查看原图"></div>')
    table.insert(html, '</div>') -- gf-image-container
    return table.concat(html, '\n')
end

local function renderInfoTable(args, pageName, frame)
    local html = {}

    local title = args['名字'] or args['tagline'] or pageName or ''

    table.insert(html, '<div class="gf-right-panel">')
    table.insert(html, '<table class="gf-info-table">')
    table.insert(html, string.format(
        '<tr><th colspan="2" class="gf-header-row">%s</th></tr>',
        escape(title)
    ))

    for _, field in ipairs(INFO_FIELDS) do
        local val = args[field[1]]
        if val and val ~= '' then
            table.insert(html, string.format(
                '<tr><td class="gf-label">%s</td><td>%s</td></tr>',
                escape(field[2]),
                frame:preprocess(val)
            ))
        end
    end

    table.insert(html, '</table>')
    table.insert(html, '</div>') -- gf-right-panel
    return table.concat(html, '\n')
end

local function renderBottomSection(args, frame)
    local rows = {}
    for _, field in ipairs(BOTTOM_FIELDS) do
        local val = args[field[1]]
        if val and val ~= '' then
            table.insert(rows, string.format(
                '<tr><td class="gf-label">%s</td><td>%s</td></tr>',
                escape(field[2]),
                frame:preprocess(val)
            ))
        end
    end

    if #rows == 0 then return '' end

    local html = {}
    table.insert(html, '<div class="gf-bottom-section">')
    table.insert(html, '<table class="gf-bottom-table">')
    for _, row in ipairs(rows) do
        table.insert(html, row)
    end
    table.insert(html, '</table>')
    table.insert(html, '</div>')
    return table.concat(html, '\n')
end

-- Cargo存储(如需启用,取消注释并补充表名/字段)
--[[
local function storeCargo(frame, args)
    -- 示例:
    -- frame:callParserFunction('#cargo_store', {
    --     _table = 'GF_Characters',
    --     名字 = args['名字'] or '',
    --     声优 = args['声优'] or '',
    --     类型 = args['类型'] or '',
    -- })
end
]]

local STYLES_PAGE = 'User:弃权者/Template:少女前线信息/styles.css'
local WIDGET_NAME = 'GF立绘切换'

function p.main(frame)
    local args = frame:getParent().args
    local pageName = mw.title.getCurrentTitle().subpageText

    local groups = parseGroups(args)

    local boxId = 'gf-box-' .. mw.uri.encode(pageName, 'PATH') .. '-' .. tostring(os.clock()):gsub('%.','')

    local html = {}

    table.insert(html, frame:extensionTag('templatestyles', '', { src = STYLES_PAGE }))

    table.insert(html, string.format('<div class="gf-infobox-new" id="%s">', escape(boxId)))

    table.insert(html, '<div class="gf-left-panel">')
    if #groups > 0 then
        table.insert(html, renderSwitcher(groups))
        table.insert(html, renderImageContainer(groups))
    end
    table.insert(html, '</div>') -- gf-left-panel

    table.insert(html, renderInfoTable(args, pageName, frame))

    table.insert(html, '</div>') -- gf-infobox-new

    table.insert(html, renderBottomSection(args, frame))

    -- storeCargo(frame, args)

    return table.concat(html, '\n')
end

return p