模块:Db:修订间差异
MJ Hamster(留言 | 贡献) 小无编辑摘要 |
MJ Hamster(留言 | 贡献) 小无编辑摘要 |
||
| 第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_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按键数', | |||
['4b_mx'] = '4B MX', | ['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按键数', | |||
['5b_nm'] = '5B NM', | |||
['5b_mx'] = '5B MX', | |||
['6b_nm'] = '6B NM', | |||
['6b_mx'] = '6B MX', | |||
['8b_nm'] = '8B NM', | |||
['8b_mx'] = '8B MX', | |||
} | } | ||
| 第70行: | 第46行: | ||
-- [[------------------------------------------------------------------]] | -- [[------------------------------------------------------------------]] | ||
local function GetValuesTable() | local function GetValuesTable() | ||
return mw.loadData('Module:db_song') | return mw.loadData('Module:db_song') | ||
end | end | ||
| 第81行: | 第56行: | ||
end | end | ||
-- 格式化单个值的私有函数 ( | -- 格式化单个值的私有函数 (基础格式化,不应用任何样式) | ||
local function formatSingleValue(value, fieldType) | local function formatSingleValue(value, fieldType) | ||
if value == nil then | if value == nil then | ||
return i18n['none'] | 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) | ||
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 '' | ||
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') | ||
local mode = checkField:sub(-2) | local mode = checkField:sub(-2) | ||
-- 返回 (btn, mode) | |||
return checkField:match("^(%d+)b"), mode | |||
end | end | ||
| 第126行: | 第99行: | ||
end | end | ||
-- ** | -- **核心:难度样式应用 (仅用于表格)** | ||
local function | 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 | ||
style = style .. ' color: #3D66FF;' | style = style .. ' color: #3D66FF;' | ||
elseif numValue == 13 then | elseif numValue == 13 then | ||
style = style .. ' color: orange;' .. blueGlow | style = style .. ' color: orange;' .. blueGlow | ||
elseif numValue == 14 then | elseif numValue == 14 then | ||
style = style .. ' color: red;' .. blueGlow | style = style .. ' color: red;' .. blueGlow | ||
elseif numValue == 15 then | elseif numValue == 15 then | ||
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 | ||
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) | ||
-- | -- 步骤 1: 基础格式化 | ||
local formattedValue = formatSingleValue(value, argType) | local formattedValue = formatSingleValue(value, argType) | ||
-- SC | -- 步骤 2: 应用 SC 前缀 (仅 p.value 需要,且不带样式) | ||
formattedValue = applySCPrefix(formattedValue, argType) | |||
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;"') | ||
-- 构造表格头部 ( | -- 构造表格头部 (保持不变) | ||
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: 基础格式化 | -- 步骤 1: 基础格式化 | ||
local formattedValue = formatSingleValue(rawValue, field) | local formattedValue = formatSingleValue(rawValue, field) | ||
| 第361行: | 第339行: | ||
-- 应用难度样式 | -- 应用难度样式 | ||
local | local _, mode = getDifficultyDetails(field) | ||
if | if mode then | ||
-- | -- 调用难度样式函数,它负责所有颜色和光晕 (不添加 'sc' 前缀) | ||
formattedValue = | 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