'use strict'; const $=(q,el=document)=>el.querySelector(q); const E=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const ATTR=s=>E(s); const cfg={automotive:{label:'汽车与出行',desc:'高级质感 · 深色车型展厅',prev:'auto',title:'Move beyond.'},industrial:{label:'工业制造',desc:'专业理性 · 工业产品展示',prev:'ind',title:'Built to last.'},corporate:{label:'企业品牌',desc:'现代明亮 · 集团企业官网',prev:'corp',title:'Ideas become impact.'},minimal:{label:'极简设计',desc:'编辑式排版 · 极简作品展示',prev:'min',title:'Less, but better.'}}; let csrfToken=''; const state={sites:[],siteId:null,site:null,entries:[],builds:[],tab:'overview',presets:[],query:'',typ:''}; const api=async(path,opt={})=>{ if(!['GET','HEAD','OPTIONS'].includes((opt.method||'GET').toUpperCase())) {opt.headers={...(opt.headers||{}),'X-SiteForge-CSRF':csrfToken}} const res=await fetch(path,opt);if(res.status===401){location.assign('/login');throw new Error('登录已过期')}let data;try{data=await res.json()}catch{data={detail:'请求失败,响应不是 JSON'}} if(!res.ok)throw new Error(typeof data.detail==='string'?data.detail:JSON.stringify(data.detail||data));return data; }; const json=(method,data)=>({method,headers:{'Content-Type':'application/json'},body:JSON.stringify(data)}); const notice=(s,bad=false)=>{const t=$('#toast');t.innerText=s;t.style.background=bad?'#a03e45':'#243952';t.classList.add('show');clearTimeout(t._timer);t._timer=setTimeout(()=>t.classList.remove('show'),4300)}; const onError=e=>{console.error(e);notice(e.message||String(e),true)}; const simpleDate=s=>s?new Date(s).toLocaleString('zh-CN',{year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'}):'—'; const b=(text,fn,extra='')=>``; const tabs=[['overview','工作概览'],['entries','内容管理'],['templates','模板与设计'],['design','可视化页面设计'],['models','内容字段模型'],['import','旧站 / 数据导入'],['seo','SEO / URL'],['builds','构建与导出']]; function topTitle(name){$('#topTitle').textContent=name} function hero(title,desc,buttons='',eyebrow='SITEFORGE / WEBSITE FACTORY'){return `
${E(eyebrow)}

${E(title)}

${E(desc)}

${buttons}
`} function themeCard(key,action){let t=cfg[key];return `
THEME / ${E(key.toUpperCase())}${E(t.title)}

${E(t.label)}

${E(t.desc)}

${action}
`} const App={ async init(){try{const me=await api('/api/auth/me');csrfToken=me.csrf;state.sites=await api('/api/sites');state.presets=await api('/api/presets');App.renderSiteNav();App.openDashboard()}catch(e){onError(e)}}, async logout(){try{await api('/api/auth/logout',{method:'POST'});location.assign('/login')}catch(e){onError(e)}}, async reload(){state.sites=await api('/api/sites');App.renderSiteNav();if(state.siteId){state.site=await api('/api/sites/'+state.siteId);state.entries=await api('/api/sites/'+state.siteId+'/entries');state.builds=await api('/api/sites/'+state.siteId+'/builds')}}, renderSiteNav(){$('#siteNav').innerHTML=state.sites.map(s=>``).join('')||'
暂无网站项目
'}, openDashboard(){state.siteId=null;topTitle('网站总览');App.renderSiteNav();document.querySelectorAll('.side-link').forEach(x=>x.classList.remove('selected'));$('#nav-dashboard').classList.add('selected'); let n=state.sites.length, counts=state.sites.reduce((x,s)=>x+s.entries_count,0),builds=state.sites.reduce((x,s)=>x+s.build_count,0); $('#view').innerHTML=hero('网站生产工作台','从零创建、迁移旧站、导入内容、更换模板,统一生产独立静态网站。',``,'WELCOME TO YOUR FACTORY')+ `
网站总数${n}独立站点项目
内容条目${counts}页面、产品、文章等
构建版本${builds}可预览与下载
可用主题4支持每站独立风格
`+ `

我的网站

选择任意站点,继续编辑、导入数据或构建版本

`+ state.sites.map(s=>`
${E(cfg[s.theme]?.label||'企业站')}
${E(s.name)}

${E(s.name)}

${E(s.domain||'待绑定域名')} · ${E(s.tagline||'尚未填写站点简介')}

${s.entries_count} 条内容${s.build_count} 次构建 →
`).join('')+`
+

创建新网站

旧站迁移 / 新建站点 / 导入内容

`+ (!state.sites.length?`

第一次体验 SiteForge?

生成演示网站,并立即构建一个可独立下载的纯静态网站。

`:''); }, async openSite(id,tab='overview'){try{state.siteId=id;state.tab=tab;await App.reload();topTitle(state.site.name);App.renderSiteNav();App.renderSite()}catch(e){onError(e)}}, renderSite(){const s=state.site;let head=hero(s.name,s.domain||'独立网站 · 尚未设置域名',``,'WEBSITE PROJECT / '+s.theme.toUpperCase()); let navigation=`
${tabs.map(([id,name])=>``).join('')}
`; $('#view').innerHTML=head+`
页面 / 内容${state.entries.length}统一内容数据中心
主题${E(cfg[s.theme]?.label)}可随时切换
构建次数${state.builds.length}独立构建版本
SEO 模式${s.mode==='migration'?'原址保留':'灵活新建'}路由独立管理
`+navigation+`
`;App.renderTab(); }, changeTab(tab){state.tab=tab;App.renderSite()}, renderTab(){let html='';switch(state.tab){case'overview':html=App.overview();break;case'entries':html=App.entriesView();break;case'templates':html=App.templateView();break;case'design':html=App.designView();break;case'models':html=App.modelsView();break;case'import':html=App.importView();break;case'seo':html=App.seoView();break;case'builds':html=App.buildView();break;}$('#tab-content').innerHTML=html;if(state.tab==='import')App.loadMedia();if(state.tab==='seo')App.loadRedirects();if(state.tab==='models')App.loadModels()}, overview(){let s=state.site, latest=state.builds[0];return `

网站生产流程

每次修改内容、主题或域名后都可以重新构建

STEP 01创建网站

选择主题,完成独立站点初始化

STEP 02添加或导入内容

手动录入、旧站采集、文件批量导入

STEP 03主题与 SEO

自定义视觉样式、路由及页面元信息

STEP 04构建并导出

生成静态 HTML 文件,预览并下载 ZIP

网站基本资料

设置域名、品牌和原网站来源

${App.settingsForm()}

最近构建版本

构建文件与管理后台彼此独立

${latest?`
静态构建完成

${latest.total_pages} 个 HTML 页面

${simpleDate(latest.created_at)}

`:`
⌁

还没有构建版本

保存内容并点击「构建网站」,即可生成首个网站。

`}
`}, settingsForm(){let s=state.site;return `
`}, async saveSettings(ev){ev.preventDefault();try{let data=Object.fromEntries(new FormData(ev.target));state.site=await api('/api/sites/'+state.siteId,json('PATCH',data));await App.reload();notice('已保存站点设置');App.renderSite()}catch(e){onError(e)}}, entriesView(){let arr=state.entries.filter(e=>(!state.typ||e.type===state.typ)&&(!state.query||e.title.toLowerCase().includes(state.query.toLowerCase())||e.route.toLowerCase().includes(state.query.toLowerCase())));return `

内容库

页面 / 产品 / 文章 / 自定义内容,支持独立 URL 和 SEO

${arr.length} 条结果
${arr.map(e=>``).join('')}
标题类型路由状态更新时间操作
${E(e.title)}
${E(e.summary||'')}
${E(e.type)}${E(e.route)}${e.status==='published'?'已发布':'草稿'}${simpleDate(e.updated_at)}
页面设计
${arr.length?'':'

尚无匹配内容

新建内容或使用导入中心批量导入

'}
`}, filterContent(){const active=document.activeElement?.id;const caret=active==='searchEntry'?$('#searchEntry').selectionStart:null;state.query=$('#searchEntry')?.value||'';state.typ=$('#typeFilter')?.value||'';$('#tab-content').innerHTML=App.entriesView();if(active==='searchEntry'){const input=$('#searchEntry');input.focus();if(caret!==null)input.setSelectionRange(caret,caret)}}, async updateNavigation(ev){ev.preventDefault();try{const raw=$('#navRoutes').value.split('\n').map(x=>x.trim()).filter(Boolean);const entries=raw.map(line=>{const sep=line.indexOf('|');if(sep<0)throw new Error('每行必须为:导航文字 | /路径/');return {title:line.slice(0,sep).trim(),route:line.slice(sep+1).trim()}});let path='/api/sites/'+state.siteId+'/site-design';let current=await api(path);current.config.nav=entries;await api(path,json('PUT',{config:current.config,expected_revision:current.revision}));notice('导航已保存为全站草稿:'+entries.length+'项,请在设计器中发布全站设计')}catch(e){onError(e)}}, async scaffold(){if(!confirm('创建关于我们、联系我们和服务页面?已有同路径页面不会覆盖。'))return;try{let r=await api('/api/sites/'+state.siteId+'/scaffold',{method:'POST'});await App.reload();App.renderSite();notice('创建 '+r.created.length+' 个页面,跳过 '+r.skipped.length+' 个')}catch(e){onError(e)}}, modelsView(){return `

内容字段模型

自定义产品、车型、品牌、文章等数据字段。字段保存在每个站点自己的配置内,不影响其他站点。

正在读取字段定义……

`}, async loadModels(){try{state.models=await api('/api/sites/'+state.siteId+'/schemas');App.renderModelFields()}catch(e){onError(e)}}, renderModelFields(){let el=$('#modelFields');if(!el||!state.models)return;let kind=$('#modelKind').value;let defs=state.models[kind]||[];el.innerHTML=`${defs.map(d=>App.modelRow(d)).join('')}
字段键名显示名称字段类型
`}, modelRow(d={}){return ``}, addModelField(){if(!$('#fieldRows'))return;$('#fieldRows').insertAdjacentHTML('beforeend',App.modelRow())}, async saveModelFields(){try{const fields=[...document.querySelectorAll('.field-row')].map(tr=>({name:tr.querySelector('.field-key').value.trim(),label:tr.querySelector('.field-label').value.trim(),type:tr.querySelector('.field-type').value}));let kind=$('#modelKind').value;let result=await api('/api/sites/'+state.siteId+'/schemas/'+kind,json('PUT',fields));state.models[kind]=result.fields;notice('已保存 '+kind+' 字段模型')}catch(e){onError(e)}}, designView(){const s=state.site;return `

Visual Studio · 页面可视化工作台

拖动区块顺序、修改属性、自动绑定内容,并在同一个界面预览 PC 和移动端。

${state.entries.filter(e=>e.type==='page'||e.type==='product'||e.type==='post').slice(0,36).map(e=>`
${E(e.type)}

${E(e.title)}

${E(e.route)}

打开可视化编辑器 ↗
`).join('')}

页面编辑后点击构建,系统生成对应的独立静态页面,不会丢失原有 URL 和 SEO。

顶部导航配置

每行:标题 | /原始路径/,不填写则按网站已有栏目自动生成导航。

`}, async applyTemplates(mode){if(!confirm(mode==='overwrite'?'将用当前主题的默认布局覆盖所有页面区块,内容和SEO不变,确定继续?':'将给尚未设置布局的页面自动套用当前主题,确定继续?'))return;try{let r=await api('/api/sites/'+state.siteId+'/apply-theme',json('POST',{mode}));await App.reload();notice('已装配 '+r.updated+' 个页面,跳过 '+r.skipped+' 个');App.renderSite()}catch(e){onError(e)}}, templateView(){let s=state.site;return `

主题样式库

切换后内容、原有 URL 和 SEO 数据不变,重新构建立即产生全新视觉版本

${Object.keys(cfg).map(t=>themeCard(t,``)).join('')}

模板工厂

保存当前主题与首页区块配置,以后创建其他网站时可以直接套用。

当前版本支持页面区块拖拽排序、PC / 手机预览、动态内容绑定。完全自由定位的像素级编辑仍不支持。
`}, importView(){return `

批量导入文件

支持 WordPress XML、CSV、Excel XLSX、JSON

建议 CSV 字段:type, title, route, summary, body, cover, seo_title, seo_description。

旧站公开页面采集

支持 WordPress、普通 HTML 与其他 CMS 的公开内容

公开爬取无法保证包含私有字段、插件数据或复杂动态页面。推荐尽量使用原站完整数据库/导出文件。

素材中心

上传图片,生成本地媒体路径,内容页可直接引用。

上传文件 URL 将返回类似 media/abc123.jpg,静态站构建时自动携带。
`}, seoView(){return `

SEO 保留策略

不因改版随意改变页面 URL

↗
页面 URL Registry

所有现有 URL 由内容库的 route 精确定义;冲突直接禁止保存。

◇
SEO Metadata

编辑内容可以设置 Title、Description、Canonical 和 Robots。

▤
Sitemap + 服务器规则

构建时生成 sitemap.xml、robots.txt、Nginx snippet 和 .htaccess。

301 / 302 重定向管理

原 URL 不能保留时,人工审批后配置对应跳转。

`}, buildView(){return `

静态构建中心

将当前内容、模板和 SEO 路由组合成完全独立的 HTML 文件。

▦
静态 HTML / CSS / JS

无需 PHP、WordPress 或中心 CMS,就能独立部署访问。

▰
可回溯构建版本

每次构建产生独立 ZIP 和版本报告,不会覆盖旧版本。

历史构建

选择版本查看预览、下载 ZIP、检查 SEO/媒体报告

${state.builds.map(x=>{let r=JSON.parse(x.report_json||'{}');return ``}).join('')}
版本 ID构建时间页面数量报告操作
${x.id}${simpleDate(x.created_at)}${x.total_pages}${r.quality_status==='warning'?'有告警':'已通过基础检查'}
预览 ↗ZIP ↓
${state.builds.length?'':'
⌘

尚无构建记录

完成内容编辑后,点击上方按钮生成版本。

'}
`}, async openTemplates(){state.siteId=null;topTitle('模板资源库');App.renderSiteNav();document.querySelectorAll('.side-link').forEach(x=>x.classList.remove('selected'));$('#nav-template').classList.add('selected');$('#view').innerHTML=hero('模板与主题资源库','从四套行业视觉风格开始,逐步沉淀企业自己的模板库。',``)+`
${Object.keys(cfg).map(t=>themeCard(t,``)).join('')}

已保存的模板预设

由已有网站保存,复用主题及首页区块结构。

${state.presets.length?state.presets.map(p=>`
${E(p.name)}

${E(cfg[p.theme]?.label||p.theme)} · ${simpleDate(p.created_at)}

`).join(''):'

暂未保存企业自定义模板

从任意网站的「模板与设计」中保存为模板。

'}
`}, openNewSite(theme='',preset=''){const f=$('#siteForm');f.reset();if(theme)f.elements.theme.value=theme;$('#presetSelector').innerHTML=''+state.presets.map(p=>``).join('');if(preset)f.elements.preset_id.value=preset;$('#siteDialog').showModal()}, closeDialog(id){$('#'+id).close()}, async createSite(ev){ev.preventDefault();try{let values=Object.fromEntries(new FormData(ev.target));let site=await api('/api/sites',json('POST',values));App.closeDialog('siteDialog');notice('网站已创建,可以开始添加内容');await App.openSite(site.id)}catch(e){onError(e)}}, openEntry(id=''){let f=$('#entryForm');f.reset();let e=state.entries.find(x=>x.id===id);f.elements.entry_id.value=id;$('#entryHeading').textContent=id?'编辑内容':'新建内容';if(e){for(let key of ['title','route','summary','body','cover','seo_title','seo_description','canonical','type','status','robots'])if(f.elements[key])f.elements[key].value=e[key]??'';f.elements.meta.value=JSON.stringify(e.meta||{},null,2)}else{f.elements.meta.value='{}';f.elements.type.value='page';f.elements.status.value='published'}$('#entryDialog').showModal();App.loadEntryFields()}, async loadEntryFields(){try{state.models=await api('/api/sites/'+state.siteId+'/schemas');App.renderEntryFields()}catch(e){onError(e)}}, renderEntryFields(){let el=$('#dynamicContentFields');if(!el)return;let kind=$('#entryType').value;let list=(state.models||{})[kind]||[];let parsed={};try{parsed=JSON.parse($('#entryMeta').value||'{}')}catch{};const values=parsed.fields||parsed;el.innerHTML=list.length?`

业务字段 · ${E(kind)}

来自当前网站的字段模型,保存时同步写入内容数据。

${list.map(f=>``).join('')}
`:''}, addBlock(type){const el=$('#entryMeta');let parsed={};try{parsed=JSON.parse(el.value||'{}')}catch{return notice('当前 JSON 格式不合法,先修复后再添加区块',true)}if(!Array.isArray(parsed.blocks))parsed.blocks=[];let obj=({hero:{type:'hero',title:'核心主标题',subtitle:'OUR VISION',description:'可编辑的首页主视觉描述'},features:{type:'features',title:'核心优势',items:[{title:'专业实力',text:'填写优势简介'},{title:'可靠交付',text:'填写优势简介'},{title:'服务网络',text:'填写优势简介'}]},stats:{type:'stats',items:[{value:'30+',label:'合作品牌'},{value:'70+',label:'服务市场'}]},cta:{type:'cta',title:'期待与您合作',subtitle:'联系我们,了解更多服务',button:'联系我们',href:'/contact/'}})[type];parsed.blocks.push(obj);el.value=JSON.stringify(parsed,null,2);notice('已添加区块,请编辑 JSON 中的标题与内容')}, async saveEntry(ev){ev.preventDefault();try{let v=Object.fromEntries(new FormData(ev.target)),id=v.entry_id;delete v.entry_id;v.meta=JSON.parse(v.meta||'{}');const fieldInputs=[...document.querySelectorAll('#dynamicContentFields .sf-data-field')];if(fieldInputs.length){let fields={...(v.meta.fields||{})};for(const input of fieldInputs)fields[input.dataset.key]=input.value;v.meta.fields=fields}if(!id&&!v.route)delete v.route;let endpoint='/api/sites/'+state.siteId+'/entries'+(id?'/'+id:'');await api(endpoint,json(id?'PATCH':'POST',v));App.closeDialog('entryDialog');await App.openSite(state.siteId,'entries');notice(id?'已更新内容':'已创建内容')}catch(e){onError(e)}}, async deleteEntry(id){if(!confirm('确定删除此内容吗?删除之后重新构建才会影响线上静态网站。'))return;try{await api('/api/sites/'+state.siteId+'/entries/'+id,{method:'DELETE'});await App.openSite(state.siteId,'entries');notice('内容已删除')}catch(e){onError(e)}}, async setTheme(theme){if(!confirm('切换到「'+cfg[theme].label+'」?内容和 URL 保持不变,需重新构建才能更新站点。'))return;try{await api('/api/sites/'+state.siteId,json('PATCH',{theme}));await App.openSite(state.siteId,'templates');notice('主题已更换,请重新构建预览')}catch(e){onError(e)}}, async savePreset(){let name=$('#presetName')?.value?.trim();if(!name)return notice('请输入新模板名称',true);try{let result=await api('/api/sites/'+state.siteId+'/save-preset',json('POST',{name}));state.presets=await api('/api/presets');notice('已保存模板:'+result.name)}catch(e){onError(e)}}, async cloneSite(){let name=prompt('新站名称:',state.site.name+' 副本');if(!name)return;try{let newsite=await api('/api/sites/'+state.siteId+'/clone',json('POST',{name}));notice('已克隆全部内容到新网站');await App.openSite(newsite.id)}catch(e){onError(e)}}, async importFile(ev){ev.preventDefault();let btn=$('button[type=submit]',ev.target);btn.disabled=true;btn.innerText='导入中...';try{let form=new FormData(ev.target);let result=await api('/api/sites/'+state.siteId+'/import',{method:'POST',body:form});await App.openSite(state.siteId,'import');notice(`导入完成:新增 ${result.imported},更新 ${result.updated},跳过 ${result.skipped},错误 ${result.errors?.length||0}`);if(result.errors?.length)alert(JSON.stringify(result.errors.slice(0,15),null,2))}catch(e){onError(e)}finally{btn.disabled=false;btn.innerText='开始批量导入'}}, async crawl(ev){ev.preventDefault();if(!confirm('确认对该公开网站进行限定范围采集?请仅采集你拥有或获授权迁移的站点。'))return;let btn=$('button[type=submit]',ev.target);btn.disabled=true;btn.innerText='正在采集...';try{const input=Object.fromEntries(new FormData(ev.target));input.max_pages=+input.max_pages;const r=await api('/api/sites/'+state.siteId+'/crawl',json('POST',input));await App.openSite(state.siteId,'import');notice(`采集完成:发现 ${r.discovered} 页,新增 ${r.imported} 页,页面获取失败 ${r.fetch_errors?.length||0}`)}catch(e){onError(e)}finally{btn.disabled=false;btn.innerText='扫描并导入公开页面'}}, async uploadMediaArchive(file){if(!file)return;try{let form=new FormData();form.append('file',file);notice('正在解压媒体文件...');let r=await api('/api/sites/'+state.siteId+'/media-archive',{method:'POST',body:form});notice(`媒体导入:${r.imported} 文件,跳过 ${r.skipped} 文件`)}catch(e){onError(e)}}, async uploadMedia(file){if(!file)return;try{let fd=new FormData();fd.append('file',file);let r=await api('/api/sites/'+state.siteId+'/media',{method:'POST',body:fd});notice('图片已上传:'+r.url);App.loadMedia()}catch(e){onError(e)}}, async uploadCover(file){if(!file)return;try{let fd=new FormData();fd.append('file',file);let r=await api('/api/sites/'+state.siteId+'/media',{method:'POST',body:fd});$('#coverInput').value=r.url;notice('封面上传成功')}catch(e){onError(e)}}, async loadMedia(){if(state.tab!=='import')return;try{let data=await api('/api/sites/'+state.siteId+'/media');$('#mediaGrid').innerHTML=data.map(x=>`
`).join('')||'

暂无本地素材

'}catch(e){onError(e)}}, async createRedirect(ev){ev.preventDefault();let value=Object.fromEntries(new FormData(ev.target));value.status_code=+value.status_code;try{await api('/api/sites/'+state.siteId+'/redirects',json('POST',value));ev.target.reset();notice('已创建重定向规则');App.loadRedirects()}catch(e){onError(e)}}, async loadRedirects(){if(state.tab!=='seo')return;try{let data=await api('/api/sites/'+state.siteId+'/redirects');$('#redirectList').innerHTML=data.length?'

已有重定向

'+data.map(x=>`

${E(x.old_path)} ${x.status_code} → ${E(x.new_path)}

`).join(''):'

当前没有重定向规则。

'}catch(e){onError(e)}}, async deleteRedirect(id){if(!confirm('确认删除这条规则?'))return;try{await api('/api/sites/'+state.siteId+'/redirects/'+id,{method:'DELETE'});App.loadRedirects()}catch(e){onError(e)}}, async publishLocal(id){if(!confirm('将此版本发布到 Docker 持久化目录?请确认配置好独立站点服务器。'))return;try{const x=await api('/api/sites/'+state.siteId+'/builds/'+id+'/publish-local',{method:'POST'});notice('已发布:'+x.release+'(发布文件位于 Docker 数据卷)')}catch(e){onError(e)}}, async build(){let s=state.siteId;if(!s)return;let mirror=$('#mirrorChoice')?.checked||false; try{let job=await api('/api/sites/'+s+'/builds',{...json('POST',{mirror_images:mirror}),headers:{'Content-Type':'application/json','Idempotency-Key':crypto.randomUUID()}}); notice('已进入后台构建队列:'+job.id+',关闭浏览器也可继续执行'); for(let i=0;i<240;i++){await new Promise(resolve=>setTimeout(resolve,1500)); let status=await api('/api/enterprise/sites/'+s+'/jobs/'+job.id); if(status.state==='done'){let result=JSON.parse(status.result_json||'{}');await App.openSite(s,'builds');notice('构建完成:'+(result.pages||0)+' 个页面');if(result.version)App.showReport(result.version);return} if(status.state==='failed'||status.state==='cancelled'){notice('任务'+status.state+': '+(status.error||''),true);return} }notice('构建仍在后台运行,请在任务中心查看状态'); }catch(e){onError(e)}}, async showReport(id){try{const r=await api('/api/sites/'+state.siteId+'/builds/'+id+'/report');let box=$('#reportBox');if(!box){alert(JSON.stringify(r,null,2));return}box.innerHTML=`

质量报告:${E(id)}

本报告只覆盖当前实现的基础结构与资源检查,不代表 SEO 排名保证。

静态 HTML 数${r.pages}
重定向数${r.redirects}
已镜像图片${r.mirrored_images}
质量告警${r.warnings.length}
${r.warnings.length?`
${r.warnings.map(x=>`• ${E(x)}`).join('
')}
`:'
✓ 当前规则下未发现告警
'}

详细报告

${E(JSON.stringify(r,null,2))}
`;box.scrollIntoView({behavior:'smooth',block:'nearest'})}catch(e){onError(e)}}, async seedDemo(){try{const s=await api('/api/sites',json('POST',{name:'HESU Global Motors · 演示站',tagline:'全球汽车采购、出口与交付服务',theme:'automotive',domain:'https://demo.example.com',mode:'new'}));let base='/api/sites/'+s.id+'/entries';for(let v of [ {type:'page',title:'关于我们',route:'/about/',summary:'专注全球汽车出口与本地交付',body:'

这里是示例公司介绍。请在内容管理中替换为你的真实资料。

',seo_title:'About us'}, {type:'product',title:'ROX 01',route:'/product/rox-01/',summary:'豪华全地形 SUV · 示例数据,可在后台编辑',body:'

产品概览

此条目为演示内容,不代表实际库存或车型参数。

'}, {type:'product',title:'BYD ATTO 3',route:'/product/byd-atto-3/',summary:'纯电 SUV · 示例车型信息',body:'

可以从 WordPress、Excel 或 JSON 重新导入真正的车型数据。

'}, {type:'post',title:'网站动态示例',route:'/news/first-news/',summary:'一个独立的新网站如何快速发布',body:'

编辑内容、切换主题、点击构建,即可导出静态网站。

'} ])await api(base,json('POST',v));await App.openSite(s.id);await App.build();notice('演示网站已创建并成功构建,可直接预览或下载 ZIP')}catch(e){onError(e)}}, }; window.App=App; $('#siteForm').addEventListener('submit',App.createSite); $('#entryForm').addEventListener('submit',App.saveEntry); window.addEventListener('DOMContentLoaded',()=>App.init());