diff --git a/web/.env.example b/web/.env.example index eac2d5e..0159f0c 100644 --- a/web/.env.example +++ b/web/.env.example @@ -5,3 +5,4 @@ VITE_APP_DOMAIN=https://yuheng.yuxindazhineng.com VITE_API_BASE= # 可选:与 Mongo 站点 _id 一致;静态 /promotion 缺文件时用于 promotion-media 回退(见 promotionVideos.js) # VITE_DEFAULT_SITE_ID=69ba1f1f41aeb82acfd609ef +# 仅走 API、跳过静态探测(无 Network 404 噪音):VITE_PROMOTION_API_ONLY=true diff --git a/web/.env.production b/web/.env.production index 0e3791b..4ff37b2 100644 --- a/web/.env.production +++ b/web/.env.production @@ -6,3 +6,4 @@ VITE_APP_DOMAIN=https://yuheng.yuxindazhineng.com VITE_API_BASE= # 可选:填官网 Mongo site_id,静态 /promotion 无视频时强制走 promotion-media 回退 # VITE_DEFAULT_SITE_ID= +# 素材只在上传目录、不想探测静态时:VITE_PROMOTION_API_ONLY=true diff --git a/web/promotion/social/README.md b/web/promotion/social/README.md index 847f0f9..bd74c6c 100644 --- a/web/promotion/social/README.md +++ b/web/promotion/social/README.md @@ -24,6 +24,8 @@ 线上访问示例:`https://你的域名/promotion/social/douyin.png` (须将 `web/promotion` 同步到 **`deploy/web/dist/promotion`**,见 `pull-and-restart.sh`。) +首页产品视频:只对**第一条**的封面与视频各探测一次静态;若任一不存在则**全部**走 `promotion-media` API(避免 Network 里 10+ 条 404)。若素材**只在上传目录**,可在 `web/.env.production` 设 **`VITE_PROMOTION_API_ONLY=true`** 并配合 **`VITE_DEFAULT_SITE_ID`**,不再发静态探测请求。 + ## 从旧「视频发布」目录迁移 **仅同步到源码 `social/`(给静态站用):** diff --git a/web/src/data/promotionVideos.js b/web/src/data/promotionVideos.js index 9a1e51e..c1538c6 100644 --- a/web/src/data/promotionVideos.js +++ b/web/src/data/promotionVideos.js @@ -87,16 +87,23 @@ export async function promotionStaticUrlExists(url) { } } +const apiOnly = + import.meta.env.VITE_PROMOTION_API_ONLY === '1' || + import.meta.env.VITE_PROMOTION_API_ONLY === 'true' + /** - * 有静态则静态,否则(需 siteId)走 promotion-media API + * 有静态则静态,否则(需 siteId)走 promotion-media API(单资源;列表请用 buildPromotionVideosAsync 批量逻辑) * @param {string} siteId * @param {string} relPath promotion 下相对路径,如 social/xxx.mov */ export async function pickPromotionAssetUrl(siteId, relPath) { + const sid = String(siteId || defaultWebSiteId || '').trim() + if (apiOnly && sid) { + return promotionMediaApiUrl(sid, relPath) + } const staticUrl = promotionUrl(relPath) const hasStatic = await promotionStaticUrlExists(staticUrl) if (hasStatic) return staticUrl - const sid = String(siteId || defaultWebSiteId || '').trim() if (sid) return promotionMediaApiUrl(sid, relPath) return staticUrl } @@ -116,20 +123,52 @@ export function buildPromotionVideos(_siteId) { } /** - * 静态优先:存在 /promotion/... 则用静态,否则用 uploads API(需 siteId) + * 静态优先:只对「示例封面 + 示例视频」各探测一次,避免 Network 里出现 10+ 条 404。 + * 二者在静态均存在则全套走 /promotion/;否则有 siteId 时全套走 promotion-media API。 * @param {string} siteId */ export async function buildPromotionVideosAsync(siteId) { - const id = siteId || '' - return Promise.all( - PROMOTION_VIDEOS_BASE.map(async (v) => { - const [cover, src] = await Promise.all([ - pickPromotionAssetUrl(id, v.relCover), - pickPromotionAssetUrl(id, v.relVideo) - ]) - return { id: v.id, title: v.title, desc: v.desc, cover, src } - }) - ) + const id = String(siteId || defaultWebSiteId || '').trim() + const first = PROMOTION_VIDEOS_BASE[0] + + let useStatic = false + if (apiOnly && id) { + useStatic = false + } else if (!apiOnly) { + const [coverOk, videoOk] = await Promise.all([ + promotionStaticUrlExists(promotionUrl(first.relCover)), + promotionStaticUrlExists(promotionUrl(first.relVideo)) + ]) + useStatic = coverOk && videoOk + } + + return PROMOTION_VIDEOS_BASE.map((v) => { + if (useStatic) { + return { + id: v.id, + title: v.title, + desc: v.desc, + cover: promotionUrl(v.relCover), + src: promotionUrl(v.relVideo) + } + } + if (id) { + return { + id: v.id, + title: v.title, + desc: v.desc, + cover: promotionMediaApiUrl(id, v.relCover), + src: promotionMediaApiUrl(id, v.relVideo) + } + } + return { + id: v.id, + title: v.title, + desc: v.desc, + cover: promotionUrl(v.relCover), + src: promotionUrl(v.relVideo) + } + }) } /** @deprecated 请用 buildPromotionVideos() 或 buildPromotionVideosAsync */