跳转到内容

模块:Db:修订间差异

来自DJMAX中文资料库
无编辑摘要
无编辑摘要
第18行: 第18行:
-- [[------------------------------------------------------------------]]
-- [[------------------------------------------------------------------]]
local displayNames = {
local displayNames = {
     -- 核心字段
     -- 核心字段 (保持不变)
     ['title'] = '歌曲标题',
     ['title'] = '歌曲标题',
     ['composer'] = '艺术家',
     ['composer'] = '艺术家',
第31行: 第31行:
     ['duration'] = '时长',
     ['duration'] = '时长',


     -- 节奏游戏字段
     -- 节奏游戏字段 (保持不变)
     ['4b_nm'] = '4B NM',
     ['4b_nm'] = '4B NM', ['4b_nm_notes'] = '4B NM按键数', ['4b_hd'] = '4B HD', ['4b_hd_notes'] = '4B HD按键数',  
    ['4b_nm_notes'] = '4B NM按键数',
     ['4b_mx'] = '4B MX', ['4b_mx_notes'] = '4B MX按键数', ['4b_sc'] = '4B SC', ['4b_sc_notes'] = '4B SC按键数',
    ['4b_hd'] = '4B HD',
     ['5b_nm'] = '5B NM', ['5b_nm_notes'] = '5B NM按键数', ['5b_hd'] = '5B HD', ['5b_hd_notes'] = '5B HD按键数',
    ['4b_hd_notes'] = '4B HD按键数',
     ['5b_mx'] = '5B MX', ['5b_mx_notes'] = '5B MX按键数', ['5b_sc'] = '5B SC', ['5b_sc_notes'] = '5B SC按键数',
     ['4b_mx'] = '4B MX',
     ['6b_nm'] = '6B NM', ['6b_nm_notes'] = '6B NM按键数', ['6b_hd'] = '6B HD', ['6b_hd_notes'] = '6B HD按键数',
    ['4b_mx_notes'] = '4B MX按键数',
     ['6b_mx'] = '6B MX', ['6b_mx_notes'] = '6B MX按键数', ['6b_sc'] = '6B SC', ['6b_sc_notes'] = '6B SC按键数',
    ['4b_sc'] = '4B SC',
     ['8b_nm'] = '8B NM', ['8b_nm_notes'] = '8B NM按键数', ['8b_hd'] = '8B HD', ['8b_hd_notes'] = '8B HD按键数',
    ['4b_sc_notes'] = '4B SC按键数',
     ['8b_mx'] = '8B MX', ['8b_mx_notes'] = '8B MX按键数', ['8b_sc'] = '8B SC', ['8b_sc_notes'] = '8B SC按键数',
     ['5b_nm'] = '5B NM',
    ['5b_nm_notes'] = '5B NM按键数',
    ['5b_hd'] = '5B HD',
    ['5b_hd_notes'] = '5B HD按键数',
     ['5b_mx'] = '5B MX',
    ['5b_mx_notes'] = '5B MX按键数',
    ['5b_sc'] = '5B SC',
    ['5b_sc_notes'] = '5B SC按键数',
     ['6b_nm'] = '6B NM',
    ['6b_nm_notes'] = '6B NM按键数',
    ['6b_hd'] = '6B HD',
    ['6b_hd_notes'] = '6B HD按键数',
     ['6b_mx'] = '6B MX',
    ['6b_mx_notes'] = '6B MX按键数',
    ['6b_sc'] = '6B SC',
    ['6b_sc_notes'] = '6B SC按键数',
     ['8b_nm'] = '8B NM',
    ['8b_nm_notes'] = '8B NM按键数',
    ['8b_hd'] = '8B HD',
    ['8b_hd_notes'] = '8B HD按键数',
     ['8b_mx'] = '8B MX',
    ['8b_mx_notes'] = '8B MX按键数',
    ['8b_sc'] = '8B SC',
    ['8b_sc_notes'] = '8B SC按键数',
}
}


第70行: 第46行:
-- [[------------------------------------------------------------------]]
-- [[------------------------------------------------------------------]]
local function GetValuesTable()
local function GetValuesTable()
    -- 假设数据源为 Module:db_song
     return mw.loadData('Module:db_song')
     return mw.loadData('Module:db_song')
end  
end  
第81行: 第56行:
end  
end  


