Files
hjc-web/app/composables/useApp.ts
T
gxwebsoft 2b69686795 feat(app): 添加多模板关于我们页面及相关路由和404页面
- 新增404页面,优化未找到页面体验,避免被搜索引擎索引
- 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理
- 实现/article、/case、/product及/page动态路由兼容列表与详情展示
- 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置
- 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持
- 模板增强支持CMS单页内容加载及SEO信息动态设置
- 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
2026-09-08 12:13:44 +08:00

79 lines
2.4 KiB
TypeScript

import type { AppProduct, TenantContext } from '~/types'
/**
* 获取当前应用产品信息(AppProduct)
*
* SSR:优先从 event.context.tenant.appProduct 读取(中间件已查询)
* 客户端:从 SSR 注入的 useState 读取;若为空则调用 /api/app/info 补查
*/
export function useApp() {
const appInfo = useState<AppProduct | null>('app-info', () => null)
const loading = useState<boolean>('app-loading', () => false)
const error = useState<string | null>('app-error', () => null)
// SSR 时直接从中间件识别结果注入,避免额外请求
if (import.meta.server && !appInfo.value) {
const event = useRequestEvent()
const ctx = event?.context?.tenant as TenantContext | undefined
if (ctx?.appProduct) {
appInfo.value = ctx.appProduct
}
}
/** 主动获取应用信息(客户端兜底 / 手动刷新) */
async function fetchAppInfo() {
if (appInfo.value) return appInfo.value
loading.value = true
error.value = null
try {
const res = await $fetch<AppProduct | null>('/api/app/info')
appInfo.value = res
return res
} catch (e: any) {
error.value = e?.message || '获取应用信息失败'
return null
} finally {
loading.value = false
}
}
/** 应用名称 */
const appName = computed(() => appInfo.value?.productName || '')
/** 应用编码 */
const appCode = computed(() => appInfo.value?.productCode || '')
/** 绑定域名 */
const appDomain = computed(() => appInfo.value?.domain || '')
/** 应用 Logo */
const appLogo = computed(() => appInfo.value?.logo || '')
/** 应用图标(站点小图标,用于 Header/Footer Logo 回退) */
const appIcon = computed(() => appInfo.value?.icon || '')
/**
* 关联模板目录名(template-XX):【code 优先,主键兜底】
* templateCode 与前端模板目录一一对应;templateId 主键存在跳号错位风险,仅兜底。
* 为空时返回 '' 由上层回退默认模板。
*/
const appTemplateId = computed(() =>
resolveTemplateKey(appInfo.value?.templateCode, appInfo.value?.templateId)
)
/** 是否已过期 */
const appExpired = computed(() => {
const t = appInfo.value?.expirationTime
if (!t) return false
return new Date(t).getTime() < Date.now()
})
return {
appInfo,
loading,
error,
fetchAppInfo,
appName,
appCode,
appDomain,
appLogo,
appIcon,
appTemplateId,
appExpired
}
}