From 1f509d434920a34f6a703b21a9d1262f28c5faab Mon Sep 17 00:00:00 2001 From: inman Date: Fri, 24 Jul 2026 10:14:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=20H5=20=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/miniprogram/config/index.ts | 2 +- apps/miniprogram/src/pages/index/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/miniprogram/config/index.ts b/apps/miniprogram/config/index.ts index 5dc96aa..3a3a5ac 100644 --- a/apps/miniprogram/config/index.ts +++ b/apps/miniprogram/config/index.ts @@ -43,7 +43,7 @@ const baseConfig: UserConfigExport = { compiler: "webpack5", defineConstants: { "process.env.TARO_APP_API_BASE_URL": JSON.stringify(process.env.TARO_APP_API_BASE_URL || DEFAULT_API_BASE_URL), - "process.env.TARO_APP_H5_URL": JSON.stringify(process.env.TARO_APP_H5_URL ?? "http://127.0.0.1:5173"), + "process.env.TARO_APP_H5_URL": JSON.stringify(process.env.TARO_APP_H5_URL ?? "https://wanderq.nianxx.com"), }, alias: { // Taro 4.2.1 requires React 18. Keep the mini program's renderer on the diff --git a/apps/miniprogram/src/pages/index/index.tsx b/apps/miniprogram/src/pages/index/index.tsx index 6f68f55..9dbf0f0 100644 --- a/apps/miniprogram/src/pages/index/index.tsx +++ b/apps/miniprogram/src/pages/index/index.tsx @@ -1,6 +1,6 @@ import { WebView } from "@tarojs/components"; -const H5_URL = String(process.env.TARO_APP_H5_URL ?? "http://127.0.0.1:5173"); +const H5_URL = String(process.env.TARO_APP_H5_URL ?? "https://wanderq.nianxx.com"); const H5_CACHE_VERSION = "ui-20260723-tab-seam-v7"; const H5_SRC = `${H5_URL}${H5_URL.includes("?") ? "&" : "?"}v=${H5_CACHE_VERSION}`; From 160e82197e40a783761dc9d5ee848127a718460c Mon Sep 17 00:00:00 2001 From: inman Date: Fri, 24 Jul 2026 12:06:41 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20H5=20=E5=95=86?= =?UTF-8?q?=E5=93=81=E5=85=9C=E5=BA=95=E5=B9=B6=E8=A1=A5=E5=85=85=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E5=8F=91=E5=B8=83=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++++ src/App.tsx | 64 +++++------------------------------------------------ 2 files changed, 17 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 877305d..c193b2b 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,15 @@ Mobile H5, admin, and API workspace for the WonderQ MiniAPP project. - `npm run dev:admin` starts the admin app. - `npm run dev:api` starts the API service. - `npm run build:all` builds all workspaces. + +## 后端内容发布 + +商品数据的正式源文件是 `src/generated-products.json`。后端部署时请从仓库根目录执行内容发布流程,不要把商品数据重新打进 H5: + +```bash +npm run db:content:release -- validate +npm run db:content:release -- plan +npm run db:content:release -- apply +``` + +`apply` 会把商品、首页配置、活动和媒体引用写入生产数据库,并在 `artifacts/` 生成可回滚快照。需要回滚时,使用发布命令输出的 `rollback` 命令。 diff --git a/src/App.tsx b/src/App.tsx index 8a4e035..e524df9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -47,7 +47,6 @@ import { type PublicSearchPageConfig, type PublicSiteConfig, } from "./api"; -import fallbackProductsJson from "./generated-products.json"; import { bottomCtas as fallbackBottomCtas, dealCards, @@ -255,54 +254,6 @@ type SwipeState = { axis: "horizontal" | "vertical" | null; }; -type SourceProduct = { - id: number; - title: string; - price: string; - priceUnit?: string | null; - pricingTiers?: ProductPricingTier[] | null; - tags: string[]; - image: string; - images?: Array<{ url: string; alt?: string | null; sortOrder?: number }>; - summary?: string | null; - destinationName?: string | null; - durationDays?: number | null; - durationNights?: number | null; - departureDates?: string[]; - remainingSpots?: number | null; - recommendation?: string | null; - keyFacts?: ProductKeyFact[] | null; - contentBlocks?: ProductContentBlock[] | null; - detailSections?: ProductDetailSection[] | null; - status?: string; - sortWeight?: number; -}; - -function normalizeFallbackProduct(product: SourceProduct): Product { - return { - id: product.id, - title: product.title, - price: product.price, - priceUnit: product.priceUnit, - pricingTiers: product.pricingTiers, - tags: product.tags, - image: product.image, - summary: product.summary, - destinationName: product.destinationName, - durationDays: product.durationDays, - durationNights: product.durationNights, - departureDates: product.departureDates, - remainingSpots: product.remainingSpots, - recommendation: product.recommendation, - images: product.images?.map((image, index) => ({ ...image, sortOrder: image.sortOrder ?? index })), - keyFacts: product.keyFacts, - contentBlocks: product.contentBlocks, - detailSections: product.detailSections, - status: product.status, - sortWeight: product.sortWeight, - }; -} - function fallbackNumberFromApiId(apiId: string, index: number) { const digits = apiId.match(/\d+/)?.[0]; return digits ? Number(digits) : 10000 + index; @@ -470,7 +421,7 @@ const fallbackData: AppData = { destinations: fallbackDestinations, themeCards: fallbackThemeCards, bottomCtas: fallbackBottomCtas, - products: (fallbackProductsJson as SourceProduct[]).map(normalizeFallbackProduct), + products: [], searchPage: fallbackSearchPageConfig, }; @@ -481,12 +432,7 @@ function useAppData() { } function getProducts(products: Product[]) { - return products.length ? products : fallbackData.products; -} - -function getProductAt(products: Product[], index: number) { - const list = getProducts(products); - return list[index] ?? list[0]; + return products; } const keywordAliases: Record = { 贵州: ["贵州", "贵阳", "黄果树", "荔波", "西江", "梵净山", "万峰林"], @@ -2515,7 +2461,7 @@ function SearchResultsPage({ {contentLoadState !== "ready" ? (
) : null} @@ -3686,14 +3632,14 @@ export default function App() { if (cancelled) return; setAppData({ ...normalizeSiteConfig(siteConfig, fallbackData), - products: products.length ? products.map(normalizeApiProduct) : fallbackData.products, + products: products.map(normalizeApiProduct), }); setContentLoadState("ready"); }) .catch((error) => { if (cancelled) return; setContentLoadState("offline"); - console.info("Public API unavailable, using bundled H5 content.", error); + console.info("Public API unavailable; product content remains empty until the API is available.", error); }); return () => {