/* About uses the existing fixed selection and detail panels. */ async function renderAbout(requestId,options={}){ const directory=node('section','about-directory');directory.setAttribute('aria-label','关于我们资料目录'); const loading=node('p','muted','正在读取公司资料…');loading.setAttribute('role','status');directory.append(loading);contentBody.append(directory); let site,items=[],banners=[]; try{ const first=await Promise.all([api(APP_BASE+'api/site'),api(APP_BASE+'api/contents?kind=company&limit=50'),api(APP_BASE+'api/banners?column=about').catch(()=>({items:[]}))]);site=first[0];items=first[1].items;banners=first[2].items; // The API returns pages of at most 50 published records. for(let page=2,previous=items.length;previous===50&&page<=100;page++){ if(requestId!==state.request)return; const next=await api(APP_BASE+'api/contents?kind=company&limit=50&page='+page);items.push(...next.items);previous=next.items.length; } }catch(error){ if(requestId!==state.request)return;clear(directory);showError(directory,error); directory.append(smallButton('重新读取公司资料',()=>setTab('about',false,options)));return; } if(requestId!==state.request)return; const facts=site.facts||{},profile=window.CompanyProfile; const groups=Object.fromEntries(profile.sections.map(section=>[section.key,items.filter(item=>profile.sectionFor(item)===section.key)])); const sections=profile.sections.filter(section=>section.core||groups[section.key].length||profile.fields.some(([key,,group])=>group===section.key&&facts[key]?.trim())); clear(directory); const brand=node('div','about-brand');const logo=node('img','about-brand-logo');logo.src=APP_BASE+'static/assets/vrfab-logo-official-v1.png';logo.alt='VRFAB 虚拟工场';logo.width=450;logo.height=450;logo.addEventListener('error',()=>{logo.hidden=true},{once:true}); const brandCopy=node('div','about-brand-copy');brandCopy.append(node('span','about-eyebrow','ABOUT US'),node('strong','',facts.company_name||'虚拟工场'),node('p','',facts.brand_name||'VRFAB'));brand.append(logo,brandCopy);directory.append(brand); directory.append(node('p','about-directory-hint','选择一项,了解我们与合作方式')); const navigationList=node('nav','about-navigation');navigationList.setAttribute('aria-label','公司资料分类');directory.append(navigationList); for(const section of sections){ const entry=node('button','about-nav-item');entry.type='button';entry.dataset.aboutSection=section.key;entry.setAttribute('aria-pressed','false'); const copy=node('span','about-nav-copy');copy.append(node('strong','',section.title),node('small','',section.description)); const arrow=node('span','about-nav-arrow','›');arrow.setAttribute('aria-hidden','true');entry.append(caseIcon(section.icon),copy,arrow); entry.addEventListener('click',()=>select(section.key,{focus:true}));navigationList.append(entry); } function highlight(key){ clearInterval(state.bannerTimer);state.bannerTimer=null; state.aboutSection=key; navigationList.querySelectorAll('[data-about-section]').forEach(entry=>{const active=entry.dataset.aboutSection===key;entry.classList.toggle('active',active);entry.setAttribute('aria-pressed',String(active))}); detailTitle.textContent='About · '+(sections.find(section=>section.key===key)?.title||'关于我们'); } function moveToDetail(){ if(!state.panelsVisible||!matchMedia('(max-width:800px)').matches)return; detailTitle.tabIndex=-1;detailTitle.focus({preventScroll:true});detailBody.closest('.detail-window').scrollIntoView({block:'start',behavior:matchMedia('(prefers-reduced-motion: reduce)').matches?'instant':'smooth'}); } function addActions(card,key){ const actions=node('div','about-actions'); if(key==='capabilities'){ actions.append(smallButton('浏览产品 ↗',()=>setTab('product')),smallButton('查看服务 ↗',()=>setTab('service')),smallButton('探索案例 ↗',()=>setTab('case'))); }else if(key!=='contact')actions.append(smallButton('探索代表案例 ↗',()=>setTab('case'))); if(key!=='contact')actions.append(smallButton('联系与合作 ↗',()=>select('contact',{focus:true}))); card.append(actions); } function addRelated(card,key,selectedSlug){ if(groups[key].length<2)return; const list=node('section','about-related');list.append(node('h4','','更多'+sections.find(section=>section.key===key).title)); for(const item of groups[key]){ const entry=node('button','about-related-item'+(selectedSlug===item.slug?' active':''));entry.type='button';entry.append(node('strong','',item.title),node('small','',item.summary||'阅读完整介绍')); entry.setAttribute('aria-pressed',String(selectedSlug===item.slug));entry.addEventListener('click',()=>openDetail(item.slug,{aboutFocus:true}));list.append(entry); } card.append(list); } function decorate(card,item){ const key=profile.sectionFor(item);highlight(key);if(key==='intro')addIntroBanner(card);addRelated(card,key,item.slug);addActions(card,key);recommend(key); } function addIntroBanner(card){ if(!banners.length)return; const banner=node('div','about-intro-banner');card.querySelector('h3').after(banner); renderBanners('about',banner,requestId,banners); } function renderFacts(key){ state.detailRequest++;state.contextId=null;state.selectedSlug=null;clear(detailBody);detailBody.setAttribute('aria-busy','false'); const card=node('article','detail-card about-detail');card.append(node('span','kicker',facts.brand_name||'VRFAB'),node('h3','',key==='intro'?(facts.company_name||'虚拟工场'):sections.find(section=>section.key===key).title)); if(key==='intro')addIntroBanner(card); const fields=profile.fields.filter(([field,,group])=>group===key&&!['company_name','brand_name','map_url'].includes(field)&&facts[field]?.trim()); // Keep previously published custom company fields readable in the introduction. if(key==='intro')for(const field of Object.keys(facts))if(field!=='assistant_name'&&!profile.fields.some(([known])=>known===field)&&facts[field]?.trim())fields.push([field,site.labels?.[field]||field]); if(fields.length){ for(const [field,label] of fields){const block=node('section','about-fact');block.append(node('h4','',label)); let link=null; if(field==='phone'&&/^[+\d\s()()-]+$/.test(facts[field])){link=node('a','about-contact-link',facts[field]);link.href='tel:'+facts[field].replace(/[^+\d]/g,'')} if(field==='email'&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(facts[field])){link=node('a','about-contact-link',facts[field]);link.href='mailto:'+facts[field]} block.append(link||node('p','body-text',facts[field]));card.append(block); } }else{ const empty=node('div','about-empty');empty.append(caseIcon(sections.find(section=>section.key===key).icon),node('h4','',key==='customers'?'客户资料整理中':key==='contact'?'期待与你交流':key==='capabilities'?'从产品与案例了解我们的工作':'更多公司介绍,即将与你见面'),node('p','',key==='customers'?'客户信息发布后,将在这里展示。':key==='contact'?'联系资料正在整理,你可以先提交项目需求,或通过底部输入与知微交流。':key==='capabilities'?'浏览已发布的产品、服务和案例,发现与你的项目有关的内容。':'公司介绍正在整理,欢迎先探索我们的产品与案例。'));card.append(empty); } if(key==='contact'){ if(facts.map_url){try{const url=new URL(facts.map_url);if(['https:','http:'].includes(url.protocol)){const map=node('a','about-map-link','在地图中查看 ↗');map.href=url.href;map.target='_blank';map.rel='noopener';card.append(map)}}catch{}} for(const item of groups.contact){ const entry=smallButton(item.title+(item.cover_asset_id?' · 查看大图 ↗':' ↗'),()=>openDetail(item.slug,{aboutFocus:true})); if(item.cover_asset_id){const image=node('img','detail-cover');image.src=APP_BASE+'api/media/'+item.cover_asset_id;image.alt=item.title;image.addEventListener('error',()=>{image.hidden=true},{once:true});entry.classList.add('about-contact-resource');entry.prepend(image)} card.append(entry); } const inquiry=node('button','primary about-inquiry','项目咨询');inquiry.type='button';inquiry.addEventListener('click',()=>{state.detailRequest++;state.contextId=null;clear(detailBody);detailTitle.textContent='About · 项目咨询';renderContact({embedded:true,onBack:()=>select('contact',{updateHistory:false,focus:true})});moveToDetail()});card.append(inquiry); } addActions(card,key);detailBody.append(card);detailBody.scrollTop=0; } async function recommend(key){ const token=++state.recommendationRequest;const kind=key==='capabilities'?'product':key==='contact'?'service':'case'; const body=document.querySelector('#recommend-body');clear(body); body.append(node('strong','','继续了解虚拟工场'),node('p','',key==='contact'?'先了解业务与能力,再聊聊你的项目需求。':'从真实的产品和案例,了解我们的工作。'),smallButton('了解业务与能力 ↗',()=>select('capabilities',{focus:true}))); try{const data=await api(APP_BASE+'api/contents?kind='+kind+'&limit=1');if(token!==state.recommendationRequest||requestId!==state.request||state.tab!=='about'||!data.items.length)return; const item=data.items[0];clear(body);body.append(node('strong','',item.title),node('p','',item.summary||'阅读已发布的详细介绍。'),smallButton('查看详情 ↗',async()=>{await setTab(item.kind);if(state.tab===item.kind)await openDetail(item.slug)})); }catch{/* Keep the useful section shortcut when no related content is available. */} } async function select(key,{updateHistory=true,focus=false}={}){ if(requestId!==state.request)return; if(!sections.some(section=>section.key===key))key='intro'; highlight(key);recommend(key); if(updateHistory){navigation++;writeUrl({tab:'about',about:key,date:null,content:null,asset:null,t:null,page:null})} if(groups[key].length&&key!=='contact')await openDetail(groups[key][0].slug,{updateHistory:false,aboutFocus:focus}); else {renderFacts(key);if(focus)moveToDetail()} } state.aboutController={highlight,decorate,sectionFor:item=>profile.sectionFor(item)}; await select(options.aboutSection||'intro',{updateHistory:false}); } /* Partner logos belong to this published company article and keep the source categories. */ function companyPartnerDescription(card,item){ if(window.CompanyProfile.sectionFor(item)!=='customers'||!Array.isArray(item.attributes?.partner_groups))return null; const images=new Map((item.media||[]).filter(asset=>asset.media_kind==='image').map(asset=>[asset.id,asset])); const groups=item.attributes.partner_groups.filter(group=>typeof group?.label==='string'&&Array.isArray(group.items)).map(group=>({label:group.label,items:group.items.filter(partner=>typeof partner?.name==='string'&&images.has(partner.asset_id))})).filter(group=>group.items.length); if(!groups.length)return null; const refs=new Set(),section=node('section','company-partners'),tabs=node('div','partner-tabs'),panels=node('div','partner-panels'); tabs.setAttribute('role','tablist');tabs.setAttribute('aria-label','合作伙伴分类');tabs.style.setProperty('--partner-categories',groups.length); const controls=[],contents=[];let active=0; function select(index,focus=false){ active=(index+groups.length)%groups.length; controls.forEach((control,i)=>{control.setAttribute('aria-selected',String(i===active));control.tabIndex=i===active?0:-1;contents[i].hidden=i!==active;contents[i].inert=i!==active}); if(focus)controls[active].focus({preventScroll:true}); } groups.forEach((group,index)=>{ const tab=node('button','partner-tab',group.label);tab.type='button';tab.id='partner-tab-'+item.id+'-'+index;tab.setAttribute('role','tab');tab.setAttribute('aria-controls','partner-panel-'+item.id+'-'+index); tab.addEventListener('click',()=>select(index)); tab.addEventListener('keydown',event=>{const next=event.key==='ArrowRight'?active+1:event.key==='ArrowLeft'?active-1:event.key==='Home'?0:event.key==='End'?groups.length-1:null;if(next!==null){event.preventDefault();select(next,true)}}); const panel=node('div','partner-grid');panel.id='partner-panel-'+item.id+'-'+index;panel.setAttribute('role','tabpanel');panel.setAttribute('aria-labelledby',tab.id); for(const partner of group.items){ refs.add('asset:'+partner.asset_id); const tile=node('figure','partner-logo'),image=node('img'),fallback=node('figcaption','partner-fallback',partner.name); image.src=APP_BASE+'api/media/'+partner.asset_id;image.alt=partner.name;image.loading='lazy';image.width=240;image.height=180;fallback.hidden=true; image.addEventListener('error',()=>{image.hidden=true;fallback.hidden=false},{once:true});tile.append(image,fallback);panel.append(tile); } controls.push(tab);contents.push(panel);tabs.append(tab);panels.append(panel); }); section.append(tabs,panels);card.append(section);select(0);return refs; }