OortCodex「来自深空的 AI 编码平台」官网前端。基于 SvelteKit 2 + @sveltejs/adapter-static 做全站预渲染,产出纯静态文件;支持部署到域名根目录或多级子目录(例如 /bus/apaas-web/oortcodexweb/);内置中英双语、统一认证(APAAS SSO)、订阅与支付链路。
- 页面:首页、定价、企业版、账户详情、企业订阅购买页,以及产品页(IDE / CLI / JetBrains 插件 / Agent SDK / Cloud Agents)、资源页(开发文档 / 博客 / 更新日志)、公司法务页(关于我们 / 合作伙伴 / 联系我们 / 服务条款 / 隐私政策)
- 语言:简体中文、English(客户端切换,无 URL 语言前缀)
- 产物:
dist/,目录式xxx/index.html,并预压缩.br/.gz - 部署形态:由
moveTodepoly.sh把dist搬进部署仓库的html/oortcodexweb后提交
| 项 | 版本 / 说明 |
|---|---|
| SvelteKit | ^2.5.27(路由、预渲染、svelte:head SEO) |
| Svelte | ^4.2.19(语法为 Svelte 4:on:click、class:x、$:) |
| Vite | ^5.4.8 |
| 适配器 | @sveltejs/adapter-static ^3.0.6 |
| 检查 | svelte-check ^3.6.4 |
| 运行时依赖 | qrcode-generator ^1.4.4(支付二维码) |
| 建议环境 | Node.js 18+(Vite 5 的最低要求) |
样式是手写 CSS(无 Tailwind / 预处理器),全部集中在 src/app.css。
npm install # 安装依赖
npm run dev # 本地开发(Vite dev server)
npm run build # 预渲染产出静态站点到 dist/
npm run preview # 以静态方式预览 dist/
npm run check # svelte-check 类型/语法检查发布(本地脚本链路,无 CI):
npm run release:oortcodex-web
# 等价于:npm run build → sh moveTodepoly.sh oortcodexweb → sh genger_log.shmoveTodepoly.sh 会把 dist 移动到部署仓库的 html/oortcodexweb 并提交;genger_log.sh 生成并推送更新日志。两者的部署仓库路径、分支名写死在脚本里(moveTodepoly.sh 的 DEPOLYROOT、lvgemgroup 分支),换机器/换环境需先改脚本。
src/
app.html # HTML 模板(favicon、%sveltekit.head%/body%)
app.css # 全站唯一样式表(设计系统 + 各页面区块)
hooks.server.js # 构建期注入 <meta name="build-time">
lib/
api/ # 后端接口封装(client / apaas / account / enterpriseSubscription / membershipCard)
components/ # 公共组件(见下)
config/ # site.js(站点域名)、auth-config.js(SSO 多区域配置)
data/ # blog.js(博客 slug 中立数据)
i18n/ # index.js + zh.js/en.js + zh|en 各 9 个命名空间字典
stores/ # auth / subscription / membershipCard / enterpriseSubscription / toast
utils/ # siteRoutes(站内链接)、format、clipboard、modalLayer
actions/ # reveal(滚动显现)
routes/ # 19 个路由(见第 4 节)
static/ # 原样拷贝到产物根:favicon.png、robots.txt、sitemap.xml、brand/logo-*.png
src/lib/components/ 分组:
- 常驻骨架:
Starfield、Announce、Header、Footer、BackTop、Toast - 页面级公共件:
Seo、Faq、EnterprisePlans、MembershipCards、LangSwitcher - 弹窗/浮层:
PayModal、MembershipRedeemModal、TenantSwitchModal、IndustrySceneModal、AppGridPopover、MoreActionPopover - 内容页排版件
page/:DocLayout(文档型页面 + 左侧目录)、CodeTabs(多命令切换 + 复制)、PageCta(页尾 CTA) - 账户页
account/:AccountSide、AccountProfile、AccountUsageCards、AccountLogs、AccountBills、AccountCards、AccountEnterprise、AccountAvatar、AccountPager、EnterpriseInvoiceSection等
根布局 src/routes/+layout.js 设置 prerender = true、trailingSlash = 'always',因此每个页面都产出为「目录 + index.html」。
| 路由 | 说明 |
|---|---|
/ |
首页:hero、产品双 Tab、能力 bento、接入方式、关键概念、社区、FAQ、CTA |
/pricing/ |
定价:个人订阅 / 企业订阅 / 会员卡三段(页内锚点 #personal-subscription 等) |
/account/ |
账户详情:五个面板用 hash 切换(#usage、#bills、#cards、#enterprise) |
/enterprise/ |
企业版落地页 |
/enterprise-subscription/purchase/ |
企业套餐购买页,通过 ?plan_id= 定位套餐,金额客户端试算、服务端校验 |
/ide/ /cli/ /jetbrains/ /agent-sdk/ /cloud-agents/ |
产品页 |
/docs/ /blog/ /changelog/ |
资源页;/blog/[slug]/ 为动态路由,entries() 由 src/lib/data/blog.js 的 blogSlugs 生成 |
/about/ /partners/ /contact/ /terms/ /privacy/ |
公司 / 法务页(terms、privacy 用 DocLayout 渲染模板条款) |
- 入口
src/lib/i18n/index.js:localestore、t(响应式)、tr(非响应式)、setLocale,语言存localStorage的oc_locale,并同步<html lang>;没有 URL 语言前缀。 - 字典按命名空间拆分,
zh.js/en.js聚合,两语言 key 结构必须逐层一致(缺失时控制台会打印[i18n] missing key: ...并回退中文)。
| 命名空间 | 覆盖 |
|---|---|
meta common announce nav footer auth toast |
site.js,平铺在根级 |
home pricing account pay card |
首页 / 定价 / 账户 / 支付 / 会员卡 |
ide cli jetbrains agentSdk cloudAgents |
products.js |
docs blog changelog |
resources.js |
about partners contact terms privacy |
company.js |
站点可能部署在 /bus/apaas-web/oortcodexweb/ 这类多级子目录下,禁止直接写 /pricing 之类的根绝对路径,统一使用 src/lib/utils/siteRoutes.js:
import { page } from '$app/stores';
import { siteHref, siteSubPath } from '$lib/utils/siteRoutes.js';
$: routeId = $page.route.id || '/';
<a href={siteHref(routeId, 'cli')} rel="external">CLI</a> <!-- 目录型路由 -->
<a href={siteSubPath(routeId, 'blog', slug + '/')}>…</a> <!-- 路由目录下的子路径 -->ROUTE_FILES是「路由名 → 静态产物路径」的映射表,siteHref会对未登记的 target 直接抛错,所以新增页面必须在此表登记。- 需要跳转(而非
<a>)时用navigateSite(routeId, target)。
src/lib/stores/auth.js:APAAS SSO 登录、回跳取 token、跨标签同步、verifyToken/getUserInfo、区域(cn / global)隔离。src/lib/api/client.js:统一封装apiFetch,基址优先级window.SUBSCRIPTION_API_BASE→auth-config.platformOrigin + /bus/apaas-newapi→ 同源/bus/apaas-newapi;401 会抛出status=401供上层跳登录。- 配置来自代码常量 + 运行时覆盖(项目不使用环境变量):
src/lib/config/auth-config.js里的FRONTEND_ONLY_HOSTS、各区域 appId / secretKey / platformOrigin,可用window.OORT_AUTH_REGIONS免重建覆盖。 - 接口与路由对照详见
frontend-backend-route-map.md,套餐/支付宝/微信购买接口见subscription-purchase-api.md。
src/lib/stores/subscription.js 编排下单、轮询、恢复中断流程与统一支付弹窗(PayModal.svelte,挂载在根布局);会员卡走 membershipCard.js + MembershipRedeemModal,企业套餐/席位/资源包走 enterpriseSubscription.js + EnterprisePlans。
src/app.css 是唯一样式源,按区块用注释分隔:设计系统变量(--ink / --ice / --border / --font-*)→ 按钮 → 公告条 / 头部 → 首页各 section → 页脚 → 定价页 → 会员卡 → 企业订阅 → 各弹窗 → 账户页 → 内容页骨架 .pp-*。
- 内容页(产品页 / 资源页 / 公司页)统一使用
.pp-*类名:pp-eyebrow、pp-hero、pp-actions、pp-section(--soft)、pp-head、pp-grid(--2/--3/--4)、pp-card、pp-list、pp-tags、pp-steps、pp-split、pp-panel、pp-terminal、pp-compare、pp-note、pp-doc*,配合组件page/DocLayout|CodeTabs|PageCta。 - 页面组件内不写
<style>块(企业页是唯一例外,保留了少量 scoped 覆盖),保持样式集中。 - 设计语言:近黑底、发丝边框、亮绿强调(
--ice: #2adb5c)、等宽小标(--font-mono);动效统一用--ease并在prefers-reduced-motion下关闭。
- 建
src/routes/<path>/+page.svelte,页面顶部放<Seo titleKey="meta.xxxTitle" descKey="meta.xxxDesc" path="/xxx/" />。 - 在
src/lib/i18n/zh/site.js与en/site.js补meta.xxxTitle/meta.xxxDesc,以及nav.*/footer.*入口文案。 - 文案写进对应命名空间字典(
zh/*.js+en/*.js),两语言 key 结构必须一致;新命名空间要在src/lib/i18n/zh.js、en.js里聚合。 - 在
src/lib/utils/siteRoutes.js的ROUTE_FILES登记xxx: 'xxx/index.html',否则siteHref抛错。 - 页面间链接一律用
siteHref/siteSubPath;页尾用PageCta,长文用DocLayout,命令块用CodeTabs。 - 需要被搜索引擎收录时,同步在
static/sitemap.xml增加条目。 npm run build后确认控制台没有[i18n] missing key告警,并逐页走查中英文两种语言。
- 产物目录
dist/(svelte.config.js的pages/assets都是dist),static/原样拷到产物根。 - 预压缩开启(
precompress: true),同时产出.br/.gz;未知路径回退到404.html。 - 由于产物是「目录 + index.html」,本地预览请用
npm run preview(直接打开dist/index.html会因根绝对路径而失效)。 - 构建期
hooks.server.js会给每个页面注入<meta name="build-time">,可用于确认线上版本。
| 位置 | 需要改什么 |
|---|---|
src/lib/config/auth-config.js |
前端独立域名映射、各区域 appId / secretKey / platformOrigin(国际版默认 http://platform.szkingdom.cloud:6080) |
window.SUBSCRIPTION_API_BASE / window.OORT_AUTH_REGIONS |
需要跨域或临时改网关时的运行时覆盖(免重建) |
| 下载地址常量 | .../releases/download/v1.0.12/...exe 出现在首页、定价、Header、Footer、ide、cli、docs、changelog、blog 等 10 处,换版本号需全局替换 |
src/lib/components/account/EnterpriseInvoiceSection.svelte |
发票中心地址 |
static/robots.txt、static/sitemap.xml |
站点域名占位 https://oortcodex.com(页面 canonical 由 src/lib/config/site.js 按访问域动态生成,无需改) |
moveTodepoly.sh / genger_log.sh |
部署仓库路径与分支名 |
- 有
npm run check(svelte-check,jsconfig.json中checkJs: false)。 - 没有单元测试 / 端到端测试,也没有 CI 配置;发布靠本地脚本链路。
- 无自动化的死链检查,建议在发布前手动执行:
npm run build后逐页走查并结合dist/产物确认站内跳转与锚点(当前全站 1800+ 条站内相对链接与锚点均为可达状态)。
历史遗留(不属于当前站点,勿误用/勿误删):
- 根目录
index.html/pricing.html/account.html与assets/(css/styles.css、js/*.js):SvelteKit 改造前的旧静态站,src/内零引用。 - 根目录
build/:一次过期的旧构建产物(缺_app/,且是扁平的pricing.html命名),当前产物是dist/(未入库,被.gitignore忽略)。 - 根目录若干
*.png截图与vite.config.js.timestamp-*.mjs:改版对比图与 Vite 临时残留。
待完善:
/terms、/privacy是通用模板文案,正式对外发布前需法务确认。static/sitemap.xml、static/robots.txt的域名仍是占位。svelte.config.js注释提到src/routes/404/+page.svelte,该路由实际不存在,404 由 adapter 的fallback: '404.html'兜底。src/lib/components/account/EnterpriseUsagePanel.svelte、EnterpriseQuotaPolicies.svelte已实现但未被任何页面引用;static/favicon-mark.png、static/brand/logo-dark.png同样暂未使用。/enterprise页正文仍是中文硬编码(已接入Seo,但未走 i18n),需要英文版时需补齐。