Files
ucvl-home-vision/web/family-events.js
T

74 lines
9.1 KiB
JavaScript
Raw Normal View History

'use strict';
function resetFamilyEvents(purge=false){
for(const id of ['family-event-person','family-event-year','family-event-search','event-person-search'])$('#'+id).value='';
if(purge){$('#family-event-person').replaceChildren();$('#family-event-year').replaceChildren();}
$('#family-event-relatives').checked=false;$('#family-event-state').value='published';$('#family-event-order').value='desc';
for(const id of ['family-timeline','event-detail-content','event-person-choices','family-event-count'])$('#'+id).replaceChildren();
}
function eventStatus(e){return e.archived?'已归档':e.status==='draft'?'草稿':'已发布';}
function eventPeople(e){return e.personIds.map(id=>personName(id)).join('、')||'全家记事';}
function filteredFamilyEvents(){
const person=$('#family-event-person').value,year=$('#family-event-year').value,term=$('#family-event-search').value.trim().toLowerCase();
const status=family.canEdit?$('#family-event-state').value:'published',ids=new Set(person?[person]:[]);
if(person&&$('#family-event-relatives').checked)for(const e of family.links.filter(e=>e.active)){if(e.fromId===person)ids.add(e.toId);if(e.toId===person)ids.add(e.fromId);}
return (family.events||[]).filter(e=>(status==='all'||(status==='archived'?e.archived:!e.archived&&e.status===status))&&(!year||e.eventDate.startsWith(year+'-'))&&(!person||e.personIds.some(id=>ids.has(id)))&&[e.title,e.summary,e.body,e.sourceName].join(' ').toLowerCase().includes(term)).sort((a,b)=>($('#family-event-order').value==='asc'?1:-1)*a.eventDate.localeCompare(b.eventDate)||a.id.localeCompare(b.id));
}
function renderFamilyEvents(){
setOptions($('#family-event-person'),'<option value="">全家</option>'+peopleOptions(false));
const years=[...new Set((family.events||[]).map(e=>e.eventDate.slice(0,4)))].sort().reverse();
setOptions($('#family-event-year'),'<option value="">所有年份</option>'+years.map(y=>`<option value="${esc(y)}">${esc(y)} 年</option>`).join(''));
$('#family-new-event').hidden=!family.canEdit;$('#family-event-state-label').hidden=!family.canEdit;
$('#family-event-relatives').disabled=!$('#family-event-person').value;
const events=filteredFamilyEvents();$('#family-event-count').textContent=`${events.length} 条记事`+($('#family-event-person').value?' · '+personName($('#family-event-person').value)+($('#family-event-relatives').checked?'及相关亲人':''):' · 全家');
let year='';
$('#family-timeline').innerHTML=events.map(e=>{
const next=e.eventDate.slice(0,4),heading=next!==year?`<h3 class="timeline-year">${esc(next)}<span>年</span></h3>`:'';year=next;
return `${heading}<button class="timeline-event ${e.status==='draft'?'draft':''}" data-view-event="${e.id}"><time datetime="${esc(e.eventDate)}">${esc(e.eventDate.slice(5).replace('-','月'))}日</time><span class="timeline-event-body"><span class="timeline-event-status">${esc(eventStatus(e))}</span><strong>${esc(e.title)}</strong><span class="timeline-summary">${esc(e.summary||e.body.slice(0,130)||'查看原始报道')}</span><small>${esc(eventPeople(e))}</small><span class="timeline-read">查看详情${e.sourceUrl?' · 附报道':''} →</span></span></button>`;
}).join('')||empty('这里还没有记事','可调整筛选条件,或写下第一件值得记住的事。');
}
function showPersonEvents(id){familyView='timeline';renderFamily();$('#family-event-person').value=id;$('#family-event-year').value='';$('#family-event-search').value='';$('#family-event-relatives').checked=false;$('#family-event-state').value='published';renderFamilyEvents();$('#family-events').scrollIntoView({behavior:'smooth',block:'start'});}
function personEventSummary(id){
const events=(family.events||[]).filter(e=>e.personIds.includes(id)&&!e.archived&&e.status==='published').sort((a,b)=>b.eventDate.localeCompare(a.eventDate));
return `<section class="person-events"><div class="section-head"><h3>相关重大记事 <small>${events.length}</small></h3>${family.canEdit?`<button class="quiet" data-new-person-event="${id}">+ 记一件事</button>`:''}</div>${(familyView==='timeline'?events.slice(0,3):[]).map(e=>`<button class="person-event-link" data-view-event="${e.id}"><time>${esc(e.eventDate)}</time><span>${esc(e.title)}</span></button>`).join('')||(familyView==='timeline'?'<p class="description">尚无已发布的相关记事。</p>':'')}<button class="quiet" data-person-events="${id}">在时间线追溯 →</button></section>`;
}
function openFamilyEvent(id){
const e=(family.events||[]).find(e=>e.id===id);if(!e)return;
// All content is plain text. External reports are links, never embedded HTML.
const safeSource=/^https?:\/\//i.test(e.sourceUrl||'')?e.sourceUrl:'';
$('#event-detail-content').innerHTML=`<div class="event-detail-meta"><time>${esc(ZhaoCalendar.describe(e.eventDate))}</time><span class="badge">${esc(eventStatus(e))}</span></div><h2 id="event-detail-title">${esc(e.title)}</h2>${e.summary?`<p class="event-lead">${esc(e.summary)}</p>`:''}<div class="event-associated"><span class="description">关联人物</span>${e.personIds.length?e.personIds.map(id=>`<button class="quiet" data-event-person="${esc(id)}">${esc(personName(id))} ↗</button>`).join(''):'<span>全家记事</span>'}</div><div class="family-prose event-article">${esc(e.body||'此条记事暂未填写详细正文。')}</div>${safeSource?`<a class="button secondary event-source" href="${esc(safeSource)}" target="_blank" rel="noopener noreferrer">阅读原始报道${e.sourceName?' · '+esc(e.sourceName):''} ↗</a>`:e.sourceName?`<p class="description">资料来源:${esc(e.sourceName)}</p>`:''}<p class="description event-updated">最近整理:${esc(new Date(e.updatedAt).toLocaleString())}</p>${family.canEdit?`<button data-edit-event="${e.id}">编辑这条记事</button>`:''}`;
$('#event-detail-dialog').showModal();
}
function editFamilyEvent(id,personId=''){
if(!family.canEdit)return;
const e=(family.events||[]).find(e=>e.id===id),f=$('#event-form');
fillForm(f,{...(e||{}),revision:family.revision});
$('#event-editor-title').textContent=e?'编辑家族记事':'写一则家族记事';
const selected=new Set(e?.personIds||(personId?[personId]:[]));
$('#event-person-choices').innerHTML=family.people.map(p=>`<label class="check"><input type="checkbox" name="personIds" value="${esc(p.id)}" ${selected.has(p.id)?'checked':''}>${esc(p.name)}${p.archived?'(已归档)':''}</label>`).join('')||'<p class="description">家谱尚无人名,此条记事将记为全家记事。</p>';
$('#event-person-search').value='';f.dataset.status=e?.status||'draft';
f.querySelector('[data-save-event]').value=f.dataset.status;f.querySelector('[data-save-event]').textContent=e?'保存修改':'保存草稿';
f.querySelector('[data-publish-event]').hidden=f.dataset.status==='published';f.querySelector('[data-withdraw-event]').hidden=f.dataset.status!=='published';
initDateFields(f);if($('#event-detail-dialog').open)$('#event-detail-dialog').close();$('#event-dialog').showModal();
}
$('#event-form').addEventListener('submit',async e=>{
e.preventDefault();const f=e.currentTarget,buttons=[...f.querySelectorAll('[type=submit]')];buttons.forEach(b=>b.disabled=true);
try{syncDateFields(true,f);const data=formValues(f);data.revision=Number(data.revision);data.personIds=[...f.querySelectorAll('[name=personIds]:checked')].map(el=>el.value);data.archived=f.elements.archived.checked;data.status=e.submitter?.value||f.dataset.status||'draft';
const result=await api('/api/family/event',data);$('#event-dialog').close();if(!await loadFamily()){if(loggedIn)toast('记事已保存,读取最新资料失败,请重新载入');return;}familyView='timeline';renderFamily();
$('#family-event-person').value='';$('#family-event-year').value='';$('#family-event-search').value='';$('#family-event-state').value=data.archived?'archived':data.status;renderFamilyEvents();openFamilyEvent(result.item.id);toast(data.archived?'记事已归档,可在“已归档”中恢复':data.status==='published'?'记事已发布到家族时间线':'草稿已保存');
}catch(err){familyFormError(f,err);}finally{buttons.forEach(b=>b.disabled=false);}
});
$('#family-view-timeline').onclick=()=>{familyView='timeline';renderFamily();};
$('#family-new-event').onclick=()=>editFamilyEvent();
for(const id of ['family-event-person','family-event-year','family-event-order','family-event-relatives','family-event-state'])$('#'+id).onchange=renderFamilyEvents;
$('#family-event-search').oninput=renderFamilyEvents;
$('#event-person-search').oninput=()=>{const term=$('#event-person-search').value.trim().toLowerCase();$('#event-person-choices').querySelectorAll('label').forEach(l=>l.hidden=!l.textContent.toLowerCase().includes(term));};
$('#family-event-clear').onclick=()=>{resetFamilyEvents();renderFamilyEvents();};
document.addEventListener('click',e=>{
const b=e.target.closest('button');if(!b)return;
if(b.dataset.viewEvent)openFamilyEvent(b.dataset.viewEvent);
if(b.dataset.editEvent)editFamilyEvent(b.dataset.editEvent);
if(b.dataset.newPersonEvent)editFamilyEvent('',b.dataset.newPersonEvent);
if(b.dataset.personEvents)showPersonEvents(b.dataset.personEvents);
if(b.dataset.eventPerson){$('#event-detail-dialog').close();selectFamilyPerson(b.dataset.eventPerson,true);}
});