模块:Schedule
来自星砂岛百科
更多操作
概述
Schedule 用于读取并展示角色行程数据,供 {{Schedule}} 与人物页“日程”章节调用。
用法
{{#invoke:Schedule|getField|晨星|calendar_id}}
{{#invoke:Schedule|renderSchedule|晨星}}
示例
{{#invoke:Schedule|renderSchedule|晨星}}
函数
getField:读取行程记录的顶层字段,如calendar_id、regular_count、special_count。renderSchedule:输出角色的日程区块,按常规、特殊、同居三类分组展示。
数据来源
local common = require('Module:Common')
local p = {}
local schedule_data
local mapping
local location_labels
local source_order = {
regular = 1,
special = 2,
living_together = 3,
}
local source_labels = {
regular = '常规日程',
special = '特殊日程',
living_together = '同居日程',
}
local month_labels = {
spring = '春季',
summer = '夏季',
autumn = '秋季',
winter = '冬季',
}
local weekday_labels = {
monday = '周一',
tuesday = '周二',
wednesday = '周三',
thursday = '周四',
friday = '周五',
saturday = '周六',
sunday = '周日',
}
local season_number_labels = {
['1'] = '春季',
['2'] = '夏季',
['3'] = '秋季',
['4'] = '冬季',
}
local weekday_number_labels = {
['0'] = '周日',
['1'] = '周一',
['2'] = '周二',
['3'] = '周三',
['4'] = '周四',
['5'] = '周五',
['6'] = '周六',
}
local weather_labels = {
Rain = '雨天',
ClearSky = '晴天',
Snow = '雪天',
}
local festival_labels = {
['Festival.SpringFestivalActivity_POI_AfterFestival'] = '春节前',
['Festival.SpringFestivalActivity_POI_InFestival'] = '春节期间',
}
local buildable_labels = {
BuildableRegion_Boat = '渡口建造',
}
local compare_op_labels = {
Equal = '等于',
GreatOrEqualThan = '大于等于',
GreatThan = '大于',
LessOrEqualThan = '小于等于',
LessThan = '小于',
Between = '介于',
}
local generic_condition_descs = {
['On Raining Days'] = true,
['雨天日程'] = true,
['雨雪天'] = true,
['雨雪天日程'] = true,
}
local generic_mission_goals = {
['执行互动'] = true,
}
local function default_mapping()
return {
name_to_id = {},
id_to_name = {},
aliases = {},
overrides = {
name_to_id = {},
aliases = {},
},
}
end
local function normalize_key(value)
return common.normalizeKey(value)
end
local function copy_array(values)
local out = {}
if type(values) ~= 'table' then
return out
end
for _, value in ipairs(values) do
out[#out + 1] = value
end
return out
end
local function append_unique(target, values)
if type(target) ~= 'table' or type(values) ~= 'table' then
return
end
local seen = {}
for _, value in ipairs(target) do
seen[tostring(value)] = true
end
for _, value in ipairs(values) do
local key = tostring(value)
if not seen[key] then
target[#target + 1] = value
seen[key] = true
end
end
end
local function sort_text_list(values, order_map)
table.sort(values, function(a, b)
local a_key = tostring(a)
local b_key = tostring(b)
local a_rank = order_map and order_map[a_key] or nil
local b_rank = order_map and order_map[b_key] or nil
if a_rank and b_rank and a_rank ~= b_rank then
return a_rank < b_rank
end
if a_rank and not b_rank then
return true
end
if b_rank and not a_rank then
return false
end
return a_key < b_key
end)
end
local function sort_number_list(values)
table.sort(values, function(a, b)
return tonumber(a) < tonumber(b)
end)
end
local function load_data()
if schedule_data then
return
end
schedule_data = common.loadJsonData('数据:Character/character_schedule_index.json') or {}
mapping = common.loadJsonData('数据:Character/character_mapping.json') or default_mapping()
location_labels = common.loadJsonData('数据:Character/schedule_location_labels.json') or {}
end
local function find_record(key)
load_data()
local resolved = common.trim(key)
if resolved == '' then
resolved = common.getCurrentTitleText()
end
local normalized = normalize_key(resolved)
if schedule_data[normalized] then
return schedule_data[normalized]
end
local override_id = mapping.overrides and mapping.overrides.name_to_id and mapping.overrides.name_to_id[normalized]
if override_id and schedule_data[normalize_key(override_id)] then
return schedule_data[normalize_key(override_id)]
end
local override_alias = mapping.overrides and mapping.overrides.aliases and mapping.overrides.aliases[normalized]
if override_alias and schedule_data[normalize_key(override_alias)] then
return schedule_data[normalize_key(override_alias)]
end
local mapped_id = mapping.name_to_id and mapping.name_to_id[normalized]
if mapped_id and schedule_data[normalize_key(mapped_id)] then
return schedule_data[normalize_key(mapped_id)]
end
local alias_id = mapping.aliases and mapping.aliases[normalized]
if alias_id and schedule_data[normalize_key(alias_id)] then
return schedule_data[normalize_key(alias_id)]
end
return nil
end
local function list_key(values)
if type(values) ~= 'table' then
return ''
end
local out = {}
for _, value in ipairs(values) do
out[#out + 1] = tostring(value)
end
return table.concat(out, ',')
end
local function build_condition_key(items)
if type(items) ~= 'table' then
return ''
end
local out = {}
for _, item in ipairs(items) do
if type(item) == 'table' then
out[#out + 1] = table.concat({
common.trim(item.type),
tostring(item.reverse),
common.trim(item.dest_type),
common.trim(item.key),
common.trim(item.tag),
common.trim(item.op),
common.trim(item.value),
tostring(item.check_day),
tostring(item.check_month),
tostring(item.check_weekday),
tostring(item.check_year),
common.trim(item.year_op),
common.trim(item.year_value),
}, '~')
end
end
return table.concat(out, '||')
end
local function build_slot_key(slots)
if type(slots) ~= 'table' then
return ''
end
local out = {}
for _, slot in ipairs(slots) do
if type(slot) == 'table' then
local primary_action = slot.primary_action
local primary_template = ''
if type(primary_action) == 'table' then
primary_template = common.trim(primary_action.template)
end
out[#out + 1] = table.concat({
common.trim(slot.begin_time),
common.trim(slot.end_time),
common.trim(slot.kind),
common.trim(slot.summary),
common.trim(slot.mission_template),
primary_template,
}, '~')
end
end
return table.concat(out, '||')
end
local function clone_variant(variant)
return {
source = common.trim(variant.source),
schedule_id = common.trim(variant.schedule_id),
months = copy_array(variant.months),
month_labels = copy_array(variant.month_labels),
weekdays = copy_array(variant.weekdays),
weekday_labels = copy_array(variant.weekday_labels),
days = copy_array(variant.days),
priority = variant.priority,
condition_desc = common.trim(variant.condition_desc),
condition_summary = variant.condition_summary or {},
condition_raw = variant.condition_raw or {},
slots = variant.slots or {},
}
end
local function merge_variants(variants)
local grouped = {}
local order = {}
if type(variants) ~= 'table' then
return order
end
for _, variant in ipairs(variants) do
if type(variant) == 'table' then
local key = table.concat({
common.trim(variant.source),
common.trim(variant.schedule_id),
list_key(variant.months),
list_key(variant.days),
common.trim(variant.condition_desc),
build_condition_key(variant.condition_summary),
build_slot_key(variant.slots),
}, '|')
if not grouped[key] then
grouped[key] = clone_variant(variant)
order[#order + 1] = grouped[key]
else
append_unique(grouped[key].weekdays, variant.weekdays or {})
append_unique(grouped[key].weekday_labels, variant.weekday_labels or {})
append_unique(grouped[key].months, variant.months or {})
append_unique(grouped[key].month_labels, variant.month_labels or {})
append_unique(grouped[key].days, variant.days or {})
end
end
end
for _, variant in ipairs(order) do
sort_number_list(variant.months)
sort_number_list(variant.weekdays)
sort_number_list(variant.days)
sort_text_list(variant.month_labels, {
spring = 1,
summer = 2,
autumn = 3,
winter = 4,
})
sort_text_list(variant.weekday_labels, {
monday = 1,
tuesday = 2,
wednesday = 3,
thursday = 4,
friday = 5,
saturday = 6,
sunday = 7,
})
end
table.sort(order, function(a, b)
local a_source = source_order[a.source] or 99
local b_source = source_order[b.source] or 99
if a_source ~= b_source then
return a_source < b_source
end
local a_month = tonumber(a.months[1] or 99) or 99
local b_month = tonumber(b.months[1] or 99) or 99
if a_month ~= b_month then
return a_month < b_month
end
local a_weekday = tonumber(a.weekdays[1] or 99) or 99
local b_weekday = tonumber(b.weekdays[1] or 99) or 99
if a_weekday ~= b_weekday then
return a_weekday < b_weekday
end
local a_day = tonumber(a.days[1] or 99) or 99
local b_day = tonumber(b.days[1] or 99) or 99
if a_day ~= b_day then
return a_day < b_day
end
local a_desc = common.trim(a.condition_desc)
local b_desc = common.trim(b.condition_desc)
if a_desc ~= b_desc then
return a_desc < b_desc
end
return common.trim(a.schedule_id) < common.trim(b.schedule_id)
end)
return order
end
local function map_labels(values, label_map)
if type(values) ~= 'table' then
return {}
end
local out = {}
for _, value in ipairs(values) do
local text = common.trim(value)
if text ~= '' then
out[#out + 1] = label_map[text] or text
end
end
return out
end
local function join_parts(values)
if type(values) ~= 'table' or #values == 0 then
return ''
end
return table.concat(values, '、')
end
local function unique_texts(values)
local out = {}
local seen = {}
if type(values) ~= 'table' then
return out
end
for _, value in ipairs(values) do
local text = common.trim(value)
if text ~= '' and not seen[text] then
out[#out + 1] = text
seen[text] = true
end
end
return out
end
local function rank_candidates(candidates)
local ranked = {}
if type(candidates) ~= 'table' then
return ranked
end
for _, candidate in ipairs(candidates) do
if type(candidate) == 'table' then
ranked[#ranked + 1] = candidate
end
end
table.sort(ranked, function(a, b)
local a_weight = tonumber(a.weight or 0) or 0
local b_weight = tonumber(b.weight or 0) or 0
if a_weight ~= b_weight then
return a_weight > b_weight
end
local a_score = tonumber(a.score or 0) or 0
local b_score = tonumber(b.score or 0) or 0
if a_score ~= b_score then
return a_score > b_score
end
return common.trim(a.template) > common.trim(b.template)
end)
return ranked
end
local function get_top_candidates(candidates)
local ranked = rank_candidates(candidates)
if #ranked == 0 then
return ranked, {}
end
local first = ranked[1]
local top_weight = tonumber(first.weight or 0) or 0
local top_score = tonumber(first.score or 0) or 0
local top = {}
for _, candidate in ipairs(ranked) do
local weight = tonumber(candidate.weight or 0) or 0
local score = tonumber(candidate.score or 0) or 0
if weight == top_weight and score == top_score then
top[#top + 1] = candidate
else
break
end
end
return ranked, top
end
local function clean_condition_desc(value)
local text = common.trim(value)
text = mw.ustring.gsub(text, '^%*+', '')
return common.trim(text)
end
local function should_use_structured_condition(desc)
local cleaned = clean_condition_desc(desc)
if cleaned == '' then
return true
end
if generic_condition_descs[cleaned] then
return true
end
if mw.ustring.find(cleaned, '[A-Za-z]') and not mw.ustring.find(cleaned, '[一-龥]') then
return true
end
return false
end
local function describe_compare_range(op, value, min_value, max_value, label_map, suffix)
local resolved_op = common.trim(op)
local resolved_value = common.trim(value)
local resolved_min = common.trim(min_value)
local resolved_max = common.trim(max_value)
local resolved_suffix = suffix or ''
local function map_value(raw)
local key = common.trim(raw)
if key == '' then
return ''
end
if label_map and label_map[key] then
return label_map[key]
end
return key .. resolved_suffix
end
if resolved_op == 'Equal' and resolved_value ~= '' then
return map_value(resolved_value)
end
if resolved_op == 'Between' and resolved_min ~= '' and resolved_max ~= '' then
local left = map_value(resolved_min)
local right = map_value(resolved_max)
if label_map then
return left .. ' - ' .. right
end
return resolved_min .. ' - ' .. resolved_max .. resolved_suffix
end
local compare_label = compare_op_labels[resolved_op] or resolved_op
if compare_label ~= '' and resolved_value ~= '' then
return compare_label .. map_value(resolved_value)
end
return ''
end
local function build_apply_text(variant)
local parts = {}
local months = map_labels(variant.month_labels, month_labels)
local weekdays = map_labels(variant.weekday_labels, weekday_labels)
local days = {}
for _, day in ipairs(variant.days or {}) do
local value = common.trim(day)
if value ~= '' then
days[#days + 1] = value .. '日'
end
end
if #months > 0 then
parts[#parts + 1] = join_parts(months)
end
if #weekdays > 0 then
parts[#parts + 1] = join_parts(weekdays)
end
if #days > 0 then
parts[#parts + 1] = join_parts(days)
end
return table.concat(parts, ' / ')
end
local function describe_condition_item(item)
if type(item) ~= 'table' then
return ''
end
if item.type == 'weather_today' then
local dest_type = common.trim(item.dest_type)
local label = weather_labels[dest_type] or dest_type
if label ~= '' then
if item.reverse then
return '非' .. label
end
return label
end
return '天气条件'
end
if item.type == 'entity_data_check_string' then
local key = common.trim(item.key)
local op = common.trim(item.op)
local value = common.trim(item.value)
if key == 'Schedule_Typhoon' and value == '1' then
if item.reverse then
return '非台风天气'
end
return '台风天气'
end
if key ~= '' and value ~= '' then
local prefix = item.reverse and '不满足:' or ''
if op ~= '' then
return prefix .. key .. ' ' .. op .. ' ' .. value
end
return prefix .. key .. ' = ' .. value
end
end
if item.type == 'npc_affection_star' then
local value = common.trim(item.value)
if value == '' then
return item.reverse and '好感条件不满足' or '好感条件'
end
local op = common.trim(item.op)
if op == 'GreatOrEqualThan' then
return item.reverse and ('好感度未达到 ' .. value .. ' 心') or ('好感度达到 ' .. value .. ' 心')
end
if op == 'Equal' then
return item.reverse and ('好感度不为 ' .. value .. ' 心') or ('好感度为 ' .. value .. ' 心')
end
local compare_label = compare_op_labels[op] or op
if compare_label ~= '' then
return item.reverse and ('好感条件不满足 ' .. compare_label .. ' ' .. value .. ' 心') or ('好感度 ' .. compare_label .. ' ' .. value .. ' 心')
end
return item.reverse and '好感条件不满足' or '好感条件'
end
if item.type == 'calendar_now_is_festival' then
local festival_template = common.trim(item.festival_template)
local label = festival_labels[festival_template] or festival_template
if label ~= '' then
if item.reverse then
return '非' .. label
end
return label
end
return item.reverse and '非节庆期间' or '节庆期间'
end
if item.type == 'buildable_region_check_completed' then
local template_name = common.trim(item.template)
local label = buildable_labels[template_name] or template_name
if label ~= '' then
if item.reverse then
return label .. '未完成'
end
return label .. '已完成'
end
return item.reverse and '建筑条件未完成' or '建筑条件已完成'
end
if item.type == 'check_has_owner' then
if item.reverse then
return '未被收养'
end
return '已被收养'
end
if item.type == 'time_check_date' then
local parts = {}
if item.check_month then
local month_text = describe_compare_range(
item.month_op,
item.month_value,
item.month_min_value,
item.month_max_value,
season_number_labels
)
if month_text ~= '' then
parts[#parts + 1] = month_text
else
parts[#parts + 1] = '月份'
end
end
if item.check_day then
local day_text = describe_compare_range(
item.day_op,
item.day_value,
item.day_min_value,
item.day_max_value,
nil,
'日'
)
if day_text ~= '' then
parts[#parts + 1] = day_text
else
parts[#parts + 1] = '日期'
end
end
if item.check_weekday then
local weekday_text = describe_compare_range(
item.weekday_op,
item.weekday_value,
item.weekday_min_value,
item.weekday_max_value,
weekday_number_labels
)
if weekday_text ~= '' then
parts[#parts + 1] = weekday_text
else
parts[#parts + 1] = '星期'
end
end
if item.check_year then
local year_text = ''
if common.trim(item.year_op) == 'Equal' and common.trim(item.year_value) ~= '' then
year_text = '第' .. common.trim(item.year_value) .. '年'
else
year_text = describe_compare_range(
item.year_op,
item.year_value,
item.year_min_value,
item.year_max_value
)
if year_text ~= '' then
year_text = '年份' .. year_text
end
end
if year_text ~= '' then
parts[#parts + 1] = year_text
else
parts[#parts + 1] = '年份'
end
end
if #parts > 0 then
local text = table.concat(parts, '')
if item.reverse then
return '非' .. text
end
return text
end
return item.reverse and '日期条件不满足' or '日期条件'
end
return '特殊条件'
end
local function build_condition_text(variant)
local condition_desc = clean_condition_desc(variant.condition_desc)
local summary = variant.condition_summary
local parts = {}
if type(summary) == 'table' then
for _, item in ipairs(summary) do
local text = describe_condition_item(item)
if text ~= '' then
parts[#parts + 1] = text
end
end
end
local structured_text = table.concat(unique_texts(parts), ';')
if condition_desc == '' then
return structured_text
end
if structured_text == '' then
return condition_desc
end
if should_use_structured_condition(condition_desc) then
return structured_text
end
return condition_desc
end
local function build_variant_heading(variant)
local parts = {}
local apply_text = build_apply_text(variant)
local condition_text = build_condition_text(variant)
if apply_text ~= '' then
parts[#parts + 1] = apply_text
end
if condition_text ~= '' then
parts[#parts + 1] = condition_text
end
if #parts == 0 then
return '默认'
end
return table.concat(parts, ' | ')
end
local function localize_location(value)
local text = common.trim(value)
if text == '' then
return ''
end
local direct = location_labels[text]
if direct then
return direct
end
local festival_base = text:match('^(.-)_BeachFestival$')
if festival_base then
local base = localize_location(festival_base)
if base ~= '' and base ~= festival_base then
return base .. '(海滩节)'
end
end
local location, actor = text:match('^(.-)_([A-Za-z][A-Za-z0-9]+)$')
if location and actor and location_labels[location] then
return location_labels[location] .. '(' .. actor .. ')'
end
return text:gsub('_', ' / ')
end
local function format_candidate_text(candidate)
if type(candidate) ~= 'table' then
return ''
end
local display_name = common.trim(candidate.display_name)
local location = localize_location(candidate.location_hint)
local template_name = common.trim(candidate.template)
if display_name ~= '' and location ~= '' then
return display_name .. '(' .. location .. ')'
end
if display_name ~= '' then
return display_name
end
if location ~= '' and template_name ~= '' then
return template_name .. '(' .. location .. ')'
end
return template_name
end
local function candidate_activity_text(candidate)
if type(candidate) ~= 'table' then
return ''
end
local display_name = common.trim(candidate.display_name)
if display_name ~= '' then
return display_name
end
return common.trim(candidate.template)
end
local function candidate_location_text(candidate)
if type(candidate) ~= 'table' then
return ''
end
return localize_location(candidate.location_hint)
end
local function format_slot_time(slot)
local begin_time = common.trim(slot.begin_time)
local end_time = common.trim(slot.end_time)
if begin_time ~= '' and end_time ~= '' then
return begin_time .. ' - ' .. end_time
end
return begin_time ~= '' and begin_time or end_time
end
local function format_slot_activity(slot)
if type(slot) ~= 'table' then
return ''
end
if common.trim(slot.kind) == 'mission' then
local mission_display = common.trim(slot.mission_display)
if mission_display ~= '' then
return mission_display
end
local mission_title = common.trim(slot.mission_title)
if mission_title ~= '' then
return mission_title
end
return '任务'
end
local ranked_candidates, top_candidates = get_top_candidates(slot.action_candidates)
if #top_candidates > 1 then
local texts = {}
for _, candidate in ipairs(top_candidates) do
texts[#texts + 1] = candidate_activity_text(candidate)
end
return table.concat(unique_texts(texts), ' / ')
end
local primary_action = slot.primary_action
if type(primary_action) ~= 'table' then
if #ranked_candidates > 0 then
return candidate_activity_text(ranked_candidates[1])
end
return common.trim(slot.summary)
end
local display_name = common.trim(primary_action.display_name)
if display_name ~= '' then
return display_name
end
return common.trim(primary_action.template)
end
local function format_slot_location(slot)
if type(slot) ~= 'table' then
return ''
end
if common.trim(slot.kind) == 'mission' then
return ''
end
local _, top_candidates = get_top_candidates(slot.action_candidates)
if #top_candidates > 1 then
local locations = {}
for _, candidate in ipairs(top_candidates) do
locations[#locations + 1] = candidate_location_text(candidate)
end
return table.concat(unique_texts(locations), ' / ')
end
local primary_action = slot.primary_action
if type(primary_action) ~= 'table' then
return ''
end
return localize_location(primary_action.location_hint)
end
local function format_slot_note(slot)
if type(slot) ~= 'table' then
return ''
end
if common.trim(slot.kind) == 'mission' then
local notes = {}
local mission_goal = common.trim(slot.mission_goal)
local mission_title = common.trim(slot.mission_title)
local mission_template = common.trim(slot.mission_template)
if mission_goal ~= '' and not generic_mission_goals[mission_goal] then
notes[#notes + 1] = mission_goal
elseif mission_title ~= '' and mission_title ~= common.trim(slot.mission_display) then
notes[#notes + 1] = mission_title
end
if mission_template ~= '' then
notes[#notes + 1] = '模板:' .. mission_template
end
return table.concat(notes, ';')
end
local notes = {}
local ranked_candidates, top_candidates = get_top_candidates(slot.action_candidates)
if #top_candidates > 1 then
local top_texts = {}
for _, candidate in ipairs(top_candidates) do
top_texts[#top_texts + 1] = format_candidate_text(candidate)
end
if #top_texts > 0 then
notes[#notes + 1] = '并列候选:' .. table.concat(unique_texts(top_texts), ' / ')
end
elseif #ranked_candidates > 1 then
local candidate_texts = {}
for _, candidate in ipairs(ranked_candidates) do
local text = format_candidate_text(candidate)
if text ~= '' then
candidate_texts[#candidate_texts + 1] = text
end
end
if #candidate_texts > 0 then
notes[#notes + 1] = '候选:' .. table.concat(candidate_texts, ' / ')
end
end
local primary_action = slot.primary_action
if type(primary_action) == 'table' then
local template_name = common.trim(primary_action.template)
local display_name = common.trim(primary_action.display_name)
if template_name ~= '' and display_name == '' then
notes[#notes + 1] = '模板:' .. template_name
end
end
return table.concat(notes, ';')
end
local function render_variant_table(variant)
local root = mw.html.create('table'):addClass('wikitable')
local head = root:tag('tr')
head:tag('th'):wikitext('时间')
head:tag('th'):wikitext('行为')
head:tag('th'):wikitext('地点')
head:tag('th'):wikitext('备注')
for _, slot in ipairs(variant.slots or {}) do
local row = root:tag('tr')
row:tag('td'):wikitext(format_slot_time(slot))
row:tag('td'):wikitext(format_slot_activity(slot))
row:tag('td'):wikitext(format_slot_location(slot))
row:tag('td'):wikitext(format_slot_note(slot))
end
return tostring(root)
end
local function render_group(source, variants)
local items = {}
for _, variant in ipairs(variants) do
if variant.source == source and type(variant.slots) == 'table' and #variant.slots > 0 then
items[#items + 1] = variant
end
end
if #items == 0 then
return ''
end
local out = {}
out[#out + 1] = '=== ' .. (source_labels[source] or source) .. ' ==='
for _, variant in ipairs(items) do
out[#out + 1] = '==== ' .. build_variant_heading(variant) .. ' ===='
out[#out + 1] = render_variant_table(variant)
end
return table.concat(out, '\n')
end
local function filter_display_variants(variants)
local out = {}
if type(variants) ~= 'table' then
return out
end
for _, variant in ipairs(variants) do
if type(variant) == 'table' and type(variant.slots) == 'table' and #variant.slots > 0 then
out[#out + 1] = variant
end
end
return out
end
local function render_schedule_by_key(key)
local record = find_record(key)
if not record then
return ''
end
local variants = filter_display_variants(merge_variants(record.variants))
if #variants == 0 then
return '暂无日程数据。'
end
local out = {}
local summary_counts = {
regular = 0,
special = 0,
living_together = 0,
}
for _, variant in ipairs(variants) do
local source = common.trim(variant.source)
if summary_counts[source] ~= nil then
summary_counts[source] = summary_counts[source] + 1
end
end
local summary = {}
if summary_counts.regular > 0 then
summary[#summary + 1] = '常规 ' .. tostring(summary_counts.regular)
end
if summary_counts.special > 0 then
summary[#summary + 1] = '特殊 ' .. tostring(summary_counts.special)
end
if summary_counts.living_together > 0 then
summary[#summary + 1] = '同居 ' .. tostring(summary_counts.living_together)
end
if #summary > 0 then
out[#out + 1] = "''来源统计:" .. table.concat(summary, ',') .. "。同一条日程下拆开的星期规则已在展示层合并,多候选动作保留在备注列。''"
end
for _, source in ipairs({ 'regular', 'special', 'living_together' }) do
local block = render_group(source, variants)
if block ~= '' then
out[#out + 1] = block
end
end
return table.concat(out, '\n\n')
end
function p.getField(frame)
local key = common.getArg(frame, 1, '')
local field = common.getArg(frame, 2, '')
if field == '' then
return ''
end
local record = find_record(key)
if not record then
return ''
end
return common.toText(record[field])
end
function p.renderSchedule(frame)
local key = common.getArg(frame, 1, '')
return render_schedule_by_key(key)
end
return p