Release v0.1.30: improve daily workflows and mobile layout

This commit is contained in:
Codex
2026-10-04 20:37:14 +08:00
parent 693dd2a10a
commit a77fcc6671
19 changed files with 252 additions and 54 deletions
+41 -15
View File
@@ -2,6 +2,21 @@
pageInfo.journal=['个人记事','一言一照,都是阅历。私藏或分享,由自己决定。'];
let journalGeneration=0,journalData=null,journalPage=0,journalUpload=false,journalRequest=null,journalRecorder=null,journalTracks=null,journalVoice=[],journalVoiceTimer=null,journalConfigRevision=0;
const journalDraftMedia=new Set(),journalSelectedMedia=new Set();
let journalBaseline='',journalSaving=false;
function journalDraftSignature(){const f=$('#journal-form');return JSON.stringify([f.elements.text.value,f.elements.occurredOn.value,f.elements.category.value,f.elements.visibility.value,[...journalSelectedMedia].sort()]);}
function journalHasDraft(){return journalUpload||!!journalTracks||!!journalBaseline&&journalDraftSignature()!==journalBaseline;}
function confirmJournalDiscard(){if(journalSaving){toast('记事正在保存,请稍候。');return false;}return !journalHasDraft()||confirm('当前记事尚未保存,确定放弃本次输入吗?已上传的附件仍保留在附件库中。');}
function resetJournalFilters(mode=$('#journal-mode').value){
for(const id of ['journal-category','journal-search','journal-from','journal-to'])$('#'+id).value='';
$('#journal-mode').value=mode;if(mode!=='person')$('#journal-person').value='';
$('#journal-person-label').hidden=mode!=='person';journalPage=0;
}
function journalEmptyMessage(){
if(['journal-category','journal-search','journal-from','journal-to'].some(id=>$('#'+id).value))return '没有符合筛选条件的记事,可以点击“清除筛选”再查看。';
if($('#journal-mode').value==='feed')return '还没有分享给当前家庭/场所的动态。仅自己可见的记事,请切换到“我的个人阅历”。';
if($('#journal-mode').value==='person')return $('#journal-person').value?'此人暂无分享给当前家庭/场所的记事。':'请先选择要查看的人物。';
return '还没有个人记事,写下今天,也可以补记从前。';
}
const journalId=()=>[...crypto.getRandomValues(new Uint8Array(16))].map(b=>b.toString(16).padStart(2,'0')).join('');
const journalToday=()=>{const d=new Date();return [d.getFullYear(),String(d.getMonth()+1).padStart(2,'0'),String(d.getDate()).padStart(2,'0')].join('-');};
function journalBusy(value){journalUpload=value;$('#journal-save').disabled=value;$('#journal-new').disabled=value;for(const control of $('#journal-filter').elements)control.disabled=value;$('#journal-prev').disabled=value||!journalData?.page;$('#journal-next').disabled=value||!journalData||(journalData.page+1)*20>=journalData.total;$('#journal-record').disabled=value||!journalData?.connection.connected||!window.isSecureContext||!navigator.mediaDevices?.getUserMedia||!window.MediaRecorder;}
@@ -54,23 +69,24 @@ function leaveJournal(){
$('#journal-list').replaceChildren();$('#journal-files').disabled=false;$('#journal-save').disabled=false;
}
function clearJournalForm(){const f=$('#journal-form');f.reset();for(const key of ['id','revision','clientId'])f.elements[key].value='';}
function resetJournal(){leaveJournal();journalDraftMedia.clear();journalSelectedMedia.clear();$('#journal-library-list').replaceChildren();$('#journal-trash-list').replaceChildren();journalData=null;journalPage=0;clearJournalForm();$('#journal-filter').reset();$('#journal-upload-list').replaceChildren();$('#journal-status').textContent='';$('#journal-person').replaceChildren();$('#journal-files').disabled=true;$('#journal-record').disabled=true;$('#baidu-config').reset();$('#baidu-status').textContent='';$('#baidu-config-status').textContent='';}
function newJournal(){clearJournalForm();stopJournalVoice();journalDraftMedia.clear();journalSelectedMedia.clear();$('#journal-library').open=false;const f=$('#journal-form');for(const input of $('#journal-upload-list').querySelectorAll('input[type=checkbox]'))input.checked=false;f.elements.clientId.value=journalId();f.elements.occurredOn.value=journalToday();$('#journal-save').textContent='保存记事';journalMessage('默认仅自己可见。选择“当前家庭/场所”后才会进入动态。');renderJournalUploads();}
async function loadJournal(){
const g=++journalGeneration;if(!loggedIn)return;
function resetJournal(){leaveJournal();journalBaseline='';journalSaving=false;journalDraftMedia.clear();journalSelectedMedia.clear();$('#journal-library-list').replaceChildren();$('#journal-trash-list').replaceChildren();journalData=null;journalPage=0;clearJournalForm();$('#journal-filter').reset();$('#journal-upload-list').replaceChildren();$('#journal-status').textContent='';$('#journal-person').replaceChildren();$('#journal-files').disabled=true;$('#journal-record').disabled=true;$('#baidu-config').reset();$('#baidu-status').textContent='';$('#baidu-config-status').textContent='';}
function newJournal(){clearJournalForm();stopJournalVoice();journalDraftMedia.clear();journalSelectedMedia.clear();$('#journal-library').open=false;const f=$('#journal-form');for(const input of $('#journal-upload-list').querySelectorAll('input[type=checkbox]'))input.checked=false;f.elements.clientId.value=journalId();f.elements.occurredOn.value=journalToday();$('#journal-save').textContent='保存记事';journalMessage('默认仅自己可见。选择“当前家庭/场所”后才会进入动态。');renderJournalUploads();journalBaseline=journalDraftSignature();}
async function loadJournal(focus=''){
if(journalSaving)return;const g=++journalGeneration;if(!loggedIn)return;
if(!$('#journal-form').elements.clientId.value)newJournal();
$('#journal-person-label').hidden=$('#journal-mode').value!=='person';
const query=new URLSearchParams({mode:$('#journal-mode').value,person:$('#journal-person').value,category:$('#journal-category').value,search:$('#journal-search').value,from:$('#journal-from').value,to:$('#journal-to').value,page:String(journalPage)});
const query=new URLSearchParams({mode:$('#journal-mode').value,person:$('#journal-person').value,category:$('#journal-category').value,search:$('#journal-search').value,from:$('#journal-from').value,to:$('#journal-to').value,page:String(journalPage),focus});
$('#journal-query-status').textContent='正在读取记事…';
try{
const result=await api('/api/journal?'+query);if(!journalValid(g))return;journalData=result;
const result=await api('/api/journal?'+query);if(!journalValid(g))return;journalData=result;journalPage=result.page;
const selected=$('#journal-person').value;$('#journal-person').innerHTML='<option value="">请选择人物</option>'+Object.entries(result.people).map(([id,name])=>`<option value="${esc(id)}">${esc(name)}</option>`).join('');$('#journal-person').value=selected;
$('#journal-query-status').textContent=result.total?`共 ${result.total} 条 · 第 ${result.page+1} 页`:'暂时没有记事。写下今天,也可以补记从前。';
$('#journal-query-status').textContent=result.total?`共 ${result.total} 条 · 第 ${result.page+1} 页`:journalEmptyMessage();
$('#journal-prev').disabled=!result.page;$('#journal-next').disabled=(result.page+1)*20>=result.total;
$('#journal-cloud-note').textContent=result.connection.connected&&!result.connection.reconnect?'附件保存到后台统一连接的百度网盘;可见范围由系统控制。':'文字可直接保存。照片、视频、语音需由超级管理员先连接百度网盘。';
$('#journal-files').disabled=journalUpload||!result.connection.connected||result.connection.reconnect;
$('#journal-record').disabled=$('#journal-files').disabled||!window.isSecureContext||!navigator.mediaDevices?.getUserMedia||!window.MediaRecorder;
renderJournalUploads();renderJournalEntries();
if(focus){const card=$$('#journal-list [data-entry]').find(el=>el.dataset.entry===focus);if(card){card.classList.add('just-saved');card.scrollIntoView({behavior:'smooth',block:'center'});}}
}catch(e){if(!e.stale&&journalValid(g))$('#journal-query-status').textContent=e.message;}
}
function journalUploadCard(m,library=false){
@@ -99,17 +115,23 @@ function renderJournalEntries(){
}
function journalComment(entry,c){return `<p class="journal-comment"><strong>${esc(c.authorName)}</strong> ${esc(c.text)} <small>${esc(new Date(c.createdAt).toLocaleString())}</small>${c.canDelete?` <button class="quiet" data-delete-comment="${esc(c.id)}" data-journal-entry="${esc(entry.id)}">删除评论</button>`:''}</p>`;}
$('#journal-form').addEventListener('submit',async event=>{
event.preventDefault();if(journalUpload){journalMessage('请等当前附件上传完成,或取消上传后保存文字。');return;}
const f=event.currentTarget,g=journalGeneration,button=$('#journal-save');button.disabled=true;
try{await api('/api/journal',{...formValues(f),revision:Number(f.elements.revision.value||0),mediaIds:[...$('#journal-upload-list').querySelectorAll('input:checked')].map(e=>e.value)});if(!journalValid(g))return;newJournal();$('#journal-mode').value='mine';journalPage=0;await loadJournal();journalMessage('已保存,动态与个人阅历使用同一条记录。');}
catch(e){if(!e.stale&&journalValid(g))journalMessage(e.message);}finally{if(journalValid(g)||activePage==='journal')button.disabled=false;}
event.preventDefault();if(journalSaving)return;if(journalUpload){journalMessage('请等当前附件上传完成,或取消上传后保存文字。');return;}
const f=event.currentTarget,g=journalGeneration,session=sessionGeneration;
const payload={...formValues(f),revision:Number(f.elements.revision.value||0),mediaIds:[...$('#journal-upload-list').querySelectorAll('input:checked')].map(e=>e.value)};
const controls=[...f.elements,...$('#journal-filter').elements],disabled=controls.map(el=>el.disabled);
const unlock=()=>controls.forEach((el,i)=>el.disabled=disabled[i]);journalSaving=true;controls.forEach(el=>el.disabled=true);
try{const saved=await api('/api/journal',payload);if(!journalValid(g))return;journalSaving=false;unlock();newJournal();resetJournalFilters('mine');await loadJournal(saved.id);journalMessage('已保存,输入已清空;下方已重新加载个人阅历。');toast('记事已保存,正在展示保存结果');}
catch(e){if(!e.stale&&journalValid(g))journalMessage(e.message);}finally{journalSaving=false;if(session===sessionGeneration)unlock();}
});
$('#journal-new').onclick=newJournal;
$('#journal-filter').onsubmit=e=>{e.preventDefault();journalPage=0;loadJournal();};
$('#journal-new').onclick=()=>{if(!journalSaving&&confirmJournalDiscard())newJournal();};
$('#journal-form').addEventListener('input',()=>{if(!journalUpload&&!journalSaving)journalMessage(journalHasDraft()?'当前输入尚未保存。':'默认仅自己可见。选择“当前家庭/场所”后才会进入动态。');});
$('#journal-filter-clear').onclick=()=>{resetJournalFilters();loadJournal();};
$('#journal-filter').onsubmit=e=>{e.preventDefault();if($('#journal-from').value&&$('#journal-to').value&&$('#journal-from').value>$('#journal-to').value){$('#journal-query-status').textContent='开始日期不能晚于结束日期。';return;}journalPage=0;loadJournal();};
$('#journal-mode').onchange=()=>{$('#journal-person-label').hidden=$('#journal-mode').value!=='person';journalPage=0;loadJournal();};
for(const id of ['journal-person','journal-category'])$('#'+id).onchange=()=>{journalPage=0;loadJournal();};
$('#journal-prev').onclick=()=>{journalPage--;loadJournal();};$('#journal-next').onclick=()=>{journalPage++;loadJournal();};
async function uploadJournalFile(file,resume=''){
if(!file||journalUpload)return;if(!journalData?.connection.connected){journalMessage('请先由超级管理员连接百度网盘。');return;}if(file.size>268435456||!file.size){journalMessage('单个文件须为 1 字节至 256 MB。');return;}
if(!file||journalUpload||journalSaving)return;if(!journalData?.connection.connected){journalMessage('请先由超级管理员连接百度网盘。');return;}if(file.size>268435456||!file.size){journalMessage('单个文件须为 1 字节至 256 MB。');return;}
journalBusy(true);const g=journalGeneration;$('#journal-save').disabled=true;$('#journal-files').disabled=true;$('#journal-cancel-upload').hidden=false;
try{
const hashes=await ZhaoFileHash.blocks(file,(n,total)=>journalMessage('正在计算文件校验:'+Math.round(n/total*100)+'%'),()=>journalValid(g)&&journalUpload);
@@ -148,7 +170,8 @@ document.addEventListener('change',e=>{if(e.target.dataset.journalResume){upload
document.addEventListener('click',async event=>{
const b=event.target.closest('button');if(!b)return;const g=journalGeneration;
if(b.dataset.journalPerson){$('#journal-mode').value='person';$('#journal-person-label').hidden=false;$('#journal-person').value=b.dataset.journalPerson;journalPage=0;loadJournal();return;}
if(b.dataset.journalEdit){const e=journalData.items.find(e=>e.id===b.dataset.journalEdit);if(!e)return;const f=$('#journal-form');clearJournalForm();for(const key of ['id','revision','clientId','text','occurredOn','category','visibility'])f.elements[key].value=e[key];journalDraftMedia.clear();journalSelectedMedia.clear();e.mediaIds.forEach(id=>{journalDraftMedia.add(id);journalSelectedMedia.add(id);});renderJournalUploads();$('#journal-save').textContent='保存修改';for(const input of $('#journal-upload-list').querySelectorAll('input[type=checkbox]'))input.checked=e.mediaIds.includes(input.value);f.scrollIntoView({behavior:'smooth'});return;}
if(b.dataset.journalEdit){if(journalSaving||!confirmJournalDiscard())return;const e=journalData.items.find(e=>e.id===b.dataset.journalEdit);if(!e)return;const f=$('#journal-form');clearJournalForm();for(const key of ['id','revision','clientId','text','occurredOn','category','visibility'])f.elements[key].value=e[key];journalDraftMedia.clear();journalSelectedMedia.clear();e.mediaIds.forEach(id=>{journalDraftMedia.add(id);journalSelectedMedia.add(id);});renderJournalUploads();$('#journal-save').textContent='保存修改';for(const input of $('#journal-upload-list').querySelectorAll('input[type=checkbox]'))input.checked=e.mediaIds.includes(input.value);journalBaseline=journalDraftSignature();f.scrollIntoView({behavior:'smooth'});return;}
if(journalSaving&&(b.dataset.useUpload||b.dataset.detachUpload||b.dataset.removeUpload||b.dataset.restoreUpload))return;
if(b.dataset.useUpload){journalDraftMedia.add(b.dataset.useUpload);journalSelectedMedia.add(b.dataset.useUpload);renderJournalUploads();return;}
if(b.dataset.detachUpload){journalDraftMedia.delete(b.dataset.detachUpload);journalSelectedMedia.delete(b.dataset.detachUpload);renderJournalUploads();return;}
if(b.dataset.previewMedia){previewJournalMedia(b.dataset.previewMedia);return;}
@@ -188,6 +211,7 @@ document.addEventListener('submit',async event=>{
});
async function loadBaiduSettings(){
const g=appearanceGeneration;$('#baidu-admin').hidden=!isPlatformAdmin();if(!isPlatformAdmin())return;
showSettingsSection();
try{const [config,status]=await Promise.all([api('/api/baidu/config'),api('/api/baidu/status')]);if(g!==appearanceGeneration||activePage!=='settings')return;
const f=$('#baidu-config');for(const k of ['appKey','appFolder','redirectUri'])f.elements[k].value=config[k];f.elements.secretKey.value='';f.elements.secretKey.placeholder=config.hasSecret?'已保存,留空保持原值':'填写 SecretKey';journalConfigRevision=config.revision;
$('#baidu-status').textContent=status.connected?(status.reconnect?'网盘授权已失效,请重新连接。':'已连接统一网盘:'+status.account):'尚未连接百度网盘';$('#baidu-connect').disabled=!config.configured;$('#baidu-disconnect').disabled=!status.connected;
@@ -196,4 +220,6 @@ async function loadBaiduSettings(){
$('#baidu-config').onsubmit=async e=>{e.preventDefault();const g=appearanceGeneration,f=e.currentTarget,b=f.querySelector('button');b.disabled=true;try{await api('/api/baidu/config',{...formValues(f),revision:journalConfigRevision});if(g!==appearanceGeneration)return;f.elements.secretKey.value='';await loadBaiduSettings();$('#baidu-config-status').textContent='应用配置已保存,下一步连接百度网盘。';}catch(e){if(!e.stale&&g===appearanceGeneration)$('#baidu-config-status').textContent=e.message;}finally{b.disabled=false;}};
$('#baidu-connect').onclick=async()=>{try{const result=await api('/api/baidu/connect',{});const address=new URL(result.url);if(address.origin!=='https://openapi.baidu.com')throw Error('授权地址不正确');location.assign(result.url);}catch(e){if(!e.stale)$('#baidu-status').textContent=e.message;}};
$('#baidu-disconnect').onclick=async()=>{if(!confirm('解除本机网盘连接后,媒体将暂时无法访问;网盘文件保留。确认解除?'))return;try{await api('/api/baidu/disconnect',{});loadBaiduSettings();}catch(e){if(!e.stale)$('#baidu-status').textContent=e.message;}};
window.addEventListener('beforeunload',event=>{if(loggedIn&&journalHasDraft()){event.preventDefault();event.returnValue='';}});
document.addEventListener('DOMContentLoaded',()=>{const result=new URLSearchParams(location.search).get('baidu');if(result){history.replaceState(null,'',location.pathname);toast(result==='ok'?'网盘授权已保存,请在设置中心查看连接状态。':'授权未完成,请检查回调地址、原登录状态,并重新连接。');}},{once:true});