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

65 lines
3.0 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/list?categoryId=1&page=1&limit=10
* 代理到 SaaS 后端 CMS 产品列表接口
* 注意:上游 cms-website 服务没有 productList 这类路由(会被 /cms/cms-website/{id} 兜底捕获并因 id 非整数报错),
* 正确的产品列表端点属于 cms-product 控制器:/cms/cms-product/page
*
* 返回结构:与 case/list 对齐,去掉上游包装层,归一化为 { list, count }
* 前端 ProductList 直接读 data.value?.list / data.value?.count,分页稳定可用。
*/
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig()
const ctx = getTenantFromContext(event, config)
const query = getQuery(event)
const modulesApiBase = config.public.modulesApiBase as string
try {
// 前端按导航模型约定传 navigationId;上游 cms-product 实际按 categoryId 过滤,
// 二者在 CMS 中同值(产品分类 ID == 对应栏目 navigationId),故透传 categoryId。
// 同时保留 navigationId 以兼容少数按 navigationId 过滤的租户。
const categoryId = query.navigationId ?? query.categoryId
// 聚合场景:前端递归收集父栏目下所有子栏目的 navigationId,以逗号串传入。
// 有 categoryIds 时优先走 IN 查询,忽略单值 categoryId,避免 AND 冲突。
const categoryIds = query.categoryIds as string | undefined
const res = await $fetch('/cms/cms-product/page', {
baseURL: modulesApiBase,
headers: {
TenantId: ctx.tenantId
},
// TenantId 同时放入 query 兜底(page 端点实测认 query 的 TenantId
// status 0=已发布 1=草稿 2=下架(与早期假设相反,已于 2026-07-29 校正),C 端只展示已发布,放最后覆盖前端传入
query: {
...query,
navigationId: categoryIds ? undefined : query.navigationId,
categoryId: categoryIds ? undefined : categoryId,
categoryIds: categoryIds || undefined,
TenantId: ctx.tenantId,
status: 0,
// 同时排除软删除(deleted=1)的产品,兜底防止已删除内容出现在前台
deleted: 0
}
})
// 与 case/list 对齐:去掉上游包装层,归一化为 { list, count }
// 上游 /cms/cms-product/page 返回 { code, message, data: { list, count } } 或 { list, count }
// 字段名可能为 count 或 total,统一兜底。
const envelopeData = (res && res.data !== undefined ? res.data : res) || {}
const rawList = Array.isArray(envelopeData.list) ? envelopeData.list : []
const count = envelopeData.count ?? envelopeData.total ?? rawList.length
return { list: rawList, count }
} catch (error: any) {
throw createError({
statusCode: error?.statusCode || error?.response?.status || 502,
statusMessage: error?.statusMessage || 'Failed to fetch product list'
})
}
})