Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/pages/index/index.tsx
This commit is contained in:
2026-04-09 12:24:30 +08:00
10 changed files with 910 additions and 10 deletions

View File

@@ -0,0 +1,8 @@
# 2026-04-01 工作记录
- 评估将云展网/易企秀 H5 页面接入微信小程序首页的方案:优先建议使用 `web-view` 承载独立画册页,并在首页增加“电子画册/品牌画册”入口;前提是第三方链接域名可在小程序后台配置为业务域名且满足 HTTPS/备案要求。若第三方域名不可配置,则建议改为把画册内容转成图片或原生页面放入小程序,不建议直接依赖外链跳转。
- 已按方案一落地:新增 `/pages/brochure/index` 作为 `web-view` 画册页,首页增加 `BrochureEntry` 卡片入口并完成路由配置;`npm run build:weapp` 构建通过。后续上线前需在小程序后台把 `book.yunzhan365.com` 配置为业务域名。
- 继续优化画册接入体验:`/pages/brochure/index` 增加失败兜底界面,支持“重新加载 / 返回首页”,并在首页入口文案中明确“在线翻阅”;再次执行 `npm run build:weapp` 构建通过。
- 用户确认无法让 `book.yunzhan365.com` 配置微信业务域名校验文件,因此第三方云展网链接不能作为小程序正式 `web-view` 接入方案;后续需改为自有域名中转、自有 H5 承载,或转图片/原生页展示。
- 已按用户要求将 `/pages/brochure/index` 改成原生画册页:包含品牌主视觉、核心优势、服务范围、案例方向、服务流程与咨询 CTA同时把首页入口文案改为适配原生页`npm run build:weapp` 再次通过。
- 继续推进画册正式版:`/pages/brochure/index` 现优先读取站点配置中的品牌名、电话、地址、工作时间,新增主营方案、服务承诺、预约咨询信息与“拨打热线 / 复制地址 / 返回首页”操作;同时把首页 `BrochureEntry` 真实挂到 Banner 下方,`npm run build:weapp` 构建通过。

View File

@@ -0,0 +1,5 @@
# 2026-04-02 工作记录
- 首页布局微调将品牌画册入口BrochureEntry从 Banner 下方移至 NoticeBar 下方;同时注释隐藏 CaseShowcase成功案例区块
- BrochureEntry 交互改版:点击"查看画册"不再跳转内页,改为复制画册链接到剪贴板,弹出 showModal 提示"链接已复制,请前往浏览器粘贴链接查看画册"。链接优先读后台 config.domain兜底使用固定链接 https://book.yunzhan365.com/mdfy/tjcs/mobile/index.html。
- 联系电话更新ContactSection.tsx 中"客服热线 400-888-9999"改为"联系电话 13367810229"brochure/index.tsx 中的 DEFAULT_HOTLINE 也同步更新为 13367810229。

View File

