From f91ecbb093bc524ee5fec10d2dbc85b395931e01 Mon Sep 17 00:00:00 2001 From: wx Date: Sat, 18 Apr 2026 15:13:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=98=E7=BD=91=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=85=A8=E9=87=8F=E6=9B=B4=E6=96=B0=20(2026-04-18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/launch.json | 2 +- components/about/CopyrightList.vue | 3 +- components/about/CultureValues.vue | 3 +- components/about/MascotShowcase.vue | 3 +- components/about/QualificationList.vue | 11 +- components/about/TeamIntro.vue | 3 +- components/about/XiaohongshuShowcase.vue | 3 +- components/admin/RichTextEditor.vue | 161 + components/autumn/ProductCard.vue | 160 +- components/common/FloatingContact.vue | 246 + components/common/WechatCTA.vue | 3 +- components/home/DifferentiatorList.vue | 4 +- components/home/ProductPreview.vue | 4 +- components/home/ReviewHighlights.vue | 3 +- components/layout/AppFooter.vue | 142 +- components/layout/AppHeader.vue | 28 +- components/products/EvolutionStats.vue | 3 +- components/products/PricingPhilosophy.vue | 3 +- components/products/SelectionGuide.vue | 3 +- components/products/SummerCampCard.vue | 7 +- components/products/VersionCompare.vue | 3 +- components/products/VersionHighlights.vue | 3 +- components/products/VersionPhilosophy.vue | 3 +- components/products/VersionUpgrades.vue | 3 +- composables/useAdminSort.js | 40 + composables/useJsonLd.js | 2 +- composables/useSectionTitles.js | 33 + data/about.json | 2 +- data/autumn-products.json | 355 +- data/blog.json | 72 +- data/brand.json | 11 +- data/calendar.json | 48 +- data/courses.json | 6 +- data/db.sqlite | 0 data/destinations-detail.json | 139 +- data/destinations.json | 6 +- data/faq.json | 26 +- data/gallery.json | 8 +- data/guide-custom.json | 82 + data/guides.json | 28 +- data/heroes.json | 25 + data/navigation.json | 4 +- data/news.json | 31 +- data/partners.json | 2 +- data/pricing.json | 2 +- data/product-lines.json | 42 + data/products.json | 22 +- data/section-titles.json | 90 + data/selector.json | 34 +- data/seo.json | 30 +- data/versions.json | 18 +- data/winter-camp.json | 20 +- data/winter-products.json | 2 +- layouts/admin.vue | 56 +- layouts/default.vue | 1 + nuxt.config.js | 35 +- package-lock.json | 6426 +++++++++++------ package.json | 8 +- pages/about.vue | 6 +- pages/admin/articles/[id].vue | 7 +- pages/admin/blogs/[id].vue | 9 +- pages/admin/content/brand.vue | 40 +- .../content/destinations-detail/[idx].vue | 21 +- .../content/destinations-detail/index.vue | 124 +- pages/admin/content/guide-custom.vue | 283 + pages/admin/content/guides.vue | 325 +- pages/admin/content/heroes.vue | 117 + pages/admin/content/pricing.vue | 11 +- pages/admin/content/section-titles.vue | 254 + pages/admin/faqs/index.vue | 11 +- pages/admin/gallery/index.vue | 9 + pages/admin/index.vue | 278 +- pages/admin/products/[key].vue | 134 +- pages/admin/products/index.vue | 13 +- pages/admin/reviews/[id].vue | 110 +- pages/admin/reviews/index.vue | 230 +- pages/admin/stories/[id].vue | 46 +- pages/admin/stories/index.vue | 9 + pages/admin/submissions/index.vue | 369 +- pages/blog/[id].vue | 2 +- pages/blog/index.vue | 5 +- pages/calendar.vue | 29 +- pages/contact.vue | 32 +- pages/courses.vue | 40 +- pages/customize.vue | 9 +- pages/destinations/[id].vue | 10 +- pages/destinations/index.vue | 15 +- pages/faq.vue | 4 +- pages/gallery.vue | 16 +- pages/guide-custom.vue | 164 +- pages/guides.vue | 3 +- pages/index.vue | 9 +- pages/news.vue | 65 +- pages/partners.vue | 40 +- pages/pricing.vue | 12 +- pages/products/autumn.vue | 21 +- pages/products/index.vue | 14 +- pages/products/winter.vue | 12 +- pages/qualifications.vue | 8 +- pages/reviews.vue | 3 +- pages/selector.vue | 7 +- pages/stories/index.vue | 62 +- pages/summer-camp.vue | 14 +- pages/winter-camp.vue | 26 +- pages/xiaohongshu/[id].vue | 2 +- pages/xiaohongshu/index.vue | 5 +- pages/youji/index.vue | 3 +- public/images/news-red-cross-1.jpg | Bin 0 -> 2643678 bytes public/images/news-red-cross-2.jpg | Bin 0 -> 4436318 bytes public/images/news-red-cross-3.jpg | Bin 0 -> 4752101 bytes scripts/.screenshot-import-report.json | 686 ++ scripts/auto-tag-reviews.mjs | 67 + scripts/import-review-screenshots.mjs | 174 + scripts/seed-blog-seo.mjs | 89 + scripts/seed-stories-batch1.mjs | 171 + scripts/seed-stories-batch2.mjs | 460 ++ server/api/admin/ocr.post.js | 39 + server/api/admin/reviews.get.js | 34 +- server/api/admin/reviews.post.js | 5 + server/api/admin/reviews/[id].get.js | 6 +- server/api/admin/reviews/[id].put.js | 3 + server/api/admin/reviews/bulk.post.js | 31 + server/api/admin/site-content.get.js | 3 +- server/api/admin/stats.get.js | 74 +- server/api/admin/stories.post.js | 4 + server/api/admin/stories/[id].get.js | 7 +- server/api/admin/stories/[id].put.js | 4 + server/api/admin/submissions/[id].delete.js | 30 + server/api/admin/submissions/[id].put.js | 25 +- server/api/content/[key].get.js | 37 +- server/database/migrate.js | 16 + server/database/schema.js | 6 + server/database/seed.js | 3 + server/storage/contact.json | 23 +- server/storage/customize.json | 108 +- 135 files changed, 10307 insertions(+), 3349 deletions(-) create mode 100644 components/admin/RichTextEditor.vue create mode 100644 components/common/FloatingContact.vue create mode 100644 composables/useAdminSort.js create mode 100644 composables/useSectionTitles.js create mode 100644 data/db.sqlite create mode 100644 data/guide-custom.json create mode 100644 data/heroes.json create mode 100644 data/product-lines.json create mode 100644 data/section-titles.json create mode 100644 pages/admin/content/guide-custom.vue create mode 100644 pages/admin/content/heroes.vue create mode 100644 pages/admin/content/section-titles.vue create mode 100644 public/images/news-red-cross-1.jpg create mode 100644 public/images/news-red-cross-2.jpg create mode 100644 public/images/news-red-cross-3.jpg create mode 100644 scripts/.screenshot-import-report.json create mode 100644 scripts/auto-tag-reviews.mjs create mode 100644 scripts/import-review-screenshots.mjs create mode 100644 scripts/seed-blog-seo.mjs create mode 100644 scripts/seed-stories-batch1.mjs create mode 100644 scripts/seed-stories-batch2.mjs create mode 100644 server/api/admin/ocr.post.js create mode 100644 server/api/admin/reviews/bulk.post.js create mode 100644 server/api/admin/submissions/[id].delete.js diff --git a/.claude/launch.json b/.claude/launch.json index 258ee65..18b8336 100644 --- a/.claude/launch.json +++ b/.claude/launch.json @@ -6,7 +6,7 @@ "runtimeExecutable": "npx", "runtimeArgs": ["nuxt", "dev", "--port", "3000"], "port": 3000, - "cwd": "/Users/liutao/Desktop/呼籁智库/hulai-website" + "cwd": "/Volumes/Mac wz/hulai-website" } ] } diff --git a/components/about/CopyrightList.vue b/components/about/CopyrightList.vue index 1d2f4cc..68c46c0 100644 --- a/components/about/CopyrightList.vue +++ b/components/about/CopyrightList.vue @@ -1,7 +1,7 @@ @@ -88,7 +135,8 @@ @@ -191,6 +279,16 @@ onMounted(loadItem) margin-bottom: 0; } +.screenshot-wrapper { + width: 100%; +} + +.screenshot-actions { + display: flex; + gap: 8px; + margin-top: 8px; +} + .save-bar { position: sticky; bottom: 0; diff --git a/pages/admin/reviews/index.vue b/pages/admin/reviews/index.vue index b583256..974bdd2 100644 --- a/pages/admin/reviews/index.vue +++ b/pages/admin/reviews/index.vue @@ -1,5 +1,5 @@ diff --git a/pages/blog/[id].vue b/pages/blog/[id].vue index 2f63482..cb0b330 100644 --- a/pages/blog/[id].vue +++ b/pages/blog/[id].vue @@ -79,7 +79,7 @@ diff --git a/pages/blog/index.vue b/pages/blog/index.vue index 3ef9c30..3716dbb 100644 --- a/pages/blog/index.vue +++ b/pages/blog/index.vue @@ -2,7 +2,7 @@
@@ -87,11 +87,12 @@ import { useBreadcrumbSchema } from '~/composables/useJsonLd' import useScrollReveal from '~/composables/useScrollReveal' const { data: blogData } = await usePublicApi('blog') +const { data: heroes } = await usePublicApi('heroes') useHead({ title: '呼伦贝尔旅行攻略 - 亲子游·避坑·穿搭·行程干货 - 呼籁旅行', meta: [ - { name: 'description', content: '呼籁旅行旅行攻略频道:呼伦贝尔亲子游完全指南、几月份去最好、旅行花费明细、避坑指南、草原旅拍穿搭,深耕11年的实用干货。' }, + { name: 'description', content: '呼籁旅行旅行攻略频道:呼伦贝尔亲子游综合指南、几月份去合适、旅行花费明细、避坑指南、草原旅拍穿搭,深耕11年的实用干货。' }, { name: 'keywords', content: '呼伦贝尔旅游攻略,呼伦贝尔亲子游攻略,呼伦贝尔几月去,呼伦贝尔旅游花费,草原旅拍穿搭' }, { property: 'og:title', content: '呼伦贝尔旅行攻略 - 呼籁旅行' }, { property: 'og:description', content: '呼伦贝尔亲子游·避坑指南·穿搭攻略,深耕11年的实用干货。' }, diff --git a/pages/calendar.vue b/pages/calendar.vue index 13d4a24..360a580 100644 --- a/pages/calendar.vue +++ b/pages/calendar.vue @@ -2,7 +2,7 @@
@@ -11,7 +11,7 @@
-

呼伦贝尔逐月出行指南:基于11年带队数据,详解1-12月天气、景色、适合活动和推荐行程。帮你选择最佳出行时间。

+

呼伦贝尔逐月出行指南:基于11年带队数据,详解1-12月天气、景色、适合活动和推荐行程。帮你选择合适的出行时间。

@@ -21,7 +21,7 @@
-

呼伦贝尔最佳出行时间一览

+

呼伦贝尔出行时间一览

什么时候来呼伦贝尔?

-

来呼伦贝尔一趟还是比较折腾的,希望大家能在每个季节相对最美的时候过来

+

来呼伦贝尔一趟还是比较折腾的,希望大家能在每个季节景色较好的时候过来

-

呼伦贝尔几月份去最好?详细解答

+

呼伦贝尔几月份去合适?详细解答

- 呼伦贝尔全年皆可出行,但来一趟毕竟不轻松,建议选对时间再出发。6月中下旬性价比最高,草原已非常美、各项活动全面开展,且尚未进入旺季价格。7月初至8月28日景色和活动巅峰,但价格也相对较高。9月20日至国庆是看大兴安岭秋景的最佳时机,非常推荐。冬季(12月至次年2月)是完全另一种美,冰雪那达慕、驯鹿部落值得体验。5月底可以提前出发避人群,但5月初和3-4月不太推荐。 + 呼伦贝尔全年皆可出行,但来一趟毕竟不轻松,建议选对时间再出发。6月中下旬性价比不错,草原已非常美、各项活动全面开展,且尚未进入旺季价格。7月初至8月28日景色和活动巅峰,但价格也相对较高。9月20日至国庆是看大兴安岭秋景的推荐时机,非常推荐。冬季(12月至次年2月)是另一种风貌,冰雪那达慕、驯鹿部落值得体验。5月底可以提前出发避人群,但5月初和3-4月不太推荐。

@@ -134,7 +134,7 @@
@@ -144,6 +144,7 @@ import { useBreadcrumbSchema } from '~/composables/useJsonLd' const { data: calData } = await usePublicApi('calendar') +const { data: heroes } = await usePublicApi('heroes') const seo = useSEO('calendar') @@ -161,7 +162,7 @@ useHead({ '@context': 'https://schema.org', '@type': 'TouristDestination', name: '呼伦贝尔大草原', - description: '呼伦贝尔是中国最美草原之一,位于内蒙古自治区东北部,拥有莫日格勒河、额尔古纳湿地、白桦林、呼伦湖等核心景观。最佳旅游时节为6-9月,夏季草原翠绿,秋季白桦金黄。', + description: '呼伦贝尔是中国著名草原之一,位于内蒙古自治区东北部,拥有莫日格勒河、额尔古纳湿地、白桦林、呼伦湖等核心景观。推荐旅游时节为6-9月,夏季草原翠绿,秋季白桦金黄。', url: 'https://1814.love/calendar', image: 'https://1814.love/images/team/hero-grassland.jpg', geo: { @@ -177,10 +178,10 @@ useHead({ }, touristType: ['家庭游客', '亲子家庭', '摄影爱好者', '自然爱好者'], includesAttraction: [ - { '@type': 'TouristAttraction', name: '莫日格勒河(额吉的故乡)', description: '呼伦贝尔最美河湾,夏季翠绿如画,是呼籁旅行夏季核心景点' }, - { '@type': 'TouristAttraction', name: '额尔古纳湿地', description: '中国最大湿地之一,鸟类天堂,秋季倒影绝美' }, + { '@type': 'TouristAttraction', name: '莫日格勒河(额吉的故乡)', description: '呼伦贝尔著名河湾,夏季翠绿如画,是呼籁旅行夏季核心景点' }, + { '@type': 'TouristAttraction', name: '额尔古纳湿地', description: '中国大型湿地之一,鸟类天堂,秋季倒影优美' }, { '@type': 'TouristAttraction', name: '白桦林', description: '九月金黄,摄影圣地,游牧的森林秋季产品核心景点' }, - { '@type': 'TouristAttraction', name: '呼伦湖', description: '中国北方第一大湖,冬季冰钓胜地,夏季湖畔骑马' }, + { '@type': 'TouristAttraction', name: '呼伦湖', description: '中国北方大型湖泊,冬季冰钓胜地,夏季湖畔骑马' }, { '@type': 'TouristAttraction', name: '中俄边境公路', description: '室韦至黑山头沿线,风景壮阔,国境线骑行体验独特' }, ], }), @@ -191,8 +192,8 @@ useHead({ const seasonalEvents = [ { key: 'event-summer', - name: '呼伦贝尔夏季旅游最佳期(6-8月)', - description: '呼伦贝尔草原夏季旅游高峰,绿草如茵,那达慕传统节庆,骑马、露营、亲子出行最佳时段。呼籁旅行提供额吉的故乡V9系列定制游及小蒙马亲子游学营。', + name: '呼伦贝尔夏季旅游推荐期(6-8月)', + description: '呼伦贝尔草原夏季旅游高峰,绿草如茵,那达慕传统节庆,骑马、露营、亲子出行推荐时段。呼籁旅行提供额吉的故乡V9系列定制游及小蒙马亲子游学营。', startDate: '2026-06-01', endDate: '2026-08-31', }, diff --git a/pages/contact.vue b/pages/contact.vue index 0a0e3d3..cc302a8 100644 --- a/pages/contact.vue +++ b/pages/contact.vue @@ -2,7 +2,7 @@
@@ -19,7 +19,7 @@
- +
@@ -62,7 +62,7 @@
- +
@@ -126,7 +126,9 @@ import { useOrganizationSchema, useBreadcrumbSchema, useContactPageSchema } from '~/composables/useJsonLd' const { data: contact } = await usePublicApi('contact') +const { data: heroes } = await usePublicApi('heroes') const { data: brand } = await usePublicApi('brand') +const st = await useSectionTitles() const visibleChannels = computed(() => (contact.value?.channels || []).filter(ch => !ch.hidden)) const wechatChannel = computed(() => visibleChannels.value.find(ch => ch.type === 'wechat')) @@ -148,13 +150,35 @@ function scrollToTop() {