Compare commits
3 Commits
ea4b76fefe
...
25abd81d9f
| Author | SHA1 | Date | |
|---|---|---|---|
| 25abd81d9f | |||
| 0be67bdb91 | |||
| 969bc00b53 |
17
.workbuddy/expert-history.json
Normal file
17
.workbuddy/expert-history.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": 2,
|
||||
"sessions": {
|
||||
"8469bdd5894b41e1ba171a40f33d6a83": [
|
||||
{
|
||||
"expertId": "UiDesigner",
|
||||
"name": "Sam",
|
||||
"profession": "UI设计师",
|
||||
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/01-Design/UiDesigner/UiDesigner.png",
|
||||
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/01-Design/UiDesigner/UiDesigner_zh.md",
|
||||
"usedAt": 1775709039214,
|
||||
"industryId": "all"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lastUpdated": 1775711001059
|
||||
}
|
||||
33
.workbuddy/memory/2026-04-08.md
Normal file
33
.workbuddy/memory/2026-04-08.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 2026-04-08 工作日志
|
||||
|
||||
## dealer/customer/add 新增接待人员选择功能
|
||||
|
||||
- 在 `src/api/shop/shopDealerApply/model/index.ts` 中为 `ShopDealerApply` 接口新增了 `receptionistId`(接待人员用户ID)和 `receptionistName`(接待人员姓名)字段
|
||||
- 在 `src/dealer/customer/add.tsx` 中实现了接待人员选择功能:
|
||||
- 引入 `Popup`、`SearchBar`、`ArrowRight`、`Del` 组件
|
||||
- 引入 `pageShopDealerUser` API
|
||||
- 添加接待人员相关状态(`showReceptionistPicker`、`receptionistList`、`selectedReceptionist` 等)
|
||||
- 在表单手机号字段后新增 `Cell` 显示已选接待人员,支持清除
|
||||
- 底部 `Popup` 弹出层,含搜索框 + 分销商用户列表选择
|
||||
- 编辑模式下自动回填已保存的接待人员信息
|
||||
- 提交时携带 `receptionistId` 和 `receptionistName` 字段
|
||||
|
||||
## 首页新增品牌画册区域
|
||||
|
||||
- 创建 `src/pages/index/CatalogShowcase.tsx` 组件:
|
||||
- 展示品牌画册封面预览
|
||||
- "点击查看"按钮,点击后复制链接并提示用户到浏览器打开
|
||||
- 链接地址:https://book.yunzhan365.com/mdfy/tjcs/mobile/index.html
|
||||
- 创建 `src/pages/index/CatalogShowcase.scss` 样式文件
|
||||
- 在 `src/pages/index/index.tsx` 中引入并添加 `CatalogShowcase` 组件,位于 `CaseShowcase` 和 `ContactSection` 之间
|
||||
|
||||
## pages/webview/index.tsx 修复
|
||||
|
||||
- 原代码 `getUrl()` 在渲染阶段直接调用 `Taro.getCurrentPages()`,数据可能未就绪导致 URL 取不到
|
||||
- 改为 `useRouter()` Hook + `useState` 获取 `params.url`,确保参数可靠后再渲染 web-view
|
||||
- URL 无效时直接 return null 并 toast 提示后返回
|
||||
|
||||
## pages/index/CatalogShowcase.tsx 图标名修复
|
||||
|
||||
- `@nutui/icons-react-taro` 中不存在 `FileText` 图标,正确名称为 `File`
|
||||
- `React error #130`(Element type is undefined)即因此导致,已修复
|
||||
23
.workbuddy/memory/2026-04-09.md
Normal file
23
.workbuddy/memory/2026-04-09.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 2026-04-09 工作日志
|
||||
|
||||
## 首页UI重构 — 去除"豆腐块"布局
|
||||
用户反馈首页过于规整的"豆腐块"布局,要求重新设计。完成以下改动:
|
||||
|
||||
### 设计思路
|
||||
- 打破均匀间距,各模块使用差异化 padding/margin
|
||||
- 去掉公式化的"模块标题+白色卡片"结构
|
||||
- 引入沉浸式视觉区域和横向交互
|
||||
|
||||
### 具体改动
|
||||
1. **index.tsx** — 重构布局结构,引入 Hero 区域概念,Banner+Grid 融为一体
|
||||
2. **index.scss** — 全局样式重写,浅灰背景(#f5f5f7),自定义公告条样式
|
||||
3. **TrustSection** — 从均匀三列改为横向滑动渐变卡片,突出数据亮点(10年/15年/98%)
|
||||
4. **ContactSection** — 从2x2网格改为全宽深色底部(#1e293b→#0f172a),沉浸式设计
|
||||
5. **BestSellers** — 从纵向列表改为横向图文卡片(左图右信息),更紧凑
|
||||
6. **CatalogShowcase** — 从小卡片改为大面积渐变视觉卡片,带装饰性书本图形
|
||||
7. **NoticeBar** — 替换NutUI NoticeBar为自定义轻量公告条
|
||||
|
||||
### 注意事项
|
||||
- `Fire` 图标在 @nutui/icons-react-taro 中不存在,改用 `StarFill`
|
||||
- Banner 组件保留动态数据加载能力,圆角样式通过外层 CSS 控制
|
||||
- Menu 组件已在原代码中 hidden,本次未改动
|
||||
@@ -20,21 +20,21 @@
|
||||
- 邀请码:`src/dealer/qrcode/index`
|
||||
- 导航工具:`src/utils/common.ts` (navTo函数)
|
||||
|
||||
## 首页结构 (2026-04-02 更新)
|
||||
- Header (吸顶搜索栏)
|
||||
- Menu (导航菜单,hidden)
|
||||
- Banner (轮播广告)
|
||||
- Grid (功能菜单)
|
||||
- NoticeBar (公告栏)
|
||||
- **BrochureEntry** (品牌画册入口卡片 — 位于公告栏下方)
|
||||
- BestSellers (热销商品)
|
||||
- **TrustSection** (品牌信任区 - 3列水平布局)
|
||||
- 品质保障:10年质保,德国进口五金
|
||||
- 专业团队:15年安装经验,持证上岗
|
||||
- 客户好评:5000+家庭选择,98%满意度
|
||||
- ~~CaseShowcase~~ (已注释隐藏,待有真实素材后再恢复)
|
||||
- **ContactSection** (联系方式 - 2x2网格布局)
|
||||
- 客服热线、在线咨询、门店地址、关注我们
|
||||
## 首页结构 (2026-04-09 重大重构)
|
||||
- Header (吸顶搜索栏,深色渐变背景)
|
||||
- **Hero区域** (Banner + Grid 融合,圆角过渡)
|
||||
- **NoticeStrip** (自定义轻量公告条,黄色圆点+文字)
|
||||
- **BestSellers** (热销推荐 — 横向图文卡片,左图右信息)
|
||||
- **CatalogShowcase** (品牌画册 — 大面积渐变视觉卡片)
|
||||
- **TrustSection** (品质信任区 — 横向滑动渐变卡片:10年质保/15年经验/98%满意度)
|
||||
- **ContactSection** (联系我们 — 全宽深色沉浸式底部)
|
||||
- PopUpAd (弹窗广告)
|
||||
|
||||
### 设计特点
|
||||
- 非豆腐块布局,差异化间距和视觉层次
|
||||
- 页面背景:#f5f5f7
|
||||
- 底部区域为深色渐变(#1e293b→#0f172a)
|
||||
- ~~CaseShowcase~~ (已注释隐藏)
|
||||
|
||||
## 图标使用注意事项
|
||||
- NutUI图标库中不存在的图标:
|
||||
@@ -45,13 +45,14 @@
|
||||
- 所有图标必须从 `@nutui/icons-react-taro` 导入
|
||||
- 构建前需验证图标名称是否在可用导出列表中
|
||||
|
||||
## 字体大小规范
|
||||
- 微信小程序使用 TailwindCSS 文本类,不使用固定像素值
|
||||
- 主标题:`text-lg font-semibold text-gray-800`
|
||||
- 副标题:`text-sm text-gray-500`
|
||||
- 项目标题:`text-base font-semibold text-gray-800`
|
||||
- 项目描述:`text-xs text-gray-500`
|
||||
- 小文本:`text-xs text-gray-500`
|
||||
## 字体大小规范 (2026-04-09 更新)
|
||||
- 微信小程序端按移动端标准设计,最小辅助文字 13-14px
|
||||
- 标签/辅助:14px
|
||||
- 正文/描述:15-16px
|
||||
- 小标题/按钮文字:16-17px
|
||||
- 区块标题:20-24px
|
||||
- 强调数字(价格、数据):28-36px
|
||||
- 所有图标必须从 `@nutui/icons-react-taro` 导入
|
||||
|
||||
## 画册页正式版 (2026-04-01)
|
||||
- 首页已实际挂载 `src/pages/index/BrochureEntry.tsx` 入口,位置在 Banner 下方。
|
||||
|
||||
@@ -48,6 +48,10 @@ export interface ShopDealerApply {
|
||||
nickName?: string;
|
||||
// 推荐人名称
|
||||
refereeName?: string;
|
||||
// 接待人员用户ID
|
||||
receptionistId?: number;
|
||||
// 接待人员姓名
|
||||
receptionistName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {useEffect, useState, useRef} from "react";
|
||||
import {Loading, CellGroup, Cell, Input, Form, Calendar} from '@nutui/nutui-react-taro'
|
||||
import {Edit, Calendar as CalendarIcon} from '@nutui/icons-react-taro'
|
||||
import {Loading, CellGroup, Cell, Input, Form, Calendar, Popup, SearchBar} from '@nutui/nutui-react-taro'
|
||||
import {Edit, Calendar as CalendarIcon, ArrowRight, Del} from '@nutui/icons-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {useRouter} from '@tarojs/taro'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
extractDateForCalendar, formatDateForDisplay
|
||||
} from "@/utils/dateUtils";
|
||||
import {ShopDealerUser} from "@/api/shop/shopDealerUser/model";
|
||||
import {getShopDealerUser} from "@/api/shop/shopDealerUser";
|
||||
import {getShopDealerUser, pageShopDealerUser} from "@/api/shop/shopDealerUser";
|
||||
|
||||
const AddShopDealerApply = () => {
|
||||
const {params} = useRouter();
|
||||
@@ -62,6 +62,13 @@ const AddShopDealerApply = () => {
|
||||
const [applyTime, setApplyTime] = useState<string>('')
|
||||
const [contractTime, setContractTime] = useState<string>('')
|
||||
|
||||
// 接待人员选择状态
|
||||
const [showReceptionistPicker, setShowReceptionistPicker] = useState<boolean>(false)
|
||||
const [receptionistSearch, setReceptionistSearch] = useState<string>('')
|
||||
const [receptionistList, setReceptionistList] = useState<ShopDealerUser[]>([])
|
||||
const [receptionistLoading, setReceptionistLoading] = useState<boolean>(false)
|
||||
const [selectedReceptionist, setSelectedReceptionist] = useState<ShopDealerUser | null>(null)
|
||||
|
||||
// 获取审核状态文字
|
||||
const getApplyStatusText = (status?: number) => {
|
||||
switch (status) {
|
||||
@@ -133,6 +140,15 @@ const AddShopDealerApply = () => {
|
||||
setContractTime(extractDateForCalendar(dealerApply.contractTime))
|
||||
}
|
||||
|
||||
// 回填接待人员
|
||||
if (dealerApply.receptionistId) {
|
||||
setSelectedReceptionist({
|
||||
userId: dealerApply.receptionistId,
|
||||
dealerName: dealerApply.receptionistName || '',
|
||||
realName: dealerApply.receptionistName || '',
|
||||
})
|
||||
}
|
||||
|
||||
Taro.setNavigationBarTitle({title: '签约'})
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -143,6 +159,43 @@ const AddShopDealerApply = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载接待人员列表
|
||||
const loadReceptionistList = async (keyword?: string) => {
|
||||
setReceptionistLoading(true)
|
||||
try {
|
||||
const res = await pageShopDealerUser({keywords: keyword || '', limit: 50, page: 1})
|
||||
setReceptionistList(res?.list || [])
|
||||
} catch (e) {
|
||||
console.error('加载接待人员失败:', e)
|
||||
} finally {
|
||||
setReceptionistLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开接待人员选择
|
||||
const openReceptionistPicker = () => {
|
||||
setReceptionistSearch('')
|
||||
loadReceptionistList()
|
||||
setShowReceptionistPicker(true)
|
||||
}
|
||||
|
||||
// 搜索接待人员
|
||||
const handleReceptionistSearch = (val: string) => {
|
||||
setReceptionistSearch(val)
|
||||
loadReceptionistList(val)
|
||||
}
|
||||
|
||||
// 选择接待人员
|
||||
const handleSelectReceptionist = (user: ShopDealerUser) => {
|
||||
setSelectedReceptionist(user)
|
||||
setShowReceptionistPicker(false)
|
||||
}
|
||||
|
||||
// 清除接待人员
|
||||
const handleClearReceptionist = () => {
|
||||
setSelectedReceptionist(null)
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
// 计算保护期过期时间(15天后)
|
||||
const calculateExpirationTime = (): string => {
|
||||
@@ -455,7 +508,10 @@ const AddShopDealerApply = () => {
|
||||
expirationTime: expirationTime,
|
||||
// 确保日期数据正确提交(使用数据库格式)
|
||||
applyTime: values.applyTime || (applyTime ? formatDateForDatabase(applyTime) : ''),
|
||||
contractTime: values.contractTime || (contractTime ? formatDateForDatabase(contractTime) : '')
|
||||
contractTime: values.contractTime || (contractTime ? formatDateForDatabase(contractTime) : ''),
|
||||
// 接待人员
|
||||
receptionistId: selectedReceptionist?.userId || undefined,
|
||||
receptionistName: selectedReceptionist ? (selectedReceptionist.realName || selectedReceptionist.dealerName || '') : undefined,
|
||||
};
|
||||
|
||||
// 调试信息
|
||||
@@ -566,6 +622,31 @@ const AddShopDealerApply = () => {
|
||||
<Form.Item name="mobile" label="手机号" initialValue={FormData?.mobile} required>
|
||||
<Input placeholder="手机号" disabled={isEditMode} maxLength={11}/>
|
||||
</Form.Item>
|
||||
{/* 接待人员选择 */}
|
||||
<Cell
|
||||
title="接待人员"
|
||||
extra={
|
||||
<View className="flex items-center">
|
||||
{selectedReceptionist ? (
|
||||
<View className="flex items-center">
|
||||
<Text className="text-sm text-gray-800 mr-2">
|
||||
{selectedReceptionist.realName || selectedReceptionist.dealerName || '已选择'}
|
||||
</Text>
|
||||
<View
|
||||
onClick={(e) => { e.stopPropagation(); handleClearReceptionist(); }}
|
||||
className="flex items-center px-1"
|
||||
>
|
||||
<Del size={14} color="#999"/>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<Text className="text-sm text-gray-400">请选择</Text>
|
||||
)}
|
||||
<ArrowRight size={14} color="#ccc"/>
|
||||
</View>
|
||||
}
|
||||
onClick={openReceptionistPicker}
|
||||
/>
|
||||
{isEditMode && (
|
||||
<>
|
||||
<Form.Item name="money" label="签约价格" initialValue={FormData?.money} required>
|
||||
@@ -628,6 +709,59 @@ const AddShopDealerApply = () => {
|
||||
onConfirm={handleContractTimeConfirm}
|
||||
/>
|
||||
|
||||
{/* 接待人员选择弹出层 */}
|
||||
<Popup
|
||||
visible={showReceptionistPicker}
|
||||
position="bottom"
|
||||
round
|
||||
onClose={() => setShowReceptionistPicker(false)}
|
||||
style={{height: '70%'}}
|
||||
>
|
||||
<View className="flex flex-col h-full">
|
||||
{/* 标题栏 */}
|
||||
<View className="flex items-center justify-between px-4 py-3 border-b border-gray-100">
|
||||
<Text className="text-base font-semibold text-gray-800">选择接待人员</Text>
|
||||
<View onClick={() => setShowReceptionistPicker(false)}>
|
||||
<Text className="text-sm text-blue-500">取消</Text>
|
||||
</View>
|
||||
</View>
|
||||
{/* 搜索框 */}
|
||||
<View className="px-3 py-2">
|
||||
<SearchBar
|
||||
value={receptionistSearch}
|
||||
placeholder="搜索姓名/手机号"
|
||||
onChange={handleReceptionistSearch}
|
||||
/>
|
||||
</View>
|
||||
{/* 列表 */}
|
||||
<View className="flex-1 overflow-y-auto">
|
||||
{receptionistLoading ? (
|
||||
<View className="flex justify-center items-center py-8">
|
||||
<Loading>加载中</Loading>
|
||||
</View>
|
||||
) : receptionistList.length === 0 ? (
|
||||
<View className="flex justify-center items-center py-8">
|
||||
<Text className="text-sm text-gray-400">暂无数据</Text>
|
||||
</View>
|
||||
) : (
|
||||
receptionistList.map((user) => (
|
||||
<Cell
|
||||
key={user.userId}
|
||||
title={user.realName || user.dealerName || '未知'}
|
||||
description={user.mobile || user.dealerPhone || ''}
|
||||
extra={
|
||||
selectedReceptionist?.userId === user.userId ? (
|
||||
<Text className="text-sm text-blue-500">已选</Text>
|
||||
) : null
|
||||
}
|
||||
onClick={() => handleSelectReceptionist(user)}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</Popup>
|
||||
|
||||
{/* 审核状态显示(仅在编辑模式下显示) */}
|
||||
{isEditMode && (
|
||||
<CellGroup>
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
.bestsellers-list {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.bestsellers-item {
|
||||
display: flex;
|
||||
background: #ffffff;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 12px;
|
||||
transition: transform 0.15s;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.985);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ═══ 左侧图片 ═══ */
|
||||
&__img-wrap {
|
||||
width: 140px;
|
||||
min-height: 140px;
|
||||
flex-shrink: 0;
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
&__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ═══ 右侧信息 ═══ */
|
||||
&__info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 12px 12px 10px 14px;
|
||||
min-height: 140px;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
&__comment {
|
||||
font-size: 14px;
|
||||
color: #f59e0b;
|
||||
background: rgba(245, 158, 11, 0.08);
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&__sales {
|
||||
font-size: 14px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
/* ═══ 底部操作栏 ═══ */
|
||||
&__bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-top: auto;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
&__price-wrap {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
&__price-symbol {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
&__price-num {
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
color: #ef4444;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__share-btn {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
background: #f3f4f6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__buy-btn {
|
||||
height: 38px;
|
||||
padding: 0 20px;
|
||||
background: linear-gradient(135deg, #2563eb, #3b82f6);
|
||||
border-radius: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
|
||||
|
||||
Text {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══ 空状态 ═══ */
|
||||
.bestsellers-empty {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
|
||||
&__text {
|
||||
font-size: 15px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,15 @@ const BestSellers = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 处理分享点击
|
||||
const handleShare = (item: ShopGoods) => {
|
||||
setGoods(item);
|
||||
|
||||
// 显示分享选项菜单
|
||||
Taro.showActionSheet({
|
||||
itemList: ['分享给好友', '分享到朋友圈'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
// 分享给好友 - 触发转发
|
||||
Taro.showShareMenu({
|
||||
withShareTicket: true,
|
||||
success: () => {
|
||||
// 提示用户点击右上角分享
|
||||
Taro.showToast({
|
||||
title: '请点击右上角分享给好友',
|
||||
icon: 'none',
|
||||
@@ -40,7 +35,6 @@ const BestSellers = () => {
|
||||
}
|
||||
});
|
||||
} else if (res.tapIndex === 1) {
|
||||
// 分享到朋友圈
|
||||
Taro.showToast({
|
||||
title: '请点击右上角分享到朋友圈',
|
||||
icon: 'none',
|
||||
@@ -58,32 +52,22 @@ const BestSellers = () => {
|
||||
reload()
|
||||
}, [])
|
||||
|
||||
// 分享给好友
|
||||
useShareAppMessage(() => {
|
||||
return {
|
||||
title: goods?.name || '精选商品',
|
||||
path: `/shop/goodsDetail/index?id=${goods?.goodsId}`,
|
||||
imageUrl: goods?.image, // 分享图片
|
||||
imageUrl: goods?.image,
|
||||
success: function (res: any) {
|
||||
console.log('分享成功', res);
|
||||
Taro.showToast({
|
||||
title: '分享成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
Taro.showToast({ title: '分享成功', icon: 'success', duration: 2000 });
|
||||
},
|
||||
fail: function (res: any) {
|
||||
console.log('分享失败', res);
|
||||
Taro.showToast({
|
||||
title: '分享失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
Taro.showToast({ title: '分享失败', icon: 'none', duration: 2000 });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// 分享到朋友圈
|
||||
useShareTimeline(() => {
|
||||
return {
|
||||
title: `${goods?.name || '精选商品'} - 南南佐顿门窗`,
|
||||
@@ -93,49 +77,62 @@ const BestSellers = () => {
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className={'py-1 px-4'}>
|
||||
<View className={'flex flex-col justify-between items-center rounded-lg px-2'}>
|
||||
{list?.map((item, index) => {
|
||||
return (
|
||||
<View key={index} className={'flex flex-col rounded-lg bg-white shadow-sm w-full mb-5'}>
|
||||
<Image src={item.image} mode={'aspectFit'} lazyLoad={false}
|
||||
radius="10px 10px 0 0" height="180"
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
||||
<View className={'flex flex-col p-2 rounded-lg'}>
|
||||
<View>
|
||||
<View className={'car-no text-sm'}>{item.name}</View>
|
||||
<View className={'flex justify-between text-xs py-1'}>
|
||||
<Text className={'text-orange-500'}>{item.comments}</Text>
|
||||
<Text className={'text-gray-400'}>已售 {item.sales}</Text>
|
||||
</View>
|
||||
<View className={'flex justify-between items-center py-2'}>
|
||||
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||
<Text className={'text-xs'}>¥</Text>
|
||||
<Text className={'font-bold text-2xl'}>{item.price}</Text>
|
||||
</View>
|
||||
<View className={'buy-btn'}>
|
||||
<View className={'cart-icon flex items-center'}>
|
||||
<View className="bestsellers-list">
|
||||
{list?.map((item, index) => (
|
||||
<View
|
||||
className={'flex flex-col justify-center items-center text-white px-3 gap-1 text-nowrap whitespace-nowrap cursor-pointer'}
|
||||
onClick={() => handleShare(item)}
|
||||
key={index}
|
||||
className="bestsellers-item"
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}
|
||||
>
|
||||
<Share size={20}/>
|
||||
{/* 左侧商品图 */}
|
||||
<View className="bestsellers-item__img-wrap">
|
||||
<Image
|
||||
src={item.image}
|
||||
mode="aspectFill"
|
||||
lazyLoad={false}
|
||||
className="bestsellers-item__img"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 右侧信息区 */}
|
||||
<View className="bestsellers-item__info">
|
||||
<Text className="bestsellers-item__name">{item.name}</Text>
|
||||
|
||||
<View className="bestsellers-item__tags">
|
||||
<Text className="bestsellers-item__comment">{item.comments}</Text>
|
||||
<Text className="bestsellers-item__sales">已售 {item.sales}</Text>
|
||||
</View>
|
||||
<Text className={'text-white pl-4 pr-5'}
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}>购买
|
||||
</Text>
|
||||
|
||||
<View className="bestsellers-item__bottom">
|
||||
{/* 价格 */}
|
||||
<View className="bestsellers-item__price-wrap">
|
||||
<Text className="bestsellers-item__price-symbol">¥</Text>
|
||||
<Text className="bestsellers-item__price-num">{item.price}</Text>
|
||||
</View>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<View className="bestsellers-item__actions">
|
||||
<View
|
||||
className="bestsellers-item__share-btn"
|
||||
onClick={(e) => { e.stopPropagation(); handleShare(item) }}
|
||||
>
|
||||
<Share size={18} color="#9ca3af" />
|
||||
</View>
|
||||
<View className="bestsellers-item__buy-btn">
|
||||
<Text>购买</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
))}
|
||||
|
||||
{list.length === 0 && (
|
||||
<View className="bestsellers-empty">
|
||||
<Text className="bestsellers-empty__text">暂无热销商品</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default BestSellers
|
||||
|
||||
144
src/pages/index/CatalogShowcase.scss
Normal file
144
src/pages/index/CatalogShowcase.scss
Normal file
@@ -0,0 +1,144 @@
|
||||
.catalog-card {
|
||||
position: relative;
|
||||
margin: 24px 16px 8px;
|
||||
padding: 24px 20px;
|
||||
background: linear-gradient(135deg, #1e3a5f 0%, #2563eb 50%, #3b82f6 100%);
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 32px rgba(37, 99, 235, 0.3);
|
||||
|
||||
&:active {
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
/* ═══ 装饰圆 ═══ */
|
||||
&__deco {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
|
||||
&--1 {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
top: -40px;
|
||||
right: -30px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
&--2 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
bottom: -20px;
|
||||
left: 20%;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══ 内容区 ═══ */
|
||||
&__content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
&__badge {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
font-size: 15px;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
&__cta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-top: 12px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 100px;
|
||||
padding: 8px 16px;
|
||||
align-self: flex-start;
|
||||
backdrop-filter: blur(4px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
&__cta-text {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* ═══ 右侧书本图形 ═══ */
|
||||
&__right {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__book {
|
||||
width: 72px;
|
||||
height: 90px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border-radius: 4px 10px 10px 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
&__book-spine {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 6px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&__book-pages {
|
||||
display: flex;
|
||||
gap: 3px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
&__book-page {
|
||||
width: 4px;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 2px;
|
||||
|
||||
&:nth-child(1) { height: 28px; }
|
||||
&:nth-child(2) { height: 40px; }
|
||||
&:nth-child(3) { height: 32px; }
|
||||
}
|
||||
|
||||
&__book-label {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
68
src/pages/index/CatalogShowcase.tsx
Normal file
68
src/pages/index/CatalogShowcase.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { ArrowRight } from '@nutui/icons-react-taro'
|
||||
import './CatalogShowcase.scss'
|
||||
|
||||
const CATALOG_URL = 'https://book.yunzhan365.com/mdfy/tjcs/mobile/index.html'
|
||||
|
||||
function CatalogShowcase() {
|
||||
const handleViewCatalog = () => {
|
||||
Taro.setClipboardData({
|
||||
data: CATALOG_URL,
|
||||
success: () => {
|
||||
Taro.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
setTimeout(() => {
|
||||
Taro.showModal({
|
||||
title: '提示',
|
||||
content: '链接已复制到剪贴板,请前往浏览器打开查看品牌画册',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
}, 2100)
|
||||
},
|
||||
fail: () => {
|
||||
Taro.showToast({ title: '复制失败,请重试', icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="catalog-card" onClick={handleViewCatalog}>
|
||||
{/* 装饰性背景元素 */}
|
||||
<View className="catalog-card__deco catalog-card__deco--1" />
|
||||
<View className="catalog-card__deco catalog-card__deco--2" />
|
||||
|
||||
<View className="catalog-card__content">
|
||||
<View className="catalog-card__left">
|
||||
<Text className="catalog-card__badge">BRAND CATALOG</Text>
|
||||
<Text className="catalog-card__title">品牌画册</Text>
|
||||
<Text className="catalog-card__desc">
|
||||
了解南南佐顿门窗的完整产品线与定制方案
|
||||
</Text>
|
||||
<View className="catalog-card__cta">
|
||||
<Text className="catalog-card__cta-text">点击查看画册</Text>
|
||||
<ArrowRight size={16} color="#ffffff" />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="catalog-card__right">
|
||||
<View className="catalog-card__book">
|
||||
<View className="catalog-card__book-spine" />
|
||||
<View className="catalog-card__book-pages">
|
||||
<View className="catalog-card__book-page" />
|
||||
<View className="catalog-card__book-page" />
|
||||
<View className="catalog-card__book-page" />
|
||||
</View>
|
||||
<Text className="catalog-card__book-label">2026</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default CatalogShowcase
|
||||
@@ -1,143 +1,95 @@
|
||||
.contact-section {
|
||||
background: #ffffff;
|
||||
padding: 24px 16px;
|
||||
margin: 16px 0;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
padding: 32px 20px 24px;
|
||||
background: linear-gradient(180deg, #1e293b 0%, #0f172a 100%);
|
||||
border-radius: 24px 24px 0 0;
|
||||
color: #ffffff;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&-text {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
/* ═══ 引言区 ═══ */
|
||||
&__intro {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: #f8fafc;
|
||||
border-radius: 12px;
|
||||
|
||||
&:active {
|
||||
background: #f1f5f9;
|
||||
transform: scale(0.98);
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--blue {
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
&--green {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
|
||||
&--orange {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
}
|
||||
|
||||
&--cyan {
|
||||
background: rgba(6, 182, 212, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__item-title {
|
||||
&__intro-title {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
margin-bottom: 4px;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
&__item-value {
|
||||
&__intro-desc {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* ═══ 操作按钮区 ═══ */
|
||||
&__actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
&__action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px 18px;
|
||||
border-radius: 14px;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
&__action--primary {
|
||||
background: linear-gradient(135deg, #3b82f6, #2563eb);
|
||||
box-shadow: 0 4px 16px rgba(59, 130, 246, 0.35);
|
||||
}
|
||||
|
||||
&__action--secondary {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
&__action-text {
|
||||
flex: 1;
|
||||
margin-left: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__action-label {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
&__action-value {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
/* ═══ 底部信息 ═══ */
|
||||
&__footer {
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
&__footer-text {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
line-height: 1.6;
|
||||
|
||||
&:first-child {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式适配
|
||||
@media (max-width: 375px) {
|
||||
.contact-section {
|
||||
padding: 20px 12px;
|
||||
margin: 12px 0;
|
||||
|
||||
&__grid {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&__footer-sub {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
}
|
||||
@@ -8,59 +8,6 @@ import {
|
||||
import './ContactSection.scss'
|
||||
|
||||
const ContactSection: React.FC = () => {
|
||||
const contactItems = [
|
||||
{
|
||||
icon: <Phone size={20} color="#3b82f6" />,
|
||||
title: '联系电话',
|
||||
value: '13367810229',
|
||||
action: 'call',
|
||||
colorClass: 'contact-item--blue'
|
||||
},
|
||||
{
|
||||
icon: <Message size={20} color="#10b981" />,
|
||||
title: '在线咨询',
|
||||
value: '点击立即咨询',
|
||||
action: 'chat',
|
||||
colorClass: 'contact-item--green'
|
||||
},
|
||||
// {
|
||||
// icon: <Location size={20} color="#f59e0b" />,
|
||||
// title: '门店地址',
|
||||
// value: '上海市浦东新区XX路888号',
|
||||
// action: 'map',
|
||||
// colorClass: 'contact-item--orange'
|
||||
// },
|
||||
// {
|
||||
// icon: <Share size={20} color="#06b6d4" />,
|
||||
// title: '关注我们',
|
||||
// value: '南南佐顿门窗',
|
||||
// action: 'wechat',
|
||||
// colorClass: 'contact-item--cyan'
|
||||
// }
|
||||
]
|
||||
|
||||
const handleAction = (action: string) => {
|
||||
switch (action) {
|
||||
case 'call':
|
||||
handleCallPhone()
|
||||
break
|
||||
case 'chat':
|
||||
handleOnlineChat()
|
||||
break
|
||||
case 'map':
|
||||
console.log('查看地图')
|
||||
// TODO: 跳转到地图导航
|
||||
break
|
||||
case 'wechat':
|
||||
console.log('关注公众号')
|
||||
// TODO: 显示公众号二维码
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 拨打电话功能
|
||||
const handleCallPhone = () => {
|
||||
Taro.showModal({
|
||||
title: '拨打电话',
|
||||
@@ -76,10 +23,7 @@ const ContactSection: React.FC = () => {
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('拨打电话失败:', err)
|
||||
Taro.showToast({
|
||||
title: '拨打电话失败',
|
||||
icon: 'none'
|
||||
})
|
||||
Taro.showToast({ title: '拨打电话失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -87,29 +31,19 @@ const ContactSection: React.FC = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 在线咨询功能
|
||||
const handleOnlineChat = () => {
|
||||
// 检查是否已登录
|
||||
Taro.getStorage({
|
||||
key: 'userInfo',
|
||||
success: (_) => {
|
||||
// 用户已登录,跳转到聊天页面
|
||||
Taro.navigateTo({
|
||||
url: '/pages/user/chat/conversation/index',
|
||||
success: () => {
|
||||
console.log('跳转到聊天页面成功')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转失败:', err)
|
||||
Taro.showToast({
|
||||
title: '跳转失败,请稍后重试',
|
||||
icon: 'none'
|
||||
})
|
||||
Taro.showToast({ title: '跳转失败,请稍后重试', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
// 用户未登录,提示登录
|
||||
Taro.showModal({
|
||||
title: '登录提示',
|
||||
content: '需要登录后才能在线咨询,是否立即登录?',
|
||||
@@ -121,10 +55,7 @@ const ContactSection: React.FC = () => {
|
||||
url: '/pages/passport/login',
|
||||
fail: (err) => {
|
||||
console.error('跳转到登录页失败:', err)
|
||||
Taro.showToast({
|
||||
title: '跳转失败',
|
||||
icon: 'none'
|
||||
})
|
||||
Taro.showToast({ title: '跳转失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -135,35 +66,40 @@ const ContactSection: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="contact-section px-4">
|
||||
<View className="contact-section__title flex flex-col">
|
||||
<Text className="text-lg font-semibold text-gray-800">联系我们</Text>
|
||||
<Text className="text-sm text-gray-500">随时为您提供专业服务</Text>
|
||||
</View>
|
||||
|
||||
<View className="contact-section__grid">
|
||||
{contactItems.map((item, index) => (
|
||||
<View
|
||||
key={index}
|
||||
className="contact-section__item"
|
||||
onClick={() => handleAction(item.action)}
|
||||
>
|
||||
<View className={`contact-section__icon ${item.colorClass}`}>
|
||||
{item.icon}
|
||||
</View>
|
||||
<View className="contact-section__content flex flex-col">
|
||||
<Text className="text-xs text-gray-500">{item.title}</Text>
|
||||
<Text className="text-sm font-semibold text-gray-800 truncate">{item.value}</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View className="contact-section__footer">
|
||||
<Text className="text-xs text-gray-500">
|
||||
营业时间:周一至周日 8:30-18:00
|
||||
<View className="contact-section">
|
||||
{/* 顶部引言区 */}
|
||||
<View className="contact-section__intro">
|
||||
<Text className="contact-section__intro-title">联系我们</Text>
|
||||
<Text className="contact-section__intro-desc">
|
||||
随时为您提供专业的门窗定制咨询服务
|
||||
</Text>
|
||||
<Text className="text-xs text-gray-500">
|
||||
</View>
|
||||
|
||||
{/* 操作按钮 — 全宽醒目 */}
|
||||
<View className="contact-section__actions">
|
||||
<View className="contact-section__action contact-section__action--primary" onClick={handleCallPhone}>
|
||||
<Phone size={22} color="#ffffff" />
|
||||
<View className="contact-section__action-text">
|
||||
<Text className="contact-section__action-label">电话咨询</Text>
|
||||
<Text className="contact-section__action-value">13367810229</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="contact-section__action contact-section__action--secondary" onClick={handleOnlineChat}>
|
||||
<Message size={22} color="#3b82f6" />
|
||||
<View className="contact-section__action-text">
|
||||
<Text className="contact-section__action-label">在线咨询</Text>
|
||||
<Text className="contact-section__action-value">点击立即咨询</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 底部信息 */}
|
||||
<View className="contact-section__footer">
|
||||
<Text className="contact-section__footer-text">
|
||||
营业时间:周一至周日 8:30 - 18:00
|
||||
</Text>
|
||||
<Text className="contact-section__footer-sub">
|
||||
节假日照常营业,欢迎随时咨询
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -1,101 +1,94 @@
|
||||
.trust-section {
|
||||
background: #ffffff;
|
||||
padding: 24px 16px;
|
||||
margin: 16px 0;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
padding: 32px 0 24px;
|
||||
background: #f5f5f7;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
&__header {
|
||||
padding: 0 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 32px;
|
||||
&__label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #9ca3af;
|
||||
letter-spacing: 2px;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&-text {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
display: block;
|
||||
/* 横向滑动容器 */
|
||||
&__scroll {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
&__track {
|
||||
display: inline-flex;
|
||||
gap: 12px;
|
||||
padding: 0 20px 8px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
/* 单张渐变卡片 */
|
||||
&__card {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
width: 200px;
|
||||
padding: 20px 16px;
|
||||
border-radius: 16px;
|
||||
color: #ffffff;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
vertical-align: top;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
&__card-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&--blue {
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
&--green {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
|
||||
&--orange {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&__item-title {
|
||||
font-size: 15px;
|
||||
&__card-title {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__item-desc {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式适配
|
||||
@media (max-width: 375px) {
|
||||
.trust-section {
|
||||
padding: 20px 12px;
|
||||
margin: 12px 0;
|
||||
|
||||
&__grid {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
&__card-highlight-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
&__card-highlight {
|
||||
font-size: 36px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&__card-desc {
|
||||
font-size: 15px;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
&__card-sub {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { View, Text, ScrollView } from '@tarojs/components'
|
||||
import {
|
||||
ShieldCheck,
|
||||
People,
|
||||
@@ -10,43 +10,60 @@ import './TrustSection.scss'
|
||||
const TrustSection: React.FC = () => {
|
||||
const trustItems = [
|
||||
{
|
||||
icon: <ShieldCheck size={24} color="#3b82f6" />,
|
||||
icon: <ShieldCheck size={28} color="#ffffff" />,
|
||||
title: '品质保障',
|
||||
description: '10年质保,德国进口五金',
|
||||
colorClass: '--blue'
|
||||
highlight: '10年',
|
||||
description: '质保承诺',
|
||||
subDescription: '德国进口五金配件',
|
||||
bg: 'linear-gradient(135deg, #3b82f6, #2563eb)',
|
||||
},
|
||||
{
|
||||
icon: <People size={24} color="#10b981" />,
|
||||
icon: <People size={28} color="#ffffff" />,
|
||||
title: '专业团队',
|
||||
description: '15年安装经验,持证上岗',
|
||||
colorClass: '--green'
|
||||
highlight: '15年',
|
||||
description: '安装经验',
|
||||
subDescription: '全员持证上岗',
|
||||
bg: 'linear-gradient(135deg, #10b981, #059669)',
|
||||
},
|
||||
{
|
||||
icon: <Star size={24} color="#f59e0b" />,
|
||||
icon: <Star size={28} color="#ffffff" />,
|
||||
title: '客户好评',
|
||||
description: '5000+家庭选择,98%满意度',
|
||||
colorClass: '--orange'
|
||||
highlight: '98%',
|
||||
description: '满意度',
|
||||
subDescription: '5000+家庭信赖之选',
|
||||
bg: 'linear-gradient(135deg, #f59e0b, #d97706)',
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<View className="trust-section">
|
||||
<View className="trust-section__title flex flex-col">
|
||||
<Text className="text-lg font-semibold text-gray-800">南南佐顿 · 品质之选</Text>
|
||||
<Text className="text-sm text-gray-500">专业门窗定制安装服务</Text>
|
||||
<View className="trust-section__header">
|
||||
<Text className="trust-section__label">WHY CHOOSE US</Text>
|
||||
<Text className="trust-section__title">为什么选择南南佐顿</Text>
|
||||
</View>
|
||||
|
||||
<View className="trust-section__grid">
|
||||
<ScrollView
|
||||
className="trust-section__scroll"
|
||||
scrollX
|
||||
enhanced
|
||||
showScrollbar={false}
|
||||
>
|
||||
<View className="trust-section__track">
|
||||
{trustItems.map((item, index) => (
|
||||
<View key={index} className="trust-section__item">
|
||||
<View className={`trust-section__icon trust-section__icon${item.colorClass}`}>
|
||||
<View key={index} className="trust-section__card" style={{background: item.bg}}>
|
||||
<View className="trust-section__card-icon">
|
||||
{item.icon}
|
||||
</View>
|
||||
<Text className="text-base font-semibold text-gray-800">{item.title}</Text>
|
||||
<Text className="text-xs text-gray-500">{item.description}</Text>
|
||||
<Text className="trust-section__card-title">{item.title}</Text>
|
||||
<View className="trust-section__card-highlight-row">
|
||||
<Text className="trust-section__card-highlight">{item.highlight}</Text>
|
||||
<Text className="trust-section__card-desc">{item.description}</Text>
|
||||
</View>
|
||||
<Text className="trust-section__card-sub">{item.subDescription}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,34 +1,135 @@
|
||||
page {
|
||||
//background: url('https://oss.wsdns.cn/20250621/33ca4ca532e647bc918a59d01f5d88a9.jpg?x-oss-process=image/resize,m_fixed,w_2000/quality,Q_90') no-repeat top center;
|
||||
//background-size: 100%;
|
||||
background: linear-gradient(to bottom, #3b82f6, #ffffff);
|
||||
background: #f5f5f7;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
// 底部内容区域统一间距
|
||||
.bottom-content-section {
|
||||
margin: 16px 0;
|
||||
/* ═══ 首页容器 ═══ */
|
||||
.home-page {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
/* ═══ Hero 顶部视觉区 ═══ */
|
||||
|
||||
.hero-banner-wrap {
|
||||
padding: 0 16px;
|
||||
padding-top: 6px;
|
||||
|
||||
/* 让Banner Swiper有圆角 */
|
||||
.nut-swiper {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 32px;
|
||||
.nut-swiper-item {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.buy-btn{
|
||||
height: 70px;
|
||||
background: linear-gradient(to bottom, #2563eb, #3b82f6);
|
||||
/* Hero下方的Grid菜单区 */
|
||||
.hero-grid {
|
||||
margin: 0 16px;
|
||||
margin-top: -12px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
background: #ffffff;
|
||||
|
||||
/* 让NutUI Grid的白色背景更好融入 */
|
||||
.nut-grid {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nut-grid-item__content {
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══ 公告条 — 自定义样式替代NutUI NoticeBar ═══ */
|
||||
.notice-strip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 20px;
|
||||
margin: 0 16px 8px;
|
||||
background: rgba(245, 158, 11, 0.08);
|
||||
border-radius: 8px;
|
||||
gap: 8px;
|
||||
|
||||
&__dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #f59e0b;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 15px;
|
||||
color: #92400e;
|
||||
line-height: 1.5;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══ 热销推荐 ═══ */
|
||||
.section-hot {
|
||||
padding: 20px 0 4px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 16px 14px;
|
||||
}
|
||||
|
||||
&__title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
&__more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
font-size: 15px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══ 通用section间距重置(去掉TrustSection/ContactSection自带的margin) ═══ */
|
||||
.home-page .trust-section,
|
||||
.home-page .contact-section {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* ═══ 底部购买按钮 ═══ */
|
||||
.buy-btn {
|
||||
height: 64px;
|
||||
background: linear-gradient(135deg, #2563eb, #3b82f6);
|
||||
border-radius: 100px;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
.cart-icon{
|
||||
background: linear-gradient(to bottom, #60a5fa, #3b82f6);
|
||||
box-shadow: 0 4px 16px rgba(37, 99, 235, 0.35);
|
||||
|
||||
.cart-icon {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 100px 0 0 100px;
|
||||
height: 70px;
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,22 @@ import Taro from '@tarojs/taro';
|
||||
import {useShareAppMessage, useShareTimeline} from "@tarojs/taro"
|
||||
import {useEffect, useState} from "react";
|
||||
import {getShopInfo} from "@/api/layout";
|
||||
import {NoticeBar} from '@nutui/nutui-react-taro'
|
||||
import {View} from '@tarojs/components'
|
||||
import Menu from "./Menu";
|
||||
import Banner from "./Banner";
|
||||
import './index.scss'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import Grid from "@/pages/index/Grid";
|
||||
import Banner from "./Banner";
|
||||
import PopUpAd from "@/pages/index/PopUpAd";
|
||||
import TrustSection from "./TrustSection";
|
||||
import CaseShowcase from "./CaseShowcase";
|
||||
import ContactSection from "./ContactSection";
|
||||
import BrochureEntry from "./BrochureEntry";
|
||||
import CatalogShowcase from "./CatalogShowcase";
|
||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
||||
import type {Config} from "@/api/cms/cmsWebsiteField/model";
|
||||
import {
|
||||
ArrowRight,
|
||||
StarFill,
|
||||
} from '@nutui/icons-react-taro';
|
||||
import './index.scss'
|
||||
|
||||
function Home() {
|
||||
// 吸顶状态
|
||||
const [config, setConfig] = useState<Config>()
|
||||
|
||||
useShareTimeline(() => {
|
||||
@@ -50,7 +50,6 @@ function Home() {
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 用户点击确认,打开授权设置页面
|
||||
openSetting();
|
||||
}
|
||||
}
|
||||
@@ -58,14 +57,11 @@ function Home() {
|
||||
};
|
||||
|
||||
const openSetting = () => {
|
||||
// Taro.openSetting:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
|
||||
Taro.openSetting({
|
||||
success: (res) => {
|
||||
if (res.authSetting['scope.userInfo']) {
|
||||
// 用户授权成功,可以获取用户信息
|
||||
reload();
|
||||
} else {
|
||||
// 用户拒绝授权,提示授权失败
|
||||
Taro.showToast({
|
||||
title: '授权失败',
|
||||
icon: 'none'
|
||||
@@ -80,29 +76,21 @@ function Home() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// 获取站点信息
|
||||
getShopInfo().then(() => {
|
||||
|
||||
})
|
||||
// 获取配置信息
|
||||
getShopInfo().then(() => {})
|
||||
configWebsiteField({}).then(data => {
|
||||
setConfig(data)
|
||||
})
|
||||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||||
Taro.getSetting({
|
||||
success: (res) => {
|
||||
if (res.authSetting['scope.userInfo']) {
|
||||
// 用户已经授权过,可以直接获取用户信息
|
||||
console.log('用户已经授权过,可以直接获取用户信息')
|
||||
reload();
|
||||
} else {
|
||||
// 用户未授权,需要弹出授权窗口
|
||||
console.log('用户未授权,需要弹出授权窗口')
|
||||
showAuthModal();
|
||||
}
|
||||
}
|
||||
});
|
||||
// 获取用户信息
|
||||
Taro.getUserInfo({
|
||||
success: (res) => {
|
||||
const avatar = res.userInfo.avatarUrl;
|
||||
@@ -113,19 +101,52 @@ function Home() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*<Sticky threshold={0} onChange={() => onSticky(arguments)}>*/}
|
||||
<Header/>
|
||||
{/*</Sticky>*/}
|
||||
<View className={'flex flex-col mt-1'}>
|
||||
<Menu/>
|
||||
<Banner/>
|
||||
<View className={'home-page'}>
|
||||
|
||||
{/* ═══ Hero 区域:Banner 融入头部渐变背景 ═══ */}
|
||||
<View className={'hero-zone my-2'}>
|
||||
<View className={'hero-banner-wrap'}>
|
||||
<Banner />
|
||||
</View>
|
||||
|
||||
{/* 功能菜单 — 直接铺在Banner下方,无卡片包裹 */}
|
||||
<View className={'hero-grid my-4'}>
|
||||
<Grid />
|
||||
<NoticeBar content={config?.NoticeBar || '南南佐顿门窗,专业门窗定制安装服务,10年质保,德国进口五金,5000+家庭选择,98%客户满意度'} />
|
||||
<BrochureEntry />
|
||||
<BestSellers/>
|
||||
<TrustSection/>
|
||||
{/* <CaseShowcase/> */}
|
||||
<ContactSection/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* ═══ 滚动公告条 — 轻量嵌入 ═══ */}
|
||||
<View className={'notice-strip my-4'}>
|
||||
<View className={'notice-strip__dot'} />
|
||||
<Text className={'text-sm'}>
|
||||
{config?.NoticeBar || '南南佐顿门窗,专业门窗定制安装服务,10年质保,德国进口五金,5000+家庭选择'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* ═══ 热销推荐 — 标题行内嵌,无卡片边框 ═══ */}
|
||||
{/*<View className={'section-hot'}>*/}
|
||||
{/* <View className={'section-hot__header'}>*/}
|
||||
{/* <View className={'section-hot__title-wrap'}>*/}
|
||||
{/* <StarFill size={20} color='#ef4444' />*/}
|
||||
{/* <Text className={'section-hot__title'}>热销推荐</Text>*/}
|
||||
{/* </View>*/}
|
||||
{/* <Text className={'section-hot__more'} onClick={() => Taro.navigateTo({url: '/shop/category/index'})}>*/}
|
||||
{/* 更多 <ArrowRight size={14} color='#9ca3af' />*/}
|
||||
{/* </Text>*/}
|
||||
{/* </View>*/}
|
||||
{/* <BestSellers />*/}
|
||||
{/*</View>*/}
|
||||
|
||||
{/* ═══ 品牌画册 — 沉浸式视觉卡片 ═══ */}
|
||||
<CatalogShowcase />
|
||||
|
||||
{/* ═══ 品质信任区 — 横向滑动卡片 ═══ */}
|
||||
<TrustSection />
|
||||
|
||||
{/* ═══ 联系我们 — 全宽底部 ═══ */}
|
||||
<ContactSection />
|
||||
|
||||
</View>
|
||||
<PopUpAd />
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user