Files
hjc-web/server/api/product/detail.get.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

72 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { $fetch } from 'ofetch'
import { createError, defineEventHandler, getQuery } from 'h3'
import { useRuntimeConfig } from '#imports'
import { getTenantFromContext } from '../../utils/tenant'
/**
* 产品详情
* GET /api/product/detail?id=1
* 代理到 SaaS 后端 CMS 产品详情接口
*/
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig()
const ctx = getTenantFromContext(event, config)
const query = getQuery(event)
const modulesApiBase = config.public.modulesApiBase as string
if (!query.id) {
throw createError({ statusCode: 400, statusMessage: 'Missing id parameter' })
}
let res: any
try {
// 上游 cms-website 服务没有 productDetail 这类路由(会被 /cms/cms-website/{id} 兜底捕获并因 id 非整数报错),
// 正确的产品详情端点属于 cms-product 控制器,且 id 走路径参数:/cms/cms-product/{id}
res = await $fetch(`/cms/cms-product/${query.id}`, {
baseURL: modulesApiBase,
headers: {
TenantId: ctx.tenantId
},
// TenantId 同时放入 query 兜底(详情端点实测认 query 的 TenantId
query: { ...query, TenantId: ctx.tenantId }
})
} catch (error: any) {
throw createError({
statusCode: error?.statusCode || error?.response?.status || 502,
statusMessage: error?.statusMessage || 'Failed to fetch product detail'
})
}
// C 端不展示草稿(1)/下架(2)/已删除产品:status 非 0(已发布) 或 deleted=1 视为不存在
// 上游真实枚举:0=已发布 1=草稿 2=下架(与早期假设相反,已于 2026-07-29 校正)
// 上游对不存在/未发布产品常返回 {code:1, message:"...不存在"}(无 data),
// 此时 res.code !== 0,必须 404,否则扁平后的对象为 truthy,前端会误判为「存在」渲染空页。
const detail = res?.data ?? res
if (typeof res?.code === 'number' && res.code !== 0) {
throw createError({ statusCode: 404, statusMessage: 'Product not found or unpublished' })
}
if (!detail || detail.status === undefined || detail.status !== 0 || detail.deleted === 1) {
throw createError({ statusCode: 404, statusMessage: 'Product not found or unpublished' })
}
// 字段兼容归一化:上游 CMS 不同版本字段名不一致,统一补齐,
// 避免前端 10 套模板的 <RichText :content> / subtitle 取不到值而渲染空白。
// - content(富文本正文):部分版本放在 description,兜底回退(content 优先)
// - subtitle(副标题):上游多数版本返回 summary,兜底回退
// - navigationId:上游用 categoryId,组件用它拼「返回列表」链接
if (detail && typeof detail === 'object') {
if (detail.content == null || detail.content === '') {
detail.content = detail.description || ''
}
if (detail.subtitle == null || detail.subtitle === '') {
detail.subtitle = detail.summary || ''
}
if (detail.navigationId == null && detail.categoryId != null) {
detail.navigationId = detail.categoryId
}
}
// 返回扁平数据,去掉上游 {code, message, data} 包装层
return detail
})