feat(app): 添加多模板关于我们页面及相关路由和404页面

- 新增404页面,优化未找到页面体验,避免被搜索引擎索引
- 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理
- 实现/article、/case、/product及/page动态路由兼容列表与详情展示
- 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置
- 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持
- 模板增强支持CMS单页内容加载及SEO信息动态设置
- 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
This commit is contained in:
2026-09-08 12:13:44 +08:00
commit 2b69686795
381 changed files with 59891 additions and 0 deletions
+169
View File
@@ -0,0 +1,169 @@
function getOrigin(url: string) {
try {
return new URL(url).origin
} catch {
return ''
}
}
/**
* 解析布尔型环境变量:'true'→true'false'→false,其余→null(交由后台配置决定)。
*/
function toBool(v?: string): boolean | null {
if (v === 'true') return true
if (v === 'false') return false
return null
}
const tenantId = process.env.NUXT_PUBLIC_TENANT_ID || ''
const appId = process.env.NUXT_PUBLIC_APP_ID || 'website'
const templateId = process.env.NUXT_PUBLIC_TEMPLATE_ID || 'template-01'
// 强制模板 ID:一旦设置则拥有最高优先级,覆盖应用/站点绑定(主要用于本地调试)
const forceTemplateId = process.env.NUXT_PUBLIC_FORCE_TEMPLATE_ID || ''
// 站点名称覆盖:设置后优先于后端 AppProduct / CMS 返回值(多用于本地调试或强制品牌名)
const siteName = process.env.NUXT_PUBLIC_SITE_NAME || ''
const serverApiBase =
process.env.NUXT_PUBLIC_SERVER_API_BASE ||
'https://server.websoft.top/api'
const modulesApiBase =
process.env.NUXT_PUBLIC_MODULES_API_BASE ||
'https://cms-api.websoft.top/api'
const appApiBase =
process.env.NUXT_PUBLIC_APP_API_BASE ||
'https://websopy-api.websoft.top'
const fileServerBase =
process.env.NUXT_PUBLIC_FILE_SERVER_BASE ||
getOrigin(serverApiBase) ||
'https://server.websoft.top'
const baseDomain =
process.env.NUXT_PUBLIC_BASE_DOMAIN || 'shoplnk.cn'
// 多主域清单:子域名租户解析支持的主域(逗号分隔)。
// 默认 shoplnk.cn,sitelink.cn,wsdns.cnbaseDomain 仅作兼容保留(取第一个)。
const baseDomains = (
process.env.NUXT_PUBLIC_BASE_DOMAINS ||
'shoplnk.cn,sitelink.cn,wsdns.cn'
).split(',').map(s => s.trim()).filter(Boolean)
// 子域名前缀白名单:仅这些前缀 + 数字租户号 + 主域 会被识别为平台子域名租户
const subdomainPrefixes = (
process.env.NUXT_PUBLIC_SUBDOMAIN_PREFIXES ||
'site,shop,store,mp,app,oa'
).split(',').map(s => s.trim()).filter(Boolean)
// 联系电话覆盖:当后端 phone 被脱敏时,作为兜底显示
const phone = process.env.NUXT_PUBLIC_PHONE || ''
const WATCH_IGNORED = [
'**/.git/**',
'**/node_modules/**',
'**/.nuxt/**',
'**/.output/**',
'**/dist/**',
'**/coverage/**',
'**/.cache/**',
'**/.workbuddy/**'
]
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
modules: ['@nuxtjs/tailwindcss', '@ant-design-vue/nuxt'],
app: {
head: {
htmlAttrs: { lang: 'zh-CN' },
titleTemplate: '%s',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ name: 'robots', content: 'index,follow' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
// 提前与内容/接口源站建立连接,降低首字节与图片加载延迟
{ rel: 'preconnect', href: 'https://server.websoft.top', crossorigin: '' },
{ rel: 'preconnect', href: 'https://cms-api.websoft.top', crossorigin: '' },
{ rel: 'dns-prefetch', href: 'https://server.websoft.top' },
{ rel: 'dns-prefetch', href: 'https://cms-api.websoft.top' },
// 思源黑体(Noto Sans SC,SIL 开源许可,版权无忧)网页字体,全站统一字体
{ rel: 'preconnect', href: 'https://fonts.googleapis.cn' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.cn', crossorigin: '' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.cn/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap' }
],
// 首屏绘制前注入 .js 类,配合 animations.css 的 `.js [data-reveal]`
// 规则实现「无 JS 时内容可见、有 JS 时先隐藏再由滚动揭示」,杜绝 SSR 闪烁
script: [
{
innerHTML:
"document.documentElement.classList.add('js')",
tagPosition: 'head'
}
]
}
},
tailwindcss: {
cssPath: '~/assets/css/tailwind.css',
configPath: 'tailwind.config.cjs'
},
experimental: { appManifest: false },
// 全局 SSR,保证 SEO
routeRules: {
'/renewal': { ssr: true }
},
runtimeConfig: {
// 仅服务端可见
subscriptionCacheTtl: Number(process.env.NUXT_SUBSCRIPTION_CACHE_TTL || 60),
public: {
tenantId,
appId,
templateId,
forceTemplateId,
siteName,
serverApiBase,
modulesApiBase,
appApiBase,
fileServerBase,
baseDomain,
baseDomains,
subdomainPrefixes,
phone,
// 微信二维码覆盖:设置后优先于 CMS 返回的 wxQrcode(用于本地调试或强制指定二维码)
// ⚠️ 不要写硬编码默认图!必须保持空字符串,让 Footer 从 siteInfo.config.wxQrcode / siteInfo.qrCode 读取后台上传
wxQrcode: process.env.NUXT_PUBLIC_WX_QRCODE || '',
// 在线留言滑块验证码开关覆盖(可选):
// 默认 null → 由后台「网站设置」setting.requireCaptcha 决定;
// 设 true/false 可在不改后台的情况下强制开/关(仅部署级覆盖,后台显式配置优先)。
contactCaptcha: toBool(process.env.NUXT_PUBLIC_CONTACT_CAPTCHA)
}
},
css: ['~/assets/css/tailwind.css', '~/assets/css/animations.css'],
vite: {
server: {
// 本地开发允许用自定义域名(如 cz-hro.shoplnk.cn)访问,
// 否则 Vite 会在请求进入中间件前直接 403Blocked request. This host is not allowed
// 以 "." 开头的条目表示允许该域名及其所有子域。
// 注意:这里只是放宽 Vite 的 host 校验,真正「是否解析为合法租户」仍由
// tenant 中间件按白名单前缀 + 主域清单判断;非白名单子域不会命中租户。
allowedHosts: ['.shoplnk.cn', '.sitelink.cn', '.wsdns.cn', 'localhost', '127.0.0.1'],
watch: {
ignored: WATCH_IGNORED
}
},
optimizeDeps: {
include: ['dayjs']
}
},
nitro: {
watchOptions: {
ignored: WATCH_IGNORED
}
},
watchers: {
chokidar: {
ignored: WATCH_IGNORED
}
}
})