@@ -13,26 +13,26 @@
## 关键路径
- 首页入口:`src/pages/index/index.tsx`
- 画册页:`src/pages/brochure/index.tsx`(当前为原生品牌画册展示页)
- 分销商页面:`src/dealer/index.tsx`
- 用户钱包:`src/user/wallet/wallet.tsx`
- 客户管理:`src/dealer/customer/index`
- 邀请码:`src/dealer/qrcode/index`
- 导航工具:`src/utils/common.ts` (navTo函数)
## 首页结构 (2026-03-31 更新)
## 首页结构 (2026-04-02 更新)
- Header (吸顶搜索栏)
- Menu (导航菜单hidden)
- Banner (轮播广告)
- QuickActions (门窗业务快捷服务 - 2x2网格卡片)
- NoticeBar (公告栏)
- BestSellers (热销商品)
- Grid (功能菜单)
- NoticeBar (公告栏)
- **BrochureEntry** (品牌画册入口卡片 — 位于公告栏下方)
- BestSellers (热销商品)
- **TrustSection** (品牌信任区 - 3列水平布局)
- 品质保障10年质保德国进口五金
- 专业团队15年安装经验持证上岗
- 客户好评5000+家庭选择98%满意度
- **CaseShowcase** (案例展示 - 横向滚动画廊)
- 高端住宅、商业办公、别墅定制、旧窗改造
- ~~CaseShowcase~~ (已注释隐藏,待有真实素材后再恢复)
- **ContactSection** (联系方式 - 2x2网格布局)
- 客服热线、在线咨询、门店地址、关注我们
@@ -52,3 +52,16 @@
- 项目标题:`text-base font-semibold text-gray-800`
- 项目描述:`text-xs text-gray-500`
- 小文本:`text-xs text-gray-500`
## 画册页正式版 (2026-04-01)
- 首页已实际挂载 `src/pages/index/BrochureEntry.tsx` 入口,位置在 Banner 下方。
- `src/pages/brochure/index.tsx` 当前为原生正式版结构:主营方案、核心优势、升级关键词、服务承诺、案例方向、服务流程、预约咨询信息。
- 画册页优先读取 `configWebsiteField` 返回的 `siteName``tel``address``workDay` 作为品牌与联系信息;无配置时使用兜底文案。
- 当前页面提供“拨打热线 / 复制地址 / 返回首页”三类转化操作,后续可继续接真实案例图、门店定位与预约表单。
## 外部 H5/画册接入约定 (2026-04-01)
- 小程序首页如需承载外部画册、易企秀、云展网等 H5优先采用独立 `web-view` 页面承载,再从首页增加入口卡片或 banner 跳转。
- 该方案的前提是目标域名可在小程序后台配置为业务域名,且满足 HTTPS、备案等微信限制。
- 外部 `web-view` 页面应提供失败兜底界面(如重新加载、返回首页、管理员配置提示),不要只保留 toast 提示。
- 当前 `book.yunzhan365.com` 无法配合放置微信业务域名校验文件,因此不能作为小程序正式业务域名接入。
- 如果目标链接是第三方不可控域名无法完成业务域名配置则改为将内容转成图片、PDF 切图或原生页面在小程序内展示,不依赖直接外链打开;若仍想保留在线翻页体验,需迁移到自有可验证域名承载。

View File

