feat(app): 添加多模板关于我们页面及相关路由和404页面
- 新增404页面,优化未找到页面体验,避免被搜索引擎索引 - 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理 - 实现/article、/case、/product及/page动态路由兼容列表与详情展示 - 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置 - 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持 - 模板增强支持CMS单页内容加载及SEO信息动态设置 - 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
This commit is contained in:
+169
@@ -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.cn;baseDomain 仅作兼容保留(取第一个)。
|
||||
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 会在请求进入中间件前直接 403(Blocked 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
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user