/* Service selection stays on the left; introductions and website actions stay on the right. */ function serviceItem(item){ const entry=node('button','service-item');entry.type='button';entry.dataset.slug=item.slug;entry.setAttribute('aria-label','查看服务:'+item.title); const active=state.selectedSlug===item.slug;entry.classList.toggle('active',active);entry.setAttribute('aria-pressed',String(active)); const thumb=node('span','service-thumb');thumb.append(caseIcon(window.ServiceProfile.icon(item))); const imageId=window.ServiceProfile.thumbnailId(item); if(imageId){const portrait=item.attributes?.service_thumbnail_focus==='portrait'&&imageId===item.attributes?.service_thumbnail_asset_id;thumb.classList.toggle('service-thumb-portrait',portrait);const image=node('img');image.src=APP_BASE+'api/media/'+imageId;image.alt='';image.loading='lazy';image.addEventListener('error',()=>{image.remove();thumb.classList.remove('service-thumb-portrait')},{once:true});thumb.append(image)} const copy=node('span','service-item-copy');copy.append(node('span','service-type',window.ServiceProfile.type(item)),node('strong','',item.title),node('span','service-item-summary',item.summary||'选择服务,查看完整介绍')); const arrow=node('span','service-item-arrow','›');arrow.setAttribute('aria-hidden','true');entry.append(thumb,copy,arrow);entry.addEventListener('click',()=>openDetail(item.slug,{serviceFocus:true}));return entry; } function serviceIntroduction(card,item){ card.classList.add('service-detail');card.append(node('span','service-type',window.ServiceProfile.type(item))); const website=window.ServiceProfile.website(item.attributes?.service_website_url);if(!website)return; const box=node('section','service-website');box.setAttribute('aria-label','专门服务网站'); const link=node('a','primary service-website-link',(item.attributes.service_website_label||'打开服务网站')+' ↗');link.href=website.href;link.target='_blank';link.rel='noopener noreferrer'; box.append(node('strong','','专门服务网站'),node('p','',website.hostname),link,node('small','','在新标签页打开,保留当前服务介绍。'));card.append(box); } async function renderServices(requestId,options={}){ const section=node('section','service-browser');section.setAttribute('aria-label','已发布服务列表'); const header=node('div','service-list-heading'),count=node('span','service-count','正在加载…');header.append(node('strong','','探索服务'),count); const hint=node('p','service-list-hint','选择服务,在右侧查看介绍与专门网站'); const list=node('div','service-list');list.id='service-list'; const placeholder=node('p','service-loading muted','正在读取服务内容…');placeholder.setAttribute('role','status');list.append(placeholder); const feedback=node('p','feedback');feedback.setAttribute('role','status'); const more=smallButton('加载更多服务',()=>loadPage());more.classList.add('service-load-more');more.hidden=true; section.append(header,hint,list,feedback,more);contentBody.append(section); let page=1,busy=false,complete=false;const seen=new Set(); function updateCount(){count.textContent=complete?seen.size+' 项服务':'已加载 '+seen.size+' 项'} state.serviceController={ensureSelected(item){ if(requestId!==state.request)return; if(!seen.has(item.slug)){list.querySelector('.service-empty')?.remove();seen.add(item.slug);list.prepend(serviceItem(item));hint.hidden=false;updateCount()} list.querySelectorAll('.service-item').forEach(entry=>{const active=entry.dataset.slug===item.slug;entry.classList.toggle('active',active);entry.setAttribute('aria-pressed',String(active))}); }}; async function loadPage(){ if(busy||complete||requestId!==state.request)return;busy=true;more.disabled=true;feedback.textContent='';more.textContent='正在加载…';list.setAttribute('aria-busy','true'); try{ const data=await api(APP_BASE+'api/contents?kind=service&limit=12&page='+page);if(requestId!==state.request)return; placeholder.remove(); for(const item of data.items)if(!seen.has(item.slug)){seen.add(item.slug);list.append(serviceItem(item))} page++;complete=data.items.length<12;more.hidden=complete;more.textContent='加载更多服务';updateCount(); if(!seen.size){const empty=node('div','service-empty');empty.append(caseIcon('enterprise'),node('strong','','新的服务,即将与你见面'),node('p','','服务发布后会列在这里,选择后可阅读介绍并打开专门网站。'));list.append(empty);hint.hidden=true} if(page===2&&seen.size&&!options.content&&!state.selectedSlug)await openDetail(list.querySelector('.service-item').dataset.slug,{updateHistory:false,serviceFocus:false}); }catch(error){if(requestId!==state.request)return;placeholder.remove();feedback.textContent=error.message;count.textContent=seen.size?'已加载 '+seen.size+' 项':'暂未加载';more.hidden=false;more.textContent='重新加载服务'} finally{busy=false;more.disabled=false;list.setAttribute('aria-busy','false')} } await loadPage(); }