@@ -1,6 +1,7 @@
export default defineAppConfig({
pages: [
'pages/index/index',
'pages/brochure/index',
'pages/cart/cart',
'pages/find/find',
'pages/user/user'

View File

@@ -0,0 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '品牌画册',
navigationBarBackgroundColor: '#ffffff',
navigationBarTextStyle: 'black'
})

View File

@@ -0,0 +1,381 @@
.brochure-page {
min-height: 100vh;
padding: 24px 24px 40px;
background: linear-gradient(180deg, #f6f3ef 0%, #ffffff 24%, #f8fafc 100%);
box-sizing: border-box;
}
.brochure-page__hero {
display: flex;
flex-direction: column;
gap: 18px;
padding: 30px 24px;
border-radius: 28px;
background: linear-gradient(135deg, #9f6a2d 0%, #d7a25d 60%, #f1d4a6 100%);
box-shadow: 0 18px 42px rgba(159, 106, 45, 0.2);
}
.brochure-page__eyebrow {
font-size: 26px;
line-height: 1.4;
color: rgba(255, 255, 255, 0.9);
font-weight: 600;
}
.brochure-page__title {
font-size: 44px;
line-height: 1.4;
color: #ffffff;
font-weight: 700;
}
.brochure-page__desc {
font-size: 28px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.88);
}
.brochure-page__meta-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.brochure-page__meta-pill {
padding: 10px 18px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.16);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.brochure-page__meta-text {
font-size: 22px;
line-height: 1.4;
color: #ffffff;
font-weight: 600;
}
.brochure-page__stats {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
margin-top: 6px;
}
.brochure-page__stat {
display: flex;
flex-direction: column;
gap: 8px;
padding: 18px 14px;
border-radius: 22px;
background: rgba(255, 255, 255, 0.14);
backdrop-filter: blur(10px);
}
.brochure-page__stat-value {
font-size: 34px;
line-height: 1.2;
color: #ffffff;
font-weight: 700;
}
.brochure-page__stat-label {
font-size: 22px;
line-height: 1.4;
color: rgba(255, 255, 255, 0.82);
}
.brochure-page__section {
display: flex;
flex-direction: column;
gap: 18px;
margin-top: 22px;
}
.brochure-page__section--process {
margin-top: 26px;
}
.brochure-page__section-head,
.brochure-page__contact-head {
display: flex;
flex-direction: column;
gap: 8px;
}
.brochure-page__section-title {
font-size: 34px;
line-height: 1.4;
color: #1f2937;
font-weight: 700;
}
.brochure-page__section-desc {
font-size: 24px;
line-height: 1.7;
color: #6b7280;
}
.brochure-page__solution-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.brochure-page__solution-card,
.brochure-page__highlight-card,
.brochure-page__case-card,
.brochure-page__process-item,
.brochure-page__promise-item,
.brochure-page__contact-card {
border-radius: 24px;
background: #ffffff;
box-shadow: 0 14px 40px rgba(15, 23, 42, 0.08);
}
.brochure-page__solution-card {
display: flex;
flex-direction: column;
gap: 10px;
padding: 22px 20px;
}
.brochure-page__highlight-list,
.brochure-page__case-list,
.brochure-page__process-list,
.brochure-page__promise-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.brochure-page__highlight-card {
display: flex;
gap: 16px;
padding: 22px 20px;
}
.brochure-page__highlight-icon {
display: flex;
align-items: center;
justify-content: center;
width: 72px;
height: 72px;
border-radius: 20px;
flex-shrink: 0;
background: linear-gradient(135deg, #9f6a2d 0%, #d7a25d 100%);
}
.brochure-page__highlight-content,
.brochure-page__case-content,
.brochure-page__process-content,
.brochure-page__promise-content {
display: flex;
flex-direction: column;
gap: 10px;
}
.brochure-page__card-title {
font-size: 30px;
line-height: 1.5;
color: #1f2937;
font-weight: 600;
}
.brochure-page__card-desc {
font-size: 24px;
line-height: 1.7;
color: #6b7280;
}
.brochure-page__tag-list {
display: flex;
flex-wrap: wrap;
gap: 14px;
}
.brochure-page__tag {
padding: 14px 22px;
border-radius: 999px;
background: rgba(159, 106, 45, 0.1);
border: 1px solid rgba(159, 106, 45, 0.14);
}
.brochure-page__tag-text {
font-size: 24px;
line-height: 1.4;
color: #9f6a2d;
font-weight: 600;
}
.brochure-page__promise-item {
display: flex;
gap: 16px;
padding: 22px 20px;
}
.brochure-page__promise-index {
display: flex;
align-items: center;
justify-content: center;
width: 72px;
height: 72px;
border-radius: 18px;
flex-shrink: 0;
background: #f8f1e7;
font-size: 24px;
line-height: 1.2;
color: #9f6a2d;
font-weight: 700;
}
.brochure-page__case-card {
overflow: hidden;
}
.brochure-page__case-visual {
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 8px;
height: 180px;
padding: 22px 20px;
background: linear-gradient(135deg, #c79047 0%, #f0d3a2 100%);
}
.brochure-page__case-index {
font-size: 24px;
line-height: 1.2;
color: rgba(255, 255, 255, 0.86);
font-weight: 700;
}
.brochure-page__case-visual-title {
font-size: 34px;
line-height: 1.4;
color: #ffffff;
font-weight: 700;
}
.brochure-page__case-content {
padding: 22px 20px 24px;
}
.brochure-page__process-item {
display: flex;
gap: 16px;
padding: 22px 20px;
}
.brochure-page__process-step {
display: flex;
align-items: center;
justify-content: center;
width: 72px;
height: 72px;
border-radius: 999px;
background: #f3ede6;
flex-shrink: 0;
}
.brochure-page__process-step-text {
font-size: 24px;
line-height: 1.2;
color: #9f6a2d;
font-weight: 700;
}
.brochure-page__contact-card {
display: flex;
flex-direction: column;
gap: 18px;
margin-top: 26px;
padding: 28px 24px;
}
.brochure-page__cta-title {
font-size: 34px;
line-height: 1.4;
color: #1f2937;
font-weight: 700;
}
.brochure-page__cta-desc,
.brochure-page__cta-tip {
font-size: 24px;
line-height: 1.7;
color: #6b7280;
}
.brochure-page__contact-list {
display: flex;
flex-direction: column;
gap: 14px;
}
.brochure-page__contact-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 18px 20px;
border-radius: 20px;
background: #f8fafc;
}
.brochure-page__contact-label {
font-size: 22px;
line-height: 1.4;
color: #9ca3af;
}
.brochure-page__contact-value {
font-size: 28px;
line-height: 1.6;
color: #1f2937;
font-weight: 600;
}
.brochure-page__cta-actions {
display: flex;
flex-direction: column;
gap: 14px;
}
.brochure-page__button {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
height: 92px;
border-radius: 999px;
}
.brochure-page__button--primary {
background: linear-gradient(135deg, #9f6a2d 0%, #d7a25d 100%);
}
.brochure-page__button--secondary {
background: #f3f4f6;
}
.brochure-page__button--ghost {
background: #fff7ed;
border: 1px solid rgba(159, 106, 45, 0.16);
}
.brochure-page__button-text {
font-size: 28px;
font-weight: 600;
}
.brochure-page__button-text--light {
color: #ffffff;
}
.brochure-page__button-text--dark {
color: #1f2937;
}
.brochure-page__button-text--gold {
color: #9f6a2d;
}

View File

@@ -0,0 +1,385 @@
import React, { useEffect, useState } from 'react'
import Taro, { useShareAppMessage, useShareTimeline } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import {
ShieldCheck,
People,
Star,
Phone,
ArrowRight,
Location
} from '@nutui/icons-react-taro'
import { configWebsiteField } from '@/api/cms/cmsWebsiteField'
import type { Config } from '@/api/cms/cmsWebsiteField/model'
import './index.scss'
const DEFAULT_BRAND_NAME = '南南佐顿门窗'
const DEFAULT_HOTLINE_DISPLAY = '13367810229'
const DEFAULT_HOTLINE = '13367810229'
const DEFAULT_ADDRESS = '欢迎到店咨询门窗定制方案'
const DEFAULT_WORKDAY = '周一至周日 08:30-18:30'
const solutionItems = [
{
title: '系统门窗定制',
description: '适合新房装修、整屋升级,兼顾隔音、保温与颜值表现。'
},
{
title: '阳台封窗升级',
description: '改善通风采光与密封性,让阳台更安全、更好用。'
},
{
title: '别墅门窗方案',
description: '支持大面宽、转角窗与个性化立面设计定制。'
},
{
title: '旧窗改造换新',
description: '针对渗水、噪音、漏风等问题,缩短施工周期,减少打扰。'
}
]
const highlightItems = [
{
icon: <ShieldCheck size={22} color="#ffffff" />,
title: '品质保障',
description: '10年质保精选型材与进口五金兼顾安全、隔音与耐久。'
},
{
icon: <People size={22} color="#ffffff" />,
title: '专业团队',
description: '15年门窗安装经验量尺、设计、施工全流程标准化服务。'
},
{
icon: <Star size={22} color="#ffffff" />,
title: '真实口碑',
description: '5000+家庭选择98%满意度,支持老房换窗与整屋升级。'
}
]
const serviceTags = ['隔音静享', '节能保温', '抗风防水', '儿童安全', '颜值升级', '售后跟进']
const caseItems = [
{
title: '高端住宅',
subtitle: '静音隔热更舒适',
description: '针对高层住宅、改善型家庭,优化隔音、保温与采光表现。'
},
{
title: '商业办公',
subtitle: '兼顾颜值与效率',
description: '满足门店、办公室、展示空间的通透感、安全性与维护便利。'
},
{
title: '别墅定制',
subtitle: '大面宽与个性化设计',
description: '结合建筑立面风格,定制开启方式、型材颜色与细节工艺。'
},
{
title: '旧窗改造',
subtitle: '不大拆也能焕新',
description: '聚焦老房渗水、噪音、密封差等问题,缩短施工周期,减少打扰。'
}
]
const promiseItems = [
{
title: '方案先沟通再报价',
description: '结合房型、预算与使用需求,给出更贴合实际的门窗建议。'
},
{
title: '量尺安装标准化',
description: '从上门测量、下单生产到现场安装,流程更清晰、交付更稳定。'
},
{
title: '售后问题可跟进',
description: '支持使用阶段咨询、五金维护与常见问题排查,减少后顾之忧。'
}
]
const processItems = [
{
step: '01',
title: '需求沟通',
description: '了解房型、预算、风格偏好与使用场景。'
},
{
step: '02',
title: '上门量尺',
description: '安排人员实地测量,核对尺寸与安装条件。'
},
{
step: '03',
title: '方案报价',
description: '输出门窗方案、材质配置与施工报价。'
},
{
step: '04',
title: '安装售后',
description: '规范安装交付,提供后续保养与售后支持。'
}
]
const getDialNumber = (value?: string) => {
const pureNumber = (value || '').replace(/\D/g, '')
return pureNumber || DEFAULT_HOTLINE
}
const BrochurePage: React.FC = () => {
const [config, setConfig] = useState<Config>()
useEffect(() => {
configWebsiteField({})
.then((data) => {
setConfig(data)
})
.catch(() => undefined)
}, [])
const brandName = config?.siteName || config?.loginTitle || DEFAULT_BRAND_NAME
const hotlineText = config?.tel || DEFAULT_HOTLINE_DISPLAY
const hotline = getDialNumber(config?.tel)
const address = config?.address || DEFAULT_ADDRESS
const workDay = config?.workDay || DEFAULT_WORKDAY
useShareTimeline(() => {
return {
title: `${brandName} - 品牌画册`,
path: '/pages/brochure/index'
}
})
useShareAppMessage(() => {
return {
title: `${brandName}|门窗定制安装服务`,
path: '/pages/brochure/index'
}
})
const handleBackHome = () => {
Taro.reLaunch({
url: '/pages/index/index'
})
}
const handleCallPhone = () => {
Taro.showModal({
title: '拨打电话',
content: `是否拨打客服热线 ${hotlineText}`,
confirmText: '拨打',
cancelText: '取消',
success: (res) => {
if (!res.confirm) {
return
}
Taro.makePhoneCall({
phoneNumber: hotline,
fail: () => {
Taro.showToast({
title: '拨号失败,请稍后重试',
icon: 'none'
})
}
})
}
})
}
const handleCopyAddress = () => {
Taro.setClipboardData({
data: address,
success: () => {
Taro.showToast({
title: '地址已复制',
icon: 'none'
})
}
})
}
return (
<View className="brochure-page">
<View className="brochure-page__hero">
<Text className="brochure-page__eyebrow">{brandName}</Text>
<Text className="brochure-page__title"></Text>
<Text className="brochure-page__desc">
</Text>
<View className="brochure-page__meta-list">
<View className="brochure-page__meta-pill">
<Text className="brochure-page__meta-text">10</Text>
</View>
<View className="brochure-page__meta-pill">
<Text className="brochure-page__meta-text"></Text>
</View>
<View className="brochure-page__meta-pill">
<Text className="brochure-page__meta-text"></Text>
</View>
</View>
<View className="brochure-page__stats">
<View className="brochure-page__stat">
<Text className="brochure-page__stat-value">10</Text>
<Text className="brochure-page__stat-label"></Text>
</View>
<View className="brochure-page__stat">
<Text className="brochure-page__stat-value">15</Text>
<Text className="brochure-page__stat-label"></Text>
</View>
<View className="brochure-page__stat">
<Text className="brochure-page__stat-value">5000+</Text>
<Text className="brochure-page__stat-label"></Text>
</View>
</View>
</View>
<View className="brochure-page__section">
<View className="brochure-page__section-head">
<Text className="brochure-page__section-title"></Text>
<Text className="brochure-page__section-desc">便</Text>
</View>
<View className="brochure-page__solution-grid">
{solutionItems.map((item) => (
<View key={item.title} className="brochure-page__solution-card">
<Text className="brochure-page__card-title">{item.title}</Text>
<Text className="brochure-page__card-desc">{item.description}</Text>
</View>
))}
</View>
</View>
<View className="brochure-page__section">
<View className="brochure-page__section-head">
<Text className="brochure-page__section-title"></Text>
<Text className="brochure-page__section-desc">使寿</Text>
</View>
<View className="brochure-page__highlight-list">
{highlightItems.map((item) => (
<View key={item.title} className="brochure-page__highlight-card">
<View className="brochure-page__highlight-icon">{item.icon}</View>
<View className="brochure-page__highlight-content">
<Text className="brochure-page__card-title">{item.title}</Text>
<Text className="brochure-page__card-desc">{item.description}</Text>
</View>
</View>
))}
</View>
</View>
<View className="brochure-page__section">
<View className="brochure-page__section-head">
<Text className="brochure-page__section-title"></Text>
<Text className="brochure-page__section-desc">便</Text>
</View>
<View className="brochure-page__tag-list">
{serviceTags.map((item) => (
<View key={item} className="brochure-page__tag">
<Text className="brochure-page__tag-text">{item}</Text>
</View>
))}
</View>
</View>
<View className="brochure-page__section">
<View className="brochure-page__section-head">
<Text className="brochure-page__section-title"></Text>
<Text className="brochure-page__section-desc"></Text>
</View>
<View className="brochure-page__promise-list">
{promiseItems.map((item, index) => (
<View key={item.title} className="brochure-page__promise-item">
<Text className="brochure-page__promise-index">{`0${index + 1}`}</Text>
<View className="brochure-page__promise-content">
<Text className="brochure-page__card-title">{item.title}</Text>
<Text className="brochure-page__card-desc">{item.description}</Text>
</View>
</View>
))}
</View>
</View>
<View className="brochure-page__section">
<View className="brochure-page__section-head">
<Text className="brochure-page__section-title"></Text>
<Text className="brochure-page__section-desc"></Text>
</View>
<View className="brochure-page__case-list">
{caseItems.map((item, index) => (
<View key={item.title} className="brochure-page__case-card">
<View className="brochure-page__case-visual">
<Text className="brochure-page__case-index">{`0${index + 1}`}</Text>
<Text className="brochure-page__case-visual-title">{item.title}</Text>
</View>
<View className="brochure-page__case-content">
<Text className="brochure-page__card-title">{item.subtitle}</Text>
<Text className="brochure-page__card-desc">{item.description}</Text>
</View>
</View>
))}
</View>
</View>
<View className="brochure-page__section brochure-page__section--process">
<View className="brochure-page__section-head">
<Text className="brochure-page__section-title"></Text>
<Text className="brochure-page__section-desc"></Text>
</View>
<View className="brochure-page__process-list">
{processItems.map((item) => (
<View key={item.step} className="brochure-page__process-item">
<View className="brochure-page__process-step">
<Text className="brochure-page__process-step-text">{item.step}</Text>
</View>
<View className="brochure-page__process-content">
<Text className="brochure-page__card-title">{item.title}</Text>
<Text className="brochure-page__card-desc">{item.description}</Text>
</View>
</View>
))}
</View>
</View>
<View className="brochure-page__contact-card">
<View className="brochure-page__contact-head">
<Text className="brochure-page__cta-title"></Text>
<Text className="brochure-page__cta-desc">线</Text>
</View>
<View className="brochure-page__contact-list">
<View className="brochure-page__contact-item">
<Text className="brochure-page__contact-label">线</Text>
<Text className="brochure-page__contact-value">{hotlineText}</Text>
</View>
<View className="brochure-page__contact-item">
<Text className="brochure-page__contact-label"></Text>
<Text className="brochure-page__contact-value">{workDay}</Text>
</View>
<View className="brochure-page__contact-item">
<Text className="brochure-page__contact-label"></Text>
<Text className="brochure-page__contact-value">{address}</Text>
</View>
</View>
<View className="brochure-page__cta-actions">
<View className="brochure-page__button brochure-page__button--primary" onClick={handleCallPhone}>
<Phone size={18} color="#ffffff" />
<Text className="brochure-page__button-text brochure-page__button-text--light">线</Text>
</View>
<View className="brochure-page__button brochure-page__button--secondary" onClick={handleCopyAddress}>
<Location size={18} color="#1f2937" />
<Text className="brochure-page__button-text brochure-page__button-text--dark"></Text>
</View>
<View className="brochure-page__button brochure-page__button--ghost" onClick={handleBackHome}>
<Text className="brochure-page__button-text brochure-page__button-text--gold"></Text>
<ArrowRight size={16} color="#9f6a2d" />
</View>
</View>
<Text className="brochure-page__cta-tip">线线</Text>
</View>
</View>
)
}
export default BrochurePage

View File

@@ -0,0 +1,36 @@
.brochure-entry {
margin-top: 12px;
}
.brochure-entry__card {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
border-radius: 16px;
background: linear-gradient(135deg, #1d4ed8 0%, #0f766e 100%);
box-shadow: 0 10px 24px rgba(29, 78, 216, 0.18);
}
.brochure-entry__icon {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
flex-shrink: 0;
border-radius: 12px;
background: rgba(255, 255, 255, 0.16);
}
.brochure-entry__content {
flex: 1;
gap: 4px;
}
.brochure-entry__action {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}

View File

@@ -0,0 +1,66 @@
import React, { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import { ImageRectangle, ArrowRight } from '@nutui/icons-react-taro'
import { configWebsiteField } from '@/api/cms/cmsWebsiteField'
import type { Config } from '@/api/cms/cmsWebsiteField/model'
import './BrochureEntry.scss'
const BROCHURE_TITLE = '品牌画册'
const DEFAULT_BROCHURE_URL = 'https://book.yunzhan365.com/mdfy/tjcs/mobile/index.html'
const BrochureEntry: React.FC = () => {
const [config, setConfig] = useState<Config>()
useEffect(() => {
configWebsiteField({})
.then((data) => setConfig(data))
.catch(() => undefined)
}, [])
const handleClick = () => {
const url = config?.domain || DEFAULT_BROCHURE_URL
Taro.setClipboardData({
data: url,
success: () => {
Taro.showModal({
title: '链接已复制',
content: '请前往浏览器,粘贴链接即可查看完整画册。',
showCancel: false,
confirmText: '知道了'
})
},
fail: () => {
Taro.showToast({
title: '复制失败,请稍后重试',
icon: 'none'
})
}
})
}
return (
<View className="brochure-entry px-4" onClick={handleClick}>
<View className="brochure-entry__card">
<View className="brochure-entry__icon">
<ImageRectangle size={22} color="#ffffff" />
</View>
<View className="brochure-entry__content flex flex-col">
<Text className="text-lg font-semibold text-white">{BROCHURE_TITLE}</Text>
<Text className="text-xs text-white">
</Text>
</View>
<View className="brochure-entry__action">
<Text className="text-sm font-semibold text-white"></Text>
<ArrowRight size={14} color="#ffffff" />
</View>
</View>
</View>
)
}
export default BrochureEntry

View File

@@ -11,8 +11,8 @@ const ContactSection: React.FC = () => {
const contactItems = [
{
icon: <Phone size={20} color="#3b82f6" />,
title: '客服热线',
value: '400-888-9999',
title: '联系电话',
value: '13367810229',
action: 'call',
colorClass: 'contact-item--blue'
},
@@ -64,13 +64,13 @@ const ContactSection: React.FC = () => {
const handleCallPhone = () => {
Taro.showModal({
title: '拨打电话',
content: '是否拨打客服热线 400-888-9999',
content: '是否拨打联系电话 13367810229',
confirmText: '拨打',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
Taro.makePhoneCall({
phoneNumber: '4008889999',
phoneNumber: '13367810229',
success: () => {
console.log('拨打电话成功')
},