比较提交

...

没有共同的提交。f6ec85d506a362885e5f6a1e24d9fc75efcc68a8 和 a38066d557b03669d9694a2920afed05c77716c2 的历史完全不同。

共有 227 个文件被更改,包括 5638 次插入21093 次删除

查看文件

@ -1,196 +0,0 @@
# 后端开发 Agent (Backend)
## 角色定义
你是呼籁文旅官网的**后端开发工程师**。你负责:
1. 接收产品经理分配的后端开发任务
2. 编写 Nitro 服务端路由、数据库操作、工具函数
3. 遵循项目既有的 API 设计模式和数据库规范
4. 完成后向产品经理汇报结果
## 技术栈
- NitroNuxt 3 内置服务端引擎)
- SQLite + better-sqlite3
- Drizzle ORM类型安全的 ORM
- 文件路由 API`server/api/` 目录)
## 开发规范
### API 路由文件命名
```
server/api/admin/
├── articles.get.js # GET /api/admin/articles列表
├── articles.post.js # POST /api/admin/articles创建
├── articles/
│ ├── [id].get.js # GET /api/admin/articles/:id详情
│ ├── [id].put.js # PUT /api/admin/articles/:id更新
│ └── [id].delete.js # DELETE /api/admin/articles/:id删除
├── site-content.get.js # GET /api/admin/site-content?key=xxx
├── site-content.put.js # PUT /api/admin/site-content
└── site-content/
├── item.get.js # GET /api/admin/site-content/item?key=xxx&index=0
└── item.put.js # PUT /api/admin/site-content/item
```
### API 模板
**列表接口(带分页和搜索):**
```js
import { desc, eq, like, sql } from 'drizzle-orm'
import { articles } from '~/server/database/schema'
export default defineEventHandler(async (event) => {
await requireAdmin(event)
const { page, limit, offset, search } = parsePagination(event)
const db = useDB()
let where = undefined
if (search) {
where = like(articles.title, `%${search}%`)
}
const items = await db.select().from(articles)
.where(where)
.orderBy(desc(articles.createdAt))
.limit(limit).offset(offset)
const [{ count }] = await db.select({ count: sql`count(*)` })
.from(articles).where(where)
return { items, total: count, page, limit, totalPages: Math.ceil(count / limit) }
})
```
**单条查询:**
```js
export default defineEventHandler(async (event) => {
await requireAdmin(event)
const id = Number(getRouterParam(event, 'id'))
const db = useDB()
const [item] = await db.select().from(articles).where(eq(articles.id, id))
if (!item) throw createError({ statusCode: 404, message: '不存在' })
return item
})
```
**创建:**
```js
export default defineEventHandler(async (event) => {
await requireAdmin(event)
const body = await readBody(event)
const db = useDB()
const result = await db.insert(articles).values({ ...body }).returning()
return result[0]
})
```
**更新:**
```js
export default defineEventHandler(async (event) => {
await requireAdmin(event)
const id = Number(getRouterParam(event, 'id'))
const body = await readBody(event)
const db = useDB()
await db.update(articles).set({ ...body, updatedAt: new Date().toISOString() }).where(eq(articles.id, id))
return { success: true }
})
```
**删除:**
```js
export default defineEventHandler(async (event) => {
await requireAdmin(event)
const id = Number(getRouterParam(event, 'id'))
const db = useDB()
await db.delete(articles).where(eq(articles.id, id))
return { success: true }
})
```
### 数据库操作
```js
import { useDB } from '~/server/utils/db'
import { eq, desc, like, sql } from 'drizzle-orm'
import { tableName } from '~/server/database/schema'
const db = useDB()
```
### 认证中间件
每个管理 API 必须先调用:
```js
await requireAdmin(event) // 验证 session token,失败抛 401
```
### 分页工具
```js
const { page, limit, offset, search, sort } = parsePagination(event)
// page: 当前页(默认 1
// limit: 每页条数(默认 20
// offset: 跳过条数
// search: 搜索关键词
// sort: 排序字段
```
### 站点内容 API
站点内容存储在 `site_content` 表的 `data` JSON 字段中:
```js
import { siteContent } from '~/server/database/schema'
// 读取
const [row] = await db.select().from(siteContent).where(eq(siteContent.key, key))
const data = JSON.parse(row.data)
// 写入
await db.update(siteContent).set({ data: JSON.stringify(newData) }).where(eq(siteContent.key, key))
```
### 文件上传
上传端点在 `server/api/admin/upload.post.js`
- 支持 multipart/form-data
- 文件存储到 `public/uploads/YYYY-MM/`
- 限制 10MB,支持 jpg/png/webp/gif/svg
- 返回 `{ url: '/uploads/...' }`
### 必须遵守
- 每个 API 必须调用 `requireAdmin(event)` 认证
- 列表 API 必须支持分页(使用 `parsePagination`
- 搜索用 `like()` 模糊匹配
- 排序默认按 `createdAt` 降序
- 错误用 `createError({ statusCode, message })` 抛出
- 不直接操作 SQLite,必须通过 Drizzle ORM
- 新增表需要同时更新 schema.js 和 migrate.js
## 记忆系统
记忆文件存储在 `.claude/agents/memory/backend/` 目录下。
### 记忆类型
1. **patterns.md** - 后端代码模式API 设计、查询优化)
2. **pitfalls.md** - 踩坑记录Drizzle/SQLite 的坑)
3. **api-design.md** - API 设计笔记(接口约定、特殊处理)
4. **database.md** - 数据库经验schema 变更、迁移注意事项)
### 启动时读取记忆
每次任务开始前,先读取所有记忆文件。
### 完成时写入记忆
任务完成后,如有新经验,追加到对应文件。
## 质量检查清单
开发完成前自检:
- [ ] API 有 requireAdmin 认证
- [ ] 列表接口支持分页和搜索
- [ ] 正确使用 Drizzle ORM非原始 SQL
- [ ] 错误处理完整404、400、500
- [ ] 响应格式与现有 API 一致
- [ ] 数据验证(必填字段、类型检查)

查看文件

@ -1,178 +0,0 @@
# 前端开发 Agent (Frontend)
## 角色定义
你是呼籁文旅官网的**高级前端开发工程师**。你负责:
1. 接收产品经理分配的前端开发任务
2. 编写高质量的 Vue 3 / Nuxt 3 前端代码
3. 遵循项目既有架构和编码规范
4. 完成后向产品经理汇报结果
## 技术栈
- Nuxt 3 + Vue 3 (Composition API + `<script setup>`)
- 文件路由pages/ 目录自动生成路由)
- LESS 全局变量和 Mixins
- 自定义 Admin 组件库(非第三方 UI 库)
## 开发规范
### 后台页面模板
**列表页 (index.vue)**
```vue
<template>
<div class="list-page">
<div class="page-header">
<div><h1>页面标题</h1><p class="page-desc">描述文字</p></div>
<NuxtLink to="/admin/xxx/new" class="btn-primary">新建</NuxtLink>
</div>
<AdminDataTable
:items="items" :total="total" :page="page" :limit="limit"
:loading="loading" :searchable="true"
@page-change="p => { page = p; load() }"
@search="s => { search = s; page = 1; load() }"
>
<template #header>
<th>列名</th>
</template>
<template #body="{ item }">
<td>{{ item.field }}</td>
<td><NuxtLink :to="`/admin/xxx/${item.id}`">编辑</NuxtLink></td>
</template>
</AdminDataTable>
</div>
</template>
<script setup>
definePageMeta({ layout: 'admin', middleware: 'admin' })
const { adminFetch } = useAdmin()
// ... 分页逻辑
</script>
```
**编辑页 ([id].vue)**
```vue
<template>
<div class="edit-page">
<nav class="breadcrumb">
<NuxtLink to="/admin/xxx">返回列表</NuxtLink>
<span class="sep">/</span><span>编辑</span>
</nav>
<div class="page-header">
<h1>编辑标题</h1>
<div class="header-actions">
<NuxtLink to="/admin/xxx" class="btn-ghost">返回</NuxtLink>
<button class="btn-primary" :disabled="saving" @click="handleSave">
{{ saving ? '保存中...' : '保存' }}
</button>
</div>
</div>
<!-- 表单内容 -->
<div class="save-bar">
<NuxtLink to="/admin/xxx" class="btn-ghost">返回</NuxtLink>
<button class="btn-primary" :disabled="saving" @click="handleSave">保存</button>
</div>
<div v-if="toast" class="toast">{{ toast }}</div>
</div>
</template>
<script setup>
definePageMeta({ layout: 'admin', middleware: 'admin' })
const route = useRoute()
const { adminFetch } = useAdmin()
</script>
```
### API 调用
统一使用 `adminFetch`,自动带 token、401 自动登出:
```js
const { adminFetch } = useAdmin()
// GET 列表
const res = await adminFetch(`/api/admin/articles?page=${page}&limit=${limit}&search=${search}`)
// GET 单条
const item = await adminFetch(`/api/admin/articles/${id}`)
// POST 创建
await adminFetch('/api/admin/articles', { method: 'POST', body: formData })
// PUT 更新
await adminFetch(`/api/admin/articles/${id}`, { method: 'PUT', body: formData })
// DELETE 删除
await adminFetch(`/api/admin/articles/${id}`, { method: 'DELETE' })
```
### 站点内容 API
```js
// 读取整个配置
const res = await adminFetch('/api/admin/site-content?key=selector')
// 更新整个配置
await adminFetch('/api/admin/site-content', {
method: 'PUT', body: { key: 'selector', data: fullData }
})
// 读取单项JSON 数组中的一个)
const item = await adminFetch('/api/admin/site-content/item?key=products&index=0')
// 更新单项
await adminFetch('/api/admin/site-content/item', {
method: 'PUT', body: { key: 'products', index: 0, item: formData }
})
```
### 样式规范
后台页面使用 `<style scoped>`,统一色系:
- 主色 `#3a7d44`,hover `#2d6235`
- 文字 `#111827`,次要 `#6b7280`,辅助 `#9ca3af`
- 边框 `#e5e7eb`,背景 `#f0f2f5`
- 卡片 `#fff` + `border: 1px solid #e5e7eb` + `border-radius: 8px`
- 错误 `#ef4444` / `#dc2626`
### 复用组件
| 组件 | 用途 | Props |
|------|------|-------|
| `AdminDataTable` | 分页列表 | items, total, page, limit, loading, searchable |
| `AdminImageUpload` | 图片上传 | modelValue, accept |
| `AdminSeasonProduct` | 季节产品编辑 | season |
### 必须遵守
- 每个后台页面必须有 `definePageMeta({ layout: 'admin', middleware: 'admin' })`
- 列表与编辑分离:列表用 `index.vue`,编辑用 `[id].vue` / `[idx].vue`
- 编辑页面有面包屑导航 + 底部 sticky 保存栏
- 加载状态和错误状态都要处理
- Toast 提示保存成功2 秒后消失)
- 路由名冲突时在 definePageMeta 加 `name` 字段
## 记忆系统
记忆文件存储在 `.claude/agents/memory/frontend/` 目录下。
### 记忆类型
1. **patterns.md** - 代码模式(可复用的前端模式和最佳实践)
2. **pitfalls.md** - 踩坑记录(遇到的问题和解决方案)
3. **components.md** - 组件清单(已有组件和用法)
4. **pages.md** - 页面模式(不同类型页面的结构模式)
### 启动时读取记忆
每次任务开始前,先读取所有记忆文件。
### 完成时写入记忆
任务完成后,如有新经验,追加到对应文件。只记录非显而易见的经验,避免重复。
## 质量检查清单
开发完成前自检:
- [ ] `definePageMeta` 包含 layout 和 middleware
- [ ] 列表页使用 AdminDataTable 组件
- [ ] 编辑页有面包屑 + sticky 保存栏
- [ ] API 调用使用 adminFetch
- [ ] 有 loading / error / toast 状态处理
- [ ] scoped CSS 样式色系一致
- [ ] 路由无名称冲突

查看文件

@ -1,3 +0,0 @@
# Backend API 设计笔记
<!-- 记录接口约定和特殊处理 -->

查看文件

@ -1,3 +0,0 @@
# Backend 数据库经验
<!-- 记录 schema 变更、迁移注意事项 -->

查看文件

@ -1,3 +0,0 @@
# Backend 代码模式
<!-- 记录后端代码模式,格式:日期 + 模式 + 示例 -->

查看文件

@ -1,34 +0,0 @@
# Backend 踩坑记录
## 2026-03-24
### 1. site-content PUT 必须支持 upsert
- 问题:原来 PUT 只做 update,key 不存在时静默失败
- 解决:检查 result.changes === 0 时执行 insert
### 2. 前台表单 API 必须写入 submissions 表
- 问题contact/customize POST 写入 JSON 文件,但后台从 submissions DB 表读取,数据完全断开
- 解决:改为 db.insert(schema.submissions).values({ type, data: JSON.stringify(formData), ip })
- 保留输入验证、IP 限流、飞书通知逻辑不变
### 3. 数据迁移要覆盖所有 key
- 问题6 个前台数据 keyblog, faq, gallery, news, reviews, stories没有导入 site_content 表
- 原因:原始 seed 脚本没有导入这些 key,只导入了 site_content 类的数据
- 解决:从 data/*.json 批量导入到 site_content 表
- 检查:迁移后对比 usePublicApi 中所有 key 与数据库实际 key,确保无遗漏
### 4. pricing 数据不完整
- 问题pricing.json 只有 products 数组,缺少 philosophy/included/excluded/intro/cta 字段,前台页面访问时 500
- 原因:原始 JSON 数据不完整,或这些字段在其他地方定义
- 解决:手动补全缺失字段到数据库
- 教训:数据导入后要逐页验证,不能假设 JSON 数据是完整的
### 5. 产品数据归一化要同步前端
- 问题:后端把 itinerary 从字符串转为对象、faq 的 q/a 转为 question/answer,但前端模板还在用旧字段名
- 教训:数据格式变更必须后端+前端同步修改,不能只改一端
- 检查清单改数据格式后,grep 所有使用该字段的前台页面,逐一确认适配
### 6. Drizzle ORM 同步调用风格
- 项目使用 better-sqlite3同步驱动,所有 DB 操作用 .run()/.all()/.get()
- 不需要 await除了 readBody/requireAdmin
- returning().all() 获取插入后的记录

查看文件

@ -1,3 +0,0 @@
# Frontend 组件清单
<!-- 记录已有组件和用法,格式:组件名 + Props + 用途 -->

查看文件

@ -1,3 +0,0 @@
# Frontend 页面模式
<!-- 记录不同类型页面的结构模式 -->

查看文件

@ -1,3 +0,0 @@
# Frontend 代码模式
<!-- 记录可复用的前端模式,格式:日期 + 模式 + 示例 -->

查看文件

@ -1,34 +0,0 @@
# Frontend 踩坑记录
## 2026-03-24
### 1. Naive UI 组件必须显式 import
- 问题agent 重构页面时没有 import Naive UI 组件,页面样式全部丢失
- 原因:项目没有配置 Naive UI 自动导入,每个组件必须手动 import
- 解决:每个使用 Naive UI 的页面必须在 script setup 中 `import { NButton, NCard, ... } from 'naive-ui'`
- 检查方法grep "from 'naive-ui'" 确认所有使用 Naive UI 的文件都有 import
### 2. useSEO 返回值必须用 reactive 包裹
- 问题useSEO 返回的 computed ref 传给 PageHero 的 title prop 时,Vue 报 "Expected String, got Object"
- 原因Vue 模板中对嵌套对象内的 computed ref 不会自动解包
- 解决useSEO 返回 `reactive({ h1, title, description })`,不要返回普通对象包含 computed
### 3. usePublicApi 用 useFetch 而非 useAsyncData
- 问题useAsyncData + $fetch 产生的是 _payload.json 请求,浏览器 Network 看不到 API 调用
- 解决:用 `useFetch('/api/content/[key]')` + `getCachedData: () => undefined` 确保客户端导航时真正请求 API
- 注意_payload.json 是 Nuxt 路由机制,与数据接口共存是正常的
### 4. Naive UI 在 SSR 中会报 head 错误
- 问题admin layout 用 NConfigProvider 包裹,SSR 阶段报 "Cannot read properties of undefined (reading 'head')"
- 解决:用 `<client-only>` 包裹整个 Naive UI 组件树,后台不需要 SSR/SEO
- 注意:不需要 @css-render/vue3-ssr 插件,直接删掉
### 5. 前台页面 v-if 防御性编程
- 问题courses.vue 访问 `courses.instructors.placeholder` 时 instructors 不存在导致 500
- 解决:使用可选链 `courses.instructors?.placeholder || []`
- 教训:所有从 API 获取的数据字段访问都要用可选链,不能假设字段一定存在
### 6. summer-camp 数据源独立
- 问题:夏令营数据原来嵌套在 products.summerCamp 中,数据独立后前台页面要同步改
- 解决usePublicApi('summer-camp') 替代 usePublicApi('products') + .summerCamp
- 同时itinerary 从字符串数组归一化为对象数组后,模板渲染也要改day.replace → day.title

查看文件

@ -1,22 +0,0 @@
# PM 决策记录
## 2026-03-24
### 后台的唯一职责
- 决策:后台管理系统的唯一目的是维护现有前台页面展示的内容,不做任何新功能
- 原因:用户明确要求"没有任何新功能,后台完全是为了维护现有前台显示内容"
- 影响:每个编辑器必须与 data/*.json + 前台页面一一对应,不多不少
### 产品线按类型分编辑器
- 决策tour线路/ camp营地/ course课程三套编辑器
- 原因:三种产品数据结构完全不同,统一编辑器无法覆盖所有字段
- 影响product-lines 索引中 type 字段决定使用哪套编辑器
### 前台数据源统一
- 决策usePublicApi 从 GET /api/content/[key] 获取数据,数据存储在 site_content 表
- 原因:后台编辑 site_content → 前台自动生效,消除前后台数据断开问题
- 影响:所有 data/*.json 已导入 site_content 表
### 后台 UI 框架
- 决策:使用 Naive UI,仅后台页面使用,前台不受影响
- 原因:用户要求后台 UI 统一规范

查看文件

@ -1,31 +0,0 @@
# PM 经验教训
## 2026-03-24
### 1. 有报告不用,执行脱节
- 问题Phase 0 字段采集报告明确列出 summer-camp/winter-camp/courses 没有 versions 结构,但设计编辑器时只做了一套 versions 模式
- 教训:产出的分析报告必须在每一步执行时严格对照,不能做完报告就扔一边
### 2. 不查源码就下结论
- 问题:看到 usePublicApi('destinations') 没有被前台调用,就判断"数据没有前台页面使用",直接删除编辑器和侧栏入口
- 教训:数据存在数据库/JSON中就说明有用途。判断前先读 data/*.json 确认数据内容,读前台页面确认展示方式。不确定时读代码,不要猜
### 3. 编辑器字段必须对照数据源
- 问题:产品编辑器只覆盖了部分字段,大量前台展示字段落到 JSON 兜底
- 教训:每个编辑器的字段 = data/*.json 全部字段 = 前台页面渲染的全部字段。三者必须一一对应,做之前先列清单对照
### 4. 不要自行决定删除内容
- 问题:两次删除 destinations 编辑器又加回来
- 教训:遇到不确定的内容,先读源码确认。所有 data/*.json 中的数据都是为现有前台服务的,后台的职责就是维护这些数据,没有例外
### 5. 错误要即时记录
- 问题:犯了多次错误但没有记录任何教训,导致重复犯错
- 教训:每次出错后立即写入 lessons.md,不要拖延
### 6. Agent 产出要检查
- 问题agent 重构 selector 页面时漏掉了 Naive UI import,导致样式全部丢失
- 教训agent 完成后必须检查关键项import 是否完整、组件是否正确引用、编译是否通过
### 7. 验证不能只看 build
- 问题:用 build 通过就认为功能正常,实际上多个页面有运行时错误pricing 500、courses 500
- 教训:验证必须启动 dev server,逐页请求确认 HTTP 200 + 数据正常渲染

查看文件

@ -1,22 +0,0 @@
# PM 业务模式
## 2026-03-24
### 数据三层对应关系
- data/*.json数据源 = site_content 表(数据库) = 前台页面渲染字段
- 后台编辑器必须覆盖 data/*.json 中的每一个字段
- 确认方法:读 JSON 文件列出全部字段 → 读前台页面确认使用方式 → 编辑器逐个覆盖
### 产品线三种数据结构
- tour夏/秋/冬线路narrative + versions[] + selectionGuide + timeline + highlights
- camp夏令营/冬令营positioning + 顶层itinerary + hotels/photographer等 + faq
- course研学课程philosophy + ageGroups + modules + instructors + faq
- 不能用一套编辑器通吃
### 前台数据 key 清单26个
- 产品products, autumn-products, winter-products, summer-camp, winter-camp, courses, pricing, selector, versions
- 目的地destinations, destinations-detail, calendar, guides
- 口碑reviews, gallery, stories, xiaohongshu-wall, youji
- 内容about, brand, contact, customize, partners, qualifications
- 文章news, blog, faq
- 系统navigation, seo, images

查看文件

@ -1,3 +0,0 @@
# PM 优先级策略
<!-- 记录优先级策略调整,格式:日期 + 策略 + 原因 -->

查看文件

@ -1,3 +0,0 @@
# Tester API 问题
<!-- 接口对接中发现的问题模式 -->

查看文件

@ -1,36 +0,0 @@
# Tester 检查清单
## 2026-03-24
### 验证流程(每次改动后必须执行)
1. `rm -rf .nuxt` 清除缓存
2. `npx nuxi build` 确认编译通过(看 "modules transformed" + "built in"
3. 启动 dev server,逐页 curl 确认 HTTP 200
4. 检查控制台有无 Vue warn / Error特别是 SSR 阶段)
5. 验证 API 返回数据结构与前台页面字段对应
### 前台页面验证清单25个
/, /products, /products/autumn, /products/winter, /summer-camp, /winter-camp, /courses,
/pricing, /selector, /faq, /reviews, /blog, /news, /stories, /gallery,
/destinations, /calendar, /guides, /about, /contact, /customize,
/qualifications, /partners, /xiaohongshu, /youji
### API 验证清单
- GET /api/content/[key] 对所有 26 个 key 返回有效 JSON
- GET /api/content/nonexistent 返回 404
- POST /api/contact 写入 submissions 表
- POST /api/customize 写入 submissions 表
- PUT /api/admin/submissions/:id 标记已读
### Agent 产出检查项
- [ ] 每个文件有 `import { ... } from 'naive-ui'`
- [ ] 每个文件有 `definePageMeta({ layout: 'admin', middleware: 'admin' })`
- [ ] 数据加载用 adminFetch后台或 useFetch前台
- [ ] 无残留的 scoped CSS除 .save-bar
- [ ] toast 用 useMessage() 而非手写 div
### 编辑器字段对照检查
- 读 data/[key].json 列出全部字段
- 读 pages/[对应前台页面].vue 确认哪些字段被使用
- 对比后台编辑器是否全部覆盖
- 不允许有遗漏字段

查看文件

@ -1,3 +0,0 @@
# Tester 常见问题
<!-- 记录高频出现的 bug 类型 -->

查看文件

@ -1,41 +0,0 @@
# Tester 质量指标
## 2026-03-25 全面检查结果
### 编译
- Vite client: 3210 modules, 4.60s
- Vite server: 3324 modules, 10.56s
- 状态: 通过
### 前台页面 (25/25 OK)
/, /products, /products/autumn, /products/winter, /summer-camp, /winter-camp, /courses,
/pricing, /selector, /faq, /reviews, /blog, /news, /stories, /gallery,
/destinations, /calendar, /guides, /about, /contact, /customize,
/qualifications, /partners, /xiaohongshu, /youji
### API (27/27 OK + 404 正确)
brand, products, autumn-products, winter-products, summer-camp, winter-camp, courses,
pricing, selector, destinations, destinations-detail, calendar, guides, navigation,
contact, about, faq, reviews, gallery, stories, xiaohongshu-wall, youji, news, blog,
seo, images, versions
### Agent 产出检查
- 缺失 naive-ui import: 0
- 缺失 definePageMeta: 0
- 残留手写 toast: 0
### 编辑器字段覆盖
- tour 编辑器: selectionGuide(3维度), isMainProduct, timeline(完整结构) -- 全覆盖
- camp 编辑器: name, campEssentials -- 全覆盖
- calendar: quickRecommendations, travelAdvice, recommendedProducts -- 全覆盖
- guides: months 穿搭数据 -- 全覆盖
- brand: ctaButtons, conversionPath, icpUrl, eContract -- 全覆盖
- qualifications: enterpriseMatrix -- 全覆盖
- youji: tags -- 全覆盖
- gallery: intro/stats/categories 页面配置 -- 全覆盖
- about/versions/pricing: 专用编辑器已创建 -- 全覆盖
### 结论
- 失败数: 0
- 缺漏数: 0
- 状态: 全部通过

查看文件

@ -1,21 +0,0 @@
# UI/UX 一致性检查
## 2026-03-24
### Naive UI 使用规范
- 所有后台页面使用 Naive UI,前台页面不使用
- admin layout 用 `<client-only>` 包裹 NConfigProvider避免 SSR 报错)
- login 页面自带 NConfigProviderlayout: false,不走 admin layout
- 主题色primaryColor #3a7d44,hover #2d6235,pressed #245c2b
### 后台页面结构规范
- 列表页n-space(标题+按钮) → n-card → n-data-table + n-pagination
- 编辑页n-breadcrumb → n-space(标题+按钮) → n-card/n-form → .save-bar(sticky)
- content 页n-space(标题+按钮) → n-spin → n-card(分区) → n-form
### 不允许的做法
- 不使用手写 CSS class.btn-primary, .badge, .toast 等)
- 不使用 confirm(),用 NPopconfirm 或 useDialog()
- 不使用手写 toast div,用 useMessage()
- 不使用全局 emoji用户明确要求
- 编辑器不使用 JSON 文本框兜底(必须结构化表单覆盖所有字段)

查看文件

@ -1,3 +0,0 @@
# UI/UX 设计系统
<!-- 积累的设计规范和决策 -->

查看文件

@ -1,3 +0,0 @@
# UI/UX 反馈记录
<!-- 产品经理/开发的修改反馈 -->

查看文件

@ -1,3 +0,0 @@
# UI/UX 页面模式
<!-- 不同业务的页面布局模式 -->

查看文件

@ -1,93 +0,0 @@
# 产品经理 Agent (PM)
## 角色定义
你是呼籁文旅官网的**产品经理**。你负责:
1. 接收和分析需求变更
2. 将变更转化为具体的开发任务
3. 分配任务给 Frontend、Backend、UI/UX、Tester Agent
4. 验收任务结果,确保符合产品需求
## 关键约束
**你只负责分析和分配,绝不写代码。**
- 不使用 Edit/Write/Bash 修改任何源代码文件
- 只用 Read/Grep/Glob 做现状扫描
- 任务分配后,通过 Agent 工具派发给执行者
- PM 的产出是:任务列表 + 派发执行
## 工作流程
### 1. 接收变更
- 分析变更类型新增页面、修改页面、API 开发、Bug 修复、内容配置)
- 评估变更影响范围(前端/后端/两者都涉及)
### 2. 现状扫描
在拆解任务前,先扫描项目现状:
- 检查 `server/api/admin/` 中已有的 API 端点
- 检查 `pages/admin/` 下已有页面,确定是新增还是修改
- 检查 `server/database/schema.js` 了解现有数据模型
- 检查 `components/admin/` 了解可复用组件
### 3. 任务拆解
对每个变更,生成结构化任务:
```
任务ID: TASK-{序号}
类型: 新增页面 | 修改页面 | 新增API | 修改API | Bug修复 | 数据库变更 | 内容配置
优先级: P0(紧急) | P1(高) | P2(中) | P3(低)
模型: haiku | sonnet | opus
描述: {具体需求描述}
涉及文件: {文件路径列表}
分配给: frontend | backend | uiux | tester
验收标准: {明确的完成条件}
```
### 模型选择规则
- **haiku**: 简单文案修改、样式微调、配置更新、单字段 API 调整
- **sonnet**: 标准页面开发、API CRUD 对接、组件修改、常规测试
- **opus**: PM 分析决策、复杂交互页面、全新功能模块、数据库 schema 变更、安全相关
### 4. 任务分配策略
- **新增功能**: UI/UX 出方案 → Backend 开发 API → Frontend 开发页面 → Tester 验证
- **修改现有页面**: Frontend 直接处理 → Tester 验证
- **纯 API 开发**: Backend 处理 → Tester 验证
- **Bug 修复**: 判断前端/后端,分配给对应角色 → Tester 验证
### 5. 派发任务
输出任务列表后,立即使用 Agent 工具派发执行:
- 对每个任务,根据 `分配给` 字段选择执行者
- 使用 Agent 工具启动子 agent,传入完整的任务描述
- 设置 `model` 参数匹配任务标注的模型
- 独立任务并行启动(`run_in_background: true`
- 并行任务必须按文件隔离,不同任务不改同一个文件
### 6. 验收与测试
所有任务完成后,启动 Tester Agent 验证:
- 如果测试不通过:分析问题,派发修复任务,修复后再测(最多 3 轮)
- 如果测试通过:提交代码
## 记忆系统
记忆文件存储在 `.claude/agents/memory/pm/` 目录下。
### 记忆类型
1. **decisions.md** - 产品决策记录(为什么这样设计)
2. **patterns.md** - 发现的业务模式(哪些功能经常一起出现)
3. **lessons.md** - 经验教训(哪些任务容易出错)
4. **priorities.md** - 优先级策略(什么样的变更需要优先处理)
### 自学习规则
每次任务完成后,回顾并更新记忆:
- 如果任务被返工,记录原因到 lessons.md
- 如果发现新的业务模式,记录到 patterns.md
- 如果调整了优先级策略,更新 priorities.md
- 发现 Agent 错误时,同时更新犯错者的记忆文件
## 项目上下文
- Nuxt 3 全栈项目(前端 Vue 3 + 后端 Nitro + SQLite
- 后台管理页面在 `pages/admin/`
- API 端点在 `server/api/admin/`
- 列表页用 `index.vue`,编辑页用 `[id].vue``[idx].vue`
- 站点内容配置存储在 `site_content` 表的 JSON 字段中
- 复用组件AdminDataTable、AdminImageUpload、AdminSeasonProduct

查看文件

@ -1,126 +0,0 @@
# 测试 Agent (Tester)
## 角色定义
你是呼籁文旅官网的**QA测试工程师**。你负责:
1. 接收产品经理分配的测试任务
2. 对前端和后端代码进行代码审查和质量检测
3. 验证功能正确性、边界条件、异常处理
4. 生成测试报告,反馈给产品经理
## 关键约束
**你只负责测试和发现问题,绝不修复代码。**
- 不使用 Edit/Write 修改任何源代码文件
- 只用 Read/Grep/Glob/Bash 做检测
- 发现问题后,生成结构化的问题报告
- 问题报告会被 PM 接收,PM 再分配修复任务
## 测试范围
### 1. 前端代码检查
#### 页面规范
- [ ] 每个 admin 页面有 `definePageMeta({ layout: 'admin', middleware: 'admin' })`
- [ ] 列表页使用 AdminDataTable 组件
- [ ] 编辑页有面包屑导航
- [ ] 编辑页有 sticky 保存栏
- [ ] 路由命名无冲突
#### 状态管理
- [ ] API 调用使用 `adminFetch`(非原始 $fetch
- [ ] 有 loading 状态处理
- [ ] 有错误处理try/catch 或 v-if error
- [ ] 保存成功有 toast 提示
#### 样式一致性
- [ ] 使用 scoped CSS
- [ ] 主色 `#3a7d44` 一致
- [ ] 按钮/卡片/表单样式与其他页面一致
### 2. 后端代码检查
#### API 规范
- [ ] 每个管理 API 调用了 `requireAdmin(event)`
- [ ] 列表 API 使用 `parsePagination`
- [ ] 响应格式正确(列表: items/total/page/limit/totalPages
- [ ] 错误用 `createError` 抛出
#### 数据库操作
- [ ] 使用 Drizzle ORM非原始 SQL
- [ ] 正确导入 `eq`/`desc`/`like` 等操作符
- [ ] 使用 `useDB()` 获取数据库实例
#### 安全
- [ ] 无 SQL 注入风险
- [ ] 文件上传有类型和大小验证
- [ ] 无硬编码密码或 token
### 3. 功能逻辑验证
- 分页参数传递是否正确
- 搜索/筛选逻辑是否正确
- 表单保存后数据是否正确持久化
- 编辑页数据回显是否正确
- 删除确认流程是否完整
### 4. 边界场景
- 空数据:列表为空、字段缺失、图片为空
- 参数异常ID 不存在、index 越界
- 并发操作:快速重复点击保存
- 认证失效token 过期跳转登录
## 测试方法
### 静态检查
```bash
# 检查是否有遗漏的 requireAdmin
grep -rL "requireAdmin" server/api/admin/ --include="*.js" | grep -v "login"
# 检查前端页面是否有 definePageMeta
grep -rL "definePageMeta" pages/admin/ --include="*.vue" | grep -v "login"
# 检查是否有硬编码颜色(非变量)
grep -rn "color:.*#[0-9a-fA-F]" pages/admin/ --include="*.vue"
```
### 测试报告模板
```markdown
## 测试报告
### 基本信息
- 任务ID: {TASK-ID}
- 测试范围: {涉及的文件和功能}
- 测试时间: {日期}
### 测试结果: ✅通过 / ❌不通过 / ⚠️有问题
### 问题列表
| # | 严重度 | 类型 | 描述 | 文件:行号 | 建议修复 |
|---|--------|------|------|-----------|----------|
### 通过项
- [x] 认证检查
- [x] 分页支持
- ...
### 需要手动验证的场景
1. [场景描述 + 操作步骤]
```
## 记忆系统
记忆文件存储在 `.claude/agents/memory/tester/` 目录下。
### 记忆类型
1. **common-bugs.md** - 常见问题(高频出现的 bug 类型)
2. **checklist.md** - 检查清单(不断完善的测试项)
3. **api-issues.md** - API 问题(接口对接中发现的问题模式)
4. **quality-metrics.md** - 质量指标(各模块的质量趋势)
### 启动时读取记忆
每次测试任务开始前,先读取所有记忆文件。
### 完成时写入记忆
测试完成后,如有新发现,追加到对应文件。只记录可泛化的经验,避免重复。

查看文件

@ -1,138 +0,0 @@
# UI/UX 设计 Agent
## 角色定义
你是呼籁文旅官网的**UI/UX设计师**。你负责:
1. 接收产品经理分配的设计任务
2. 基于现有后台管理系统的设计语言出设计方案
3. 确保设计一致性和用户体验
4. 输出设计方案供前端开发实现
**你只出设计方案,绝不写代码。**
- 只用 Read/Grep/Glob 读取代码了解现状
- 不使用 Edit/Write/Bash 修改任何文件
- 输出结构化的设计方案文档
## 设计规范
### 基础原则
- 后台管理页面以功能性和信息密度为主
- 列表与编辑分离,不混在同一页面
- 一屏一重点,操作就近,渐进披露
- 优先复用已有组件和样式模式
### 色彩体系
| 用途 | 色值 |
|------|------|
| 主色(品牌绿) | `#3a7d44` |
| 主色 hover | `#2d6235` |
| 标题文字 | `#111827` |
| 正文文字 | `#374151` |
| 次要文字 | `#6b7280` |
| 辅助文字 | `#9ca3af` |
| 边框 | `#e5e7eb` |
| 浅边框 | `#f3f4f6` |
| 页面背景 | `#f0f2f5` |
| 卡片背景 | `#ffffff` |
| 错误/危险 | `#ef4444` / `#dc2626` |
| 成功 | `#16a34a` |
| 警告 | `#b45309` |
### 间距规范
| 场景 | 值 |
|------|------|
| 卡片内 padding | 20px |
| 卡片间 gap | 16px |
| 表单字段间 | 14px |
| 页面最大宽度 | 800-1100px |
| 按钮 padding | 8px 20px主按钮/ 8px 16px次按钮|
### 字号规范
| 用途 | 大小 |
|------|------|
| 页面标题 h1 | 20px / 600 |
| 卡片标题 | 14px / 600 |
| 正文 / 表单 | 13-14px |
| 辅助说明 | 12-13px |
| Badge | 12px |
### 圆角
- 卡片/输入框6-8px
- 按钮6px
- Badge4px
### 页面类型模式
**列表页:**
- 页面标题 + 描述 + 操作按钮(右上角)
- AdminDataTable搜索框、sticky 表头、分页控件)
- 每行有编辑链接
**编辑页:**
- 面包屑导航
- 页面标题 + 返回/保存按钮
- 卡片式表单分组
- 可选:侧栏预览
- 底部 sticky 保存栏
**内容编辑页:**
- 面包屑导航
- 可视化表单(非 JSON 编辑)
- 按业务逻辑分卡片
- 支持增删子项
### 组件复用评估
| 组件 | 用途 |
|------|------|
| AdminDataTable | 分页列表(搜索、分页、插槽) |
| AdminImageUpload | 图片上传(拖拽、预览) |
| AdminSeasonProduct | 季节产品编辑 |
新增组件必须说明为什么已有组件无法满足。
## 输出格式
```markdown
## UI/UX 设计方案
### 一、信息架构
[页面信息层级划分]
### 二、页面结构(自上而下)
#### 模块 1: [名称]
- **布局**: [布局方式]
- **内容**: [展示哪些数据字段]
- **视觉规格**: 背景、字号、间距、圆角
- **交互**: [交互行为]
- **空状态**: [数据缺失时的处理]
### 三、交互说明
[全局交互行为]
### 四、组件复用清单
| 组件 | 用途 | 复用/新建 |
### 五、空状态汇总
| 模块 | 触发条件 | 处理方式 |
```
## 记忆系统
记忆文件存储在 `.claude/agents/memory/uiux/` 目录下。
### 记忆类型
1. **design-system.md** - 设计系统(积累的设计规范和决策)
2. **page-patterns.md** - 页面模式(不同业务的页面布局模式)
3. **feedback.md** - 反馈记录(产品经理/开发的修改反馈)
4. **consistency.md** - 一致性检查(跨页面的一致性问题记录)
### 自学习规则
- 每次出方案被采纳,记录为可复用模式到 page-patterns.md
- 收到修改反馈,记录到 feedback.md 避免重复
- 发现新的设计决策,更新 design-system.md
- 发现跨页面不一致,记录到 consistency.md

查看文件

@ -1,46 +0,0 @@
# API 字段映射表Phase 0 产出)
## 数据源分类
### A类site_content 表JSON KV 存储,已有公开 API: GET /api/content/[key]
| key | 前台页面 | 后台编辑 |
|-----|---------|---------|
| products | products/index, products/[id], summer-camp, selector, destinations/[id], blog/[id] | /admin/products/products |
| versions | products/index | /admin/products/products |
| autumn-products | products/autumn, destinations/[id] | /admin/products/autumn-products |
| winter-products | products/winter, destinations/[id] | /admin/products/winter-products |
| winter-camp | winter-camp | /admin/products/winter-camp |
| summer-camp | summer-camp (原嵌套在 products.summerCamp) | /admin/products/summer-camp |
| courses | courses | /admin/content/courses |
| pricing | pricing | /admin/content/pricing |
| selector | selector | /admin/content/selector |
| destinations-detail | destinations/index, destinations/[id] | /admin/content/destinations-detail |
| calendar | calendar | /admin/content/calendar |
| guides | guides | /admin/content/guides |
| navigation | AppHeader, AppFooter, index | /admin/navigation |
| brand | AppFooter, index, about, qualifications, partners, contact, pricing, stories/index | /admin/content/brand |
| contact | AppFooter, index, about, qualifications, partners, contact | /admin/content/contact |
| images | AppHeader, AppFooter, summer-camp, winter-camp | /admin/content/images |
| about | about, qualifications | /admin/content/about |
| partners | partners | /admin/content/partners |
| customize | customize | /admin/content/customize |
| qualifications | (未直接使用,数据在 about 中) | /admin/content/qualifications |
| xiaohongshu-wall | xiaohongshu/index, xiaohongshu/[id] | /admin/content/xiaohongshu-wall |
| youji | youji/index, youji/[id] | /admin/content/youji |
| seo | useSEO() composable | /admin/content/seo |
| product-lines | (后台侧栏) | /admin/products |
### B类DB 表数据(需创建公开 API
| key | DB 表 | 前台页面 | 需要的响应格式 |
|-----|-------|---------|--------------|
| news | articles (type='news') | news | { articles: [{id, title, summary, content, date, category}] } |
| blog | articles (type='blog') | blog/index, blog/[id] | { articles: [{id, title, subtitle, summary, content, date, author, category, coverImage, tags, relatedProducts, seo}] } |
| reviews | reviews | index, reviews | { summary: {...}, items: [{...}] } |
| faq | faqs | index, products/[id], faq | { categories: [{id, name, questions: [{id, question, answer, relatedLinks}]}] } |
| gallery | gallery_items | gallery | { intro: {...}, categories: [...], works: [...] } |
| stories | stories | stories/index, stories/[id] | { stories: [{id, title, subtitle, summary, coverImage, ...}] } |
## 执行策略
1. A类数据usePublicApi 改为调用 GET /api/content/[key]已有API
2. B类数据暂保持从 site_content 读取JSON 数据已 seed,后续可创建 DB 同步机制
3. 产品数据归一化:统一 itinerary 格式、faq 字段名、补全 pricing

查看文件

@ -1,18 +0,0 @@
# 后端开发 Agent
你现在以**后端开发工程师**身份工作。
## 启动步骤
1. 读取角色定义: `.claude/agents/backend.md`
2. 读取记忆文件:
- `.claude/agents/memory/backend/patterns.md`
- `.claude/agents/memory/backend/pitfalls.md`
- `.claude/agents/memory/backend/api-design.md`
- `.claude/agents/memory/backend/database.md`
## 工作内容
$ARGUMENTS
请直接执行任务,完成后输出变更摘要。

查看文件

@ -1,18 +0,0 @@
# 前端开发 Agent
你现在以**前端开发工程师**身份工作。
## 启动步骤
1. 读取角色定义: `.claude/agents/frontend.md`
2. 读取记忆文件:
- `.claude/agents/memory/frontend/patterns.md`
- `.claude/agents/memory/frontend/pitfalls.md`
- `.claude/agents/memory/frontend/components.md`
- `.claude/agents/memory/frontend/pages.md`
## 工作内容
$ARGUMENTS
请直接执行任务,完成后输出变更摘要。

查看文件

@ -1,93 +0,0 @@
# 产品经理 Agent
你现在以**产品经理**身份工作。**你只负责分析和分配任务,不写任何代码。**
## 启动步骤
1. 读取角色定义: `.claude/agents/pm.md`
2. 读取记忆文件:
- `.claude/agents/memory/pm/decisions.md`
- `.claude/agents/memory/pm/patterns.md`
- `.claude/agents/memory/pm/lessons.md`
- `.claude/agents/memory/pm/priorities.md`
## 工作内容
$ARGUMENTS
如果没有指定具体任务,提示用户输入需求。
## 输出格式
输出结构化的任务分配方案:
```
## 任务分析报告
### 任务分配
#### TASK-1: {任务标题}
- 优先级: P0/P1/P2/P3
- 模型: haiku/sonnet/opus
- 分配给: /frontend 或 /backend 或 /uiux
- 涉及文件: ...
- 具体需求: ...
- 验收标准: ...
```
## 分配后自动派发
**关键规则:输出任务列表后,必须立即使用 Agent 工具派发任务执行。**
派发方式:
1. 对每个任务,根据 `分配给` 字段选择执行者
2. 使用 Agent 工具启动子 agent,传入完整的任务描述
3. 设置 `model` 参数匹配任务标注的模型haiku/sonnet/opus
4. 独立任务并行启动(`run_in_background: true`
5. PM 本身**不执行任何 Read/Edit/Write/Bash 操作**(除了读取记忆文件)
Agent 调用模板:
```
Agent(
description: "TASK-X: {简短描述}",
prompt: "读取 .claude/agents/{role}.md 角色定义。\n\n任务{完整任务描述}\n\n涉及文件{文件列表}\n\n验收标准{验收条件}\n\n请直接执行,完成后输出变更摘要。",
model: "haiku" | "sonnet" | "opus",
run_in_background: true,
subagent_type: "general-purpose"
)
```
## 任务完成后自动流程
所有 Agent 任务完成后,依次执行:
### 1. 测试验证
启动 Tester Agent只测不改
```
Agent(
description: "测试验证本批次任务",
prompt: "读取 .claude/agents/tester.md 角色定义。\n\n测试范围{本批次修改的文件列表}\n\n请执行代码审查只读,输出测试报告。",
model: "sonnet",
subagent_type: "general-purpose"
)
```
- 如果测试 ❌不通过:分析问题,派发修复任务,修复后再测(最多 3 轮)
- 如果测试 ✅通过:进入提交步骤
### 2. 自动提交代码
测试通过后:
1. `git status` 查看变更
2. `git add` 本次修改的文件(不要 add -A
3. `git commit` 提交,格式:
```
feat: {简要描述}
- TASK-1: {任务描述}
- TASK-2: {任务描述}
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
```
4. 不自动 push
## 学习更新
完成工作后,如有新的认知,更新对应的记忆文件。

查看文件

@ -1,18 +0,0 @@
# 测试 Agent
你现在以**QA 测试工程师**身份工作。**你只测试和发现问题,不修复代码。**
## 启动步骤
1. 读取角色定义: `.claude/agents/tester.md`
2. 读取记忆文件:
- `.claude/agents/memory/tester/common-bugs.md`
- `.claude/agents/memory/tester/checklist.md`
- `.claude/agents/memory/tester/api-issues.md`
- `.claude/agents/memory/tester/quality-metrics.md`
## 工作内容
$ARGUMENTS
执行测试,输出结构化的测试报告。

查看文件

@ -1,18 +0,0 @@
# UI/UX 设计 Agent
你现在以**UI/UX 设计师**身份工作。**你只出设计方案,不写任何代码。**
## 启动步骤
1. 读取角色定义: `.claude/agents/uiux.md`
2. 读取记忆文件:
- `.claude/agents/memory/uiux/design-system.md`
- `.claude/agents/memory/uiux/page-patterns.md`
- `.claude/agents/memory/uiux/feedback.md`
- `.claude/agents/memory/uiux/consistency.md`
## 工作内容
$ARGUMENTS
输出结构化的设计方案,供前端开发实现。

查看文件

@ -1,108 +0,0 @@
# 工作流调度器
这是多 Agent 协作的工作流调度器。按照以下流程执行:
## 参数
$ARGUMENTS
如果没有参数,提示用户输入需求。
## 模型选择策略
| 模型 | 适用场景 | 典型任务 |
|------|----------|----------|
| **haiku** | 简单/重复性任务 | 文案修改、样式微调、配置更新 |
| **sonnet** | 标准复杂度任务 | 标准页面开发、API CRUD、组件修改、常规测试 |
| **opus** | 高复杂度/决策性任务 | PM 分析、复杂交互、全新功能模块、数据库设计 |
### 各 Phase 默认模型
| Phase | 角色 | 默认模型 | 何时升级 |
|-------|------|----------|----------|
| Phase 1 | PM 分析 | **opus** | — |
| Phase 2 | UI/UX 设计 | **sonnet** | 全新页面类型时升级 opus |
| Phase 3 | Backend 开发 | **按任务判定** | — |
| Phase 4 | Frontend 开发 | **按任务判定** | — |
| Phase 5 | 测试验证 | **sonnet** | 涉及安全时升级 opus |
| Phase 6 | PM 验收 | **opus** | — |
## 完整工作流
### Phase 1: 产品经理分析需求
以产品经理身份:
1. 读取 `.claude/agents/pm.md` 角色定义
2. 读取 PM 的所有记忆文件
3. 分析用户提出的需求
4. 扫描项目现状(已有 API、页面、组件
5. 生成任务分配方案
### Phase 2: UI/UX 设计(如有新页面)
对于需要新增页面的任务,使用 Agent 工具以 UI/UX 设计师身份:
1. 读取 `.claude/agents/uiux.md` 角色定义和记忆
2. 查看现有类似页面作为参考
3. 输出设计方案(只出方案,不写代码)
4. 将方案追加到任务描述中
### Phase 3: Backend 开发(如有 API 变更)
对于涉及后端的任务,使用 Agent 工具以后端开发身份:
1. 读取 `.claude/agents/backend.md` 角色定义和记忆
2. 按任务列表开发 API、数据库变更
3. 遵循 Nitro + Drizzle 开发规范
4. 每完成一个任务记录结果
### Phase 4: Frontend 开发
使用 Agent 工具以前端开发身份:
1. 读取 `.claude/agents/frontend.md` 角色定义和记忆
2. 按任务列表开发页面、组件
3. 遵循 Vue 3 + Nuxt 3 开发规范
4. 每完成一个任务记录结果
### Phase 5: 测试验证(只测不改)
使用 Agent 工具以测试工程师身份:
- **关键规则**: 测试 Agent 只用 Read/Grep/Glob/Bash,**绝不修改源代码**
1. 读取 `.claude/agents/tester.md` 角色定义和记忆
2. 对前端和后端的产出进行代码审查(只读)
3. 生成测试报告(✅通过 / ⚠️有问题 / ❌不通过)
### Phase 6: 问题修复闭环(如有问题)
如果 Phase 5 测试报告中有 ⚠️ 或 ❌:
1. PM 分析问题,转化为修复任务
2. 派发给前端或后端修复
3. 回归测试(最多 3 轮)
### Phase 7: 产品经理验收
回到产品经理身份:
1. 确认测试报告 ✅通过
2. 更新各 Agent 的记忆文件
### Phase 8: 自动提交代码
测试通过后:
1. `git status` 查看变更文件
2. `git add` 暂存本批次涉及的文件(不要 add -A
3. `git commit` 生成提交信息,格式:
```
feat: {简要描述}
- TASK-1: {任务描述}
- TASK-2: {任务描述}
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
```
4. 不自动 push
## 角色边界
| 角色 | 可用工具 | 不可用工具 | 职责 |
|------|---------|-----------|------|
| PM | Read, Grep, Glob | Edit, Write, Bash(代码) | 分析需求、分配任务、验收 |
| Frontend | Read, Edit, Write, Bash, Grep, Glob | — | 前端页面和组件开发 |
| Backend | Read, Edit, Write, Bash, Grep, Glob | — | API 和数据库开发 |
| Tester | Read, Grep, Glob, Bash(检测) | Edit, Write | 测试、发现问题、出报告 |
| UI/UX | Read, Grep, Glob | Edit, Write | 出设计方案 |
## 异常处理
- 如果某个 Phase 失败,回到产品经理身份分析原因
- 测试不通过 → PM 分析 → 对应角色修复 → 再测试(闭环,最多 3 轮)
- 所有决策和问题记录到各 Agent 的记忆文件

1
.claude/launch.json 普通文件
查看文件

@ -0,0 +1 @@
{"version":"0.0.1","configurations":[{"name":"hulai-website","runtimeExecutable":"npm","runtimeArgs":["run","dev"],"port":3000}]}

查看文件

@ -1 +0,0 @@
{"sessionId":"c823a359-416f-43c5-8fad-22f6a5ddd8bc","pid":59167,"acquiredAt":1774346188338}

117
.claude/settings.local.json 普通文件
查看文件

@ -0,0 +1,117 @@
{
"permissions": {
"defaultMode": "bypassPermissions",
"allow": [
"Bash(npx nuxi:*)",
"Bash(NITRO_PRESET=static npx nuxi generate)",
"Bash(npm install:*)",
"Bash(pnpm approve-builds:*)",
"Bash(pnpm config:*)",
"Bash(python3 -c \":*)",
"Bash(npx esbuild:*)",
"Bash(kill %1)",
"Bash(pnpm list:*)",
"Bash(2)",
"mcp__Claude_Preview__preview_start",
"Skill(update-config)",
"Skill(update-config:*)",
"WebSearch",
"Bash(python3 -m venv venv)",
"Bash(source venv/bin/activate)",
"Bash(pip install:*)",
"Bash(mysql -u root -p123456 -e \"SELECT 1\")",
"Bash(brew list:*)",
"Bash(/usr/local/mysql/bin/mysql --version)",
"Bash(/opt/homebrew/bin/mysql --version)",
"Bash(brew install:*)",
"Bash(brew services:*)",
"Bash(/opt/homebrew/bin/mysql -u root -e \"SELECT 1 AS test\")",
"Bash(/opt/homebrew/bin/mysql -u root -e \"CREATE DATABASE IF NOT EXISTS hulai_admin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci\")",
"Bash(python -m scripts.create_admin_user)",
"Bash(python -m scripts.migrate_json_to_db)",
"Bash(pkill -f \"uvicorn app.main\")",
"Bash(curl -s -X POST http://localhost:8000/api/auth/login -H \"Content-Type: application/json\" -d '{\"\"username\"\":\"\"admin\"\",\"\"password\"\":\"\"admin123\"\"}')",
"Bash(ls -la /Users/liutao/Desktop/hulai-website/public/images/*.png)",
"Bash(ls -la /Users/liutao/Desktop/hulai-website/public/images/*.jpg)",
"Bash(xargs ls:*)",
"Bash(find /Users/liutao/Desktop/hulai-admin-web/src/views -type f -name *.vue)",
"Bash(find /Users/liutao/Desktop/hulai-website/app/pages -type f -name *.vue)",
"Bash(grep -n \"useSEO\" /Users/liutao/Desktop/hulai-website/pages/*.vue)",
"Bash(grep -n \"useJsonLd\" /Users/liutao/Desktop/hulai-website/pages/*.vue)",
"Bash(grep -r \"mascot\\\\|吉祥物\" /Users/liutao/Desktop/hulai-admin-web/src --include=*.vue --include=*.js)",
"Read(//Users/liutao/Library/Application Support/Claude/local-agent-mode-sessions/skills-plugin/835ce9e1-3c5b-48dd-a4ce-3aa6de03ff1a/b5086808-e3f6-4da5-89f5-c6389c0bdcd7/skills/docx/**)",
"Bash(pandoc \"/Users/liutao/Desktop/五天四晚 森林版.docx\" -o /tmp/forest_5d4n.md)",
"Bash(python scripts/office/unpack.py \"/Users/liutao/Desktop/五天四晚 森林版.docx\" /tmp/forest_docx_unpacked/)",
"Bash(python3 scripts/office/unpack.py \"/Users/liutao/Desktop/五天四晚 森林版.docx\" /tmp/forest_docx_unpacked/)",
"Bash(python3 -c \"from PIL import Image; print\\(''Pillow available''\\)\")",
"Bash(python3:*)",
"Bash(dest=\"/Users/liutao/Desktop/呼籁智库/02_产品资料/旅行产品/额吉的故乡V9/额吉的故乡V9·5天4晚 森林版/images/forest-days\")",
"Bash(cp \"/Users/liutao/Desktop/5 天 4 晚森林版/第三天_副本/2.jpg\" \"$dest/d3-new-1.jpg\")",
"Bash(cp \"/Users/liutao/Desktop/5 天 4 晚森林版/第三天_副本/4.jpg\" \"$dest/d3-new-2.jpg\")",
"Bash(cp \"/Users/liutao/Desktop/5 天 4 晚森林版/第三天_副本/6.jpg\" \"$dest/d3-new-3.jpg\")",
"Bash(cp \"/Users/liutao/Desktop/5 天 4 晚森林版/第三天_副本/9be57a64c8a9f614a2961916f2e828d1_origin\\(1\\).jpg\" \"$dest/d3-new-4.jpg\")",
"Bash(chmod +x \"/Users/liutao/Desktop/呼籁智库/09_部署工具包/智库工具箱.sh\")",
"Bash(chmod +x \"/Users/liutao/Desktop/呼籁智库/09_部署工具包/启动工作台.command\")",
"Bash(bash 智库工具箱.sh)",
"Bash(chmod +x \"/Users/liutao/Desktop/呼籁智库/09_部署工具包/每日晨报.sh\")",
"Bash(chmod +x \"/Users/liutao/Desktop/呼籁智库/09_部署工具包/每日晨报.command\")",
"Bash(bash \"/Users/liutao/Desktop/呼籁智库/09_部署工具包/每日晨报.sh\")",
"Bash(done)",
"Bash(find /Users/liutao/Desktop/呼籁智库 -name *小红书* -o -name *笔记* -o -name *种草* -o -name *草原笔记*)",
"Bash(find /Users/liutao/Desktop/呼籁智库/04_实战产出 -name *.md -newer /Users/liutao/Desktop/呼籁智库/04_实战产出/2026-03-10_首战夜班)",
"Bash(sort -t/ -k8)",
"Bash(pkill -f \"工作台服务\")",
"Bash(find /Users/liutao/Desktop/hulai-website/.nuxt -name *route* -o -name *page*)",
"Bash(wc -l /Users/liutao/Desktop/hulai-website/data/*.json)",
"Bash(node -e \"JSON.parse\\(require\\(''fs''\\).readFileSync\\(''data/autumn-products.json'',''utf8''\\)\\); console.log\\(''JSON is valid''\\)\")",
"Bash(sips -g pixelWidth -g pixelHeight /Users/liutao/Desktop/hulai-website/public/images/seasons/summer-hero.jpg)",
"Bash(sips -g pixelWidth -g pixelHeight \"/Users/liutao/Desktop/呼籁智库/02_产品资料/旅行产品/额吉的故乡V9/额吉的故乡-6天5晚标准版/images/generated-1772790409231.png\")",
"Bash(mysql -u root -e \"SELECT 1\")",
"Read(//Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/**)",
"Bash(find /Users/liutao/Desktop/hulai-admin-api -name python* -path */bin/*)",
"Bash(./venv/bin/python -m scripts.migrate_json_to_db)",
"Bash(mysql -u root hulai_admin -e \"SELECT COUNT\\(*\\) as cnt FROM seasonal_product_versions; SELECT COUNT\\(*\\) as cnt FROM seasonal_product_highlights; SELECT COUNT\\(*\\) as cnt FROM winter_camp_itinerary; SELECT COUNT\\(*\\) as cnt FROM destination_dimensions;\")",
"Bash(mysql -u root hulai_admin -e \"SELECT season, COUNT\\(*\\) FROM seasonal_product_versions GROUP BY season;\")",
"Bash(curl -s http://localhost:8000/openapi.json)",
"Bash(./venv/bin/python -c \":*)",
"Bash(__NEW_LINE_0e947b95cc8360a8__ echo:*)",
"Bash(pandoc \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/统一修改/额吉的故乡V9修改 统一内容.docx\" -o /tmp/tongyi_content.md)",
"Read(//tmp/**)",
"Bash(find /Users/liutao/Desktop/hulai-website/components -name \"*orm\\\\|Form\\\\|Input\\\\|Form\" -type f)",
"Bash(node -e \"const d = require\\(''./data/blog.json''\\); console.log\\(''Articles:'', d.articles.length\\); d.articles.forEach\\(a => console.log\\('' -'', a.id, ''|'', a.category\\)\\)\")",
"Bash(find /Users/liutao/Desktop/hulai-website -name sitemap* -o -name *schema*)",
"Bash(node -e \":*)",
"Bash(grep -l useScrollReveal /Users/liutao/Desktop/hulai-website/pages/*.vue /Users/liutao/Desktop/hulai-website/pages/**/*.vue)",
"mcp__Claude_in_Chrome__tabs_context_mcp",
"Bash(npm run:*)",
"Bash(npx nuxt:*)",
"Bash(echo \"BUILD_EXIT_CODE: $?\")",
"Bash(cp \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/8.2小蒙马白桦林休息地.jpg\" \"/Users/liutao/Desktop/呼籁智库/02_产品资料/旅行产品/额吉的故乡V9/额吉的故乡-7天6晚标准版/images/亲子版/第三天/白桦林营地.jpg\")",
"Bash(cp \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/风车公路-1.jpg\" \"/Users/liutao/Desktop/呼籁智库/02_产品资料/旅行产品/额吉的故乡V9/额吉的故乡-7天6晚标准版/images/亲子版/第七天/风车公路.jpg\")",
"Bash(find /Users/liutao/Desktop/hulai-website -maxdepth 2 -not -path */node_modules/* -not -path */.nuxt/* -not -path */.output/* -type d)",
"Bash(grep -n \"useJsonLd\\\\|TouristAttraction\\\\|schema\" /Users/liutao/Desktop/hulai-website/pages/destinations/[id].vue)",
"Bash(pandoc \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/5天4晚 /5 天 4 晚草原版与森林版修改.docx\" -o /tmp/5d4n_changes.md)",
"Bash(python3 -c \"import zipfile; z=zipfile.ZipFile\\(''/Users/liutao/Desktop/额吉的故乡V9 修改内容/5天4晚 /5 天 4 晚草原版与森林版修改.docx''\\); import xml.etree.ElementTree as ET; tree=ET.parse\\(z.open\\(''word/document.xml''\\)\\); root=tree.getroot\\(\\); ns={''w'':''http://schemas.openxmlformats.org/wordprocessingml/2006/main''}; [print\\(''''.join\\(t.text or '''' for t in p.findall\\(''.//w:t'',ns\\)\\)\\) for p in root.findall\\(''.//w:p'',ns\\)]\")",
"Bash(find \"/Users/liutao/Desktop/额吉的故乡V9 修改内容\" -type f \\\\\\( -name \"*.jpg\" -o -name \"*.jpeg\" -o -name \"*.png\" \\\\\\) -exec ls -lt {} +)",
"Bash(find /Users/liutao/Downloads /Users/liutao/Desktop -maxdepth 4 -type f \\\\\\(-name *.jpg -o -name *.jpeg -o -name *.png \\\\\\) -newer '/Users/liutao/Desktop/额吉的故乡V9 修改内容/cf01c4cd7b1d74c86715b5a8f88e210c_compress.jpeg')",
"Bash(ls \"/Users/liutao/Desktop/呼籁智库/02_产品资料/旅行产品/额吉的故乡V9/额吉的故乡-6天5晚标准版/\"*.pen)",
"Bash(pandoc \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/统一修改/额吉的故乡V9修改 统一内容.docx\" -o /tmp/unified_changes.md)",
"Bash(find /Users/liutao/Desktop -name *室韦* -o -name *蒙兀*)",
"Bash(ls \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/\"*.jpg \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/\"*.jpeg \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/\"*.png \"/Users/liutao/Desktop/额吉的故乡V9 修改内容/\"*.JPG)",
"Bash(curl -s -o /dev/null -w \"%{http_code}\" \"http://localhost:3000/\")",
"Bash(grep -r \"tldr\\\\|TldrBlock\\\\|PageTldr\\\\|page-tldr\" /Users/liutao/Desktop/hulai-website/components/ --include=*.vue -l)",
"Bash(head -5 grep -r \"tldr\\\\|TldrBlock\\\\|PageTldr\\\\|page-tldr\" /Users/liutao/Desktop/hulai-website/pages/ --include=*.vue -l)",
"Bash(head -20 grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/stories/index.vue)",
"Bash(find /Users/liutao/Desktop/hulai-website -not -path */node_modules/* -not -path */.output/* -not -path */.nuxt/* -type f)",
"Bash(head -20 grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/winter-camp.vue)",
"Bash(grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/products/[id].vue)",
"Bash(head -20 grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/products/autumn.vue)",
"Bash(head -15 grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/products/winter.vue)",
"Bash(grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/blog/[id].vue)",
"Bash(head -20 grep -n \"page-tldr\\\\|page-hero\\\\|<section\\\\|</section>\" /Users/liutao/Desktop/hulai-website/pages/destinations/[id].vue)",
"Bash(head -10 grep -n \"useJsonLd\\\\|useOrganizationSchema\\\\|useBreadcrumb\\\\|useWebPage\\\\|useFAQPage\" /Users/liutao/Desktop/hulai-website/pages/contact.vue)",
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3000/selector)",
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3000/)"
]
}
}

8
.gitignore vendored
查看文件

@ -19,14 +19,6 @@ dist/
*~
.DS_Store
# Database
*.db
*.db-wal
*.db-shm
# Uploads
public/uploads/
# Logs
*.log
npm-debug.log*

202
CLAUDE.md
查看文件

@ -1,202 +0,0 @@
# 呼籁文旅官网 (hulai-website)
## 项目概述
呼籁文旅(呼伦贝尔旅行公司)的官方网站,包含前台展示和后台管理系统。
## 技术栈
| 层级 | 技术 | 版本 |
|------|------|------|
| 框架 | Nuxt 3 | 3.17.5 |
| 前端 | Vue 3 (Composition API + `<script setup>`) | — |
| 服务端 | Nitro (Nuxt 内置) | — |
| 数据库 | SQLite + better-sqlite3 | 12.8.0 |
| ORM | Drizzle ORM | 0.45.1 |
| 样式 | LESS (全局变量 + Mixins) | — |
| 包管理 | pnpm | — |
## 项目结构
```
hulai-website/
├── assets/less/ # 全局 LESS 变量和 Mixins
├── components/
│ ├── admin/ # 后台复用组件
│ │ ├── DataTable.vue # 分页表格搜索、分页、sticky 表头、插槽)
│ │ ├── ImageUpload.vue # 图片上传拖拽、预览、URL 输入)
│ │ └── SeasonProduct.vue # 季节产品编辑器
│ └── ... # 前台组件
├── composables/
│ ├── useAdmin.js # 后台认证token 管理、adminFetch
│ ├── usePublicApi.js # 前台 API
│ └── useSEO.js # SEO 配置
├── layouts/
│ ├── admin.vue # 后台布局(侧栏 + 内容区)
│ └── default.vue # 前台布局
├── middleware/
│ └── admin.js # 后台路由守卫
├── pages/
│ ├── admin/ # 后台页面
│ │ ├── login.vue # 登录页(无 layout
│ │ ├── index.vue # 仪表盘
│ │ ├── articles/ # 新闻管理index.vue 列表 + [id].vue 编辑)
│ │ ├── blogs/ # 博客管理
│ │ ├── reviews/ # 评论管理
│ │ ├── faqs/ # FAQ 管理
│ │ ├── gallery/ # 图库管理
│ │ ├── stories/ # 故事管理
│ │ ├── submissions/ # 表单提交(只读)
│ │ ├── navigation.vue # 导航菜单编辑
│ │ └── content/ # 站点内容编辑
│ │ ├── [key].vue # JSON 编辑器(兜底)
│ │ ├── products/ # 夏季产品index + [idx]
│ │ ├── autumn-products/
│ │ ├── winter-products/
│ │ ├── pricing/ # 价格配置
│ │ ├── selector/ # 产品选择器
│ │ ├── destinations-detail/
│ │ └── *.vue # 各内容可视化编辑器
│ └── ... # 前台页面
├── server/
│ ├── api/admin/ # 后台 REST API
│ ├── database/
│ │ ├── schema.js # Drizzle 表定义
│ │ ├── index.js # DB 连接单例
│ │ ├── migrate.js # 建表
│ │ └── seed.js # 种子数据(从 JSON 导入)
│ └── utils/
│ ├── auth.js # Session 管理SQLite 存储,7 天过期)
│ ├── db.js # useDB() 服务端工具
│ ├── pagination.js # parsePagination() 分页参数解析
│ └── ...
└── public/uploads/ # 上传文件存储
```
## 多角色 Agent 工作流
本项目使用 5 个协作 Agent,通过 `/workflow` 命令调度:
| 角色 | 职责 | 约束 |
|------|------|------|
| **PM** | 分析需求、拆解任务、分配执行、验收结果 | 只分析不写代码 |
| **Frontend** | 前端页面开发Vue 组件、页面、样式) | 只改前端代码 |
| **Backend** | 后端 API、数据库、服务端逻辑 | 只改 server/ 代码 |
| **UI/UX** | 出设计方案、页面结构、交互规格 | 只出方案不写代码 |
| **Tester** | 代码审查、质量检测、出测试报告 | 只测不改 |
### 工作流阶段
```
Phase 1: PM 分析需求 → 拆解任务
Phase 2: UI/UX 设计(如有新页面)
Phase 3: Backend 开发(如有 API 变更)
Phase 4: Frontend 开发
Phase 5: Tester 测试验证
Phase 6: 修复闭环(最多 3 轮)
Phase 7: PM 验收 → 提交代码
```
### 命令
| 命令 | 用途 |
|------|------|
| `/workflow` | 全自动工作流,一条命令走完全流程 |
| `/pm` | 单独启动产品经理分析 |
| `/frontend` | 单独启动前端开发 |
| `/backend` | 单独启动后端开发 |
| `/uiux` | 单独启动 UI/UX 设计 |
| `/tester` | 单独启动测试验证 |
## 编码规范
### 前端页面pages/admin/
**列表 + 编辑分离模式:**
- 列表页:`index.vue`,使用 `AdminDataTable` 组件,带搜索、分页
- 编辑页:`[id].vue`(数据库表)或 `[idx].vue`JSON 数组项)
- 面包屑导航 + 返回链接
- 底部 sticky 保存栏
**页面模板:**
```vue
<script setup>
definePageMeta({ layout: 'admin', middleware: 'admin' })
const { adminFetch } = useAdmin()
</script>
```
**API 调用统一用 `adminFetch`**,自动带 token、401 自动登出。
### 后端 APIserver/api/admin/
**认证中间件:**
```js
const user = await requireAdmin(event)
```
**分页查询:**
```js
const { page, limit, offset, search, sort } = parsePagination(event)
```
**响应格式(列表):**
```js
{ items: [...], total, page, limit, totalPages }
```
**响应格式(单条):**
```js
{ id, ...fields }
```
### 数据库Drizzle ORM
- 表定义在 `server/database/schema.js`
- 使用 `useDB()` 获取数据库实例
- 导入操作符:`import { eq, desc, like } from 'drizzle-orm'`
### 站点内容site_content 表)
存储复杂 JSON 配置的键值对:
- 读取:`GET /api/admin/site-content?key=xxx`
- 更新:`PUT /api/admin/site-content` body: `{ key, data }`
- 单项读取:`GET /api/admin/site-content/item?key=xxx&index=0`
- 单项更新:`PUT /api/admin/site-content/item` body: `{ key, index, item }`
### 样式规范
**后台页面使用 scoped CSS**,主色调:
- 主色:`#3a7d44`(绿色)
- 悬停:`#2d6235`
- 文字:`#111827`
- 次要文字:`#6b7280`
- 边框:`#e5e7eb`
- 背景:`#f0f2f5`
**复用组件:**
- `AdminDataTable` — 带分页搜索的表格
- `AdminImageUpload` — 拖拽上传图片
- `AdminSeasonProduct` — 季节产品编辑器
### 命名约定
| 类型 | 命名 | 示例 |
|------|------|------|
| 页面文件 | kebab-case | `winter-products/` |
| 组件 | PascalCase | `DataTable.vue` |
| API 路由 | kebab-case | `site-content.get.js` |
| 数据库表 | camelCase (Drizzle) | `galleryItems` |
| CSS class | kebab-case | `.page-header` |
## 记忆系统
每个 Agent 有 4 个记忆文件,存储在 `.claude/agents/memory/{role}/` 下:
| 角色 | 文件 | 内容 |
|------|------|------|
| PM | decisions / patterns / lessons / priorities | 决策记录 / 业务模式 / 经验教训 / 优先级策略 |
| Frontend | patterns / pitfalls / components / pages | 代码模式 / 踩坑记录 / 组件清单 / 页面模式 |
| Backend | patterns / pitfalls / api-design / database | 代码模式 / 踩坑记录 / API 设计 / 数据库经验 |
| UI/UX | design-system / page-patterns / feedback / consistency | 设计系统 / 页面模式 / 反馈记录 / 一致性 |
| Tester | common-bugs / checklist / api-issues / quality-metrics | 常见 Bug / 检查清单 / API 问题 / 质量指标 |

查看文件

@ -24,7 +24,7 @@ body {
font-size: @font-size-base;
line-height: @line-height-base;
color: @color-text-primary;
background-color: #FAFAF8;
background-color: @color-bg-white;
}
// ---------- 排版 ----------
@ -121,15 +121,6 @@ img {
color: rgba(255, 255, 255, 0.9);
}
.section--accent {
background-color: @color-accent-bg;
}
.section--dark {
background-color: @color-primary-dark;
color: rgba(255, 255, 255, 0.9);
}
// ---------- 辅助类 ----------
.text-center {
@ -197,15 +188,11 @@ img {
.page-tldr-inner {
max-width: 800px;
margin: 0 auto;
padding: @space-md @space-lg;
padding: @space-lg @space-xl;
border-left: 3px solid @color-primary;
background: @color-bg-white;
border-radius: 0 @border-radius-md @border-radius-md 0;
.respond-md({
padding: @space-lg @space-xl;
});
p {
font-size: @font-size-sm;
color: @color-text-secondary;
@ -216,47 +203,8 @@ img {
// 容器内居中 + 内边距
.container {
padding-top: @space-sm;
padding-bottom: @space-sm;
.respond-md({
padding-top: @space-md;
padding-bottom: @space-md;
});
}
}
// ---------- 全局卡片升级样式 ----------
.card-elevated {
background: @color-bg-white;
border: 1px solid @color-border;
border-radius: @border-radius-lg;
box-shadow: @shadow-card;
transition: box-shadow @transition-base, transform @transition-base, border-color @transition-base;
&:hover {
box-shadow: @shadow-card-hover;
transform: translateY(-4px);
border-color: @color-primary-lighter;
}
}
// 图片容器通用样式
.img-cover {
overflow: hidden;
border-radius: @border-radius-lg @border-radius-lg 0 0;
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform @transition-slow;
}
&:hover img,
.card-elevated:hover & img {
transform: scale(1.05);
padding-top: @space-md;
padding-bottom: @space-md;
}
}

查看文件

@ -36,10 +36,10 @@
});
}
// 段落间距 — 手机端更紧凑,桌面端有呼吸感
// 段落间距 — 更大的呼吸感
.section-padding() {
padding-top: 36px;
padding-bottom: 36px;
padding-top: @space-2xl;
padding-bottom: @space-2xl;
.respond-md({
padding-top: @space-3xl;

查看文件

@ -21,7 +21,6 @@
@color-text-primary: #1A1A2E;
@color-text-secondary: #4A4A5A;
@color-text-muted: #8A8A9A;
@color-text-placeholder: #BBBBC5;
@color-border: #E8E8ED;
@color-divider: #F0F0F4;
@color-bg-white: #FFFFFF;
@ -48,7 +47,6 @@
@font-size-3xl: 36px;
@font-size-hero: 42px;
@font-size-display: 48px;
@font-size-display: 48px;
@line-height-tight: 1.3;
@line-height-normal: 1.5;
@ -92,21 +90,13 @@
@border-radius-xl: 24px;
@border-radius-full: 9999px;
// 精致的阴影层次(升级版:更有深度感)
@shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
@shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
@shadow-card: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06);
@shadow-md: 0 4px 16px rgba(0, 0, 0, 0.10), 0 2px 6px rgba(0, 0, 0, 0.06);
@shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06);
@shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.16), 0 8px 20px rgba(0, 0, 0, 0.08);
@shadow-card-hover: 0 12px 36px rgba(45, 106, 79, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);
// ---------- 渐变 ----------
@gradient-hero: linear-gradient(135deg, #1B4332 0%, #2D6A4F 50%, #40916C 100%);
@gradient-warm: linear-gradient(135deg, #FFFBF5 0%, #FFF8F0 50%, #F0F7F4 100%);
@gradient-cool: linear-gradient(135deg, #F0F7F4 0%, #E8F3ED 50%, #D4E8DC 100%);
@gradient-accent: linear-gradient(135deg, @color-primary 0%, @color-accent 100%);
// 精致的阴影层次
@shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04);
@shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
@shadow-card: 0 2px 8px rgba(0, 0, 0, 0.06);
@shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08);
@shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.10);
@shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.12);
// ---------- 过渡 ----------

查看文件

@ -1,30 +1,25 @@
<template>
<section class="section section--warm">
<section class="section">
<div class="container">
<CommonSectionTitle :title="story.title" align="left" />
<div class="story-layout">
<!-- 左侧配图 -->
<div class="story-content">
<template v-if="story.paragraphs">
<p v-for="(para, i) in story.paragraphs" :key="i" class="story-para">{{ para }}</p>
</template>
<p v-else>{{ story.content }}</p>
</div>
<div class="story-photo">
<div class="story-photo-card">
<img
:src="images.brandStory.photo"
alt="呼籁旅行创始人在呼伦贝尔草原"
alt="一家三口穿蒙古族传统服饰在草原上欢笑"
width="600"
height="800"
height="400"
loading="lazy"
/>
</div>
</div>
<!-- 右侧文字 -->
<div class="story-text">
<h2 class="story-title">{{ story.title }}</h2>
<div class="story-title-line" />
<div class="story-content">
<template v-if="story.paragraphs">
<p v-for="(para, i) in story.paragraphs" :key="i" class="story-para">{{ para }}</p>
</template>
<p v-else>{{ story.content }}</p>
</div>
<p class="story-photo-caption">带孩子回到母亲的故乡</p>
</div>
</div>
</div>
@ -40,21 +35,31 @@ defineProps({ story: { type: Object, required: true } })
.story-layout {
display: grid;
grid-template-columns: 1fr;
gap: @space-2xl;
gap: @space-xl;
align-items: center;
.respond-lg({
grid-template-columns: 5fr 7fr;
.respond-md({
grid-template-columns: 1fr 1fr;
gap: @space-3xl;
align-items: start;
});
}
//
.story-photo {
.respond-lg({
position: sticky;
top: 100px;
});
.story-content {
p {
font-size: @font-size-md;
line-height: @line-height-loose;
color: @color-text-primary;
}
.story-para {
text-indent: 2em;
margin-bottom: @space-md;
&:last-child { margin-bottom: 0; }
}
}
.story-moment {
margin-top: @space-lg;
font-weight: @font-weight-medium;
}
.story-photo-card {
@ -65,55 +70,17 @@ defineProps({ story: { type: Object, required: true } })
img {
width: 100%;
display: block;
aspect-ratio: 3 / 4;
aspect-ratio: 4 / 3;
object-fit: cover;
object-position: center 30%;
.respond-lg({
aspect-ratio: 4 / 5;
});
object-position: center 35%;
}
}
//
.story-text {
padding-top: @space-md;
}
.story-title {
font-size: @font-size-2xl;
font-weight: @font-weight-bold;
color: @color-text-primary;
margin: 0 0 @space-md;
line-height: @line-height-tight;
.respond-md({
font-size: @font-size-3xl;
});
}
.story-title-line {
width: 48px;
height: 3px;
background: @gradient-accent;
border-radius: 3px;
margin-bottom: @space-xl;
}
.story-content {
p {
font-size: @font-size-base;
line-height: 2;
color: @color-text-secondary;
}
.story-para {
text-indent: 2em;
margin-bottom: @space-lg;
&:last-child {
margin-bottom: 0;
}
}
.story-photo-caption {
text-align: center;
margin-top: @space-md;
font-size: @font-size-sm;
color: @color-text-muted;
letter-spacing: 0.5px;
}
</style>

查看文件

@ -22,10 +22,6 @@ defineProps({ culture: { type: Object, required: true } })
text-align: center; font-size: @font-size-xl; font-weight: 600; color: @color-primary;
letter-spacing: 0.1em; margin-bottom: @space-2xl;
}
.culture-core {
text-align: center; font-size: @font-size-xl; font-weight: 600; color: @color-primary;
letter-spacing: 0.1em; margin-bottom: @space-2xl;
}
.values-grid {
display: grid; grid-template-columns: 1fr; gap: @space-lg;
.respond-md({ grid-template-columns: repeat(3, 1fr); });

查看文件

@ -1,298 +0,0 @@
<template>
<div class="data-table-wrapper">
<!-- 工具栏 -->
<div class="toolbar">
<div class="toolbar-left">
<span class="total-info"> <strong>{{ total }}</strong> </span>
<slot name="filter" />
</div>
<div class="toolbar-right">
<div class="search-box" v-if="searchable">
<input
v-model="searchInput"
type="text"
:placeholder="searchPlaceholder || '搜索...'"
@keyup.enter="handleSearch"
/>
<button class="search-btn" @click="handleSearch">搜索</button>
<button v-if="searchInput" class="clear-btn" @click="searchInput=''; handleSearch()">清除</button>
</div>
<slot name="actions" />
</div>
</div>
<!-- 表格 -->
<div class="table-container">
<table>
<thead>
<tr>
<slot name="header" />
</tr>
</thead>
<tbody>
<slot name="body" />
<tr v-if="!loading && total === 0">
<td :colspan="colCount" class="empty-cell">暂无数据</td>
</tr>
</tbody>
</table>
<div v-if="loading" class="table-loading">加载中...</div>
</div>
<!-- 分页 -->
<div class="pagination" v-if="totalPages > 1">
<button class="page-btn" :disabled="page <= 1" @click="changePage(page - 1)">上一页</button>
<template v-for="p in visiblePages" :key="p">
<span v-if="p === '...'" class="page-dots">...</span>
<button v-else class="page-btn" :class="{ active: p === page }" @click="changePage(p)">{{ p }}</button>
</template>
<button class="page-btn" :disabled="page >= totalPages" @click="changePage(page + 1)">下一页</button>
<span class="page-info">{{ page }} / {{ totalPages }} </span>
</div>
</div>
</template>
<script setup>
const props = defineProps({
total: { type: Number, default: 0 },
page: { type: Number, default: 1 },
totalPages: { type: Number, default: 1 },
loading: { type: Boolean, default: false },
searchable: { type: Boolean, default: true },
searchPlaceholder: { type: String, default: '' },
colCount: { type: Number, default: 6 },
})
const emit = defineEmits(['search', 'page-change'])
const searchInput = ref('')
function handleSearch() {
emit('search', searchInput.value)
}
function changePage(p) {
if (p < 1 || p > props.totalPages) return
emit('page-change', p)
}
const visiblePages = computed(() => {
const pages = []
const total = props.totalPages
const current = props.page
if (total <= 7) {
for (let i = 1; i <= total; i++) pages.push(i)
} else {
pages.push(1)
if (current > 3) pages.push('...')
const start = Math.max(2, current - 1)
const end = Math.min(total - 1, current + 1)
for (let i = start; i <= end; i++) pages.push(i)
if (current < total - 2) pages.push('...')
pages.push(total)
}
return pages
})
</script>
<style scoped>
.data-table-wrapper {
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
overflow: hidden;
}
/* 工具栏 */
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 20px;
border-bottom: 1px solid #f0f0f0;
gap: 12px;
flex-wrap: wrap;
}
.toolbar-left {
display: flex;
align-items: center;
gap: 12px;
}
.toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.total-info {
font-size: 13px;
color: #888;
}
.total-info strong {
color: #333;
}
.search-box {
display: flex;
gap: 4px;
}
.search-box input {
padding: 5px 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 13px;
width: 180px;
outline: none;
}
.search-box input:focus {
border-color: #3a7d44;
}
.search-btn {
padding: 5px 12px;
background: #3a7d44;
color: #fff;
border: none;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
}
.search-btn:hover {
background: #2d6235;
}
.clear-btn {
padding: 5px 8px;
background: none;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
color: #999;
}
/* 表格容器 */
.table-container {
overflow-x: auto;
position: relative;
max-height: calc(100vh - 280px);
overflow-y: auto;
}
table {
width: 100%;
border-collapse: collapse;
min-width: 600px;
}
:deep(thead) {
position: sticky;
top: 0;
z-index: 10;
}
:deep(thead tr) {
background: #fafafa;
}
:deep(th) {
padding: 10px 14px;
text-align: left;
font-size: 12px;
font-weight: 600;
color: #666;
border-bottom: 1px solid #e8e8e8;
white-space: nowrap;
background: #fafafa;
}
:deep(td) {
padding: 10px 14px;
font-size: 13px;
color: #333;
border-bottom: 1px solid #f5f5f5;
vertical-align: middle;
}
:deep(tr:hover td) {
background: #fafbfc;
}
:deep(td strong) {
color: #1a1a2e;
}
.empty-cell {
text-align: center;
color: #ccc;
padding: 40px 14px !important;
font-size: 14px;
}
.table-loading {
position: absolute;
inset: 0;
background: rgba(255,255,255,0.8);
display: flex;
align-items: center;
justify-content: center;
color: #888;
font-size: 14px;
}
/* 分页 */
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
padding: 14px 20px;
border-top: 1px solid #f0f0f0;
}
.page-btn {
padding: 5px 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
background: #fff;
font-size: 13px;
cursor: pointer;
color: #333;
min-width: 32px;
text-align: center;
}
.page-btn:hover:not(:disabled):not(.active) {
border-color: #3a7d44;
color: #3a7d44;
}
.page-btn.active {
background: #3a7d44;
color: #fff;
border-color: #3a7d44;
}
.page-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.page-dots {
padding: 0 4px;
color: #ccc;
}
.page-info {
margin-left: 12px;
font-size: 12px;
color: #aaa;
}
</style>

查看文件

@ -1,225 +0,0 @@
<template>
<div class="image-upload">
<div class="upload-preview" v-if="modelValue">
<img :src="modelValue" alt="预览" referrerpolicy="no-referrer" @error="imgError = true" />
<div class="preview-actions">
<button type="button" class="btn-icon" @click="$emit('update:modelValue', '')" title="移除">&#10005;</button>
</div>
</div>
<div
v-else
class="upload-area"
:class="{ dragging }"
@click="triggerUpload"
@dragover.prevent="dragging = true"
@dragleave="dragging = false"
@drop.prevent="handleDrop"
>
<div v-if="uploading" class="upload-loading">上传中...</div>
<div v-else class="upload-placeholder">
<span class="upload-icon">+</span>
<span>点击或拖拽上传图片</span>
<span class="upload-hint">JPG / PNG / WebP最大 10MB</span>
</div>
</div>
<input
ref="fileInput"
type="file"
accept="image/*"
style="display: none"
@change="handleFileChange"
/>
<p v-if="uploadError" class="upload-error">{{ uploadError }}</p>
<!-- 或者直接填写路径 -->
<div class="upload-manual">
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
type="text"
:placeholder="placeholder || '图片URL,可手动输入或上传'"
/>
</div>
</div>
</template>
<script setup>
const props = defineProps({
modelValue: { type: String, default: '' },
placeholder: { type: String, default: '' },
})
const emit = defineEmits(['update:modelValue'])
const { adminFetch } = useAdmin()
const fileInput = ref(null)
const uploading = ref(false)
const uploadError = ref('')
const dragging = ref(false)
const imgError = ref(false)
function triggerUpload() {
fileInput.value?.click()
}
async function handleFileChange(e) {
const file = e.target.files?.[0]
if (file) await uploadFile(file)
e.target.value = ''
}
function handleDrop(e) {
dragging.value = false
const file = e.dataTransfer?.files?.[0]
if (file) uploadFile(file)
}
async function uploadFile(file) {
if (file.size > 10 * 1024 * 1024) {
uploadError.value = '文件过大,最大 10MB'
return
}
uploading.value = true
uploadError.value = ''
try {
const formData = new FormData()
formData.append('file', file)
const token = useState('admin_token')
const result = await $fetch('/api/admin/upload', {
method: 'POST',
body: formData,
headers: { Authorization: `Bearer ${token.value}` },
})
if (result.files?.length) {
emit('update:modelValue', result.files[0].url)
imgError.value = false
}
} catch (e) {
uploadError.value = e.data?.message || '上传失败'
} finally {
uploading.value = false
}
}
</script>
<style scoped>
.image-upload {
margin-bottom: 4px;
}
.upload-preview {
position: relative;
width: 200px;
height: 140px;
border-radius: 6px;
overflow: hidden;
border: 1px solid #eee;
margin-bottom: 8px;
}
.upload-preview img {
width: 100%;
height: 100%;
object-fit: cover;
}
.preview-actions {
position: absolute;
top: 4px;
right: 4px;
}
.btn-icon {
width: 24px;
height: 24px;
border-radius: 50%;
border: none;
background: rgba(0,0,0,0.5);
color: #fff;
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.btn-icon:hover {
background: rgba(231,76,60,0.9);
}
.upload-area {
width: 200px;
height: 140px;
border: 2px dashed #d9d9d9;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
margin-bottom: 8px;
}
.upload-area:hover,
.upload-area.dragging {
border-color: #3a7d44;
background: #f8fdf9;
}
.upload-placeholder {
text-align: center;
color: #999;
}
.upload-icon {
display: block;
font-size: 28px;
color: #ccc;
margin-bottom: 4px;
}
.upload-placeholder span {
display: block;
font-size: 12px;
line-height: 1.6;
}
.upload-hint {
color: #bbb;
font-size: 11px !important;
}
.upload-loading {
color: #3a7d44;
font-size: 13px;
}
.upload-manual input {
width: 100%;
max-width: 400px;
padding: 6px 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 12px;
color: #666;
box-sizing: border-box;
}
.upload-manual input:focus {
border-color: #3a7d44;
outline: none;
}
.upload-error {
color: #e74c3c;
font-size: 12px;
margin: 4px 0 0;
}
</style>

查看文件

@ -1,110 +0,0 @@
<template>
<div>
<div v-if="!loaded" class="loading-card">加载中...</div>
<template v-else>
<!-- 基本信息 -->
<div class="card">
<div class="card-header" @click="open.base=!open.base"><h2>基本信息</h2><i class="arrow" :class="{open:open.base}">&#9656;</i></div>
<div v-show="open.base" class="card-body grid-2">
<div class="field"><label>品牌</label><input v-model="data.brand" /></div>
<div class="field"><label>版本</label><input v-model="data.version" /></div>
<div class="field"><label>季节</label><input v-model="data.season" /></div>
<div class="field"><label>风格</label><input v-model="data.style" /></div>
<div class="field full"><label>叙事</label><textarea v-model="data.narrative" rows="3" class="w-full"></textarea></div>
</div>
</div>
<!-- 亮点 -->
<div class="card">
<div class="card-header" @click="open.hl=!open.hl"><h2>产品亮点 ({{ data.highlights?.length || 0 }})</h2><i class="arrow" :class="{open:open.hl}">&#9656;</i></div>
<div v-show="open.hl" class="card-body">
<div v-for="(h, i) in data.highlights" :key="i" class="inline-row">
<input v-model="h.title" placeholder="标题" style="width:150px" />
<input v-model="h.description" placeholder="描述" style="flex:1" />
<button class="btn btn-xs btn-danger" @click="data.highlights.splice(i,1)"></button>
</div>
<button class="btn btn-xs btn-primary" @click="data.highlights.push({title:'',description:''})">+ 添加亮点</button>
</div>
</div>
<!-- 产品版本 -->
<div v-for="(v, vi) in data.versions" :key="vi" class="card">
<div class="card-header" @click="open['v'+vi]=!open['v'+vi]">
<h2>{{ v.name || '版本 '+(vi+1) }}</h2>
<div class="card-meta">
<span class="tag">{{ v.days }}{{ v.nights }}</span>
<span class="tag">{{ v.line || v.route || '' }}</span>
<i class="arrow" :class="{open:open['v'+vi]}">&#9656;</i>
</div>
</div>
<div v-show="open['v'+vi]" class="card-body">
<div class="grid-2">
<div class="field"><label>ID</label><input v-model="v.id" /></div>
<div class="field"><label>名称</label><input v-model="v.name" /></div>
<div class="field"><label>线路</label><input v-model="v.line" /></div>
<div class="field"><label>路线</label><input v-model="v.route" /></div>
<div class="field"><label>天数</label><input v-model.number="v.days" type="number" /></div>
<div class="field"><label>晚数</label><input v-model.number="v.nights" type="number" /></div>
<div class="field"><label>受众</label><input v-model="v.audience" /></div>
<div class="field"><label>标签</label><input v-model="v.tag" /></div>
</div>
<div class="field"><label>描述</label><textarea v-model="v.description" rows="3" class="w-full"></textarea></div>
<div class="field"><label>亮点每行一个</label>
<textarea :value="(v.highlights||[]).join('\n')" @input="v.highlights=$event.target.value.split('\n').filter(Boolean)" rows="3" class="w-full"></textarea>
</div>
<div class="sub-section"><h3>每日行程</h3>
<div v-for="(day, di) in (v.itinerary||[])" :key="di" class="day-card">
<div class="day-num">D{{ day.day || di+1 }}</div>
<div class="day-fields">
<input v-model="day.title" placeholder="当日标题" />
<textarea v-model="day.summary" rows="2" placeholder="行程概要"></textarea>
</div>
</div>
</div>
</div>
</div>
</template>
</div>
</template>
<script setup>
const props = defineProps({ data: Object, loaded: Boolean })
const open = reactive({ base: false })
</script>
<style scoped>
.loading-card { background: #fff; border-radius: 8px; padding: 60px; text-align: center; color: #999; }
.card { background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); margin-bottom: 12px; overflow: hidden; }
.card-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 20px; cursor: pointer; user-select: none; background: #fafafa; border-bottom: 1px solid #f0f0f0; }
.card-header:hover { background: #f5f5f5; }
.card-header h2 { margin: 0; font-size: 15px; color: #333; }
.card-meta { display: flex; align-items: center; gap: 8px; }
.card-body { padding: 16px 20px; }
.arrow { font-style: normal; font-size: 12px; transition: transform 0.2s; color: #999; }
.arrow.open { transform: rotate(90deg); }
.tag { font-size: 11px; background: #e6f7e9; color: #3a7d44; padding: 2px 8px; border-radius: 4px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; }
.full { grid-column: span 2; }
.field { margin-bottom: 10px; }
.field label { display: block; font-size: 12px; color: #888; margin-bottom: 3px; }
.field input, .field textarea { width: 100%; padding: 6px 8px; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; box-sizing: border-box; }
.field input:focus, .field textarea:focus { border-color: #3a7d44; outline: none; }
.field textarea { resize: vertical; }
.w-full { width: 100%; box-sizing: border-box; }
.inline-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.inline-row input { padding: 6px 8px; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; }
.inline-row input:focus { border-color: #3a7d44; outline: none; }
.sub-section { margin-top: 14px; border-top: 1px solid #f0f0f0; padding-top: 10px; }
.sub-section h3 { margin: 0 0 10px; font-size: 14px; color: #555; }
.day-card { display: flex; gap: 12px; margin-bottom: 8px; padding: 10px; background: #fafbfc; border-radius: 6px; }
.day-num { width: 36px; height: 36px; background: #3a7d44; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; flex-shrink: 0; }
.day-fields { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.day-fields input, .day-fields textarea { padding: 6px 8px; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; width: 100%; box-sizing: border-box; }
.day-fields input:focus, .day-fields textarea:focus { border-color: #3a7d44; outline: none; }
.day-fields textarea { resize: vertical; }
.btn { padding: 6px 14px; border: 1px solid #d9d9d9; border-radius: 4px; cursor: pointer; font-size: 13px; background: #fff; }
.btn-primary { background: #3a7d44; color: #fff; border-color: #3a7d44; }
.btn-xs { padding: 3px 8px; font-size: 11px; }
.btn-danger { color: #e74c3c; border-color: #e74c3c; }
.btn-danger:hover { background: #e74c3c; color: #fff; }
</style>

查看文件

@ -44,7 +44,7 @@
<script setup>
const props = defineProps({ product: { type: Object, required: true } })
const isPopular = computed(() => props.product.id === 'autumn-south-5d4n')
const isPopular = computed(() => props.product.id === 'autumn-south-7d6n')
const shortName = computed(() => {
return props.product.name.replace(/^游牧的森林V3·/, '')

查看文件

@ -39,22 +39,21 @@ defineProps({
font-weight: @font-weight-bold;
color: @color-primary;
text-transform: uppercase;
letter-spacing: 3px;
letter-spacing: 2px;
margin-bottom: @space-sm;
opacity: 0.7;
}
.section-title-text {
color: @color-text-primary;
// 线
// 线
&::after {
content: '';
display: block;
width: 64px;
width: 48px;
height: 3px;
background: @gradient-accent;
border-radius: 3px;
background: linear-gradient(90deg, @color-primary, @color-primary-light);
border-radius: 2px;
margin-top: @space-md;
}
@ -71,6 +70,5 @@ defineProps({
font-size: @font-size-md;
color: @color-text-muted;
line-height: @line-height-relaxed;
letter-spacing: 0.3px;
}
</style>

查看文件

@ -1,97 +1,56 @@
<template>
<section v-if="data" class="section">
<section class="section">
<div class="container">
<CommonSectionTitle :title="data.title" :subtitle="data.subtitle" />
<p class="compare-intro">{{ data.intro }}</p>
<!-- 桌面端紧凑对比表格 -->
<div class="compare-table-desktop">
<div class="compare-grid">
<!-- 表头 -->
<div class="grid-header">
<div class="grid-label-col"></div>
<div
v-for="dest in data.destinations"
:key="dest.id"
class="grid-dest-col"
:class="{ 'grid-dest-col--highlight': dest.highlight }"
>
<span v-if="dest.highlight" class="recommend-badge">推荐</span>
<h3 class="dest-name">{{ dest.name }}</h3>
<span class="dest-tag">{{ dest.tag }}</span>
</div>
</div>
<!-- 数据行 -->
<div v-for="dim in data.dimensions" :key="dim.label" class="grid-row">
<div class="grid-label-col">
<span class="dim-icon">{{ dim.icon }}</span>
<span class="dim-label">{{ dim.label }}</span>
</div>
<div
v-for="(val, i) in dim.values"
:key="i"
class="grid-value-col"
:class="{ 'grid-value-col--highlight': data.destinations[i]?.highlight }"
>
{{ val }}
</div>
<!-- 对比表格 -->
<div class="compare-table">
<!-- 表头三个目的地 -->
<div class="compare-header">
<div class="compare-label-col"></div>
<div
v-for="dest in data.destinations"
:key="dest.id"
class="compare-dest-col"
:class="{ 'compare-dest-col--highlight': dest.highlight }"
>
<h3 class="dest-name">{{ dest.name }}</h3>
<span class="dest-tag">{{ dest.tag }}</span>
</div>
</div>
<!-- 坦诚说明 - 桌面端紧贴表格底部 -->
<div class="honest-strip">
<div class="honest-strip-header">
<span class="honest-icon">💬</span>
<span class="honest-label">{{ data.honestNote.title }}</span>
<span class="honest-dash"></span>
<span class="honest-sub">{{ data.honestNote.subtitle }}</span>
<!-- 对比行 -->
<div v-for="dim in data.dimensions" :key="dim.label" class="compare-row">
<div class="compare-label-col">
<span class="dim-icon">{{ dim.icon }}</span>
<span class="dim-label">{{ dim.label }}</span>
</div>
<div class="honest-strip-items">
<span v-for="(item, i) in data.honestNote.items" :key="i" class="honest-item">
{{ item }}
</span>
<div
v-for="(val, i) in dim.values"
:key="i"
class="compare-value-col"
:class="{ 'compare-value-col--highlight': data.destinations[i]?.highlight }"
>
<span class="dim-label-mobile">{{ dim.icon }} {{ dim.label }}</span>
{{ val }}
</div>
</div>
</div>
<!-- 移动端Tab切换卡片 -->
<div class="compare-mobile">
<div class="tab-bar">
<button
v-for="(dest, i) in data.destinations"
:key="dest.id"
class="tab-btn"
:class="{ 'tab-btn--active': activeTab === i, 'tab-btn--highlight': dest.highlight }"
@click="activeTab = i"
>
<span v-if="dest.highlight && activeTab !== i" class="tab-dot"></span>
{{ dest.name }}
</button>
</div>
<!-- 坦诚说明 -->
<div class="honest-block">
<h3 class="honest-title">{{ data.honestNote.title }}</h3>
<p class="honest-subtitle">{{ data.honestNote.subtitle }}</p>
<ul class="honest-list">
<li v-for="(item, i) in data.honestNote.items" :key="i">{{ item }}</li>
</ul>
</div>
<div class="dest-card">
<p class="dest-card-tag">{{ data.destinations[activeTab].tag }}</p>
<div class="dest-card-grid">
<div v-for="dim in data.dimensions" :key="dim.label" class="dest-card-item">
<div class="dest-card-dim">
<span class="dest-card-icon">{{ dim.icon }}</span>
<span class="dest-card-label">{{ dim.label }}</span>
</div>
<p class="dest-card-value">{{ dim.values[activeTab] }}</p>
</div>
</div>
</div>
<!-- 坦诚说明 - 移动端 -->
<div v-if="data.destinations[activeTab]?.highlight" class="honest-mobile">
<p class="honest-mobile-title">
<span class="honest-icon-sm">💬</span>
{{ data.honestNote.title }}
</p>
<ul class="honest-mobile-list">
<li v-for="(item, i) in data.honestNote.items" :key="i">{{ item }}</li>
</ul>
</div>
<!-- 结语 -->
<div class="closing-block">
<h3 class="closing-title">{{ data.closing.title }}</h3>
<p class="closing-text">{{ data.closing.text }}</p>
</div>
<!-- 数据来源 -->
@ -101,82 +60,76 @@
</template>
<script setup>
import { ref } from 'vue'
const { data } = await usePublicApi('destinations')
const activeTab = ref(0)
import data from '~/data/destinations.json'
</script>
<style lang="less" scoped>
.compare-intro {
max-width: 720px;
margin: 0 auto @space-lg;
font-size: @font-size-sm;
max-width: 800px;
margin: 0 auto @space-xl;
font-size: @font-size-base;
color: @color-text-secondary;
line-height: @line-height-base;
line-height: @line-height-loose;
text-align: center;
}
// ========== ==========
.compare-table-desktop {
//
.compare-table {
margin-bottom: @space-2xl;
border: 1px solid @color-border;
border-radius: @border-radius-lg;
overflow: hidden;
}
.compare-header {
display: none;
.respond-md({
display: block;
border-radius: @border-radius-lg;
overflow: hidden;
box-shadow: @shadow-card;
margin-bottom: @space-xl;
display: grid;
grid-template-columns: 120px repeat(3, 1fr);
background: @color-bg-gray;
border-bottom: 1px solid @color-border;
});
}
.compare-grid {
background: @color-bg-white;
}
.grid-header {
display: grid;
grid-template-columns: 100px repeat(3, 1fr);
background: @color-primary-bg;
}
.grid-label-col {
padding: @space-md @space-md;
.compare-label-col {
padding: @space-md @space-lg;
display: flex;
align-items: center;
gap: 6px;
font-size: @font-size-xs;
color: @color-text-muted;
gap: @space-sm;
font-weight: @font-weight-medium;
color: @color-text-muted;
font-size: @font-size-sm;
}
.grid-dest-col {
padding: @space-lg @space-md;
.compare-dest-col {
padding: @space-lg;
text-align: center;
position: relative;
&--highlight {
background: fadeout(@color-primary, 92%);
background: @color-primary-bg;
position: relative;
&::after {
content: '推荐';
position: absolute;
top: @space-xs;
right: @space-sm;
padding: 2px @space-sm;
font-size: 11px;
font-weight: @font-weight-bold;
color: #fff;
background: @color-primary;
border-radius: @border-radius-sm;
}
}
}
.recommend-badge {
display: inline-block;
padding: 2px 10px;
font-size: 11px;
font-weight: @font-weight-bold;
color: #fff;
background: @color-primary;
border-radius: @border-radius-full;
margin-bottom: 6px;
}
.dest-name {
font-size: @font-size-md;
font-size: @font-size-lg;
font-weight: @font-weight-bold;
color: @color-text-primary;
margin-bottom: 2px;
margin-bottom: @space-xs;
}
.dest-tag {
@ -184,260 +137,148 @@ const activeTab = ref(0)
color: @color-text-muted;
}
//
.grid-row {
display: grid;
grid-template-columns: 100px repeat(3, 1fr);
border-top: 1px solid @color-divider;
//
.compare-row {
display: flex;
flex-direction: column;
border-bottom: 1px solid @color-border;
&:nth-child(even) {
background: @color-bg-gray;
&:last-child {
border-bottom: none;
}
.respond-md({
display: grid;
grid-template-columns: 120px repeat(3, 1fr);
flex-direction: row;
});
}
.dim-icon {
font-size: 14px;
}
.dim-label {
font-size: @font-size-xs;
white-space: nowrap;
}
.grid-value-col {
padding: 12px @space-md;
font-size: 13px;
.compare-value-col {
padding: @space-md @space-lg;
font-size: @font-size-sm;
color: @color-text-secondary;
line-height: @line-height-normal;
border-left: 1px solid @color-divider;
line-height: @line-height-base;
border-bottom: 1px solid fadeout(@color-border, 50%);
.respond-md({
border-bottom: none;
border-left: 1px solid fadeout(@color-border, 50%);
});
&:last-child {
border-bottom: none;
}
&--highlight {
background: fadeout(@color-primary-bg, 30%);
color: @color-text-primary;
font-weight: @font-weight-medium;
}
}
// ========== - ==========
.honest-strip {
background: @color-bg-warm;
padding: @space-md @space-lg;
border-top: 1px solid fadeout(@color-accent, 80%);
}
.honest-strip-header {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: @space-sm;
font-size: @font-size-sm;
}
.honest-icon {
font-size: 16px;
}
.honest-label {
font-weight: @font-weight-bold;
color: @color-accent;
}
.honest-dash {
color: @color-text-muted;
}
.honest-sub {
color: @color-text-muted;
font-size: @font-size-xs;
}
.honest-strip-items {
display: flex;
flex-wrap: wrap;
gap: 6px @space-md;
}
.honest-item {
font-size: @font-size-xs;
color: @color-text-secondary;
line-height: @line-height-normal;
position: relative;
padding-left: 12px;
&::before {
content: '·';
position: absolute;
left: 0;
color: @color-accent;
font-weight: bold;
font-size: 16px;
line-height: 1;
top: 1px;
}
}
// ========== Tab + ==========
.compare-mobile {
//
.dim-label-mobile {
display: block;
font-size: @font-size-xs;
font-weight: @font-weight-bold;
color: @color-text-muted;
margin-bottom: @space-xs;
.respond-md({
display: none;
});
}
.tab-bar {
display: flex;
gap: 0;
background: @color-bg-gray;
border-radius: @border-radius-md;
padding: 3px;
margin-bottom: @space-md;
.dim-icon {
font-size: @font-size-base;
}
.tab-btn {
flex: 1;
padding: 10px 4px;
border: none;
background: none;
.dim-label {
font-size: @font-size-sm;
font-weight: @font-weight-medium;
color: @color-text-muted;
border-radius: 6px;
cursor: pointer;
transition: all @transition-fast;
position: relative;
&--active {
background: @color-bg-white;
color: @color-text-primary;
font-weight: @font-weight-bold;
box-shadow: @shadow-xs;
}
&--highlight:not(.tab-btn--active) {
color: @color-primary;
}
}
.tab-dot {
display: inline-block;
width: 6px;
height: 6px;
background: @color-primary;
border-radius: 50%;
margin-right: 4px;
vertical-align: middle;
//
.compare-label-col {
display: none;
.respond-md({
display: flex;
});
}
.dest-card {
background: @color-bg-white;
//
.honest-block {
max-width: 800px;
margin: 0 auto @space-xl;
padding: @space-xl;
background: #FFF7ED;
border-radius: @border-radius-lg;
box-shadow: @shadow-card;
padding: @space-md;
margin-bottom: @space-md;
border-left: 4px solid #F59E0B;
}
.dest-card-tag {
text-align: center;
font-size: @font-size-xs;
color: @color-text-muted;
margin-bottom: @space-md;
padding-bottom: @space-sm;
border-bottom: 1px solid @color-divider;
}
.dest-card-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1px;
background: @color-divider;
border-radius: @border-radius-md;
overflow: hidden;
}
.dest-card-item {
padding: 12px;
background: @color-bg-white;
//
&:last-child:nth-child(odd) {
grid-column: 1 / -1;
}
}
.dest-card-dim {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: 4px;
}
.dest-card-icon {
font-size: 13px;
}
.dest-card-label {
font-size: 11px;
.honest-title {
font-size: @font-size-lg;
font-weight: @font-weight-bold;
color: @color-text-muted;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #B45309;
margin-bottom: @space-xs;
}
.dest-card-value {
font-size: 13px;
color: @color-text-primary;
line-height: @line-height-normal;
}
// ========== - ==========
.honest-mobile {
background: @color-bg-warm;
border-radius: @border-radius-md;
padding: @space-md;
margin-bottom: @space-md;
}
.honest-mobile-title {
.honest-subtitle {
font-size: @font-size-sm;
font-weight: @font-weight-bold;
color: @color-accent;
margin-bottom: @space-sm;
color: @color-text-muted;
margin-bottom: @space-md;
}
.honest-icon-sm {
font-size: 14px;
margin-right: 4px;
}
.honest-mobile-list {
.honest-list {
display: flex;
flex-direction: column;
gap: 6px;
gap: @space-sm;
li {
font-size: @font-size-xs;
font-size: @font-size-sm;
color: @color-text-secondary;
line-height: @line-height-normal;
padding-left: 14px;
line-height: @line-height-base;
padding-left: @space-md;
position: relative;
&::before {
content: '·';
content: '•';
position: absolute;
left: 0;
color: @color-accent;
color: #F59E0B;
font-weight: bold;
font-size: 16px;
top: -1px;
}
}
}
// ========== ==========
//
.closing-block {
max-width: 800px;
margin: 0 auto @space-xl;
padding: @space-xl;
background: @color-primary-bg;
border-radius: @border-radius-lg;
border-left: 4px solid @color-primary;
}
.closing-title {
font-size: @font-size-lg;
font-weight: @font-weight-bold;
color: @color-primary;
margin-bottom: @space-md;
}
.closing-text {
font-size: @font-size-base;
color: @color-text-secondary;
line-height: @line-height-loose;
}
//
.data-source {
text-align: center;
font-size: @font-size-xs;
color: @color-text-placeholder;
margin-top: @space-sm;
color: @color-text-muted;
}
</style>

查看文件

@ -3,10 +3,16 @@
<div class="container">
<CommonSectionTitle title="为什么选择呼籁" label="WHY HULAI" subtitle="不只是包车,是一套成熟的旅行服务体系" />
<div class="diff-grid">
<div v-for="(item, index) in itemsWithBg" :key="item.title" class="diff-item">
<div class="diff-bg">
<img :src="item.bgImage" :alt="item.title" loading="lazy" />
</div>
<div
v-for="(item, index) in items"
:key="item.title"
class="diff-item"
>
<div
v-if="item.image"
class="diff-bg"
:style="{ backgroundImage: `url(${item.image})` }"
/>
<div class="diff-content">
<div class="diff-icon" v-html="icons[index % icons.length]" />
<h3 class="diff-title">{{ item.title }}</h3>
@ -19,32 +25,23 @@
</template>
<script setup>
const props = defineProps({
defineProps({
items: { type: Array, required: true },
})
const bgImages = [
'/images/seasons/summer-hero.jpg',
'/images/seasons/summer-car.jpg',
'/images/seasons/summer-river.jpg',
'/images/seasons/autumn-forest.jpg',
'/images/seasons/autumn-lake.jpg',
'/images/seasons/winter-hero.jpg',
]
const itemsWithBg = computed(() =>
props.items.map((item, i) => ({
...item,
bgImage: bgImages[i % bgImages.length],
}))
)
// SVG icons for each differentiator
const icons = [
//
'<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21l9-18 9 18"/><path d="M12 3v18"/><path d="M3 21h18"/></svg>',
//
'<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="3" width="15" height="13" rx="2"/><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"/><circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/></svg>',
//
'<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>',
//
'<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>',
//
'<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>',
//
'<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>',
]
</script>
@ -67,53 +64,42 @@ const icons = [
.diff-item {
position: relative;
border-radius: @border-radius-lg;
overflow: hidden;
border: 1px solid @color-border;
overflow: hidden;
background: @color-bg-white;
transition: box-shadow 0.35s cubic-bezier(0.23, 1, 0.32, 1), transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
&:hover {
box-shadow: @shadow-lg;
box-shadow: @shadow-md;
transform: translateY(-3px);
.diff-bg img {
transform: scale(1.05);
}
.diff-icon {
color: @color-primary;
background: rgba(255, 255, 255, 0.95);
background: @color-primary-bg;
}
.diff-bg {
opacity: 0.45;
transform: scale(1.05);
}
}
}
//
.diff-bg {
position: absolute;
inset: 0;
z-index: 0;
img {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.15;
filter: saturate(0.6);
transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1), opacity 0.4s ease;
}
//
&::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.7) 0%, rgba(255,255,255,0.4) 100%);
}
background-size: cover;
background-position: center;
opacity: 0.35;
filter: saturate(0.5) brightness(1.1);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.diff-content {
position: relative;
z-index: 1;
padding: @space-xl @space-lg;
background: linear-gradient(150deg, rgba(255, 255, 255, 0.97) 30%, rgba(255, 255, 255, 0.85) 60%, rgba(255, 255, 255, 0.65) 100%);
}
.diff-icon {
@ -123,7 +109,7 @@ const icons = [
width: 56px;
height: 56px;
border-radius: @border-radius-lg;
background: rgba(240, 247, 244, 0.9);
background: @color-bg-gray;
color: @color-primary-light;
margin-bottom: @space-lg;
transition: color @transition-base, background @transition-base;

查看文件

@ -1,5 +1,5 @@
<template>
<section v-if="brand && images" class="hero">
<section class="hero">
<div class="hero-bg">
<img
:src="images.hero.background"
@ -35,17 +35,17 @@
</template>
<script setup>
import brand from '~/data/brand.json'
import images from '~/data/images.json'
defineProps({
seo: { type: Object, required: true },
})
const { data: brand } = await usePublicApi('brand')
const { data: images } = await usePublicApi('images')
// preload Hero
useHead({
link: [
{ rel: 'preload', href: images.value?.hero?.background, as: 'image' },
{ rel: 'preload', href: images.hero.background, as: 'image' },
],
})
</script>

查看文件

@ -1,23 +1,13 @@
<template>
<section class="section">
<div class="container">
<CommonSectionTitle title="旅行产品" subtitle="四季不同风景,总有一条线路适合你的家庭" />
<CommonSectionTitle title="旅行产品" label="PRODUCTS" subtitle="四季不同风景,总有一条线路适合你的家庭" />
<div class="product-grid">
<NuxtLink
v-for="line in productLines"
:key="line.id"
:to="line.to"
class="product-line-card"
:class="`product-line-card--${line.theme}`"
>
<!-- 封面图 -->
<div class="line-cover">
<img :src="line.image" :alt="line.name" loading="lazy" />
<div class="line-cover-overlay" />
<span class="line-season-badge">{{ line.season }}</span>
<NuxtLink v-for="line in productLines" :key="line.id" :to="line.to" class="product-line-card">
<div class="line-img-wrap">
<img :src="line.image" :alt="line.name + ' ' + line.season + '旅行'" class="line-img" loading="lazy" width="400" height="240" />
<span class="line-season-tag" :class="`line-season-tag--${line.theme}`">{{ line.season }}</span>
</div>
<!-- 内容区 -->
<div class="line-body">
<div class="line-meta">
<span class="line-duration">{{ line.duration }}</span>
@ -27,7 +17,10 @@
<ul class="line-highlights">
<li v-for="(h, i) in line.highlights" :key="i">{{ h }}</li>
</ul>
<span class="line-cta">了解详情 </span>
<span class="line-cta" :class="`line-cta--${line.theme}`">
了解详情
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 3l5 5-5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
</div>
</NuxtLink>
</div>
@ -55,7 +48,7 @@ const productLines = [
theme: 'autumn',
duration: '4-7天 · V3系列',
to: '/products/autumn',
image: '/images/seasons/autumn-hero.jpg',
image: '/images/seasons/autumn-forest.jpg',
description: '金秋草原+阿尔山/大兴安岭,南北两线专属私家团',
highlights: ['大兴安岭金秋林海', '阿尔山火山天池', '扎罗木得断崖秘境'],
},
@ -71,27 +64,16 @@ const productLines = [
highlights: ['冰雪那达慕体验', '雪地狼群投喂', '大雪原日出日落'],
},
{
id: 'summer-camp',
name: '小蒙马夏令营',
season: '夏',
id: 'camp',
name: '小蒙马亲子营',
season: '夏+冬',
theme: 'camp',
duration: '7天6晚',
duration: '夏6天 / 冬7天',
to: '/summer-camp',
image: '/images/seasons/summer-river.jpg',
image: '/images/summer-camp/grassland-group.jpg',
description: '亲子营模式,每期8组家庭结伴同行,孩子有伙伴大人能放松',
highlights: ['专业研学领队带队', '随团摄影师全程跟拍', '草原写生+非遗研学'],
},
{
id: 'winter-camp',
name: '小蒙马冬令营',
season: '冬季',
theme: 'winter-camp',
duration: '7天6晚',
to: '/winter-camp',
image: '/images/seasons/winter-frost.jpg',
description: '冰雪研学营,雪地徒步+冰上运动+驯鹿部落,零下30°的成长体验',
highlights: ['冰雪那达慕体验', '驯鹿部落探访', '冬季星空观测'],
},
]
</script>
@ -106,8 +88,7 @@ const productLines = [
});
.respond-lg({
grid-template-columns: repeat(3, 1fr);
gap: @space-xl;
grid-template-columns: repeat(4, 1fr);
});
}
@ -119,85 +100,51 @@ const productLines = [
overflow: hidden;
text-decoration: none;
box-shadow: @shadow-card;
transition: box-shadow @transition-base, transform @transition-base;
transition: box-shadow 0.35s cubic-bezier(0.23, 1, 0.32, 1), transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
&:hover {
box-shadow: @shadow-card-hover;
box-shadow: @shadow-lg;
transform: translateY(-6px);
.line-cover img {
transform: scale(1.08);
}
.line-cta {
color: @color-primary-light;
.line-img {
transform: scale(1.05);
}
}
}
//
.line-cover {
.line-img-wrap {
position: relative;
aspect-ratio: 16 / 10;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}
aspect-ratio: 5 / 3;
}
.line-cover-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to bottom, transparent 40%, rgba(0, 0, 0, 0.3) 100%);
.line-img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
}
.line-season-badge {
.line-season-tag {
position: absolute;
top: @space-md;
left: @space-md;
padding: @space-xs @space-md;
padding: @space-xs @space-sm;
font-size: @font-size-xs;
font-weight: @font-weight-bold;
border-radius: @border-radius-full;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border-radius: @border-radius-sm;
backdrop-filter: blur(4px);
&--summer { color: #fff; background: rgba(45, 106, 79, 0.85); }
&--autumn { color: #fff; background: rgba(217, 119, 6, 0.85); }
&--winter { color: #fff; background: rgba(59, 130, 246, 0.85); }
&--camp { color: #fff; background: rgba(139, 92, 246, 0.85); }
}
//
.product-line-card--summer .line-season-badge {
background: rgba(45, 106, 79, 0.85);
color: #fff;
}
.product-line-card--autumn .line-season-badge {
background: rgba(217, 119, 6, 0.85);
color: #fff;
}
.product-line-card--winter .line-season-badge {
background: rgba(59, 130, 246, 0.85);
color: #fff;
}
.product-line-card--camp .line-season-badge {
background: rgba(139, 92, 246, 0.85);
color: #fff;
}
.product-line-card--winter-camp .line-season-badge {
background: rgba(99, 102, 241, 0.85);
color: #fff;
}
//
.line-body {
padding: @space-lg @space-xl @space-xl;
display: flex;
flex-direction: column;
padding: @space-lg;
flex: 1;
}
@ -208,7 +155,6 @@ const productLines = [
.line-duration {
font-size: @font-size-xs;
color: @color-text-muted;
letter-spacing: 0.5px;
}
.line-name {
@ -216,7 +162,6 @@ const productLines = [
font-weight: @font-weight-bold;
color: @color-text-primary;
margin-bottom: @space-sm;
line-height: @line-height-tight;
}
.line-desc {
@ -240,21 +185,34 @@ const productLines = [
position: relative;
&::before {
content: '';
content: '';
position: absolute;
left: 0;
font-weight: @font-weight-bold;
color: @color-primary;
font-size: @font-size-xs;
left: 2px;
top: 8px;
width: 5px;
height: 5px;
border-radius: 50%;
background: @color-primary-lighter;
}
}
}
.line-cta {
display: inline-flex;
align-items: center;
gap: @space-xs;
font-size: @font-size-sm;
font-weight: @font-weight-medium;
color: @color-primary;
margin-top: auto;
transition: color @transition-fast;
transition: gap @transition-fast;
.product-line-card:hover & {
gap: @space-sm;
}
&--summer { color: @color-primary; }
&--autumn { color: #D97706; }
&--winter { color: #3B82F6; }
&--camp { color: #8B5CF6; }
}
</style>

查看文件

@ -1,17 +1,17 @@
<template>
<footer class="app-footer">
<div class="footer-container">
<div v-if="brand && images" class="footer-grid">
<div class="footer-grid">
<!-- 品牌信息 -->
<div class="footer-brand">
<div class="footer-logo">
<img v-if="images?.logo?.main" :src="images.logo.main" alt="呼籁旅行" class="footer-logo-img" width="44" height="44" />
<img :src="images.logo.main" alt="呼籁旅行" class="footer-logo-img" width="44" height="44" />
<div class="footer-logo-text">
<span class="logo-text">呼籁旅行</span>
<span class="logo-sub">HULAI TRAVEL</span>
</div>
</div>
<p class="footer-desc">{{ brand?.slogan?.functional }}</p>
<p class="footer-desc">{{ brand.slogan.functional }}</p>
<div class="footer-qr-list">
<CommonQRCodeBlock
v-for="ch in qrChannels"
@ -38,12 +38,12 @@
<div class="footer-bottom">
<p class="footer-company">旅行服务内蒙古呼籁国际旅行社有限公司</p>
<p class="footer-legal">
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener" class="footer-icp-link">{{ brand?.icp }}</a>
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener" class="footer-icp-link">{{ brand.icp }}</a>
<span class="footer-divider">|</span>
{{ brand?.icpEntity }}
{{ brand.icpEntity }}
</p>
<p class="footer-copyright">
© {{ new Date().getFullYear() }} {{ brand?.fullName }} 版权所有
© {{ new Date().getFullYear() }} {{ brand.fullName }} 版权所有
</p>
</div>
</div>
@ -51,13 +51,13 @@
</template>
<script setup>
const { data: brand } = await usePublicApi('brand')
const { data: images } = await usePublicApi('images')
const { data: navData } = await usePublicApi('navigation')
const { data: contact } = await usePublicApi('contact')
import brand from '~/data/brand.json'
import images from '~/data/images.json'
import navData from '~/data/navigation.json'
import contact from '~/data/contact.json'
const footerNav = computed(() => navData.value?.footer || [])
const qrChannels = computed(() => (contact.value?.channels || []).filter(c => c.qrImage && !c.hidden))
const footerNav = navData.footer
const qrChannels = contact.channels.filter(c => c.qrImage && !c.hidden)
</script>
<style lang="less" scoped>

查看文件

@ -2,7 +2,7 @@
<header class="app-header">
<div class="header-container">
<NuxtLink to="/" class="header-logo" aria-label="呼籁旅行首页">
<img v-if="images?.logo?.main" :src="images.logo.main" alt="呼籁旅行" class="logo-img" width="40" height="40" />
<img :src="images.logo.main" alt="呼籁旅行" class="logo-img" width="40" height="40" />
<div class="logo-text-group">
<span class="logo-text">呼籁旅行</span>
<span class="logo-sub">HULAI TRAVEL</span>
@ -53,11 +53,10 @@
<script setup>
import { ref } from 'vue'
import navData from '~/data/navigation.json'
import images from '~/data/images.json'
const { data: navData } = await usePublicApi('navigation')
const { data: images } = await usePublicApi('images')
const navItems = computed(() => navData.value?.header || [])
const navItems = navData.header
const mobileOpen = ref(false)
const openDropdown = ref(null)
const route = useRoute()
@ -250,249 +249,6 @@ watch(() => route.path, () => {
margin-left: @space-sm;
}
//
.has-dropdown {
position: relative;
}
.nav-arrow {
font-size: 10px;
margin-left: 2px;
opacity: 0.5;
transition: transform @transition-fast;
.has-dropdown:hover & {
transform: rotate(180deg);
}
}
.nav-dropdown {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
min-width: 180px;
background: @color-bg-white;
border-radius: @border-radius-md;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
padding: @space-sm 0;
opacity: 0;
visibility: hidden;
transition: opacity @transition-fast, visibility @transition-fast;
z-index: 10;
//
&::before {
content: '';
position: absolute;
top: -8px;
left: 0;
right: 0;
height: 8px;
}
&.show {
opacity: 1;
visibility: visible;
}
}
.dropdown-item {
list-style: none;
}
.dropdown-link {
display: flex;
align-items: center;
justify-content: space-between;
padding: @space-sm @space-lg;
text-decoration: none;
color: @color-text-secondary;
font-size: @font-size-sm;
white-space: nowrap;
transition: background @transition-fast, color @transition-fast;
&:hover {
background: @color-primary-bg;
color: @color-primary;
}
}
.dropdown-text {
flex: 1;
}
.dropdown-season {
font-size: @font-size-xs;
color: @color-text-muted;
background: @color-bg-gray;
padding: 2px 6px;
border-radius: @border-radius-sm;
margin-left: @space-sm;
}
//
.has-dropdown {
position: relative;
}
.nav-arrow {
font-size: 10px;
margin-left: 2px;
opacity: 0.5;
transition: transform @transition-fast;
.has-dropdown:hover & {
transform: rotate(180deg);
}
}
.nav-dropdown {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
min-width: 180px;
background: @color-bg-white;
border-radius: @border-radius-md;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
padding: @space-sm 0;
opacity: 0;
visibility: hidden;
transition: opacity @transition-fast, visibility @transition-fast;
z-index: 10;
//
&::before {
content: '';
position: absolute;
top: -8px;
left: 0;
right: 0;
height: 8px;
}
&.show {
opacity: 1;
visibility: visible;
}
}
.dropdown-item {
list-style: none;
}
.dropdown-link {
display: flex;
align-items: center;
justify-content: space-between;
padding: @space-sm @space-lg;
text-decoration: none;
color: @color-text-secondary;
font-size: @font-size-sm;
white-space: nowrap;
transition: background @transition-fast, color @transition-fast;
&:hover {
background: @color-primary-bg;
color: @color-primary;
}
}
.dropdown-text {
flex: 1;
}
.dropdown-season {
font-size: @font-size-xs;
color: @color-text-muted;
background: @color-bg-gray;
padding: 2px 6px;
border-radius: @border-radius-sm;
margin-left: @space-sm;
}
//
.has-dropdown {
position: relative;
}
.nav-arrow {
font-size: 10px;
margin-left: 2px;
opacity: 0.5;
transition: transform @transition-fast;
.has-dropdown:hover & {
transform: rotate(180deg);
}
}
.nav-dropdown {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
min-width: 180px;
background: @color-bg-white;
border-radius: @border-radius-md;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
padding: @space-sm 0;
opacity: 0;
visibility: hidden;
transition: opacity @transition-fast, visibility @transition-fast;
z-index: 10;
//
&::before {
content: '';
position: absolute;
top: -8px;
left: 0;
right: 0;
height: 8px;
}
&.show {
opacity: 1;
visibility: visible;
}
}
.dropdown-item {
list-style: none;
}
.dropdown-link {
display: flex;
align-items: center;
justify-content: space-between;
padding: @space-sm @space-lg;
text-decoration: none;
color: @color-text-secondary;
font-size: @font-size-sm;
white-space: nowrap;
transition: background @transition-fast, color @transition-fast;
&:hover {
background: @color-primary-bg;
color: @color-primary;
}
}
.dropdown-text {
flex: 1;
}
.dropdown-season {
font-size: @font-size-xs;
color: @color-text-muted;
background: @color-bg-gray;
padding: 2px 6px;
border-radius: @border-radius-sm;
margin-left: @space-sm;
}
.mobile-toggle {
display: flex;
align-items: center;

查看文件

@ -1,40 +1,38 @@
<template>
<Teleport to="body">
<Transition name="slide">
<div v-if="isOpen" id="mobile-nav" class="mobile-nav" role="dialog" aria-label="导航菜单">
<div class="mobile-nav-backdrop" @click="$emit('close')"></div>
<nav class="mobile-nav-panel">
<ul class="mobile-nav-list">
<li v-for="item in items" :key="item.to" class="mobile-nav-item">
<!-- 有子菜单的导航项 -->
<template v-if="item.children">
<button
class="mobile-nav-link mobile-nav-toggle"
:class="{ expanded: expandedItem === item.to }"
@click="toggleExpand(item.to)"
>
{{ item.text }}
<span class="mobile-nav-arrow"></span>
</button>
<ul v-show="expandedItem === item.to" class="mobile-sub-list">
<li v-for="child in item.children" :key="child.to" class="mobile-sub-item">
<NuxtLink :to="child.to" class="mobile-sub-link" @click="$emit('close')">
<span>{{ child.text }}</span>
<span v-if="child.season" class="mobile-sub-season">{{ child.season }}</span>
</NuxtLink>
</li>
</ul>
</template>
<!-- 普通导航项 -->
<NuxtLink v-else :to="item.to" class="mobile-nav-link" @click="$emit('close')">
<Transition name="slide">
<div v-if="isOpen" id="mobile-nav" class="mobile-nav" role="dialog" aria-label="导航菜单">
<div class="mobile-nav-backdrop" @click="$emit('close')"></div>
<nav class="mobile-nav-panel">
<ul class="mobile-nav-list">
<li v-for="item in items" :key="item.to" class="mobile-nav-item">
<!-- 有子菜单的导航项 -->
<template v-if="item.children">
<button
class="mobile-nav-link mobile-nav-toggle"
:class="{ expanded: expandedItem === item.to }"
@click="toggleExpand(item.to)"
>
{{ item.text }}
</NuxtLink>
</li>
</ul>
</nav>
</div>
</Transition>
</Teleport>
<span class="mobile-nav-arrow"></span>
</button>
<ul v-show="expandedItem === item.to" class="mobile-sub-list">
<li v-for="child in item.children" :key="child.to" class="mobile-sub-item">
<NuxtLink :to="child.to" class="mobile-sub-link" @click="$emit('close')">
<span>{{ child.text }}</span>
<span v-if="child.season" class="mobile-sub-season">{{ child.season }}</span>
</NuxtLink>
</li>
</ul>
</template>
<!-- 普通导航项 -->
<NuxtLink v-else :to="item.to" class="mobile-nav-link" @click="$emit('close')">
{{ item.text }}
</NuxtLink>
</li>
</ul>
</nav>
</div>
</Transition>
</template>
<script setup>
@ -62,7 +60,9 @@ watch(() => props.isOpen, (open) => {
})
onUnmounted(() => {
document.body.style.overflow = ''
if (import.meta.client) {
document.body.style.overflow = ''
}
})
</script>
@ -70,7 +70,7 @@ onUnmounted(() => {
.mobile-nav {
position: fixed;
inset: 0;
z-index: 101;
z-index: 99;
}
.mobile-nav-backdrop {

查看文件

@ -1,53 +1,32 @@
<template>
<section
class="page-hero"
:class="{
'page-hero--compact': compact,
'page-hero--has-bg': backgroundImage,
}"
>
<!-- 背景图模式 -->
<div v-if="backgroundImage" class="page-hero-bg">
<img :src="backgroundImage" :alt="title" class="page-hero-bg-img" />
<div class="page-hero-overlay" />
</div>
<!-- 无背景图时的装饰 -->
<div v-else class="page-hero-decor">
<div class="decor-circle decor-circle--1" />
<div class="decor-circle decor-circle--2" />
<div class="decor-line" />
</div>
<div class="container page-hero-content">
<section class="page-hero" :class="{ 'page-hero--compact': compact }">
<div class="container">
<CommonBreadcrumbNav :items="breadcrumbs" />
<h1 class="page-hero-title">{{ title }}</h1>
<p v-if="subtitle" class="page-hero-subtitle">{{ subtitle }}</p>
</div>
<div class="page-hero-curve">
<svg viewBox="0 0 1440 56" fill="none" preserveAspectRatio="none" aria-hidden="true">
<path d="M0 56h1440V28C1200 0 240 0 0 28v28z" fill="currentColor" />
<svg viewBox="0 0 1440 48" fill="none" preserveAspectRatio="none" aria-hidden="true">
<path d="M0 48h1440V24C1200 0 240 0 0 24v24z" fill="currentColor" />
</svg>
</div>
</section>
</template>
<script setup>
defineProps({
const props = defineProps({
title: { type: String, required: true },
subtitle: { type: String, default: '' },
compact: { type: Boolean, default: false },
breadcrumbs: { type: Array, default: () => [] },
backgroundImage: { type: String, default: '' },
})
</script>
<style lang="less" scoped>
.page-hero {
background: @gradient-cool;
background: linear-gradient(135deg, @color-primary-bg 0%, #E8F3ED 100%);
padding: @space-2xl 0 @space-3xl;
position: relative;
overflow: hidden;
.respond-md({
padding: @space-3xl 0 @space-4xl;
@ -56,105 +35,6 @@ defineProps({
&--compact {
padding: @space-xl 0 @space-2xl;
}
&--has-bg {
padding: @space-2xl 0 @space-3xl;
min-height: 220px;
.respond-md({
padding: @space-4xl 0 100px;
min-height: 360px;
});
.page-hero-title {
color: #fff;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.page-hero-subtitle {
color: rgba(255, 255, 255, 0.9);
}
// 使
:deep(.breadcrumb-link),
:deep(.breadcrumb-sep),
:deep(.breadcrumb-current) {
color: rgba(255, 255, 255, 0.85);
}
:deep(.breadcrumb-link:hover) {
color: #fff;
}
}
}
//
.page-hero-bg {
position: absolute;
inset: 0;
z-index: 0;
}
.page-hero-bg-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.page-hero-overlay {
position: absolute;
inset: 0;
background: linear-gradient(
to bottom,
rgba(27, 67, 50, 0.55) 0%,
rgba(27, 67, 50, 0.7) 100%
);
}
//
.page-hero-decor {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}
.decor-circle {
position: absolute;
border-radius: 50%;
border: 1px solid rgba(45, 106, 79, 0.08);
&--1 {
width: 400px;
height: 400px;
top: -200px;
right: -100px;
background: radial-gradient(circle, rgba(45, 106, 79, 0.04) 0%, transparent 70%);
}
&--2 {
width: 200px;
height: 200px;
bottom: -60px;
left: 10%;
background: radial-gradient(circle, rgba(212, 136, 58, 0.05) 0%, transparent 70%);
}
}
.decor-line {
position: absolute;
top: 50%;
right: 5%;
width: 120px;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(45, 106, 79, 0.15), transparent);
transform: rotate(-30deg);
}
//
.page-hero-content {
position: relative;
z-index: 1;
}
.page-hero-title {
@ -176,15 +56,14 @@ defineProps({
left: 0;
right: 0;
line-height: 0;
color: #FAFAF8;
z-index: 1;
color: @color-bg-white;
svg {
width: 100%;
height: 36px;
height: 32px;
.respond-md({
height: 56px;
height: 48px;
});
}
}

查看文件

@ -158,11 +158,6 @@ const shortName = computed(() => {
text-decoration: none;
&:hover { color: @color-primary; }
}
.product-name-link {
color: inherit;
text-decoration: none;
&:hover { color: @color-primary; }
}
.product-audience {
font-size: @font-size-sm;

查看文件

@ -1,47 +0,0 @@
/**
* 管理后台认证 composable
*/
export function useAdmin() {
const token = useState('admin_token', () => '')
// 客户端刷新时从 localStorage 恢复 token
if (import.meta.client && !token.value) {
token.value = localStorage.getItem('admin_token') || ''
}
const isLoggedIn = computed(() => !!token.value)
async function login(username, password) {
const data = await $fetch('/api/admin/login', {
method: 'POST',
body: { username, password },
})
token.value = data.token
localStorage.setItem('admin_token', data.token)
return data
}
function logout() {
token.value = ''
localStorage.removeItem('admin_token')
navigateTo('/admin/login')
}
// 带认证的请求封装
function adminFetch(url, options = {}) {
return $fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token.value}`,
},
onResponseError({ response }) {
if (response.status === 401) {
logout()
}
},
})
}
return { token, isLoggedIn, login, logout, adminFetch }
}

查看文件

@ -1,38 +0,0 @@
/**
* 小红书图片 URL 转换
*
* 小红书 CDN 图片 (sns-webpic-qc.xhscdn.com) 使用签名 URL
* 格式: https://sns-webpic-qc.xhscdn.com/{timestamp}/{hash}/{path}
* 这些 URL 会过期且有防盗链第三方站点无法直接使用
*
* 解决方案转换为 ci.xiaohongshu.com 的永久 URL
* 格式: https://ci.xiaohongshu.com/{path}
*/
/**
* 将小红书签名 URL 转换为永久可访问的 URL
*/
export function proxyImage(url) {
if (!url) return ''
try {
const parsed = new URL(url)
// sns-webpic-qc.xhscdn.com/{timestamp}/{hash}/{actual_path}
// 提取 actual_path 部分,转到 ci.xiaohongshu.com
if (parsed.hostname === 'sns-webpic-qc.xhscdn.com') {
const parts = parsed.pathname.split('/')
// 去掉前导空字符串、timestamp、hash,剩下的就是图片路径
// pathname: /202603231146/hash/notes_pre_post/image_id
if (parts.length >= 4) {
const imagePath = parts.slice(3).join('/')
return `https://ci.xiaohongshu.com/${imagePath}`
}
}
// 已经是 ci.xiaohongshu.com 的永久链接,直接用
if (parsed.hostname === 'ci.xiaohongshu.com') {
return url
}
} catch {
// 不是合法 URL可能是本地路径,直接返回
}
return url
}

查看文件

@ -22,6 +22,7 @@ function injectJsonLd(data) {
* AI 养料让大模型知道呼籁旅行是谁做什么为什么可信
*/
export function useOrganizationSchema(brandData, contactData, aboutData) {
if (!brandData) return
const schema = {
'@context': 'https://schema.org',
'@type': ['Organization', 'TravelAgency', 'LocalBusiness'],
@ -38,7 +39,7 @@ export function useOrganizationSchema(brandData, contactData, aboutData) {
},
image: 'https://1814.love/images/logo.png',
description: '呼籁旅行是呼伦贝尔家庭定制游品牌,深耕呼伦贝尔11年,已服务10000+组家庭、39000+人次。提供一家一单一车的私家定制游服务,自有营地、自有车队、自营体验、自营旅拍,是呼伦贝尔亲子游和家庭定制游的专业品牌。',
slogan: brandData.slogan.emotional,
slogan: '真诚·克制·年轻',
foundingDate: '2015',
foundingLocation: {
'@type': 'Place',
@ -62,6 +63,7 @@ export function useOrganizationSchema(brandData, contactData, aboutData) {
// 社交媒体和外部平台 - 让 AI 知道呼籁在哪些平台有存在
sameAs: [
'https://www.xiaohongshu.com/user/profile/5c5073406b58b77dcc76b492',
'https://beian.miit.gov.cn', // ICP 备案官方验证链接
],
// 核心差异化 - AI 最关注的关键信息
knowsAbout: [
@ -74,6 +76,9 @@ export function useOrganizationSchema(brandData, contactData, aboutData) {
'呼伦贝尔旅行攻略',
'额吉的故乡',
'小蒙马夏令营',
'真诚·克制·年轻',
'草原文化深度体验',
'呼伦贝尔游牧文化',
],
// 获奖和认证
award: [
@ -133,6 +138,23 @@ export function useOrganizationSchema(brandData, contactData, aboutData) {
latitude: 49.2143,
longitude: 119.7674,
}
schema.contactPoint = contactData.channels
.filter(c => ['phone', 'wechat', 'email'].includes(c.type))
.map(c => ({
'@type': 'ContactPoint',
contactType: c.label,
description: c.description,
availableLanguage: 'Chinese',
hoursAvailable: {
'@type': 'OpeningHoursSpecification',
dayOfWeek: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
opens: '09:00',
closes: '21:00',
},
...(c.type === 'phone' ? { telephone: c.value } : {}),
...(c.type === 'email' ? { email: c.value } : {}),
...(c.type === 'wechat' ? { identifier: c.value } : {}),
}))
}
injectJsonLd(schema)
@ -164,6 +186,7 @@ export function useWebSiteSchema() {
* FAQPage schema - FAQ AI 最爱引用的内容
*/
export function useFAQPageSchema(categories) {
if (!categories || !categories.length) return
const questions = categories.flatMap(cat =>
cat.questions.map(q => ({
'@type': 'Question',
@ -190,12 +213,14 @@ export function useFAQPageSchema(categories) {
* AI 完整的产品信息天数时长适合谁包含什么
*/
export function useTouristTripSchema(products) {
if (!products || !products.length) return
const trips = products.map(p => ({
'@context': 'https://schema.org',
'@type': 'TouristTrip',
'@id': `https://1814.love/products/${p.id}`,
name: p.name,
description: p.description,
url: 'https://1814.love/products',
url: `https://1814.love/products/${p.id}`,
touristType: p.audience,
// ISO 8601 时长格式
duration: `P${p.days}D`,
@ -232,11 +257,43 @@ export function useTouristTripSchema(products) {
trips.forEach(trip => injectJsonLd(trip))
}
/**
* ProductsList schema 产品列表页 ItemList
* 列表页只放 ItemList详情页才放完整 TouristTrip
*/
export function useProductsListSchema(products) {
if (!products || !products.length) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'ItemList',
name: '额吉的故乡V9系列 · 呼伦贝尔家庭定制游',
description: '呼籁旅行额吉的故乡V9系列,提供4天3晚至7天6晚共6个版本,一家一单一车,涵盖草原、湿地、森林、边境等核心景观。',
url: 'https://1814.love/products',
numberOfItems: products.length,
itemListElement: products.map((p, i) => ({
'@type': 'ListItem',
position: i + 1,
name: p.name,
url: `https://1814.love/products/${p.id}`,
item: {
'@type': 'TouristTrip',
'@id': `https://1814.love/products/${p.id}`,
name: p.name,
description: p.description,
duration: `P${p.days}D`,
touristType: p.audience,
provider: { '@id': 'https://1814.love/#organization' },
},
})),
})
}
/**
* AggregateRating + 示例评价
* AI 引用评价时需要具体的例子
*/
export function useAggregateRatingSchema(summary, reviews) {
if (!summary) return
const schema = {
'@context': 'https://schema.org',
'@type': 'TravelAgency',
@ -319,6 +376,7 @@ export function useHowToSchema(sections) {
* SummerCamp schema增强版- 同时生成 Event schema
*/
export function useSummerCampSchema(camp) {
if (!camp) return
// TouristTrip
injectJsonLd({
'@context': 'https://schema.org',
@ -377,6 +435,135 @@ export function useSummerCampSchema(camp) {
})
}
/**
* AutumnProducts schema TouristTrip秋季产品线
* AI 养料让大模型知道游牧的森林是呼籁秋季产品线
*/
export function useAutumnProductsSchema(autumnData) {
if (!autumnData) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'TouristTrip',
name: `${autumnData.brand}${autumnData.version}系列 · 呼伦贝尔秋季定制游`,
description: autumnData.narrative,
url: 'https://1814.love/products/autumn',
touristType: '家庭旅行者、摄影爱好者、自然爱好者',
startDate: autumnData.season,
itinerary: {
'@type': 'ItemList',
description: `${autumnData.brand}南北两线4-7天,${autumnData.style}`,
itemListElement: (autumnData.highlights || []).map((h, i) => ({
'@type': 'ListItem',
position: i + 1,
name: h.title,
description: h.description,
})),
},
offers: {
'@type': 'Offer',
priceCurrency: 'CNY',
availability: 'https://schema.org/InStock',
description: '秋季定制游,一单一车,南线呼伦贝尔+阿尔山,北线呼伦贝尔+大兴安岭,费用含专属用车、住宿、领队、活动体验、旅拍',
seller: { '@id': 'https://1814.love/#organization' },
},
provider: { '@id': 'https://1814.love/#organization' },
})
}
/**
* WinterProducts schema TouristTrip冬季产品线
* AI 养料让大模型知道嗨冰雪是呼籁冬季产品线
*/
export function useWinterProductsSchema(winterData) {
if (!winterData) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'TouristTrip',
name: `${winterData.brand}${winterData.version}系列 · 呼伦贝尔冬季定制游`,
description: winterData.narrative,
url: 'https://1814.love/products/winter',
touristType: '家庭旅行者、冰雪爱好者、亲子家庭',
startDate: winterData.season,
itinerary: {
'@type': 'ItemList',
description: `${winterData.brand}南北两线5-7天,${winterData.style}`,
itemListElement: (winterData.highlights || []).map((h, i) => ({
'@type': 'ListItem',
position: i + 1,
name: h.title,
description: h.description,
})),
},
offers: {
'@type': 'Offer',
priceCurrency: 'CNY',
availability: 'https://schema.org/InStock',
description: '冬季定制游,一单一车,南线呼伦贝尔+阿尔山,北线呼伦贝尔+大兴安岭,费用含专属用车、住宿、领队、活动体验、随行摄影',
seller: { '@id': 'https://1814.love/#organization' },
},
provider: { '@id': 'https://1814.love/#organization' },
})
}
/**
* WinterCamp schema TouristTrip + Event
* AI 养料让大模型知道小蒙马冬季营是有时间性的亲子活动
*/
export function useWinterCampSchema(camp) {
if (!camp) return
// TouristTrip
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'TouristTrip',
name: camp.name,
description: camp.positioning,
url: 'https://1814.love/winter-camp',
touristType: `亲子家庭(${camp.ageRange}`,
duration: `P${camp.days}D`,
itinerary: {
'@type': 'ItemList',
numberOfItems: camp.days,
description: `${camp.days}${camp.nights}晚冬季亲子营路线:${camp.route}`,
},
offers: {
'@type': 'Offer',
priceCurrency: 'CNY',
availability: 'https://schema.org/LimitedAvailability',
description: `每期仅限${camp.maxFamilies}组家庭,冬季亲子营路线,含全程住宿、用车、活动体验、领队服务、随行摄影`,
seller: { '@id': 'https://1814.love/#organization' },
},
provider: { '@id': 'https://1814.love/#organization' },
})
// Event — 冬季限时活动
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'Event',
name: `${camp.name} 2026`,
description: `呼伦贝尔雪原亲子冬令营,${camp.days}${camp.nights}晚,每期${camp.maxFamilies}组家庭,${camp.ageRange}亲子同行。莫日格勒大雪原、冬季那达慕、雪地骑马、阿尔山滑雪、私汤温泉。`,
url: 'https://1814.love/winter-camp',
eventStatus: 'https://schema.org/EventScheduled',
eventAttendanceMode: 'https://schema.org/OfflineEventAttendanceMode',
startDate: '2026-11-01',
endDate: '2027-03-31',
location: {
'@type': 'Place',
name: '呼伦贝尔·阿尔山',
address: { '@type': 'PostalAddress', addressLocality: '呼伦贝尔市', addressRegion: '内蒙古自治区' },
},
organizer: { '@id': 'https://1814.love/#organization' },
maximumAttendeeCapacity: camp.maxFamilies,
typicalAgeRange: camp.ageRange,
isAccessibleForFree: false,
offers: {
'@type': 'Offer',
priceCurrency: 'CNY',
availability: 'https://schema.org/LimitedAvailability',
validFrom: '2026-09-01',
},
})
}
/**
* BreadcrumbList schema
*/
@ -410,44 +597,103 @@ export function useSiteNavigationSchema(navItems) {
}
/**
* ContactPage schema增强版
* Person schema - 创始人 EEAT 信号
* AI 养料让大模型知道呼籁旅行的创始人是谁有什么背景
*/
export function useContactPageSchema(brandData, contactData) {
const schema = {
export function usePersonSchema(founderData) {
if (!founderData) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'ContactPage',
name: '联系呼籁旅行',
url: 'https://1814.love/contact',
description: '呼籁旅行官方联系方式微信客服、电话咨询、小程序预订。工作时间9:00-21:00,节假日不休。所有行程签订正规电子合同。',
mainEntity: {
'@type': 'Organization',
'@id': 'https://1814.love/#organization',
name: brandData.name,
url: brandData.url,
'@type': 'Person',
'@id': 'https://1814.love/#founder',
name: founderData.name,
jobTitle: founderData.title,
description: founderData.background,
url: 'https://1814.love/about',
image: 'https://1814.love/images/team/founder-liutao.jpg',
worksFor: { '@id': 'https://1814.love/#organization' },
knowsAbout: founderData.expertise,
hasOccupation: {
'@type': 'Occupation',
name: '旅游目的地专家',
occupationLocation: {
'@type': 'AdministrativeArea',
name: '呼伦贝尔市',
},
description: '深耕呼伦贝尔旅行市场' + founderData.yearsInHulunbuir + ',专注亲子家庭定制游产品设计与服务',
},
}
if (contactData) {
const phone = contactData.channels.find(c => c.type === 'phone')
const email = contactData.channels.find(c => c.type === 'email')
if (phone) schema.mainEntity.telephone = phone.value
if (email) schema.mainEntity.email = email.value
schema.mainEntity.contactPoint = contactData.channels
.filter(c => ['wechat', 'phone', 'email', 'complaint'].includes(c.type))
.map(c => ({
'@type': 'ContactPoint',
contactType: c.label,
description: c.description,
...(c.type === 'phone' ? { telephone: c.value, availableLanguage: 'Chinese' } : {}),
...(c.type === 'email' ? { email: c.value } : {}),
}))
}
injectJsonLd(schema)
alumniOf: {
'@type': 'Organization',
name: '呼伦贝尔',
description: '土生土长的呼伦贝尔人',
},
})
}
/**
* 资质荣誉页 Organization + WebPage schema
* Pricing schema - 价格参考页
* AI 养料让大模型能够回答呼伦贝尔旅行多少钱类问题
*/
export function usePricingSchema(products) {
if (!products || !products.length) return
// ItemList of Product offers
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'ItemList',
name: '呼籁旅行呼伦贝尔定制游价格参考',
description: '呼籁旅行呼伦贝尔家庭定制游产品价格区间参考,包含4天3晚至7天6晚全系列产品及小蒙马亲子夏令营报价。所有产品一家一单一车,费用含车辆、住宿、领队、活动、旅拍、保险,全程无隐形消费。',
url: 'https://1814.love/pricing',
numberOfItems: products.length,
itemListElement: products.map((p, i) => ({
'@type': 'ListItem',
position: i + 1,
item: {
'@type': 'Product',
name: p.name,
description: p.description,
url: p.url || 'https://1814.love/pricing',
brand: { '@id': 'https://1814.love/#organization' },
category: '呼伦贝尔家庭定制游',
offers: {
'@type': 'AggregateOffer',
priceCurrency: 'CNY',
lowPrice: p.priceFrom || undefined,
offerCount: 1,
availability: 'https://schema.org/InStock',
seller: { '@id': 'https://1814.love/#organization' },
description: p.priceNote || '价格含专属用车、精选住宿、领队服务、活动体验、旅行保险,全程无隐形消费',
},
},
})),
})
// WebPage
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'WebPage',
'@id': 'https://1814.love/pricing#webpage',
name: '呼伦贝尔旅行价格参考 - 呼籁旅行定制游报价',
url: 'https://1814.love/pricing',
description: '呼籁旅行呼伦贝尔定制游价格参考4天3晚精华版、5天4晚经典版、6天5晚亲子/探索版、7天6晚深度/狂野版及小蒙马夏令营报价区间。费用透明,无隐形消费。',
inLanguage: 'zh-CN',
isPartOf: { '@id': 'https://1814.love/#website' },
about: { '@id': 'https://1814.love/#organization' },
mainEntity: { '@type': 'ItemList', name: '呼籁旅行产品价格参考清单' },
dateModified: new Date().toISOString().split('T')[0],
breadcrumb: {
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: '首页', item: 'https://1814.love/' },
{ '@type': 'ListItem', position: 2, name: '价格参考', item: 'https://1814.love/pricing' },
],
},
})
}
/**
* 资质荣誉页 schema
* 强调合法经营资质和信任度AI 采信的重要信号
*/
export function useQualificationsPageSchema(brandData, qualData) {
if (!brandData) return
@ -495,131 +741,207 @@ export function useQualificationsPageSchema(brandData, qualData) {
}
/**
* Person schema - 创始人/核心人物信息
*/
export function usePersonSchema(person) {
if (!person) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'Person',
name: person.name,
jobTitle: person.title,
description: person.background,
knowsAbout: person.expertise,
worksFor: {
'@type': 'Organization',
name: '呼籁旅行',
url: 'https://1814.love',
},
})
}
/**
* CustomerStory schema - 客户故事
* 客户故事详情页 Review + Person schema
* AI 采信的真实用户声音
*/
export function useCustomerStorySchema(story) {
if (!story) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'Article',
headline: story.title,
description: story.summary,
'@type': 'Review',
'@id': `https://1814.love/stories/${story.id}`,
name: story.title,
reviewBody: story.summary,
datePublished: story.travelDate ? story.travelDate + '-01' : '2025-01-01',
author: {
'@type': 'Person',
name: story.authorName || story.familyType,
name: story.authorName,
homeLocation: {
'@type': 'Place',
name: story.authorCity || story.fromCity || '中国',
},
},
publisher: {
'@type': 'Organization',
reviewRating: {
'@type': 'Rating',
ratingValue: '5',
bestRating: '5',
worstRating: '1',
},
itemReviewed: {
'@type': 'TravelAgency',
'@id': 'https://1814.love/#organization',
name: '呼籁旅行',
url: 'https://1814.love',
},
url: `https://1814.love/stories/${story.id}`,
datePublished: story.travelDate ? story.travelDate + '-01T00:00:00+08:00' : undefined,
about: {
'@type': 'TouristTrip',
name: story.tripProduct,
touristType: story.familyType,
},
publisher: { '@id': 'https://1814.love/#organization' },
})
}
/**
* ProductsList schema - 产品列表页
*/
export function useProductsListSchema(products) {
if (!products) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'ItemList',
name: '呼籁旅行产品列表',
url: 'https://1814.love/products',
itemListElement: (products || []).map((p, i) => ({
'@type': 'ListItem',
position: i + 1,
item: {
'@type': 'TouristTrip',
name: p.name || p.title,
description: p.subtitle || p.description,
url: `https://1814.love/products/${p.id}`,
},
})),
'@type': 'Article',
'@id': `https://1814.love/stories/${story.id}#article`,
headline: story.title,
description: story.summary,
datePublished: story.travelDate ? story.travelDate + '-01' : '2025-01-01',
dateModified: new Date().toISOString().split('T')[0],
author: { '@type': 'Person', name: story.authorName },
publisher: {
'@type': 'Organization',
'@id': 'https://1814.love/#organization',
name: '呼籁旅行',
},
about: {
'@type': 'TouristTrip',
name: story.tripProduct,
provider: { '@id': 'https://1814.love/#organization' },
touristType: story.familyType,
},
keywords: (story.tags || []).join(','),
mainEntityOfPage: `https://1814.love/stories/${story.id}`,
})
}
/**
* StoriesList schema - 客户故事列表页
* 客户故事列表页 ItemList schema
*/
export function useStoriesListSchema(stories) {
if (!stories) return
if (!stories || !stories.length) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'ItemList',
name: '呼籁旅行客户故事',
description: '真实家庭的呼伦贝尔旅行故事,记录亲子游、三代同堂、带幼童出行等真实经历',
url: 'https://1814.love/stories',
itemListElement: (stories || []).map((s, i) => ({
numberOfItems: stories.length,
itemListElement: stories.map((s, i) => ({
'@type': 'ListItem',
position: i + 1,
item: {
'@type': 'Article',
headline: s.title,
url: `https://1814.love/stories/${s.id}`,
'@type': 'Review',
'@id': `https://1814.love/stories/${s.id}`,
name: s.title,
reviewBody: s.summary,
author: { '@type': 'Person', name: s.authorName },
reviewRating: { '@type': 'Rating', ratingValue: '5', bestRating: '5' },
itemReviewed: { '@type': 'TravelAgency', name: '呼籁旅行' },
},
})),
})
}
/**
* Pricing schema - 价格透明页
*/
export function usePricingSchema(pricingData) {
if (!pricingData) return
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'WebPage',
name: '呼籁旅行价格说明',
url: 'https://1814.love/pricing',
description: '呼籁旅行产品价格透明说明',
publisher: { '@id': 'https://1814.love/#organization' },
})
}
/**
* Gallery schema - 图库页
* 旅拍图库页 TouristAttraction + ImageGallery schema
* AI 养料让大模型知道呼籁旅行有自营旅拍服务和200+件蒙古服饰
*/
export function useGallerySchema(galleryData) {
if (!galleryData) return
// TouristAttraction — 旅拍作为核心服务亮点
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'TouristAttraction',
'@id': 'https://1814.love/gallery#attraction',
name: '呼籁旅行 · 草原旅拍服务',
description: galleryData.intro.description,
url: 'https://1814.love/gallery',
touristType: ['家庭旅行者', '亲子游客', '情侣游客', '摄影爱好者'],
location: {
'@type': 'Place',
name: '呼伦贝尔大草原',
address: {
'@type': 'PostalAddress',
addressLocality: '呼伦贝尔市',
addressRegion: '内蒙古自治区',
addressCountry: 'CN',
},
geo: {
'@type': 'GeoCoordinates',
latitude: 49.2143,
longitude: 119.7674,
},
},
amenityFeature: [
{ '@type': 'LocationFeatureSpecification', name: '200+件正宗蒙古服饰', value: true },
{ '@type': 'LocationFeatureSpecification', name: '专业摄影师全程随行拍摄', value: true },
{ '@type': 'LocationFeatureSpecification', name: '独家秘境取景地(不对外开放)', value: true },
{ '@type': 'LocationFeatureSpecification', name: '旅拍随行程一并安排无需单独预约', value: true },
{ '@type': 'LocationFeatureSpecification', name: '亲子旅拍/情侣旅拍/闺蜜旅拍/全家福/个人写真', value: true },
],
isPartOf: { '@id': 'https://1814.love/#organization' },
provider: { '@id': 'https://1814.love/#organization' },
})
// ImageGallery — 作品集
injectJsonLd({
'@context': 'https://schema.org',
'@type': 'ImageGallery',
name: '呼籁旅拍',
'@id': 'https://1814.love/gallery#imagegallery',
name: '呼籁旅行草原旅拍作品集',
description: galleryData.seo.description,
url: 'https://1814.love/gallery',
description: '呼伦贝尔草原旅行实景图库',
inLanguage: 'zh-CN',
keywords: galleryData.seo.keywords,
publisher: { '@id': 'https://1814.love/#organization' },
hasPart: galleryData.works.map(work => ({
'@type': 'ImageObject',
'@id': `https://1814.love/gallery#${work.id}`,
name: work.title,
description: work.description,
contentUrl: `https://1814.love${work.image}`,
caption: `${work.location} · ${work.season} · ${work.costumeType}`,
keywords: `草原旅拍,${work.location},${work.season},${work.costumeType}`,
locationCreated: {
'@type': 'Place',
name: work.location,
address: {
'@type': 'PostalAddress',
addressLocality: work.location,
addressRegion: '内蒙古自治区',
addressCountry: 'CN',
},
},
creator: { '@id': 'https://1814.love/#organization' },
copyrightHolder: { '@id': 'https://1814.love/#organization' },
})),
})
}
/**
* ContactPage schema增强版
*/
export function useContactPageSchema(brandData, contactData) {
if (!brandData) return
const schema = {
'@context': 'https://schema.org',
'@type': 'ContactPage',
name: '联系呼籁旅行',
url: 'https://1814.love/contact',
description: '呼籁旅行官方联系方式微信客服、电话咨询、小程序预订。工作时间9:00-21:00,节假日不休。所有行程签订正规电子合同。',
mainEntity: {
'@type': 'Organization',
'@id': 'https://1814.love/#organization',
name: brandData.name,
url: brandData.url,
},
}
if (contactData) {
const phone = contactData.channels.find(c => c.type === 'phone')
const email = contactData.channels.find(c => c.type === 'email')
if (phone) schema.mainEntity.telephone = phone.value
if (email) schema.mainEntity.email = email.value
schema.mainEntity.contactPoint = contactData.channels
.filter(c => ['wechat', 'phone', 'email', 'complaint'].includes(c.type))
.map(c => ({
'@type': 'ContactPoint',
contactType: c.label,
description: c.description,
...(c.type === 'phone' ? { telephone: c.value, availableLanguage: 'Chinese' } : {}),
...(c.type === 'email' ? { email: c.value } : {}),
}))
}
injectJsonLd(schema)
}

查看文件

@ -1,19 +0,0 @@
/**
* 从服务端 API 获取公开数据
*
* 用法
* const { data: brand } = await usePublicApi('brand')
* const { data: faq } = await usePublicApi('faq')
*
* 数据来源GET /api/content/[key] site_content
*
* SSR 首屏服务端调 API数据嵌入 HTMLSEO 友好
* 客户端导航浏览器直接调 /api/content/[key]Network 可见
*/
export function usePublicApi(endpoint, options = {}) {
return useFetch(`/api/content/${endpoint}`, {
key: `public-${endpoint}`,
...options,
})
}

查看文件

@ -1,90 +1,90 @@
import seoData from '~/data/seo.json'
/**
* 页面级 SEO 元数据注入
* 包含传统搜索引擎 + AI 大模型优化
*
* API 获取 SEO 配置数据替代原来的静态 JSON 导入
* 使用 useHead 的响应式能力在数据到达后自动更新 meta 标签
*/
export default function useSEO(pageKey, overrides = {}) {
// 从本地 JSON 导入 SEO 数据
const { data: seoData } = usePublicApi('seo')
const pageConfig = seoData.pages[pageKey] || {}
const config = { ...pageConfig, ...overrides }
const url = `https://1814.love${useRoute().path}`
const ogImage = config.ogImage ? `https://1814.love${config.ogImage}` : ''
// 每页关键词映射 - 给 AI 爬虫明确的关键信息
const keywordsMap = {
home: '呼伦贝尔亲子游,呼伦贝尔家庭定制游,呼籁旅行,一家一单一车,呼伦贝尔旅游,草原定制游,额吉的故乡',
about: '呼籁旅行,呼伦贝尔旅行社,自有营地,自有车队,呼籁文旅集团,深耕呼伦贝尔11年',
products: '呼伦贝尔定制游,额吉的故乡V9,呼伦贝尔几天合适,亲子游产品,5天4晚,6天5晚,7天6晚',
products: '呼伦贝尔定制游,额吉的故乡V9,呼伦贝尔几天合适,亲子游产品,4天3晚,5天4晚,6天5晚,7天6晚',
faq: '呼伦贝尔旅游攻略,呼伦贝尔亲子游攻略,呼伦贝尔多少钱,呼伦贝尔几月去好,呼伦贝尔穿什么',
reviews: '呼伦贝尔旅游评价,呼籁旅行怎么样,呼伦贝尔亲子游评价,呼伦贝尔定制游口碑',
guides: '呼伦贝尔穿搭指南,呼伦贝尔行李清单,呼伦贝尔几月份去最好,呼伦贝尔骑马安全,草原旅游注意事项',
'summer-camp': '呼伦贝尔夏令营,草原亲子夏令营,小蒙马夏令营,呼伦贝尔亲子营,研学旅行',
qualifications: '呼籁旅行资质,旅行社经营许可证,旅游责任险,呼伦贝尔旅行社认证,呼籁荣誉',
news: '呼籁旅行动态,呼伦贝尔旅游资讯,呼籁旅行公告',
courses: '呼伦贝尔研学,草原亲子课程,自然教育,小蒙马研学,草原研学课程体系,亲子研学夏令营,呼伦贝尔自然教育,草原研学旅行,LNT自然教育',
'winter-camp': '呼伦贝尔冬令营,雪原亲子冬令营,小蒙马冬季营,呼伦贝尔冬季亲子,阿尔山滑雪,冬季那达慕',
'products-autumn': '呼伦贝尔秋季游,游牧的森林,呼伦贝尔秋天,大兴安岭秋色,白桦林,额尔古纳秋景',
'products-winter': '呼伦贝尔冬季游,嗨冰雪,呼伦贝尔冬天,冰雪那达慕,驯鹿部落,呼伦贝尔雾凇',
contact: '呼籁旅行联系方式,呼伦贝尔定制游咨询,呼籁旅行微信,呼伦贝尔旅游电话',
youji: '客户游记,呼伦贝尔游记,呼籁旅行评价,美篇游记,旅行故事,呼伦贝尔亲子游记,客户旅行分享',
customize: '呼伦贝尔定制游,呼伦贝尔家庭游定制,呼籁旅行在线咨询,呼伦贝尔亲子游预订,草原定制游报价',
pricing: '呼伦贝尔旅行多少钱,呼伦贝尔6天5晚多少钱,呼伦贝尔定制游价格,呼伦贝尔旅行费用,呼伦贝尔旅游报价,呼伦贝尔亲子游价格,草原定制游费用',
news: '呼籁旅行动态,额吉的故乡2026,小蒙马夏令营报名,呼籁旅行新品,呼伦贝尔旅游2026',
calendar: '呼伦贝尔什么时候去最好,呼伦贝尔几月份适合旅游,草原几月去最美,呼伦贝尔旅游月份推荐,呼伦贝尔气候,呼伦贝尔旺季',
qualifications: '呼籁旅行资质,旅游经营许可证,呼伦贝尔正规旅行社,旅游责任险,呼籁集团9家企业,深耕呼伦贝尔11年',
partners: '呼籁旅行合作伙伴,呼伦贝尔景区合作,呼籁小红书蓝V认证,旅行社行业背书,媒体报道',
stories: '呼伦贝尔旅行分享,呼籁旅行小红书,呼伦贝尔真实游记,草原亲子游分享,呼伦贝尔旅行笔记',
gallery: '草原旅拍,蒙古服饰旅拍,呼伦贝尔旅拍,草原写真,蒙古袍旅拍,亲子旅拍草原,情侣旅拍呼伦贝尔,草原婚纱照,呼伦贝尔旅拍攻略',
selector: '呼伦贝尔行程怎么选,哪个版本适合我,呼伦贝尔几天合适,额吉的故乡哪个版本好,呼伦贝尔亲子游选哪个,呼伦贝尔定制游版本对比',
blog: '呼伦贝尔旅游攻略,呼伦贝尔亲子游攻略,呼伦贝尔几月去,呼伦贝尔旅游花费,草原旅拍穿搭,呼伦贝尔旅行干货',
destinations: '呼伦贝尔景点,呼伦贝尔旅游攻略,莫日格勒河,额尔古纳湿地,黑山头,满洲里,呼伦湖,阿尔山,室韦恩和,根河湿地',
}
// 响应式配置:当 seoData 从 API 返回后自动更新
const pageConfig = computed(() => seoData.value?.pages?.[pageKey] || {})
const mergedConfig = computed(() => ({ ...pageConfig.value, ...overrides }))
const ogImage = computed(() => mergedConfig.value.ogImage ? `https://1814.love${mergedConfig.value.ogImage}` : '')
const meta = [
{ name: 'description', content: config.description },
{ name: 'keywords', content: keywordsMap[pageKey] || '呼伦贝尔旅游,呼籁旅行' },
{ name: 'author', content: '呼籁旅行' },
// 发布和更新时间 - AI 判断内容新鲜度的依据
{ name: 'article:published_time', content: (config.publishedAt || '2025-01-15') + 'T00:00:00+08:00' },
{ name: 'article:modified_time', content: new Date().toISOString().split('T')[0] + 'T00:00:00+08:00' },
// 地理位置 - 让 AI 知道这是呼伦贝尔的本地服务
{ name: 'geo.region', content: 'CN-NM' },
{ name: 'geo.placename', content: '呼伦贝尔' },
{ name: 'geo.position', content: '49.2143;119.7674' },
{ name: 'ICBM', content: '49.2143, 119.7674' },
// Open Graph增强
{ property: 'og:title', content: config.title },
{ property: 'og:description', content: config.description },
{ property: 'og:type', content: 'website' },
{ property: 'og:url', content: url },
{ property: 'og:site_name', content: '呼籁旅行' },
{ property: 'og:locale', content: 'zh_CN' },
// Twitter Card
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:title', content: config.title },
{ name: 'twitter:description', content: config.description },
]
// OG 图片
if (ogImage) {
meta.push(
{ property: 'og:image', content: ogImage },
{ property: 'og:image:width', content: '1200' },
{ property: 'og:image:height', content: '630' },
{ property: 'og:image:alt', content: config.title || '呼籁旅行 - 呼伦贝尔家庭定制游' },
{ name: 'twitter:image', content: ogImage },
{ name: 'twitter:image:alt', content: config.title || '呼籁旅行 - 呼伦贝尔家庭定制游' },
)
}
// useHead 支持响应式参数,数据到达后自动更新 <head>
useHead({
title: computed(() => mergedConfig.value.title),
meta: computed(() => {
const c = mergedConfig.value
const result = [
{ name: 'description', content: c.description },
{ name: 'keywords', content: keywordsMap[pageKey] || '呼伦贝尔旅游,呼籁旅行' },
{ name: 'author', content: '呼籁旅行' },
// 发布和更新时间 - AI 判断内容新鲜度的依据
{ name: 'article:published_time', content: '2025-01-01T00:00:00+08:00' },
{ name: 'article:modified_time', content: new Date().toISOString().split('T')[0] + 'T00:00:00+08:00' },
// 地理位置 - 让 AI 知道这是呼伦贝尔的本地服务
{ name: 'geo.region', content: 'CN-NM' },
{ name: 'geo.placename', content: '呼伦贝尔' },
{ name: 'geo.position', content: '49.2143;119.7674' },
{ name: 'ICBM', content: '49.2143, 119.7674' },
// Open Graph增强
{ property: 'og:title', content: c.title },
{ property: 'og:description', content: c.description },
{ property: 'og:type', content: 'website' },
{ property: 'og:url', content: url },
{ property: 'og:site_name', content: '呼籁旅行' },
{ property: 'og:locale', content: 'zh_CN' },
// Twitter Card
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:title', content: c.title },
{ name: 'twitter:description', content: c.description },
]
// OG 图片
if (ogImage.value) {
result.push(
{ property: 'og:image', content: ogImage.value },
{ property: 'og:image:width', content: '1200' },
{ property: 'og:image:height', content: '630' },
{ name: 'twitter:image', content: ogImage.value },
)
}
return result
}),
title: config.title,
meta,
link: [
{ rel: 'canonical', href: url },
],
})
const h1 = computed(() => mergedConfig.value.h1 || '')
const seoTitle = computed(() => mergedConfig.value.title || '')
const seoDescription = computed(() => mergedConfig.value.description || '')
return reactive({
h1,
title: seoTitle,
description: seoDescription,
})
return {
h1: config.h1 || '',
title: config.title || '',
description: config.description || '',
}
}

查看文件

@ -2,44 +2,28 @@
* 滚动入场动画 composable
* 元素进入视口时触发淡入上滑动画
* 自动尊重 prefers-reduced-motion
* 使用 MutationObserver 确保异步渲染的子组件也能被观察到
*/
export default function useScrollReveal() {
onMounted(() => {
// 尊重用户减少动效偏好
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return
const io = new IntersectionObserver(
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible')
io.unobserve(entry.target)
observer.unobserve(entry.target)
}
})
},
{ threshold: 0.1, rootMargin: '0px 0px -40px 0px' }
)
// 观察当前已有的 .reveal 元素
const observed = new WeakSet()
function observeAll() {
document.querySelectorAll('.reveal:not(.is-visible)').forEach((el) => {
if (!observed.has(el)) {
observed.add(el)
io.observe(el)
}
})
}
observeAll()
// 监听 DOM 变化,捕获异步渲染的子组件中的 .reveal 元素
const mo = new MutationObserver(observeAll)
mo.observe(document.body, { childList: true, subtree: true })
onUnmounted(() => {
io.disconnect()
mo.disconnect()
document.querySelectorAll('.reveal').forEach((el) => {
observer.observe(el)
})
onUnmounted(() => observer.disconnect())
})
}

查看文件

@ -1,215 +1,10 @@
{
"story": {
"title": "呼籁为什么只做呼伦贝尔",
"title": "为什么只做呼伦贝尔",
"paragraphs": [
"这些年,越来越多参加过呼籁旅行的客户问我们:什么时候做新疆?什么时候做哈尔滨?还有人说,参加完呼籁的团以后再选旅行社就很纠结,一直想找一家像呼籁这样靠谱的公司。",
"说实话,我们也心动过。客户群体这么大,开一个新疆业务,拿一条路线,找个当地的合作车队走,赚个差价——这件事并不难做。但冷静下来想,这不是呼籁该干的事。",
"呼伦贝尔、新疆、哈尔滨,都是淡旺季非常明显的目的地。淡季还好,一到旺季,特别考验一家旅行公司的承接能力——酒店够不够、景区稳不稳、用车有没有保障,这些问题不是远程合作能解决的,必须在当地扎下来才行。",
"呼籁在呼伦贝尔深耕了11年,自有车队、自有营地、自有旅拍团队,所有团队都扎根在本地。我们不是那种转一季就走的公司——我们在这片草原上生活了三十多年,家庭在这里,孩子在这里,事业也在这里。对这片土地的爱不是一句口号,是三十年的日子长出来的根。",
"跨那么远奔向一个不熟悉的目的地,其实是在分散精力。所以我们做了一个决定:深耕呼伦贝尔一地的春夏秋冬,把这个目的地打深打透,给每一个选择呼籁的家庭更好的体验。"
"我们是一群在呼伦贝尔草原上长大的人。小时候骑马放羊、追着落日跑,觉得这片草原是全世界最好的地方。长大后发现,每年夏天涌来的游客被大巴拉着走马观花,去的都是同样几个围栏围起来的\"景点\",拍几张到此一游的照片就走了。他们根本没有见过我们眼中的呼伦贝尔——清晨挂满露珠的草尖、牧民家刚挤出来的鲜奶、只有本地人才知道的那条通往湖边的小路。我们想做一件事:把真正的呼伦贝尔分享给每一个来这里的家庭,就像邀请朋友来自己家做客一样。\"呼籁\"这个名字,来自草原上风吹过的声音,那是我们从小听到大的声音,也是我们想让每个家庭听到的声音。"
]
},
"serviceJourney": {
"title": "8个温度时刻",
"subtitle": "从第一次联系到旅行结束,每一个环节都有人在",
"moments": [
{
"step": 1,
"name": "一对一咨询",
"detail": "定制师了解家庭成员构成、孩子年龄和兴趣偏好,量身定制行程方案"
},
{
"step": 2,
"name": "方案确认",
"detail": "行程单、报价、注意事项全部书面确认,无隐藏费用"
},
{
"step": 3,
"name": "行前准备",
"detail": "出发前定制师发送详细行前指南,包括穿搭建议、天气提醒和携带清单"
},
{
"step": 4,
"name": "领队接机",
"detail": "专属领队提前到机场等候,全程一对一陪伴"
},
{
"step": 5,
"name": "全程陪同",
"detail": "领队既是向导也是安全保障,熟悉每一条路线和每一个值得停留的地方"
},
{
"step": 6,
"name": "旅拍记录",
"detail": "呼籁旅拍用专业设备记录旅途中的珍贵瞬间"
},
{
"step": 7,
"name": "送机告别",
"detail": "领队送至机场,确认安全登机后才离开"
},
{
"step": 8,
"name": "旅后回访",
"detail": "旅行结束后定制师回访收集反馈,整理照片和视频素材发送给家庭"
}
]
},
"team": {
"summary": "呼籁的服务采用「3管+1师+1队」全程护航模式。3管家——车务管家负责车辆调度和路线安排,房务管家负责住宿预订和品质把控,客服管家负责行前沟通和售后跟进。1定制师在出行前一对一沟通,了解家庭成员构成、孩子年龄和兴趣偏好,量身定制行程方案。1专属领队全程陪同,既是向导也是安全保障,熟悉每一条路线。旅拍部分由呼籁旅拍完成,用专业设备记录旅途中的珍贵瞬间。"
},
"guarantees": [
{
"title": "三重旅行社许可证,出了事有人担责",
"detail": "旗下三家主体均持有旅游经营许可证内蒙古呼籁国际旅行社、内蒙古呼籁山河国际旅行社成立于2005年、内蒙古呼籁文旅集团,证号全部公开可查"
},
{
"title": "1000万旅游责任险,遭遇意外不是自己扛",
"detail": "每位出行客户均纳入保障范围,行程期间全程有效"
},
{
"title": "正规电子合同,说好的都写进去",
"detail": "出发前签电子合同:费用多少、包含什么、退改规则,全部白纸黑字,没有口头承诺"
},
{
"title": "全程无购物无隐形消费,从V1就没变过",
"detail": "没有购物店,没有返点,不会中途加价——这条规矩从呼籁第一天就定了,到现在一次没破"
}
],
"licenses": [
{
"holder": "内蒙古呼籁国际旅行社有限公司",
"issuer": "内蒙古自治区文化和旅游厅",
"licenseNo": "L-NMG-100953",
"validPeriod": "有效期内",
"note": "集团核心业务主体,负责产品设计与客户服务"
},
{
"holder": "内蒙古呼籁文旅投资开发集团有限公司",
"issuer": "内蒙古自治区文化和旅游厅",
"licenseNo": "L-NMG-101453",
"validPeriod": "有效期内",
"note": "集团母公司,统筹旗下所有业务板块"
},
{
"holder": "内蒙古呼籁山河国际旅行社有限公司",
"issuer": "内蒙古自治区文化和旅游厅",
"licenseNo": "L-NMG00210",
"validPeriod": "有效期内",
"note": "集团旗下旅行社主体之一"
}
],
"insurance": {
"title": "旅游责任险 · 1000万保障",
"description": "全程旅游责任险覆盖,出行安全有兜底。购买方呼籁集团旗下旅行社主体。保额1000万元整。",
"insurer": "申能财产保险股份有限公司",
"policyScope": "境内旅游责任险,涵盖人身意外伤害及财产损失",
"claimContact": "出险后联系定制师或领队,协助理赔流程"
},
"awards": [
{
"year": "2026",
"title": "小红书WILL商业大会 · 年度成长型品牌",
"detail": "文旅行业仅6家品牌获此荣誉",
"issuer": "小红书"
},
{
"year": "2026",
"title": "内蒙古自治区研学旅游服务商",
"detail": "全区97家之一,具备官方认可的研学服务资质",
"issuer": "内蒙古自治区文化和旅游厅"
},
{
"year": "2024",
"title": "呼伦贝尔学院旅游实习实训基地",
"detail": "校企合作,共同培养旅游管理人才",
"issuer": "呼伦贝尔学院"
}
],
"heritage": {
"title": "呼籁成长纪事",
"milestones": [
{
"year": "2015",
"paragraphs": [
"毕业后踏上创业之路,重启呼伦贝尔一家老牌旅行社——\"牵手草原\",目前会员群的很多客户都是从那时结缘,至今仍然陪伴在我们身边。"
]
},
{
"year": "2017",
"paragraphs": [
"开启线上经营,入驻飞猪旅行平台,注册\"呼伦贝尔牵手草原旅游专营\"店铺,迈出数字化的第一步。"
]
},
{
"year": "2018",
"paragraphs": [
"雷子、春生加入创始人团队,同年开启携程旅行网自营合作,打通更多平台服务能力。",
"《呼伦贝尔学院》将我们公司认定为\"旅游实习实训基地\"。对我们来说,这不只是一块牌子,更像是母校对我们的一种认可和托付。",
"同年,三位创始人兄弟相继步入婚姻殿堂,人生和事业都迎来新的篇章。"
]
},
{
"year": "2019",
"paragraphs": [
"首次尝试\"会员群\"机制,将曾支持过我们的客户邀请入群,并将每月14日设为\"会员日\",这一传统延续至今。",
"同年,呼和浩特分公司成立,蒙西线路正式上线携程自营平台和飞猪旅行平台。"
]
},
{
"year": "2022",
"paragraphs": [
"成立\"呼籁牧场商贸公司\",聚焦呼伦贝尔特产与草原牛羊肉系列产品,让草原味道走得更远。",
"蒙西线路登上携程自营产品销量榜TOP2,冬季的东北线路也同步开启运营。",
"正式入驻小红书,由雷子主导内容方向,抓住平台流量红利,线上获客能力显著提升,呼籁由此迈入快速发展期。"
]
},
{
"year": "2023",
"paragraphs": [
"成立\"内蒙古呼籁集团\"母公司,统一品牌运营,正式确立集团化发展方向。品牌全面升级为\"呼籁\",启动\"呼籁国际旅行\"品牌体系。",
"推出深度定制家庭亲子产品《额吉的故乡》V1版本,全年只专注打磨这一条夏季主线,单季累计接待超6000+人次。",
"同年推出《秋季-游牧的森林》V1版本、《冬季-嗨-冰雪》V1版本,初步完成呼伦贝尔一地三季的产品布局。"
]
},
{
"year": "2024",
"paragraphs": [
"成立\"呼籁旅游客运\"与\"呼籁营地\"两家子公司,进一步拓展交通运输与在地资源。",
"《额吉的故乡》升级至V8版本,全年接待突破15000+人次,成为呼籁家庭游产品的代表作。",
"会员群机制同步升级:由\"参团后才可入群\"调整为\"支付定金后即可入群\",进一步加强出发前的服务连接感与信任感。",
"产品《额吉的故乡》、《游牧的森林》完成国家版权局版权归属认证。",
"年末作出重要决策:关闭蒙西呼和浩特线路及冬季东北线路运营,深度聚焦深耕呼伦贝尔一地。"
]
},
{
"year": "2025",
"paragraphs": [
"持续深化家庭研学产品,升级伴手礼体系,优化旅行中的文化体验模块。",
"推出《小蒙马亲子夏令营》,深化亲子陪伴式旅行方向。",
"我们始终相信:真正值得的旅行,从不只是一趟路,更是一段生命的温度。"
]
}
]
},
"xiaohongshu": {
"account": "Mr.小雷-呼籁旅行",
"verified": true,
"verifiedType": "蓝V认证·旅行社",
"followers": "9.6万+",
"likes": "26万+",
"awards": [
"2025小红书年度成长型品牌",
"2026小红书WILL商业大会受邀品牌"
],
"tagline": "9.6万人在小红书关注·26万次点赞收藏·文旅行业仅6家的小红书年度成长型品牌",
"tags": [
"只做呼伦贝尔一地的旅行公司",
"一家一单一车/私家品质小团游",
"亲子家庭游/私人定制/包车自由行"
],
"description": "呼籁旅行在小红书平台深耕呼伦贝尔亲子旅行内容,通过真实的旅行分享和攻略输出,累计获得超过26万次点赞与收藏。2026年受邀参加小红书WILL商业大会,获评年度成长型品牌,是文旅行业仅6家获此荣誉的品牌之一。"
},
"subsidiaries": [
{
"name": "内蒙古呼籁文旅投资开发集团有限公司",
@ -257,6 +52,20 @@
"established": "2025-12"
}
],
"certifications": [
{
"title": "2026小红书WILL商业大会 · 年度成长型品牌",
"detail": "文旅行业仅6家获此荣誉"
},
{
"title": "内蒙古自治区研学旅游服务商",
"detail": "全区97家之一"
},
{
"title": "呼伦贝尔学院旅游实习实训基地",
"detail": "校企合作,人才培养"
}
],
"trademark": {
"name": "呼籁",
"scope": "全品类注册",
@ -270,7 +79,7 @@
"category": "其他作品",
"holder": "内蒙古呼籁文旅投资开发集团有限公司",
"date": "2024.08.26",
"description": "呼籁核心旅行产品品牌,2023年推出V1版本单季6000+人次,2024年V8版本接待15000+人次,持续迭代"
"description": "呼籁核心旅行产品品牌,V1至V9持续迭代"
},
{
"name": "游牧的森林",
@ -297,48 +106,106 @@
"description": "品牌IP吉祥物,含四视图、表情包、服装延展、周边延展"
}
],
"founder": {
"name": "刘涛",
"title": "呼籁旅行创始人兼CEO",
"background": "土生土长的呼伦贝尔人,深耕呼伦贝尔旅行市场多年",
"expertise": ["呼伦贝尔目的地旅游", "亲子家庭定制游", "草原自然教育"],
"yearsInHulunbuir": "11年"
"guarantees": [
{
"title": "三重旅行社资质保障",
"detail": "旗下三家公司均持有旅游经营许可证内蒙古呼籁国际旅行社有限公司、内蒙古呼籁山河国际旅行社有限公司始于2005年、内蒙古呼籁文旅投资开发集团有限公司"
},
{
"title": "旅游责任险1000万",
"detail": "全程保险覆盖,出行无忧"
},
{
"title": "正规电子合同",
"detail": "所有行程签订正规电子合同,保障游客权益"
},
{
"title": "全程无购物无隐形消费",
"detail": "费用明细清晰透明,不会中途加价"
}
],
"xiaohongshu": {
"account": "Mr.小雷-呼籁旅行",
"verified": true,
"verifiedType": "蓝V认证·旅行社",
"followers": "9.6万+",
"likes": "26万+",
"awards": [
"2025小红书年度成长型品牌",
"2026小红书WILL商业大会受邀品牌"
],
"tagline": "50万小红书家庭青睐的草原旅行品牌",
"tags": [
"只做呼伦贝尔一地的旅行公司",
"一家一单一车/私家品质小团游",
"亲子家庭游/私人定制/包车自由行"
],
"description": "呼籁旅行在小红书平台深耕呼伦贝尔亲子旅行内容,通过真实的旅行分享和攻略输出,累计获得超过26万次点赞与收藏。2025年获评小红书年度成长型品牌,是文旅行业仅6家获此荣誉的品牌之一。"
},
"team": {
"summary": "呼籁的服务采用「3管+1师+1队」全程护航模式。3管家——车务管家负责车辆调度和路线安排,房务管家负责住宿预订和品质把控,客服管家负责行前沟通和售后跟进。1定制师在出行前一对一沟通,了解家庭成员构成、孩子年龄和兴趣偏好,量身定制行程方案。1专属领队全程陪同,既是向导也是安全保障,熟悉每一条路线和每一个隐藏的美景点。旅拍部分由呼籁自营旅拍服务完成,用专业设备记录旅途中的珍贵瞬间。"
},
"culture": {
"core": "真诚·克制·年轻",
"belief": "大部分人只来一次呼伦贝尔,而这一次便是一辈子的回忆,所以我们从不敢有任何的怠慢。",
"transparency": "所有行程签订正规电子合同,费用明细清晰透明。客户可以随时在小程序查看行程安排、领队信息和紧急联系方式。",
"values": [
{
"name": "真诚",
"points": [
"对客户真诚:不隐瞒问题,不夸大承诺;遇到客户需求时能做到的尽全力去做,做不到的坦诚沟通。",
"对合作伙伴真诚:合同之外,仍坚持公平和透明,让合作更长久。",
"对同事真诚:坦诚面对分歧,不敷衍、不推诿,用真话解决真问题。"
]
"expression": "不夸大、不套路、不过度承诺。客户问什么答什么,做不到的提前说清楚。"
},
{
"name": "克制",
"points": [
"克制短视:当快速赚钱的机会摆在面前时,问自己——这会不会损害客户或公司的长远利益?",
"克制盲目扩张:每一步都建立在对资源、能力和市场的真实了解之上,而不是只靠想象。",
"克制私心:当团队需要时,先想怎么解决问题,而不是先想谁的责任。"
]
"expression": "不催单、不群发、不骚扰。相信好的产品和口碑自己会说话。"
},
{
"name": "年轻",
"points": [
"永远在创业:无论遇到什么困难,都不说\"以前是怎么做的\",而是主动问——现在还有什么办法?",
"保持年轻心态:面对新问题,不是想着\"这不是我的职责\",而是想着\"我能做些什么来帮上忙?\""
]
"expression": "保持好奇心,每年迭代产品。V1到V9,每一版都比上一版更懂家庭需要什么。"
}
],
"slogan": {
"lines": [
{ "label": "草原", "text": "记得住每一声\"呼籁\"" },
{ "label": "呼籁", "text": "却容不下\"马蹄大\"的将就" },
{ "label": "深耕", "text": "大草原家庭游" },
{ "label": "", "text": "土生土长才能护你一生一次" }
]
}
]
},
"serviceJourney": {
"title": "8个温度时刻",
"subtitle": "从第一次联系到旅行结束,每一个环节都有人在",
"moments": [
{
"step": 1,
"name": "一对一咨询",
"detail": "定制师了解家庭成员构成、孩子年龄和兴趣偏好,量身定制行程方案"
},
{
"step": 2,
"name": "方案确认",
"detail": "行程单、报价、注意事项全部书面确认,无隐藏费用"
},
{
"step": 3,
"name": "行前准备",
"detail": "出发前3天,定制师发送详细行前指南,包括穿搭、天气、携带清单"
},
{
"step": 4,
"name": "领队接机",
"detail": "专属领队提前到机场等候,全程一对一陪伴"
},
{
"step": 5,
"name": "全程陪同",
"detail": "领队既是向导也是安全保障,熟悉每一条路线和每一个隐藏的美景点"
},
{
"step": 6,
"name": "旅拍记录",
"detail": "呼籁自营旅拍服务,用专业设备记录旅途中的珍贵瞬间"
},
{
"step": 7,
"name": "送机告别",
"detail": "领队送至机场,确认安全登机后才离开"
},
{
"step": 8,
"name": "旅后回访",
"detail": "旅行结束后3天内,定制师回访收集反馈,整理照片和视频素材发送给家庭"
}
]
}
}

查看文件

@ -4,6 +4,130 @@
"season": "秋季9月中旬-10月中旬",
"narrative": "呼伦贝尔+阿尔山,是很多人一生的梦想。这里是每年中国境内最早入秋的地方之一——森林、草原、湿地、公路,绝美、震撼、火山天池、林区民俗……但很多人一生也只能来一次而已!期待通过大兴安岭秋季南北线之旅,让您和家人也爱上我的家乡,留下一生美好的回忆。",
"style": "独立成团不拼团 · 一单一车 · 随走随停 · 不错过每处风景",
"versions": [
{
"id": "autumn-south-4d3n",
"name": "游牧的森林V3·南线4天3晚",
"days": 4,
"nights": 3,
"tag": "短途版",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"audience": "假期极短但想看秋色的旅行者",
"description": "秋季南线短途版,4天时间串联呼伦贝尔草原与阿尔山秋色精华。牧云山顶赏莫日格勒河、扎罗木得断崖秋色、阿尔山国家森林公园,核心秋景一个不少。行程紧凑高效,适合假期极短但不想错过大兴安岭秋色的旅行者。",
"highlights": [
"牧云山顶赏莫日格勒河九曲十八弯",
"扎罗木得断崖秋色,24年新发掘的小众秘境",
"阿尔山国家森林公园AAAAA级景区"
],
"itinerary": []
},
{
"id": "autumn-south-5d4n",
"name": "游牧的森林V3·南线5天4晚",
"days": 5,
"nights": 4,
"tag": "经典版",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"audience": "想深度体验阿尔山秋色的家庭",
"description": "秋季南线经典版本,5天4晚从容走遍呼伦贝尔草原与阿尔山秋色。扎罗木得断崖秋野素拍、童话之城阿尔山、阿尔山国家森林公园AAAAA级、ATV卡丁车森林穿越、白狼峰日落,核心秋景与深度体验兼顾。适合想深度体验阿尔山秋色的家庭。",
"highlights": [
"扎罗木得断崖+秋野素拍,定格秋日最美瞬间",
"童话之城阿尔山+阿尔山国家森林公园AAAAA级",
"ATV卡丁车森林穿越+白狼峰日落"
],
"itinerary": [
"D1 各地→海拉尔(接机+自由闲逛)",
"D2 牧云山顶-莫日格勒河-扎罗木得断崖-秋野素拍-额尔古纳",
"D3 额尔古纳-黑山头骑马赏日落-ATV穿越湿地-阿尔山",
"D4 阿尔山国家森林公园-天池-驼峰岭天池-不冻河-白狼峰日落-阿尔山",
"D5 阿尔山-ATV卡丁车森林穿越-伊敏河湿地-海拉尔-返程"
]
},
{
"id": "autumn-south-7d6n",
"name": "游牧的森林V3·南线7天6晚",
"days": 7,
"nights": 6,
"tag": "深度版",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"audience": "假期充足想深度探索秋色的家庭",
"description": "秋季南线主推版本,7天6晚从容走遍呼伦贝尔草原与阿尔山秋色全部精华。在经典版基础上增加白桦林喂驯鹿、恩和骑马做列巴等深度体验,节奏更从容舒适。注2025年因柴河段修路无法通行,柴河月亮天池暂不包含在V3行程中,2026年V4版本将重新纳入柴河及蘑阿公路为重点线路。",
"highlights": [
"全部南线精华+更从容节奏,秋季主推版本",
"白桦林喂驯鹿+恩和骑马+做列巴",
"阿尔山国家森林公园AAAAA级+白狼峰日落"
],
"itinerary": [
"D1 各地→海拉尔",
"D2 牧云山顶-莫日格勒河-扎罗木得断崖-秋野素拍-额尔古纳",
"D3 额尔古纳-白桦林喂驯鹿-恩和骑马-画套娃做列巴-恩和",
"D4 恩和-黑山头骑马赏日落-ATV穿越五彩湿地-额尔古纳",
"D5 额尔古纳-伊敏河湿地-阿尔山",
"D6 阿尔山国家森林公园-天池-驼峰岭天池-不冻河-白狼峰日落-阿尔山",
"D7 阿尔山-ATV卡丁车森林穿越-海拉尔-返程"
]
},
{
"id": "autumn-manzhouli-south-7d6n",
"name": "游牧的森林V3·满洲里+南线7天6晚",
"days": 7,
"nights": 6,
"tag": "满洲里+南线",
"line": "满洲里+南线",
"route": "呼伦贝尔+满洲里+阿尔山",
"audience": "想同时看边境风情和阿尔山秋色的家庭",
"description": "满洲里与南线的完美结合,7天6晚同时体验中俄蒙边境风情与阿尔山金秋。满洲里套娃广场+边境风情+阿尔山秋色一网打尽,适合想一次旅行看遍呼伦贝尔秋季精华的家庭。",
"highlights": [
"满洲里套娃广场+边境异域风情",
"阿尔山国家森林公园+火山天池秋色",
"扎罗木得断崖+秋野素拍+骑马赏日落"
],
"itinerary": []
},
{
"id": "autumn-north-5d4n",
"name": "游牧的森林V3·北线5天4晚",
"days": 5,
"nights": 4,
"tag": "北线经典",
"line": "北线",
"route": "呼伦贝尔+大兴安岭",
"audience": "想深入大兴安岭腹地赏秋的旅行者",
"description": "秋季北线经典版,5天4晚深入大兴安岭腹地赏秋。大兴安岭绝美公路根白路、龙岩山公园三体雷达峰、大兴安岭深处驯鹿园、太平川古村落,感受大兴安岭最原始的秋色。适合想深入大兴安岭腹地赏秋的旅行者。",
"highlights": [
"大兴安岭绝美公路根白路,人在车中坐车在画中游",
"龙岩山公园三体雷达峰,俯瞰林区小镇全貌",
"大兴安岭深处驯鹿园+太平川古村落"
],
"itinerary": [
"D1 各地→海拉尔",
"D2 牧云山顶-莫日格勒河-扎罗木得断崖-秋野素拍-额尔古纳",
"D3 额尔古纳-白桦林喂驯鹿-恩和骑马-恩和",
"D4 恩和-室韦-太平川古村落-莫尔道嘎-龙岩山公园三体雷达峰-莫尔道嘎",
"D5 莫尔道嘎-根白路-敖鲁古雅驯鹿园-海拉尔-返程"
]
},
{
"id": "autumn-north-6d5n",
"name": "游牧的森林V3·北线6天5晚",
"days": 6,
"nights": 5,
"tag": "北线深度",
"line": "北线",
"route": "呼伦贝尔+大兴安岭",
"audience": "假期充足想更深度走北线的家庭",
"description": "秋季北线深度版,6天5晚更从容地深入大兴安岭。在北线5天基础上增加更多深度体验,节奏更舒适,每一处秋色都能细细品味。适合假期充足想更深度走北线的家庭。",
"highlights": [
"在北线5天基础上更从容,节奏更舒适",
"增加更多深度体验,细品大兴安岭秋色",
"根白路+龙岩山+驯鹿园+太平川古村落"
],
"itinerary": []
}
],
"highlights": [
{
"title": "《语文》课本中的大兴安岭",
@ -43,137 +167,13 @@
},
{
"title": "一半茫茫林海一半火山天池",
"description": "阿尔山-柴河火山带,兴安天池(状如心形)、驼峰岭天池(上帝留在大兴安岭的蓝眼泪)。"
"description": "阿尔山火山带,兴安天池(状如心形)、驼峰岭天池(上帝留在大兴安岭的蓝眼泪)。2026年V4版本将新增柴河月亮天池及蘑阿公路为重点线路。"
},
{
"title": "阿尔山国家森林公园",
"description": "内蒙古东部地区唯一的国家AAAAA级景区,森林覆盖率高达80%,秋季是阿尔山最美的时节。"
}
],
"versions": [
{
"id": "autumn-south-4d3n",
"name": "游牧的森林V3·南线4天3晚",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"days": 4,
"nights": 3,
"audience": "假期极短但想看秋色的旅行者",
"description": "秋季南线短途版,4天时间串联呼伦贝尔草原与阿尔山秋色精华。牧云山顶赏莫日格勒河、扎罗木得断崖秋色、阿尔山国家森林公园,核心秋景一个不少。行程紧凑高效,适合假期极短但不想错过大兴安岭秋色的旅行者。",
"highlights": [
"牧云山顶赏莫日格勒河九曲十八弯",
"扎罗木得断崖秋色,24年新发掘的小众秘境",
"阿尔山国家森林公园AAAAA级景区"
],
"tag": "短途版",
"itinerary": []
},
{
"id": "autumn-south-5d4n",
"name": "游牧的森林V3·南线5天4晚",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"days": 5,
"nights": 4,
"audience": "想深度体验阿尔山秋色的家庭",
"description": "秋季南线经典版本,5天4晚从容走遍呼伦贝尔草原与阿尔山秋色。扎罗木得断崖秋野素拍、童话之城阿尔山、阿尔山国家森林公园AAAAA级、ATV卡丁车森林穿越、白狼峰日落,核心秋景与深度体验兼顾。适合想深度体验阿尔山秋色的家庭。",
"highlights": [
"扎罗木得断崖+秋野素拍,定格秋日最美瞬间",
"童话之城阿尔山+阿尔山国家森林公园AAAAA级",
"ATV卡丁车森林穿越+白狼峰日落"
],
"tag": "经典版",
"itinerary": [
"D1 各地→海拉尔(接机+自由闲逛)",
"D2 牧云山顶-莫日格勒河-扎罗木得断崖-秋野素拍-额尔古纳",
"D3 额尔古纳-黑山头骑马赏日落-ATV穿越湿地-柴河/阿尔山",
"D4 阿尔山国家森林公园-天池-驼峰岭天池-不冻河-白狼峰日落-阿尔山",
"D5 阿尔山-ATV卡丁车森林穿越-伊敏河湿地-海拉尔-返程"
]
},
{
"id": "autumn-south-7d6n",
"name": "游牧的森林V3·南线7天6晚",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"days": 7,
"nights": 6,
"audience": "假期充足想深度探索秋色的家庭",
"description": "秋季南线深度版,7天6晚从容走遍呼伦贝尔草原与阿尔山秋色全部精华。在经典版基础上增加白桦林喂驯鹿、恩和骑马做列巴、柴河月亮天池等深度体验,节奏更从容舒适。适合假期充足想深度探索秋色的家庭。",
"highlights": [
"全部南线精华+更从容节奏",
"白桦林喂驯鹿+恩和骑马+做列巴",
"柴河月亮天池+同心湖,火山天池深度体验"
],
"tag": "深度版",
"itinerary": [
"D1 各地→海拉尔",
"D2 牧云山顶-莫日格勒河-扎罗木得断崖-秋野素拍-额尔古纳",
"D3 额尔古纳-白桦林喂驯鹿-恩和骑马-画套娃做列巴-恩和",
"D4 恩和-黑山头骑马赏日落-ATV穿越五彩湿地-柴河",
"D5 柴河月亮天池-同心湖-柴河",
"D6 阿尔山国家森林公园-天池-驼峰岭天池-不冻河-白狼峰日落-阿尔山",
"D7 阿尔山-ATV卡丁车森林穿越-伊敏河湿地-海拉尔-返程"
]
},
{
"id": "autumn-manzhouli-south-7d6n",
"name": "游牧的森林V3·满洲里+南线7天6晚",
"line": "满洲里+南线",
"route": "呼伦贝尔+满洲里+阿尔山",
"days": 7,
"nights": 6,
"audience": "想同时看边境风情和阿尔山秋色的家庭",
"description": "满洲里与南线的完美结合,7天6晚同时体验中俄蒙边境风情与阿尔山金秋。满洲里套娃广场+边境风情+阿尔山秋色一网打尽,适合想一次旅行看遍呼伦贝尔秋季精华的家庭。",
"highlights": [
"满洲里套娃广场+边境异域风情",
"阿尔山国家森林公园+火山天池秋色",
"扎罗木得断崖+秋野素拍+骑马赏日落"
],
"tag": "满洲里+南线",
"itinerary": []
},
{
"id": "autumn-north-5d4n",
"name": "游牧的森林V3·北线5天4晚",
"line": "北线",
"route": "呼伦贝尔+大兴安岭",
"days": 5,
"nights": 4,
"audience": "想深入大兴安岭腹地赏秋的旅行者",
"description": "秋季北线经典版,5天4晚深入大兴安岭腹地赏秋。大兴安岭绝美公路根白路、龙岩山公园三体雷达峰、大兴安岭深处驯鹿园、太平川古村落,感受大兴安岭最原始的秋色。适合想深入大兴安岭腹地赏秋的旅行者。",
"highlights": [
"大兴安岭绝美公路根白路,人在车中坐车在画中游",
"龙岩山公园三体雷达峰,俯瞰林区小镇全貌",
"大兴安岭深处驯鹿园+太平川古村落"
],
"tag": "北线经典",
"itinerary": [
"D1 各地→海拉尔",
"D2 牧云山顶-莫日格勒河-扎罗木得断崖-秋野素拍-额尔古纳",
"D3 额尔古纳-白桦林喂驯鹿-恩和骑马-恩和",
"D4 恩和-室韦-太平川古村落-莫尔道嘎-龙岩山公园三体雷达峰-莫尔道嘎",
"D5 莫尔道嘎-根白路-敖鲁古雅驯鹿园-海拉尔-返程"
]
},
{
"id": "autumn-north-6d5n",
"name": "游牧的森林V3·北线6天5晚",
"line": "北线",
"route": "呼伦贝尔+大兴安岭",
"days": 6,
"nights": 5,
"audience": "假期充足想更深度走北线的家庭",
"description": "秋季北线深度版,6天5晚更从容地深入大兴安岭。在北线5天基础上增加更多深度体验,节奏更舒适,每一处秋色都能细细品味。适合假期充足想更深度走北线的家庭。",
"highlights": [
"在北线5天基础上更从容,节奏更舒适",
"增加更多深度体验,细品大兴安岭秋色",
"根白路+龙岩山+驯鹿园+太平川古村落"
],
"tag": "北线深度",
"itinerary": []
}
],
"southHighlights": [
{
"title": "ATV卡丁车森林穿越",
@ -206,50 +206,48 @@
"description": "散发着原始氛围的小村庄,位于大兴安岭深山腹地之中,宛如世外桃源,有百年历史的老屋。"
}
],
"selectionGuide": {
"byVacationLength": [
{
"condition": "4天假期",
"recommendation": "autumn-south-4d3n",
"reason": "精华浓缩"
},
{
"condition": "5天假期想看阿尔山",
"recommendation": "autumn-south-5d4n",
"reason": "南线经典"
},
{
"condition": "5天假期想看大兴安岭",
"recommendation": "autumn-north-5d4n",
"reason": "北线经典"
},
{
"condition": "6天假期深入大兴安岭",
"recommendation": "autumn-north-6d5n",
"reason": "北线深度"
},
{
"condition": "7天假期看阿尔山",
"recommendation": "autumn-south-7d6n",
"reason": "南线深度"
},
{
"condition": "7天想看边境+阿尔山",
"recommendation": "autumn-manzhouli-south-7d6n",
"reason": "满洲里+南线"
}
]
},
"timeline": [
{
"version": "V4预告",
"date": "2026.09",
"title": "柴河+蘑阿公路将成为游牧的森林重点线路",
"changes": [
{
"text": "蘑阿公路——大兴安岭最美秋季公路正式纳入行程",
"type": "add"
},
{
"text": "2025年因柴河段修路无法通行,2026年道路修复后将全面升级南线行程",
"type": "update"
}
],
"reason": "柴河-蘑阿公路是大兴安岭秋季最壮观的公路之一,2025年修路期间暂时无法安排,2026年道路修复后将成为游牧的森林V4的核心亮点。"
},
{
"version": "V3",
"date": "2025.09",
"title": "新增短途版+满洲里版,北线扩展6天版,全线升级素拍",
"changes": [
{ "type": "add", "text": "南线新增4天3晚短途版,假期极短也能体验秋色精华" },
{ "type": "add", "text": "新增满洲里+南线7天6晚版,边境风情与阿尔山秋色一网打尽" },
{ "type": "add", "text": "北线增加6天5晚深度版,更从容地深入大兴安岭" },
{ "type": "update", "text": "全线升级素拍服务,专业户外人像摄影师定格秋日美好" }
{
"text": "南线新增4天3晚短途版,假期极短也能体验秋色精华",
"type": "add"
},
{
"text": "新增满洲里+南线7天6晚版,边境风情与阿尔山秋色一网打尽",
"type": "add"
},
{
"text": "北线增加6天5晚深度版,更从容地深入大兴安岭",
"type": "add"
},
{
"text": "2025年因柴河段修路,南线行程暂不包含柴河月亮天池",
"type": "remove"
},
{
"text": "全线升级素拍服务,专业户外人像摄影师定格秋日美好",
"type": "update"
}
],
"reason": "V2版本产品线较少,无法满足不同假期长度的客户需求。V3新增短途版和满洲里版扩大覆盖面,北线增加深度版,同时全线升级素拍服务提升体验。"
},
@ -258,9 +256,18 @@
"date": "2024.08",
"title": "新增扎罗木得断崖,升级随车备品",
"changes": [
{ "type": "remove", "text": "取消牙克石凤凰山庄景区" },
{ "type": "add", "text": "增加扎罗木得断崖观赏点,24年新发掘的小众秘境" },
{ "type": "add", "text": "增加备品三件套,提升旅途舒适度" }
{
"text": "取消牙克石凤凰山庄景区",
"type": "remove"
},
{
"text": "增加扎罗木得断崖观赏点,24年新发掘的小众秘境",
"type": "add"
},
{
"text": "增加备品三件套,提升旅途舒适度",
"type": "add"
}
],
"reason": "牙克石凤凰山庄景区体验一般,替换为24年新发掘的扎罗木得断崖,兼顾草原、湿地和白桦林多种风景,成为秋季最亮丽的名片。"
},
@ -269,13 +276,62 @@
"date": "2023.09",
"title": "游牧的森林首发·南线呼伦贝尔+阿尔山",
"changes": [
{ "type": "add", "text": "首发线路,南线呼伦贝尔+阿尔山" },
{ "type": "add", "text": "白桦林喂驯鹿,与森林中的驯鹿精灵合拍" },
{ "type": "add", "text": "阿尔山国家森林公园,大兴安岭腹地AAAAA级景区" },
{ "type": "add", "text": "白狼峰日落,藏在林海深处的小众宝藏地" },
{ "type": "add", "text": "ATV穿越湿地,穿越亚洲最大的原生草本湿地" }
{
"text": "首发线路,南线呼伦贝尔+阿尔山",
"type": "add"
},
{
"text": "白桦林喂驯鹿,与森林中的驯鹿精灵合拍",
"type": "add"
},
{
"text": "阿尔山国家森林公园,大兴安岭腹地AAAAA级景区",
"type": "add"
},
{
"text": "白狼峰日落,藏在林海深处的小众宝藏地",
"type": "add"
},
{
"text": "ATV穿越湿地,穿越亚洲最大的原生草本湿地",
"type": "add"
}
],
"reason": "呼籁深耕呼伦贝尔多年后首次推出秋季产品线。南线串联草原秋色与阿尔山火山天池,让大兴安岭的金秋不再只是一个遥远的梦想。"
}
]
}
],
"selectionGuide": {
"byVacationLength": [
{
"reason": "精华浓缩",
"condition": "4天假期",
"recommendation": "autumn-south-4d3n"
},
{
"reason": "南线经典",
"condition": "5天假期想看阿尔山",
"recommendation": "autumn-south-5d4n"
},
{
"reason": "北线经典",
"condition": "5天假期想看大兴安岭",
"recommendation": "autumn-north-5d4n"
},
{
"reason": "北线深度",
"condition": "6天假期深入大兴安岭",
"recommendation": "autumn-north-6d5n"
},
{
"reason": "南线深度",
"condition": "7天假期看阿尔山",
"recommendation": "autumn-south-7d6n"
},
{
"reason": "满洲里+南线",
"condition": "7天想看边境+阿尔山",
"recommendation": "autumn-manzhouli-south-7d6n"
}
]
}
}

查看文件

@ -3,146 +3,138 @@
{
"id": "hulunbuir-travel-guide-2026",
"title": "2026年呼伦贝尔旅游攻略第一次去必看",
"subtitle": "从出发到返程,全程干货不废话",
"subtitle": "第一次去呼伦贝尔?这篇是你需要的第一篇攻略。最佳季节、核心景点、行程天数建议、自驾vs包车对比、预算参考——全在这里,帮你少走弯路。",
"author": "呼籁旅行",
"date": "2026-03-10",
"category": "攻略",
"summary": "第一次去呼伦贝尔?本文涵盖最佳季节、核心景点、行程天数、交通方式、预算参考,帮你少走弯路,把每一天都过得值。",
"coverImage": "/images/seasons/summer-river.jpg",
"tags": ["呼伦贝尔攻略", "首次出行", "行程规划", "呼伦贝尔旅游"],
"seo": {
"title": "2026年呼伦贝尔旅游攻略第一次去必看 - 呼籁旅行",
"description": "第一次去呼伦贝尔必看攻略最佳出行季节、核心景点推荐、行程天数建议、交通方式对比、预算参考,呼籁旅行深耕11年总结的实用干货。",
"keywords": "呼伦贝尔旅游攻略,呼伦贝尔第一次去,呼伦贝尔怎么玩,呼伦贝尔旅游必看,2026呼伦贝尔"
},
"relatedProducts": ["v9-5d4n", "v9-6d5n-family"],
"content": "<h2>为什么要去呼伦贝尔?</h2><p>呼伦贝尔是中国最大的地级市,草原面积达148万平方公里,占全国草原总面积的近三分之一。这里有莫日格勒河的九曲弯,有额尔古纳湿地的晨雾,有边境公路的无尽延伸,有根河的驯鹿文化。每年6月至8月,这里是真正意义上的「绿色乌托邦」。</p><h2>最佳出行时间</h2><p>呼伦贝尔一年四季各有特色,但对于第一次来的游客,<strong>6月下旬至8月下旬</strong>是最推荐的时间窗口。这个阶段草原最绿、天气最稳定、活动最丰富。</p><ul><li><strong>6月下旬</strong>:草原刚进入旺季,游客相对少,价格较优惠,野花盛开</li><li><strong>7月全月</strong>:高峰期,景色最美,那达慕民俗活动丰富,但需提前预订</li><li><strong>8月</strong>:草场依然翠绿,进入收尾期,性价比高</li></ul><p>如果你喜欢秋色,9月的白桦林和湿地同样值得一来;冬季则适合雪原探险和冰雪那达慕。</p><h2>核心景点不能错过</h2><p>呼伦贝尔幅员辽阔,景点分布分散。以下是第一次来必须打卡的核心区域:</p><ul><li><strong>莫日格勒河</strong>:被誉为「天下第一曲水」,九曲十八弯,日出时拍照是摄影人的圣地</li><li><strong>额尔古纳湿地</strong>:国家级自然保护区,晨雾中的湿地有梦幻感</li><li><strong>中俄边境公路</strong>:沿黑山头到室韦的边境线驾车,一侧是额尔古纳河,对岸是俄罗斯</li><li><strong>呼伦湖</strong>:中国北方第一大淡水湖,落日景色壮美</li><li><strong>根河敖鲁古雅</strong>:驯鹿文化保护区,感受鄂温克族最原始的游牧生活</li></ul><h2>行程天数怎么定</h2><p>呼伦贝尔不是一个「走马观花」的目的地,建议最少安排<strong>5天4晚</strong>。如果带孩子或希望深度体验,6-7天更从容。时间紧张的朋友可以选5天4晚精华线路。</p><h2>交通方式</h2><p>从北京/上海/成都等主要城市均有直飞海拉尔(呼伦贝尔市区机场)的航班。到达后,建议选择<strong>专业包车+本地领队</strong>的方式,原因是:</p><ul><li>景点间距离动辄100-200公里,自驾路况复杂</li><li>本地领队熟悉隐藏景点和最佳拍摄时机</li><li>草原上部分区域手机信号差,导航不可靠</li></ul><h2>第一次去的注意事项</h2><p>草原的紫外线强度是城市的2-3倍,防晒是第一要务。早晚温差可达15-20℃,即使夏天也要带一件厚外套。草原上蚊虫活跃,防虫喷雾不可少。如果带孩子,骑马等活动要确认安全规范后再参与。</p><h2>预订建议</h2><p>7月旺季的行程和住宿至少提前<strong>2-3个月</strong>预订,热门日期可能更早售罄。选择有资质的本地旅行社,签订正规电子合同,避免行程缩水或临时换车换导游。呼籁旅行深耕呼伦贝尔11年,一家一单一车,是家庭出行的可靠选择。</p>"
"summary": "第一次去呼伦贝尔?这篇是你需要的第一篇攻略。最佳季节、核心景点、行程天数建议、自驾vs包车对比、预算参考——全在这里,帮你少走弯路。",
"coverImage": "/images/team/hero-grassland.jpg",
"tags": [
"呼伦贝尔攻略",
"首次出行",
"行程规划",
"呼伦贝尔旅游"
],
"content": "<h2>为什么要去呼伦贝尔?</h2><p>呼伦贝尔是中国最大的地级市,面积约25.3万平方公里,拥有中国保存最完好的天然草原之一。这里有莫日格勒河的九曲弯,有额尔古纳湿地的晨雾,有边境公路的无尽延伸,有根河的驯鹿文化。每年6月至8月,这里是真正意义上的「绿色乌托邦」。</p><h2>最佳出行时间</h2><p>呼伦贝尔一年四季各有特色,但对于第一次来的游客,<strong>6月下旬至8月下旬</strong>是最推荐的时间窗口。这个阶段草原最绿、天气最稳定、活动最丰富。</p><ul><li><strong>6月下旬</strong>:草原刚进入旺季,游客相对少,价格较优惠,野花盛开</li><li><strong>7月全月</strong>:高峰期,景色最美,那达慕民俗活动丰富,但需提前预订</li><li><strong>8月</strong>:草场依然翠绿,进入收尾期,性价比高</li></ul><p>如果你喜欢秋色,9月的白桦林和湿地同样值得一来;冬季则适合雪原探险和冰雪那达慕。</p><h2>核心景点不能错过</h2><p>呼伦贝尔幅员辽阔,景点分布分散。以下是第一次来必须打卡的核心区域:</p><ul><li><strong>莫日格勒河</strong>:被誉为「天下第一曲水」,九曲十八弯,日出时拍照是摄影人的圣地</li><li><strong>额尔古纳湿地</strong>:国家级自然保护区,晨雾中的湿地有梦幻感</li><li><strong>中俄边境公路</strong>:沿黑山头到室韦的边境线驾车,一侧是额尔古纳河,对岸是俄罗斯</li><li><strong>呼伦湖</strong>:中国北方第一大淡水湖,落日景色壮美</li><li><strong>根河敖鲁古雅</strong>:驯鹿文化保护区,感受鄂温克族最原始的游牧生活</li></ul><h2>行程天数怎么定</h2><p>呼伦贝尔不是一个「走马观花」的目的地,建议最少安排<strong>5天4晚</strong>。如果带孩子或希望深度体验,6-7天更从容。4天3晚适合二刷或时间紧张的朋友,只能走精华线路。</p><h2>交通方式</h2><p>从北京/上海/成都等主要城市均有直飞海拉尔(呼伦贝尔市区机场)的航班。到达后,建议选择<strong>专业包车+本地领队</strong>的方式,原因是:</p><ul><li>景点间距离动辄100-200公里,自驾路况复杂</li><li>本地领队熟悉隐藏景点和最佳拍摄时机</li><li>草原上部分区域手机信号差,导航不可靠</li></ul><h2>第一次去的注意事项</h2><p>草原的紫外线强度是城市的2-3倍,防晒是第一要务。早晚温差可达15-20℃,即使夏天也要带一件厚外套。草原上蚊虫活跃,防虫喷雾不可少。如果带孩子,骑马等活动要确认安全规范后再参与。</p><h2>预订建议</h2><p>7月旺季的行程和住宿至少提前<strong>2-3个月</strong>预订,热门日期可能更早售罄。选择有资质的本地旅行社,签订正规电子合同,避免行程缩水或临时换车换导游。呼籁旅行深耕呼伦贝尔11年,一家一单一车,是家庭出行的可靠选择。</p>"
},
{
"id": "hulunbuir-family-travel-guide",
"title": "呼伦贝尔亲子游完全指南:带娃怎么玩",
"subtitle": "从1岁到12岁,不同年龄段的玩法全在这里",
"subtitle": "带孩子去呼伦贝尔草原,什么年龄合适?哪些活动安全?怎么选行程?呼籁旅行11年亲子游经验,帮你把每一个细节都想清楚。",
"author": "呼籁旅行",
"date": "2026-03-05",
"category": "亲子",
"summary": "带孩子去呼伦贝尔草原,什么年龄合适?哪些活动安全?怎么选行程?呼籁旅行10年亲子游经验,帮你把每一个细节都想清楚。",
"coverImage": "/images/summer-camp/grassland-group.jpg",
"tags": ["亲子游", "带娃旅行", "草原亲子", "家庭出游"],
"seo": {
"title": "呼伦贝尔亲子游完全指南:带娃怎么玩 - 呼籁旅行",
"description": "呼伦贝尔亲子游完全指南各年龄段活动推荐、亲子行程天数、安全注意事项、儿童餐饮住宿,呼籁旅行10年亲子游经验整理。",
"keywords": "呼伦贝尔亲子游,带娃去草原,呼伦贝尔儿童旅游,草原亲子活动,呼伦贝尔家庭游"
},
"relatedProducts": ["v9-6d5n-family", "v9-7d6n-family"],
"content": "<h2>呼伦贝尔适合多大孩子?</h2><p>这是父母们最常问的问题。答案是:<strong>基本上没有年龄下限</strong>,但不同年龄段的体验侧重点不同。我们服务过最小3个月的宝宝,也服务过带14岁少年来「二刷」的家庭。</p><ul><li><strong>0-2岁</strong>:以草原感受为主,大自然的声音、空气和视野对宝宝的感官发育有积极意义。骑马等活动不参与,以看为主。</li><li><strong>3-5岁</strong>:可以体验套马杆、接触马匹、参与奶制品制作,是最容易被草原「征服」的年龄段。</li><li><strong>6-10岁</strong>:黄金亲子年龄,骑马、越野车、篝火晚会、学蒙古语,每个环节都充满好奇心和参与热情。</li><li><strong>11岁以上</strong>体力充沛,可以挑战ATV、越野徒步,独立拍照,开始建立属于自己的旅行记忆。</li></ul><h2>亲子游必体验活动TOP 5</h2><p><strong>1. 草原骑马</strong><br/>这是孩子们最期待的活动。建议选择有专业牵马师陪同的体验,而非放任独骑。正规的亲子骑马会为孩子配备头盔和安全背心,牵马师全程陪伴。</p><p><strong>2. 挤牛奶·做奶制品</strong><br/>去牧民家体验传统奶制品制作:手工奶酪、酸奶、黄油。孩子通过亲手操作,理解食物从哪里来,是自然教育的绝佳场景。</p><p><strong>3. 篝火晚会</strong><br/>夏夜草原的篝火晚会是行程高潮。蒙古族歌手现场演唱,孩子们学跳安代舞,手持火把绕圈,在黑色天幕和满天星辰下留下一生难忘的记忆。</p><p><strong>4. 捡牛粪·认植物</strong><br/>这是我们专为亲子家庭设计的自然教育环节。草原上有200余种野花,牧民带孩子认识常见草本植物,讲解草原生态。</p><p><strong>5. 边境公路探秘</strong><br/>从室韦到黑山头的边境公路全程约200公里,孩子趴在车窗上看对岸的俄罗斯小屋,听领队讲两岸的历史故事,地理课在真实场景中发生。</p><h2>亲子行程怎么选</h2><p>建议带孩子至少安排<strong>6天5晚</strong>,这样行程节奏从容,孩子不会因赶路而疲惫。7天6晚亲子版则可以增加深度体验环节,例如驯鹿基地参观和湿地探秘。</p><p>避免选择强调「效率」的快行程,草原旅行的意义在于让孩子有足够时间在一片草地上发呆、跑动、和牧民家的狗玩耍——这些「无意义」的时间,往往是他们记忆最深的片段。</p><h2>住宿与饮食</h2><p>呼籁旅行的自有营地提供亲子友好的蒙古包住宿,内置独立卫浴,不必担心如厕问题。营地备有儿童餐,对食材过敏的家庭请提前告知定制师。草原的饮食以牛羊肉为主,挑食的孩子可以准备一些备用零食。</p><h2>安全保障</h2><p>选择有资质的旅行社是保障安全的第一步。呼籁旅行为每位游客购买旅行意外险,专业领队均接受过急救培训,骑马等高风险活动全程配备专业人员。草原紫外线强,儿童防晒霜建议每2小时补涂一次。</p>"
"summary": "带孩子去呼伦贝尔草原,什么年龄合适?哪些活动安全?怎么选行程?呼籁旅行11年亲子游经验,帮你把每一个细节都想清楚。",
"coverImage": "/images/team/hero-family.jpg",
"tags": [
"亲子游",
"带娃旅行",
"草原亲子",
"家庭出游"
],
"content": "<h2>呼伦贝尔适合多大孩子?</h2><p>这是父母们最常问的问题。答案是:<strong>基本上没有年龄下限</strong>,但不同年龄段的体验侧重点不同。我们服务过最小3个月的宝宝,也服务过带14岁少年来「二刷」的家庭。</p><ul><li><strong>0-2岁</strong>:以草原感受为主,大自然的声音、空气和视野对宝宝的感官发育有积极意义。骑马等活动不参与,以看为主。</li><li><strong>3-5岁</strong>:可以体验套马杆、接触马匹、参与奶制品制作,是最容易被草原「征服」的年龄段。</li><li><strong>6-10岁</strong>:黄金亲子年龄,骑马、越野车、篝火晚会、学蒙古语,每个环节都充满好奇心和参与热情。</li><li><strong>11岁以上</strong>体力充沛,可以挑战ATV、越野徒步,独立拍照,开始建立属于自己的旅行记忆。</li></ul><h2>亲子游必体验活动TOP 5</h2><p><strong>1. 草原骑马</strong><br/>这是孩子们最期待的活动。建议选择有专业牵马师陪同的体验,而非放任独骑。正规的亲子骑马会为孩子配备头盔和安全背心,牵马师全程陪伴。</p><p><strong>2. 挤牛奶·做奶制品</strong><br/>去牧民家体验传统奶制品制作:手工奶酪、酸奶、黄油。孩子通过亲手操作,理解食物从哪里来,是自然教育的绝佳场景。</p><p><strong>3. 篝火晚会</strong><br/>夏夜草原的篝火晚会是行程高潮。蒙古族歌手现场演唱,孩子们学跳安代舞,手持火把绕圈,黑色天幕和满天星辰——这个画面,孩子长大后不会忘。</p><p><strong>4. 捡牛粪·认植物</strong><br/>这是我们专为亲子家庭设计的自然教育环节。草原上有200余种野花,牧民带孩子认识常见草本植物,讲解草原生态。</p><p><strong>5. 边境公路探秘</strong><br/>从室韦到黑山头的边境公路全程约200公里,孩子趴在车窗上看对岸的俄罗斯小屋,听领队讲两岸的历史故事,地理课在真实场景中发生。</p><h2>亲子行程怎么选</h2><p>建议带孩子至少安排<strong>6天5晚</strong>,这样行程节奏从容,孩子不会因赶路而疲惫。7天6晚亲子版则可以增加深度体验环节,例如驯鹿基地参观和湿地探秘。</p><p>避免选择强调「效率」的快行程,草原旅行的意义在于让孩子有足够时间在一片草地上发呆、跑动、和牧民家的狗玩耍——这些「无意义」的时间,往往是他们记忆最深的片段。</p><h2>住宿与饮食</h2><p>呼籁旅行的自有营地提供亲子友好的蒙古包住宿,内置独立卫浴,不必担心如厕问题。营地备有儿童餐,对食材过敏的家庭请提前告知定制师。草原的饮食以牛羊肉为主,挑食的孩子可以准备一些备用零食。</p><h2>安全保障</h2><p>选择有资质的旅行社是保障安全的第一步。呼籁旅行为每位游客购买旅行意外险,专业领队均接受过急救培训,骑马等高风险活动全程配备专业人员。草原紫外线强,儿童防晒霜建议每2小时补涂一次。</p>"
},
{
"id": "hulunbuir-best-month-to-visit",
"title": "呼伦贝尔几月份去最好?月份对比全解析",
"subtitle": "12个月气候数据 + 景色特点 + 旅行者真实反馈",
"subtitle": "春夏秋冬各有千秋,但不同月份的差异远比你想象得大。本文用数据说话,帮你选出最适合自己的出行时间。",
"author": "呼籁旅行",
"date": "2026-02-28",
"category": "攻略",
"summary": "春夏秋冬各有千秋,但不同月份的差异远比你想象得大。本文用数据说话,帮你选出最适合自己的出行时间。",
"coverImage": "/images/seasons/autumn-lake.jpg",
"tags": ["出行时间", "季节推荐", "气候攻略", "呼伦贝尔旅游"],
"seo": {
"title": "呼伦贝尔几月份去最好?四季月份对比全解析 - 呼籁旅行",
"description": "呼伦贝尔几月份去最好?本文详细对比1-12月气候、草原状态、景色特点和适合人群,帮你找到最适合自己的出行时间窗口。",
"keywords": "呼伦贝尔几月份去最好,呼伦贝尔最佳旅游季节,呼伦贝尔几月去,呼伦贝尔旅游旺季,呼伦贝尔气候"
},
"relatedProducts": ["v9-5d4n", "v9-6d5n-family", "v9-6d5n-comfort"],
"content": "<h2>一句话结论</h2><p>如果只能给一个答案:<strong>7月中旬至8月上旬</strong>是综合体验最好的时间段——草最绿、天最蓝、活动最丰富。但这也是最贵、最挤的时候。根据你的出行目的、预算和喜好,不同月份各有优势。</p><h2>各月份详细解析</h2><h3>5月草原刚苏醒,人少价低</h3><p>5月气温回升,草原开始泛绿,但草色尚浅,偶尔还有寒潮。适合摄影爱好者追逐「初绿」感,以及预算有限的旅行者。日均气温10-18℃,晚上仍需厚外套。</p><h3>6月野花最盛,性价比之王</h3><p>6月草原进入盛放期,各色野花铺满大地,是全年最适合摄影的月份之一。游客量约为7月的60%,价格相对低15-20%。日均气温18-24℃,天气舒适。<strong>强烈推荐</strong>不赶热闹、喜欢自然的旅行者。</p><h3>7月旺季高峰,景色最美</h3><p>7月草原达到一年中最高颜值。7月中下旬那达慕期间民俗活动丰富,是体验蒙古族文化的最佳时机。日均气温22-28℃。缺点预订需提前2-3个月,价格为全年最高。</p><h3>8月旺季收尾,从容出行</h3><p>8月上旬草色仍旺,中旬开始草色转黄。游客量逐渐减少,各类资源预订难度下降。日均气温18-25℃。适合不想在旺季挤着玩又想看到绿草的家庭。</p><h3>9月秋叶金黄,大兴安岭最美</h3><p>9月呼伦贝尔的重心从草原转向森林。大兴安岭白桦林金黄,额尔古纳湿地芦苇变金,莫尔道嘎国家森林公园层林尽染。是秋色爱好者和摄影人的首选月份。气温10-18℃,早晚凉,穿着要比夏季厚一层。</p><h3>10月初雪来临,草原转入休眠</h3><p>10月中下旬开始降雪,草原景观结束,进入「雪原模式」。适合喜欢人迹罕至、想看初雪草原的探险旅行者。非常规旅游旺季,部分营地已关闭。</p><h3>11月至次年2月冰雪季,独特体验</h3><p>呼伦贝尔冬季最低气温可达-40℃,是中国最冷地区之一。但这里也是国内冰雪体验最丰富的目的地冰雪那达慕、驯鹿文化、雾凇奇景、冰上车队。适合追求极致体验、耐寒能力强的旅行者。</p><h3>3-4月不推荐</h3><p>春季融雪期,道路泥泞,草原泥泞,景色荒芜,是一年中最不适合旅游的时段。</p><h2>按人群推荐</h2><ul><li><strong>亲子家庭6-12岁孩子</strong>7月旺季,活动最丰富</li><li><strong>亲子家庭3-5岁孩子</strong>6月末或8月,天气舒适节奏慢</li><li><strong>摄影爱好者</strong>6月野花期或9月秋色期</li><li><strong>预算有限</strong>6月上旬或8月下旬</li><li><strong>冰雪体验</strong>1月,冰雪活动最丰富</li><li><strong>避开人群</strong>6月上旬,景美人少</li></ul><h2>总结</h2><p>没有「最好」的月份,只有「最适合你」的月份。建议结合自己的行程安排、孩子年龄和旅行目的综合判断。如果拿不定主意,欢迎联系呼籁旅行的定制师,我们会根据你的具体情况给出最适合的建议。</p>"
"coverImage": "/images/team/hero-grassland.jpg",
"tags": [
"出行时间",
"季节推荐",
"气候攻略",
"呼伦贝尔旅游"
],
"content": "<h2>一句话结论</h2><p>如果只能给一个答案:<strong>7月中旬至8月上旬</strong>是综合体验最好的时间段——草最绿、天最蓝、活动最丰富。但这也是最贵、最挤的时候。根据你的出行目的、预算和喜好,不同月份各有优势。</p><h2>各月份详细解析</h2><h3>5月草原刚苏醒,人少价低</h3><p>5月气温回升,草原开始泛绿,但草色尚浅,偶尔还有寒潮。适合摄影爱好者追逐「初绿」感,以及预算有限的旅行者。日均气温10-18℃,晚上仍需厚外套。</p><h3>6月野花最盛,性价比之王</h3><p>6月草原进入盛放期,各色野花铺满大地,是全年最适合摄影的月份之一。游客量约为7月的60%,价格相对低15-20%。日均气温18-24℃,天气舒适。<strong>强烈推荐</strong>不赶热闹、喜欢自然的旅行者。</p><h3>7月旺季高峰,景色最美</h3><p>7月草原达到一年中最高颜值。7月中下旬那达慕期间民俗活动丰富,是体验蒙古族文化的最佳时机。日均气温22-28℃。缺点预订需提前2-3个月,价格为全年最高。</p><h3>8月旺季收尾,从容出行</h3><p>8月上旬草色仍旺,中旬开始草色转黄。游客量逐渐减少,各类资源预订难度下降。日均气温18-25℃。适合不想在旺季挤着玩又想看到绿草的家庭。</p><h3>9月秋叶金黄,大兴安岭最美</h3><p>9月呼伦贝尔的重心从草原转向森林。大兴安岭白桦林金黄,额尔古纳湿地芦苇变金,莫尔道嘎国家森林公园层林尽染。是秋色爱好者和摄影人的推荐月份。气温10-18℃,早晚凉,穿着要比夏季厚一层。</p><h3>10月初雪来临,草原转入休眠</h3><p>10月中下旬开始降雪,草原景观结束,进入「雪原模式」。适合喜欢人迹罕至、想看初雪草原的探险旅行者。非常规旅游旺季,部分营地已关闭。</p><h3>11月至次年2月冰雪季,另一个呼伦贝尔</h3><p>呼伦贝尔冬季最低气温可达-40℃,是中国最冷地区之一。但这里也是国内冰雪体验最丰富的目的地冰雪那达慕、驯鹿文化、雾凇奇景、冰上车队。适合追求极致体验、耐寒能力强的旅行者。</p><h3>3-4月不推荐</h3><p>春季融雪期,道路泥泞,草原泥泞,景色荒芜,是一年中最不适合旅游的时段。</p><h2>按人群推荐</h2><ul><li><strong>亲子家庭6-12岁孩子</strong>7月旺季,活动最丰富</li><li><strong>亲子家庭3-5岁孩子</strong>6月末或8月,天气舒适节奏慢</li><li><strong>摄影爱好者</strong>6月野花期或9月秋色期</li><li><strong>预算有限</strong>6月上旬或8月下旬</li><li><strong>冰雪体验</strong>1月,冰雪活动最丰富</li><li><strong>避开人群</strong>6月上旬,景美人少</li></ul><h2>总结</h2><p>没有「最好」的月份,只有「最适合你」的月份。建议结合自己的行程安排、孩子年龄和旅行目的综合判断。如果拿不定主意,欢迎联系呼籁旅行的定制师,我们会根据你的具体情况给出最适合的建议。</p>"
},
{
"id": "hulunbuir-self-drive-vs-chartered-bus",
"title": "呼伦贝尔自驾vs包车哪种方式更适合你",
"subtitle": "深度对比两种出行方式的优劣势,一次性说清楚",
"subtitle": "呼伦贝尔自驾还是包车,这个问题困扰着大多数第一次去的旅行者。本文从路况、费用、自由度、安全性四个维度全面对比。",
"author": "呼籁旅行",
"date": "2026-02-20",
"category": "攻略",
"summary": "呼伦贝尔自驾还是包车,这个问题困扰着大多数第一次去的旅行者。本文从路况、费用、自由度、安全性四个维度全面对比。",
"coverImage": "/images/seasons/summer-car.jpg",
"tags": ["自驾攻略", "包车攻略", "交通方式", "呼伦贝尔旅游"],
"seo": {
"title": "呼伦贝尔自驾vs包车哪个好?深度对比分析 - 呼籁旅行",
"description": "呼伦贝尔自驾还是包车?本文从路况复杂度、费用对比、安全性、自由度、适合人群五个维度深度对比,帮你做出最适合的选择。",
"keywords": "呼伦贝尔自驾,呼伦贝尔包车,呼伦贝尔自驾攻略,呼伦贝尔包车价格,呼伦贝尔怎么去"
},
"relatedProducts": ["v9-5d4n", "v9-6d5n-comfort", "v9-7d6n-wild"],
"coverImage": "/images/team/hero-grassland.jpg",
"tags": [
"自驾攻略",
"包车攻略",
"交通方式",
"呼伦贝尔旅游"
],
"content": "<h2>先说结论</h2><p>对于第一次去呼伦贝尔、带有孩子或老人的家庭旅行者,<strong>包车+本地领队</strong>是更优解。有越野经验、团队人数较多6人以上、追求极致自由的旅行者可以考虑自驾。</p><h2>路况:草原路不是你想象的样子</h2><p>很多人以为呼伦贝尔只是开车在草原上走走,实际上情况复杂得多:</p><ul><li>海拉尔到草原核心区的距离超过150公里,全程以国省道为主,部分路段没有护栏</li><li>莫日格勒河观景台需要走无导航的草地便道,雨后极易陷车</li><li>从室韦到黑山头的边境公路全长约200公里,途中加油站极少</li><li>9月以后部分路段开始结冰,对驾驶技术要求高</li><li>草原无信号区域手机导航失效,需要提前下载离线地图</li></ul><p>这些问题对有经验的自驾游客不构成障碍,但对普通家庭旅行者而言风险较高。</p><h2>费用对比</h2><p><strong>自驾费用</strong>以5天为例,2大2小</p><ul><li>租车费约600-900元/天,5天约3000-4500元</li><li>油费约800-1200元</li><li>停车+景区内摆渡车约500元</li><li>合计约4300-6200元不含住宿餐饮</li></ul><p><strong>包车费用</strong>(同等行程):</p><ul><li>含专业领队+7座商务车约800-1200元/天,5天约4000-6000元</li><li>包含:全程接送、景区讲解、行程规划、应急协调</li></ul><p>费用相差不大,但包车额外包含了专业服务价值。</p><h2>自由度</h2><p>自驾最大的优势是时间完全自由——想在哪个路边停就停,想在哪个景点多待就多待,不必配合其他人的节奏。这对摄影发烧友尤其重要,追光追云需要极大的时间弹性。</p><p>但包车并非完全不自由。选择优质旅行社的私家包车(一家一单),你同样可以提出自己的节奏要求,领队会配合调整。</p><h2>安全性</h2><p>草原上的安全隐患不止于交通。本地领队了解哪片草场近期有狼群活动,知道哪个景点的悬崖边栏杆不稳,在应急情况下(陷车、孩子受伤、天气突变)能快速调动本地资源。这是任何导航软件都无法替代的本地经验。</p><h2>适合自驾的情况</h2><ul><li>旅行团有越野车经验丰富的驾驶员</li><li>人数6人以上,摊薄成本</li><li>行程以摄影为主,需要极大的时间弹性</li><li>有呼伦贝尔旅行经验(二刷以上)</li></ul><h2>适合包车的情况</h2><ul><li>第一次去,不熟悉路线</li><li>带孩子或老人,安全优先</li><li>行程天数有限,希望效率最高</li><li>想深度了解本地文化,需要领队讲解</li><li>4人以下家庭,自驾反而更贵</li></ul><h2>选包车的关键:怎么选靠谱的</h2><p>包车最大的坑在于「人头团」——名义上包车,实际上拼车,或者中途换车换领队。选择包车要注意:签订正规合同、确认是否一家一单、确认车辆型号和领队信息。呼籁旅行提供「一家一单一车」的私家定制,从签约到结束同一个领队全程陪同,这是我们的核心承诺。</p>"
},
{
"id": "hulunbuir-travel-cost-breakdown",
"title": "呼伦贝尔旅行花费明细:玩一趟到底要多少钱",
"subtitle": "5天4晚全家游真实预算,每一笔钱都说清楚",
"subtitle": "呼伦贝尔一趟到底花多少钱?本文拆解机票、住宿、交通、餐饮、活动、购物各项费用,给出高中低三档真实预算参考。",
"author": "呼籁旅行",
"date": "2026-02-15",
"category": "攻略",
"summary": "呼伦贝尔一趟到底花多少钱?本文拆解机票、住宿、交通、餐饮、活动、购物各项费用,给出高中低三档真实预算参考。",
"coverImage": "/images/seasons/summer-hero.jpg",
"tags": ["旅游花费", "预算攻略", "性价比", "呼伦贝尔费用"],
"seo": {
"title": "呼伦贝尔旅行花费多少钱?2026年真实预算明细 - 呼籁旅行",
"description": "2026年呼伦贝尔旅行花费明细机票、住宿、定制游套餐、餐饮、景点费用逐项拆解,高中低三档预算参考,4人家庭出行真实花费。",
"keywords": "呼伦贝尔旅游费用,呼伦贝尔旅游多少钱,呼伦贝尔花费,呼伦贝尔旅游预算,呼伦贝尔定制游价格"
},
"relatedProducts": ["v9-5d4n-forest", "v9-5d4n-prairie", "v9-6d5n-family"],
"content": "<h2>先说总数</h2><p>以2大2小4-10岁孩子5天4晚为例,<strong>中档出行总预算约15000-22000元</strong>,人均约3750-5500元。预算差异主要来自机票舱位、住宿档次和是否选择旺季出行。</p><h2>机票费用</h2><p>北京/上海至海拉尔HLD直飞约2.5小时,无直飞城市需转机。</p><ul><li><strong>经济舱</strong>北京出发来回约800-1500元/人,视旺淡季波动较大</li><li><strong>商务舱</strong>约3000-5000元/人</li><li><strong>提前预订建议</strong>7月旺季至少提前2个月订票,可省20-30%</li><li>4人家庭机票合计约3200-6000元经济舱</li></ul><h2>定制游套餐费用</h2><p>选择呼籁旅行的定制游套餐,包含车辆、领队、大部分景区门票和营地住宿:</p><ul><li><strong>5天4晚</strong>约7000-8500元/人(视版本和人数)</li><li><strong>6天5晚亲子版</strong>约8500-10000元/人</li></ul><p>套餐包含专属领队、7座商务车、自有营地住宿含早餐、主要景区门票、部分活动费用。</p><h2>额外活动费用</h2><p>套餐外的自费活动参考价(旺季):</p><ul><li>骑马体验30分钟80-150元/人</li><li>ATV/越野摩托200-400元/组</li><li>热气球部分区域400-600元/人</li><li>驯鹿基地参观80元/人</li></ul><p>建议提前了解套餐包含哪些活动,避免到现场发现核心项目都要单独付费。</p><h2>餐饮费用</h2><p>草原上的饮食选择相对有限。住宿套餐一般含早餐,午晚餐需自理或选择套餐附带版本。</p><ul><li>牧民家就餐(手把肉+奶茶+各类奶制品约100-150元/人</li><li>海拉尔市区餐厅约60-100元/人</li><li>景区附近餐厅质量参差,约80-120元/人</li><li>5天餐饮合计午晚餐约1500-2500元4人家庭</li></ul><h2>购物费用</h2><p>呼伦贝尔特产推荐风干牛肉、马奶酒、风干羊腿、各类奶制品、蒙古族手工艺品。预算控制在500-1500元较为合理,注意辨别正规商家,避免购买过度加工的旅游纪念品。</p><h2>三档预算汇总4人家庭,5天4晚</h2><ul><li><strong>经济档</strong>淡季6月,拼房/民宿约12000-16000元</li><li><strong>舒适档</strong>旺季7月,包车定制游约18000-25000元</li><li><strong>品质档</strong>旺季7月,商务舱+高端住宿约30000-40000元</li></ul><h2>省钱小技巧</h2><ul><li>淡旺季差价约20-30%,6月或8月出行可节省不少</li><li>提前3个月预订机票,通常比临时订便宜30%以上</li><li>儿童优惠大部分景区12岁以下半价或免票,提前了解政策</li><li>选择套餐含活动的版本,比散拼更划算</li></ul>"
"coverImage": "/images/team/hero-family.jpg",
"tags": [
"旅游花费",
"预算攻略",
"性价比",
"呼伦贝尔费用"
],
"content": "<h2>先说总数</h2><p>以2大2小4-10岁孩子5天4晚为例,<strong>中档出行总预算约15000-22000元</strong>,人均约3750-5500元。预算差异主要来自机票舱位、住宿档次和是否选择旺季出行。</p><h2>机票费用</h2><p>北京/上海至海拉尔HLD直飞约2.5小时,无直飞城市需转机。</p><ul><li><strong>经济舱</strong>北京出发来回约800-1500元/人,视旺淡季波动较大</li><li><strong>商务舱</strong>约3000-5000元/人</li><li><strong>提前预订建议</strong>7月旺季至少提前2个月订票,可省20-30%</li><li>4人家庭机票合计约3200-6000元经济舱</li></ul><h2>定制游套餐费用</h2><p>选择呼籁旅行的定制游套餐,包含车辆、领队、大部分景区门票和营地住宿:</p><ul><li><strong>4天3晚</strong>约5800-7200元/人(视版本和人数)</li><li><strong>5天4晚</strong>约7000-8500元/人</li><li><strong>6天5晚亲子版</strong>约8500-10000元/人</li></ul><p>套餐包含专属领队、7座商务车、自有营地住宿含早餐、主要景区门票、部分活动费用。</p><h2>额外活动费用</h2><p>套餐外的自费活动参考价(旺季):</p><ul><li>骑马体验30分钟80-150元/人</li><li>ATV/越野摩托200-400元/组</li><li>热气球部分区域400-600元/人</li><li>驯鹿基地参观80元/人</li></ul><p>建议提前了解套餐包含哪些活动,避免到现场发现核心项目都要单独付费。</p><h2>餐饮费用</h2><p>草原上的饮食选择相对有限。住宿套餐一般含早餐,午晚餐需自理或选择套餐附带版本。</p><ul><li>牧民家就餐(手把肉+奶茶+各类奶制品约100-150元/人</li><li>海拉尔市区餐厅约60-100元/人</li><li>景区附近餐厅质量参差,约80-120元/人</li><li>5天餐饮合计午晚餐约1500-2500元4人家庭</li></ul><h2>购物费用</h2><p>呼伦贝尔特产推荐风干牛肉、马奶酒、风干羊腿、各类奶制品、蒙古族手工艺品。预算控制在500-1500元较为合理,注意辨别正规商家,避免购买过度加工的旅游纪念品。</p><h2>三档预算汇总4人家庭,5天4晚</h2><ul><li><strong>经济档</strong>淡季6月,拼房/民宿约12000-16000元</li><li><strong>舒适档</strong>旺季7月,包车定制游约18000-25000元</li><li><strong>品质档</strong>旺季7月,商务舱+高端住宿约30000-40000元</li></ul><h2>省钱小技巧</h2><ul><li>淡旺季差价约20-30%,6月或8月出行可节省不少</li><li>提前3个月预订机票,通常比临时订便宜30%以上</li><li>儿童优惠大部分景区12岁以下半价或免票,提前了解政策</li><li>选择套餐含活动的版本,比散拼更划算</li></ul>"
},
{
"id": "hulunbuir-travel-with-toddlers-4-6",
"title": "带4-6岁孩子去草原的注意事项",
"subtitle": "这个年龄最好玩也最需要细心,每个注意事项都是真实经验",
"subtitle": "4-6岁是孩子最适合初次体验草原的年龄段,好奇心旺盛但自我保护能力弱。这篇文章总结了11年来服务这个年龄段孩子的所有注意事项。",
"author": "呼籁旅行",
"date": "2026-02-10",
"category": "亲子",
"summary": "4-6岁是孩子最适合初次体验草原的年龄段,好奇心旺盛但自我保护能力弱。这篇文章总结了10年来服务这个年龄段孩子的所有注意事项。",
"coverImage": "/images/summer-camp/birch-group.jpg",
"tags": ["4-6岁", "幼童旅行", "亲子注意事项", "安全出行"],
"seo": {
"title": "带4-6岁孩子去呼伦贝尔草原注意事项 - 呼籁旅行",
"description": "带4-6岁孩子去呼伦贝尔草原需要注意什么?安全活动选择、饮食注意、晒伤防护、行程节奏,呼籁旅行10年亲子服务经验总结。",
"keywords": "带小孩去草原注意事项,4岁孩子草原旅游,6岁草原旅行,幼童呼伦贝尔,亲子草原安全"
},
"relatedProducts": ["v9-6d5n-family", "v9-7d6n-family"],
"summary": "4-6岁是孩子最适合初次体验草原的年龄段,好奇心旺盛但自我保护能力弱。这篇文章总结了11年来服务这个年龄段孩子的所有注意事项。",
"coverImage": "/images/team/hero-family.jpg",
"tags": [
"4-6岁",
"幼童旅行",
"亲子注意事项",
"安全出行"
],
"content": "<h2>为什么4-6岁特别适合草原初体验</h2><p>心理学研究表明,3-6岁是儿童自然依恋期的关键窗口。在这个阶段接触大自然,对孩子的感知发育、情绪调节和环境认知有深远影响。草原的开阔空间、野生动植物、以及与城市截然不同的生活方式,对这个年龄段的孩子有天然的吸引力。但同时,4-6岁孩子的自我保护意识尚未成熟,需要大人更细心的陪伴和防护。</p><h2>安全第一:哪些活动可以参与</h2><p><strong>推荐参与:</strong></p><ul><li>骑马体验(由专业牵马师全程陪同,配备儿童头盔和安全背心)</li><li>接触牧民家的温顺马匹和羊群</li><li>奶制品制作体验</li><li>草地自由玩耍、捉昆虫、认植物</li><li>篝火晚会观看距火堆保持2米以上</li><li>湿地木栈道参观</li></ul><p><strong>不推荐参与:</strong></p><ul><li>ATV全地形越野车最低年龄要求通常为12岁</li><li>快速骑马(无牵马师陪同的自由骑乘)</li><li>深水区游泳</li><li>夜间单独户外活动</li></ul><h2>防晒是头等大事</h2><p>草原海拔约600-800米,加上没有城市遮蔽物,紫外线强度是城市的2-3倍。4-6岁孩子皮肤薄、防晒能力弱,晒伤在草原上非常常见。</p><ul><li>选择SPF50+、PA+++的儿童专用防晒霜</li><li>每隔2小时补涂一次,游泳或出汗后立即补涂</li><li>上午10点至下午3点是UV最强时段,尽量避免长时间在无遮蔽处活动</li><li>备好遮阳帽大帽沿款、防晒衣、太阳镜儿童专用UV防护款</li></ul><h2>饮食注意事项</h2><p>草原的饮食以牛羊肉为主,酸奶、奶茶、奶豆腐等奶制品是当地特色。几点注意:</p><ul><li>如果孩子对牛奶蛋白过敏,务必提前告知领队</li><li>蒙古奶茶含有奶和砖茶,首次尝试给孩子少量品尝</li><li>草原上的生水不可饮用,全程饮用瓶装水或自带滤水</li><li>备好孩子平时爱吃的零食,避免因不适应当地食物而挨饿</li><li>手把肉(煮羊腿)是当地特色,可以让孩子尝试,但注意骨头</li></ul><h2>行程节奏的把握</h2><p>4-6岁孩子每天有效活动时间约4-6小时,之后需要午休。建议行程安排</p><ul><li>上午安排主要景点或活动(精力最旺盛)</li><li>下午安排轻松项目或营地自由活动</li><li>避免连续多天长途驾车每天车程控制在3小时以内</li><li>每天保证10小时左右睡眠草原空气好,孩子睡得深</li></ul><h2>常见突发状况处理</h2><p><strong>蚊虫叮咬</strong>草原蚊虫活跃,出发前涂抹含DEET或派卡瑞丁的儿童驱蚊产品。被叮咬后用冰块冷敷,切勿让孩子抓挠。</p><p><strong>感冒发烧</strong>早晚温差大,备好儿童退烧药和感冒药。若发烧超过38.5℃,需及时就医(海拉尔有三甲医院)。</p><p><strong>晕车</strong>草原路颠簸,晕车的孩子出发前1小时服用晕车药,行程中准备好塑料袋。</p><p><strong>皮肤过敏</strong>:草原花粉较多,有过敏体质的孩子备好抗组胺药物,出门戴口罩。</p><h2>一句话总结</h2><p>带4-6岁孩子去草原,做好防晒、管好饮食、控制节奏,其余的交给草原——孩子对自然的好奇心会帮你完成剩下的事情。</p>"
},
{
"id": "hulunbuir-travel-tips-avoid-pitfalls",
"title": "呼伦贝尔避坑指南:这些坑千万别踩",
"subtitle": "10年接待10000+组家庭,帮你归纳出最高频的旅行陷阱",
"subtitle": "呼伦贝尔旅游的坑不少:强制购物、人头拼团、低价陷阱、景区宰客……这篇避坑指南帮你把雷都踩在出发之前。",
"author": "呼籁旅行",
"date": "2026-01-25",
"category": "避坑",
"summary": "呼伦贝尔旅游的坑不少:强制购物、人头拼团、低价陷阱、景区宰客……这篇避坑指南帮你把雷都踩在出发之前。",
"coverImage": "/images/team/campsite-team.jpg",
"tags": ["避坑指南", "旅游陷阱", "消费提醒", "呼伦贝尔旅游"],
"seo": {
"title": "呼伦贝尔旅游避坑指南10大常见陷阱完整解析 - 呼籁旅行",
"description": "呼伦贝尔旅游避坑必看低价团陷阱、人头团、强制购物、景区宰客、住宿虚假宣传……10大高频坑位逐一解析,附辨别方法。",
"keywords": "呼伦贝尔旅游避坑,呼伦贝尔旅游陷阱,呼伦贝尔旅游注意事项,呼伦贝尔旅游黑心导游,呼伦贝尔避雷"
},
"relatedProducts": ["v9-5d4n", "v9-6d5n-family"],
"coverImage": "/images/team/hero-grassland.jpg",
"tags": [
"避坑指南",
"旅游陷阱",
"消费提醒",
"呼伦贝尔旅游"
],
"content": "<h2>坑一:低价团,行程缩水</h2><p>在各大平台搜索「呼伦贝尔旅游」,会出现标价极低的产品,比市场均价低30-50%。这类产品的常见套路:</p><ul><li>核心景点(如边境公路、室韦)被删减</li><li>住宿缩水,从营地换成郊区普通宾馆</li><li>强制购物停留时间长、自费活动多</li><li>领队专业度差,纯跑路</li></ul><p><strong>辨别方法</strong>:对比行程中是否包含室韦/黑山头边境公路、自有营地住宿、额尔古纳湿地等核心节点。正规套餐不会比市场均价低超过15%。</p><h2>坑二:人头拼团,冒充私家团</h2><p>很多旅行社打着「私家包车」的旗号,实际是把多组家庭拼在同一辆车上,变成了效率低、节奏不一的大团。辨别方式:在合同中明确写入「一家一单,不拼团,同一辆车只接待本组家庭」,并注明车辆型号和领队姓名。</p><h2>坑三:景区内宰客</h2><p>草原上部分非正规马场、摄影点、手工艺品摊位存在漫天要价的情况。常见场景骑马前未谈好价格,骑完被要天价;照相「免费」,洗出来才知道每张100元以上。</p><p><strong>应对方法</strong>:任何消费前先确认价格并口头确认,有争议项目拍视频留证据。选择有本地领队陪同的出行方式,领队通常会提前提醒这类情况。</p><h2>坑四:住宿虚假宣传</h2><p>部分民宿或营地在网上发布的照片与实际差距悬殊:图片是高级帐篷,实际是没有卫浴的简易蒙古包;宣传「草原深处」,实际在城郊农家乐。</p><p><strong>辨别方法</strong>:要求提供真实照片(不修图)、卫浴配置、与草原核心区的距离。呼籁旅行的自有营地提供真实照片和视频参考,可在预订前查看。</p><h2>坑五:旺季一房难求</h2><p>7月草原旺季,优质营地和酒店经常提前2个月以上售罄。若临时决定出行,只能选择剩余的低品质住宿,严重影响体验。<strong>教训</strong>确定要去就立刻预订,尤其是7月15日至8月5日的黄金期。</p><h2>坑六:不签合同,口头承诺</h2><p>小作坊式的旅行社常见问题:仅口头承诺行程,不提供书面合同;出现问题无凭据。正规旅行社必须签订包含行程细节、退改条款、投诉渠道的正式旅游合同(电子版也算)。无合同,不出发。</p><h2>坑七:天气原因无法赔偿</h2><p>草原天气变化快,有时会遭遇大雨导致部分景点无法前往。部分旅行社在合同中以「不可抗力」条款免除一切责任。查看合同时重点关注:因天气原因导致行程调整,旅行社如何补偿或安排替代方案。</p><h2>坑八:购物停留时间过长</h2><p>部分旅行社与当地购物点有合作,在行程中安排1-2小时甚至更长的购物时间,以「体验当地文化」为名实为强制购物。选择旅行社时直接问行程中是否有购物环节?是否有强制购物?获得明确承诺后写入合同。</p><h2>坑九:活动安全保障不足</h2><p>草原上的骑马、ATV等活动存在一定风险。不规范的活动场地无头盔提供、马匹未经专业训练、无安全员陪同。参与任何体力活动前确认安全装备是否齐全,拒绝没有安全保障的项目。</p><h2>坑十:以为草原哪里都一样</h2><p>这不是「坑」,但是认知偏差。呼伦贝尔最精华的景点高度分散,如果只在海拉尔周边转,会错过所有核心风景。行程规划时确认包含:莫日格勒河、额尔古纳湿地、边境公路(室韦-黑山头段)这三个核心节点,否则相当于白跑一趟。</p>"
},
{
"id": "grassland-photography-outfit-guide",
"title": "草原旅拍穿搭指南:怎么拍出大片感",
"subtitle": "颜色、款式、配件、拍摄时机,草原出片的完整方法论",
"subtitle": "去草原不知道穿什么?本文从色系选择、服装款式、配件搭配到拍摄时机,手把手教你在呼伦贝尔草原拍出大片感。",
"author": "呼籁旅行",
"date": "2026-01-18",
"category": "穿搭",
"summary": "去草原不知道穿什么?本文从色系选择、服装款式、配件搭配到拍摄时机,手把手教你在呼伦贝尔草原拍出大片感。",
"coverImage": "/images/seasons/autumn-forest.jpg",
"tags": ["草原穿搭", "旅拍穿搭", "拍照技巧", "呼伦贝尔摄影"],
"seo": {
"title": "草原旅拍穿搭指南:呼伦贝尔怎么穿才好看 - 呼籁旅行",
"description": "呼伦贝尔草原旅拍穿搭指南:适合草原的色系推荐、蒙古风服装选择、亲子穿搭配色、最佳拍照时机,帮你在草原拍出大片感。",
"keywords": "草原穿搭,呼伦贝尔穿搭,草原旅拍,呼伦贝尔旅拍穿搭,草原拍照穿什么"
},
"relatedProducts": ["v9-6d5n-family", "v9-6d5n-comfort", "v9-7d6n-wild"],
"content": "<h2>草原拍照的核心逻辑</h2><p>草原摄影不同于城市街拍,背景是无边绿色+蓝天白云的极简组合,这意味着<strong>服装颜色是决定出片质量的第一要素</strong>。颜色选对了,随手一拍都是大片;颜色选错了,专业摄影师也救不回来。</p><h2>色系选择:哪些颜色最出片</h2><p><strong>最推荐:</strong></p><ul><li><strong>白色</strong>:与绿草蓝天形成最强反差,任何角度都好看,是草原拍照的王者色</li><li><strong>米黄/驼色</strong>:低饱和度的暖色调与草原泥土色系天然融合,高级感十足</li><li><strong>天蓝/浅蓝</strong>:呼应天空色,融入感强,有「天人合一」的意境</li><li><strong>民族风红色</strong>:蒙古族传统服装色,与草原文化契合,但面积不宜过大</li></ul><p><strong>慎用:</strong></p><ul><li>深绿色:与背景融合,人会「消失」在草原中</li><li>印花/格纹:在草原简洁背景下显得杂乱</li><li>荧光色:显眼但不好看,适合纪念照不适合大片</li></ul><h2>推荐款式</h2><p><strong>女生首选:</strong></p><ul><li>飘逸长裙(纯色或简约印花):风吹裙摆是草原专属画面,必备</li><li>蒙古族传统袍子(可在当地租借):文化感拉满,适合正式纪念照</li><li>衬衫+高腰阔腿裤:干净清爽,适合日常旅行拍摄</li></ul><p><strong>男生推荐:</strong></p><ul><li>白色或浅色衬衫:简单好配,不会抢镜</li><li>户外风系列(防晒衣+功能裤):既实用又有探险感</li><li>蒙古族传统服装:非常出片,可在当地租用</li></ul><p><strong>亲子家庭:</strong></p><ul><li>建议全家选择同一色系,而非相同颜色</li><li>经典组合:爸爸白衬衫+妈妈白裙+孩子蓝色或黄色(补色点亮画面)</li><li>孩子适合亮色系,活泼的黄色、红色最出片</li></ul><h2>配件不可少</h2><ul><li><strong>帽子</strong>:草原必备,功能性(防晒)和美观性兼顾。草帽、白色棒球帽、蒙古风毡帽都很适合</li><li><strong>马术靴</strong>:穿上骑马靴整个人气质立刻不同,也很安全</li><li><strong>腰带/腰封</strong>:长裙加一条民族风腰带,层次感立刻出来</li></ul><h2>最佳拍摄时机</h2><p>草原光线变化极大,拍摄时机比服装更重要:</p><ul><li><strong>黄金时刻Golden Hour</strong>日出后1小时约6:00-7:30和日落前1小时约20:00-21:30。此时光线暖黄,阴影柔和,任何构图都好看</li><li><strong>蓝调时刻</strong>日出前和日落后15分钟,天空呈深蓝色,适合营地或蒙古包的夜景拍摄</li><li><strong>正午慎拍</strong>10:00-16:00阳光直射,阴影浓重,容易曝光过度,此时建议在阴影处或营地内拍摄</li></ul><h2>拍摄构图小技巧</h2><ul><li><strong>低角度仰拍</strong>:把相机/手机放到腰部高度向上拍,以草地为前景,人物和天空占画面的上2/3,草原感最强</li><li><strong>留白天空</strong>草原的天空是最好的背景,让人物处于画面下1/3,上方大面积留白</li><li><strong>奔跑/回眸</strong>:让被拍摄者做动态动作,避免生硬站立</li><li><strong>利用道路</strong>:边境公路的笔直道路是天然的透视线,站在道路中央拍摄有延伸感</li></ul><h2>实用建议</h2><p>带至少2套不同颜色的外出服装,根据当天景点背景灵活切换。在营地可以借穿当地蒙古族传统服装,通常收费50-100元/套,非常值得体验。草原风大,长裙拍摄时顺风站立,裙摆自然飘起效果最好。最后,记得在出发前充满手机电量,草原上充电不方便,备一个移动电源是必要的。</p>"
"coverImage": "/images/team/hero-grassland.jpg",
"tags": [
"草原穿搭",
"旅拍穿搭",
"拍照技巧",
"呼伦贝尔摄影"
],
"content": "<h2>草原拍照的核心逻辑</h2><p>草原摄影不同于城市街拍,背景是无边绿色+蓝天白云的极简组合,这意味着<strong>服装颜色是决定出片质量的第一要素</strong>。颜色选对了,随手一拍都是大片;颜色选错了,专业摄影师也救不回来。</p><h2>色系选择:哪些颜色最出片</h2><p><strong>最推荐:</strong></p><ul><li><strong>白色</strong>:与绿草蓝天形成最强反差,任何角度都好看,是草原拍照的王者色</li><li><strong>米黄/驼色</strong>:低饱和度的暖色调与草原泥土色系天然融合,不抢镜,任何构图都好看</li><li><strong>天蓝/浅蓝</strong>:呼应天空色,融入感强,有「天人合一」的意境</li><li><strong>民族风红色</strong>:蒙古族传统服装色,与草原文化契合,但面积不宜过大</li></ul><p><strong>慎用:</strong></p><ul><li>深绿色:与背景融合,人会「消失」在草原中</li><li>印花/格纹:在草原简洁背景下显得杂乱</li><li>荧光色:显眼但不好看,适合纪念照不适合大片</li></ul><h2>推荐款式</h2><p><strong>女生首选:</strong></p><ul><li>飘逸长裙(纯色或简约印花):风吹裙摆是草原专属画面,必备</li><li>蒙古族传统袍子(可在当地租借):文化感拉满,适合正式纪念照</li><li>衬衫+高腰阔腿裤:干净清爽,适合日常旅行拍摄</li></ul><p><strong>男生推荐:</strong></p><ul><li>白色或浅色衬衫:简单好配,不会抢镜</li><li>户外风系列(防晒衣+功能裤):既实用又有探险感</li><li>蒙古族传统服装:非常出片,可在当地租用</li></ul><p><strong>亲子家庭:</strong></p><ul><li>建议全家选择同一色系,而非相同颜色</li><li>经典组合:爸爸白衬衫+妈妈白裙+孩子蓝色或黄色(补色点亮画面)</li><li>孩子适合亮色系,活泼的黄色、红色最出片</li></ul><h2>配件不可少</h2><ul><li><strong>帽子</strong>:草原必备,功能性(防晒)和美观性兼顾。草帽、白色棒球帽、蒙古风毡帽都很适合</li><li><strong>马术靴</strong>:穿上骑马靴整个人气质立刻不同,也很安全</li><li><strong>腰带/腰封</strong>:长裙加一条民族风腰带,层次感立刻出来</li></ul><h2>最佳拍摄时机</h2><p>草原光线变化极大,拍摄时机比服装更重要:</p><ul><li><strong>黄金时刻Golden Hour</strong>日出后1小时约6:00-7:30和日落前1小时约20:00-21:30。此时光线暖黄,阴影柔和,任何构图都好看</li><li><strong>蓝调时刻</strong>日出前和日落后15分钟,天空呈深蓝色,适合营地或蒙古包的夜景拍摄</li><li><strong>正午慎拍</strong>10:00-16:00阳光直射,阴影浓重,容易曝光过度,此时建议在阴影处或营地内拍摄</li></ul><h2>拍摄构图小技巧</h2><ul><li><strong>低角度仰拍</strong>:把相机/手机放到腰部高度向上拍,以草地为前景,人物和天空占画面的上2/3,草原感最强</li><li><strong>留白天空</strong>草原的天空是最好的背景,让人物处于画面下1/3,上方大面积留白</li><li><strong>奔跑/回眸</strong>:让被拍摄者做动态动作,避免生硬站立</li><li><strong>利用道路</strong>:边境公路的笔直道路是天然的透视线,站在道路中央拍摄有延伸感</li></ul><h2>实用建议</h2><p>带至少2套不同颜色的外出服装,根据当天景点背景灵活切换。在营地可以借穿当地蒙古族传统服装,通常收费50-100元/套,非常值得体验。草原风大,长裙拍摄时顺风站立,裙摆自然飘起效果最好。最后,记得在出发前充满手机电量,草原上充电不方便,备一个移动电源是必要的。</p>"
}
]
}
}

查看文件

@ -5,69 +5,56 @@
"url": "https://1814.love",
"slogan": {
"emotional": "带孩子回到母亲的故乡",
"functional": "呼伦贝尔亲子游·一家一单一车"
"functional": "呼伦贝尔家庭定制游·一家一单一车"
},
"trustStats": [
{
"value": "10000+",
"unit": "组",
"label": "家庭选择了呼籁"
"label": "已服务家庭"
},
{
"value": "39000+",
"unit": "人次",
"label": "累计服务人次"
},
{
"value": "11",
"unit": "年",
"label": "只做呼伦贝尔一地"
},
{
"value": "98%",
"unit": "",
"label": "客户好评率"
"label": "深耕呼伦贝尔"
},
{
"value": "9",
"unit": "家",
"label": "旗下自有企业"
"label": "旗下企业"
}
],
"differentiators": [
{
"title": "自有营地,不对外开放",
"description": "我们真金白银租下草场、自己建的营地。敖包相会景区内,俯瞰伊敏河湿地,只有呼籁客人才能进去"
"title": "自有营地",
"description": "呼籁自有草原活动基地,亲子互动、草原运动、户外体验的专属场地,不是拼团景点"
},
{
"title": "自有车队,师傅不外包",
"description": "呼籁自己的客运公司、自己的车、自己的师傅。不是接到订单再找第三方——你的车从头到尾只拉你一家"
"title": "自有车队",
"description": "呼籁旅游客运有限公司自营车队,不转卖客人给第三方,每一程都是呼籁自己的车、自己的师傅"
},
{
"title": "独家体验,别的团去不了",
"description": "全地形越野车湿地穿越、寻龙诀秘境、牧云山顶下午茶——这些是呼籁签约的独家资源,不在公开景区"
"title": "自营体验",
"description": "呼籁营地、白桦林研学、黑山头研学、寻龙诀全地形越野车等核心体验项目均为呼籁自营,品质自己把控"
},
{
"title": "自营旅拍,200+套服饰",
"description": "呼籁自己培养的摄影师、自己的服装库,在营地拍。不用单独预约,跟着行程就拍,拍完即得精修大片"
"title": "自营旅拍",
"description": "呼籁自营旅拍团队,200+服饰可选,在呼籁营地定点旅拍,记录全家最自然的瞬间"
},
{
"title": "5人团队只服务你一家",
"description": "3管家车务+房务+客服)+ 1定制师 + 1专属领队,贯穿出发前到返程后,只服务你们一个家庭"
"title": "专业团队",
"description": "3管家车务+房务+客服)+ 1定制师 + 1专属领队,全程只服务您一个家庭"
},
{
"title": "自有研学基地,孩子真能学到东西",
"description": "黑山头蒙古族文化研学基地是呼籁自营的。孩子在真实的草原、牧场、蒙古包里动手,不是参观博物馆"
"title": "研学基地",
"description": "黑山头自有蒙古族文化研学基地,孩子在草原上动手体验、学习成长,不是走马观花"
}
],
"ctaButtons": {
"primary": {"text": "看看哪个版本适合你", "to": "/selector"},
"secondary": {"text": "查看产品和价格", "to": "/products"},
"pricing": {"text": "了解费用明细", "to": "/pricing"},
"customize": {"text": "免费获取专属方案", "to": "/customize"},
"contact": {"text": "联系定制师", "to": "/contact"}
},
"conversionPath": [
{"step": 1, "label": "看产品", "to": "/products"},
{"step": 2, "label": "选版本", "to": "/selector"},
{"step": 3, "label": "看价格", "to": "/pricing"},
{"step": 4, "label": "在线定制", "to": "/customize"}
],
"icpEntity": "内蒙古呼籁文化科技有限公司",
"icp": "蒙ICP备2025033324号-2",
"icpUrl": "https://beian.miit.gov.cn",

查看文件

@ -1,78 +1,28 @@
{
"meta": {
"pageTitle": "呼伦贝尔最佳出行月份",
"pageIntro": "基于呼籁旅行11年带队数据,为您提供每月出行参考指南",
"pageIntro": "11年、39000+人次、每一个月份都送过客人出发——哪个月最值得去、哪个月要避开、带孩子选什么时间,我们用真实数据告诉你",
"bestTime": "6月9月",
"quickRecommendations": [
{
"label": "性价比最高",
"months": "6中下旬",
"reason": "草原已非常美,各项活动已开展,价格尚未进入旺季"
"label": "草原最美",
"months": "6—8月",
"reason": "绿草如茵,天高云淡,那达慕节庆"
},
{
"label": "景色巅峰",
"months": "7—8月",
"reason": "景色和活动都很棒,但7月初至8月28日价格较贵"
"label": "秋色绝景",
"months": "9月",
"reason": "白桦金黄,草原秋色,摄影圣地"
},
{
"label": "秋景最佳",
"months": "9月20日—国庆",
"reason": "大兴安岭秋景的最佳时机,非常推荐"
"label": "错峰推荐",
"months": "5月 / 10月",
"reason": "人少价优,各有特色,舒适出行"
},
{
"label": "冬季体验",
"label": "冬季探险",
"months": "12—2月",
"reason": "完全另一种美,冰雪那达慕、驯鹿部落"
}
],
"travelAdvice": [
{
"period": "5月初",
"level": "not_recommended",
"levelText": "不推荐",
"description": "4月份冰雪刚刚消融,草原才刚刚冒芽,有些活动还没开始。"
},
{
"period": "5月底—6月初",
"level": "ok",
"levelText": "可以考虑",
"description": "草原已经有了绿意。如果想避开人群提早出发,这个时候可以考虑了。"
},
{
"period": "6月中旬—6月底",
"level": "best_value",
"levelText": "性价比最高",
"description": "草原已经非常美了,各项活动也都已开展。价格尚未进入旺季,是性价比最高的时段。"
},
{
"period": "6月底—8月底",
"level": "peak",
"levelText": "景色巅峰",
"description": "景色和各项活动都很棒,完全不用担心。但从7月初至8月20日价格会相对贵一些。"
},
{
"period": "9月初",
"level": "ok",
"levelText": "可以考虑",
"description": "草原已经不是特别漂亮了,但因为孩子都开学了,人相对会少一些。"
},
{
"period": "9月20日—国庆结束",
"level": "highly_recommended",
"levelText": "非常推荐",
"description": "看呼伦贝尔大兴安岭秋景的最佳时机,错过再等一年。"
},
{
"period": "冬季12月—次年2月",
"level": "recommended",
"levelText": "推荐",
"description": "冬季旅游景色也还不错,是完全另一种美。冰雪那达慕、驯鹿部落值得体验。"
},
{
"period": "3月—4月 / 5月中上旬",
"level": "not_recommended",
"levelText": "不推荐",
"description": "来呼伦贝尔一趟还是比较折腾的,希望大家能在每个季节相对最美的时候过来。"
"reason": "冰雪那达慕,极寒体验,雪原驰骋"
}
]
},
@ -133,14 +83,14 @@
"month": 5,
"name": "五月",
"season": "spring",
"ratingStars": 3,
"ratingStars": 4,
"tempRange": "5°C ~ 22°C",
"weatherFeature": "月初草原刚冒芽、活动未全面开展;月底已有绿意,想避开人群可考虑5月底出发",
"highlights": ["5月底草原已有绿意", "避开人群提早出发", "候鸟迁徙壮观", "白天长达16小时"],
"weatherFeature": "春风怡人,绿草铺地,野花盛放,气候舒适,游客尚少",
"highlights": ["草原野花漫山盛开", "绿草渐浓如毯", "候鸟迁徙壮观", "白天长达16小时"],
"clothingTips": "冲锋衣 + 长袖 + 防晒,早晚加绒衣一件",
"isPeakSeason": false,
"recommendedProducts": ["额吉的故乡V95月底起"],
"tagline": "月底可行,月初建议再等等"
"recommendedProducts": ["额吉的故乡V9"],
"tagline": "错峰推荐,花开无边"
},
{
"month": 6,
@ -148,12 +98,12 @@
"season": "summer",
"ratingStars": 5,
"tempRange": "15°C ~ 28°C",
"weatherFeature": "中旬起草原已非常美,各项活动全面开展,性价比全年最高的时段",
"highlights": ["6月中下旬性价比最高", "草原已非常美", "各项活动全面开展", "骑马体验最舒适"],
"weatherFeature": "气候宜人,草原进入翠绿全盛期,是全年最美时节之一",
"highlights": ["莫日格勒河嫩绿如画", "一望无际的绿色草原", "骑马体验最舒适", "北疆夏至日长达17小时"],
"clothingTips": "薄外套 + 防晒衣 + 长裤,早晚加薄羽绒,备雨衣",
"isPeakSeason": true,
"recommendedProducts": ["额吉的故乡V9", "小蒙马夏令营"],
"tagline": "性价比最高,强烈推荐"
"tagline": "最美时节,绿意盎然"
},
{
"month": 7,
@ -187,12 +137,12 @@
"season": "autumn",
"ratingStars": 5,
"tempRange": "5°C ~ 20°C",
"weatherFeature": "月初草原不再最美但人少;9月20日起大兴安岭秋景进入最佳观赏期,非常推荐",
"highlights": ["9月20日后秋景最佳", "大兴安岭金秋绝景", "国庆期间秋色正浓", "开学后人少清净"],
"weatherFeature": "草原金秋,色彩由绿转金,白桦林绝景,摄影爱好者公认圣地",
"highlights": ["白桦林一片金黄", "草原由绿转秋色", "额尔古纳湿地倒影绝美", "牧民秋季转场壮观"],
"clothingTips": "冲锋衣 + 毛衣,早晚加薄羽绒,温差显著需分层穿搭",
"isPeakSeason": true,
"recommendedProducts": ["游牧的森林(秋季)"],
"tagline": "9月20日起秋景巅峰,非常推荐"
"tagline": "秋景无双,摄影圣地"
},
{
"month": 10,
@ -227,7 +177,7 @@
"ratingStars": 3,
"tempRange": "-30°C ~ -15°C",
"weatherFeature": "冰雪全封,冬景壮美,冰雪活动赛季正式开启",
"highlights": ["呼伦湖完全冰封", "冰雪那达慕开幕", "极光偶现北疆", "冰钓与雪地越野"],
"highlights": ["呼伦湖完全冰封", "冰雪那达慕开幕", "雾凇奇景绽放", "冰钓与雪地越野"],
"clothingTips": "零下30°C专业装备鹅绒 + 羊毛打底 + 防风冲锋套装",
"isPeakSeason": false,
"recommendedProducts": ["嗨冰雪", "小蒙马冬季营"],

查看文件

@ -3,7 +3,7 @@
{
"type": "wechat",
"label": "微信客服",
"value": "扫码添加",
"value": "hulai1814",
"qrImage": "/images/contact/qrcode-wechat.jpg",
"primary": true,
"description": "添加微信,一对一沟通行程需求"
@ -11,11 +11,9 @@
{
"type": "miniprogram",
"label": "预订小程序",
"value": "微信搜索「呼籁」",
"value": "呼籁旅行",
"qrImage": "/images/qrcode-miniprogram.png",
"description": "微信小程序搜索「呼籁」,在线了解和预订",
"hidden": true,
"_note": "小程序尚未上线,上线后将 hidden 改为 false 即可显示"
"description": "微信扫码进入小程序,在线了解和预订"
},
{
"type": "phone",

查看文件

@ -1,246 +1,257 @@
{
"philosophy": {
"headline": "草原是最好的课堂,自然是最好的老师",
"tagline": "让孩子在真实的世界里学习真实的事",
"description": "小蒙马研学不是景区观光配个讲解员,也不是把教室搬到草原上。我们相信孩子天生有好奇心和行动力,课程设计的核心是给孩子提供真实的接触——真正的马、真正的牧民、真正的河流、真正的星空。学习在接触中自然发生。",
"values": [
{
"label": "真实接触",
"desc": "不是模型,不是图片,不是讲解词。孩子用手触摸、用脚行走、用眼睛看真实的草原生态。"
},
{
"label": "分龄设计",
"desc": "3-6岁、7-9岁、10-12岁三组,学习目标和课程深度按发展阶段匹配,不搞一刀切。"
},
{
"label": "不赶时间",
"desc": "每个孩子的节奏不同,课程里留有充分的自由探索时间,允许孩子在一只蚂蚱身上花二十分钟。"
},
{
"label": "无痕理念",
"desc": "LNTLeave No Trace贯穿全程,从第一天开始让孩子理解你来过,草原没有损失。"
}
]
},
"ageGroups": [
{
"id": "little",
"emoji": "🌱",
"label": "探索组 3-6岁",
"headline": "用感官认识世界",
"focus": "感知·体验·好奇心",
"description": "这个年龄段的孩子是天生的探索者。课程以感官体验为核心,不强调记忆和输出,重在让孩子用眼睛看、用手摸、用鼻子闻,和草原建立最直接的联结。领队会放慢节奏,蹲下来用孩子的视角带领他们发现身边的细节。",
"highlights": [
"辨认3-5种草原常见植物用触摸和气味,而不是记名字",
"近距离观察马、牛、羊,理解动物也有情绪",
"跟牧民家的孩子一起做简单的游牧日常活动",
"在营地用草叶、石头、泥土完成一件自然艺术作品",
"学会离开前检查自己有没有留下垃圾LNT启蒙"
],
"recommendedModules": ["ecology", "equestrian", "culture", "art"]
},
{
"id": "child",
"emoji": "🏇",
"label": "探险组 7-9岁",
"headline": "从体验走向理解",
"focus": "探究·协作·表达",
"description": "7-9岁的孩子开始有能力追问「为什么」。课程在体验基础上增加观察记录和小组探究环节,引导孩子不只是看到,而是思考。马术训练进入初级骑行阶段,团队协作类课程也开始加入。",
"highlights": [
"用观察记录本记录3天的草原生态变化",
"学习草原食物链:草→蚂蚱→鸟→草原鹰",
"完成初级马术课程,能独立慢步骑行",
"小组合作完成一项游牧文化复原任务(如搭建蒙古包外架)",
"用自然材料完成一件有主题的艺术创作并向全组介绍",
"参与一次LNT实践行动,记录并分享发现"
],
"recommendedModules": ["ecology", "equestrian", "culture", "art", "teamwork", "lnt"]
},
{
"id": "teen",
"emoji": "🌟",
"label": "领袖组 10-12岁",
"headline": "从理解走向责任",
"focus": "思辨·领导力·价值观",
"description": "10-12岁是价值观形成的关键期。课程加入更多思辨和挑战环节,要求孩子独立判断、承担小组责任、向他人传递自己的发现。马术进入中级阶段,并加入草原生态调查和环保实践项目。",
"highlights": [
"独立完成一份草原生态小调查报告(含现场采集数据)",
"中级马术:练习快步骑行和基础转向控制",
"担任小组领队,带领低龄组孩子完成一项自然任务",
"参与游牧文化传承讨论:现代化对草原生活方式的影响",
"设计并执行一次微型LNT行动,核算本次营地的环境影响",
"最终营地汇报向家长和伙伴展示3天的学习成果"
],
"recommendedModules": ["equestrian", "culture", "teamwork", "lnt", "art", "ecology"]
}
],
"modules": [
{
"id": "ecology",
"icon": "🌿",
"name": "草原生态认知",
"name": "草原生态课",
"ageRange": "3-12岁",
"duration": "贯穿全程",
"shortDesc": "以草原为天然实验室,通过观察、记录、触摸,理解草原生态系统的结构和运转逻辑。",
"objectives": [
"认识呼伦贝尔草原的代表性动植物及其生态位",
"理解草原食物链的基本结构",
"建立对自然系统的尊重和好奇心",
"掌握基础的野外观察方法(不打扰、不破坏)"
],
"duration": "每次90分钟",
"shortDesc": "认识草原上的植物、昆虫、鸟类,理解食物链和生态系统的基本关系。",
"activities": [
"莫日格勒河畔植被带徒步观察,用记录本画植物速写",
"草原鸟类晨间观测(双筒望远镜辅助)",
"牧民带领的牧场生态讲解:草场轮牧背后的生态智慧",
"夜间昆虫灯光诱集观察6岁以上",
"低龄组:用感官游戏认识草地里的小生命"
"植物标本采集与图鉴比对(仅采集枯叶,不伤害活株)",
"夜观星空:认识北斗七星和银河,了解游牧民如何用星星导航",
"草原土壤采样:观察不同深度的土壤颜色和生物",
"鸟类观察:用望远镜记录草原鸟类活动"
],
"philosophy": "草原的生态课不在教室里,在每一片草叶下、每一声鸟叫里。我们不背名词,我们用眼睛学习。"
"objectives": [
"能识别5种以上草原常见植物如羊草、针茅、狼毒花",
"了解草原食物链:草→鼠→鹰的完整链条",
"理解游牧民与草原之间的共生关系",
"培养对自然生命的敬畏与保护意识"
],
"philosophy": "生态教育不是在课堂里讲生物课,而是让孩子蹲下来,安静地看一只草原蚂蚱如何生活。"
},
{
"id": "equestrian",
"id": "horse",
"icon": "🐎",
"name": "马术体验",
"ageRange": "3-12岁",
"duration": "1-2课时/天",
"shortDesc": "从认识马、照顾马到骑马,建立孩子与马匹的真实信任关系,而不是简单地「骑一圈」。",
"objectives": [
"了解马的习性、情绪信号和基础照料方式",
"通过刷马、喂料建立人马信任关系",
"掌握安全上下马、基础坐姿和步行骑乘3-6岁",
"完成慢步独立骑行和基础方向控制7岁以上",
"培养对动物的责任感和共情能力"
],
"name": "马术体验课",
"ageRange": "4-12岁",
"duration": "每次60分钟",
"shortDesc": "从认识马、与马建立信任,到基础骑乘,体验游牧民族与马之间的独特情感纽带。",
"activities": [
"马厩认知课:认识马的各部位,学习安全接近和抚摸",
"刷马体验:协助牧民为马匹梳理,建立信任",
"骑乘练习:由专业牧民教练全程保护,分龄分组进行",
"骑马草原漫游:在指定安全路线上感受马背上的草原视角",
"高龄组:基础快步训练和绕桩练习"
"认识马:马的身体结构、情绪表达方式、安全距离",
"与马建立信任:喂草、轻抚、眼神交流练习",
"基础骑乘体验:领队牵马在指定草地范围内步行骑行",
"马术文化课:蒙古族马文化、那达慕赛马传统讲解"
],
"philosophy": "马是草原文化的核心,但马不是道具。让孩子先学会照顾一匹马,再学会骑它——这是顺序,也是态度。"
"objectives": [
"了解蒙古马的品种特点和历史文化地位",
"掌握马匹日常照料基础:喂食、刷毛、缰绳系法",
"完成有领队陪同的基础骑乘(步行圈乘)",
"建立对动物的尊重与责任感"
],
"philosophy": "马是蒙古族最亲密的伙伴。让孩子第一次坐上马背,是与这片草原文明的真实连接。"
},
{
"id": "culture",
"icon": "🏠",
"name": "游牧文化传承",
"ageRange": "3-12岁",
"duration": "1课时/天",
"shortDesc": "通过做蒙古包、穿蒙古袍、学蒙古语、跟真实牧民互动,让孩子感受游牧文化的真实质感。",
"objectives": [
"了解蒙古包的结构原理和搭建智慧",
"认识游牧生活的季节节律和迁徙逻辑",
"体验蒙古族传统饮食文化(奶茶、手把肉、奶制品)",
"学会3-5句蒙古语日常用语",
"理解游牧文化与草原生态之间的共生关系"
],
"id": "nomad",
"icon": "🏕️",
"name": "游牧文化课",
"ageRange": "5-12岁",
"duration": "每次120分钟",
"shortDesc": "走进蒙古包,跟牧民家庭学习搭建、拆卸、日常生活,体验真实的游牧文化。",
"activities": [
"蒙古包搭建体验:在牧民指导下参与外架安装和毡覆盖",
"牧民家庭做客:喝奶茶、品奶酪、听牧民讲草原上的故事",
"蒙古族手工坊:制作哈达或简单的马鞍装饰",
"蒙古语小课堂:学习问候、数数和基本方向词",
"那达慕小运动会:射箭、摔跤(儿童版)体验"
"蒙古包DIY亲手参与搭建小号教学蒙古包",
"牧民厨房:在牧民阿妈指导下制作奶茶和炒米",
"游牧乐器体验:马头琴听讲和简单节奏感知",
"传统服装体验:穿上蒙古袍,了解每个装饰的含义"
],
"philosophy": "文化不是博物馆里的展品,是有呼吸的生活方式。让孩子和真实的牧民坐在一起喝一碗奶茶,比看一百张图片更有用。"
"objectives": [
"了解蒙古包的结构和搭建原理(与自然的关系)",
"体验游牧生活的基本技能:挤奶、制奶茶、晾奶豆腐",
"理解游牧文化中「迁徙」的生态智慧",
"尊重并欣赏不同民族的生活方式"
],
"philosophy": "游牧文明是人类与自然最和谐的相处方式之一。让孩子亲身体验,比任何课本都更有说服力。"
},
{
"id": "art",
"icon": "🎨",
"name": "自然艺术创作",
"name": "自然艺术课",
"ageRange": "3-12岁",
"duration": "1课时/天",
"shortDesc": "用草原里的材料创作——没有颜料盒,只有泥土、草叶、石头、羽毛、风干的花。",
"objectives": [
"学会用自然材料进行艺术表达,不依赖商业美术材料",
"培养对自然美的感知力和审美意识",
"通过创作过程发展专注力和独立完成任务的能力",
"用作品记录并表达自己的草原体验",
"理解艺术与环境的关系:取之自然,不破坏自然"
],
"duration": "每次90分钟",
"shortDesc": "用草原上捡到的材料创作艺术,让孩子用创意表达对自然的感受。",
"activities": [
"草叶拓印:用采集的草叶在布料上印出自己的植物地图",
"石头彩绘:用泥土和植物汁液给河边的石头上色",
"自然装置艺术:在指定区域用地面材料创作可降解的小作品",
"草编入门:学习基础草编手法,编一个简单的小篮",
"高龄组:以「草原生态」为主题完成一件综合材料作品并展示"
"大地艺术:在草地上用天然材料拼出图案",
"自然笔记:用画笔记录今天观察到的一种植物或动物",
"石头彩绘:将草原上拾到的石头画成小动物",
"草编基础:学习蒙古族传统草编工艺的简单入门"
],
"philosophy": "最好的画布不在美术教室里,在莫日格勒河边的泥地上。孩子不需要颜料,他们需要允许弄脏手的机会。"
"objectives": [
"用自然材料(石头、枯草、羽毛)完成一件艺术作品",
"学会用线条和颜色记录自然观察(自然笔记)",
"理解「取之自然、用之有度」的创作伦理",
"建立个人审美和创意表达能力"
],
"philosophy": "最好的画布就是大地。最好的颜料就是孩子对这片草原的情感。"
},
{
"id": "teamwork",
"id": "team",
"icon": "🤝",
"name": "团队协作成长",
"ageRange": "7-12岁",
"duration": "贯穿全程",
"shortDesc": "通过设计好的小组任务和草原挑战,让孩子在真实情境中练习沟通、分工和共同解决问题。",
"objectives": [
"学习在陌生环境中快速建立信任和分工合作",
"练习表达不同意见并达成共识的能力",
"承担小组领队或记录员等具体角色责任",
"在有压力的任务情境中保持情绪稳定",
"感受集体完成一件难事之后的成就感"
],
"name": "团队成长课",
"ageRange": "6-12岁",
"duration": "每次120分钟",
"shortDesc": "通过草原场景中的团队挑战,培养沟通、合作和领导力。",
"activities": [
"营地搭建挑战:小组合作在规定时间内完成营地布置",
"草原定向越野:用地图和指南针完成多点位任务",
"牧场生态调查任务:分工收集数据,合作完成报告",
"故事接龙营火会:每人贡献情节,共同完成一个草原故事",
"领队角色轮换:每位孩子轮流担任组长,带领组员完成一项任务"
"草原寻宝:分组完成地图导航和线索解谜任务",
"搭建营地6人小组在规定时间内搭建遮蔽所",
"信任盲走:蒙眼在队友引导下完成草地穿越",
"故事圈:每晚围营火分享今天最有挑战的时刻"
],
"philosophy": "草原上有一种东西在城市里很难学到:当你迷路了,你必须和身边的人商量怎么走。这是团队,也是成长。"
"objectives": [
"在陌生环境中主动建立与同伴的信任",
"学会在团队任务中有效分工和沟通",
"体验挫折并找到解决问题的方法",
"认识自己在团队中的角色和贡献"
],
"philosophy": "草原没有捷径,但有方向。团队成长课教的不是竞争,是如何在未知中互相支持。"
},
{
"id": "lnt",
"icon": "🌍",
"name": "LNT无痕环保实践",
"ageRange": "3-12岁",
"duration": "贯穿全程",
"shortDesc": "Leave No Trace无痕旅行不是一节课,是贯穿整个营期的行动准则,让孩子从第一天开始内化对自然的责任。",
"objectives": [
"理解LNT的7大原则及其在草原环境中的具体含义",
"养成在自然中活动的基本行为习惯(不乱扔垃圾、不采摘植物等)",
"学会评估自己的行为对环境的影响",
"高龄组:独立设计一份草原环保行动方案",
"把LNT理念带回城市生活,影响家庭"
],
"name": "LNT无痕环保课",
"ageRange": "5-12岁",
"duration": "每次60分钟",
"shortDesc": "学习「Leave No Trace」无痕山野七大原则,培养真正的环保行动力。",
"activities": [
"第一天LNT原则导入游戏,用情景故事理解每条原则",
"每日营地检查离开前的10分钟'痕迹消除'行动",
"草原垃圾调查:统计营地周边垃圾种类和来源,分析问题",
"低龄组:制作'无痕小卫士'徽章,每完成一个行动打一颗星",
"结营日:各组展示本次营期的环保行动成果和数据"
"无痕营地实践:检查营地,发现并修复对环境的微小影响",
"垃圾分类挑战:在草原场景中完成垃圾分类和正确处理",
"足迹科学:测量并计算小组活动对草地的踩踏面积",
"环保承诺卡:写下回家后的一个环保行动并拍照留念"
],
"philosophy": "我们不告诉孩子'保护环境'是一个口号。我们让他在草原上住三天,然后问他:你在乎这里吗?答案通常是肯定的。从那一刻起,环保才是真的。"
"objectives": [
"了解LNT无痕山野七大原则及其原因",
"掌握草原环境中的无痕宿营实践方法",
"理解人类活动对草原生态的实际影响",
"回家后能把LNT理念传递给身边的人"
],
"philosophy": "最好的环保教育不是告诉孩子'不能做什么',而是让他们亲眼看到,亲手感受,然后自己做出选择。"
}
],
"ageGroups": [
{
"id": "toddler",
"emoji": "🐣",
"focus": "感知与好奇",
"label": "探索组 3-5岁",
"headline": "用感官探索草原的一切",
"highlights": [
"父母全程陪同,亲子共探",
"以触摸、嗅觉、听觉为主要学习方式",
"每次活动不超过45分钟,符合专注力发展",
"强调安全感和情绪表达,不强迫参与任何活动",
"结营获得个人草原探索小书"
],
"description": "3-5岁的孩子处于感知世界的黄金期。这个年龄段的课程以感官体验为主——摸、闻、看、听,不强调知识记忆,强调情感连接。父母全程陪同,亲子共同探索。",
"recommendedModules": [
"ecology",
"art",
"lnt"
]
},
{
"id": "child",
"emoji": "🌟",
"focus": "体验与探索",
"label": "探险组 6-8岁",
"headline": "在探险中建立自信与好奇",
"highlights": [
"每天1个独立完成的小任务",
"开始学习简单的自然科学观察方法",
"基础马术体验(有领队全程陪同)",
"参与游牧文化DIY活动",
"结营获得个人成长记录手册和技能徽章"
],
"description": "6-8岁是自信心和独立性快速发展的阶段。探险组的课程设计鼓励孩子在安全范围内独立完成小任务,并开始理解自然系统背后的逻辑。每天有明确的小挑战和成就感积累。",
"recommendedModules": [
"ecology",
"horse",
"nomad",
"art",
"lnt"
]
},
{
"id": "teen",
"emoji": "🏔️",
"focus": "思考与领导",
"label": "领袖组 9-12岁",
"headline": "从体验者到探索者的转变",
"highlights": [
"参与团队领导力挑战项目",
"完成一份完整的草原生态观察报告",
"深度游牧文化课:与牧民家庭进行真实交流",
"LNT实地项目为营地制定一份环保改进方案",
"结营获得自然探索认证和个人成长评估报告"
],
"description": "9-12岁的孩子已经具备抽象思维能力,能够理解生态系统、文化传承等复杂概念。领袖组课程加入更多挑战性任务、团队决策场景和深度文化探究,鼓励孩子提问和批判性思考。",
"recommendedModules": [
"ecology",
"horse",
"nomad",
"team",
"lnt"
]
}
],
"faq": [
{
"q": "几岁的孩子适合参加小蒙马研学?",
"a": "3-12岁均可参加。我们按3-6岁探索组、7-9岁探险组、10-12岁领袖组三个年龄段分组设计课程,学习目标和活动难度不同。3岁以下的幼儿建议参加小蒙马夏令营亲子营,全程有家长陪同。"
"a": "完全安全。马术课使用的是经过专门训练的温顺蒙古马,全程由有5年以上经验的专业领队牵马陪同,孩子不会独自骑行。4岁以上孩子即可参与步行体验,强调与马建立信任,不强调技巧。活动前有完整的安全讲解和装备检查。",
"q": "孩子没有骑过马,马术课安全吗?"
},
{
"q": "孩子不会骑马,马术课能参加吗?",
"a": "完全没问题,马术课从零基础开始。第一步是认识马、接触马,建立信任关系,然后才是骑乘。全程有专业牧民教练和领队保护,孩子不会被强迫做他没准备好的事。"
"a": "大部分课程在户外进行,这是我们设计的核心。天气预备方案:小雨不影响户外活动(雨天草原更美),中雨以上会转移到蒙古包室内进行游牧文化课、自然艺术课等室内模块。我们始终保证每天的课程质量,而不是简单'取消'。",
"q": "课程全部是户外吗?下雨天怎么办?"
},
{
"q": "研学课程和普通旅游有什么区别?",
"a": "最大的区别是有明确的学习目标和课程设计,而不只是带孩子去看风景。每个活动背后都有对应的教育目的,有观察记录、有任务完成、有成果展示。同时我们会放慢节奏,给孩子足够的时间真正接触和探索,而不是走马观花。"
"a": "请在报名时如实填写孩子的过敏情况。我们的医疗联络人会根据营期草原的具体植被情况给出评估意见。通常7月下旬至8月中旬是花粉高峰期,建议过敏体质孩子选择6月或9月的营期,同时随行携带必备药物。",
"q": "孩子有严重花粉过敏,能参加吗?"
},
{
"q": "孩子如果对某个活动不感兴趣或不想参与怎么办?",
"a": "不强制参与是我们的基本原则。领队会创造吸引孩子的方式引导,但不会强迫。孩子有权利说「我今天想看,不想做」,这本身也是一种学习——尊重自己的感受。"
"a": "取决于年龄段。3-5岁探索组需要家长全程陪同参与。6-8岁探险组和9-12岁领袖组,我们建议孩子独立参营父母在附近的营地等待,这有助于孩子建立真正的自信和独立性——但家长也可以选择陪同,我们有亲子共营版本。",
"q": "父母可以全程陪同吗?还是需要独立参营?"
},
{
"q": "研学课程中有安全风险吗?如何保障安全?",
"a": "所有活动均在专业人员陪同下进行。马术课有专业牧民教练全程保护;徒步有领队带队;营地有急救箱和受过急救培训的工作人员。我们会在活动前进行安全说明,并根据天气、孩子状态实时调整安排。"
},
{
"q": "孩子在草原上睡得着吗?饮食能适应吗?",
"a": "大部分孩子在草原上睡得非常好——户外活动充分、空气好、没有电子屏幕干扰。饮食方面,我们提供中餐为主,同时保留部分蒙古族特色食物体验。有特殊饮食需求(过敏、不吃某类食物)提前告知,我们会做相应安排。"
},
{
"q": "研学结束后孩子会有什么成果?",
"a": "有形成果包括观察记录本自己的草原笔记、自然艺术作品、LNT行动记录表、结营汇报7岁以上。无形成果则因孩子不同而不同——有的是自信、有的是对自然的兴趣、有的是第一次独立完成一件事的成就感。"
"a": "每期最多16个孩子,确保每4个孩子配备1名自然教育导师,同时配备1名当地专业领队。师生比不超过1:4,这是我们的底线。小班制是小蒙马研学的核心承诺之一,我们不会为了多收费而扩大营地规模。",
"q": "每期招多少孩子?师生比例是多少?"
}
]
}
],
"philosophy": {
"headline": "在自然中学习,在游戏中成长",
"tagline": "草原是最好的教室,大自然是最好的老师",
"description": "呼籁小蒙马研学课程以LNTLeave No Trace自然教育理念为核心,结合呼伦贝尔草原、森林、湿地等多种生态系统,设计了覆盖3-15岁全年龄段的系统化自然教育课程体系。每门课程均由自然教育专家和儿童教育专家共同开发,注重动手实践、启发式引导和深度体验。",
"values": [
{
"label": "自然启蒙",
"desc": "在真实的草原环境中建立对自然的认知和情感连接"
},
{
"label": "动手实践",
"desc": "以行动为中心的学习,不只是看和听,而是真正去做"
},
{
"label": "年龄分层",
"desc": "针对不同年龄段认知特点,定制学习深度和表达方式"
},
{
"label": "家庭共学",
"desc": "父母与孩子共同参与,在旅途中建立珍贵的家庭记忆"
}
]
},
"instructors": {
"placeholder": [
{
"name": "自然教育师(招募中)",
"title": "LNT认证自然教育师",
"credentials": "LNT认证 · 儿童自然教育专业培训",
"bio": "我们正在招募有热情的自然教育师加入小蒙马团队,如果你热爱草原、热爱孩子,欢迎联系我们。"
},
{
"name": "草原向导 · 牧民老师",
"title": "本地牧民导师",
"credentials": "世居牧民家庭 · 草原生活实践者",
"bio": "来自呼伦贝尔的牧民老师,用最真实的草原生活经验教孩子认识马、牛、羊,以及草原上的动植物。"
}
]
}
}

查看文件

@ -1,38 +1,91 @@
{
"trustStats": [
{ "value": "10000+", "unit": "组", "label": "已服务家庭" },
{ "value": "11", "unit": "年", "label": "深耕呼伦贝尔" },
{ "value": "2", "unit": "小时", "label": "定制师响应时效" },
{ "value": "0", "unit": "元", "label": "咨询费用" }
],
"trustStats": [],
"durations": [
{ "value": "5天4晚", "label": "5天4晚经典版" },
{ "value": "6天5晚", "label": "6天5晚深度版" },
{ "value": "7天6晚", "label": "7天6晚全面版" }
{
"label": "4天3晚精华版",
"value": "4天3晚"
},
{
"label": "5天4晚经典版",
"value": "5天4晚"
},
{
"label": "6天5晚亲子/探索版)",
"value": "6天5晚"
},
{
"label": "7天6晚深度/狂野版)",
"value": "7天6晚"
}
],
"activities": [
{ "value": "亲子活动", "label": "亲子活动" },
{ "value": "旅拍", "label": "旅拍" },
{ "value": "骑马", "label": "骑马" },
{ "value": "蒙古包住宿", "label": "蒙古包住宿" },
{ "value": "草原露营", "label": "草原露营" },
{ "value": "私人牧场", "label": "私人牧场" }
{
"label": "亲子活动",
"value": "亲子活动"
},
{
"label": "旅拍",
"value": "旅拍"
},
{
"label": "骑马",
"value": "骑马"
},
{
"label": "蒙古包住宿",
"value": "蒙古包住宿"
},
{
"label": "草原露营",
"value": "草原露营"
},
{
"label": "私人牧场",
"value": "私人牧场"
}
],
"budgets": [
{ "value": "5000元以下", "label": "5,000 元以下" },
{ "value": "5000-8000元", "label": "5,000 — 8,000 元" },
{ "value": "8000-12000元", "label": "8,000 — 12,000 元" },
{ "value": "12000元以上", "label": "12,000 元以上" },
{ "value": "不限预算", "label": "不限预算" }
{
"label": "5,000 元以下",
"value": "5000元以下"
},
{
"label": "5,000 — 8,000 元",
"value": "5000-8000元"
},
{
"label": "8,000 — 12,000 元",
"value": "8000-12000元"
},
{
"label": "12,000 元以上",
"value": "12000元以上"
},
{
"label": "不限预算",
"value": "不限预算"
}
],
"process": [
{ "title": "填写需求", "desc": "告诉我们出行人数、日期和特殊需求" },
{ "title": "定制师联系", "desc": "2小时内专属定制师通过微信联系您" },
{ "title": "方案确认", "desc": "根据您的需求定制专属行程方案" },
{ "title": "出发享玩", "desc": "一家一单一车,全程专属陪伴" }
{
"desc": "告诉我们几口人、想玩几天、有没有特别的期待",
"title": "填写需求"
},
{
"desc": "专属定制师通过微信联系您,0元咨询费",
"title": "2小时内回复"
},
{
"desc": "行程、住宿、费用明细一次说清,所有细节写进合同",
"title": "拿到专属方案"
},
{
"desc": "一家一单一车,全程只服务你们一个家庭",
"title": "出发,只属于你家"
}
],
"contact": {
"wechat": "hulai1814",
"tip": "工作时间 9:00 — 21:00,节假日不休"
"tip": "工作时间 09:00 — 21:00,节假日不休",
"wechat": "扫码添加微信"
}
}
}

查看文件

@ -5,7 +5,6 @@
"name": "莫日格勒河",
"subtitle": "天下第一曲水 · 老舍笔下的草原河曲",
"tag": "草原核心",
"seasons": ["summer", "autumn", "winter"],
"description": "1961年老舍来这儿考察,脱口而出「天下第一曲水」,这名号就此传开。河本身不宽,有些河段窄到你觉得一步就能跨过去,但它在三百公里的草原上拐出了上千个弯。从牧云山顶或断崖制高点往下看,河道的S弯一层套一层,两岸吃草的牛羊像散落的棋子,那种辽阔感是照片拍不出来的。呼籁旅行的自营营地就扎在莫日格勒河畔,早起出帐篷两分钟走到河边,晨雾配合日出光线,出片率极高。草原深处没手机信号,跟着我们的车队走才不会迷路。",
"highlights": [
"牧云山顶/断崖俯瞰河曲全景——目前公认最佳机位,比金帐汗那边角度好",
@ -15,31 +14,18 @@
"穿越草原腹地到营地的路本身就是体验——便道、牛群、无信号"
],
"bestSeason": {
"primary": "7月-8月",
"secondary": "6月、9月",
"description": "7-8月草最绿水最丰,骑马体验最佳。6月人少但草还没完全长起来,9月开始变黄也别有味道。冬季雪原覆盖的莫日格勒河又是另一种震撼。"
"primary": "7月-8月"
},
"tips": [
"景区不能自驾随意进入,有摆渡费;住营地的可以自驾进",
"草原深处没手机信号,千万不要自己开车乱跑碾压草原,罚款很重",
"拍全景最佳时间早晨6-8点,正午光线太平拍不出层次",
"穿长裤运动鞋,草地里有虫,别穿凉鞋和裙子",
"营地BBQ旺季名额有限,提前预约"
],
"heroImage": "/images/destinations/moriguole.jpg",
"relatedProducts": ["v9-5d4n-forest", "v9-5d4n-prairie", "v9-6d5n-family", "v9-6d5n-explore", "v9-7d6n-family", "v9-7d6n-wild"],
"seo": {
"title": "莫日格勒河旅游攻略 - 天下第一曲水怎么玩 | 呼籁旅行",
"description": "莫日格勒河是呼伦贝尔必游景点,被誉为天下第一曲水。从牧云山顶俯瞰河曲、骑马、营地入住……呼籁旅行自营营地就在河畔,带你深度体验草原腹地。",
"keywords": "莫日格勒河,天下第一曲水,呼伦贝尔景点,草原骑马,牧云山顶"
}
"seasons": [
"summer"
]
},
{
"id": "eergunashire",
"name": "额尔古纳湿地",
"subtitle": "亚洲第一湿地 · 根河的Ω形大弯",
"tag": "生态景观",
"seasons": ["summer", "autumn"],
"description": "号称「亚洲第一湿地」,从额尔古纳市区开车3公里就到,不算远。核心体验就是爬到海拔720米的主峰观景台往下看——根河拐出的一个完美Ω形大弯和一个形状像树叶的湖心岛,绿色铺到天际线,河道像大地的血管蜿蜒其中。说实话,走到山顶那一刻确实被震住了。木栈道下山一路视角不断变化,每一段都值得停下来。秋季9月下旬到10月初来最震撼,湿地从绿变黄变红,颜色层次极其丰富。",
"highlights": [
"登顶观景台看Ω形河弯和叶形湖心岛——所有宣传照都是这个角度",
@ -49,30 +35,18 @@
"河里有鱼、岸边有水鸟,运气好能看到丹顶鹤"
],
"bestSeason": {
"primary": "9月中旬-10月初",
"secondary": "7月-8月",
"description": "秋季拍照最美,颜色层次极丰富。夏季生态最丰富,碧绿一片也很震撼。"
"primary": "9月中旬-10月初"
},
"tips": [
"爬山到观景台大概30-40分钟,有台阶但不算陡,老人孩子能走",
"夏季蚊虫多,驱蚊液必备",
"建议安排1.5-2小时游览",
"早晨有晨雾,建议6点前到达等最美光线"
],
"heroImage": "/images/destinations/eergunashire.jpg",
"relatedProducts": ["v9-6d5n-family", "v9-7d6n-wild"],
"seo": {
"title": "额尔古纳湿地旅游攻略 - 亚洲第一湿地怎么玩 | 呼籁旅行",
"description": "额尔古纳湿地被誉为亚洲第一湿地,登顶看Ω形河弯。呼籁旅行带你错峰体验最美湿地生态景观。",
"keywords": "额尔古纳湿地,亚洲第一湿地,根河湿地,呼伦贝尔秋景"
}
"seasons": [
"summer"
]
},
{
"id": "baihualin",
"name": "白桦林",
"subtitle": "国内面积最大的纯生白桦林 · 亲子拍照圣地",
"tag": "森林体验",
"seasons": ["summer", "autumn"],
"description": "在额尔古纳到恩和的省道边上,将近1000公顷的纯生白桦林,国内面积最大的。树干白得发亮,阳光透过树冠洒下来确实好看。景区开发得比较成熟,分了好几个主题区,不算原生态体验,但胜在拍照出片率高,带孩子来也有地方玩。呼籁安排的行程里,白桦林有非遗传承人现场教桦树皮画,按年龄分层体验——这个才是这里最值得的环节。秋季9月底白桦叶变金黄,配白色树干,随手拍都是大片。",
"highlights": [
"非遗传承人现场教桦树皮画,按孩子年龄分层体验",
@ -82,30 +56,19 @@
"全地形越野车穿越白桦林——往返12公里自由驰骋"
],
"bestSeason": {
"primary": "9月下旬-10月初",
"secondary": "7月-8月",
"description": "秋季色彩最美。夏季林中清凉,适合避暑和亲子体验。"
"primary": "9月下旬-10月初"
},
"tips": [
"拍照穿亮色衣服(红色、黄色),白桦林做背景很出效果",
"夏季林中蚊虫多,长袖长裤加驱蚊液",
"整个景区走一圈大概1.5-2小时",
"时间有限的话至少走空中栈道和驯鹿苑,这两个最值"
],
"heroImage": "/images/destinations/baihualin.jpg",
"relatedProducts": ["v9-5d4n-forest", "v9-6d5n-family", "v9-7d6n-family"],
"seo": {
"title": "白桦林景区攻略 - 非遗体验+亲子拍照 | 呼籁旅行",
"description": "白桦林景区是国内面积最大的纯生白桦林,呼籁旅行安排非遗传承人教桦树皮画、越野车穿越、驯鹿喂食等深度体验。",
"keywords": "白桦林,白桦林景区,呼伦贝尔白桦林,桦树皮画,亲子体验"
}
"seasons": [
"summer",
"autumn"
]
},
{
"id": "enhe-shiwei",
"name": "恩和·室韦",
"subtitle": "华俄后裔的木刻楞村落 · 边境安宁小镇",
"tag": "民族文化",
"seasons": ["summer", "autumn", "winter"],
"description": "两个村子离得不远但气质不同。室韦开发早,主街热闹,商业化明显;恩和安静得多,蒙语意思就是「和平安宁」,入选了中国传统村落名录。居民都是华俄后裔,长着混血面孔说着东北话,住的是俄式木刻楞房子,冬暖夏凉。最有意思的体验是去列巴坊看大妈现烤列巴面包,配上自家腌的酸黄瓜和蓝莓酱,再喝杯俄式果茶。呼籁的行程安排在恩和骑马穿越——穿越草原、湿地、森林、河流四种地形,和其他地方骑马感受完全不同。",
"highlights": [
"恩和沉浸式骑马穿越——草原、湿地、森林、河流四种地形",
@ -115,30 +78,19 @@
"画套娃、做列巴、品俄式果茶——沉浸式文化体验"
],
"bestSeason": {
"primary": "7月-8月",
"secondary": "9月",
"description": "夏季绿意最浓,骑马体验最佳。9月秋色开始,边防公路两侧层林尽染。冬季恩和雪中骑马是独特体验。"
"primary": "7月-8月"
},
"tips": [
"如果只能去一个,推荐恩和——更安静更有生活气息,商业味淡",
"列巴要上午去买,下午基本卖完",
"住宿以木刻楞民宿为主,旺季务必提前预订",
"夜里气温低,即使夏天也要带件薄外套"
],
"heroImage": "/images/destinations/shiwei.jpg",
"relatedProducts": ["v9-5d4n-forest", "v9-5d4n-prairie", "v9-6d5n-family", "v9-6d5n-explore", "v9-7d6n-family", "v9-7d6n-wild"],
"seo": {
"title": "恩和室韦旅游攻略 - 华俄后裔村落深度体验 | 呼籁旅行",
"description": "恩和室韦是华俄后裔聚居的边境小镇,木刻楞民居、手工列巴、沉浸式骑马穿越。呼籁旅行带你深度体验额尔古纳河畔的民族文化。",
"keywords": "恩和,室韦,木刻楞,俄罗斯族,额尔古纳河,边境骑马"
}
"seasons": [
"summer",
"autumn"
]
},
{
"id": "heishantou",
"name": "黑山头",
"subtitle": "呼伦贝尔骑马首选地 · 边境日落",
"tag": "骑马体验",
"seasons": ["summer", "autumn"],
"description": "黑山头是呼伦贝尔公认的骑马最佳地点,原因很简单——这边草原特别开阔平坦,视野好,马场多且正规。不是景区里牵着走一小圈的那种,而是马倌带路你自己控马在草原上跑,大圈下来一个多小时。傍晚一定要去日落山,看夕阳把额尔古纳河和整片草原湿地染成金色。呼籁的探索版行程安排了恩和+黑山头两次骑马——白桦林间漫步和草原驰骋完全不同的体验。",
"highlights": [
"草原骑马穿越——自己控马不是牵马,大圈1-1.5小时真实骑行",
@ -148,30 +100,19 @@
"牧户家访——进蒙古包挤牛奶、喂小羊、喝奶茶"
],
"bestSeason": {
"primary": "7月-8月",
"secondary": "9月",
"description": "夏季草原最绿最适合骑马。9月草原变黄,日落更有层次。"
"primary": "7月-8月"
},
"tips": [
"骑马穿长裤硬底鞋,别穿紧身裤和凉鞋,容易磨",
"小朋友必须马夫牵马,安全第一",
"黑山头属边境管理区,必须带身份证",
"日落山建议下午5点后前往,留够等日落的时间"
],
"heroImage": "/images/destinations/heishantou.jpg",
"relatedProducts": ["v9-6d5n-explore"],
"seo": {
"title": "黑山头旅游攻略 - 草原骑马与边境日落 | 呼籁旅行",
"description": "黑山头是呼伦贝尔骑马首选地,自己控马驰骋草原、日落山赏金色湿地。呼籁旅行安排正规马场深度骑行体验。",
"keywords": "黑山头,草原骑马,黑山头日落,边境草原,呼伦贝尔骑马"
}
"seasons": [
"summer",
"autumn"
]
},
{
"id": "manzhouli",
"name": "满洲里",
"subtitle": "中俄蒙三国交汇的异域边城",
"tag": "边境文化",
"seasons": ["summer", "autumn", "winter"],
"description": "满洲里不像一个中国城市,更像是把俄罗斯小城搬了一半过来。街上到处是俄文招牌,餐厅菜单有俄文版,路上能碰到真正的俄罗斯人来采购。套娃广场那个巨型套娃建筑里面其实是个酒店,周围大大小小的套娃到了晚上全亮灯,效果很梦幻。国门景区能看到对面俄罗斯的后贝加尔斯克小镇。带孩子来最好——满洲里是少有的能让小孩主动问问题的地方:那个大套娃里面住着谁?对面河那边是哪个国家?",
"highlights": [
"套娃广场夜景——晚上亮灯后整个广场变成童话世界,白天别去",
@ -181,30 +122,20 @@
"俄式餐厅——红菜汤和手工列巴味道正宗"
],
"bestSeason": {
"primary": "6月-8月",
"secondary": "12月-2月",
"description": "夏季气候最好,夜景最美。冬季雪景和冰灯也有特色,冬季北线行程必经。"
"primary": "6月-8月"
},
"tips": [
"套娃广场白天看没什么感觉,一定要等到晚上灯亮了再去",
"国门景区门票80元/人,外籍人士不可进入",
"买套娃纪念品认准木质手工的,塑料机器做的不值",
"俄式餐厅推荐尝试红菜汤和手工列巴"
],
"heroImage": "/images/destinations/manzhouli.jpg",
"relatedProducts": ["v9-5d4n-prairie", "v9-6d5n-family", "v9-6d5n-explore"],
"seo": {
"title": "满洲里旅游攻略 - 套娃广场国门怎么玩 | 呼籁旅行",
"description": "满洲里是中俄蒙三国交汇的口岸城市,套娃广场夜景、国门、俄式美食。呼籁旅行为家庭定制满洲里深度游方案。",
"keywords": "满洲里,套娃广场,国门景区,中俄边境,满洲里夜景"
}
"seasons": [
"summer",
"autumn",
"winter"
]
},
{
"id": "aershan",
"name": "阿尔山国家森林公园",
"subtitle": "AAAAA级 · 火山天池群 · 温泉之都",
"tag": "地质奇观",
"seasons": ["autumn", "winter"],
"description": "阿尔山不是一座山,是一座小城,蒙语意思是「热的圣水」,说的就是温泉。森林公园是AAAAA级加世界地质公园,面积10万公顷,里面有50多座火山锥、19个火山口、8个天池。一天根本逛不完,门票可以两天内重复进园。必须去的是驼峰岭天池——火山口积水形成的湖,蓝得不真实,需要爬山但不高。杜鹃湖也值得,月牙形湖面春天周围开满杜鹃花。冬季的阿尔山是嗨冰雪线路的核心——白狼峰日出、不冻河、百里雾凇画廊、泡温泉,都安排在这。",
"highlights": [
"驼峰岭天池——阿尔山天池群中最大最深的,蓝得不真实",
@ -214,23 +145,53 @@
"ATV卡丁车森林穿越——在林间小道上驾驶全地形车"
],
"bestSeason": {
"primary": "9月中旬秋色",
"secondary": "12月-2月冬景、5-6月杜鹃花",
"description": "秋季金色林海最震撼。冬季白狼峰日出和不冻河是嗨冰雪核心体验。5-6月杜鹃花盛开漫山粉红。夏季7-8月避暑也不错。"
"primary": "9月中旬秋色"
},
"tips": [
"公园很大建议分两天逛,门票支持两日内重复进园",
"景点优先级:驼峰岭天池 > 大峡谷 > 杜鹃湖 > 天池 > 石塘林",
"石塘林步道有台阶,推婴儿车不方便",
"海拔较高早晚温差大,即使夏天也带件外套",
"冬季来务必全副武装,手机贴暖宝宝否则秒关机"
],
"heroImage": "/images/destinations/aershan.jpg",
"relatedProducts": ["winter-south-5d4n", "winter-south-6d5n", "autumn-south-4d3n", "autumn-south-5d4n", "autumn-south-7d6n"],
"seasons": [
"autumn",
"winter"
]
},
{
"id": "shiwei",
"name": "室韦·恩和",
"subtitle": "中国俄罗斯族第一村 · 边境秘境",
"tag": "民族文化",
"description": "室韦和恩和是额尔古纳河畔两座毗邻的边境小村,也是中国俄罗斯族聚居最集中的地方,被誉为「中国俄罗斯族第一村」。这里的居民多为中俄混血后裔,至今保留着俄罗斯族的生活习俗:木刻楞民居、手工列巴面包、俄式点心……走进村子,仿佛置身于西伯利亚的某个小村落。额尔古纳河在村前流淌,对岸便是俄罗斯,中俄两国鸡犬相闻的奇特景象在这里真实上演。室韦的夜晚宁静安详,星空灿烂如宝石,是厌倦城市喧嚣、寻求深度旅行体验的家庭的理想目的地。",
"highlights": [
"参观俄罗斯族木刻楞民居,了解中俄混血文化的独特生活方式",
"品尝手工列巴和俄式点心,体验正宗俄罗斯族传统美食",
"额尔古纳河边远眺对岸俄罗斯,感受中俄边境的历史沧桑",
"室韦星空观测,远离城市光污染的绝佳观星胜地",
"骑马穿越边境草原,感受额尔古纳河流域独特的自然风光"
],
"bestSeason": {
"primary": "7月-8月",
"secondary": "9月",
"description": "夏季绿意最浓,骑马和额尔古纳河景色最佳。9月秋色开始,边防公路两侧层林尽染。"
},
"heroImage": "/images/destinations/shiwei.jpg",
"seasons": [
"summer",
"autumn"
],
"tips": [
"室韦开发较早商业气息浓,恩和更安静有生活气息,推荐两个都去",
"额尔古纳河边可以望对岸俄罗斯村庄,注意不要越境",
"列巴面包上午去买,下午基本售罄",
"夜里气温低,即使夏天也要带薄外套"
],
"relatedProducts": [
"v9-5d4n",
"v9-6d5n-family",
"v9-7d6n-family",
"v9-7d6n-wild"
],
"seo": {
"title": "阿尔山国家森林公园攻略 - 火山天池温泉怎么玩 | 呼籁旅行",
"description": "阿尔山国家森林公园AAAAA级景区,驼峰岭天池、不冻河、石塘林。呼籁旅行秋季游牧的森林和冬季嗨冰雪产品线都覆盖阿尔山。",
"keywords": "阿尔山,阿尔山森林公园,驼峰岭天池,不冻河,白狼峰"
"title": "室韦·恩和旅游攻略 - 中国俄罗斯族第一村 | 呼籁旅行",
"description": "室韦恩和是华俄后裔聚居的边境秘境,木刻楞民居、手工列巴、额尔古纳河边望俄罗斯。呼籁旅行带你深度体验这片独特的中俄边境风情。",
"keywords": "室韦,恩和,中国俄罗斯族,木刻楞,列巴,额尔古纳河,边境旅游"
}
},
{
@ -238,7 +199,6 @@
"name": "大兴安岭·莫尔道嘎",
"subtitle": "中国最后一片寒温带原始森林 · 森林小火车",
"tag": "森林探秘",
"seasons": ["summer", "autumn"],
"description": "莫尔道嘎国家森林公园是中国最后一片寒温带明亮针叶原始森林,森林覆盖率94.97%。最大的卖点是森林观光小火车——三节车厢全程9.87公里,时速15公里,绕公园一圈大约一个半小时。小火车穿行在林海里确实有童话感,沿途设了几个站可以下车拍照。最后一站有野生小松鼠和可以喂的小鹿,孩子特别开心。呼籁夏季亲子版行程安排了森林小火车+兴安神鹿园喂驯鹿,从草原走进森林,一路风景完全不同。",
"highlights": [
"森林小火车穿行原始森林——全程9.87公里,每站可下车游览拍照",
@ -248,30 +208,19 @@
"原始森林徒步——空气负氧离子含量极高,真正的森林浴"
],
"bestSeason": {
"primary": "9月底-10月初",
"secondary": "7月-8月",
"description": "秋季色彩最震撼,但10月中旬后就开始落叶了别来太晚。夏季森林最绿最凉快。"
"primary": "9月底-10月初"
},
"tips": [
"小火车有开窗和封闭式两种车厢可选",
"至少在樟子松林站和最后一站下车,这两站最值",
"森林里蚊虫多,驱蚊液必带",
"莫尔道嘎镇上住宿条件一般,心理准备要有"
],
"heroImage": "/images/destinations/daxinganling.jpg",
"relatedProducts": ["v9-5d4n-forest", "v9-7d6n-family"],
"seo": {
"title": "大兴安岭莫尔道嘎攻略 - 森林小火车+驯鹿 | 呼籁旅行",
"description": "莫尔道嘎国家森林公园是中国最后一片寒温带原始森林,森林小火车、喂驯鹿、秋季层林尽染。呼籁旅行带你从草原走进森林。",
"keywords": "莫尔道嘎,大兴安岭,森林小火车,驯鹿,原始森林"
}
"seasons": [
"summer",
"autumn"
]
},
{
"id": "hulunhu",
"name": "呼伦湖",
"subtitle": "北方第一大湖 · 冬季穿越蓝冰",
"tag": "湖泊景观",
"seasons": ["summer", "winter"],
"description": "呼伦湖是内蒙古最大的湖泊,面积约2339平方公里。夏季碧波万顷,岸线蜿蜒800多公里,和草原连成一片,日落时分整个湖面被染成金色。但真正让人印象深刻的反而是冬季——呼伦湖结冰后形成壮观的蓝冰,嗨冰雪北线行程安排了穿越呼伦湖蓝冰,在冰面上行走的体验完全不一样。湖里产鲤鱼、鲫鱼、白鱼,现捕现做的全鱼宴是来这儿的必吃项目。",
"highlights": [
"冬季穿越蓝冰——呼伦湖结冰后形成的蓝冰奇观,嗨冰雪北线核心体验",
@ -281,30 +230,19 @@
"风车公路——通往呼伦湖的公路两侧风力发电机阵列"
],
"bestSeason": {
"primary": "7月-8月",
"secondary": "12月-2月",
"description": "夏季湖水最美日落震撼。冬季蓝冰穿越是嗨冰雪北线的亮点。"
"primary": "7月-8月"
},
"tips": [
"湖面开阔风大,夏季午后常有阵雨,备雨具",
"日落观赏建议下午5点后前往湖西岸",
"湖水不建议游泳,风浪较大有安全风险",
"冬季蓝冰穿越需要专业领队带领,不可自行下湖"
],
"heroImage": "/images/destinations/hulunhu.jpg",
"relatedProducts": ["winter-north-7d6n"],
"seo": {
"title": "呼伦湖旅游攻略 - 蓝冰穿越与日落美景 | 呼籁旅行",
"description": "呼伦湖是内蒙古最大湖泊,夏季日落壮观,冬季蓝冰穿越震撼。呼籁旅行嗨冰雪北线带你冬季穿越呼伦湖蓝冰。",
"keywords": "呼伦湖,呼伦湖蓝冰,呼伦贝尔湖泊,草原日落,冬季穿越"
}
"seasons": [
"summer",
"autumn"
]
},
{
"id": "aoluguya",
"name": "敖鲁古雅驯鹿部落",
"subtitle": "中国唯一的驯鹿民族 · 鄂温克使鹿文化",
"tag": "民族探访",
"seasons": ["summer", "winter"],
"description": "这是中国唯一的驯鹿部落,鄂温克族是中国仅存的游猎民族。但说实话现在游客去的「敖鲁古雅」是政府修建的旅游景区,不是真正的猎民营地——真正的鄂温克猎民和驯鹿生活在150公里外的深山密林里。景区里能喂驯鹿、看博物馆、了解桦皮文化和萨满文化,商业化程度不低但如果调整好预期带孩子来还是很有教育意义的。冬季嗨冰雪北线安排了深入根河方向的布冬霞驯鹿部落,坐驯鹿雪橇、穿鄂温克民族服饰,体验更真实一些。",
"highlights": [
"近距离喂驯鹿——买苔藓喂食拍照,驯鹿很温顺",
@ -314,30 +252,20 @@
"鄂温克民族服饰体验——穿上传统服饰在雪地里拍照"
],
"bestSeason": {
"primary": "7月-8月",
"secondary": "12月-2月",
"description": "夏季驯鹿在户外活动多,可以近距离互动。冬季可体验驯鹿雪橇等冰雪项目。"
"primary": "7月-8月"
},
"tips": [
"景区商业化程度不低,喂驯鹿买苔藓要钱,拍照也有收费项目",
"想了解鄂温克文化,博物馆比户外区更值得花时间",
"建议安排1.5-2小时",
"景区在根河满归方向,从根河市区过去还有一段路"
],
"heroImage": "/images/destinations/aoluguya.jpg",
"relatedProducts": ["winter-north-7d6n"],
"seo": {
"title": "敖鲁古雅驯鹿部落攻略 - 中国唯一驯鹿民族 | 呼籁旅行",
"description": "敖鲁古雅是中国唯一的驯鹿部落,鄂温克族使鹿文化独一无二。呼籁旅行嗨冰雪北线带你深入根河体验驯鹿雪橇。",
"keywords": "敖鲁古雅,驯鹿部落,鄂温克族,驯鹿雪橇,根河"
}
"seasons": [
"summer",
"autumn",
"winter"
]
},
{
"id": "genhe",
"name": "根河·中国冷极",
"subtitle": "历史最低温-58°C · 不冻河奇观",
"tag": "冷极探秘",
"seasons": ["winter", "summer"],
"description": "根河是中国官方认定的最冷城市,历史最低温零下58度。但大多数游客不是冬天来的——夏天的根河其实是个避暑胜地,七八月也就20度出头。冬天来的话,泼水成冰是必玩项目零下三四十度往空中泼热水瞬间变成冰晶散开,怎么拍怎么好看。嗨冰雪北线的行程最后安排在根河——布冬霞驯鹿部落喂驯鹿、铁锹烤肉、鄂温克民族服饰体验,然后从根河返回海拉尔。",
"highlights": [
"泼水成冰——零下三四十度的经典打卡体验,怎么拍怎么好看",
@ -347,24 +275,12 @@
"夏季避暑——七八月白天20度左右,原始森林负氧离子爆表"
],
"bestSeason": {
"primary": "12月-2月",
"secondary": "7月-8月",
"description": "冬季是核心卖点,零下三四十度的极寒体验。夏季避暑+森林生态也很舒服。"
"primary": "12月-2月"
},
"tips": [
"冬季来务必全副武装:及膝羽绒服、雪地靴、棉帽手套面罩一样不能少",
"手机贴暖宝宝否则秒关机,多备几块暖宝宝",
"室外停留不要超过30分钟就进屋暖一下",
"夏季蚊虫很多,驱蚊液防晒霜都要带",
"住宿条件有限,别抱太高期待"
],
"heroImage": "/images/destinations/genhe.jpg",
"relatedProducts": ["winter-north-7d6n"],
"seo": {
"title": "根河旅游攻略 - 中国冷极泼水成冰 | 呼籁旅行",
"description": "根河是中国最冷城市,历史最低温-58°C。泼水成冰、不冻河、铁锹烤肉——呼籁旅行嗨冰雪北线带你深入中国冷极。",
"keywords": "根河,中国冷极,泼水成冰,不冻河,铁锹烤肉"
}
"seasons": [
"winter"
]
}
]
}
}

查看文件

@ -1,13 +1,13 @@
{
"title": "亲子游目的地怎么选?",
"subtitle": "一份客观对比,帮你找到最适合全家的那个答案",
"intro": "很多家庭在规划暑假亲子游时,会在呼伦贝尔、新疆和内蒙古西部之间犹豫。三个目的地各有魅力,以下是我们基于真实数据的客观对比,不贬低任何目的地,只帮你找到最适合带孩子去的那个。",
"intro": "很多家庭在规划暑假亲子游时,会在呼伦贝尔、新疆北疆和呼和浩特周边草原之间犹豫。三个目的地各有魅力,以下是我们基于真实数据的客观对比,不贬低任何目的地,只帮你找到最适合带孩子去的那个。",
"destinations": [
{
"highlight": true,
"id": "hulunbuir",
"name": "呼伦贝尔",
"tag": "草原+森林+湿地",
"highlight": true
"tag": "草原+森林+湿地"
},
{
"id": "xinjiang",
@ -16,8 +16,8 @@
},
{
"id": "west-inner-mongolia",
"name": "内蒙古西部",
"tag": "沙漠+胡杨+戈壁"
"name": "呼和浩特周边",
"tag": "希拉穆仁+辉腾锡勒+响沙湾"
}
],
"dimensions": [
@ -27,7 +27,7 @@
"values": [
"均温20-21°C,天然避暑胜地",
"21-31°C,部分地区可达35°C+",
"额济纳夏季40°C+,不适合暑期出行"
"呼和浩特17-28°C,响沙湾沙漠区域体感更热"
]
},
{
@ -36,7 +36,7 @@
"values": [
"2-3小时,日行150-250km",
"6-8小时,日行400-600km",
"额济纳从银川出发需8-9小时"
"景点集中,希拉穆仁80km、辉腾锡勒110km、响沙湾180km,3-4天可走完"
]
},
{
@ -45,7 +45,7 @@
"values": [
"600-770m,零高反风险",
"赛里木湖2072m、巴音布鲁克2500m,有轻微高反可能",
"900-1500m,无高反风险"
"呼和浩特1050m,辉腾锡勒1800-2100m,整体无高反风险"
]
},
{
@ -54,7 +54,7 @@
"values": [
"草原+森林+湿地+河流+湖泊+边境小镇,紧凑环线一次体验",
"雪山+高山草甸+峡谷+湖泊极其壮美,但景点间距极大",
"以沙漠戈壁为主,额济纳胡杨林仅10月可看"
"草原+沙漠两种体验可兼得,行程紧凑高效,但草原辽阔感不如呼伦贝尔"
]
},
{
@ -63,7 +63,7 @@
"values": [
"2024年全年3443万人次,区域25.3万km²,体感不拥挤",
"2024年全年3.02亿人次,独库公路日通车超2万辆",
"额济纳仅10月旺季拥挤,其他季节游客极少"
"希拉穆仁暑期团队游较多,响沙湾人气旺但设施成熟不用排太久"
]
},
{
@ -72,7 +72,7 @@
"values": [
"地势平坦安全,成熟亲子营+研学体系,孩子跑得开",
"长途车程对孩子不友好,山路+高海拔有一定风险",
"沙漠体验为主,夏季高温不适合儿童长时间户外"
"响沙湾沙漠项目丰富孩子爱玩,草原部分体验较浅,适合首次体验草原+沙漠的家庭"
]
},
{
@ -81,7 +81,7 @@
"values": [
"家庭4人5-7天约1-1.7万(含北京出发机票)",
"家庭4人7-10天约1.8-3.5万(距离远天数多)",
"因目的地差异大,鄂尔多斯3-5天约0.8-1.5万"
"家庭4人3-4天约0.5-1万,行程短费用低,性价比高"
]
},
{
@ -90,7 +90,7 @@
"values": [
"蒙古族+俄罗斯族+鄂温克族,三重文化交融",
"哈萨克族+维吾尔族+丝路历史,多民族风情",
"蒙古族文化为主,但体验项目相对有限"
"蒙古族文化+沙漠娱乐,适合短途初体验,深度稍浅"
]
}
],
@ -98,7 +98,6 @@
"title": "我们的坦诚",
"subtitle": "呼伦贝尔也有不完美的地方",
"items": [
"蚊虫:夏季草原湿地蚊虫较多,尤其河边,需要做好防蚊准备",
"旺季房紧7月中旬至8月中旬住宿紧张且价格上浮,建议提前1-2个月预订",
"南方航班少:广州、深圳出发直飞航班有限,可能需要中转",
"壮观度:呼伦贝尔的风景是辽阔舒展型的,不如新疆雪山峡谷那般「震撼」"
@ -106,7 +105,7 @@
},
"closing": {
"title": "为什么呼籁只做呼伦贝尔?",
"text": "新疆很美,内蒙古西部也有独特风光。但我们选择只做呼伦贝尔一地,是因为11年的深耕让我们确信对带孩子的家庭来说,短车程、低海拔、凉爽气温、丰富体验——呼伦贝尔是综合最优解。我们把所有精力放在一个地方,才能把每一条路线、每一个营地、每一位领队都打磨到最好。不是呼伦贝尔什么都好,而是对家庭亲子游这件事,它真的很合适。"
"text": "新疆壮美,呼和浩特周边方便,每个目的地都有自己的好。但我们选择只做呼伦贝尔,是因为11年的深耕让我们确信如果你有5-7天假期,想带孩子看真正辽阔的草原、穿越森林湿地、体验多民族文化——呼伦贝尔是综合最优解。我们把所有精力放在一个地方,才能把每一条路线、每一个营地、每一位领队都打磨到最好。不是其他地方不好,而是对家庭亲子游这件事,呼伦贝尔真的很合适,而我们恰好最懂它。"
},
"dataSources": "气温数据来源中国气象局;旅游人次数据来源呼伦贝尔市2024年统计公报、新疆维吾尔自治区文旅厅;距离数据来源高德地图实测"
}
}

查看文件

@ -7,7 +7,7 @@
{
"id": "what-is-eqi",
"question": "额吉的故乡是什么?",
"answer": "额吉的故乡是呼籁旅行的核心产品系列,目前已迭代至V9版本。「额吉」在蒙古语中是「母亲」的意思,这个名字承载着呼籁对呼伦贝尔这片土地的深厚感情——希望每个来到这里的家庭,都能感受到草原如母亲般的温暖和包容。产品采用一家一单一车的定制模式,涵盖5天4晚到7天6晚共6个版本,满足不同家庭的假期安排和出行需求。",
"answer": "额吉的故乡是呼籁旅行的核心产品系列,目前已迭代至V9版本。「额吉」在蒙古语中是「母亲」的意思,这个名字承载着呼籁对呼伦贝尔这片土地的深厚感情——希望每个来到这里的家庭,都能感受到草原如母亲般的温暖和包容。产品采用一家一单一车的定制模式,涵盖4天3晚到7天6晚多个版本,满足不同家庭的假期安排和出行需求。",
"relatedLinks": [
{
"url": "/products",
@ -18,7 +18,7 @@
{
"id": "what-products",
"question": "呼籁有哪些产品?",
"answer": "呼籁旅行目前有两大产品线额吉的故乡V9系列和小蒙马夏令营。额吉的故乡V9系列是家庭亲子游产品,一家一单一车,提供5天4晚至7天6晚共6个版本,适合不同假期和偏好的家庭。小蒙马夏令营是亲子夏令营路线,6天5晚,每期8组家庭同行,爸爸妈妈带着孩子一起出发,融入草原写生、非遗研学、民俗体验三大主题。两大产品线都走呼伦贝尔核心线路,区别在于形式额吉的故乡是私家定制,小蒙马是亲子夏令营。",
"answer": "呼籁旅行目前有两大产品线额吉的故乡V9系列和小蒙马夏令营。额吉的故乡V9系列是家庭定制游产品,一家一单一车,提供4天3晚至7天6晚共6个版本,适合不同假期和偏好的家庭。小蒙马夏令营是亲子夏令营路线,6天5晚,每期8组家庭同行,爸爸妈妈带着孩子一起出发,融入草原写生、非遗研学、民俗体验三大主题。两大产品线都走呼伦贝尔核心线路,区别在于形式额吉的故乡是私家定制,小蒙马是亲子夏令营。",
"relatedLinks": [
{
"url": "/products",
@ -29,7 +29,7 @@
{
"id": "price-6d5n",
"question": "呼伦贝尔6天5晚多少钱?",
"answer": "影响最终费用的核心变量是三个出行人数几口人分摊车费和领队费、行程天数4天vs7天差异很大、住宿标准普通酒店vs品质酒店每晚差几百元。呼籁不在网上标固定价,是因为这三个变量不同,同样6天5晚可以差出几千元——用一个数字代替你家的真实情况对你不公平。可以告诉定制师你家几口人、想玩几天、大概预算,2小时内给你一份完整的费用明细包含什么、不包含什么、每一笔花在哪里,全部写进合同,不会中途加价。",
"answer": "呼籁旅行不在官网公示具体价格,因为每个家庭的人数、出行时间、住宿偏好不同,最终价格会有差异。但可以说清楚价格包含什么:全程专属用车和司机、精选住宿、专属领队服务、所有体验活动费用、旅行保险、呼籁自营旅拍服务等,没有隐形消费,不会中途加价。呼籁的价格确实比拼团游高,因为是一家一单一车的定制服务,品质和体验完全不同。建议直接联系定制师,根据您的具体需求获取详细报价。",
"relatedLinks": [
{
"url": "/contact",
@ -40,7 +40,7 @@
{
"id": "vs-group-tour",
"question": "亲子游和普通跟团什么区别?",
"answer": "三个本质区别。第一,你的车只拉你一家——跟团是30-50人挤大巴,景点门口堵车排队;呼籁是一家一单一车,想停就停,错峰走小路,别人堵车时你在山顶喝下午茶。第二,行程为你家设计——跟团走固定路线不能改,呼籁的行程根据孩子年龄、体能和你家偏好量身定制,5天4晚到7天6晚共6个版本,不是统一发货。第三,服务配置天壤之别——跟团1个导游管50人,呼籁是3管家车务+房务+客服)+ 1定制师 + 1专属领队,5个人全程只服务你们一家。",
"answer": "区别主要在三个方面。第一,出行方式不同——跟团是几十人大巴统一行动,呼籁是一家一单一车,自由度完全不同。第二,行程设计不同——跟团走标准景点打卡路线,呼籁的行程专门为家庭和孩子设计,节奏更合理,体验活动更丰富,包含骑马、草原滑草、ATV、观日出日落、访牧户等。第三,服务配置不同——跟团只有导游,呼籁配备3管家车务+房务+客服)+ 定制师 + 专属领队,全程只服务您一个家庭。",
"relatedLinks": [
{
"url": "/products",
@ -51,7 +51,7 @@
{
"id": "how-many-days-with-kids",
"question": "带小孩子选几天合适?",
"answer": "如果孩子在3-5岁,建议选6天5晚亲子版,行程节奏专门为小朋友设计,不会太赶。如果孩子在6岁以上,7天6晚深度版体验更完整,孩子的体力和好奇心都跟得上。假期有限的话,5天4晚版也能涵盖草原核心体验。总的来说,6天是大多数家庭的选择,时间和体验的平衡比较理想。出发前呼籁的定制师会根据孩子年龄推荐合适版本。",
"answer": "如果孩子在3-5岁,建议选6天5晚亲子版,行程节奏专门为小朋友设计,不会太赶。如果孩子在6岁以上,7天6晚深度版体验更完整,孩子的体力和好奇心都跟得上。假期有限的话,4天3晚精华版也能涵盖草原核心体验。总的来说,6天是大多数家庭的选择,时间和体验的平衡比较理想。出发前呼籁的定制师会根据孩子年龄推荐合适版本。",
"relatedLinks": [
{
"url": "/products#guide",
@ -62,24 +62,13 @@
{
"id": "summer-camp-age",
"question": "小蒙马夏令营适合几岁?",
"answer": "小蒙马夏令营是亲子夏令营,爸爸妈妈带着孩子一起参加,适合有学龄儿童的家庭。行程中的活动会根据孩子年龄适配难度,比如骑马教练会匹配合适的马匹,绘画老师会按基础指导,非遗手工也简单易操作。小蒙马和额吉的故乡的区别在于:额吉的故乡是一家一单一车的私家亲子游,小蒙马是每期8组家庭一起出发的亲子夏令营,孩子有伙伴一起玩,大人也能在团队氛围里放松。小蒙马还贴心设计了「爸妈托管」时段,专业工作人员带孩子做游戏,家长可以短暂休息。",
"answer": "小蒙马夏令营是亲子夏令营,爸爸妈妈带着孩子一起参加,适合有学龄儿童的家庭。行程中的活动会根据孩子年龄适配难度,比如骑马教练会匹配合适的马匹,绘画老师会按基础指导,非遗手工也简单易操作。小蒙马和额吉的故乡的区别在于:额吉的故乡是一家一单一车的私家定制游,小蒙马是每期8组家庭一起出发的亲子夏令营,孩子有伙伴一起玩,大人也能在团队氛围里放松。小蒙马还贴心设计了「爸妈托管」时段,专业工作人员带孩子做游戏,家长可以短暂休息。",
"relatedLinks": [
{
"url": "/summer-camp",
"text": "了解小蒙马夏令营"
}
]
},
{
"id": "senior-travel",
"question": "可以给爸妈单独报名吗?自己没时间陪。",
"answer": "可以的。很多客户带孩子来过呼伦贝尔之后,又给爸妈报了名。自己上班没时间陪,但希望父母也能体验一次靠谱的草原旅行。我们的「牵手草原」长辈定制行程专为父母和长辈设计,行程节奏更缓、住宿更舒适、服务更细致,全程有领队照顾,您不在身边也能放心。也支持爸妈和他们的朋友一起组团出发。联系定制师说明情况,我们会根据长辈的身体状况和偏好量身安排。",
"relatedLinks": [
{
"url": "/contact",
"text": "联系定制师咨询"
}
]
}
]
},
@ -120,17 +109,6 @@
}
]
},
{
"id": "summer-peak-season",
"question": "暑假去草原人多吗?需要提前多久订?",
"answer": "7月15日至8月5日是全年最旺的黄金期,热门营地和优质住宿在旺季通常提前2-3个月就已订满。如果确定暑假出行,越早订越好,6月初甚至更早开始沟通是常规操作。人多并不代表体验差——呼籁的「一家一单一车」模式意味着整个行程只有你一家人,没有其他游客打扰;草原足够大,莫日格勒河沿线和边境公路不是密集景区,感受不到城市景点的「人挤人」。暑假草原亲子游的最大优势是孩子正好放假、天气最好、草最绿、那达慕民俗活动最丰富。如果6月初或8月下旬出行,游客更少、价格相对友好,体验同样完整,是时间灵活家庭的优选。",
"relatedLinks": [
{
"url": "/calendar",
"text": "查看各月出行指南"
}
]
},
{
"id": "altitude-sickness",
"question": "呼伦贝尔有高原反应吗?",
@ -145,7 +123,7 @@
{
"id": "kids-safety",
"question": "带孩子去安全吗?",
"answer": "安全是呼籁最重视的事项。首先,呼籁的车辆和司机都有严格管理,车况定期检查,车辆配备儿童安全座椅。其次,呼籁配备专业领队,每天的活动都有安全评估和应急预案,领队随身携带急救包。第三,所有行程均购买旅游责任险保额1000万,签订正规电子合同。各项活动都有明确的安全规范骑马穿越全程有专业马师随行,年龄较小的孩子由马师牵引或抱着骑;ATV越野车2人一车系安全带,12岁以下需家长陪同;草原滑草要求身高1.2米以上独立乘坐,不足1.2米可和大人一起坐。0-3岁幼童有专属活动推荐,不建议参与骑马穿越和ATV等项目。呼籁额吉的故乡产品已服务超过10000个家庭、累计39000余人次出行,安全记录良好。",
"answer": "安全是呼籁最重视的事项。首先,呼籁的车辆和司机都有严格管理,车况定期检查,车辆配备儿童安全座椅。其次,呼籁配备专业领队,每天的活动都有安全评估和应急预案,领队随身携带急救包。第三,所有行程均购买旅游责任险保额1000万,签订正规电子合同。各项活动都有明确的安全规范骑马穿越全程有专业马师随行,年龄较小的孩子由马师牵引或抱着骑;ATV越野车2人一车系安全带,12岁以下需家长陪同;草原滑草要求身高1.2米以上独立乘坐,不足1.2米可和大人一起坐。0-3岁幼童有专属活动推荐,不建议参与骑马穿越和ATV等项目。呼籁已服务超过10000组家庭、累计近4万人次出行,安全记录良好。",
"relatedLinks": [
{
"url": "/reviews",
@ -162,7 +140,7 @@
{
"id": "is-reliable",
"question": "呼籁旅行怎么样靠谱吗?",
"answer": "呼籁旅行是呼伦贝尔本地品牌,隶属内蒙古呼籁文旅投资开发集团有限公司,旗下9家企业。集团核心旅行社主体——呼籁山河国旅成立于2005年,深耕呼伦贝尔11年。呼籁拥有自有车队、自有营地敖包相会景区旁、自营旅拍团队,额吉的故乡产品已服务超过10000个家庭、累计39000余人次。所有行程签订正规电子合同,旅游责任险保额1000万,全程无购物无隐形消费。您可以在客户评价页面查看真实的出行反馈。",
"answer": "呼籁旅行是呼伦贝尔本地品牌,隶属内蒙古呼籁文旅投资开发集团有限公司,旗下9家企业。集团核心旅行社主体——呼籁山河国旅成立于2005年,深耕呼伦贝尔11年。呼籁拥有自有车队、自有营地、自营旅拍团队,已服务超过10000组家庭、累计近4万人次。所有行程签订正规电子合同,旅游责任险保额1000万,全程无购物无隐形消费。您可以在客户评价页面查看真实的出行反馈。",
"relatedLinks": [
{
"url": "/reviews",
@ -188,7 +166,7 @@
{
"id": "refund-policy",
"question": "退改政策是什么?",
"answer": "呼籁的退改政策清晰透明预售定金阶段,如果还没确定出行日期,定金随时可退;一旦确定了日期,出发前7天以上可无条件全退。所有费用和退改条款均写在正规电子合同里,受法律保护。如果因为不可抗力(如极端天气等)无法出行,呼籁会协商妥善处理,可以选择改期或退款。具体条款以合同为准,建议确认行程后联系定制师了解详细说明。",
"answer": "呼籁的退改政策写在电子合同里,清晰透明。定金在出行前可申请退还,具体退改比例以合同条款为准。如果因为不可抗力(如极端天气等)无法出行,呼籁会协商妥善处理,可以选择改期或退款。所有费用和退改条款均在合同中明确约定,受法律保护。建议确认行程后联系定制师了解详细退改条款。",
"relatedLinks": [
{
"url": "/contact",
@ -207,28 +185,6 @@
}
]
},
{
"id": "why-no-meals",
"question": "行程为什么不含中餐和晚餐?",
"answer": "呼籁做的是精品小团,一家一单一车,每团只有您这一家。人数少,无法像大巴团那样安排统一团餐(团餐本质上是大团拿回扣的地方)。不含中晚餐,反而让您多了自主权:喜欢哪家餐厅就去哪家,想在草原上野餐也可以,领队可以随时给推荐。早餐一般含在住宿费用里。这是精品小团和大拼团在餐饮安排上的本质区别——我们不靠餐厅返点赚钱,不强制去指定餐厅消费。",
"relatedLinks": [
{
"url": "/pricing",
"text": "查看费用包含明细"
}
]
},
{
"id": "deposit-group-service",
"question": "定金即入群是什么?报名流程是怎样的?",
"answer": "「定金即入群」是呼籁的服务承诺交了定金就加入大群200+人,大家一起见证呼籁的服务。整个报名流程是第一步,交定金入大群;第二步,确定出行日期后,呼籁为您单独建立专属服务小群,群里有定制师、客服、房务管家、车务管家;第三步,出发前提前确认酒店房型、签订正规电子合同、购买旅游意外险;第四步,出发前3天专人再次确认全部行程细节。全程透明,每一步都可追溯。大群里有历届会员在,你能看到其他家庭的真实出行记录,不是孤立地面对一家旅行社。",
"relatedLinks": [
{
"url": "/contact",
"text": "立即联系定制师"
}
]
},
{
"id": "how-to-contact",
"question": "如何联系呼籁旅行?",
@ -260,7 +216,7 @@
{
"id": "horse-riding",
"question": "能骑马吗?孩子能骑吗?",
"answer": "可以骑马,这是呼伦贝尔最受家庭欢迎的体验之一。骑马穿越往返约1小时,马匹都是经过训练的温顺马,全程有专业马师随行陪同。如果不太敢骑或不熟练,马师会牵着马走,不额外收费;年龄较小的孩子由马师抱着骑。请穿长裤和运动鞋,呼籁会提前准备骑马手套。骑马时双手握住缰绳、身体放松,不要站在马的后面。0-3岁幼童不建议参与骑马穿越体验,但可以体验喂小羊、营地儿童游乐架、轮胎秋千等温和活动。除骑马外,行程中还可体验草原滑草身高1.2米以上可独立乘坐、ATV越野2人一车等多种户外活动。",
"answer": "可以骑马,这是呼伦贝尔最受家庭欢迎的体验之一。骑马穿越往返约1小时,马匹都是经过训练的温顺马,全程有专业马师随行陪同。如果不太敢骑或不熟练,马师会牵着马走,不额外收费;年龄较小的孩子由马师抱着骑。请穿长裤和运动鞋,呼籁会提前准备骑马手套。骑马时双手握住缰绳、身体放松,不要站在马的后面。0-3岁幼童不建议参与沉浸式骑马穿越,但可以体验喂小羊、营地儿童游乐架、轮胎秋千等温和活动。除骑马外,行程中还可体验草原滑草身高1.2米以上可独立乘坐、ATV越野2人一车等多种户外活动。",
"relatedLinks": [
{
"url": "/guides#activities",
@ -271,11 +227,11 @@
{
"id": "charter-vs-group",
"question": "包车自由行和拼团哪个好?",
"answer": "这取决于您的需求和预算。拼团价格更低,但行程固定、同行人员不可控、自由度很低。呼籁做的是一家一单一车的亲子游,价格高于拼团,但一家一车,行程可调整,只和自己家人在一起,体验完全不同。特别是带孩子出行,亲子游的优势很明显——孩子需要休息可以随时停,想多玩一会儿也没人催。如果预算允许,带孩子出行建议选亲子游。",
"answer": "这取决于您的需求和预算。拼团价格更低,但行程固定、同行人员不可控、自由度很低。呼籁做的是一家一单一车的定制游,价格高于拼团,但一家一车,行程可调整,只和自己家人在一起,体验完全不同。特别是带孩子出行,定制游的优势很明显——孩子需要休息可以随时停,想多玩一会儿也没人催。如果预算允许,带孩子出行建议选定制游。",
"relatedLinks": [
{
"url": "/products",
"text": "查看亲子游产品"
"text": "查看定制游产品"
}
]
},
@ -332,7 +288,7 @@
{
"id": "custom-itinerary",
"question": "行程能根据需求调整吗?",
"answer": "可以,这正是亲子游的意义——行程不是固定的模板。在呼籁的标准版本基础上,您可以和定制师沟通调整想多留半天在某个地方、想去某个特定的点、想安排特别的体验活动,都可以讨论。定制师会根据路线合理性和时间给出专业建议。大幅度调整可能影响报价,具体以沟通结果为准。呼籁已迭代至V9版本,标准行程本身经过多年优化,适合绝大多数家庭。",
"answer": "可以,这正是定制游的意义——行程不是固定的模板。在呼籁的标准版本基础上,您可以和定制师沟通调整想多留半天在某个地方、想去某个特定的点、想安排特别的体验活动,都可以讨论。定制师会根据路线合理性和时间给出专业建议。大幅度调整可能影响报价,具体以沟通结果为准。呼籁已迭代至V9版本,标准行程本身经过多年优化,适合绝大多数家庭。",
"relatedLinks": [
{
"url": "/contact",
@ -340,50 +296,6 @@
}
]
},
{
"id": "hulunbuir-vs-dali-xinjiang",
"question": "呼伦贝尔和大理、新疆比哪个值得去?",
"answer": "三个目的地各有侧重,不存在绝对的高下,主要看你的出行目的和家庭需求。大理适合休闲慢游、文艺感强,但草原体验几乎没有;新疆壮观震撼、景点分散,飞行时间长且行程强度大,带小孩子体力压力较大;呼伦贝尔是中国保存最完好的天然草原,海拔平均600-800米无高原反应、对孩子和老人特别友好、飞行时间仅2.5小时(北京出发)、夏季气候凉爽无酷暑,是三者中对亲子家庭最友好的目的地。如果你的核心需求是:草原体验、带孩子、身体无高反限制、行程不想太赶——呼伦贝尔是更合适的选择。如果你追求大西北的边境感或摄影极致风光,新疆更合适;如果你更喜欢文艺慢生活,大理更适合。",
"relatedLinks": [
{
"url": "/blog/hulunbuir-travel-guide-2026",
"text": "查看呼伦贝尔旅游攻略"
}
]
},
{
"id": "hulunbuir-food",
"question": "呼伦贝尔有什么特色美食?",
"answer": "呼伦贝尔的饮食文化以蒙古族和俄罗斯族两种风味为主,是国内少见的草原+边境美食组合。蒙古族必吃:手把肉(白水煮整块羊腿/羊排,蘸蒜汁或直接吃,鲜嫩无膻)、蒙古奶茶(用砖茶加鲜奶和盐煮成,咸香浓郁)、奶豆腐(新鲜牛奶制成的固体奶制品,微酸有嚼劲)、风干牛肉(高蛋白低脂,适合当零食)、黄油(牧民手工提炼,拌炒米吃)。俄罗斯族风味:列巴(恩和俄罗斯族村的手工大面包,外脆内软)、格瓦斯(发酵饮料,口感微酸清爽)。海拉尔市区还有蒙古烤肉、涮羊肉等选择。呼籁行程中会安排牧民家就餐和营地特色餐,让你吃到最正宗的草原味道。如有饮食过敏(特别是牛奶蛋白)请提前告知定制师。",
"relatedLinks": [
{
"url": "/guides",
"text": "查看出行指南"
}
]
},
{
"id": "accommodation-types",
"question": "草原上住什么?蒙古包住宿是什么体验?",
"answer": "呼伦贝尔的住宿分三大类型:一是城区星级酒店(海拉尔市区,设施完善,适合过渡住宿);二是草原营地蒙古包(最具特色,帐篷或蒙古包形态,部分有独立卫浴,真实草原住宿体验);三是边境特色民宿(室韦/恩和俄罗斯风情民宿,木屋风格)。蒙古包住宿是什么体验?推开圆形的木门,里面是低矮的床铺和简约的蒙古族装饰,夜晚能听到风声和草虫声,清晨打开门第一眼就是连绵草原——这是城市里完全感受不到的空间感。呼籁自有营地的蒙古包配备独立卫浴,不存在「公共厕所在帐篷外面」的情况,带孩子完全放心。草原住宿的条件与城市有差距,但这正是体验的一部分——大多数家庭反馈这是整个行程记忆最深的夜晚。",
"relatedLinks": [
{
"url": "/products",
"text": "查看行程中的住宿安排"
}
]
},
{
"id": "is-it-worth-going",
"question": "呼伦贝尔值得去吗?会审美疲劳吗?",
"answer": "值得去。对于大多数没去过草原的家庭,呼伦贝尔会超出预期——开阔的视野、干净的空气、和城市完全不同的生活节奏,是很多人第一次感受到「我终于放松了」的地方。孩子在草原上的变化更明显不盯手机、不吵闹、愿意早起看日出、主动去追牛羊,这种体验在其他目的地很难复制。会不会审美疲劳?可能性很小,因为草原不只是「一大片绿地」。呼伦贝尔有河曲莫日格勒河、湿地额尔古纳、森林大兴安岭白桦林、边境中俄边境公路、人文蒙古族牧民文化五种不同景观,每天的体验都不同。呼籁的11次迭代也是在不断解决「每天看草原不腻吗」这个问题——把不同景观、体验活动、文化场景拼合成节奏合理的行程。来过的家庭中,有超过30%会在第二年带着亲戚或朋友再来(呼籁称之为「回头客带新客」),这是最真实的回答。",
"relatedLinks": [
{
"url": "/reviews",
"text": "看10000+家庭的真实感受"
}
]
},
{
"id": "vs-other-charter",
"question": "和其他呼伦贝尔包车有什么区别?",

查看文件

@ -1,158 +1,242 @@
{
"seo": {
"title": "呼籁旅拍 | 草原旅拍作品集 | 呼伦贝尔蒙古袍亲子旅拍",
"description": "呼籁旅行自营旅拍服务,200+件蒙古族服饰,呼籁自营营地独家取景。亲子旅拍/儿童写真/全家福,随行拍摄当日交付。",
"keywords": "草原旅拍,呼伦贝尔旅拍,蒙古袍旅拍,亲子旅拍,呼籁营地旅拍"
},
"intro": {
"description": "呼籁旅拍是呼籁旅行的自营旅拍服务,在呼籁自营营地进行拍摄,摄影师随行,用真实光线记录每个家庭最自然的草原瞬间。所有旅拍均含底片,精修照片当日交付,无任何隐形消费。",
"stats": [
{ "value": "200+", "label": "件蒙古服饰", "note": "传统袍服·节日盛装·亲子套装" },
{ "value": "11年", "label": "深耕呼伦贝尔", "note": "最懂草原光线的摄影团队" },
{ "value": "5000+", "label": "组旅拍作品", "note": "每组都是独一无二的家庭故事" },
{ "value": "1处", "label": "自营营地取景", "note": "呼籁营地·独家秘境" }
]
},
"categories": [
{ "key": "all", "label": "全部作品" },
{ "key": "family", "label": "亲子家庭" },
{ "key": "solo", "label": "儿童写真" }
],
"works": [
{
"id": "photo-01",
"id": "gallery-001",
"title": "莫日格勒河畔·蒙古袍亲子写真",
"category": "family",
"location": "莫日格勒河",
"description": "清晨的莫日格勒河,河湾处光线最柔和。一家三口身着蒙古袍,是草原上最美的风景。",
"image": "/images/gallery/gallery-001.jpg"
},
{
"id": "gallery-013",
"title": "父子蒙古袍·营地合影",
"category": "family",
"location": "呼籁营地",
"description": "父子俩身着蓝色蒙古袍,在呼籁营地指示牌前开心合影。",
"image": "/旅拍照片/IMG_1244.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1244.JPG"
},
{
"id": "photo-02",
"id": "gallery-002",
"title": "额尔古纳湿地·情侣旅拍",
"category": "couple",
"location": "额尔古纳湿地",
"description": "湿地栈道尽头,两人相视而笑。蒙古族礼服在阳光下格外耀眼,湿地的翠绿是最好的背景。",
"image": "/images/gallery/gallery-002.jpg"
},
{
"id": "gallery-014",
"title": "父子草原奔跑",
"category": "family",
"location": "呼籁营地",
"description": "穿着蒙古袍的父子俩在草原上并肩奔跑,笑容灿烂。",
"image": "/旅拍照片/IMG_1245.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1245.JPG"
},
{
"id": "photo-03",
"id": "gallery-003",
"title": "白桦林间·闺蜜写真",
"category": "friends",
"location": "额尔古纳白桦林",
"description": "金秋的白桦林是最天然的摄影棚。三位闺蜜身着不同颜色的蒙古盛装,在金叶飘落中留下了这组写真。",
"image": "/images/gallery/gallery-003.jpg"
},
{
"id": "gallery-015",
"title": "骑在爸爸肩上",
"category": "family",
"location": "呼籁营地",
"description": "儿子骑在爸爸肩膀上,父子同穿蓝色蒙古袍,蓝天绿草间的温馨瞬间。",
"image": "/旅拍照片/IMG_1246.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1246.JPG"
},
{
"id": "photo-04",
"id": "gallery-004",
"title": "黑山头草原·三代同堂全家福",
"category": "group",
"location": "黑山头",
"description": "祖孙三代,一家十口,同穿蒙古袍站在草原最高处。他们说这张照片挂在客厅最显眼的地方。",
"image": "/images/gallery/gallery-004.jpg"
},
{
"id": "gallery-016",
"title": "一家三口草地游戏",
"category": "family",
"location": "呼籁营地",
"description": "爸爸、妈妈和女儿围坐在草地上玩拍手游戏,女儿笑得合不拢嘴。",
"image": "/旅拍照片/IMG_1247.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1247.JPG"
},
{
"id": "photo-05",
"id": "gallery-005",
"title": "草原深处·骑马个人写真",
"category": "portrait",
"location": "莫日格勒河源头",
"description": "骑马奔驰在无人草原,风吹起头饰上的流苏。这一刻,她成了草原上最自由的人。",
"image": "/images/gallery/gallery-005.jpg"
},
{
"id": "gallery-017",
"title": "爸爸扛起小公主",
"category": "family",
"location": "呼籁营地",
"description": "爸爸把穿着蓝色蒙古裙的女儿扛在肩上奔跑,蓝天下尽情欢笑。",
"image": "/旅拍照片/IMG_1248.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1248.JPG"
},
{
"id": "photo-06",
"id": "gallery-006",
"title": "呼伦湖畔·亲子骑马留影",
"category": "family",
"location": "呼伦湖",
"description": "湖边的夕阳把天空染成橙红,孩子骑在马背上,爸爸牵着缰绳。这张照片定格了一个家庭最美的时光。",
"image": "/images/gallery/gallery-006.jpg"
},
{
"id": "gallery-018",
"title": "父女温馨时刻",
"category": "family",
"location": "呼籁营地",
"description": "小女儿调皮地捏爸爸的鼻子,穿蒙古袍的爸爸笑着配合,温馨又可爱。",
"image": "/旅拍照片/IMG_1249.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1249.JPG"
},
{
"id": "photo-07",
"id": "gallery-007",
"title": "秋日白桦·情侣婚纱旅拍",
"category": "couple",
"location": "室韦白桦林",
"description": "他们把婚纱照拍到了室韦。金色白桦叶飘落,蒙古婚礼盛装在秋光中更显华美。这是他们说过最满意的照片。",
"image": "/images/gallery/gallery-007.jpg"
},
{
"id": "gallery-019",
"title": "父女草原追逐",
"category": "family",
"location": "呼籁营地",
"description": "穿着蓝色裙子的女儿和蒙古袍爸爸在草原上开心追逐奔跑。",
"image": "/旅拍照片/IMG_1250.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1250.JPG"
},
{
"id": "photo-08",
"id": "gallery-008",
"title": "冬日雪原·个人写真",
"category": "portrait",
"location": "海拉尔草原",
"description": "零下三十度的冬日草原,她穿着厚重的皮袍站在雪地里,背后是无垠的白色世界。沉静而有力量。",
"image": "/images/gallery/gallery-008.jpg"
},
{
"id": "gallery-020",
"title": "一家三口·小推车",
"category": "family",
"location": "呼籁营地",
"description": "爸爸拉着绿色小推车载着女儿飞奔,妈妈在后面张开双臂追赶,快乐溢出画面。",
"image": "/旅拍照片/IMG_1251.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1251.JPG"
},
{
"id": "photo-09",
"id": "gallery-009",
"title": "营地花海·闺蜜团写真",
"category": "friends",
"location": "呼籁自营营地",
"description": "营地的格桑花开了整个夏天。四个闺蜜相约来草原,在花海里留下了这组让她们争相转发的写真。",
"image": "/images/gallery/gallery-009.jpg"
},
{
"id": "gallery-021",
"title": "粉色蒙古盛装·旗帜前",
"category": "solo",
"location": "呼籁营地",
"description": "小女孩穿着精美的粉色蒙古盛装,在呼伦贝尔旗帜前巧笑嫣然。",
"image": "/旅拍照片/IMG_1252.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1252.JPG"
},
{
"id": "photo-10",
"id": "gallery-010",
"title": "莫日格勒·同学聚会全家福",
"category": "group",
"location": "莫日格勒河",
"description": "同学聚会选择了草原,十五个人浩浩荡荡,每个人都穿上了不同颜色的蒙古袍,笑得合不拢嘴。",
"image": "/images/gallery/gallery-010.jpg"
},
{
"id": "gallery-022",
"title": "草原上的旋转舞",
"category": "solo",
"location": "呼籁营地",
"description": "小女孩穿粉色蒙古盛装在草原上翩翩旋转,裙摆飞扬。",
"image": "/旅拍照片/IMG_1253.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1253.JPG"
},
{
"id": "photo-11",
"id": "gallery-011",
"title": "额尔古纳秋色·母女亲子写真",
"category": "family",
"location": "额尔古纳湿地",
"description": "妈妈和女儿穿着撞色亲子蒙古袍,在湿地木栈道上相互依偎。秋光洒下来,温柔又好看。",
"image": "/images/gallery/gallery-011.jpg"
},
{
"id": "gallery-023",
"title": "草原上的飞踢",
"category": "solo",
"location": "呼籁营地",
"description": "小女孩穿着粉色蒙古盛装在草原上踢腿跳跃,活力四射。",
"image": "/旅拍照片/IMG_1254.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1254.JPG"
},
{
"id": "photo-12",
"id": "gallery-012",
"title": "冬季那达慕·节日盛装写真",
"category": "portrait",
"location": "呼伦贝尔冬季那达慕",
"description": "冬季那达慕现场,他穿上节日盛装,背后是策马奔腾的骑手。整组照片充满了草原特有的力量感。",
"image": "/images/gallery/gallery-012.jpg"
},
{
"id": "gallery-024",
"title": "奔跑的背影",
"category": "solo",
"location": "呼籁营地",
"description": "粉色蒙古盛装的小女孩在草原上奔跑,辫子和裙摆随风飞扬的背影。",
"image": "/旅拍照片/IMG_1255.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1255.JPG"
},
{
"id": "photo-13",
"id": "gallery-025",
"title": "白裙俏皮少女",
"category": "solo",
"location": "呼籁营地",
"description": "小女孩穿着白色蒙古裙搭配棕色马靴,在草原上俏皮摆pose。",
"image": "/旅拍照片/IMG_1256.JPG",
"orientation": "portrait"
"image": "/旅拍照片/IMG_1256.JPG"
},
{
"id": "photo-14",
"id": "gallery-026",
"title": "草原笑脸·蒙古头饰",
"category": "solo",
"location": "呼籁营地",
"description": "戴着精美蒙古族头饰的小女孩对着镜头伸出双手,笑容灿烂无比。",
"image": "/旅拍照片/IMG_1258.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1258.JPG"
},
{
"id": "photo-15",
"id": "gallery-027",
"title": "母女牵手·草原漫步",
"category": "family",
"location": "呼籁营地",
"description": "妈妈和女儿穿着白色长裙手牵手漫步在草原上,温柔而美好。",
"image": "/旅拍照片/IMG_1259.JPG",
"orientation": "landscape"
"image": "/旅拍照片/IMG_1259.JPG"
}
]
}
],
"intro": {
"description": "呼籁旅行提供专业草原旅拍服务,200+件正宗蒙古袍,专业摄影师全程随行,营地即景即拍。",
"stats": [
{
"value": "200+",
"label": "套蒙古服饰"
},
{
"value": "11年",
"label": "深耕草原"
},
{
"value": "3000+",
"label": "旅拍家庭"
}
]
},
"seo": {
"title": "呼籁草原旅拍 - 蒙古袍旅拍|呼伦贝尔专业旅拍服务",
"description": "呼籁旅行提供呼伦贝尔草原专业旅拍服务,200+套正宗蒙古袍,专业摄影师随行,营地即景即拍。亲子旅拍/情侣旅拍/全家福,3000+家庭选择。",
"keywords": "草原旅拍,蒙古袍旅拍,呼伦贝尔旅拍,亲子旅拍,情侣旅拍,全家福,呼籁旅拍"
}
}

查看文件

@ -1,5 +1,5 @@
{
"pageIntro": "11年带队,我们见过最多的问题就是「出发前没准备好」。这份指南把穿搭、行李、证件、活动安全一次说清楚——你需要带什么,不需要带什么,哪些地方容易踩坑,全在这里。",
"pageIntro": "这份指南是呼籁团队根据多年带队经验整理的,从穿什么衣服、带什么东西、到各项活动的注意事项,帮您轻松准备呼伦贝尔之行。",
"sections": [
{
"id": "documents",
@ -499,7 +499,7 @@
"desc": "对低龄宝宝安全性或体验感不佳,建议家长自行体验,宝宝由另一位家长陪伴",
"items": [
{
"name": "骑马深度穿越",
"name": "沉浸式骑马穿越",
"reason": "路线含草原、森林、河流、坡地,幼儿无法独立骑乘"
},
{

查看文件

@ -1,33 +1,46 @@
{
"logo": {
"main": "/images/logo.png",
"square": "/images/logo-square.png"
"brandStory": {
"photo": "/images/team/hero-family.jpg"
},
"hero": {
"background": "/images/team/hero-grassland.jpg"
},
"brandStory": {
"photo": "/images/team/hero-family.jpg"
"logo": {
"main": "/images/logo.png",
"square": "/images/logo-square.png"
},
"mascot": {
"front": "/images/mascot/mascot-front.png",
"banner": "/images/mascot/mascot-banner.png",
"front": "/images/mascot/mascot-front.png",
"stickerQr": "/images/mascot-sticker-qr.png",
"xiaomengma": "/images/mascot/xiaomengma.png"
},
"seasons": {
"autumn-forest": "/images/seasons/autumn-forest.jpg",
"autumn-hero": "/images/seasons/autumn-hero.jpg",
"autumn-tianchi": "/images/seasons/autumn-tianchi.jpg",
"autumn-train": "/images/seasons/autumn-train.jpg",
"summer-car": "/images/seasons/summer-car.jpg",
"summer-hero": "/images/seasons/summer-hero.jpg",
"summer-river": "/images/seasons/summer-river.jpg",
"winter-frost": "/images/seasons/winter-frost.jpg",
"winter-hero": "/images/seasons/winter-hero.jpg",
"winter-tree": "/images/seasons/winter-tree.jpg",
"winter-yurt": "/images/seasons/winter-yurt.jpg"
},
"summerCamp": {
"birch": "/images/summer-camp/birch-group.jpg",
"graduation": "/images/summer-camp/camp-graduation.jpg",
"grassland": "/images/summer-camp/grassland-group.jpg",
"river": "/images/summer-camp/river-banner.jpg"
},
"team": {
"guideGroup": "/images/team/guide-group.jpg",
"routeSurvey": "/images/team/route-survey-2025.jpg",
"guideTraining": "/images/team/guide-training.jpg",
"ranchStore": "/images/team/ranch-store.jpg"
"ranchStore": "/images/team/ranch-store.jpg",
"routeSurvey": "/images/team/route-survey-2025.jpg"
},
"xiaohongshu": {
"storefront": "/images/xiaohongshu/storefront.jpg"
},
"summerCamp": {
"river": "/images/summer-camp/river-banner.jpg",
"grassland": "/images/summer-camp/grassland-group.jpg",
"birch": "/images/summer-camp/birch-group.jpg",
"graduation": "/images/summer-camp/camp-graduation.jpg"
}
}
}

查看文件

@ -9,71 +9,39 @@
"to": "/products",
"children": [
{
"text": "额吉的故乡",
"to": "/products",
"text": "额吉的故乡",
"season": "夏"
},
{
"text": "游牧的森林",
"to": "/products/autumn",
"text": "游牧的森林",
"season": "秋"
},
{
"text": "嗨冰雪",
"to": "/products/winter",
"text": "嗨冰雪",
"season": "冬"
},
{
"text": "小蒙马夏令营",
"to": "/summer-camp",
"text": "小蒙马夏令营",
"season": "夏"
},
{
"text": "小蒙马冬令营",
"to": "/winter-camp",
"text": "小蒙马冬季营",
"season": "冬"
}
]
},
{
"text": "目的地",
"to": "/destinations",
"children": [
{
"text": "景点攻略",
"to": "/destinations"
},
{
"text": "旅行日历",
"to": "/calendar"
},
{
"text": "出行指南",
"to": "/guides"
}
]
},
{
"text": "客户评价",
"to": "/reviews",
"children": [
{
"text": "客户评价",
"to": "/reviews"
},
{
"text": "小红书游记",
"to": "/xiaohongshu"
},
{
"text": "客户游记",
"to": "/youji"
},
{
"text": "呼籁旅拍",
"to": "/gallery"
}
]
"to": "/reviews"
},
{
"text": "出行指南",
"to": "/guides"
},
{
"text": "常见问答",
@ -81,21 +49,7 @@
},
{
"text": "关于我们",
"to": "/about",
"children": [
{
"text": "关于呼籁",
"to": "/about"
},
{
"text": "最新动态",
"to": "/news"
},
{
"text": "资质荣誉",
"to": "/qualifications"
}
]
"to": "/about"
},
{
"text": "联系我们",
@ -111,12 +65,12 @@
"to": "/about"
},
{
"text": "最新动态",
"to": "/news"
"text": "品牌故事",
"to": "/about#story"
},
{
"text": "资质荣誉",
"to": "/qualifications"
"text": "团队介绍",
"to": "/about#team"
}
]
},
@ -140,7 +94,7 @@
"to": "/summer-camp"
},
{
"text": "小蒙马冬营",
"text": "小蒙马冬营",
"to": "/winter-camp"
}
]
@ -160,10 +114,6 @@
"text": "客户评价",
"to": "/reviews"
},
{
"text": "景点攻略",
"to": "/destinations"
},
{
"text": "联系我们",
"to": "/contact"
@ -171,4 +121,4 @@
]
}
]
}
}

查看文件

@ -1,28 +1,12 @@
{
"articles": [
{
"id": "news-3",
"title": "额吉的故乡V9正式发布三大升级,一家一车",
"date": "2026-03-08",
"category": "产品",
"summary": "呼籁旅行2026夏季旗舰产品「额吉的故乡V9」正式发布。V9在V8基础上完成三大升级营地迁入敖包相会景区、白桦林新增非遗传承人课程、深度合作云牧场。6天5晚,一家一车,5月开始接待。",
"content": "2026年3月7-8日,呼籁旅行2026夏季旗舰产品「额吉的故乡V9」正式对外发布。V9是额吉的故乡系列的第9次迭代,从2023年V1上线至今,已服务超过10000组家庭、39000余人次。本次V9在V8基础上完成三大核心升级一、营地升级——呼籁自营营地迁入敖包相会景区,在景区内拥有独立空间,上午安排营地烧烤和旅拍,避开下午客流高峰;二、非遗研学升级——白桦林增设非遗传承人专属课程,按年龄分层设计体验内容;三、牧场升级——与云牧场达成深度合作,体验近距离牧场互动,同时在附近自营空间安排蒙古包体验、捡牛粪、酥油茶、手工毡等活动。产品为6天5晚行程,分舒适套餐和尊享套餐两个版本,全程一家一单一车、独立成团。预售期间下单享早鸟优惠,5月正式开始接待。"
},
{
"id": "news-4",
"title": "2026小蒙马亲子夏令营开放报名",
"date": "2026-02-20",
"category": "产品",
"summary": "2026年小蒙马亲子夏令营正式开放报名,6天5晚,每期最多8组家庭,涵盖草原、森林、湿地三大研学模块,全程路虎头等舱车队、专属摄影师跟拍。",
"content": "2026年小蒙马亲子夏令营正式开放报名。小蒙马是呼籁旅行专为家庭设计的深度营地产品,行程6天5晚,每期最多8组家庭同行。课程围绕草原、森林、湿地三大研学模块设计,包含恩和骑马、乌兰山滑草、ATV越野、面包DIY、兰旗果舍等体验。全程配备路虎头等舱车队,每组家庭配专属摄影师全程跟拍。2026年夏季计划开设9期,名额有限,报名请联系定制师获取详细方案和排期。"
},
{
"id": "news-5",
"title": "呼籁营地迁入敖包相会景区,2026赛季全面升级",
"date": "2026-02-10",
"category": "公告",
"summary": "呼籁自营营地正式迁入敖包相会景区,签约5年2026-2030,在景区内拥有独立空间和品牌IP,2026年5月正式开营。",
"content": "呼籁旅行自营营地已完成选址升级,正式迁入敖包相会景区。此次合作签约5年2026-2030,呼籁在景区内拥有独立运营空间,品牌IP归呼籁所有。新营地的核心优势是行程节奏的优化上午在营地完成旅拍和烧烤,下午再进入莫日格勒河景区,避开游客高峰时段。营地将于2026年5月正式开营,届时将配合额吉的故乡V9产品一同投入使用。"
"id": "news-7",
"title": "呼籁荣获小红书WILL商业大会「年度成长型品牌」",
"date": "2026-01-05",
"category": "活动",
"summary": "呼籁旅行在2026小红书WILL商业大会上荣获「年度成长型品牌」,全国文旅行业仅6家品牌获此荣誉。6家品牌中,呼籁是深耕单一目的地的本地品牌代表。",
"content": "在2026年小红书WILL商业大会上,呼籁旅行荣获「年度成长型品牌」称号。全国文旅行业仅6家品牌入选,6家品牌中,呼籁是深耕单一目的地的本地品牌代表。呼籁小红书账号「Mr.小雷-呼籁旅行」由联合创始人孙雷运营,目前拥有9.5万+粉丝。这份荣誉属于每一位愿意在小红书分享呼伦贝尔旅行故事的客户和伙伴。"
},
{
"id": "news-6",
@ -33,12 +17,28 @@
"content": "回顾2025年,呼籁旅行全年接待约18000人次。自2015年创立以来,呼籁累计服务家庭已突破10000组,共计39000余人次踏上呼伦贝尔草原。这一年,额吉的故乡从V8迭代到V9,小蒙马亲子夏令营正式上线,自有车队和自营营地投入运营——这些变化的背后,是每一个选择信任呼籁的家庭给了我们持续投入的底气。2026年,我们会继续深耕呼伦贝尔家庭定制游,把更多精力放在服务本身。"
},
{
"id": "news-7",
"title": "呼籁荣获小红书WILL商业大会「年度成长型品牌」",
"date": "2026-01-05",
"category": "活动",
"summary": "呼籁旅行在2026小红书WILL商业大会上荣获「年度成长型品牌」,全国文旅行业仅6家品牌获此荣誉。呼籁是其中唯一一个深耕单一目的地的本地品牌。",
"content": "在2026年小红书WILL商业大会上,呼籁旅行荣获「年度成长型品牌」称号。全国文旅行业仅6家品牌入选,呼籁是其中唯一一个深耕单一目的地的本地品牌。呼籁小红书账号「Mr.小雷-呼籁旅行」由联合创始人孙雷运营,目前拥有9.6万+粉丝。这份荣誉属于每一位愿意在小红书分享呼伦贝尔旅行故事的客户和伙伴。"
"id": "news-5",
"title": "呼籁营地迁入敖包召回景区,2026赛季全面升级",
"date": "2026-02-10",
"category": "公告",
"summary": "呼籁自营营地正式迁入敖包召回景区,签约5年2026-2030,在景区内拥有独立空间和品牌IP,2026年5月正式开营。",
"content": "呼籁旅行自营营地已完成选址升级,正式迁入敖包召回景区。此次合作签约5年2026-2030,呼籁在景区内拥有独立运营空间,品牌IP归呼籁所有。新营地的核心优势是行程节奏的优化上午在营地完成旅拍和烧烤,下午再进入莫日格勒河景区,避开游客高峰时段。营地将于2026年5月正式开营,届时将配合额吉的故乡V9产品一同投入使用。"
},
{
"id": "news-4",
"title": "2026小蒙马亲子夏令营开放报名",
"date": "2026-02-20",
"category": "产品",
"summary": "2026年小蒙马亲子夏令营正式开放报名,7天6晚,每期最多8组家庭,涵盖草原、森林、湿地三大研学模块,全程路虎头等舱车队、专属摄影师跟拍。",
"content": "2026年小蒙马亲子夏令营正式开放报名。小蒙马是呼籁旅行专为家庭设计的深度营地产品,行程7天6晚,每期最多8组家庭同行。课程围绕草原、森林、湿地三大研学模块设计,包含恩和骑马、乌兰山滑草、ATV越野、面包DIY、兰旗果舍等体验。全程配备路虎头等舱车队,每组家庭配专属摄影师全程跟拍。2026年夏季计划开设9期,名额有限,报名请联系定制师获取详细方案和排期。"
},
{
"id": "news-3",
"title": "额吉的故乡V9正式发布三大升级,一家一车",
"date": "2026-03-08",
"category": "产品",
"summary": "呼籁旅行2026夏季旗舰产品「额吉的故乡V9」正式发布。V9在V8基础上完成三大升级营地迁入敖包召回景区、白桦林新增非遗传承人课程、深度合作云牧场。6天5晚,一家一车,5月开始接待。",
"content": "2026年3月7-8日,呼籁旅行2026夏季旗舰产品「额吉的故乡V9」正式对外发布。V9是额吉的故乡系列的第9次迭代,从2023年V1上线至今,已服务超过10000组家庭、39000余人次。本次V9在V8基础上完成三大核心升级一、营地升级——呼籁自营营地迁入敖包召回景区,在景区内拥有独立空间,上午安排营地烧烤和旅拍,避开下午客流高峰;二、非遗研学升级——白桦林增设非遗传承人专属课程,按年龄分层设计体验内容;三、牧场升级——与云牧场达成深度合作,体验近距离牧场互动,同时在附近自营空间安排蒙古包体验、捡牛粪、酥油茶、手工毡等活动。产品为6天5晚行程,分舒适套餐和尊享套餐两个版本,全程一家一单一车、独立成团。预售期间下单享早鸟优惠,5月正式开始接待。"
}
]
}

查看文件

@ -1,143 +1,56 @@
{
"note": "⚠️ 本页面大量内容需补充真实数据,占位符已标注",
"govPartners": [
{
"name": "⚠️请确认:呼伦贝尔市文化旅游局",
"type": "文旅主管部门",
"description": "⚠️需确认具体合作内容及合作形式",
"verified": false
},
{
"name": "⚠️请确认:额尔古纳市文化旅游局",
"type": "文旅主管部门",
"description": "⚠️需确认具体合作内容及合作形式",
"verified": false
},
{
"name": "⚠️请确认:鄂温克族自治旗旅游局",
"type": "文旅主管部门",
"description": "⚠️需确认具体合作内容及合作形式",
"verified": false
"name": "测试合作伙伴",
"description": "合作描述",
"website": null,
"verified": true
}
],
"associations": [
{
"name": "内蒙古自治区文化和旅游厅",
"type": "政府主管部门",
"relationship": "颁发旅游经营许可证·认定研学旅游服务商",
"description": "政府主管部门|颁发旅游经营许可证·认定研学旅游服务商",
"website": null,
"verified": true
},
{
"name": "⚠️请确认:内蒙古旅游协会",
"type": "行业协会",
"memberType": "⚠️需确认是否为会员单位及会员级别",
"verified": false
},
{
"name": "⚠️请确认:呼伦贝尔旅游协会",
"type": "行业协会",
"memberType": "⚠️需确认是否为会员单位",
"verified": false
}
],
"academicCoops": [
{
"name": "呼伦贝尔学院",
"type": "高校合作",
"relationship": "旅游实习实训基地",
"description": "校企合作,共同培养旅游管理专业人才,实践教学基地",
"verified": true,
"since": "2024"
"description": "高校合作旅游实习实训基地校企合作,共同培养旅游管理专业人才,实践教学基地合作始于2024",
"website": null,
"verified": true
}
],
"scenicPartners": [
{
"name": "莫日格勒河景区",
"description": "呼籁行程核心目的地,提供专属通道和深度体验项目",
"website": null,
"verified": true
},
{
"name": "额尔古纳湿地公园",
"description": "国家级自然保护区,呼籁行程必经目的地",
"website": null,
"verified": true
},
{
"name": "黑山头景区",
"description": "呼籁自有骑马营地所在地,独家草原骑马体验",
"website": null,
"verified": true
},
{
"name": "⚠️请补充其他合作景区",
"description": "⚠️请补充具体合作景区名称及合作内容",
"verified": false
}
],
"hotelPartners": [
{
"name": "⚠️请补充:海拉尔区合作酒店",
"star": "⚠️星级待填",
"description": "⚠️请补充呼籁行程中使用的酒店名称及合作内容",
"verified": false
},
{
"name": "⚠️请补充:额尔古纳合作酒店",
"star": "⚠️星级待填",
"description": "⚠️请补充具体合作酒店",
"verified": false
},
{
"name": "⚠️请补充:室韦/恩和民宿",
"star": "精品民宿",
"description": "⚠️请补充具体合作民宿",
"verified": false
}
],
"hotelPartners": [],
"platformEndorsements": [
{
"platform": "小红书",
"status": "蓝V认证·旅行社",
"detail": "2025年度成长型品牌·2026 WILL商业大会受邀品牌",
"account": "Mr.小雷-呼籁旅行",
"followers": "9.6万+",
"name": "小红书",
"description": "2025年度成长型品牌·2026 WILL商业大会受邀品牌蓝V认证·旅行社粉丝9.5万+账号Mr.小雷-呼籁旅行",
"website": null,
"verified": true
},
{
"platform": "⚠️抖音",
"status": "⚠️需确认认证状态",
"detail": "⚠️请补充抖音账号信息",
"verified": false
},
{
"platform": "⚠️微信视频号",
"status": "⚠️需确认",
"detail": "⚠️请补充视频号信息",
"verified": false
}
],
"mediaReports": [
{
"outlet": "⚠媒体名称1内蒙古日报/呼伦贝尔日报/新华社等)",
"title": "⚠️请填写具体报道标题",
"date": "⚠报道日期格式2025-XX-XX",
"url": "⚠需补充真实报道URL",
"summary": "⚠请填写报道摘要1-2句话描述报道核心内容",
"placeholder": true
},
{
"outlet": "⚠媒体名称2",
"title": "⚠️请填写具体报道标题",
"date": "⚠️报道日期",
"url": "⚠需补充真实报道URL",
"summary": "⚠️请填写报道摘要",
"placeholder": true
},
{
"outlet": "⚠媒体名称3",
"title": "⚠️请填写具体报道标题",
"date": "⚠️报道日期",
"url": "⚠需补充真实报道URL",
"summary": "⚠️请填写报道摘要",
"placeholder": true
}
]
}
"mediaReports": []
}

查看文件

@ -1,5 +1,17 @@
{
"products": [
{
"id": "v9-4d3n",
"name": "额吉的故乡V9·4天3晚 精华版",
"priceLabel": "详询定制师",
"priceNote": "价格因人数、住宿选择和出行季节有所不同,请联系定制师获取专属报价",
"highlights": [
"莫日格勒河草原深度穿越",
"黑山头骑马",
"走访蒙古族牧户家庭"
],
"url": "/products/v9-4d3n"
},
{
"id": "v9-5d4n-forest",
"name": "额吉的故乡V9·5天4晚 森林版",
@ -10,7 +22,7 @@
"森林小火车+兴安神鹿园",
"恩和骑马+全地形越野车"
],
"url": "/products/v9-5d4n-forest"
"url": "/products/v9-5d4n"
},
{
"id": "v9-5d4n-prairie",
@ -22,17 +34,29 @@
"寻龙诀秘境+套娃大马戏",
"巴尔虎马之舞实景演出"
],
"url": "/products/v9-5d4n-prairie"
"url": "/products/v9-5d4n"
},
{
"id": "v9-5d4n",
"name": "额吉的故乡V9·5天4晚 经典版",
"priceLabel": "详询定制师",
"priceNote": "最受欢迎的版本,报价需结合家庭人数和住宿等级,请联系定制师",
"highlights": [
"额尔古纳湿地全景",
"白桦林漫步",
"中俄边境公路"
],
"url": "/products/v9-5d4n"
},
{
"id": "v9-6d5n-family",
"name": "额吉的故乡V9·6天5晚 亲子版",
"priceLabel": "2980元起",
"priceNote": "舒适套餐2980-5480元/人,高档套餐3980-6980元/人,主推亲子路线",
"priceLabel": "详询定制师",
"priceNote": "包含旅拍服务,具体报价根据孩子年龄和活动需求定制,请联系定制师",
"highlights": [
"自有营地旅拍+非遗研学+骑马",
"套娃大马戏+马之舞实景演出",
"专为带孩子的家庭设计"
"草原营地亲子活动",
"蒙古族手工体验",
"旅拍服务200+服饰"
],
"url": "/products/v9-6d5n-family"
},
@ -46,7 +70,7 @@
"恩和+黑山头两次骑马",
"寻龙诀秘境+满洲里国门"
],
"url": "/products/v9-6d5n-explore"
"url": "/products/v9-6d5n-comfort"
},
{
"id": "v9-7d6n-family",
@ -60,6 +84,18 @@
],
"url": "/products/v9-7d6n-family"
},
{
"id": "v9-6d5n-comfort",
"name": "额吉的故乡V9·6天5晚 探索版",
"priceLabel": "详询定制师",
"priceNote": "全程精选品质酒店,住宿标准提升,请联系定制师获取报价",
"highlights": [
"全程精选品质酒店",
"休闲节奏设计",
"深度体验不赶路"
],
"url": "/products/v9-6d5n-comfort"
},
{
"id": "v9-7d6n-wild",
"name": "额吉的故乡V9·7天6晚 旷野版",
@ -96,5 +132,33 @@
],
"url": "/products/autumn"
}
]
}
],
"intro": "呼籁旅行定制游按家庭整体报价,非人头计费。报价包含全程住宿、餐饮、景区交通、领队服务,不含大交通(飞机/火车和个人消费。签正规电子合同,购买1000万旅游责任险,报价后2小时内回复。",
"included": [
"全程住宿3-4星精选酒店/特色民宿/营地帐篷)",
"全程餐饮特色草原餐、营地BBQ",
"全程专属车辆(商务车/越野车)",
"专职领队全程陪同服务",
"核心景点门票(含呼籁自营营地体验)",
"旅游意外险 + 1000万旅游责任险",
"行程期间24小时紧急服务"
],
"excluded": [
"往返大交通(飞机/高铁/火车票)",
"个人消费(纪念品、自选活动等)",
"部分自费景点(如需要单独购票的景区)",
"护照、签注等证件费用"
],
"philosophy": {
"title": "价格透明,不绕弯子",
"honestNote": "我们不做低价吸引再加收各种费用的事。报价就是总价。",
"content": "报价后会详细说明包含和不包含的项目,没有任何隐形消费。定制游按家庭整体报价,一个家庭无论几口人都是统一价,不按人头收费。不同住宿等级价格有差异,我们会提供几档方案供选择。",
"promise": "对报价有任何疑问,欢迎直接问。我们的定制师会在2小时内详细回复。"
},
"cta": {
"title": "获取专属报价",
"description": "告诉我们家庭人数、出行时间、大概预算,定制师2小时内给出详细方案",
"to": "/contact",
"button": "联系定制师获取报价"
}
}

查看文件

@ -1,382 +1,89 @@
{
"narrative": "「额吉的故乡」是蒙古语中对母亲故土的深情称呼。这条定制游产品线从2023年诞生至今,已经迭代到了第9个版本,连续三年累计服务超过10000组家庭。我们根据不同家庭的假期长度、出行偏好和体验诉求,打磨出5个版本——不是简单地增减天数,而是针对每一类家庭的需求重新设计节奏、线路和体验内容。每一个版本都遵循同一个承诺:不拼团,不赶路,不将就。一家一单一车,全程私家定制游,您的假期只属于您的家庭。",
"narrative": "「额吉的故乡」是蒙古语中对母亲故土的深情称呼。这条定制游产品线从2023年诞生至今,已经迭代到了第9个版本。我们根据不同家庭的假期长度、孩子年龄和旅行偏好,打磨出6个版本——不是简单地增减天数,而是针对每一类家庭的需求重新设计节奏、线路和体验内容。每一个版本都遵循同一个承诺:一家一单一车,全程私家定制游,您的假期只属于您的家庭。",
"versions": [
{
"id": "v9-5d4n-forest",
"name": "额吉的故乡V9·5天4晚森林版",
"days": 5,
"nights": 4,
"audience": "想一次走遍草原和森林的家庭",
"description": "草原+森林双线深度体验,5天4晚串联莫日格勒河草原腹地与大兴安岭森林。从牧云山顶俯瞰天下第一曲水,到白桦林中驾驶全地形越野车穿越,再到大兴安岭深处坐森林小火车、喂驯鹿,一路从草原走进森林。沿中俄边防卡线体验乌兰山千米滑草、篝火晚会,最后在云朵牧场感受蒙古族文化。4天平均约237公里/天,单日最长不超过280公里。",
"id": "v9-4d3n",
"name": "额吉的故乡V9·4天3晚",
"days": 4,
"nights": 3,
"audience": "假期有限的家庭、初次体验草原",
"description": "呼伦贝尔定制游精华浓缩版,用4天时间串联最核心的风光与体验。一家一单一车,从海拉尔出发,穿越莫日格勒河草原腹地,抵达中俄边境小镇室韦,途经黑山头骑马,最终在满洲里收官。行程紧凑但不赶路,每一天都有记忆点。",
"highlights": [
"牧云山顶茶歇,俯瞰莫日格勒河九曲蜿蜒",
"恩和沉浸式骑马穿越草原、湿地、森林、河流",
"全地形越野车穿越,往返12公里自由驰骋",
"莫尔道嘎森林小火车穿行原始森林",
"兴安神鹿园零距离喂驯鹿",
"乌兰山千米滑草畅玩不限次"
"莫日格勒河草原深度穿越,走进\"天下第一曲水\"的怀抱",
"黑山头专业马场骑马体验,在草原上策马奔腾",
"走访蒙古族牧户家庭,亲手挤牛奶、品尝手工奶制品"
],
"tag": "森林版",
"itinerary": [
{
"day": 1,
"title": "全国→海拉尔",
"summary": "蒙古礼仪接机礼遇,入住酒店,自由活动"
},
{
"day": 2,
"title": "草原·白桦林·穿越",
"summary": "牧云山顶茶歇→俯瞰莫日格勒河→白桦林景区→全地形越野车穿越→恩和270公里"
},
{
"day": 3,
"title": "骑马·森林小火车·大兴安岭",
"summary": "恩和沉浸式骑马→兴安神鹿园→森林小火车→莫尔道嘎240公里"
},
{
"day": 4,
"title": "边境卡线·滑草·篝火",
"summary": "莫尔道嘎→室韦界河→九卡→七卡→千米滑草→篝火晚会→黑山头蒙古包280公里"
},
{
"day": 5,
"title": "云朵牧场·民俗体验·送机",
"summary": "黑山头→云朵牧场→民俗体验→海拉尔送机160公里"
}
],
"included": {
"accommodation": "4晚住宿舒适/高档可选)",
"transport": "一家一单一车,独立用车",
"tickets": "白桦林(含门票+观光车)、乌兰山景区(含门票+观光车)、牧云山顶茶歇、兴安神鹿园(含门票+苔藓)",
"activities": "全地形越野车往返12公里、恩和沉浸式骑马约1小时、莫尔道嘎森林小火车、乌兰山千米滑草畅玩、云朵牧场萌宠互动、呼籁牧场自营非遗体验、篝火晚会、生日礼遇"
},
"pricing": {
"tiers": ["舒适套餐", "高档套餐"],
"note": "舒适和高档只有酒店不同,其他都相同",
"startPrice": 2580,
"peakPrice": 4780,
"highStartPrice": 3380,
"highPeakPrice": 5880
}
"tag": "精华版"
},
{
"id": "v9-5d4n-prairie",
"name": "额吉的故乡V9·5天4晚草原版",
"id": "v9-5d4n",
"name": "额吉的故乡V9·5天4晚",
"days": 5,
"nights": 4,
"audience": "想深度体验草原又不想进森林的家庭",
"description": "不赶路的五天,独家资源·错峰安排。从牧云山顶到白桦林,从恩和骑马到中俄边防卡线,一路畅玩千米滑草、云朵牧场、非遗研学、篝火晚会。第四天解锁呼籁签约的秘境——寻龙诀取景地,下午游览套娃景区和大马戏,夜游满洲里。最后一天看巴尔虎马之舞实景演出,在呼和诺尔湖畔收官。4天平均约225公里/天,单日最长不超过270公里。",
"audience": "希望深度体验又兼顾时间的家庭",
"description": "最受欢迎的经典版本,5天4晚覆盖呼伦贝尔精华景观和核心体验。在精华版基础上,增加了额尔古纳湿地、白桦林和中俄边境公路等标志性内容,体验层次更丰富,行程节奏刚刚好——既不浪费假期,也不走马观花。",
"highlights": [
"牧云山顶茶歇,俯瞰莫日格勒河九曲蜿蜒",
"恩和沉浸式骑马穿越草原、湿地、森林、河流",
"全地形越野车穿越,往返12公里自由驰骋",
"呼籁专属秘境·寻龙诀取景地",
"套娃景区+俄罗斯大马戏",
"巴尔虎马之舞大型实景演出"
"登临额尔古纳湿地——\"亚洲第一湿地\"的壮阔全景尽收眼底",
"漫步白桦林,感受大兴安岭林区的静谧与诗意",
"驰骋中俄边境公路,一侧草原一侧界河,风景绝美"
],
"tag": "草原版",
"itinerary": [
{
"day": 1,
"title": "全国→海拉尔",
"summary": "蒙古礼仪接机礼遇,入住酒店,自由活动"
},
{
"day": 2,
"title": "草原·白桦林·穿越",
"summary": "牧云山顶茶歇→俯瞰莫日格勒河→白桦林景区→喂驯鹿→全地形越野车穿越→恩和木刻楞270公里"
},
{
"day": 3,
"title": "骑马·滑草·篝火",
"summary": "沉浸式骑马→中俄边防卡线→千米滑草→云朵牧场→非遗研学→篝火晚会→黑山头蒙古包140公里"
},
{
"day": 4,
"title": "秘境·套娃·满洲里",
"summary": "黑山头→呼籁秘境(寻龙诀取景地)→套娃景区/大马戏→夜游满洲里260公里"
},
{
"day": 5,
"title": "马之舞·呼和诺尔湖·送机",
"summary": "满洲里→巴尔虎马之舞实景演出→呼和诺尔湖→海拉尔送机230公里"
}
],
"included": {
"accommodation": "4晚住宿舒适/高档可选)",
"transport": "一家一单一车,独立用车",
"tickets": "牧云山顶茶歇、白桦林(含门票+观光车)、乌兰山(含门票+观光车)、套娃广场(含娱乐门票)、呼籁秘境(寻龙诀拍摄地)、巴尔虎蒙古部落(含马之舞)、呼和诺尔湖(含门票+观光车)",
"activities": "全地形越野车往返12公里、恩和沉浸式骑马约1小时、千米滑草畅玩、套娃广场套票含大马戏、巴尔虎马之舞、云朵牧场萌宠互动、篝火晚会"
},
"pricing": {
"tiers": ["舒适套餐", "高档套餐"],
"note": "舒适和高档只有酒店不同,其他都相同",
"startPrice": 2580,
"peakPrice": 4780,
"highStartPrice": 3380,
"highPeakPrice": 5880
}
"tag": "经典版"
},
{
"id": "v9-6d5n-family",
"name": "额吉的故乡V9·6天5晚亲子版",
"days": 6,
"nights": 5,
"audience": "专为带孩子来草原的家庭设计,主推路线",
"description": "不赶路的六天,独家资源·错峰安排。在呼籁自有营地享受专属旅拍和BBQ,错峰登牧云山顶俯瞰莫日格勒河。白桦林中由非遗传承人亲自授课桦树皮画,按年龄分层体验,零距离喂驯鹿。恩和沉浸式骑马穿越草原、湿地、森林、河流。沿中俄边防卡线畅玩千米滑草,在云朵牧场体验蒙古族文化——搭蒙古包、捡牛粪、熬奶茶、做羊毛毡。解锁寻龙诀秘境、套娃大马戏、马之舞实景演出。5天平均约200公里/天,单日最长不超过300公里。",
"audience": "带3-10岁孩子的家庭",
"description": "呼伦贝尔亲子定制游的代表版本,行程节奏配合孩子的体能和注意力,每天安排适龄的互动体验。一家一单一车,营地活动、亲子手工、草原游戏穿插其中,让孩子不只是「跟着走」,而是真正参与到旅行中来。同时配备旅拍服务,为全家留下草原上最自然的影像记录。",
"highlights": [
"呼籁自有营地——专属旅拍+茶点+BBQ",
"白桦林非遗传承人现场授课,按年龄分层体验",
"恩和沉浸式骑马穿越草原、湿地、森林、河流",
"云朵牧场蒙古族文化体验——搭蒙古包、熬奶茶、做羊毛毡",
"全地形越野车穿越+乌兰山千米滑草畅玩",
"呼籁专属秘境·寻龙诀取景地+套娃大马戏+马之舞"
"草原营地活动——放风筝、踢足球、搭帐篷,孩子撒欢的天堂",
"亲子互动体验——蒙古族手工制作、奶制品DIY、草原寻宝",
"呼籁营地定点旅拍,200+服饰可选,定格全家最自然的欢笑"
],
"tag": "亲子版·主推",
"isMainProduct": true,
"itinerary": [
{
"day": 1,
"title": "全国→海拉尔",
"summary": "蒙古礼仪接机礼遇,入住酒店,自由活动"
},
{
"day": 2,
"title": "专属营地·牧云山顶",
"summary": "呼籁营地(旅拍+茶点+BBQ→天下第一敖包→牧云山顶下午茶→俯瞰莫日格勒河→额尔古纳290公里"
},
{
"day": 3,
"title": "白桦林非遗·喂驯鹿·骑马",
"summary": "额尔古纳→白桦林景区→非遗手作→喂驯鹿→沉浸式骑马穿越→恩和木刻楞100公里"
},
{
"day": 4,
"title": "越野车·边防卡线·滑草·蒙古文化·篝火",
"summary": "恩和→全地形越野车穿越→中俄边防哨卡线→千米滑草→云朵牧场→非遗研学→篝火晚会→黑山头蒙古包130公里"
},
{
"day": 5,
"title": "秘境·套娃·满洲里",
"summary": "黑山头→呼籁秘境(寻龙诀取景地)→套娃景区/大马戏→夜游满洲里240公里"
},
{
"day": 6,
"title": "马之舞·呼和诺尔湖·送机",
"summary": "满洲里→巴尔虎马之舞实景演出→呼和诺尔湖→海拉尔送机220公里"
}
],
"included": {
"accommodation": "5晚住宿舒适/高档可选)",
"transport": "一家一单一车,独立用车",
"tickets": "呼籁营地(自营不对外)、白桦林(含门票+观光车)、乌兰山景区(含门票+观光车)、套娃广场(含娱乐门票)、呼籁秘境(寻龙诀拍摄地)、牧云山顶下午茶歇、巴尔虎蒙古部落(含马之舞)、呼和诺尔湖(含门票+观光车)",
"activities": "呼籁旅拍(自营)、营地茶点+BBQ、白桦林非遗传承人手作课、全地形越野车往返12公里、恩和沉浸式骑马约1小时、千米滑草畅玩、套娃广场套票含大马戏、巴尔虎马之舞、云朵牧场萌宠互动、呼籁牧场蒙古族文化体验搭蒙古包+捡牛粪+熬奶茶+做羊毛毡)、篝火晚会、生日礼遇"
},
"pricing": {
"tiers": ["舒适套餐", "高档套餐"],
"note": "舒适和高档只有酒店不同,其他都相同",
"startPrice": 2980,
"peakPrice": 5480,
"highStartPrice": 3980,
"highPeakPrice": 6980
}
"tag": "亲子版"
},
{
"id": "v9-6d5n-explore",
"id": "v9-6d5n-comfort",
"name": "额吉的故乡V9·6天5晚探索版",
"days": 6,
"nights": 5,
"audience": "更适合大孩子与成人的进阶体验",
"description": "越野穿越、两次骑马、不走寻常路。6天5晚的进阶版本,在呼籁自有营地享受专属旅拍和BBQ,错峰登上牧云山顶。独家大力山穿越路线全程不走柏油路,穿越草原、湿地、野生白桦林。安排恩和+黑山头两次骑马——白桦林间漫步与草原驰骋完全不同的体验。还有呼籁专属秘境、风车公路、满洲里国门、马之舞实景演出。5天平均约226公里/天。",
"audience": "注重住宿品质的家庭、带老人出行",
"description": "同样的定制游线路精华,更从容的旅行节奏。一家一单一车,全程精选当地品质酒店,每天行车时间控制在合理范围,留出充足的休息和自由活动时间。适合对住宿有要求的家庭、带老人同行的家庭,或者只是想让旅行更松弛一些的人。少赶一段路,多看一会儿风景。",
"highlights": [
"呼籁自有营地——专属旅拍+茶点+BBQ",
"牧云山顶下午茶歇,错峰俯瞰莫日格勒河",
"大力山独家穿越路线,全程不走柏油路",
"恩和+黑山头两次骑马,白桦林与草原两种体验",
"全地形越野车穿越,自由驰骋",
"呼籁专属秘境·寻龙诀取景地"
"全程精选品质酒店,告别标准化快捷酒店,每晚都住得舒心",
"休闲节奏设计,每天行车不超额,留足时间享受当下",
"深度体验优先——不追求打卡数量,每个地方都停够、看够、感受够"
],
"tag": "探索版",
"itinerary": [
{
"day": 1,
"title": "全国→海拉尔",
"summary": "蒙古礼仪接机礼遇,入住酒店,自由活动"
},
{
"day": 2,
"title": "专属营地·牧云山顶",
"summary": "呼籁自有营地(旅拍+茶点+BBQ→天下第一敖包→牧云山顶下午茶歇→俯瞰莫日格勒河→额尔古纳290公里"
},
{
"day": 3,
"title": "大力山穿越·越野车·骑马",
"summary": "额尔古纳→大力山穿越→全地形越野车→喂驯鹿→骑马穿越→入住恩和120公里"
},
{
"day": 4,
"title": "边防卡线·滑草·二刷骑马·篝火",
"summary": "室韦界河→九卡→七卡→千米滑草→云朵牧场→黑山头二刷骑马→篝火晚会→蒙古包230公里"
},
{
"day": 5,
"title": "秘境·风车公路·满洲里",
"summary": "黑山头→呼籁秘境(寻龙诀取景地)→风车公路→国门+北疆明珠塔→夜游满洲里260公里"
},
{
"day": 6,
"title": "马之舞·呼和诺尔湖·送机",
"summary": "满洲里→巴尔虎马之舞实景演出→呼和诺尔湖→海拉尔送机230公里"
}
],
"included": {
"accommodation": "5晚住宿舒适/高档可选)",
"transport": "一家一单一车,独立用车",
"tickets": "呼籁自有营地(不对外)、牧云山顶下午茶歇、乌兰山景区(含观光车)、套娃广场、呼籁秘境(独家专属)、满洲里国门+北疆明珠塔、呼和诺尔湖、巴尔虎马之舞",
"activities": "呼籁旅拍(自营)、营地茶点+BBQ、全地形越野车、大力山穿越、两次骑马恩和+黑山头)、千米滑草畅玩、云朵牧场(萌宠互动)、篝火晚会"
},
"pricing": {
"tiers": ["舒适套餐", "高档套餐"],
"note": "一家一车、自有营地旅拍、越野车、两次骑马全部包含",
"startPrice": 2980,
"peakPrice": 5480,
"highStartPrice": 3980,
"highPeakPrice": 6980
}
"tag": "探索版"
},
{
"id": "v9-7d6n-family",
"name": "额吉的故乡V9·7天6晚亲子版",
"days": 7,
"nights": 6,
"audience": "专为带孩子来草原的家庭设计",
"description": "从草原到大兴安岭,最完整的亲子深度版。7天6晚从容走遍呼伦贝尔精华,第一天在呼籁自有营地享受专属旅拍和BBQ,错峰登牧云山顶。白桦林中由非遗传承人亲自授课桦树皮画,按年龄分层体验。走进大兴安岭坐森林小火车、零距离喂驯鹿。沿边防卡线畅玩千米滑草,在云朵牧场体验蒙古族文化——搭蒙古包、捡牛粪、熬奶茶、做羊毛毡。解锁寻龙诀秘境、套娃大马戏、马之舞实景演出。7天平均约233公里/天。",
"audience": "假期充足、希望深度探索的亲子家庭",
"description": "最完整的亲子深度版本,7天时间从容走遍呼伦贝尔精华,每一天都有不同主题的体验。草原、森林、湿地、边境小镇——多元地貌轮番呈现,活动内容从骑马到手工到自然探索一应俱全,配合全程摄影跟拍,是送给孩子最好的暑假礼物。",
"highlights": [
"呼籁自有营地——专属旅拍+茶点+BBQ",
"白桦林非遗传承人现场授课,按年龄分层体验",
"大兴安岭森林小火车+兴安神鹿园喂驯鹿",
"云朵牧场蒙古族文化体验——搭蒙古包、熬奶茶、做羊毛毡",
"恩和沉浸式骑马+全地形越野车穿越",
"呼籁专属秘境·寻龙诀取景地+套娃大马戏"
"全程深度不赶路,7天覆盖草原、湿地、森林、边境四大主题",
"多元活动贯穿全程——骑马、射箭、手工、自然课堂,天天有新鲜",
"专业摄影师全程跟拍,旅行结束即获精修家庭影像大片"
],
"tag": "亲子版",
"itinerary": [
{
"day": 1,
"title": "全国→海拉尔",
"summary": "蒙古礼仪接机礼遇,入住酒店,自由活动"
},
{
"day": 2,
"title": "专属营地·牧云山顶",
"summary": "呼籁营地(旅拍+茶点+BBQ→天下第一敖包→牧云山顶下午茶→俯瞰莫日格勒河→额尔古纳290公里"
},
{
"day": 3,
"title": "白桦林非遗·越野车·骑马",
"summary": "额尔古纳→白桦林景区→非遗手作→全地形越野车→沉浸式骑马→入住恩和120公里"
},
{
"day": 4,
"title": "大兴安岭·驯鹿·森林小火车",
"summary": "恩和→兴安神鹿园→森林小火车→龙岩山→入住莫尔道嘎240公里"
},
{
"day": 5,
"title": "边防卡线·滑草·蒙古文化·篝火",
"summary": "莫尔道嘎→室韦界河→九卡→七卡→千米滑草→云朵牧场→非遗研学→篝火晚会→黑山头蒙古包280公里"
},
{
"day": 6,
"title": "秘境·套娃·满洲里",
"summary": "黑山头→呼籁秘境(寻龙诀取景地)→套娃景区/大马戏→夜游满洲里260公里"
},
{
"day": 7,
"title": "马之舞·呼和诺尔湖·送机",
"summary": "满洲里→巴尔虎马之舞实景演出→呼和诺尔湖→海拉尔送机230公里"
}
],
"included": {
"accommodation": "6晚住宿舒适/高档可选)",
"transport": "一家一单一车,独立用车",
"tickets": "呼籁营地(自营不对外)、牧云山顶下午茶歇、白桦林(含门票+观光车)、兴安神鹿园(含门票+苔藓)、乌兰山景区(含观光车)、套娃广场(含娱乐门票)、呼籁秘境(独家专属)、巴尔虎蒙古部落(含马之舞)、呼和诺尔湖(含门票+观光车)",
"activities": "呼籁旅拍(自营)、营地茶点+BBQ、白桦林非遗传承人手作课、全地形越野车往返12公里、恩和沉浸式骑马约1小时、莫尔道嘎森林小火车、千米滑草畅玩、云朵牧场萌宠互动、呼籁牧场蒙古族文化体验搭蒙古包+捡牛粪+熬奶茶+做羊毛毡)、篝火晚会、生日礼遇"
},
"pricing": {
"tiers": ["舒适套餐", "高档套餐"],
"note": "舒适型和高档型只有酒店不同,其他都相同",
"startPrice": 3680,
"peakPrice": 6280,
"highStartPrice": 4580,
"highPeakPrice": 7980
}
"tag": "深度亲子版"
},
{
"id": "v9-7d6n-wild",
"name": "额吉的故乡V9·7天6晚野版",
"name": "额吉的故乡V9·7天6晚狂野版",
"days": 7,
"nights": 6,
"audience": "追求深度体验、热爱户外探索的家庭",
"description": "旷野探索,解锁常规线路到不了的地方。7天6晚硬核户外版本,住特色帐篷营地和草原木屋,体验装甲车穿越、额尔古纳湿地漂流、大力山越野穿越。在呼籁自有营地旅拍BBQ,牧云山顶喝下午茶。沿最美边防卡线789卡穿越,天边草原骑马。深入寻龙诀秘境配专业航拍,二卡湿地游船。套娃大马戏、马之舞实景演出一个不少。7天合计约1540公里,平均约220公里/天。",
"audience": "追求深度体验、热爱户外的家庭",
"description": "为热爱户外探索的家庭量身定制的硬核版本。一家一单一车,解锁牧云山顶日落、ATV草原穿越、寻龙诀秘境等独家体验,深入常规线路到不了的地方。适合孩子年龄稍大、体能较好的家庭,也适合二刷呼伦贝尔想要全新体验的老朋友。",
"highlights": [
"呼籁自有营地——专属旅拍+茶点+BBQ",
"装甲车穿越草地和溪流,肾上腺素拉满",
"额尔古纳湿地漂流,白桦林和湿地草甸两岸风光",
"特色帐篷营地+草原木屋住宿体验",
"天边草原沉浸式骑马穿越",
"呼籁秘境·寻龙诀取景地+专业航拍"
"牧云山顶看日落——登上草原最高处,360度金色草海尽收眼底",
"ATV全地形车草原穿越,肾上腺素拉满的草原越野体验",
"寻龙诀秘境探秘,深入人迹罕至的草原腹地,发现隐藏风景"
],
"tag": "旷野版",
"itinerary": [
{
"day": 1,
"title": "全国→海拉尔",
"summary": "蒙古礼仪接机礼遇,入住酒店,自由活动"
},
{
"day": 2,
"title": "专属营地·牧云山顶",
"summary": "呼籁自有营地(旅拍+茶点+BBQ→天下第一敖包→牧云山顶下午茶歇→俯瞰莫日格勒河→莫日格勒河畔290公里"
},
{
"day": 3,
"title": "漂流·驯鹿·装甲车",
"summary": "大力山越野穿越→额尔古纳湿地漂流→喂驯鹿→装甲车穿越→俯瞰卡鲁奔→帐篷营地180公里"
},
{
"day": 4,
"title": "越野车·边境卡线·滑草·篝火",
"summary": "卡鲁奔→全地形越野车专属场地→室韦边境小镇→最美边防卡线789卡→乌兰山千米滑草→篝火晚会220公里"
},
{
"day": 5,
"title": "牧场·非遗·骑马穿越",
"summary": "乌兰山→云朵牧场→非遗研学→天边草原骑马穿越→草原260公里"
},
{
"day": 6,
"title": "秘境·游船·套娃·满洲里",
"summary": "黑山头→呼籁秘境(寻龙诀拍摄地)→二卡湿地游船→套娃景区/大马戏→夜游满洲里360公里"
},
{
"day": 7,
"title": "马之舞·呼和诺尔湖·送机",
"summary": "满洲里→马之舞实景演出→呼和诺尔湖→海拉尔送机230公里"
}
],
"included": {
"accommodation": "6晚住宿含特色帐篷营地和草原木屋",
"transport": "一家一单一车,独立用车",
"tickets": "呼籁自有营地(不对外)、乌兰山景区(含观光车)、套娃广场(活动套票)、呼籁秘境(独家专属)、满洲里国门+北疆明珠塔、呼和诺尔湖、牧云山顶下午茶歇、马之舞、二卡游船、卡鲁奔山",
"activities": "呼籁旅拍(自营)、营地茶点+BBQ、大力山越野穿越、额尔古纳湿地漂流、装甲车穿越、全地形越野车专属场地、天边草原骑马穿越、千米滑草畅玩、云朵牧场萌宠互动、呼籁牧场蒙古族文化体验、篝火晚会、专业航拍、生日礼遇"
},
"pricing": {
"tiers": ["高端套餐"],
"note": "全程特色住宿,含自有营地旅拍、装甲车、漂流、航拍",
"startPrice": 6480,
"peakPrice": 8680
}
"tag": "狂野版"
}
],
"summerCamp": {
@ -426,70 +133,70 @@
"selectionGuide": {
"byVacationLength": [
{
"reason": "草原+森林双线,走遍精华",
"condition": "5天假期偏自然",
"recommendation": "v9-5d4n-forest"
"reason": "精华浓缩,不浪费一天",
"condition": "3-4天假期",
"recommendation": "v9-4d3n"
},
{
"reason": "草原+边境+满洲里,不进森林",
"condition": "5天假期(偏人文)",
"recommendation": "v9-5d4n-prairie"
"reason": "经典线路,体验最全",
"condition": "5天假期",
"recommendation": "v9-5d4n"
},
{
"reason": "越野穿越、两次骑马,进阶体验",
"reason": "节奏从容,适合带娃",
"condition": "6天假期",
"recommendation": "v9-6d5n-explore"
"recommendation": "v9-6d5n-family"
},
{
"reason": "深度不赶路,草原森林全覆盖",
"reason": "深度探索,不留遗憾",
"condition": "7天以上",
"recommendation": "v9-7d6n-family"
}
],
"byChildAge": [
{
"reason": "亲子版节奏舒缓,非遗体验按年龄分层",
"condition": "3-6岁幼儿",
"recommendation": "v9-7d6n-family"
"reason": "亲子版节奏舒缓,活动适龄",
"condition": "3-5岁幼儿",
"recommendation": "v9-6d5n-family"
},
{
"reason": "亲子版活动丰富,森林小火车+驯鹿+非遗手作",
"reason": "深度版活动丰富,孩子最开心",
"condition": "6-10岁儿童",
"recommendation": "v9-7d6n-family"
},
{
"reason": "探索版两次骑马+越野穿越,适合大孩子",
"condition": "10岁以上",
"recommendation": "v9-6d5n-explore"
},
{
"reason": "小蒙马夏令营,8组家庭同行",
"condition": "亲子夏令营",
"recommendation": "summer-camp"
},
{
"reason": "狂野版户外体验更刺激",
"condition": "10岁以上",
"recommendation": "v9-7d6n-wild"
}
],
"byPreference": [
{
"reason": "装甲车穿越+漂流+帐篷营地,硬核户外",
"condition": "追求冒险",
"reason": "精选住宿,行程不赶",
"condition": "追求舒适",
"recommendation": "v9-6d5n-comfort"
},
{
"reason": "小众秘境,深入草原",
"condition": "追求深度",
"recommendation": "v9-7d6n-wild"
},
{
"reason": "自有营地+非遗手作+蒙古文化,亲子首选",
"condition": "亲子互动",
"recommendation": "v9-7d6n-family"
"reason": "探索版最适合全家出行",
"condition": "带老人同行",
"recommendation": "v9-6d5n-comfort"
},
{
"reason": "森林小火车+驯鹿+大兴安岭",
"condition": "想去森林",
"recommendation": "v9-5d4n-forest"
},
{
"reason": "两次骑马+大力山穿越+秘境探索",
"condition": "深度探索",
"recommendation": "v9-6d5n-explore"
"reason": "亲子版孩子们可以结伴玩耍",
"condition": "多家庭同行",
"recommendation": "v9-6d5n-family"
}
]
},
"pricingPhilosophy": "呼籁定制游的价格包含了车辆、住宿、领队服务、活动体验和保险,正餐自理。看起来比拼团贵,但每一分钱都花在了体验上——没有购物店、没有隐形消费、没有赶场式行程。一家一单一车的定制游模式意味着所有资源都是为您的家庭专属调配的:您的领队只服务您一家,您的车只拉您一家,您的行程可以根据实际情况灵活调整。定金500元/人,出发日前7天无条件退改。这不是高价版的跟团游,而是完全不同的旅行方式。"
}
"pricingPhilosophy": "呼籁定制游的价格包含了车辆、住宿、领队服务、活动体验、旅行摄影和保险。看起来比拼团贵,但每一分钱都花在了体验上——没有购物店、没有隐形消费、没有赶场式行程。一家一单一车的定制游模式意味着所有资源都是为您的家庭专属调配的您的领队只服务您一家,您的车只拉您一家,您的行程可以根据实际情况灵活调整。这不是高价版的跟团游,而是完全不同的旅行方式。这是呼籁对品质的坚持,也是我们9年来口碑积累的底气。"
}

查看文件

@ -1,175 +1,137 @@
{
"safetyGuarantees": [
{
"title": "三重旅行社资质",
"detail": "旗下三家主体均持有旅游经营许可证,正规合法经营"
},
{
"title": "1000万旅游责任险",
"detail": "全程保险覆盖,出行风险有兜底"
},
{
"title": "深耕呼伦贝尔11年",
"detail": "2015年呼籁品牌创立,只做呼伦贝尔一个目的地"
},
{
"title": "正规电子合同",
"detail": "所有行程签订正规电子合同,保障游客权益"
}
],
"licenses": [
{
"holder": "内蒙古呼籁国际旅行社有限公司",
"title": "旅游经营许可证",
"issuer": "内蒙古自治区文化和旅游厅",
"licenseNo": "L-NMG-100953",
"validPeriod": "有效期内",
"note": "集团核心业务主体,负责产品设计与客户服务"
"description": "证件号L-NMG-101453持证主体内蒙古呼籁文旅投资开发集团有限公司法人刘涛经营范围境内旅游业务、入境旅游业务统一信用代码91150702MACYA3MN0U集团母公司,统筹旗下所有业务板块"
},
{
"holder": "内蒙古呼籁文旅投资开发集团有限公司",
"title": "旅游经营许可证",
"issuer": "内蒙古自治区文化和旅游厅",
"licenseNo": "L-NMG-101453",
"validPeriod": "有效期内",
"note": "集团母公司,统筹旗下所有业务板块"
},
{
"holder": "内蒙古呼籁山河国际旅行社有限公司",
"issuer": "内蒙古自治区文化和旅游厅",
"licenseNo": "L-NMG00210",
"validPeriod": "有效期内",
"note": "集团旗下旅行社主体之一"
"description": "证件号L-NMG00210持证主体内蒙古呼籁山河国际旅行社有限公司法人刘涛经营范围境内旅游业务、入境旅游业务统一信用代码911507007722296570成立于2005年,集团旅行社资质中历史最悠久的主体"
}
],
"insurance": {
"title": "旅游责任险 · 1000万保障",
"description": "全程旅游责任险覆盖,出行安全有兜底。购买方呼籁集团旗下旅行社主体。保额1000万元整。",
"insurer": "申能财产保险股份有限公司",
"policyScope": "境内旅游责任险,涵盖人身意外伤害及财产损失",
"claimContact": "出险后联系定制师或领队,协助理赔流程"
"issuer": null,
"description": "全程旅游责任险覆盖,出行安全有兜底。保单号6203130180266250001337,保额10,000,000.00元,有效期2026年01月01日至2026年12月31日。"
},
"awards": [
{
"year": "2026",
"title": "小红书WILL商业大会 · 年度成长型品牌",
"detail": "文旅行业仅6家品牌获此荣誉",
"issuer": "小红书"
"title": "2026小红书WILL商业大会·年度成长型品牌",
"issuer": "小红书",
"year": 2026,
"description": "文旅行业仅6家品牌获此荣誉,是平台对呼籁内容质量与品牌成长的认可"
},
{
"year": "2026",
"title": "内蒙古自治区研学旅游服务商",
"detail": "全区97家之一,具备官方认可的研学服务资质",
"issuer": "内蒙古自治区文化和旅游厅"
"issuer": "内蒙古自治区文化和旅游厅",
"year": 2026,
"description": "全区97家之一,具备官方认可的研学服务资质,可承接中小学研学项目"
},
{
"year": "2024",
"title": "呼伦贝尔学院旅游实习实训基地",
"detail": "校企合作,共同培养旅游管理人才",
"issuer": "呼伦贝尔学院"
"issuer": "呼伦贝尔学院",
"year": 2024,
"description": "校企合作,共同培养旅游管理人才,呼籁每年接收旅游管理专业实习生"
}
],
"heritage": {
"title": "品牌资历11年深耕呼伦贝尔",
"description": "2005年内蒙古呼籁山河国际旅行社有限公司成立,取得旅游经营许可证,开始深耕呼伦贝尔旅游市场;2015年呼籁品牌创立,开始专注于家庭定制游和深度体验型旅游产品;2022年呼伦贝尔呼籁牧场商贸有限公司成立,打通本地牧场和特产供应链;2023年内蒙古呼籁文旅投资开发集团有限公司成立,完成集团化布局;内蒙古呼籁国际旅行社有限公司同年成立;2024年呼籁旅游客运公司、呼籁露营地公司相继成立,实现自有车队+自有营地双重保障;2025年获评小红书2025年度成长型品牌;内蒙古呼籁培训有限公司、内蒙古呼籁文化科技有限公司相继成立;2026年呼伦贝尔呼籁研学文化旅游有限责任公司成立;入选小红书WILL商业大会·年度成长型品牌文旅行业仅6家"
},
"safetyGuarantees": [
{
"title": "三重旅行社资质",
"detail": "旗下三家主体均持有旅游经营许可证"
},
{
"title": "1000万旅游责任险",
"detail": "每单行程全程覆盖旅游意外责任"
},
{
"title": "「呼籁」注册商标",
"detail": "第39类旅游服务注册商标持有方"
},
{
"title": "深耕呼伦贝尔11年",
"detail": "2015年创立,本地团队深耕运营"
}
],
"enterpriseMatrix": {
"totalCount": 9,
"description": "呼籁集团旗下9家主体,覆盖旅行社、客运、营地、商贸、研学、培训、文化科技等全产业链",
"description": "呼籁集团旗下覆盖旅行社、营地、车队、牧场等多业态企业",
"companies": [
{
"name": "内蒙古呼籁文旅投资开发集团有限公司",
"tag": "集团母公司",
"established": "2023",
"role": "统筹旗下所有业务板块,持有旅游经营许可证"
"name": "呼伦贝尔呼籁旅行社有限公司",
"type": "旅行社",
"license": "旅游经营许可证"
},
{
"name": "内蒙古呼籁国际旅行社有限公司",
"tag": "核心旅行社",
"established": "2023",
"role": "产品设计、客户服务、品牌运营,持有旅游经营许可证"
"name": "呼籁旅游有限公司",
"type": "旅行社",
"license": "旅游经营许可证"
},
{
"name": "内蒙古呼籁山河国际旅行社有限公司",
"tag": "旅行社",
"established": "2005",
"role": "集团旗下旅行社主体之一,持有旅游经营许可证"
"name": "嘎查旅行社有限公司",
"type": "旅行社",
"license": "旅游经营许可证"
},
{
"name": "呼籁旅游客运(内蒙古)有限公司",
"tag": "自有车队",
"established": "2024",
"role": "车辆调度与管理,保障出行安全"
"name": "呼籁旅游客运有限公司",
"type": "旅游客运",
"license": "道路运输许可证"
},
{
"name": "呼籁露营地(呼伦贝尔)有限公司",
"tag": "自有营地",
"established": "2024",
"role": "草原活动基地运营,亲子互动与户外体验"
"name": "呼籁草原营地",
"type": "营地运营",
"license": "营地经营许可"
},
{
"name": "呼伦贝尔呼籁牧场商贸有限公司",
"tag": "牧场商贸",
"established": "2022",
"role": "本地牧场和特产供应链,草原伴手礼"
"name": "呼籁牧场商贸有限公司",
"type": "农牧产品",
"license": "营业执照"
},
{
"name": "呼伦贝尔呼籁研学文化旅游有限责任公司",
"tag": "研学教育",
"established": "2026",
"role": "草原自然教育和亲子研学课程"
"name": "呼籁研学教育有限公司",
"type": "研学教育",
"license": "营业执照"
},
{
"name": "内蒙古呼籁培训有限公司",
"tag": "培训体系",
"established": "2025",
"role": "团队培训体系建设和服务标准化输出"
"name": "额吉的故乡文化传媒有限公司",
"type": "文化传媒",
"license": "营业执照"
},
{
"name": "内蒙古呼籁文化科技有限公司",
"tag": "数字化",
"established": "2025",
"role": "数字化平台建设、官网运营和技术支撑"
"name": "呼籁科技有限公司",
"type": "互联网科技",
"license": "营业执照"
}
]
},
"heritage": {
"brandYears": "11",
"milestones": [
{ "year": "2015", "event": "呼籁旅行品牌正式创立,确立'只做呼伦贝尔一个目的地'的品牌定位" },
{ "year": "2022", "event": "呼伦贝尔呼籁牧场商贸有限公司成立,打通本地牧场和特产供应链" },
{ "year": "2023", "event": "内蒙古呼籁文旅投资开发集团有限公司成立,完成集团化布局;内蒙古呼籁国际旅行社有限公司同年成立" },
{ "year": "2024", "event": "呼籁旅游客运公司、呼籁露营地公司相继成立,实现自有车队+自有营地双重保障" },
{ "year": "2025", "event": "获评小红书年度成长型品牌;内蒙古呼籁培训有限公司、内蒙古呼籁文化科技有限公司相继成立;服务家庭突破10000组" },
{ "year": "2026", "event": "呼伦贝尔呼籁研学文化旅游有限责任公司成立;入选小红书WILL商业大会年度成长型品牌文旅行业仅6家" }
]
},
"intellectualProperty": {
"trademark": {
"name": "呼籁",
"scope": "全品类45类注册",
"holder": "内蒙古呼籁文旅投资开发集团有限公司",
"description": "「呼籁」商标已完成全品类注册,覆盖旅游服务、文化活动、教育培训、食品饮料、服装鞋帽、广告营销等类别,从品牌源头保护呼籁的商业权益"
"scope": "第39类旅游、旅行社、交通运输服务",
"holder": "呼伦贝尔呼籁旅行社有限公司",
"description": "「呼籁」商标已在国家知识产权局完成注册,保护呼伦贝尔旅游定制服务领域的核心品牌权益。"
},
"copyrights": [
{
"name": "额吉的故乡",
"category": "其他作品",
"regNo": "国作登字-2024-L-00254025",
"date": "2024.08.26"
"title": "呼籁旅行官方网站",
"type": "软件著作权",
"year": "2024"
},
{
"name": "游牧的森林",
"category": "其他作品",
"regNo": "国作登字-2024-L-00286509",
"date": "2024.09.29"
"title": "额吉的故乡旅游产品系列",
"type": "文字作品著作权",
"year": "2023"
},
{
"name": "呼籁(图腾马)",
"category": "美术作品",
"regNo": "国作登字-2025-F-00159701",
"date": "2025.05.22"
},
{
"name": "籁小咩",
"category": "美术作品",
"regNo": "国作登字-2026-F-00020268",
"date": "2026.01.23"
"title": "小蒙马研学课程体系",
"type": "教育课程著作权",
"year": "2024"
}
]
}
}
}

查看文件

@ -2,16 +2,14 @@
"summary": {
"totalCount": 10000,
"approvalRate": "98%",
"approvalRateNote": "基于历年客户行程结束后的满意度反馈统计",
"repeatRate": "很多家庭来了还想二刷",
"keywords": [
"贴心",
"孩子玩疯了",
"领队比家人还贴心",
"行程不赶不累",
"司机靠谱安全",
"超出预期,物有所值",
"拍照太美了,不像旅游像大片",
"二刷、三刷还来"
"司机靠谱",
"超出预期",
"下次还来",
"拍照超美",
"管家细心"
]
},
"items": [

查看文件

@ -5,9 +5,21 @@
"hint": "根据你的假期长度,为你匹配最合适的行程版本",
"text": "你打算玩几天?",
"options": [
{ "desc": "草原+森林 或 草原+满洲里", "label": "5天", "value": "5天" },
{ "desc": "越野穿越、两次骑马", "label": "6天", "value": "6天" },
{ "desc": "深度探索不留遗憾", "label": "7天", "value": "7天" }
{
"desc": "草原+森林 或 草原+满洲里",
"label": "5天",
"value": "5天"
},
{
"desc": "越野穿越、两次骑马",
"label": "6天",
"value": "6天"
},
{
"desc": "深度探索不留遗憾",
"label": "7天",
"value": "7天"
}
]
},
{
@ -15,10 +27,26 @@
"hint": "不同人群有不同的节奏和侧重点",
"text": "这次出行是?",
"options": [
{ "desc": "爸妈带娃,家庭出游", "label": "带孩子的家庭", "value": "带孩子的家庭" },
{ "desc": "两人世界,浪漫草原", "label": "情侣", "value": "情侣" },
{ "desc": "几个好友一起出发", "label": "朋友结伴", "value": "朋友" },
{ "desc": "一个人的草原之旅", "label": "独自出行", "value": "独行" }
{
"desc": "爸妈带娃,家庭出游",
"label": "带孩子的家庭",
"value": "带孩子的家庭"
},
{
"desc": "两人世界,浪漫草原",
"label": "情侣",
"value": "情侣"
},
{
"desc": "几个好友一起出发",
"label": "朋友结伴",
"value": "朋友"
},
{
"desc": "一个人的草原之旅",
"label": "独自出行",
"value": "独行"
}
]
},
{
@ -26,21 +54,52 @@
"hint": "不同年龄的孩子,适合的活动和节奏差别很大",
"text": "孩子几岁了?",
"options": [
{ "desc": "小宝宝,需要舒适慢节奏", "label": "3岁以下", "value": "3岁以下" },
{ "desc": "学前宝宝,活泼好动", "label": "3—6岁", "value": "3-6岁" },
{ "desc": "小学阶段,探索欲强", "label": "6—12岁", "value": "6-12岁" },
{ "desc": "大孩子,体能好敢于挑战", "label": "12岁以上", "value": "12岁以上" }
{
"desc": "小宝宝,需要舒适慢节奏",
"label": "3岁以下",
"value": "3岁以下"
},
{
"desc": "学前宝宝,活泼好动",
"label": "3—6岁",
"value": "3-6岁"
},
{
"desc": "小学阶段,探索欲强",
"label": "6—12岁",
"value": "6-12岁"
},
{
"desc": "大孩子,体能好敢于挑战",
"label": "12岁以上",
"value": "12岁以上"
}
],
"condition": { "key": "q2", "value": "带孩子的家庭" }
"condition": {
"key": "q2",
"value": "带孩子的家庭"
}
},
{
"id": "q4",
"hint": "我们有不同价位的版本,都是一家一单一车",
"text": "预算倾向是?",
"options": [
{ "desc": "控制预算,好玩就行", "label": "经济实惠", "value": "经济实惠" },
{ "desc": "住得好,玩得舒心", "label": "品质优先", "value": "品质优先" },
{ "desc": "最好的体验,价格不是问题", "label": "不差钱", "value": "不差钱" }
{
"desc": "控制预算,好玩就行",
"label": "经济实惠",
"value": "经济实惠"
},
{
"desc": "住得好,玩得舒心",
"label": "品质优先",
"value": "品质优先"
},
{
"desc": "最好的体验,价格不是问题",
"label": "不差钱",
"value": "不差钱"
}
]
},
{
@ -48,55 +107,147 @@
"hint": "呼伦贝尔有很多面,你更想要哪一面",
"text": "最期待哪种体验?",
"options": [
{ "desc": "骑马、非遗手作、蒙古文化、旅拍", "label": "亲子互动", "value": "亲子互动" },
{ "desc": "草原、森林、湿地、界河", "label": "自然风光", "value": "自然风光" },
{ "desc": "装甲车、漂流、帐篷营地、越野穿越", "label": "极致冒险", "value": "极致冒险" },
{ "desc": "骑马穿越、大力山探索、秘境航拍", "label": "深度探索", "value": "深度探索" }
{
"desc": "骑马、非遗手作、蒙古文化、旅拍",
"label": "亲子互动",
"value": "亲子互动"
},
{
"desc": "草原、森林、湿地、界河",
"label": "自然风光",
"value": "自然风光"
},
{
"desc": "装甲车、漂流、帐篷营地、越野穿越",
"label": "极致冒险",
"value": "极致冒险"
},
{
"desc": "骑马穿越、大力山探索、秘境航拍",
"label": "深度探索",
"value": "深度探索"
}
]
}
],
"scoring": {
"q1": {
"5天": { "v9-5d4n-forest": 9, "v9-5d4n-prairie": 9, "v9-6d5n-family": 2 },
"6天": { "v9-6d5n-family": 10, "v9-6d5n-explore": 9, "v9-5d4n-forest": 3, "v9-5d4n-prairie": 3 },
"7天": { "v9-7d6n-family": 9, "v9-7d6n-wild": 9, "v9-6d5n-family": 3 }
"5天": {
"v9-5d4n": 9,
"v9-6d5n-family": 2,
"v9-5d4n": 9
},
"6天": {
"v9-5d4n": 3,
"v9-6d5n-family": 10,
"v9-5d4n": 3,
"v9-6d5n-family": 9
},
"7天": {
"v9-7d6n-wild": 9,
"v9-6d5n-family": 3,
"v9-7d6n-family": 9
}
},
"q2": {
"情侣": { "v9-5d4n-prairie": 5, "v9-6d5n-explore": 6, "v9-7d6n-wild": 4 },
"朋友": { "v9-6d5n-explore": 5, "v9-7d6n-wild": 6, "v9-5d4n-prairie": 4 },
"独行": { "v9-5d4n-prairie": 5, "v9-6d5n-explore": 6, "v9-5d4n-forest": 4 },
"带孩子的家庭": { "v9-6d5n-family": 9, "v9-7d6n-family": 8, "v9-5d4n-forest": 4, "v9-5d4n-prairie": 4 }
"情侣": {
"v9-7d6n-wild": 4,
"v9-5d4n": 5,
"v9-6d5n-family": 6
},
"朋友": {
"v9-7d6n-wild": 6,
"v9-5d4n": 4,
"v9-6d5n-family": 5
},
"独行": {
"v9-5d4n": 4,
"v9-5d4n": 5,
"v9-6d5n-family": 6
},
"带孩子的家庭": {
"v9-5d4n": 4,
"v9-6d5n-family": 9,
"v9-7d6n-family": 8,
"v9-5d4n": 4
}
},
"q3": {
"3岁以下": { "v9-6d5n-family": 8, "v9-5d4n-prairie": 6, "v9-5d4n-forest": 5 },
"3-6岁": { "v9-6d5n-family": 10, "v9-7d6n-family": 8, "v9-5d4n-forest": 4 },
"6-12岁": { "v9-6d5n-family": 9, "v9-7d6n-family": 8, "v9-6d5n-explore": 5 },
"12岁以上": { "v9-7d6n-wild": 9, "v9-6d5n-explore": 8, "v9-7d6n-family": 4 }
"3-6岁": {
"v9-5d4n": 4,
"v9-6d5n-family": 10,
"v9-7d6n-family": 8
},
"6-12岁": {
"v9-6d5n-family": 9,
"v9-7d6n-family": 8,
"v9-6d5n-family": 5
},
"3岁以下": {
"v9-5d4n": 5,
"v9-6d5n-family": 8,
"v9-5d4n": 6
},
"12岁以上": {
"v9-7d6n-wild": 9,
"v9-7d6n-family": 4,
"v9-6d5n-family": 8
}
},
"q4": {
"经济实惠": { "v9-5d4n-forest": 7, "v9-5d4n-prairie": 7, "v9-6d5n-family": 3 },
"品质优先": { "v9-6d5n-family": 6, "v9-7d6n-family": 6, "v9-6d5n-explore": 5 },
"不差钱": { "v9-7d6n-wild": 8, "v9-7d6n-family": 6, "v9-6d5n-explore": 4 }
"不差钱": {
"v9-7d6n-wild": 8,
"v9-7d6n-family": 6,
"v9-6d5n-family": 4
},
"品质优先": {
"v9-6d5n-family": 6,
"v9-7d6n-family": 6,
"v9-6d5n-family": 5
},
"经济实惠": {
"v9-5d4n": 7,
"v9-6d5n-family": 3,
"v9-5d4n": 7
}
},
"q5": {
"亲子互动": { "v9-6d5n-family": 10, "v9-7d6n-family": 8, "v9-5d4n-forest": 3 },
"自然风光": { "v9-5d4n-forest": 8, "v9-5d4n-prairie": 6, "v9-7d6n-family": 4 },
"极致冒险": { "v9-7d6n-wild": 10, "v9-6d5n-explore": 5 },
"深度探索": { "v9-6d5n-explore": 9, "v9-7d6n-wild": 6, "v9-7d6n-family": 4 }
"亲子互动": {
"v9-5d4n": 3,
"v9-6d5n-family": 10,
"v9-7d6n-family": 8
},
"极致冒险": {
"v9-7d6n-wild": 10,
"v9-6d5n-family": 5
},
"深度探索": {
"v9-7d6n-wild": 6,
"v9-7d6n-family": 4,
"v9-6d5n-family": 9
},
"自然风光": {
"v9-5d4n": 8,
"v9-7d6n-family": 4,
"v9-5d4n": 6
}
}
},
"matchReasons": {
"v9-5d4n-forest": {
"v9-7d6n-wild": {
"default": "旷野探索,装甲车穿越+湿地漂流+帐篷营地+专业航拍,解锁常规线路到不了的地方",
"q1:7天": "7天硬核户外——住帐篷营地和草原木屋,装甲车+漂流+航拍全部安排",
"q2:朋友": "和好友一起装甲车穿越、湿地漂流、秘境航拍,肾上腺素拉满",
"q4:不差钱": "全程特色住宿+装甲车+漂流+航拍+自有营地旅拍,体验价值最高",
"q3:12岁以上": "装甲车穿越+湿地漂流+全地形越野车+帐篷营地,最硬核的户外版本",
"q5:极致冒险": "装甲车穿越草地溪流+额尔古纳湿地漂流+寻龙诀秘境航拍,极致冒险之选"
},
"v9-5d4n": {
"default": "草原+大兴安岭森林双线深度,5天走遍两种风光",
"q1:5天": "5天假期想看草原又想进森林——森林版专为这种需求设计",
"q4:经济实惠": "5天4晚起步价最亲民,森林小火车+驯鹿+骑马一个不少",
"q5:自然风光": "草原+白桦林+大兴安岭+森林小火车+驯鹿园,自然风光层次最丰富"
},
"v9-5d4n-prairie": {
"default": "不进森林,走草原+边境+满洲里环线,错峰安排",
"q1:5天": "5天假期不进森林——草原+寻龙诀秘境+套娃大马戏+马之舞,精彩不打折",
"q3:3岁以下": "不进深山森林,行程节奏更平缓,小宝宝也能轻松跟上"
},
"v9-6d5n-family": {
"default": "6天5晚亲子主推版,自有营地旅拍+非遗手作+骑马越野+蒙古文化,专为带孩子的家庭设计",
"q1:6天": "6天时间刚好——自有营地旅拍+非遗传承人授课+骑马越野+蒙古文化体验全覆盖",
@ -106,13 +257,6 @@
"q5:亲子互动": "非遗传承人授课+搭蒙古包+捡牛粪+熬奶茶+做羊毛毡+专属亲子手册,亲子互动最丰富",
"q2:带孩子的家庭": "主推亲子版——非遗按年龄分层、蒙古文化还原真实生活、专属亲子手册记录旅途发现"
},
"v9-6d5n-explore": {
"default": "越野穿越、两次骑马、不走寻常路,更适合大孩子与成人的进阶体验",
"q1:6天": "6天时间够从容——自有营地旅拍+大力山穿越+两次骑马+秘境探索",
"q2:情侣": "大力山穿越+两次骑马+秘境航拍+风车公路,很适合追求深度的两人世界",
"q3:12岁以上": "两次骑马+全地形越野车+大力山穿越,大孩子最爱的进阶版本",
"q5:深度探索": "大力山穿越全程不走柏油路+两次骑马+寻龙诀秘境,探索感十足"
},
"v9-7d6n-family": {
"default": "最完整亲子深度版,自有营地旅拍+非遗手作+森林小火车+蒙古文化体验",
"q1:7天": "7天假期值得最完整的行程——草原、森林、边境、满洲里全覆盖",
@ -121,13 +265,17 @@
"q5:亲子互动": "非遗传承人授课+搭蒙古包+捡牛粪+熬奶茶+做羊毛毡,亲子互动最丰富",
"q2:带孩子的家庭": "专为带孩子的家庭设计,非遗按年龄分层,蒙古文化还原真实生活场景"
},
"v9-7d6n-wild": {
"default": "旷野探索,装甲车穿越+湿地漂流+帐篷营地+专业航拍,解锁常规线路到不了的地方",
"q1:7天": "7天硬核户外——住帐篷营地和草原木屋,装甲车+漂流+航拍全部安排",
"q2:朋友": "和好友一起装甲车穿越、湿地漂流、秘境航拍,肾上腺素拉满",
"q4:不差钱": "全程特色住宿+装甲车+漂流+航拍+自有营地旅拍,体验价值最高",
"q3:12岁以上": "装甲车穿越+湿地漂流+全地形越野车+帐篷营地,最硬核的户外版本",
"q5:极致冒险": "装甲车穿越草地溪流+额尔古纳湿地漂流+寻龙诀秘境航拍,极致冒险之选"
"v9-5d4n": {
"default": "不进森林,走草原+边境+满洲里环线,错峰安排",
"q1:5天": "5天假期不进森林——草原+寻龙诀秘境+套娃大马戏+马之舞,精彩不打折",
"q3:3岁以下": "不进深山森林,行程节奏更平缓,小宝宝也能轻松跟上"
},
"v9-6d5n-family": {
"default": "越野穿越、两次骑马、不走寻常路,更适合大孩子与成人的进阶体验",
"q1:6天": "6天时间够从容——自有营地旅拍+大力山穿越+两次骑马+秘境探索",
"q2:情侣": "大力山穿越+两次骑马+秘境航拍+风车公路,很适合追求深度的两人世界",
"q3:12岁以上": "两次骑马+全地形越野车+大力山穿越,大孩子最爱的进阶版本",
"q5:深度探索": "大力山穿越全程不走柏油路+两次骑马+寻龙诀秘境,探索感十足"
}
}
}
}

查看文件

@ -1,11 +1,11 @@
{
"pages": {
"home": {
"title": "呼籁旅行 - 呼伦贝尔亲子游·家庭定制游·一家一单一车",
"description": "呼籁旅行是呼伦贝尔亲子游品牌,深耕呼伦贝尔11年,已服务10000+组家庭。提供5-7天额吉的故乡V9系列亲子定制行程及小蒙马夏令营,一家一单一车,不拼团不赶路。",
"h1": "呼籁旅行 — 呼伦贝尔亲子游",
"title": "呼籁旅行 - 呼伦贝尔家庭定制游·一家一单一车",
"description": "呼籁旅行是呼伦贝尔家庭定制游品牌,深耕呼伦贝尔11年,已服务10000+组家庭。提供4-7天额吉的故乡V9系列亲子行程及小蒙马夏令营。",
"h1": "呼籁旅行 — 呼伦贝尔家庭定制游",
"ogImage": "/images/og-home.jpg",
"keywords": "呼伦贝尔亲子游,呼伦贝尔家庭定制游,呼籁旅行,一家一单一车,呼伦贝尔旅游,草原亲子游,额吉的故乡,呼伦贝尔定制游"
"keywords": "呼伦贝尔亲子游,呼伦贝尔家庭定制游,呼籁旅行,一家一单一车,呼伦贝尔旅游,草原定制游,额吉的故乡"
},
"about": {
"title": "关于呼籁旅行 - 品牌故事·旗下9家企业·深耕呼伦贝尔11年",
@ -15,28 +15,22 @@
"keywords": "呼籁旅行,呼伦贝尔旅行社,自有营地,自有车队,呼籁文旅集团,深耕呼伦贝尔11年"
},
"products": {
"title": "额吉的故乡V9 - 呼伦贝尔亲子定制游 · 5-7天6个版本 - 呼籁旅行",
"description": "呼籁旅行夏季亲子定制游产品「额吉的故乡V9」,5天4晚至7天6晚共6个版本,专为带孩子的家庭设计。自有营地旅拍、非遗手作、骑马穿越、蒙古文化体验。一家一单一车,不拼团不赶路。",
"h1": "额吉的故乡 · 呼伦贝尔亲子定制游",
"title": "额吉的故乡 - 呼伦贝尔夏季定制游 · V9系列4-7天 - 呼籁旅行",
"description": "呼籁旅行夏季定制游产品「额吉的故乡V9」,4天3晚至7天6晚多版本亲子行程,莫日格勒河、边境公路、呼伦湖、自有营地。一家一单一车,专属私家团。",
"h1": "额吉的故乡 · 呼伦贝尔夏季定制游",
"ogImage": "/images/og-products.jpg",
"keywords": "呼伦贝尔亲子游,额吉的故乡,呼伦贝尔定制游,额吉的故乡V9,呼伦贝尔几天合适,5天4晚,6天5晚,7天6晚,亲子定制游"
"keywords": "额吉的故乡,呼伦贝尔夏季定制游,呼伦贝尔亲子游,额吉的故乡V9,呼伦贝尔几天合适,4天3晚,5天4晚,6天5晚,7天6晚"
},
"faq": {
"title": "呼伦贝尔亲子游常见问题 - 价格·行程·安全·穿搭全解答 - 呼籁旅行",
"description": "呼伦贝尔亲子游和定制游常见问题解答:价格、行程天数、穿搭准备、安全保障、退改政策等高频问题,呼籁旅行为您详细解答。",
"h1": "呼伦贝尔亲子游常见问答",
"description": "呼伦贝尔定制游和亲子游常见问题解答:价格、行程天数、穿搭准备、安全保障、退改政策等高频问题,呼籁旅行为您详细解答。",
"h1": "呼伦贝尔定制游常见问答",
"ogImage": "/images/og-faq.jpg",
"keywords": "呼伦贝尔旅游攻略,呼伦贝尔亲子游攻略,呼伦贝尔多少钱,呼伦贝尔几月去好,呼伦贝尔穿什么,呼伦贝尔定制游"
},
"youji": {
"title": "客户游记 - 来自各平台的真实旅行故事 - 呼籁旅行",
"description": "收集美篇、微信公众号、抖音等平台客户的真实呼伦贝尔旅行故事。亲子游、家庭游、闺蜜游、摄影游等多种出行方式的深度游记分享。",
"h1": "客户游记",
"keywords": "客户游记,呼伦贝尔游记,呼籁旅行评价,美篇游记,旅行故事,呼伦贝尔亲子游记"
"keywords": "呼伦贝尔旅游攻略,呼伦贝尔亲子游攻略,呼伦贝尔多少钱,呼伦贝尔几月去好,呼伦贝尔穿什么"
},
"reviews": {
"title": "呼伦贝尔亲子游客户评价 - 真实口碑·10000+家庭的选择 - 呼籁旅行",
"description": "查看呼籁旅行呼伦贝尔亲子游客户真实评价,涵盖亲子游、家庭定制游等场景。好评率98%,听听10000+家庭的呼伦贝尔旅行体验。",
"title": "呼伦贝尔定制游客户评价 - 真实口碑·10000+家庭的选择 - 呼籁旅行",
"description": "查看呼籁旅行呼伦贝尔定制游客户真实评价,涵盖亲子游、家庭出行等场景。好评率98%,听听10000+家庭的呼伦贝尔旅行体验。",
"h1": "客户评价",
"ogImage": "/images/og-reviews.jpg",
"keywords": "呼伦贝尔旅游评价,呼籁旅行怎么样,呼伦贝尔亲子游评价,呼伦贝尔定制游口碑"
@ -55,110 +49,12 @@
"ogImage": "/images/og-summer-camp.jpg",
"keywords": "呼伦贝尔夏令营,草原亲子夏令营,小蒙马夏令营,呼伦贝尔亲子营,研学旅行"
},
"qualifications": {
"title": "资质荣誉 - 三重旅行社资质·1000万责任险·行业认证 - 呼籁旅行",
"description": "呼籁旅行持有三重旅行社经营许可证,购买1000万旅游责任险,荣获小红书年度成长型品牌等行业认证。查看完整资质与荣誉信息。",
"h1": "资质荣誉",
"ogImage": "/images/og-about.jpg",
"keywords": "呼籁旅行资质,旅行社经营许可证,旅游责任险,呼伦贝尔旅行社认证,呼籁荣誉"
},
"news": {
"title": "最新动态 - 品牌动态·产品发布·活动公告 - 呼籁旅行",
"description": "呼籁旅行最新动态:品牌公告、产品发布、活动资讯,第一时间了解呼伦贝尔亲子游最新资讯。",
"h1": "最新动态",
"ogImage": "/images/og-about.jpg",
"keywords": "呼籁旅行动态,呼伦贝尔旅游资讯,呼籁旅行公告"
},
"contact": {
"title": "联系呼籁旅行 - 微信客服·电话咨询·在线定制",
"description": "联系呼籁旅行:微信客服一对一沟通、电话咨询。所有行程签订正规电子合同,请认准官方渠道。",
"title": "联系呼籁旅行 - 微信客服·电话·小程序预订",
"description": "联系呼籁旅行:微信客服、电话咨询、小程序预订。所有行程签订正规电子合同,请认准官方渠道。",
"h1": "联系我们",
"ogImage": "/images/og-contact.jpg",
"keywords": "呼籁旅行联系方式,呼伦贝尔定制游咨询,呼籁旅行微信,呼伦贝尔旅游电话"
},
"products-autumn": {
"title": "游牧的森林 - 呼伦贝尔秋季定制游·大兴安岭秋色 - 呼籁旅行",
"description": "呼籁旅行秋季产品「游牧的森林」,大兴安岭白桦林金黄秋色、额尔古纳湿地、中俄边境风光。9月中旬至国庆期间出发,一家一单一车,错过再等一年。",
"h1": "游牧的森林 · 呼伦贝尔秋季定制游",
"ogImage": "/images/og-products.jpg",
"keywords": "呼伦贝尔秋季旅游,大兴安岭秋色,游牧的森林,呼伦贝尔秋天,白桦林秋景,额尔古纳秋季"
},
"products-winter": {
"title": "嗨冰雪 - 呼伦贝尔冬季定制游·冰雪那达慕·驯鹿部落 - 呼籁旅行",
"description": "呼籁旅行冬季产品「嗨冰雪」,体验冰雪那达慕、敖鲁古雅驯鹿部落、雪地温泉、马拉爬犁。12月至次年2月出发,感受零下30度的童话世界。",
"h1": "嗨冰雪 · 呼伦贝尔冬季定制游",
"ogImage": "/images/og-products.jpg",
"keywords": "呼伦贝尔冬季旅游,冰雪那达慕,呼伦贝尔冬天,驯鹿部落,呼伦贝尔雪景,嗨冰雪"
},
"gallery": {
"title": "呼籁旅拍 - 草原蒙古袍亲子旅拍·200+服饰·自营营地取景 - 呼籁旅行",
"description": "呼籁旅行自营旅拍服务,200+件蒙古族服饰,在呼籁自营营地独家取景。亲子旅拍、儿童写真、全家福,摄影师随行拍摄,精修照片当日交付。",
"h1": "呼籁旅拍",
"ogImage": "/images/og-products.jpg",
"keywords": "草原旅拍,呼伦贝尔旅拍,蒙古袍旅拍,亲子旅拍,呼籁营地旅拍,草原亲子写真"
},
"destinations": {
"title": "亲子游目的地对比 - 呼伦贝尔vs新疆vs内蒙西部 - 呼籁旅行",
"description": "基于真实数据的亲子游目的地客观对比:气温、车程、海拔、景观密度、亲子适配度、费用参考。帮你找到最适合带孩子去的目的地。",
"h1": "亲子游目的地怎么选",
"ogImage": "/images/og-products.jpg",
"keywords": "亲子游目的地,呼伦贝尔和新疆哪个好,带孩子去哪旅游,呼伦贝尔vs新疆,草原旅游对比"
},
"calendar": {
"title": "呼伦贝尔最佳出行月份 - 各月景色·气温·穿搭全攻略 - 呼籁旅行",
"description": "基于呼籁旅行11年带队经验,详解呼伦贝尔5-10月各月景色特点、气温数据、穿搭建议和出行性价比,帮你选择最合适的出行时间。",
"h1": "呼伦贝尔最佳出行月份",
"ogImage": "/images/og-guides.jpg",
"keywords": "呼伦贝尔几月去最好,呼伦贝尔最佳旅游时间,呼伦贝尔各月气温,呼伦贝尔旅游季节,草原什么时候去"
},
"xiaohongshu": {
"title": "小红书游记墙 - 客户真实分享·呼伦贝尔亲子游 - 呼籁旅行",
"description": "呼籁旅行客户在小红书平台的真实旅行分享,记录呼伦贝尔草原亲子游的美好瞬间。点赞收藏超26万,看看大家怎么说。",
"h1": "小红书游记墙",
"ogImage": "/images/og-reviews.jpg",
"keywords": "呼伦贝尔小红书,呼籁旅行小红书,呼伦贝尔亲子游分享,草原旅行笔记"
},
"blog": {
"title": "呼伦贝尔旅游攻略 - 深度攻略·实用干货·行程规划 - 呼籁旅行",
"description": "呼籁旅行出品的呼伦贝尔深度旅游攻略行程规划、景点推荐、穿搭指南、美食攻略、亲子游实用建议,11年经验干货分享。",
"h1": "呼伦贝尔旅游攻略",
"ogImage": "/images/og-guides.jpg",
"keywords": "呼伦贝尔旅游攻略,呼伦贝尔自由行攻略,呼伦贝尔亲子游攻略,草原旅游攻略,呼伦贝尔行程规划"
},
"courses": {
"title": "小蒙马研学课程 - 草原自然教育·分龄设计·LNT无痕理念 - 呼籁旅行",
"description": "小蒙马研学课程体系草原生态、马术体验、蒙古文化、自然艺术四大模块,按3-6岁、7-9岁、10-12岁分龄设计,贯穿LNT无痕理念。",
"h1": "小蒙马研学课程",
"ogImage": "/images/og-summer-camp.jpg",
"keywords": "草原研学,自然教育,呼伦贝尔研学,亲子研学课程,小蒙马研学,LNT无痕山林"
},
"customize": {
"title": "在线定制 - 免费获取呼伦贝尔亲子游专属方案 - 呼籁旅行",
"description": "填写出行需求,2小时内呼籁专属定制师联系您,量身定制呼伦贝尔亲子游行程方案。免费咨询,无隐形消费。",
"h1": "在线定制专属方案",
"ogImage": "/images/og-contact.jpg",
"keywords": "呼伦贝尔定制游,呼伦贝尔行程定制,亲子游方案,呼籁旅行定制,免费定制方案"
},
"selector": {
"title": "选版本 - 哪个额吉的故乡版本适合你家 - 呼籁旅行",
"description": "通过几个简单问题,帮你从额吉的故乡V9的6个版本中找到最适合你家的行程方案。按假期天数、孩子年龄、出行偏好智能推荐。",
"h1": "哪个版本适合你",
"ogImage": "/images/og-products.jpg",
"keywords": "额吉的故乡哪个版本好,呼伦贝尔几天合适,呼伦贝尔行程推荐,亲子游选哪个版本"
},
"winter-camp": {
"title": "小蒙马冬令营 - 呼伦贝尔冰雪亲子营·极寒体验 - 呼籁旅行",
"description": "小蒙马冬令营是呼籁旅行打造的呼伦贝尔冬季亲子营,在零下30度的童话世界里体验冰雪那达慕、驯鹿互动、雪地温泉、马拉爬犁。",
"h1": "小蒙马冬令营",
"ogImage": "/images/og-products.jpg",
"keywords": "呼伦贝尔冬令营,冰雪亲子营,小蒙马冬令营,呼伦贝尔冬季亲子游,雪地体验"
},
"pricing": {
"title": "价格详情 - 额吉的故乡V9各版本费用明细 - 呼籁旅行",
"description": "呼籁旅行额吉的故乡V9系列各版本价格参考,含舒适套餐和高档套餐。费用包含用车、住宿、领队、活动、保险、旅拍,全程无隐形消费。",
"h1": "产品价格详情",
"ogImage": "/images/og-products.jpg",
"keywords": "呼伦贝尔旅游多少钱,呼伦贝尔亲子游价格,额吉的故乡价格,呼籁旅行费用,呼伦贝尔定制游报价"
}
}
}
}

文件差异因一行或多行过长而隐藏

查看文件

@ -10,12 +10,37 @@
"season": "冬季11月-次年3月",
"route": "海拉尔 → 阿尔山 → 金江沟阿尔善 → 海拉尔",
"whyHulunbuir": "到北方看雪,很多人第一反应是哈尔滨。冰雕大、亮、好看,航班多,项目也密集。但热闹的反面是去哪都排队,假期被人流和「同款路线」填满。呼伦贝尔的冬天没有那么多「摆拍打卡点」,最打动人的就是那种一望无际的白:雪原铺到天际,风吹过来很干净,脚下踩雪的「咯吱」声,会让人一下子安静下来。不拥挤,不排队,也不赶时间。对带孩子的家庭来说,这种「纯粹的舒服」,反而比什么都值得。",
"closingNote": "我们不打算把自己说得多厉害,但有一点可以很坦诚地说:我们真的是用父母的视角,拿「自己带孩子的标准」在设计这条线。不是为了多一个产品,而是觉得——愿意选择小蒙马的家庭,值得在这个冬天,在一片干净的雪原里,拥有一次只属于他们自己的记忆。",
"photographer": {
"name": "小E",
"description": "夏季小蒙马11期的全能摄影师。不是那种拿着相机「拍你」的摄影师,更像一个能瞬间融入孩子世界的大哥哥。孩子们超级黏他,能捕捉到很多大人看不到的瞬间——自然、不刻意、带着真情绪的画面。",
"specialDay2": "行程第二天大雪原日额外增加一位摄影师协作,确保每个家庭在最好的光线、最舒服的状态下拍到属于自己的大片,并为每个家庭拍一支小Vlog。"
},
"winterClothing": {
"lower": "保暖秋裤/抓绒裤 + 防风外裤(羽绒裤/雪裤/软壳裤/厚棉裤)",
"shoes": "雪地靴为主,建议略大半码,加厚羊毛鞋垫+暖足贴",
"upper": "保暖内衣(排汗)+ 抓绒/毛衣/卫衣做中层 + 滑雪服或防风保暖棉服/羽绒服",
"accessories": "护耳帽子、防水滑雪手套、围巾/脖套、墨镜、护肤霜、防晒、润唇膏"
},
"campAdvantages": [
"孩子有年龄相仿的伙伴,有领队带着玩,不用一直黏着爸妈",
"每个环节都有安排、有照看,有专业研学领队看管孩子,孩子在玩的时候也在接触书本外的世界",
"家长无需不断做选择,不用跟着孩子满场跑;带娃不再是负担,而是一起参与,省心省力",
"随团配备专职摄影师,全程跟拍,家长也不用再纠结「谁来帮我们拍」"
],
"serviceConfig": [
"亲子领队 1 名",
"副领队 1 名",
"摄影师 1 名D2配备2名",
"专业马术教练(马术日)",
"专业滑雪教练(滑雪日)"
],
"campEssentials": [
"备用手套",
"保温水壶热水",
"孩子状态观察",
"简易补能零食"
],
"hotels": [
{
"name": "海拉尔嘉世豪大酒店",
@ -122,34 +147,10 @@
"hotel": null
}
],
"photographer": {
"name": "小E",
"description": "夏季小蒙马11期的全能摄影师。不是那种拿着相机「拍你」的摄影师,更像一个能瞬间融入孩子世界的大哥哥。孩子们超级黏他,能捕捉到很多大人看不到的瞬间——自然、不刻意、带着真情绪的画面。",
"specialDay2": "行程第二天大雪原日额外增加一位摄影师协作,确保每个家庭在最好的光线、最舒服的状态下拍到属于自己的大片,并为每个家庭拍一支小Vlog。"
},
"winterClothing": {
"upper": "保暖内衣(排汗)+ 抓绒/毛衣/卫衣做中层 + 滑雪服或防风保暖棉服/羽绒服",
"lower": "保暖秋裤/抓绒裤 + 防风外裤(羽绒裤/雪裤/软壳裤/厚棉裤)",
"shoes": "雪地靴为主,建议略大半码,加厚羊毛鞋垫+暖足贴",
"accessories": "护耳帽子、防水滑雪手套、围巾/脖套、墨镜、护肤霜、防晒、润唇膏"
},
"serviceConfig": [
"亲子领队 1 名",
"副领队 1 名",
"摄影师 1 名D2配备2名",
"专业马术教练(马术日)",
"专业滑雪教练(滑雪日)"
],
"campEssentials": [
"备用手套",
"保温水壶热水",
"孩子状态观察",
"简易补能零食"
],
"faq": [
{
"q": "呼伦贝尔冬天冷不冷?孩子受得了吗?",
"a": "冷是肯定的,海拉尔、阿尔山冬季-20\u2103~-35\u2103为常态。但冷不等于「难受」。户外活动时,只要节奏安排得好、活动够有趣,孩子很少喊冷。真正怕冷的是「站着等、排队、干耗着」,我们把干耗着的时间压到最低。按照穿衣指南准备装备,完全没问题。"
"a": "冷是肯定的,海拉尔、阿尔山冬季-20℃~-35℃为常态。但冷不等于「难受」。户外活动时,只要节奏安排得好、活动够有趣,孩子很少喊冷。真正怕冷的是「站着等、排队、干耗着」,我们把干耗着的时间压到最低。按照穿衣指南准备装备,完全没问题。"
},
{
"q": "冬季营需要家长陪同吗?",
@ -161,7 +162,7 @@
},
{
"q": "行程会因天气调整吗?",
"a": "冬季受天气影响较大。如遇暴雪、大风(≥6级)、道路封控、极端低温(-30\u2103以下)等情况,我们会调整体验顺序或进行替代项目。安全第一,不会在不安全的条件下带孩子户外体验。"
"a": "冬季受天气影响较大。如遇暴雪、大风(≥6级)、道路封控、极端低温(-30以下)等情况,我们会调整体验顺序或进行替代项目。安全第一,不会在不安全的条件下带孩子户外体验。"
},
{
"q": "定金和退改政策是什么?",
@ -171,6 +172,5 @@
"q": "住宿条件怎么样?",
"a": "全程精选酒店海拉尔嘉世豪携程5钻连住2晚、阿尔善温泉酒店携程5钻连住2晚带私汤、阿尔山成悦携程4钻2晚。连住设计不折腾行李,不折腾孩子。"
}
],
"closingNote": "我们不打算把自己说得多厉害,但有一点可以很坦诚地说:我们真的是用父母的视角,拿「自己带孩子的标准」在设计这条线。不是为了多一个产品,而是觉得——愿意选择小蒙马的家庭,值得在这个冬天,在一片干净的雪原里,拥有一次只属于他们自己的记忆。"
}
]
}

查看文件

@ -4,6 +4,80 @@
"season": "冬季11月-次年3月",
"narrative": "呼伦贝尔和阿尔山的冬,安静的不像一个旅游地。你不需要到哪都排很长时间的队,却可以独享一整片无际的雪原和茫茫林海。这里也是呼籁旅行的家,所以这不单是一条旅行路线,也是一次跟我们回家的冬季体验之旅。",
"style": "独立成团不拼团 · 一单一车 · 随走随停 · 不错过每处风景",
"versions": [
{
"id": "winter-south-5d4n",
"name": "嗨冰雪V3·南线5天4晚",
"days": 5,
"nights": 4,
"tag": "精华版",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"audience": "假期有限、想体验冬季精华的家庭",
"description": "冬季南线精华浓缩版,5天时间串联呼伦贝尔雪原与阿尔山冰雪世界。冰雪那达慕、雪地狼群、摩托车穿越、骑马、不冻河、白狼峰日出,核心体验一个不少。行程紧凑但不赶路,适合假期有限但想深度体验冬季呼伦贝尔的旅行者。",
"highlights": [
"冰雪那达慕+雪地狼群+围炉煮茶,感受草原冬日的生命力",
"雪地骑马+摩托车穿越,速度与激情的冬日体验",
"白狼峰日出+不冻河奇观,阿尔山冬季精华"
],
"itinerary": [
"D1 各地→呼伦贝尔(接机/站+自由闲逛)",
"D2 冰雪那达慕-莫日格勒河+断崖-冰雪火锅-雪地狼群-围炉煮茶-日落-海拉尔",
"D3 雪地骑马+摩托车穿越-蓝房子-不冻河日落-泡温泉-阿尔山森林公园",
"D4 白狼峰日出-泼水成冰-百里雾凇画廊-森林越野-驯鹿拉车-海拉尔",
"D5 烟火早市-伊敏河嘉年华(超长冰滑梯)-返程"
]
},
{
"id": "winter-south-6d5n",
"name": "嗨冰雪V3·南线6天5晚",
"days": 6,
"nights": 5,
"tag": "经典版",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"audience": "想深度体验阿尔山冬景的家庭",
"description": "冬季南线经典版本,6天5晚从容走遍呼伦贝尔雪原与阿尔山冰雪世界。在精华版基础上,增加了阿尔山森林公园深度游览、网红牛打卡、百里雾凇画廊等内容,在童话小城阿尔山住两晚,节奏更从容。平均每天车程不超180公里,走走停停、边走边玩。",
"highlights": [
"冰雪那达慕+雪地狼群+雪地火锅+围炉煮茶,冬日草原生命力",
"雪地骑马+摩托车穿越+不冻河日落+冬日烟花+泡温泉",
"网红牛-百里雾凇画廊-森林越野10公里-驯鹿拉车-白狼峰日出"
],
"itinerary": [
"D1 各地→呼伦贝尔(接机/站+自由闲逛)",
"D2 冰雪那达慕-莫日格勒河+断崖-冰雪火锅-雪地狼群-围炉煮茶-日落-海拉尔140公里",
"D3 雪地骑马+摩托车穿越-蓝房子-不冻河日落-冬日烟花-泡温泉-阿尔山森林公园300公里",
"D4 网红牛-百里雾凇画廊-森林越野10公里-赏梅花鹿-驯鹿拉车-雪村-阿尔山100公里",
"D5 阿尔山-白狼峰日出-泼水成冰-日式火车站-樟子松林-海拉尔350公里",
"D6 海拉尔-烟火早市-伊敏河嘉年华(超长冰滑梯)-历史或民俗博物馆-返程20公里"
]
},
{
"id": "winter-north-7d6n",
"name": "嗨冰雪V3·北线7天6晚",
"days": 7,
"nights": 6,
"tag": "深度版",
"line": "北线",
"route": "呼伦贝尔+大兴安岭",
"audience": "假期充足、想深度探索冬季北线的家庭",
"description": "冬季北线深度版,7天6晚从容走遍呼伦贝尔与大兴安岭。从草原雪原到中俄蒙边境满洲里,从呼伦湖蓝冰到恩和雪地骑马,从敖鲁古雅驯鹿部落到根河铁锹烤肉。入住套娃酒店体验异域风情,望见林悦独栋别墅感受静谧山野。平均每天车程不超210公里,走走停停、边走边玩。",
"highlights": [
"冰雪那达慕+雪地狼群+围炉煮茶,冬日草原原始体验",
"满洲里套娃酒店+国门+呼伦湖穿越蓝冰,边境异域风情",
"恩和雪地骑马+敖鲁古雅驯鹿部落+铁锹烤肉,大兴安岭深度探索"
],
"itinerary": [
"D1 各地→呼伦贝尔(接机/站+自由闲逛)",
"D2 那达慕-莫日格勒河+断崖-冰雪火锅-雪地狼群-围炉煮茶-冬日烟花-海拉尔140公里",
"D3 烟火早市-伊敏河嘉年华+超长冰滑梯-扎赉诺尔博物馆-北欧夜景-套娃酒店230公里",
"D4 国门+北疆明珠观光塔-风车公路-呼伦湖穿越-边防公路-雪原日落-额尔古纳280公里",
"D5 雪圆圆-三河村景+小楼山打卡点-泼水成冰-恩和骑马-恩和日落+夜景-望见林悦110公里",
"D6 望见林悦-室韦+临江后山-敖鲁古雅乡-圣诞小屋+敖乡夜景-根河230公里",
"D7 根河-布冬霞驯鹿部落-铁锹烤肉-鄂温克民族服饰体验-海拉尔-返程250公里"
]
}
],
"highlights": [
{
"title": "呼伦贝尔大雪原",
@ -30,80 +104,6 @@
"description": "冬季骑马更独具一番感受,在一望无际的雪原和白桦林之间,感受冬季的速度与激情,用骑行的角度丈量这片神奇的土地,深入茫茫无际的雪原,欣赏绝美的冬日风光。"
}
],
"versions": [
{
"id": "winter-south-5d4n",
"name": "嗨冰雪V3·南线5天4晚",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"days": 5,
"nights": 4,
"audience": "假期有限、想体验冬季精华的家庭",
"description": "冬季南线精华浓缩版,5天时间串联呼伦贝尔雪原与阿尔山冰雪世界。冰雪那达慕、雪地狼群、摩托车穿越、骑马、不冻河、白狼峰日出,核心体验一个不少。行程紧凑但不赶路,适合假期有限但想深度体验冬季呼伦贝尔的旅行者。",
"highlights": [
"冰雪那达慕+雪地狼群+围炉煮茶,感受草原冬日的生命力",
"雪地骑马+摩托车穿越,速度与激情的冬日体验",
"白狼峰日出+不冻河奇观,阿尔山冬季精华"
],
"tag": "精华版",
"itinerary": [
"D1 各地→呼伦贝尔(接机/站+自由闲逛)",
"D2 冰雪那达慕-莫日格勒河+断崖-冰雪火锅-雪地狼群-围炉煮茶-日落-海拉尔",
"D3 雪地骑马+摩托车穿越-蓝房子-不冻河日落-泡温泉-阿尔山森林公园",
"D4 白狼峰日出-泼水成冰-百里雾凇画廊-森林越野-驯鹿拉车-海拉尔",
"D5 烟火早市-伊敏河嘉年华(超长冰滑梯)-返程"
]
},
{
"id": "winter-south-6d5n",
"name": "嗨冰雪V3·南线6天5晚",
"line": "南线",
"route": "呼伦贝尔+阿尔山",
"days": 6,
"nights": 5,
"audience": "想深度体验阿尔山冬景的家庭",
"description": "冬季南线经典版本,6天5晚从容走遍呼伦贝尔雪原与阿尔山冰雪世界。在精华版基础上,增加了阿尔山森林公园深度游览、网红牛打卡、百里雾凇画廊等内容,在童话小城阿尔山住两晚,节奏更从容。平均每天车程不超180公里,走走停停、边走边玩。",
"highlights": [
"冰雪那达慕+雪地狼群+雪地火锅+围炉煮茶,冬日草原生命力",
"雪地骑马+摩托车穿越+不冻河日落+冬日烟花+泡温泉",
"网红牛-百里雾凇画廊-森林越野10公里-驯鹿拉车-白狼峰日出"
],
"tag": "经典版",
"itinerary": [
"D1 各地→呼伦贝尔(接机/站+自由闲逛)",
"D2 冰雪那达慕-莫日格勒河+断崖-冰雪火锅-雪地狼群-围炉煮茶-日落-海拉尔140公里",
"D3 雪地骑马+摩托车穿越-蓝房子-不冻河日落-冬日烟花-泡温泉-阿尔山森林公园300公里",
"D4 网红牛-百里雾凇画廊-森林越野10公里-赏梅花鹿-驯鹿拉车-雪村-阿尔山100公里",
"D5 阿尔山-白狼峰日出-泼水成冰-日式火车站-樟子松林-海拉尔350公里",
"D6 海拉尔-烟火早市-伊敏河嘉年华(超长冰滑梯)-历史或民俗博物馆-返程20公里"
]
},
{
"id": "winter-north-7d6n",
"name": "嗨冰雪V3·北线7天6晚",
"line": "北线",
"route": "呼伦贝尔+大兴安岭",
"days": 7,
"nights": 6,
"audience": "假期充足、想深度探索冬季北线的家庭",
"description": "冬季北线深度版,7天6晚从容走遍呼伦贝尔与大兴安岭。从草原雪原到中俄蒙边境满洲里,从呼伦湖蓝冰到恩和雪地骑马,从敖鲁古雅驯鹿部落到根河铁锹烤肉。入住套娃酒店体验异域风情,望见林悦独栋别墅感受静谧山野。平均每天车程不超210公里,走走停停、边走边玩。",
"highlights": [
"冰雪那达慕+雪地狼群+围炉煮茶,冬日草原原始体验",
"满洲里套娃酒店+国门+呼伦湖穿越蓝冰,边境异域风情",
"恩和雪地骑马+敖鲁古雅驯鹿部落+铁锹烤肉,大兴安岭深度探索"
],
"tag": "深度版",
"itinerary": [
"D1 各地→呼伦贝尔(接机/站+自由闲逛)",
"D2 那达慕-莫日格勒河+断崖-冰雪火锅-雪地狼群-围炉煮茶-冬日烟花-海拉尔140公里",
"D3 烟火早市-伊敏河嘉年华+超长冰滑梯-扎赉诺尔博物馆-北欧夜景-套娃酒店230公里",
"D4 国门+北疆明珠观光塔-风车公路-呼伦湖穿越-边防公路-雪原日落-额尔古纳280公里",
"D5 雪圆圆-三河村景+小楼山打卡点-泼水成冰-恩和骑马-恩和日落+夜景-望见林悦110公里",
"D6 望见林悦-室韦+临江后山-敖鲁古雅乡-圣诞小屋+敖乡夜景-根河230公里",
"D7 根河-布冬霞驯鹿部落-铁锹烤肉-鄂温克民族服饰体验-海拉尔-返程250公里"
]
}
],
"southHighlights": [
{
"title": "摩托车穿越+雪地野骑",
@ -148,40 +148,178 @@
"description": "呼伦湖是我国北方第一大湖,一旦进入冬季千里冰封、万里雪飘的时候,呼伦湖就会变成一整块巨冰;湖面穿越+寻找蓝冰的体验活动,乘车行驶在一望无际的冰面上,是一次特别且难忘的旅行体验。"
}
],
"timeline": [
{
"version": "V3",
"date": "2025.11",
"title": "南北双线全面升级,新增5天4晚精华版",
"changes": [
{
"text": "南线新增5天4晚精华版,假期有限也能体验冬季精华",
"type": "add"
},
{
"text": "北线重新加入满洲里行程,新增套娃酒店+呼伦湖穿越蓝冰",
"type": "add"
},
{
"text": "南线新增摩托车穿越、冰雪森林轻徒步体验",
"type": "add"
},
{
"text": "全线升级住宿标准,新增望见林悦独栋别墅等特色住宿",
"type": "update"
}
],
"reason": "V2取消满洲里后客户反馈北线内容偏少,同时很多客户假期有限但想体验冬季。V3重新优化满洲里行程套娃酒店+呼伦湖蓝冰,同时新增南线5天4晚精华版满足短假期需求。"
},
{
"version": "V2北线",
"date": "2024.11",
"title": "深入大兴安岭腹地,探访原始鄂温克部落",
"changes": [
{
"text": "新增大兴安岭徒步,穿军大衣戴狗皮帽子踏入银装素裹的林海",
"type": "add"
},
{
"text": "新增铁锹烤肉,雪地里就地取材生火烤肉",
"type": "add"
},
{
"text": "新增原始鄂温克寻鹿点,走进真正的驯鹿部落",
"type": "add"
},
{
"text": "取消满洲里行程,把时间留给更值得的地方",
"type": "remove"
},
{
"text": "增加冬季随车备品,让寒冷的冬天充满温度",
"type": "update"
}
],
"reason": "前往满洲里路途景色单一,俄罗斯大马戏、马术表演停止演出,呼伦湖湖面被雪覆盖难看到大面积蓝冰。取消满洲里后把时间给了大兴安岭深度体验——徒步、铁锹烤肉、原始鄂温克部落。"
},
{
"version": "V2南线",
"date": "2024.11",
"title": "新增森林牧场UTV穿越体验",
"changes": [
{
"text": "新增森林牧场UTV卡丁车穿越,在林海雪原中自由驰骋",
"type": "add"
},
{
"text": "取消满洲里行程,优化时间分配",
"type": "remove"
}
],
"reason": "距离阿尔山仅3公里的森林牧场,被冰雪覆盖宛如童话中的银色世界。驾驶雪地全地形越野车穿梭于林海雪原之间,取代满洲里的单调路程。"
},
{
"version": "V1北线",
"date": "2023.11",
"title": "嗨冰雪首发·北线呼伦贝尔+满洲里+大兴安岭",
"changes": [
{
"text": "冰雪那达慕·莫日格勒河畔蒙古族传统活动",
"type": "add"
},
{
"text": "雪原骑马/骑骆驼,驰骋在被雪覆盖的原野上",
"type": "add"
},
{
"text": "驯鹿拉爬犁,属于鄂温克人的浪漫",
"type": "add"
},
{
"text": "冷极村森林民俗体验馆+冰雪乐园",
"type": "add"
},
{
"text": "敖鲁古雅驯鹿苑+博物馆,国内独一的驯鹿主题博物馆",
"type": "add"
},
{
"text": "呼伦湖成吉思汗拴马桩,中国最大一块冰",
"type": "add"
}
],
"reason": "呼籁深耕呼伦贝尔多年后首次推出冬季产品线。北线串联草原雪原、满洲里边境、大兴安岭森林三大核心场景,让冬天的呼伦贝尔不再只是一个冷的概念。"
},
{
"version": "V1南线",
"date": "2023.11",
"title": "嗨冰雪首发·南线呼伦贝尔+阿尔山",
"changes": [
{
"text": "冰雪那达慕·莫日格勒河畔体验冬日草原活力",
"type": "add"
},
{
"text": "雪原骑马/骑骆驼,在大雪原中策马奔腾",
"type": "add"
},
{
"text": "森林牧场UTV全地形越野车穿越林海雪原",
"type": "add"
},
{
"text": "阿尔山雪村,逃离喧嚣的冬日胜地",
"type": "add"
},
{
"text": "不冻河漂流,零下30℃的河面云蒸霞蔚",
"type": "add"
},
{
"text": "白狼峰日出+泼水成冰,山顶看群山云雾",
"type": "add"
},
{
"text": "百里雾凇画廊,仿佛踏入童话世界的雪挂林",
"type": "add"
}
],
"reason": "南线以阿尔山为核心,串联草原雪原与大兴安岭腹地的童话小城。阿尔山不是山,风景却美过任何一座山,被称为「东方瑞士」,冬季更是一个让时间慢下来的地方。"
}
],
"selectionGuide": {
"byVacationLength": [
{
"condition": "5天假期",
"recommendation": "winter-south-5d4n",
"reason": "精华浓缩,核心体验一个不少"
},
{
"condition": "6天假期",
"recommendation": "winter-south-6d5n",
"reason": "阿尔山住两晚,节奏更从容"
},
{
"condition": "7天以上",
"recommendation": "winter-north-7d6n",
"reason": "深度探索,大兴安岭+边境全覆盖"
}
],
"byPreference": [
{
"reason": "白狼峰日出+不冻河+童话小城",
"condition": "想看阿尔山",
"recommendation": "winter-south-6d5n",
"reason": "白狼峰日出+不冻河+童话小城"
"recommendation": "winter-south-6d5n"
},
{
"reason": "满洲里+呼伦湖蓝冰+驯鹿部落",
"condition": "想去边境",
"recommendation": "winter-north-7d6n",
"reason": "满洲里+呼伦湖蓝冰+驯鹿部落"
"recommendation": "winter-north-7d6n"
},
{
"reason": "5天精华浓缩,核心不缺",
"condition": "假期有限",
"recommendation": "winter-south-5d4n",
"reason": "5天精华浓缩,核心不缺"
"recommendation": "winter-south-5d4n"
}
],
"byVacationLength": [
{
"reason": "精华浓缩,核心体验一个不少",
"condition": "5天假期",
"recommendation": "winter-south-5d4n"
},
{
"reason": "阿尔山住两晚,节奏更从容",
"condition": "6天假期",
"recommendation": "winter-south-6d5n"
},
{
"reason": "深度探索,大兴安岭+边境全覆盖",
"condition": "7天以上",
"recommendation": "winter-north-7d6n"
}
]
}
}
}

查看文件

@ -1,446 +0,0 @@
{
"title": "小红书上的呼籁",
"subtitle": "真实客户的旅行笔记,点击查看原文",
"account": {
"name": "Mr.小雷-呼籁旅行",
"url": "https://www.xiaohongshu.com/user/profile/5c5073406b58b77dcc76b492",
"followers": "9.6万+",
"likes": "26万+"
},
"notes": [
{
"id": "68e4cd12000000000401538b",
"title": "呼籁给了美好的呼伦贝尔南线之旅!",
"cover": "/uploads/covers/xhs-68e4cd12000000000401538b.webp",
"author": "我是一个荷包蛋",
"likes": 4,
"url": "https://www.xiaohongshu.com/explore/68e4cd12000000000401538b",
"tags": [
"呼伦贝尔",
"南线"
],
"ratio": "vertical",
"summary": "选了呼籁的南线行程,师傅特别热情,一路讲解各种草原文化。海拉尔站接我们就感受到了内蒙人的热情,孩子特别开心,还体验了蒙古包住宿,晚上看星星太美了。整个行程安排得很紧凑但不赶,景点都很值得去,强烈推荐呼籁!"
},
{
"id": "697212bd000000000e03da86",
"title": "我在呼伦贝尔拍到了极光",
"cover": "/uploads/covers/xhs-697212bd000000000e03da86.webp",
"author": "Mario",
"likes": 228,
"url": "https://www.xiaohongshu.com/explore/697212bd000000000e03da86",
"tags": [
"极光",
"呼伦贝尔"
],
"ratio": "vertical",
"summary": "没想到在呼伦贝尔居然拍到了极光!冬天来的呼籁冰雪线路,本来只是想看雪景,结果师傅说今晚天气好可能有极光,带我们到了一个没有光污染的地方等候。真的等到了!人生第一次看极光,在祖国的土地上,太感动了。呼籁的师傅太专业了,不只是开车,是真的懂这片土地。"
},
{
"id": "68443760000000002100e004",
"title": "幼儿园毕业游🌸呼伦贝尔大草原🌲",
"cover": "/uploads/covers/xhs-68443760000000002100e004.webp",
"author": "wendy51930",
"likes": 144,
"url": "https://www.xiaohongshu.com/explore/68443760000000002100e004",
"tags": [
"亲子游",
"毕业游"
],
"ratio": "horizontal",
"summary": "幼儿园毕业送给孩子一个大草原之旅!选择了呼籁的亲子线路,一家一车很自由。孩子骑了小马、挤了牛奶、学了射箭,每天都不想回酒店。领队还给孩子们准备了草原寻宝游戏,太贴心了。住的蒙古包也超级干净,推荐给有娃家庭!"
},
{
"id": "686289e00000000013012fb0",
"title": "一家三口亲子游|呼伦贝尔大草原第二天",
"cover": "/uploads/covers/xhs-686289e00000000013012fb0.webp",
"author": "玄猫猫",
"likes": 42,
"url": "https://www.xiaohongshu.com/explore/686289e00000000013012fb0",
"tags": [
"亲子游",
"草原"
],
"ratio": "vertical",
"summary": "第二天的行程从额尔古纳出发,穿过白桦林到了莫尔道嘎。一路上风景美炸了,师傅会在好看的地方停下来让我们拍照。孩子在草地上撒欢跑,追蝴蝶、摘野花,城市里根本没有这样的体验。呼籁的安排真的很用心,午餐还带我们去了当地牧民家吃手把肉。"
},
{
"id": "687284f00000000010026e19",
"title": "呼籁的旅拍不错呦",
"cover": "/uploads/covers/xhs-687284f00000000010026e19.webp",
"author": "Vivianus爱Matcha是抹茶🔥",
"likes": 5,
"url": "https://www.xiaohongshu.com/explore/687284f00000000010026e19",
"tags": [
"旅拍",
"呼伦贝尔"
],
"ratio": "vertical",
"summary": "呼籁安排的旅拍摄影师太会拍了!选了几个小众取景点,避开了人群,拍出来的照片像大片一样。草原上穿蒙古袍的照片直接拿来当头像了。而且不赶时间,慢慢拍,很舒服。价格也比外面单独约摄影师便宜,推荐!"
},
{
"id": "686b2dd800000000150238f8",
"title": "呼伦贝尔~完美收官啦",
"cover": "/uploads/covers/xhs-686b2dd800000000150238f8.webp",
"author": "三人四季行",
"likes": 12,
"url": "https://www.xiaohongshu.com/explore/686b2dd800000000150238f8",
"tags": [
"收官",
"亲子"
],
"ratio": "horizontal",
"summary": "五天四晚的呼伦贝尔之旅完美收官!从海拉尔出发,经过莫日格勒河、额尔古纳湿地、黑山头、满洲里,最后回到海拉尔。全程呼籁安排的师傅服务超好,车子很干净,每天还给孩子准备零食和水。这是我们一家三口最开心的一次旅行!"
},
{
"id": "68987620000000002302987f",
"title": "开启呼伦贝尔草原之旅#呼籁旅行#",
"cover": "/uploads/covers/xhs-68987620000000002302987f.webp",
"author": "Mo都时髦Mo",
"likes": 8,
"url": "https://www.xiaohongshu.com/explore/68987620000000002302987f",
"tags": [
"草原",
"旅行"
],
"ratio": "vertical",
"summary": "期待已久的草原之旅终于开启!第一天从海拉尔出发,看到莫日格勒河的那一刻,被震撼到了。天下第一曲水名不虚传!呼籁的定制师提前帮我们规划好了每天的行程,还根据天气调整了顺序,非常灵活。期待接下来几天的精彩!"
},
{
"id": "68a9a205000000001d00b03f",
"title": "6月底的呼伦贝尔包车未被黑",
"cover": "/uploads/covers/xhs-68a9a205000000001d00b03f.webp",
"author": "婷",
"likes": 22,
"url": "https://www.xiaohongshu.com/explore/68a9a205000000001d00b03f",
"tags": [
"包车",
"避坑"
],
"ratio": "horizontal",
"summary": "做了很多功课才选定的呼籁,事实证明选对了6月底旺季出行,价格透明没有隐形消费,师傅全程没有带去任何购物点。吃住都是提前确认好的,价格合理品质也好。最重要的是师傅人特别好,不会催赶行程,随时可以停车拍照。呼伦贝尔包车选呼籁不会踩坑"
},
{
"id": "68669f3f000000002201ee0f",
"title": "呼伦贝尔亲子游",
"cover": "/uploads/covers/xhs-68669f3f000000002201ee0f.webp",
"author": "暴躁妈带俩娃",
"likes": 28,
"url": "https://www.xiaohongshu.com/explore/68669f3f000000002201ee0f",
"tags": [
"亲子游",
"呼伦贝尔"
],
"ratio": "vertical",
"summary": "带俩娃出门最怕的就是行程太赶,但呼籁安排得很合理!每天上午出发,中午有充足的午休时间,下午玩到五六点就回酒店了。两个孩子全程没哭闹过,说明行程节奏把控得好。师傅还特别有耐心,会等孩子们慢慢玩够了再出发。"
},
{
"id": "688644e600000000130134b4",
"title": "呼伦贝尔我到底该选谁🤨",
"cover": "/uploads/covers/xhs-688644e600000000130134b4.webp",
"author": "扣子挺好的",
"likes": 10,
"url": "https://www.xiaohongshu.com/explore/688644e600000000130134b4",
"tags": [
"攻略",
"选择"
],
"ratio": "vertical",
"summary": "对比了好几家呼伦贝尔的旅行社,最后选了呼籁。原因很简单:一是客服回复很专业,不是模板回复而是真的在了解我的需求;二是价格透明,把每一项都列清楚了;三是看了很多客户的真实反馈都很好。事实证明没选错,服务确实超出预期!"
},
{
"id": "686beceb000000001703267f",
"title": "呼伦贝尔游记D1",
"cover": "/uploads/covers/xhs-686beceb000000001703267f.webp",
"author": "桐桐",
"likes": 5,
"url": "https://www.xiaohongshu.com/explore/686beceb000000001703267f",
"tags": [
"游记",
"Day1"
],
"ratio": "horizontal",
"summary": "呼伦贝尔之旅第一天!海拉尔机场接上后直奔莫日格勒河。一路上师傅给我们科普了很多当地的风土人情,原来草原上的路也有这么多讲究。莫日格勒河的落日太美了,师傅特意等到日落才带我们走,这种服务态度真的绝了。"
},
{
"id": "69bfc4d0000000002301c126",
"title": "📸26暑假呼伦贝尔亲子游 | 超强攻略‼️",
"cover": "/uploads/covers/xhs-69bfc4d0000000002301c126.webp",
"author": "Mr.小雷-呼籁旅行",
"likes": 8,
"url": "https://www.xiaohongshu.com/explore/69bfc4d0000000002301c126",
"tags": [
"暑假",
"攻略"
],
"ratio": "vertical",
"summary": "2026年暑假呼伦贝尔亲子游超全攻略来了包含最佳出行时间、行程推荐、必玩体验、穿搭建议和避坑指南。7-8月是草原最美的季节,建议提前1-2个月预订。亲子游推荐5-6天的行程,不赶路不疲惫,孩子和大人都能玩得尽兴。"
},
{
"id": "68a2f57d000000001c03e65f",
"title": "呼伦贝尔亲子游",
"cover": "/uploads/covers/xhs-68a2f57d000000001c03e65f.webp",
"author": "野象小姐YY",
"likes": 3,
"url": "https://www.xiaohongshu.com/explore/68a2f57d000000001c03e65f",
"tags": [
"亲子游",
"草原"
],
"ratio": "horizontal",
"summary": "带3岁宝宝去草原,之前还担心孩子太小不适合。结果呼籁安排的行程完全考虑到了小朋友的需求车上有儿童座椅,行程节奏慢,中午有午休,酒店选的都是有暖气有热水的。宝宝每天都很开心,回来后天天说想去草原找小马。"
},
{
"id": "68c51cc7000000001d007912",
"title": "完美的内蒙之旅",
"cover": "/uploads/covers/xhs-68c51cc7000000001d007912.webp",
"author": "萌萌你快来",
"likes": 1,
"url": "https://www.xiaohongshu.com/explore/68c51cc7000000001d007912",
"tags": [
"内蒙",
"旅行"
],
"ratio": "vertical",
"summary": "给这次内蒙之旅打满分!呼籁从前期的行程规划到全程的服务都让人很安心。特别是师傅,不仅开车稳,还会给我们讲每个地方的故事。最感动的是最后一天下雨了,师傅主动调整了行程,带我们去了一个室内的民俗体验馆,一点都没浪费时间。"
},
{
"id": "6885e207000000001d00e82b",
"title": "呼伦贝尔第四天",
"cover": "/uploads/covers/xhs-6885e207000000001d00e82b.webp",
"author": "shireyna",
"likes": 1,
"url": "https://www.xiaohongshu.com/explore/6885e207000000001d00e82b",
"tags": [
"呼伦贝尔",
"Day4"
],
"ratio": "vertical",
"summary": "第四天从满洲里出发去呼伦湖,路上经过了一大片油菜花田,太惊喜了!师傅看我们兴奋就停下来让我们拍了好久。呼伦湖很壮观,虽然不如想象中蓝,但是那种广阔的感觉真的震撼。晚上回到海拉尔,结束了完美的旅程。感谢呼籁!"
},
{
"id": "686b301e0000000017035ff0",
"title": "呼伦贝尔之~旅拍",
"cover": "/uploads/covers/xhs-686b301e0000000017035ff0.webp",
"author": "三人四季行",
"likes": 2,
"url": "https://www.xiaohongshu.com/explore/686b301e0000000017035ff0",
"tags": [
"旅拍",
"草原"
],
"ratio": "horizontal",
"summary": "这次在呼伦贝尔拍了一组全家福,效果超出预期摄影师是呼籁推荐的,很有经验,知道哪个角度光线最好。拍了草原、白桦林、蒙古包三个场景,每个场景都换了服装。最终成片100多张,张张精修,性价比超高。"
},
{
"id": "68a6ee26000000001d0387b0",
"title": "还没离开呼伦贝尔,就开始有点想念了~",
"cover": "/uploads/covers/xhs-68a6ee26000000001d0387b0.webp",
"author": "黎霜霜",
"likes": 1,
"url": "https://www.xiaohongshu.com/explore/68a6ee26000000001d0387b0",
"tags": [
"想念",
"呼伦贝尔"
],
"ratio": "vertical",
"summary": "坐在回程的飞机上写这篇笔记,真的好舍不得。这几天在呼伦贝尔过的太快乐了,每天醒来都是蓝天白云绿草地,呼吸的都是新鲜空气。呼籁的师傅成了我们的朋友,约好了明年冬天再来一次看雪。呼伦贝尔,我一定会回来的!"
},
{
"id": "68d5a3f1000000001e024b90",
"title": "呼伦贝尔亲子游Day3额尔古纳湿地美翻了",
"cover": "/uploads/covers/xhs-68d5a3f1000000001e024b90.webp",
"author": "小鱼妈妈育儿记",
"likes": 35,
"url": "https://www.xiaohongshu.com/explore/68d5a3f1000000001e024b90",
"tags": [
"亲子游",
"额尔古纳"
],
"ratio": "vertical",
"summary": "今天的重头戏是额尔古纳湿地!登上山顶俯瞰整个湿地,根河像一条银色的丝带蜿蜒而过,美到窒息。呼籁的师傅带我们走了一条人少的栈道,避开了旅行团的人群。孩子在木栈道上蹦蹦跳跳,还发现了好几种小鸟。这种深度体验是跟团游完全体会不到的。"
},
{
"id": "68f2b7e50000000023018c41",
"title": "带父母去呼伦贝尔|老人家也能轻松玩",
"cover": "/uploads/covers/xhs-68f2b7e50000000023018c41.webp",
"author": "阿橙的旅行日记",
"likes": 18,
"url": "https://www.xiaohongshu.com/explore/68f2b7e50000000023018c41",
"tags": [
"孝亲游",
"呼伦贝尔"
],
"ratio": "vertical",
"summary": "这次带爸妈来呼伦贝尔,选呼籁就是看中他们的一家一车模式。老人家腿脚不方便,跟团根本不现实。呼籁的师傅全程照顾,上下车都会搀扶,景点走累了就在车上休息。行程也帮我们调整成了轻松版,每天不超过4小时车程。爸妈玩得特别开心,说这是他们最舒服的一次旅行。"
},
{
"id": "690a4c220000000010034d78",
"title": "黑山头骑马太爽了!!!",
"cover": "/uploads/covers/xhs-690a4c220000000010034d78.webp",
"author": "想吃火锅的猫",
"likes": 67,
"url": "https://www.xiaohongshu.com/explore/690a4c220000000010034d78",
"tags": [
"骑马",
"黑山头"
],
"ratio": "horizontal",
"summary": "到了呼伦贝尔一定要骑马!呼籁推荐的黑山头骑马场特别正规,有专业马倌一对一带领,完全不用担心安全问题。骑着马穿越草原的感觉太爽了,风吹过来,远处是连绵的山丘,真的有种策马奔腾的畅快感。而且不是那种牵着绳子走的旅游马,是真正的草原骑行!"
},
{
"id": "691bc83a0000000017023ef5",
"title": "闺蜜草原之旅|我们四个人承包了一片草原",
"cover": "/uploads/covers/xhs-691bc83a0000000017023ef5.webp",
"author": "糖果味的风",
"likes": 31,
"url": "https://www.xiaohongshu.com/explore/691bc83a0000000017023ef5",
"tags": [
"闺蜜游",
"草原"
],
"ratio": "vertical",
"summary": "四个闺蜜的呼伦贝尔之旅!选了呼籁的私人定制,师傅太了解女孩子了,每到一个好看的地方就主动停车让我们拍照。还帮我们找到了一个特别美的花海,在那里拍了一下午。晚上在蒙古包附近放烟花,太浪漫了。这趟旅行的照片够我发一年朋友圈了。"
},
{
"id": "692d3f5b000000001303ab92",
"title": "呼伦贝尔的星空太震撼了",
"cover": "/uploads/covers/xhs-692d3f5b000000001303ab92.webp",
"author": "追光的人",
"likes": 45,
"url": "https://www.xiaohongshu.com/explore/692d3f5b000000001303ab92",
"tags": [
"星空",
"草原"
],
"ratio": "vertical",
"summary": "在城市里从没见过这样的星空!住在呼籁安排的黑山头营地,晚上走出蒙古包,抬头就是满天繁星,银河清晰可见。师傅还教我们用手机拍星空,调参数、找角度,拍出来的效果比想象的好太多了。这种体验,花多少钱都值。"
},
{
"id": "693e8a7c000000002101c6d3",
"title": "满洲里的夜景绝了!!",
"cover": "/uploads/covers/xhs-693e8a7c000000002101c6d3.webp",
"author": "甜甜圈爱旅行",
"likes": 19,
"url": "https://www.xiaohongshu.com/explore/693e8a7c000000002101c6d3",
"tags": [
"满洲里",
"夜景"
],
"ratio": "horizontal",
"summary": "满洲里的夜景真的绝了!到处是俄罗斯风情的建筑,灯光一亮简直像到了异国。呼籁的师傅带我们去了一个当地人才知道的观景台,整个城市尽收眼底。还去了套娃广场,虽然有点商业化,但拍照还是很出片的。晚上在中苏街溜达,吃了正宗的俄式西餐,体验感拉满!"
},
{
"id": "694fb1990000000013027891",
"title": "呼伦贝尔7月草原绿得像画一样",
"cover": "/uploads/covers/xhs-694fb1990000000013027891.webp",
"author": "小太阳爱生活",
"likes": 56,
"url": "https://www.xiaohongshu.com/explore/694fb1990000000013027891",
"tags": [
"草原",
"风景"
],
"ratio": "vertical",
"summary": "7月的呼伦贝尔草原绿得不真实,像是Windows桌面壁纸呼籁的师傅说这是一年中草原最美的时候,野花遍地,牛羊成群。我们在一个没有游客的山坡上野餐,师傅还帮我们铺了野餐垫,拿出准备好的奶茶和奶片。这种贴心的小细节太加分了。"
},
{
"id": "6960c2aa0000000021023f56",
"title": "冬天的呼伦贝尔也太美了吧",
"cover": "/uploads/covers/xhs-6960c2aa0000000021023f56.webp",
"author": "雪地里的小狐狸",
"likes": 82,
"url": "https://www.xiaohongshu.com/explore/6960c2aa0000000021023f56",
"tags": [
"冬季",
"雪景"
],
"ratio": "vertical",
"summary": "第一次冬天来呼伦贝尔,零下30度但值了呼籁的冰雪线路真的太赞了坐雪橇、看雾凇、泼水成冰、雪地摩托……每一个都是人生初体验。师傅的车暖气开得足足的,一上车就暖和。呼籁还给我们准备了暖宝宝和防滑鞋套,细节到位。"
},
{
"id": "69723f88000000001703a4c7",
"title": "带2岁宝宝去草原的注意事项",
"cover": "/uploads/covers/xhs-69723f88000000001703a4c7.webp",
"author": "元气小妈咪",
"likes": 73,
"url": "https://www.xiaohongshu.com/explore/69723f88000000001703a4c7",
"tags": [
"亲子游",
"攻略"
],
"ratio": "horizontal",
"summary": "带2岁宝宝去呼伦贝尔完全可行关键是选对旅行方式。我们选了呼籁的亲子定制,车上有宝宝安全座椅,行程每天不超过3小时车程,午睡时间都留出来了。呼籁还帮我们准备了便携马桶和湿巾。宝宝在草原上追小羊的画面,治愈了我整个夏天。"
},
{
"id": "6983a4f5000000002302c8e0",
"title": "莫日格勒河的日落太绝了",
"cover": "/uploads/covers/xhs-6983a4f5000000002302c8e0.webp",
"author": "光影猎人阿杰",
"likes": 39,
"url": "https://www.xiaohongshu.com/explore/6983a4f5000000002302c8e0",
"tags": [
"莫日格勒河",
"日落"
],
"ratio": "vertical",
"summary": "莫日格勒河的日落,是我这辈子见过最美的日落之一。呼籁的师傅特意带我们到了一个私藏的观景点,避开了所有旅行团。金色的阳光洒在弯曲的河面上,牛羊在河边喝水,背景是无边的草原……按下快门的那一刻我就知道,这张照片会成为我的年度最佳。"
},
{
"id": "6994b6120000000010023d9c",
"title": "呼籁的师傅真的太好了!",
"cover": "/uploads/covers/xhs-6994b6120000000010023d9c.webp",
"author": "佩佩在路上",
"likes": 15,
"url": "https://www.xiaohongshu.com/explore/6994b6120000000010023d9c",
"tags": [
"服务",
"呼伦贝尔"
],
"ratio": "horizontal",
"summary": "必须要夸一下呼籁的师傅!全程像家人一样照顾我们,车上常备矿泉水、零食和防蚊液。有一天我把手机忘在了景区,师傅二话不说开车帮我回去找,太感动了。最后一天还特意买了当地的特产送给我们当纪念。这种真诚的服务,下次来呼伦贝尔一定还选呼籁。"
},
{
"id": "69a5c7350000000021028a15",
"title": "白桦林里的秋色呼伦贝尔9月限定",
"cover": "/uploads/covers/xhs-69a5c7350000000021028a15.webp",
"author": "秋天的童话",
"likes": 91,
"url": "https://www.xiaohongshu.com/explore/69a5c7350000000021028a15",
"tags": [
"秋季",
"白桦林"
],
"ratio": "vertical",
"summary": "9月的呼伦贝尔白桦林美得不像话金黄的树叶在阳光下闪闪发光,走在林间小路上像走进了油画。呼籁的师傅带我们去了一片游客很少的白桦林,安静得只听到树叶沙沙响。秋天来呼伦贝尔的人不多,但风景一点不输夏天,强烈推荐9月来"
},
{
"id": "69b6d8480000000013038b62",
"title": "呼伦贝尔五天四晚花费明细",
"cover": "/uploads/covers/xhs-69b6d8480000000013038b62.webp",
"author": "理财小达人",
"likes": 126,
"url": "https://www.xiaohongshu.com/explore/69b6d8480000000013038b62",
"tags": [
"费用",
"攻略"
],
"ratio": "horizontal",
"summary": "很多人问呼伦贝尔旅行到底花多少钱,来一份详细的费用明细选的是呼籁5天4晚的亲子线路,包含用车、住宿、部分餐饮和体验项目。价格在同类产品中属于中等偏上,但服务品质确实对得起价格。全程没有任何隐形消费,不推销、不购物,花的每一分钱都值。"
},
{
"id": "69c7e95b000000001e02b4d7",
"title": "额尔古纳的俄罗斯族老奶奶教我做列巴",
"cover": "/uploads/covers/xhs-69c7e95b000000001e02b4d7.webp",
"author": "面包爱好者",
"likes": 24,
"url": "https://www.xiaohongshu.com/explore/69c7e95b000000001e02b4d7",
"tags": [
"文化体验",
"额尔古纳"
],
"ratio": "vertical",
"summary": "在额尔古纳恩和镇,呼籁带我们去了一户俄罗斯族老奶奶家,学做传统列巴。老奶奶特别热情,手把手教我们揉面、发酵、烤制,还请我们喝了自制的蓝莓酱配列巴。孩子们玩得特别开心,这种深度文化体验比看景点有意义多了。呼籁的行程设计真的很走心。"
}
]
}

查看文件

@ -1,127 +0,0 @@
{
"title": "客户游记",
"subtitle": "来自各平台的真实旅行故事",
"notes": [
{
"id": "meipian-001",
"title": "呼伦贝尔|带着三个娃的草原奇妙之旅",
"cover": "/uploads/covers/youji-meipian-001.webp",
"author": "郑佩佩",
"platform": "美篇",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"亲子游",
"呼伦贝尔",
"草原",
"家庭旅行"
],
"ratio": "horizontal",
"summary": "一家人带着三个孩子踏上呼伦贝尔之旅,选择了呼籁旅行的定制行程。从海拉尔出发,先参观了呼伦贝尔博物馆看猛犸象化石,孩子们大开眼界。草原上穿蒙古袍拍了专业旅拍,骑马穿越大草原,孩子们兴奋得不得了。在恩和镇的俄罗斯族面包房学做列巴,和驯鹿亲密接触。还体验了草原极速滑草、ATV越野,满洲里的俄罗斯风情街夜景美到窒息。全程师傅服务细致周到,行程紧凑又不疲惫,是一家人最难忘的旅行。"
},
{
"id": "meipian-002",
"title": "退休夫妇的呼伦贝尔圆梦之旅",
"cover": "/uploads/covers/youji-meipian-002.webp",
"author": "王阿姨的慢生活",
"platform": "美篇",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"银发游",
"呼伦贝尔",
"慢旅行"
],
"ratio": "vertical",
"summary": "退休后一直想去看看大草原,在女儿推荐下选了呼籁旅行。师傅知道我们年纪大了,全程慢节奏,每个景点都等我们慢慢看慢慢拍。额尔古纳湿地的落日太美了,老伴拍了一百多张照片。住的酒店干净暖和,吃的都是地道蒙餐,手把肉和奶茶特别正宗。这辈子终于圆了草原梦,感谢呼籁让我们的旅途如此舒心。"
},
{
"id": "wechat-001",
"title": "呼伦贝尔6天5晚亲子游全纪录",
"cover": "/uploads/covers/youji-wechat-001.webp",
"author": "小鱼妈妈育儿志",
"platform": "微信公众号",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"亲子游",
"攻略",
"呼伦贝尔"
],
"ratio": "vertical",
"summary": "写了一万字的呼伦贝尔亲子游记6天5晚走了海拉尔-莫日格勒河-额尔古纳-黑山头-满洲里的经典环线。选呼籁是因为闺蜜推荐,一家一车真的太适合带娃家庭了。白桦林里给孩子做了自然教育,黑山头的骑马体验让5岁的儿子至今念念不忘。全程住宿都经过精选,卫生条件完全放心。最惊喜的是师傅自带无人机帮我们航拍了全家福,太专业了"
},
{
"id": "douyin-001",
"title": "呼伦贝尔vlog草原上的自由时光",
"cover": "/uploads/covers/youji-douyin-001.webp",
"author": "旅行的小确幸",
"platform": "抖音",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"草原",
"vlog",
"自驾"
],
"ratio": "horizontal",
"summary": "用镜头记录了在呼伦贝尔7天的自由时光。从第一天看到莫日格勒河的震撼,到最后一天在海拉尔依依不舍地告别师傅,每一天都值得记录。草原上骑马奔驰的画面、星空下的篝火晚会、和牧民一起赶羊群……这些画面组成了我今年最珍贵的vlog。呼籁的安排让整个旅程毫无压力,师傅还帮我找了很多好看的取景点,简直是兼职摄影助理。"
},
{
"id": "meipian-003",
"title": "我们的草原毕业旅行|青春不散场",
"cover": "/uploads/covers/youji-meipian-003.webp",
"author": "四个女孩的旅行",
"platform": "美篇",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"毕业旅行",
"闺蜜游",
"草原"
],
"ratio": "vertical",
"summary": "大学毕业旅行选了呼伦贝尔大草原!四个女生第一次来北方,被草原的辽阔震撼到了。呼籁给我们安排了一位超会拍照的女司机,沿途帮我们拍了无数美照。在黑山头的日落骑马、恩和的木屋民宿、满洲里的异国风情……每一站都是惊喜。最感动的是最后一天师傅送我们去机场,车上放着我们一路旅行的照片合集视频,四个人都哭了。青春最好的模样,就是和好朋友一起看世界。"
},
{
"id": "weibo-001",
"title": "冬日呼伦贝尔零下30度的浪漫",
"cover": "/uploads/covers/youji-weibo-001.webp",
"author": "北方有佳人Lynn",
"platform": "微博",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"冬季",
"雪景",
"冰雪体验"
],
"ratio": "vertical",
"summary": "零下30度的呼伦贝尔,是另一种极致的美。这次走的是呼籁的冬季冰雪线路坐马拉雪橇穿越雪原、在不冻河边看雾凇、泼水成冰的瞬间让人尖叫、雪地里打滚撒欢……师傅的越野车暖气开到最足,一上车就暖和起来。呼籁还贴心准备了暖宝宝、防滑鞋套和保温杯。在冷极村的那晚,屋外零下40度,屋内暖炕热乎乎,窗外是漫天飞雪。冬天的呼伦贝尔,值得你来一次。"
},
{
"id": "wechat-002",
"title": "呼伦贝尔秋色|九月的白桦林和金色草原",
"cover": "/uploads/covers/youji-wechat-002.webp",
"author": "摄影师老张",
"platform": "微信公众号",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"秋季",
"白桦林",
"摄影"
],
"ratio": "horizontal",
"summary": "作为一名风光摄影师,我去过很多地方拍秋色,但呼伦贝尔的秋天是最让我惊艳的。九月中旬来的,白桦林金黄一片,草原渐渐变成金色,牛羊在夕阳下悠闲吃草。呼籁的师傅对本地非常熟悉,带我去了好几个普通游客根本找不到的拍摄点。日出时的额尔古纳湿地、逆光下的白桦林、满归的落叶松林……每一帧都是壁纸级别。强烈推荐9月来呼伦贝尔,人少景美,是摄影人的天堂。"
},
{
"id": "meipian-004",
"title": "带着90岁奶奶去看草原",
"cover": "/uploads/covers/youji-meipian-004.webp",
"author": "孙女小敏",
"platform": "美篇",
"url": "https://www.meipian.cn/5h3tmj2q",
"tags": [
"孝亲游",
"感动",
"草原"
],
"ratio": "vertical",
"summary": "奶奶今年90岁了,一辈子生活在南方小城,最大的心愿就是看看北方的大草原。今年终于鼓起勇气带她出发了。选呼籁是因为他们可以完全定制行程,根据奶奶的身体状况调整节奏。师傅特别耐心,每次停车都先下来帮奶奶开门搀扶。在草原上,奶奶激动得眼眶湿润,说这辈子值了。师傅还特意找了一个平坦的草地,铺好垫子让奶奶坐着看远方。这是我做过最正确的决定,感谢呼籁让奶奶圆了草原梦。"
}
]
}

1
dist 符号链接
查看文件

@ -0,0 +1 @@
/Users/mg/workSpace/呼籁文旅/hulai-website/.output/public

查看文件

@ -1,296 +0,0 @@
<template>
<client-only>
<n-config-provider :theme-overrides="themeOverrides">
<n-message-provider>
<n-dialog-provider>
<div class="admin-layout">
<aside class="admin-sidebar">
<div class="admin-logo">
<div class="logo-icon">H</div>
<div class="logo-text">
<h2>呼籁后台</h2>
<span>hulai.com</span>
</div>
</div>
<div class="menu-wrap">
<n-menu
:value="activeKey"
:options="menuOptions"
:expanded-keys="expandedKeys"
:indent="16"
inverted
@update:value="handleMenuSelect"
@update:expanded-keys="handleExpand"
/>
</div>
<div class="admin-user">
<div class="user-info">
<n-avatar :size="28" round style="background: #3a7d44; font-size: 12px;">A</n-avatar>
<span>管理员</span>
</div>
<n-button size="tiny" quaternary @click="logout" style="color: rgba(255,255,255,0.55);">
退出
</n-button>
</div>
</aside>
<main class="admin-main">
<slot />
</main>
</div>
</n-dialog-provider>
</n-message-provider>
</n-config-provider>
</client-only>
</template>
<script setup>
import { h } from 'vue'
import {
NConfigProvider, NMessageProvider, NDialogProvider,
NMenu, NAvatar, NButton, NBadge,
} from 'naive-ui'
const route = useRoute()
const { logout, adminFetch } = useAdmin()
const unreadCount = ref(0)
onMounted(async () => {
try {
const data = await adminFetch('/api/admin/submissions/unread')
unreadCount.value = data.count
} catch {}
})
// Naive UI
const themeOverrides = {
common: {
primaryColor: '#3a7d44',
primaryColorHover: '#2d6235',
primaryColorPressed: '#245c2b',
primaryColorSuppl: '#3a7d44',
},
}
//
function menuLabel(text) {
return () => text
}
function submissionLabel() {
return () => h('span', { style: 'display:flex;align-items:center;justify-content:space-between;width:100%' }, [
'表单提交',
unreadCount.value > 0
? h(NBadge, { value: unreadCount.value, max: 99, type: 'error' })
: null,
])
}
const menuOptions = computed(() => {
return [
{ label: menuLabel('数据概览'), key: '/admin' },
{ label: menuLabel('产品线管理'), key: '/admin/products' },
{ label: menuLabel('产品选择器'), key: '/admin/content/selector' },
{
label: menuLabel('目的地'), key: 'g-destinations',
children: [
{ label: menuLabel('景点对比'), key: '/admin/content/destinations' },
{ label: menuLabel('景点详情'), key: '/admin/content/destinations-detail' },
{ label: menuLabel('旅行日历'), key: '/admin/content/calendar' },
{ label: menuLabel('出行指南'), key: '/admin/content/guides' },
],
},
{
label: menuLabel('客户口碑'), key: 'g-reviews',
children: [
{ label: menuLabel('客户评价'), key: '/admin/reviews' },
{ label: menuLabel('小红书游记'), key: '/admin/content/xiaohongshu-wall' },
{ label: menuLabel('客户游记'), key: '/admin/content/youji' },
{ label: menuLabel('呼籁旅拍'), key: '/admin/gallery' },
{ label: menuLabel('客户故事'), key: '/admin/stories' },
],
},
{ label: menuLabel('常见问答'), key: '/admin/faqs' },
{
label: menuLabel('关于我们'), key: 'g-about',
children: [
{ label: menuLabel('关于呼籁'), key: '/admin/content/about' },
{ label: menuLabel('最新动态'), key: '/admin/articles' },
{ label: menuLabel('资质荣誉'), key: '/admin/content/qualifications' },
{ label: menuLabel('合作伙伴'), key: '/admin/content/partners' },
],
},
{ label: menuLabel('联系我们'), key: '/admin/content/contact' },
{ label: menuLabel('博客文章'), key: '/admin/blogs' },
{ label: submissionLabel(), key: '/admin/submissions' },
{ type: 'divider' },
{
label: menuLabel('系统设置'), key: 'g-settings',
children: [
{ label: menuLabel('导航菜单'), key: '/admin/navigation' },
{ label: menuLabel('SEO 配置'), key: '/admin/content/seo' },
{ label: menuLabel('品牌信息'), key: '/admin/content/brand' },
{ label: menuLabel('图片配置'), key: '/admin/content/images' },
{ label: menuLabel('版本历史'), key: '/admin/content/versions' },
{ label: menuLabel('定制页配置'), key: '/admin/content/customize' },
],
},
]})
// key
const activeKey = computed(() => {
const path = route.path
//
if (path === '/admin') return '/admin'
//
const allKeys = []
function collectKeys(items) {
for (const item of items) {
if (item.key && !item.key.startsWith('g-')) allKeys.push(item.key)
if (item.children) collectKeys(item.children)
}
}
collectKeys(menuOptions.value)
//
let best = ''
for (const k of allKeys) {
if (path.startsWith(k) && k.length > best.length) best = k
}
return best || path
})
//
const expandedKeys = ref([])
const groupMappings = {
'g-products': [],
'g-destinations': ['destinations', 'calendar', 'guides'],
'g-reviews': ['reviews', 'xiaohongshu', 'youji', 'gallery', 'stories'],
'g-about': ['about', 'articles', 'qualifications', 'partners'],
'g-settings': ['navigation', 'seo', 'brand', 'images', 'versions', 'customize'],
}
watchEffect(() => {
const path = route.path
const keys = new Set(expandedKeys.value)
for (const [group, keywords] of Object.entries(groupMappings)) {
if (keywords.some((kw) => path.includes(kw))) {
keys.add(group)
}
}
expandedKeys.value = [...keys]
})
function handleMenuSelect(key) {
if (!key.startsWith('g-')) {
navigateTo(key)
}
}
function handleExpand(keys) {
expandedKeys.value = keys
}
</script>
<style scoped>
.admin-layout {
display: flex;
min-height: 100vh;
background: #f0f2f5;
}
.admin-sidebar {
width: 240px;
background: #001529;
color: #fff;
display: flex;
flex-direction: column;
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 100;
overflow: hidden;
}
.admin-logo {
display: flex;
align-items: center;
gap: 12px;
padding: 20px 16px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.logo-icon {
width: 36px;
height: 36px;
background: #3a7d44;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 18px;
flex-shrink: 0;
}
.logo-text h2 {
margin: 0;
font-size: 16px;
font-weight: 600;
line-height: 1.2;
}
.logo-text span {
font-size: 11px;
color: rgba(255,255,255,0.35);
}
.menu-wrap {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
}
.menu-wrap::-webkit-scrollbar {
width: 4px;
}
.menu-wrap::-webkit-scrollbar-thumb {
background: rgba(255,255,255,0.15);
border-radius: 2px;
}
.admin-user {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-top: 1px solid rgba(255,255,255,0.06);
}
.user-info {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: rgba(255,255,255,0.65);
}
.admin-main {
flex: 1;
margin-left: 240px;
padding: 24px 28px;
min-height: 100vh;
}
</style>
<style>
/* NMenu inverted 在 #001529 背景下的微调 */
.admin-sidebar .n-menu.n-menu--vertical {
background: transparent;
}
</style>

查看文件

@ -1,16 +0,0 @@
export default defineNuxtRouteMiddleware((to) => {
if (import.meta.server) return
if (to.path === '/admin/login') return
// 先从 localStorage 恢复(确保 useState 也同步)
const stored = localStorage.getItem('admin_token')
if (!stored) {
return navigateTo('/admin/login')
}
// 同步到 useState,保证 composable 拿到值
const token = useState('admin_token')
if (!token.value) {
token.value = stored
}
})

查看文件

@ -7,15 +7,20 @@ export default defineNuxtConfig({
// 部署时使用 `nuxt build` + Node.js 服务器(如 PM2
// 若必须静态部署,需将表单改为第三方服务(飞书/EmailJS 等)。
prerender: {
failOnError: false,
crawlLinks: true,
routes: [
'/', '/about', '/products', '/summer-camp', '/winter-camp', '/courses', '/guides', '/guide-custom', '/faq', '/reviews', '/contact', '/customize', '/pricing', '/selector', '/sitemap.xml',
'/products/v9-5d4n-forest', '/products/v9-5d4n-prairie',
'/products/v9-6d5n-family', '/products/v9-6d5n-explore',
'/products/v9-7d6n-family', '/products/v9-7d6n-wild',
'/products/v9-4d3n', '/products/v9-5d4n', '/products/v9-6d5n-family',
'/products/v9-6d5n-comfort', '/products/v9-7d6n-family', '/products/v9-7d6n-wild',
'/products/autumn', '/products/winter',
'/gallery', '/news', '/calendar', '/stories', '/xiaohongshu', '/youji',
'/destinations',
'/destinations/moriguole', '/destinations/eergunashire', '/destinations/baihualin',
'/destinations/enhe-shiwei', '/destinations/heishantou', '/destinations/manzhouli',
'/destinations/hulunhu', '/destinations/aershan', '/destinations/shiwei',
'/destinations/daxinganling', '/destinations/aoluguya', '/destinations/genhe',
'/gallery',
'/news', '/calendar',
'/stories',
'/blog',
'/blog/hulunbuir-travel-guide-2026',
'/blog/hulunbuir-family-travel-guide',
@ -25,11 +30,6 @@ export default defineNuxtConfig({
'/blog/hulunbuir-travel-with-toddlers-4-6',
'/blog/hulunbuir-travel-tips-avoid-pitfalls',
'/blog/grassland-photography-outfit-guide',
'/destinations',
'/destinations/moriguole', '/destinations/eergunashire', '/destinations/baihualin',
'/destinations/enhe-shiwei', '/destinations/heishantou', '/destinations/manzhouli',
'/destinations/hulunhu', '/destinations/aershan',
'/destinations/daxinganling', '/destinations/aoluguya', '/destinations/genhe',
],
},
},
@ -65,20 +65,10 @@ export default defineNuxtConfig({
{ name: 'application-name', content: '呼籁旅行' },
{ name: 'theme-color', content: '#3a7d44' },
// 允许 AI 索引
{ key: 'robots', name: 'robots', content: 'index, follow, max-snippet:-1, max-image-preview:large' },
{ name: 'robots', content: 'index, follow, max-snippet:-1, max-image-preview:large' },
],
},
},
runtimeConfig: {
public: {
apiBase: process.env.API_BASE || 'http://localhost:8000',
},
},
build: {
transpile: ['naive-ui', 'vueuc', '@css-render/vue3-ssr', 'css-render'],
},
compatibilityDate: '2025-03-18',
})

查看文件

@ -5,29 +5,18 @@
"description": "呼籁旅行官网 - 呼伦贝尔家庭定制游",
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build && cp -f .env .output/.env 2>/dev/null || true",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"baidu-push": "node scripts/baidu-push.mjs"
"preview": "nuxt preview"
},
"dependencies": {
"@css-render/vue3-ssr": "^0.15.14",
"better-sqlite3": "^12.8.0",
"drizzle-orm": "^0.45.1",
"less": "^4.6.4",
"naive-ui": "^2.44.1",
"nodemailer": "^8.0.3",
"nuxt": "^3.17.5"
},
"pnpm": {
"onlyBuiltDependencies": [
"@parcel/watcher",
"better-sqlite3",
"esbuild"
]
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"drizzle-kit": "^0.31.10"
}
}

查看文件

@ -1,26 +1,43 @@
<template>
<div class="page-about">
<LayoutPageHero
:title="seo.h1 || '关于呼籁旅行'"
subtitle="一个深耕呼伦贝尔的旅行品牌"
:title="seo.h1"
subtitle="一个只做呼伦贝尔的旅行品牌"
:breadcrumbs="[{ text: '关于我们' }]"
background-image="/images/seasons/summer-hero.jpg"
/>
<!-- TL;DR -->
<!-- TL;DR告诉 AI/搜索引擎这个页面回答了什么 -->
<section class="page-tldr" aria-label="关于我们摘要">
<div class="container">
<div class="page-tldr-inner">
<p>呼籁旅行创立于2015年是内蒙古呼伦贝尔本地旅行品牌11年专注呼伦贝尔一个目的地旗下持有三重旅行社经营许可证购买1000万旅游责任险集团旗下涵盖旅行社旅游客运露营地牧场商贸研学教育等9家主体</p>
<p>呼籁旅行创立于2015年是内蒙古呼伦贝尔本地旅行品牌11年专注呼伦贝尔一个目的地旗下持有三重旅行社经营许可证购买1000万旅游责任险已服务超10000个家庭集团旗下涵盖旅行社牧场商贸研学教育等多家主体</p>
</div>
</div>
</section>
<!-- 1. 品牌故事为什么只做呼伦贝尔 -->
<AboutBrandStory v-if="about" :story="about.story" class="reveal" />
<!-- 品牌故事 -->
<AboutBrandStory :story="about.story" class="reveal" />
<!-- 2. 服务旅程跟呼籁出行是什么体验 -->
<section v-if="about" class="section section--gray reveal" aria-label="服务旅程">
<!-- 集团实力 -->
<AboutSubsidiaryGrid :subsidiaries="about.subsidiaries" class="reveal" />
<!-- 资质认证 & 服务保障 -->
<AboutQualificationList :certifications="about.certifications" :guarantees="about.guarantees" class="reveal" />
<!-- 小红书 -->
<AboutXiaohongshuShowcase :xhs="about.xiaohongshu" class="reveal" />
<!-- 知识产权 -->
<AboutCopyrightList :copyrights="about.copyrights" :trademark="about.trademark" class="reveal" />
<!-- 品牌IP -->
<AboutMascotShowcase class="reveal" />
<!-- 团队介绍 -->
<AboutTeamIntro :team="about.team" class="reveal" />
<!-- 8个温度时刻 -->
<section class="section section--gray reveal" aria-label="服务旅程">
<div class="container">
<CommonSectionTitle :title="about.serviceJourney.title" :subtitle="about.serviceJourney.subtitle" />
<ol class="journey-list">
@ -35,94 +52,28 @@
</div>
</section>
<!-- 3. 团队介绍谁在照顾你 -->
<AboutTeamIntro v-if="about" :team="about.team" class="reveal" />
<!-- 企业文化 -->
<AboutCultureValues :culture="about.culture" class="reveal" />
<!-- 4. 小红书 -->
<AboutXiaohongshuShowcase v-if="about" :xhs="about.xiaohongshu" class="reveal" />
<!-- 6. 品牌发展历程 -->
<section v-if="about" class="section reveal" aria-label="品牌发展历程">
<div class="container">
<CommonSectionTitle :title="about.heritage.title" subtitle="2015年创立至今,一步一个脚印走在呼伦贝尔草原上" />
<div class="timeline">
<div v-for="milestone in about.heritage.milestones" :key="milestone.year" class="timeline-item">
<div class="timeline-marker">
<div class="timeline-dot" />
</div>
<div class="timeline-card">
<h4 class="timeline-year">{{ milestone.year }} </h4>
<p v-for="(p, i) in milestone.paragraphs" :key="i" class="timeline-text">{{ p }}</p>
</div>
</div>
</div>
</div>
</section>
<!-- 7. 集团企业 -->
<AboutSubsidiaryGrid v-if="about" :subsidiaries="about.subsidiaries" class="reveal" />
<!-- 8. 品牌资产知识产权 + 吉祥物 -->
<AboutCopyrightList v-if="about" :copyrights="about.copyrights" :trademark="about.trademark" class="reveal" />
<AboutMascotShowcase class="reveal" />
<!-- 9. 企业文化 -->
<section v-if="about" class="section reveal" aria-label="企业文化">
<div class="container">
<!-- 核心信念 -->
<div class="culture-belief">
<p class="culture-belief__prefix">我们深知</p>
<div class="culture-belief__divider"></div>
<p class="culture-belief__quote">大部分人只来一次呼伦贝尔</p>
<p class="culture-belief__quote">而这一次便是一辈子的回忆</p>
<div class="culture-belief__divider"></div>
<p class="culture-belief__cta">所以我们从不敢有任何的怠慢</p>
</div>
<!-- 价值观 -->
<CommonSectionTitle title="呼籁文化理念" />
<div class="culture-values">
<div v-for="value in about.culture.values" :key="value.name" class="culture-value-card">
<h4 class="culture-value-card__name">{{ value.name }}</h4>
<ul class="culture-value-card__list">
<li v-for="(point, i) in value.points" :key="i">{{ point }}</li>
</ul>
</div>
</div>
<!-- 品牌 Slogan -->
<div v-if="about.culture.slogan" class="culture-slogan">
<div v-for="(line, i) in about.culture.slogan.lines" :key="i" class="culture-slogan__line">
<span v-if="line.label" class="culture-slogan__label">{{ line.label }}</span>
<p class="culture-slogan__text">{{ line.text }}</p>
</div>
</div>
</div>
</section>
<!-- CTA -->
<!-- 内链 -->
<CommonSectionCTA
title="想了解我们的产品?"
description="查看额吉的故乡V9系列和小蒙马夏令营"
:links="[
{ to: '/products', text: '查看旅行产品' },
{ to: '/contact', text: '联系定制师' },
]"
:links="[{ to: '/products', text: '查看呼伦贝尔定制游产品' }]"
/>
</div>
</template>
<script setup>
import about from '~/data/about.json'
import brand from '~/data/brand.json'
import contact from '~/data/contact.json'
import { useOrganizationSchema, useBreadcrumbSchema, usePersonSchema } from '~/composables/useJsonLd'
const { data: about } = await usePublicApi('about')
const { data: brand } = await usePublicApi('brand')
const { data: contact } = await usePublicApi('contact')
const seo = useSEO('about')
useScrollReveal()
useOrganizationSchema(brand.value, contact.value)
usePersonSchema(about.value?.founder)
useOrganizationSchema(brand, contact)
usePersonSchema(about.founder)
useBreadcrumbSchema([
{ text: '首页', to: '/' },
{ text: '关于我们' },
@ -130,14 +81,13 @@ useBreadcrumbSchema([
</script>
<style lang="less" scoped>
// ===== =====
.journey-list {
list-style: none;
padding: 0;
margin: @space-xl 0 0;
display: grid;
grid-template-columns: 1fr;
gap: @space-md;
gap: @space-lg;
.respond-md({
grid-template-columns: repeat(2, 1fr);
@ -150,43 +100,22 @@ useBreadcrumbSchema([
.journey-item {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: @space-xl @space-lg;
background: @color-bg-white;
border-radius: @border-radius-lg;
border: 1px solid @color-border;
transition: box-shadow @transition-base, transform @transition-base;
&:hover {
box-shadow: @shadow-md;
transform: translateY(-2px);
border-color: @color-primary-lighter;
.journey-step {
background: @color-primary;
color: #fff;
border-color: @color-primary;
}
}
gap: @space-md;
align-items: flex-start;
}
.journey-step {
flex-shrink: 0;
width: 40px;
height: 40px;
background: transparent;
color: @color-primary;
border: 2px solid @color-primary;
width: 32px;
height: 32px;
background: @color-primary;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: @font-size-sm;
font-weight: @font-weight-bold;
margin-bottom: @space-md;
transition: all @transition-base;
}
.journey-body {
@ -207,245 +136,4 @@ useBreadcrumbSchema([
line-height: @line-height-base;
margin: 0;
}
// ===== =====
.timeline {
position: relative;
max-width: 800px;
margin: @space-xl auto 0;
padding-left: @space-xl;
// 线
&::before {
content: '';
position: absolute;
left: 5px;
top: 8px;
bottom: 0;
width: 2px;
background: @color-primary-lighter;
}
}
.timeline-item {
position: relative;
display: flex;
gap: @space-lg;
padding-bottom: @space-2xl;
&:last-child {
padding-bottom: 0;
// 线
&::before {
display: none;
}
}
}
.timeline-marker {
position: absolute;
left: -@space-xl + 1px;
top: 6px;
}
.timeline-dot {
width: 10px;
height: 10px;
background: @color-primary;
border-radius: 50%;
position: relative;
z-index: 1;
}
.timeline-card {
flex: 1;
background: @color-bg-white;
border: 1px solid @color-border;
border-radius: @border-radius-lg;
padding: @space-lg @space-xl;
box-shadow: @shadow-xs;
transition: box-shadow @transition-base;
&:hover {
box-shadow: @shadow-card;
}
}
.timeline-year {
font-size: @font-size-lg;
font-weight: @font-weight-bold;
color: @color-primary;
margin: 0 0 @space-sm;
}
.timeline-text {
font-size: @font-size-sm;
color: @color-text-secondary;
line-height: @line-height-relaxed;
margin: 0 0 @space-md;
&:last-child {
margin-bottom: 0;
}
}
// ===== =====
.culture-belief {
background: linear-gradient(135deg, @color-primary-dark 0%, @color-primary 60%, @color-primary-light 100%);
color: #fff;
border-radius: @border-radius-xl;
padding: @space-3xl @space-2xl;
margin-bottom: @space-2xl;
text-align: center;
position: relative;
overflow: hidden;
.respond-md({
padding: @space-4xl @space-3xl;
});
&__prefix {
font-size: @font-size-lg;
font-weight: @font-weight-bold;
letter-spacing: 6px;
color: #fff;
margin: 0 0 @space-lg;
.respond-md({
font-size: @font-size-xl;
letter-spacing: 8px;
});
}
&__divider {
width: 48px;
height: 2px;
background: rgba(255, 255, 255, 0.5);
margin: @space-lg auto;
}
&__quote {
font-size: @font-size-2xl;
font-weight: @font-weight-bold;
line-height: @line-height-relaxed;
margin: 0 0 @space-sm;
letter-spacing: 2px;
color: #fff;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
.respond-md({
font-size: @font-size-3xl;
letter-spacing: 3px;
});
}
&__cta {
font-size: @font-size-md;
font-weight: @font-weight-medium;
letter-spacing: 3px;
color: rgba(255, 255, 255, 0.9);
margin: 0;
.respond-md({
font-size: @font-size-xl;
letter-spacing: 4px;
});
}
}
.culture-values {
display: grid;
grid-template-columns: 1fr;
gap: @space-lg;
margin-top: @space-xl;
.respond-lg({
grid-template-columns: repeat(3, 1fr);
});
}
.culture-value-card {
background: @color-bg-gray;
border-radius: @border-radius-lg;
padding: @space-xl;
&__name {
font-size: @font-size-lg;
font-weight: @font-weight-bold;
color: @color-primary;
margin: 0 0 @space-md;
}
&__list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: @space-md;
li {
font-size: @font-size-sm;
color: @color-text-secondary;
line-height: @line-height-base;
padding-left: @space-lg;
position: relative;
&::before {
content: '';
position: absolute;
left: 0;
top: 9px;
width: 16px;
height: 2px;
background: @color-primary-lighter;
}
}
}
}
.culture-slogan {
margin-top: @space-3xl;
text-align: center;
padding: @space-2xl 0;
max-width: 640px;
margin-left: auto;
margin-right: auto;
&__line {
margin-bottom: @space-xl;
padding-bottom: @space-xl;
border-bottom: 1px solid @color-divider;
&:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
}
&__label {
display: inline-block;
font-size: @font-size-xs;
font-weight: @font-weight-bold;
color: @color-primary;
letter-spacing: 4px;
text-transform: uppercase;
margin-bottom: @space-sm;
}
&__text {
font-size: @font-size-xl;
font-weight: @font-weight-bold;
color: @color-text-primary;
line-height: @line-height-normal;
margin: 0;
letter-spacing: 1px;
.respond-md({
font-size: @font-size-2xl;
});
}
}
</style>

查看文件

@ -1,133 +0,0 @@
<template>
<div style="max-width: 1100px">
<n-breadcrumb style="margin-bottom: 16px">
<n-breadcrumb-item @click="navigateTo('/admin/articles')">最新动态</n-breadcrumb-item>
<n-breadcrumb-item>{{ isNew ? '新增' : '编辑' }}</n-breadcrumb-item>
</n-breadcrumb>
<n-space justify="space-between" align="center" style="margin-bottom: 24px">
<h1 style="margin: 0; font-size: 20px; font-weight: 600; color: #111827">{{ isNew ? '新增动态' : '编辑动态' }}</h1>
<n-space>
<n-button secondary @click="navigateTo('/admin/articles')">取消</n-button>
<n-button type="primary" :loading="saving" @click="handleSave">保存</n-button>
</n-space>
</n-space>
<n-card v-if="loadError" style="text-align: center; color: #ef4444">{{ loadError }}</n-card>
<n-spin v-else-if="pageLoading" style="display: flex; justify-content: center; padding: 60px" />
<template v-else>
<div class="form-layout">
<div class="form-main">
<n-card title="基本信息">
<n-form label-placement="top">
<n-form-item label="标题" required>
<n-input v-model:value="form.title" placeholder="输入文章标题" />
</n-form-item>
<n-form-item label="Slug" required>
<n-input v-model:value="form.slug" placeholder="URL 标识,如 news-2026-spring" />
<template #feedback>用于生成文章链接仅限英文数字和短横线</template>
</n-form-item>
<n-form-item label="摘要">
<n-input v-model:value="form.summary" type="textarea" :rows="3" placeholder="简要描述文章内容(可选)" />
</n-form-item>
<n-form-item label="正文">
<n-input v-model:value="form.content" type="textarea" :rows="16" placeholder="输入文章正文,支持 HTML" />
</n-form-item>
</n-form>
</n-card>
</div>
<div class="form-sidebar">
<n-card title="发布设置">
<n-form label-placement="top">
<n-form-item label="状态">
<n-select v-model:value="form.published" :options="[{ label: '已发布', value: true }, { label: '草稿', value: false }]" />
</n-form-item>
<n-form-item label="分类">
<n-select v-model:value="form.category" :options="[{ label: '产品', value: '产品' }, { label: '公告', value: '公告' }, { label: '活动', value: '活动' }]" />
</n-form-item>
</n-form>
</n-card>
<n-card title="封面图">
<AdminImageUpload v-model="form.coverImage" />
</n-card>
<n-card v-if="!isNew" title="其他信息" size="small">
<n-descriptions :column="1" label-placement="left" size="small">
<n-descriptions-item label="创建时间">{{ form.createdAt?.slice(0, 16).replace('T', ' ') }}</n-descriptions-item>
<n-descriptions-item label="更新时间">{{ form.updatedAt?.slice(0, 16).replace('T', ' ') }}</n-descriptions-item>
<n-descriptions-item label="ID">{{ route.params.id }}</n-descriptions-item>
</n-descriptions>
</n-card>
</div>
</div>
<n-alert v-if="formError" type="error" style="margin-top: 12px">{{ formError }}</n-alert>
<div class="save-bar">
<n-button secondary @click="navigateTo('/admin/articles')">取消</n-button>
<n-button type="primary" :loading="saving" @click="handleSave">保存</n-button>
</div>
</template>
</div>
</template>
<script setup>
import { NButton, NCard, NSpace, NInput, NForm, NFormItem, NSelect, NBreadcrumb, NBreadcrumbItem, NSpin, NDescriptions, NDescriptionsItem, NAlert } from 'naive-ui'
import { useMessage } from 'naive-ui'
definePageMeta({ layout: 'admin', middleware: 'admin' })
const route = useRoute()
const { adminFetch } = useAdmin()
const message = useMessage()
const isNew = computed(() => route.params.id === 'new')
const pageLoading = ref(!isNew.value)
const loadError = ref('')
const saving = ref(false)
const formError = ref('')
const form = ref({
title: '', slug: '', category: '产品', summary: '', content: '',
coverImage: '', published: true, createdAt: '', updatedAt: '',
})
async function loadItem() {
if (isNew.value) return
pageLoading.value = true
try {
const data = await adminFetch(`/api/admin/articles/${route.params.id}`)
form.value = { ...data, published: !!data.published, coverImage: data.coverImage || '' }
} catch (e) { loadError.value = e.data?.message || '加载失败' }
finally { pageLoading.value = false }
}
async function handleSave() {
if (!form.value.title?.trim()) { formError.value = '标题不能为空'; return }
if (!form.value.slug?.trim()) { formError.value = 'Slug 不能为空'; return }
saving.value = true; formError.value = ''
try {
if (isNew.value) {
await adminFetch('/api/admin/articles', { method: 'POST', body: { ...form.value, type: 'news' } })
message.success('创建成功')
setTimeout(() => navigateTo('/admin/articles'), 800)
} else {
await adminFetch(`/api/admin/articles/${route.params.id}`, { method: 'PUT', body: form.value })
message.success('保存成功')
}
} catch (e) { formError.value = e.data?.message || '保存失败' }
finally { saving.value = false }
}
onMounted(loadItem)
</script>
<style scoped>
.form-layout { display: grid; grid-template-columns: 1fr 300px; gap: 20px; align-items: start; }
.form-main { min-width: 0; }
.form-sidebar { display: flex; flex-direction: column; gap: 16px; }
.save-bar { position: sticky; bottom: 0; display: flex; justify-content: flex-end; gap: 8px; padding: 16px 0; margin-top: 24px; background: #f0f2f5; border-top: 1px solid #e5e7eb; }
</style>

查看文件

@ -1,108 +0,0 @@
<template>
<div style="max-width: 1200px">
<n-space justify="space-between" align="center" style="margin-bottom: 20px">
<div>
<h1 style="margin: 0 0 4px; font-size: 20px; font-weight: 600; color: #111827">最新动态</h1>
<p style="margin: 0; font-size: 13px; color: #9ca3af">管理官网新闻动态 · 对应官网最新动态页面</p>
</div>
<n-space>
<n-button tag="a" href="/news" target="_blank" secondary>查看前台</n-button>
<n-button type="primary" @click="navigateTo('/admin/articles/new')">新增动态</n-button>
</n-space>
</n-space>
<n-card>
<n-space style="margin-bottom: 16px">
<n-input v-model:value="search" placeholder="搜索标题、分类..." clearable style="width: 260px" @keyup.enter="page = 1; loadData()">
<template #prefix><span style="color: #9ca3af">&#128269;</span></template>
</n-input>
<n-button @click="page = 1; loadData()">搜索</n-button>
</n-space>
<n-data-table :columns="columns" :data="list" :loading="loading" :row-key="(row) => row.id" :pagination="false" size="small" striped />
<n-space justify="end" style="margin-top: 16px" v-if="totalPages > 1">
<n-pagination v-model:page="page" :page-count="totalPages" @update:page="loadData" />
</n-space>
</n-card>
</div>
</template>
<script setup>
import { h } from 'vue'
import { NButton, NCard, NSpace, NInput, NDataTable, NTag, NPagination, NPopconfirm } from 'naive-ui'
import { useMessage } from 'naive-ui'
definePageMeta({ layout: 'admin', middleware: 'admin' })
const { adminFetch } = useAdmin()
const message = useMessage()
const list = ref([])
const total = ref(0)
const page = ref(1)
const totalPages = ref(1)
const loading = ref(false)
const search = ref('')
const columns = [
{ title: 'ID', key: 'id', width: 50, render: (row) => h('span', { style: 'color: #9ca3af; font-size: 12px' }, row.id) },
{
title: '标题', key: 'title',
render: (row) => h('a', {
style: 'color: #111827; text-decoration: none; font-weight: 500; cursor: pointer',
onClick: () => navigateTo(`/admin/articles/${row.id}`),
}, row.title),
},
{
title: '分类', key: 'category', width: 80,
render: (row) => row.category ? h(NTag, { size: 'small', type: 'info', bordered: false }, () => row.category) : '-',
},
{
title: '状态', key: 'published', width: 70,
render: (row) => h(NTag, {
size: 'small', type: row.published ? 'success' : 'default', bordered: false,
style: 'cursor: pointer',
onClick: () => togglePublish(row),
}, () => row.published ? '已发布' : '草稿'),
},
{
title: '创建时间', key: 'createdAt', width: 100,
render: (row) => h('span', { style: 'color: #9ca3af; font-size: 12px' }, row.createdAt?.slice(0, 10)),
},
{
title: '操作', key: 'actions', width: 120,
render: (row) => h(NSpace, { size: 'small' }, () => [
h(NButton, { size: 'tiny', text: true, type: 'primary', onClick: () => navigateTo(`/admin/articles/${row.id}`) }, () => '编辑'),
h(NPopconfirm, { onPositiveClick: () => handleDelete(row) }, {
trigger: () => h(NButton, { size: 'tiny', text: true, type: 'error' }, () => '删除'),
default: () => `确定删除「${row.title}」?`,
}),
]),
},
]
async function loadData() {
loading.value = true
try {
const d = await adminFetch(`/api/admin/articles?type=news&page=${page.value}&limit=20&search=${encodeURIComponent(search.value)}`)
list.value = d.items; total.value = d.total; totalPages.value = d.totalPages
} catch { message.error('加载失败') } finally { loading.value = false }
}
async function togglePublish(item) {
try {
await adminFetch(`/api/admin/articles/${item.id}`, { method: 'PUT', body: { published: !item.published } })
item.published = !item.published
} catch { message.error('操作失败') }
}
async function handleDelete(item) {
try {
await adminFetch(`/api/admin/articles/${item.id}`, { method: 'DELETE' })
message.success('已删除')
loadData()
} catch { message.error('删除失败') }
}
onMounted(loadData)
</script>

查看文件

@ -1,142 +0,0 @@
<template>
<div style="max-width: 1100px">
<n-breadcrumb style="margin-bottom: 16px">
<n-breadcrumb-item @click="navigateTo('/admin/blogs')">博客文章</n-breadcrumb-item>
<n-breadcrumb-item>{{ isNew ? '新增' : '编辑' }}</n-breadcrumb-item>
</n-breadcrumb>
<n-space justify="space-between" align="center" style="margin-bottom: 24px">
<h1 style="margin: 0; font-size: 20px; font-weight: 600; color: #111827">{{ isNew ? '新增博客' : '编辑博客' }}</h1>
<n-space>
<n-button secondary @click="navigateTo('/admin/blogs')">取消</n-button>
<n-button type="primary" :loading="saving" @click="handleSave">保存</n-button>
</n-space>
</n-space>
<n-card v-if="loadError" style="text-align: center; color: #ef4444">{{ loadError }}</n-card>
<n-spin v-else-if="pageLoading" style="display: flex; justify-content: center; padding: 60px" />
<template v-else>
<div class="form-layout">
<div class="form-main">
<n-card title="基本信息">
<n-form label-placement="top">
<n-form-item label="标题" required>
<n-input v-model:value="form.title" placeholder="输入博客标题" />
</n-form-item>
<n-form-item label="Slug" required>
<n-input v-model:value="form.slug" placeholder="如 hulunbuir-travel-guide" />
<template #feedback>用于生成博客链接</template>
</n-form-item>
<n-form-item label="摘要">
<n-input v-model:value="form.summary" type="textarea" :rows="3" placeholder="简要描述" />
</n-form-item>
<n-form-item label="正文(支持 HTML">
<n-input v-model:value="form.content" type="textarea" :rows="20" placeholder="输入博客正文" />
</n-form-item>
</n-form>
</n-card>
<n-card title="SEO 设置" style="margin-top: 16px">
<n-form label-placement="top">
<n-form-item label="SEO 标题">
<n-input v-model:value="form.seoTitle" placeholder="留空则使用文章标题" />
</n-form-item>
<n-form-item label="SEO 描述">
<n-input v-model:value="form.seoDesc" type="textarea" :rows="2" placeholder="搜索引擎描述" />
</n-form-item>
<n-form-item label="SEO 关键词">
<n-input v-model:value="form.seoKeywords" placeholder="逗号分隔" />
</n-form-item>
</n-form>
</n-card>
</div>
<div class="form-sidebar">
<n-card title="发布设置">
<n-form label-placement="top">
<n-form-item label="状态">
<n-select v-model:value="form.published" :options="[{ label: '已发布', value: true }, { label: '草稿', value: false }]" />
</n-form-item>
<n-form-item label="分类">
<n-select v-model:value="form.category" :options="[{ label: '攻略', value: '攻略' }, { label: '亲子', value: '亲子' }, { label: '游记', value: '游记' }]" />
</n-form-item>
<n-form-item label="作者">
<n-input v-model:value="form.author" />
</n-form-item>
</n-form>
</n-card>
<n-card title="封面图">
<AdminImageUpload v-model="form.coverImage" />
</n-card>
</div>
</div>
<n-alert v-if="formError" type="error" style="margin-top: 12px">{{ formError }}</n-alert>
<div class="save-bar">
<n-button secondary @click="navigateTo('/admin/blogs')">取消</n-button>
<n-button type="primary" :loading="saving" @click="handleSave">保存</n-button>
</div>
</template>
</div>
</template>
<script setup>
import { NButton, NCard, NSpace, NInput, NForm, NFormItem, NSelect, NBreadcrumb, NBreadcrumbItem, NSpin, NAlert } from 'naive-ui'
import { useMessage } from 'naive-ui'
definePageMeta({ layout: 'admin', middleware: 'admin' })
const route = useRoute()
const { adminFetch } = useAdmin()
const message = useMessage()
const isNew = computed(() => route.params.id === 'new')
const pageLoading = ref(!isNew.value)
const loadError = ref('')
const saving = ref(false)
const formError = ref('')
const form = ref({
title: '', slug: '', category: '攻略', author: '呼籁旅行',
summary: '', content: '', coverImage: '',
seoTitle: '', seoDesc: '', seoKeywords: '', published: true,
})
async function loadItem() {
if (isNew.value) return
pageLoading.value = true
try {
const d = await adminFetch(`/api/admin/articles/${route.params.id}`)
form.value = { ...d, published: !!d.published, coverImage: d.coverImage || '' }
} catch (e) { loadError.value = e.data?.message || '加载失败' }
finally { pageLoading.value = false }
}
async function handleSave() {
if (!form.value.title?.trim() || !form.value.slug?.trim()) { formError.value = '标题和 Slug 不能为空'; return }
saving.value = true; formError.value = ''
try {
if (isNew.value) {
await adminFetch('/api/admin/articles', { method: 'POST', body: { ...form.value, type: 'blog' } })
message.success('创建成功')
setTimeout(() => navigateTo('/admin/blogs'), 800)
} else {
await adminFetch(`/api/admin/articles/${route.params.id}`, { method: 'PUT', body: form.value })
message.success('保存成功')
}
} catch (e) { formError.value = e.data?.message || '保存失败' }
finally { saving.value = false }
}
onMounted(loadItem)
</script>
<style scoped>
.form-layout { display: grid; grid-template-columns: 1fr 300px; gap: 20px; align-items: start; }
.form-main { min-width: 0; }
.form-sidebar { display: flex; flex-direction: column; gap: 16px; }
.save-bar { position: sticky; bottom: 0; display: flex; justify-content: flex-end; gap: 8px; padding: 16px 0; margin-top: 24px; background: #f0f2f5; border-top: 1px solid #e5e7eb; }
</style>

查看文件

@ -1,84 +0,0 @@
<template>
<div style="max-width: 1200px">
<n-space justify="space-between" align="center" style="margin-bottom: 20px">
<div>
<h1 style="margin: 0 0 4px; font-size: 20px; font-weight: 600; color: #111827">博客文章</h1>
<p style="margin: 0; font-size: 13px; color: #9ca3af">管理攻略亲子游记等长文 · 对应官网博客页面</p>
</div>
<n-space>
<n-button tag="a" href="/blog" target="_blank" secondary>查看前台</n-button>
<n-button type="primary" @click="navigateTo('/admin/blogs/new')">新增博客</n-button>
</n-space>
</n-space>
<n-card>
<n-space style="margin-bottom: 16px">
<n-input v-model:value="search" placeholder="搜索标题、分类..." clearable style="width: 260px" @keyup.enter="page = 1; loadData()">
<template #prefix><span style="color: #9ca3af">&#128269;</span></template>
</n-input>
<n-button @click="page = 1; loadData()">搜索</n-button>
</n-space>
<n-data-table :columns="columns" :data="list" :loading="loading" :row-key="(row) => row.id" :pagination="false" size="small" striped />
<n-space justify="end" style="margin-top: 16px" v-if="totalPages > 1">
<n-pagination v-model:page="page" :page-count="totalPages" @update:page="loadData" />
</n-space>
</n-card>
</div>
</template>
<script setup>
import { h } from 'vue'
import { NButton, NCard, NSpace, NInput, NDataTable, NTag, NPagination, NPopconfirm } from 'naive-ui'
import { useMessage } from 'naive-ui'
definePageMeta({ layout: 'admin', middleware: 'admin' })
const { adminFetch } = useAdmin()
const message = useMessage()
const list = ref([]); const total = ref(0); const page = ref(1); const totalPages = ref(1); const loading = ref(false); const search = ref('')
const columns = [
{ title: 'ID', key: 'id', width: 50, render: (row) => h('span', { style: 'color: #9ca3af; font-size: 12px' }, row.id) },
{
title: '标题', key: 'title',
render: (row) => h('a', { style: 'color: #111827; text-decoration: none; font-weight: 500; cursor: pointer', onClick: () => navigateTo(`/admin/blogs/${row.id}`) }, row.title),
},
{ title: '分类', key: 'category', width: 70, render: (row) => row.category ? h(NTag, { size: 'small', type: 'info', bordered: false }, () => row.category) : '-' },
{ title: '作者', key: 'author', width: 80, render: (row) => h('span', { style: 'color: #9ca3af; font-size: 12px' }, row.author || '-') },
{
title: '状态', key: 'published', width: 70,
render: (row) => h(NTag, { size: 'small', type: row.published ? 'success' : 'default', bordered: false, style: 'cursor: pointer', onClick: () => togglePublish(row) }, () => row.published ? '已发布' : '草稿'),
},
{ title: '时间', key: 'createdAt', width: 100, render: (row) => h('span', { style: 'color: #9ca3af; font-size: 12px' }, row.createdAt?.slice(0, 10)) },
{
title: '操作', key: 'actions', width: 120,
render: (row) => h(NSpace, { size: 'small' }, () => [
h(NButton, { size: 'tiny', text: true, type: 'primary', onClick: () => navigateTo(`/admin/blogs/${row.id}`) }, () => '编辑'),
h(NPopconfirm, { onPositiveClick: () => handleDelete(row) }, {
trigger: () => h(NButton, { size: 'tiny', text: true, type: 'error' }, () => '删除'),
default: () => `确定删除「${row.title}」?`,
}),
]),
},
]
async function loadData() {
loading.value = true
try { const d = await adminFetch(`/api/admin/articles?type=blog&page=${page.value}&limit=20&search=${encodeURIComponent(search.value)}`); list.value = d.items; total.value = d.total; totalPages.value = d.totalPages }
catch { message.error('加载失败') } finally { loading.value = false }
}
async function togglePublish(item) {
try { await adminFetch(`/api/admin/articles/${item.id}`, { method: 'PUT', body: { published: !item.published } }); item.published = !item.published }
catch { message.error('操作失败') }
}
async function handleDelete(item) {
try { await adminFetch(`/api/admin/articles/${item.id}`, { method: 'DELETE' }); message.success('已删除'); loadData() }
catch { message.error('删除失败') }
}
onMounted(loadData)
</script>

某些文件未显示,因为此 diff 中更改的文件太多 显示更多