跳转到内容

模块:Db:修订间差异

来自DJMAX中文资料库
无编辑摘要
无编辑摘要
第1行: 第1行:
local p = {}
-- 1. 国际化和常量
local i18n = {
['true'] = '是',      -- 布尔值:真
['false'] = '否',    -- 布尔值:假
['none'] = '无',
['category_missing_value'] = '缺失%s',
['error_no_type'] = '<span class="error">b:调用时必须提供type参数。</span>',
}
local displayNames = {
    ['title'] = '歌曲标题',
    ['composer'] = '作曲家',
    ['singer'] = '歌手',
    ['genre'] = '流派',
    ['key'] = 'KEY音',
    ['bpm'] = 'BPM',
    ['pack'] = '曲包',
    ['id'] = '歌曲ID',
    ['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按键数',
}
-- 2. 辅助函数
-- 导入歌曲数据,从 Module:db_song 中获取数据表
local function GetValuesTable()
local function GetValuesTable()
-- 从 Module:db_song 中获取数据。
     return mw.loadData('Module:db_song')
     return mw.loadData('Module:db_song')
end
end


-- 从值列表按照键值获得值,找不到则返回nil。
local function ValueFromValuesByKey(values, key)
local function ValueFromValuesByKey(values, key)
if values and key then
if values and key then
第69行: 第10行:
end
end


-- 3. 值格式化方法 (valueMappingMethod)
-- 格式化单个值的私有函数 (重点:确保此定义被包含)
local valueMappingMethod = {
local function formatSingleValue(value, fieldType)
     -- 格式化函数:将时长(秒)格式化为 'M:SS' 格式
    if value == nil then
        return i18n['none']
    elseif type(value) == 'boolean' then
        return value and i18n['true'] or i18n['false']
     -- 注意:这里调用了 p.valueMappingMethod,它在 p 被返回之前完成定义
    elseif type(p.valueMappingMethod[fieldType]) == 'function' then
        return p.valueMappingMethod[fieldType](value)
    else
        return tostring(value)
    end
end
 
-- 4. 值格式化方法 (valueMappingMethod)
p.valueMappingMethod = {
     ['duration'] = (function (value)
     ['duration'] = (function (value)
         if type(value) == 'number' then
         if type(value) == 'number' then
第80行: 第34行:
         return value
         return value
     end),
     end),
    -- 格式化函数:将艺术家名称自动链接
     ['artist'] = (function (value)
     ['artist'] = (function (value)
         if type(value) == 'string' and value ~= '' then
         if type(value) == 'string' and value ~= '' then
第89行: 第42行:
}
}


-- 4. 外部调用函数 (p.value)
-- [[------------------------------------------------------------------]]
-- [[ 5. 外部调用函数 (p.*) ]]
-- [[------------------------------------------------------------------]]
 
-- p.value 函数体(调用 formatSingleValue)
function p.value(f)
function p.value(f)
local args = f
    local args = f
local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
if f == frame then
if f == frame then
第97行: 第54行:
end
end
      
      
local argTargetName = mw.text.trim(args[1] or '') -- 歌曲ID (键名)
local argTargetName = mw.text.trim(args[1] or '')  
local argType = args.type                       -- 字段名 (type)
local argTypeString = args.type                
local argNocat = args.nocat                    -- 是否禁止分类追踪
local argNocat = args.nocat                     
      
      
     if not argType then
     if not argTypeString then
         return i18n['error_no_type']
         return i18n['error_no_type']
     end
     end
      
      
    -- 1. 加载歌曲数据
     local values = GetValuesTable()  
     local values = GetValuesTable()  
   
    -- 2. 获取目标歌曲条目
     local songEntry = ValueFromValuesByKey(values, argTargetName)
     local songEntry = ValueFromValuesByKey(values, argTargetName)


     if not songEntry then
     if not songEntry then
         -- [处理歌曲ID缺失...]
         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']
         return i18n['none']
     end
     end
      
      
    -- 3. 从歌曲条目中获取特定字段的值
     local fieldNames = mw.text.split(argTypeString, ',')
     local value = ValueFromValuesByKey(songEntry, argType)
     local resultTable = {}
      
 
     if value == nil then
     for _, argType in ipairs(fieldNames) do
         -- [处理特定字段的值缺失...]
         argType = mw.text.trim(argType)
         -- ... (代码省略,与之前版本相同)
         local value = ValueFromValuesByKey(songEntry, argType)
         return i18n['none']
         -- 调用本地函数
    end
        local formattedValue = formatSingleValue(value, argType)
   
          
    -- 4. 应用格式化
         table.insert(resultTable, formattedValue)
   
    -- **新增:优先级最高的布尔值转换**
    if type(value) == 'boolean' then
        if value then
            return i18n['true']
         else
            return i18n['false']
         end
     end
     end
      
      
    -- 接下来应用字段特定的格式化
return table.concat(resultTable, ' / ')
if type(valueMappingMethod[argType]) == 'function' then
return valueMappingMethod[argType](value)
else
-- 转换为字符串输出
return tostring(value)
end
end
end
-- 5. 反向查找
 
function p.findKeysByValue(f)
-- p.findKeysByValue 函数体
function p.findKeysByValue(f)
     local args = f
     local args = f
     local frame = mw.getCurrentFrame()
     local frame = mw.getCurrentFrame()
第154行: 第99行:
      
      
     local targetField = mw.text.trim(args.field or '')
     local targetField = mw.text.trim(args.field or '')
    -- 如果目标值是字符串,清除其两侧空格,否则保持原类型 (如数字)
     local targetValue = args.value  
     local targetValue = args.value  
     if type(targetValue) == 'string' then
     if type(targetValue) == 'string' then
第160行: 第104行:
     end
     end
      
      
    -- 检查必要参数
     if targetField == '' or targetValue == nil then
     if targetField == '' or targetValue == nil then
         return i18n['error_find_keys_args']
         return i18n['error_find_keys_args']
     end
     end


    -- 获取所有歌曲数据
     local songData = GetValuesTable()
     local songData = GetValuesTable()
   
     local matchingKeys = {}
     local matchingKeys = {}
      
      
    -- 遍历数据,查找匹配的键
     for songId, songEntry in pairs(songData) do
     for songId, songEntry in pairs(songData) do
         local currentValue = ValueFromValuesByKey(songEntry, targetField)
         local currentValue = ValueFromValuesByKey(songEntry, targetField)
          
          
        -- 直接比较当前值和目标值
         if currentValue == targetValue then
         if currentValue == targetValue then
             table.insert(matchingKeys, songId)
             table.insert(matchingKeys, songId)
第180行: 第119行:
     end
     end
      
      
    -- 对找到的键进行排序 (可选,但有助于规范输出)
     table.sort(matchingKeys)
     table.sort(matchingKeys)
      
      
    -- 返回以逗号和空格分隔的歌曲ID列表
     return table.concat(matchingKeys, ', ')
     return table.concat(matchingKeys, ', ')
end
end


--6. 表格生成函数
-- p.generateListTable 函数体(调用 formatSingleValue)
function p.generateListTable(f)
function p.generateListTable(f)
     local args = require('Module:ProcessArgs').merge(true)  
     local args = require('Module:ProcessArgs').merge(true)  
第242行: 第179行:
     table.insert(output, '{| class="wikitable sortable"')
     table.insert(output, '{| class="wikitable sortable"')
     table.insert(output, '|-')
     table.insert(output, '|-')
    -- ID 总是第一列
     table.insert(output, '! ' .. (displayNames['id'] or 'ID'))  
     table.insert(output, '! ' .. (displayNames['id'] or 'ID'))  
      
      
     for _, field in ipairs(displayFields) do
     for _, field in ipairs(displayFields) do
         field = mw.text.trim(field)
         field = mw.text.trim(field)
        -- 使用 displayNames 查找列标题
         table.insert(output, '! ' .. (displayNames[field] or field))
         table.insert(output, '! ' .. (displayNames[field] or field))
     end
     end
第256行: 第191行:
         table.insert(output, '|-')
         table.insert(output, '|-')
          
          
        -- 第一列: Song ID
         table.insert(output, '| ' .. songId)  
         table.insert(output, '| ' .. songId)  
          
          
        -- 后续列: 数据字段
         for _, field in ipairs(displayFields) do
         for _, field in ipairs(displayFields) do
             field = mw.text.trim(field)
             field = mw.text.trim(field)
             local rawValue = ValueFromValuesByKey(songEntry, field)
             local rawValue = ValueFromValuesByKey(songEntry, field)
            -- 调用本地函数
             local formattedValue = formatSingleValue(rawValue, field)
             local formattedValue = formatSingleValue(rawValue, field)
             table.insert(output, '| ' .. formattedValue)
             table.insert(output, '| ' .. formattedValue)
第268行: 第202行:
     end
     end
      
      
    -- 闭合表格
     table.insert(output, '|}')
     table.insert(output, '|}')
      
      
     return table.concat(output, '\n')
     return table.concat(output, '\n')
end
end


return p
return p

2025年11月29日 (六) 09:17的版本

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

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


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']
    -- 注意:这里调用了 p.valueMappingMethod,它在 p 被返回之前完成定义
    elseif type(p.valueMappingMethod[fieldType]) == 'function' then
        return p.valueMappingMethod[fieldType](value)
    else
        return tostring(value)
    end
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),
    ['artist'] = (function (value)
        if type(value) == 'string' and value ~= '' then
            return '[[' .. value .. ']]'
        end
        return value
    end),
}

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

-- p.value 函数体(调用 formatSingleValue)
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)
        -- 调用本地函数
        local formattedValue = formatSingleValue(value, argType)
        
        table.insert(resultTable, formattedValue)
    end
    
	return table.concat(resultTable, ' / ')
end

-- p.findKeysByValue 函数体
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

-- p.generateListTable 函数体(调用 formatSingleValue)
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 = {}
    
    -- 构造表格头部
    table.insert(output, '{| class="wikitable sortable"')
    table.insert(output, '|-')
    table.insert(output, '! ' .. (displayNames['id'] or 'ID')) 
    
    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, '|-')
        
        table.insert(output, '| ' .. songId) 
        
        for _, field in ipairs(displayFields) do
            field = mw.text.trim(field)
            local rawValue = ValueFromValuesByKey(songEntry, field)
            -- 调用本地函数
            local formattedValue = formatSingleValue(rawValue, field)
            table.insert(output, '| ' .. formattedValue)
        end
    end
    
    table.insert(output, '|}')
    
    return table.concat(output, '\n')
end

return p