170 lines
6.1 KiB
TypeScript
170 lines
6.1 KiB
TypeScript
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://hjc-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://hjc-api.websoft.top', crossorigin: '' },
|
||
{ rel: 'dns-prefetch', href: 'https://server.websoft.top' },
|
||
{ rel: 'dns-prefetch', href: 'https://hjc-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
|
||
}
|
||
}
|
||
})
|