-- 格式化单个值的私有函数 (基础格式化,不应用BPM或难度样式)
-- 格式化单个值的私有函数 (基础格式化,不应用任何样式)
local function formatSingleValue(value, fieldType)
local function formatSingleValue(value, fieldType)
     if value == nil then
     if value == nil then
         return i18n['none'] -- 将 nil 转换为 '无'
         return i18n['none']
     elseif type(value) == 'boolean' then
     elseif type(value) == 'boolean' then
         return value and i18n['true'] or i18n['false']
         return value and i18n['true'] or i18n['false']
第96行: 第71行:
-- 仅在表格中应用的BPM样式
-- 仅在表格中应用的BPM样式
local function formatBPMValue(valueString)
local function formatBPMValue(valueString)
    -- valueString 预期是经过 formatSingleValue 处理的字符串
     if string.find(valueString, '-') then
     if string.find(valueString, '-') then
         return '<span style="color:red;">' .. valueString .. '</span>'
         return '<span style="color:red;">' .. valueString .. '</span>'
第108行: 第82行:
     local checkField = field and string.lower(mw.text.trim(field)) or ''
     local checkField = field and string.lower(mw.text.trim(field)) or ''
      
      
    -- 哈希表包含所有难度字段,排除 _notes
     local difficultyFields = {
     local difficultyFields = {
         ['4b_nm'] = true, ['4b_hd'] = true, ['4b_mx'] = true, ['4b_sc'] = true,
         ['4b_nm'] = true, ['4b_hd'] = true, ['4b_mx'] = true, ['4b_sc'] = true,
第117行: 第90行:


     if difficultyFields[checkField] == true then
     if difficultyFields[checkField] == true then
         -- 匹配成功,安全提取模式 (最后两个字符: 'nm', 'hd', 'mx', or 'sc')
         -- 提取模式 ('nm', 'hd', 'mx', or 'sc')
         local mode = checkField:sub(-2)
         local mode = checkField:sub(-2)
         local btn = checkField:match("^(%d+)b")
         -- 返回 (btn, mode)
        return btn, mode
        return checkField:match("^(%d+)b"), mode
     end
     end
      
      
第126行: 第99行:
end
end


-- **核心功能:根据难度和数值应用内联样式 (仅用于表格)**
-- **核心:难度样式应用 (仅用于表格)**
local function formatDifficultyValue(valueString, btn, mode)
local function formatDifficultyStyles(valueString, mode)
     -- valueString 预期是经过 formatSingleValue 处理的字符串 (例如 '15', ' - ', 或 '无')
     -- valueString 预期是经过 formatSingleValue 处理的字符串 (例如 '15', ' - ', 或 '无')
     local numValue = tonumber(valueString)
     local numValue = tonumber(valueString)
      
      
     -- 如果无法转换为数字,则返回原始字符串 (例如: ' - ' 或 '无')
     -- 如果无法转换为数字,则返回原始字符串
     if numValue == nil then
     if numValue == nil then
         return valueString  
         return valueString  
第139行: 第112行:
      
      
     if mode == 'sc' then
     if mode == 'sc' then
         local blueGlow = ' text-shadow: 0 0 5px #3D66FF, 0 0 8px #3D66FF;' -- 定义统一的光晕样式
        -- SC 样式 (包括颜色和光晕)
         local blueGlow = ' text-shadow: 0 0 5px #3D66FF, 0 0 8px #3D66FF;'
         style = 'font-weight: bold;'
         style = 'font-weight: bold;'
          
          
第147行: 第121行:
             style = style .. ' color: #C604E3;'
             style = style .. ' color: #C604E3;'
         elseif numValue >= 11 and numValue <= 12 then
         elseif numValue >= 11 and numValue <= 12 then
            -- 11 and 12 颜色为 #3D66FF
             style = style .. ' color: #3D66FF;'  
             style = style .. ' color: #3D66FF;'  
         elseif numValue == 13 then
         elseif numValue == 13 then
            -- 13 颜色改为橙色,光晕为 #3D66FF
             style = style .. ' color: orange;' .. blueGlow
             style = style .. ' color: orange;' .. blueGlow
         elseif numValue == 14 then
         elseif numValue == 14 then
            -- 14 颜色改为红色,光晕为 #3D66FF
             style = style .. ' color: red;' .. blueGlow
             style = style .. ' color: red;' .. blueGlow
         elseif numValue == 15 then
         elseif numValue == 15 then
            -- 15 颜色改为紫色,光晕为 #3D66FF
             style = style .. ' color: purple;' .. blueGlow
             style = style .. ' color: purple;' .. blueGlow
         end
         end
     elseif (mode == 'nm' or mode == 'hd' or mode == 'mx') then
     elseif (mode == 'nm' or mode == 'hd' or mode == 'mx') then
        -- NM/HD/MX 样式 (仅 14/15)
         if numValue == 14 then
         if numValue == 14 then
             style = 'font-weight: bold; color: orange;'
             style = 'font-weight: bold; color: orange;'
第167行: 第138行:
     end
     end
      
      
    -- displayValue 已经是纯数字字符串 (例如 '15')
     if style ~= '' then
     if style ~= '' then
         -- 返回带样式的纯数字字符串 (不包含 'sc' 前缀)
         -- 返回带样式的纯数字字符串 (不包含 'sc' 前缀)
第173行: 第143行:
     end
     end
      
      
     return valueString -- 返回纯数字字符串(如果没有样式应用)
     return valueString -- 返回原始数字字符串(如果没有样式应用)
end
 
-- **SC 前缀应用 (仅用于 p.value)**
local function applySCPrefix(valueString, fieldType)
    local isSC = string.match(fieldType, '_sc$')
   
    -- 仅当是 SC 字段,且值存在(不是 '无')且不为 ' - ' 时,添加 "sc" 前缀
    if isSC and valueString ~= i18n['none'] and valueString ~= '-' then
        return 'sc' .. valueString
    end
   
    return valueString
end
end


第229行: 第211行:
         local value = ValueFromValuesByKey(songEntry, argType)
         local value = ValueFromValuesByKey(songEntry, argType)
          
          
         -- 核心:p.value 只进行基础格式化,不应用 BPM 或难度样式
         -- 步骤 1: 基础格式化
         local formattedValue = formatSingleValue(value, argType)  
         local formattedValue = formatSingleValue(value, argType)  
          
          
         -- SC 前缀逻辑:如果是 SC 字段,且值存在(不是 '无')且不为 ' - ',添加 "sc" 前缀
         -- 步骤 2: 应用 SC 前缀 (仅 p.value 需要,且不带样式)
        local isSC = string.match(argType, '_sc$')
         formattedValue = applySCPrefix(formattedValue, argType)
          
        if isSC and formattedValue ~= i18n['none'] and formattedValue ~= '-' then
            formattedValue = 'sc' .. formattedValue
        end


         table.insert(resultTable, formattedValue)
         table.insert(resultTable, formattedValue)
第287行: 第265行:
     local displayFieldsString = mw.text.trim(args.columns or '')  
     local displayFieldsString = mw.text.trim(args.columns or '')  
      
      
     -- 预处理 conditionValue 的类型
     -- 预处理 conditionValue 的类型 (保持不变)
     if type(conditionValue) == 'string' then
     if type(conditionValue) == 'string' then
         local trimmedValue = mw.text.trim(conditionValue)
         local trimmedValue = mw.text.trim(conditionValue)
第332行: 第310行:
     table.insert(output, '{| class="wikitable sortable" style="width: 100%; margin: 0 auto; text-align: center;"')
     table.insert(output, '{| class="wikitable sortable" style="width: 100%; margin: 0 auto; text-align: center;"')
      
      
     -- 构造表格头部 (不包含 ID)
     -- 构造表格头部 (保持不变)
     table.insert(output, '|-')
     table.insert(output, '|-')
     for _, field in ipairs(displayFields) do
     for _, field in ipairs(displayFields) do
第339行: 第317行:
     end
     end
      
      
     -- 构造表格行 (使用最稳健的多行结构)
     -- 构造表格行
     for _, songId in ipairs(matchingKeys) do
     for _, songId in ipairs(matchingKeys) do
         local songEntry = songData[songId]
         local songEntry = songData[songId]
第350行: 第328行:
             local rawValue = ValueFromValuesByKey(songEntry, field)
             local rawValue = ValueFromValuesByKey(songEntry, field)
              
              
             -- 步骤 1: 基础格式化 (处理 nil, boolean, duration 等)
             -- 步骤 1: 基础格式化
             local formattedValue = formatSingleValue(rawValue, field)
             local formattedValue = formatSingleValue(rawValue, field)
              
              
第361行: 第339行:


             -- 应用难度样式
             -- 应用难度样式
             local btn, mode = getDifficultyDetails(field)
             local _, mode = getDifficultyDetails(field)
             if btn and mode then
             if mode then
                 -- CRITICAL FIX: 传入已经过基础格式化的 formattedValue
                 -- 调用难度样式函数,它负责所有颜色和光晕 (不添加 'sc' 前缀)
                 formattedValue = formatDifficultyValue(formattedValue, btn, mode)
                 formattedValue = formatDifficultyStyles(formattedValue, mode)
             end
             end
              
              

2025年11月29日 (六) 13:10的版本

本模块为自动表核心功能程序,根据输入的信息自动筛选数据。

数据库储存在Module:db_song,通过Template:db可以调用数据库中的信息,也可以通过Template:songlist生成自动表格。


local p = {}

-- [[------------------------------------------------------------------]]
-- [[ 1. 国际化和常量 ]]
-- [[------------------------------------------------------------------]]
local i18n = {
	['true'] = '是',      
	['false'] = '否',     
	['none'] = '无',
	['category_missing_value'] = '缺失%s',
	['error_no_type'] = '<span class="error">Db:调用时必须提供type参数。</span>',
    ['error_find_keys_args'] = '<span class="error">Db:findKeysByValue必须提供field和value参数。</span>', 
    ['error_generate_table_args'] = '<span class="error">Db:generateListTable调用缺少field, value或columns参数。</span>',
}

-- [[------------------------------------------------------------------]]
-- [[ 2. 表格标题映射 ]]
-- [[------------------------------------------------------------------]]
local displayNames = {
    -- 核心字段 (保持不变)
    ['title'] = '歌曲标题',
    ['composer'] = '艺术家',
    ['bpm'] = 'BPM',
    ['singer'] = '歌手',
    ['genre'] = '流派',
    ['id'] = '歌曲ID',
    ['key'] = 'KEY音',
    ['bga'] = 'BGA作者',

    -- 保留常用字段
    ['duration'] = '时长',

    -- 节奏游戏字段 (保持不变)
    ['4b_nm'] = '4B NM', ['4b_nm_notes'] = '4B NM按键数', ['4b_hd'] = '4B HD', ['4b_hd_notes'] = '4B HD按键数', 
    ['4b_mx'] = '4B MX', ['4b_mx_notes'] = '4B MX按键数', ['4b_sc'] = '4B SC', ['4b_sc_notes'] = '4B SC按键数',
    ['5b_nm'] = '5B NM', ['5b_nm_notes'] = '5B NM按键数', ['5b_hd'] = '5B HD', ['5b_hd_notes'] = '5B HD按键数',
    ['5b_mx'] = '5B MX', ['5b_mx_notes'] = '5B MX按键数', ['5b_sc'] = '5B SC', ['5b_sc_notes'] = '5B SC按键数',
    ['6b_nm'] = '6B NM', ['6b_nm_notes'] = '6B NM按键数', ['6b_hd'] = '6B HD', ['6b_hd_notes'] = '6B HD按键数',
    ['6b_mx'] = '6B MX', ['6b_mx_notes'] = '6B MX按键数', ['6b_sc'] = '6B SC', ['6b_sc_notes'] = '6B SC按键数',
    ['8b_nm'] = '8B NM', ['8b_nm_notes'] = '8B NM按键数', ['8b_hd'] = '8B HD', ['8b_hd_notes'] = '8B HD按键数',
    ['8b_mx'] = '8B MX', ['8b_mx_notes'] = '8B MX按键数', ['8b_sc'] = '8B SC', ['8b_sc_notes'] = '8B SC按键数',
}

-- [[------------------------------------------------------------------]]
-- [[ 3. 本地辅助函数定义 ]]
-- [[------------------------------------------------------------------]]
local function GetValuesTable()
    return mw.loadData('Module:db_song')
end 

local function ValueFromValuesByKey(values, key)
	if values and key then
		return values[key]
	end
	return nil
end 

-- 格式化单个值的私有函数 (基础格式化,不应用任何样式)
local function formatSingleValue(value, fieldType)
    if value == nil then
        return i18n['none']
    elseif type(value) == 'boolean' then
        return value and i18n['true'] or i18n['false']
    elseif type(p.valueMappingMethod[fieldType]) == 'function' then
        return p.valueMappingMethod[fieldType](value)
    else
        return tostring(value)
    end
end 

-- 仅在表格中应用的BPM样式
local function formatBPMValue(valueString)
    if string.find(valueString, '-') then
        return '<span style="color:red;">' .. valueString .. '</span>'
    end
    return valueString
end


-- 获取难度模式 (用于判断是否为难度字段)
local function getDifficultyDetails(field)
    local checkField = field and string.lower(mw.text.trim(field)) or ''
    
    local difficultyFields = {
        ['4b_nm'] = true, ['4b_hd'] = true, ['4b_mx'] = true, ['4b_sc'] = true,
        ['5b_nm'] = true, ['5b_hd'] = true, ['5b_mx'] = true, ['5b_sc'] = true,
        ['6b_nm'] = true, ['6b_hd'] = true, ['6b_mx'] = true, ['6b_sc'] = true,
        ['8b_nm'] = true, ['8b_hd'] = true, ['8b_mx'] = true, ['8b_sc'] = true,
    }

    if difficultyFields[checkField] == true then
        -- 提取模式 ('nm', 'hd', 'mx', or 'sc')
        local mode = checkField:sub(-2)
        -- 返回 (btn, mode)
        return checkField:match("^(%d+)b"), mode
    end
    
    return nil, nil
end

-- **核心:难度样式应用 (仅用于表格)**
local function formatDifficultyStyles(valueString, mode)
    -- valueString 预期是经过 formatSingleValue 处理的字符串 (例如 '15', ' - ', 或 '无')
    local numValue = tonumber(valueString)
    
    -- 如果无法转换为数字,则返回原始字符串
    if numValue == nil then
        return valueString 
    end

    local style = ''
    
    if mode == 'sc' then
        -- SC 样式 (包括颜色和光晕)
        local blueGlow = ' text-shadow: 0 0 5px #3D66FF, 0 0 8px #3D66FF;'
        style = 'font-weight: bold;'
        
        if numValue >= 1 and numValue <= 5 then
            style = style .. ' color: #E00075;'
        elseif numValue >= 6 and numValue <= 10 then
            style = style .. ' color: #C604E3;'
        elseif numValue >= 11 and numValue <= 12 then
            style = style .. ' color: #3D66FF;' 
        elseif numValue == 13 then
            style = style .. ' color: orange;' .. blueGlow
        elseif numValue == 14 then
            style = style .. ' color: red;' .. blueGlow
        elseif numValue == 15 then
            style = style .. ' color: purple;' .. blueGlow
        end
    elseif (mode == 'nm' or mode == 'hd' or mode == 'mx') then
        -- NM/HD/MX 样式 (仅 14/15)
        if numValue == 14 then
            style = 'font-weight: bold; color: orange;'
        elseif numValue == 15 then
            style = 'font-weight: bold; color: red;'
        end
    end
    
    if style ~= '' then
        -- 返回带样式的纯数字字符串 (不包含 'sc' 前缀)
        return '<span style="' .. style .. '">' .. valueString .. '</span>'
    end
    
    return valueString -- 返回原始数字字符串(如果没有样式应用)
end

-- **SC 前缀应用 (仅用于 p.value)**
local function applySCPrefix(valueString, fieldType)
    local isSC = string.match(fieldType, '_sc$')
    
    -- 仅当是 SC 字段,且值存在(不是 '无')且不为 ' - ' 时,添加 "sc" 前缀
    if isSC and valueString ~= i18n['none'] and valueString ~= '-' then
        return 'sc' .. valueString
    end
    
    return valueString
end


-- 4. 值格式化方法 (valueMappingMethod)
p.valueMappingMethod = {
    ['duration'] = (function (value)
        if type(value) == 'number' then
            local minutes = math.floor(value / 60)
            local seconds = value % 60
            return string.format('%d:%02d', minutes, seconds)
        end
        return value
    end),
}

-- [[------------------------------------------------------------------]]
-- [[ 5. 外部调用函数 (p.*) ]]
-- [[------------------------------------------------------------------]]

function p.value(f)
    local args = f
	local frame = mw.getCurrentFrame()
	if f == frame then
		args = require('Module:ProcessArgs').merge(true)
	end
    
	local argTargetName = mw.text.trim(args[1] or '') 
	local argTypeString = args.type                 
	local argNocat = args.nocat                     
    
    if not argTypeString then
        return i18n['error_no_type']
    end
    
    local values = GetValuesTable() 
    local songEntry = ValueFromValuesByKey(values, argTargetName)

    if not songEntry then
        if not argNocat then
            local title = mw.title.getCurrentTitle()
            if title.namespace == 0 and not title.isSubpage then
                return '?' .. '[[Category:' .. string.format(i18n['category_missing_value'], '歌曲ID ' .. argTargetName) .. ']]'
            end
        end
        return i18n['none']
    end
    
    local fieldNames = mw.text.split(argTypeString, ',')
    local resultTable = {}

    for _, argType in ipairs(fieldNames) do
        argType = mw.text.trim(argType)
        
        local value = ValueFromValuesByKey(songEntry, argType)
        
        -- 步骤 1: 基础格式化
        local formattedValue = formatSingleValue(value, argType) 
        
        -- 步骤 2: 应用 SC 前缀 (仅 p.value 需要,且不带样式)
        formattedValue = applySCPrefix(formattedValue, argType)

        table.insert(resultTable, formattedValue)
    end
    
	return table.concat(resultTable, ' / ')
end

function p.findKeysByValue(f)
    local args = f
    local frame = mw.getCurrentFrame()
    if f == frame then
        args = require('Module:ProcessArgs').merge(true)
    end
    
    local targetField = mw.text.trim(args.field or '')
    local targetValue = args.value 
    
    if type(targetValue) == 'string' then
        targetValue = mw.text.trim(targetValue)
    end
    
    if targetField == '' or targetValue == nil then
        return i18n['error_find_keys_args']
    end

    local songData = GetValuesTable()
    local matchingKeys = {}
    
    for songId, songEntry in pairs(songData) do
        local currentValue = ValueFromValuesByKey(songEntry, targetField)
        
        if currentValue == targetValue then
            table.insert(matchingKeys, songId)
        end
    end
    
    table.sort(matchingKeys)
    
    return table.concat(matchingKeys, ', ')
end


function p.generateListTable(f)
    local args = require('Module:ProcessArgs').merge(true) 
    
    local conditionField = mw.text.trim(args.field or '')   
    local conditionValue = args.value                       
    local displayFieldsString = mw.text.trim(args.columns or '') 
    
    -- 预处理 conditionValue 的类型 (保持不变)
    if type(conditionValue) == 'string' then
        local trimmedValue = mw.text.trim(conditionValue)
        
        local lowerValue = string.lower(trimmedValue)
        if lowerValue == 'true' or trimmedValue == '是' then
            conditionValue = true
        elseif lowerValue == 'false' or trimmedValue == '否' then
            conditionValue = false
        else
            local num = tonumber(trimmedValue)
            if num ~= nil then
                conditionValue = num
            else
                conditionValue = trimmedValue
            end
        end
    end
    
    if conditionField == '' or conditionValue == nil or displayFieldsString == '' then
        return i18n['error_generate_table_args']
    end

    local songData = GetValuesTable()
    local displayFields = mw.text.split(displayFieldsString, ',')
    local matchingKeys = {}
    
    for songId, songEntry in pairs(songData) do
        local currentValue = ValueFromValuesByKey(songEntry, conditionField)
        if currentValue == conditionValue then
            table.insert(matchingKeys, songId)
        end
    end
    
    table.sort(matchingKeys)

    if #matchingKeys == 0 then
        return '未找到符合条件的歌曲。'
    end

    local output = {}
    
    -- 表格样式: 宽度 100%, 居中, 内容居中
    table.insert(output, '{| class="wikitable sortable" style="width: 100%; margin: 0 auto; text-align: center;"')
    
    -- 构造表格头部 (保持不变)
    table.insert(output, '|-')
    for _, field in ipairs(displayFields) do
        field = mw.text.trim(field)
        table.insert(output, '! ' .. (displayNames[field] or field))
    end
    
    -- 构造表格行
    for _, songId in ipairs(matchingKeys) do
        local songEntry = songData[songId]
        table.insert(output, '|-') -- 新行开始
        
        -- 数据字段
        for _, field in ipairs(displayFields) do
            field = mw.text.trim(field)
            
            local rawValue = ValueFromValuesByKey(songEntry, field)
            
            -- 步骤 1: 基础格式化
            local formattedValue = formatSingleValue(rawValue, field)
            
            -- 步骤 2: **仅在表格中**应用特殊样式
            
            -- 应用 BPM 样式
            if field == 'bpm' then
                formattedValue = formatBPMValue(formattedValue)
            end

            -- 应用难度样式
            local _, mode = getDifficultyDetails(field)
            if mode then
                -- 调用难度样式函数,它负责所有颜色和光晕 (不添加 'sc' 前缀)
                formattedValue = formatDifficultyStyles(formattedValue, mode)
            end
            
            -- 确保每个单元格都在自己的行上
            table.insert(output, '|' .. formattedValue)
        end
    end
    
    table.insert(output, '|}')
    
    -- 使用 \n 连接所有行,确保 MediaWiki 解析器能识别所有表格元素
    return table.concat(output, '\n')
end

return p