feat(customer): 新增接待人员选择功能
- 为 ShopDealerApply 模型增加接待人员 ID 和姓名字段 - dealer/customer/add 页面引入 Popup、SearchBar 及图标组件 - 实现接待人员选择弹层及搜索功能 - 表单中新增接待人员展示及清除操作 - 编辑模式下回填接待人员信息 - 提交表单时携带接待人员相关字段 feat(index): 新增首页品牌画册展示组件 - 创建 CatalogShowcase 组件及样式文件 - 展示品牌画册封面及标题说明 - “点击查看”按钮复制链接并提示用户打开浏览器查看 - 在首页主视图添加 CatalogShowcase 组件显示 fix(webview): 优化 webview 页面 URL 获取逻辑 - 使用 useRouter Hook 获取参数替代直接调用 Taro.getCurrentPages -
This commit is contained in:
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)即因此导致,已修复
|
||||||
@@ -48,6 +48,10 @@ export interface ShopDealerApply {
|
|||||||
nickName?: string;
|
nickName?: string;
|
||||||
// 推荐人名称
|
// 推荐人名称
|
||||||
refereeName?: string;
|
refereeName?: string;
|
||||||
|
// 接待人员用户ID
|
||||||
|
receptionistId?: number;
|
||||||
|
// 接待人员姓名
|
||||||
|
receptionistName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useEffect, useState, useRef} from "react";
|
import {useEffect, useState, useRef} from "react";
|
||||||
import {Loading, CellGroup, Cell, Input, Form, Calendar} from '@nutui/nutui-react-taro'
|
import {Loading, CellGroup, Cell, Input, Form, Calendar, Popup, SearchBar} from '@nutui/nutui-react-taro'
|
||||||
import {Edit, Calendar as CalendarIcon} from '@nutui/icons-react-taro'
|
import {Edit, Calendar as CalendarIcon, ArrowRight, Del} from '@nutui/icons-react-taro'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import {useRouter} from '@tarojs/taro'
|
import {useRouter} from '@tarojs/taro'
|
||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
extractDateForCalendar, formatDateForDisplay
|
extractDateForCalendar, formatDateForDisplay
|
||||||
} from "@/utils/dateUtils";
|
} from "@/utils/dateUtils";
|
||||||
import {ShopDealerUser} from "@/api/shop/shopDealerUser/model";
|
import {ShopDealerUser} from "@/api/shop/shopDealerUser/model";
|
||||||
import {getShopDealerUser} from "@/api/shop/shopDealerUser";
|
import {getShopDealerUser, pageShopDealerUser} from "@/api/shop/shopDealerUser";
|
||||||
|
|
||||||
const AddShopDealerApply = () => {
|
const AddShopDealerApply = () => {
|
||||||
const {params} = useRouter();
|
const {params} = useRouter();
|
||||||
@@ -62,6 +62,13 @@ const AddShopDealerApply = () => {
|
|||||||
const [applyTime, setApplyTime] = useState<string>('')
|
const [applyTime, setApplyTime] = useState<string>('')
|
||||||
const [contractTime, setContractTime] = 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) => {
|
const getApplyStatusText = (status?: number) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -133,6 +140,15 @@ const AddShopDealerApply = () => {
|
|||||||
setContractTime(extractDateForCalendar(dealerApply.contractTime))
|
setContractTime(extractDateForCalendar(dealerApply.contractTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 回填接待人员
|
||||||
|
if (dealerApply.receptionistId) {
|
||||||
|
setSelectedReceptionist({
|
||||||
|
userId: dealerApply.receptionistId,
|
||||||
|
dealerName: dealerApply.receptionistName || '',
|
||||||
|
realName: dealerApply.receptionistName || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Taro.setNavigationBarTitle({title: '签约'})
|
Taro.setNavigationBarTitle({title: '签约'})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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天后)
|
// 计算保护期过期时间(15天后)
|
||||||
const calculateExpirationTime = (): string => {
|
const calculateExpirationTime = (): string => {
|
||||||
@@ -455,7 +508,10 @@ const AddShopDealerApply = () => {
|
|||||||
expirationTime: expirationTime,
|
expirationTime: expirationTime,
|
||||||
// 确保日期数据正确提交(使用数据库格式)
|
// 确保日期数据正确提交(使用数据库格式)
|
||||||
applyTime: values.applyTime || (applyTime ? formatDateForDatabase(applyTime) : ''),
|
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>
|
<Form.Item name="mobile" label="手机号" initialValue={FormData?.mobile} required>
|
||||||
<Input placeholder="手机号" disabled={isEditMode} maxLength={11}/>
|
<Input placeholder="手机号" disabled={isEditMode} maxLength={11}/>
|
||||||
</Form.Item>
|
</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 && (
|
{isEditMode && (
|
||||||
<>
|
<>
|
||||||
<Form.Item name="money" label="签约价格" initialValue={FormData?.money} required>
|
<Form.Item name="money" label="签约价格" initialValue={FormData?.money} required>
|
||||||
@@ -628,6 +709,59 @@ const AddShopDealerApply = () => {
|
|||||||
onConfirm={handleContractTimeConfirm}
|
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 && (
|
{isEditMode && (
|
||||||
<CellGroup>
|
<CellGroup>
|
||||||
|
|||||||
109
src/pages/index/CatalogShowcase.scss
Normal file
109
src/pages/index/CatalogShowcase.scss
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
.catalog-showcase {
|
||||||
|
margin: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-header {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-title-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-subtitle {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-preview {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-cover {
|
||||||
|
width: 140px;
|
||||||
|
height: 180px;
|
||||||
|
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-text {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #ffffff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-subtext {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-catalog-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
background: linear-gradient(to right, #3b82f6, #2563eb);
|
||||||
|
border-radius: 22px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-text {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/pages/index/CatalogShowcase.tsx
Normal file
71
src/pages/index/CatalogShowcase.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { View, Text } from '@tarojs/components'
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import { Button } from '@nutui/nutui-react-taro'
|
||||||
|
import { File, 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-showcase">
|
||||||
|
<View className="catalog-header">
|
||||||
|
<View className="catalog-title-bar">
|
||||||
|
<File className="catalog-icon" />
|
||||||
|
<Text className="catalog-title">品牌画册</Text>
|
||||||
|
</View>
|
||||||
|
<Text className="catalog-subtitle">了解南南佐顿门窗的产品与服务</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="catalog-content">
|
||||||
|
<View className="catalog-preview">
|
||||||
|
<View className="catalog-cover">
|
||||||
|
<File className="cover-icon" />
|
||||||
|
<Text className="cover-text">南南佐顿门窗</Text>
|
||||||
|
<Text className="cover-subtext">品牌电子画册</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className="view-catalog-btn"
|
||||||
|
type="primary"
|
||||||
|
onClick={handleViewCatalog}
|
||||||
|
>
|
||||||
|
<Text className="btn-text">点击查看</Text>
|
||||||
|
<ArrowRight className="btn-icon" />
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CatalogShowcase
|
||||||
@@ -14,6 +14,7 @@ import PopUpAd from "@/pages/index/PopUpAd";
|
|||||||
import TrustSection from "./TrustSection";
|
import TrustSection from "./TrustSection";
|
||||||
import CaseShowcase from "./CaseShowcase";
|
import CaseShowcase from "./CaseShowcase";
|
||||||
import ContactSection from "./ContactSection";
|
import ContactSection from "./ContactSection";
|
||||||
|
import CatalogShowcase from "./CatalogShowcase";
|
||||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
||||||
import type {Config} from "@/api/cms/cmsWebsiteField/model";
|
import type {Config} from "@/api/cms/cmsWebsiteField/model";
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ function Home() {
|
|||||||
<BestSellers/>
|
<BestSellers/>
|
||||||
<TrustSection/>
|
<TrustSection/>
|
||||||
<CaseShowcase/>
|
<CaseShowcase/>
|
||||||
|
<CatalogShowcase/>
|
||||||
<ContactSection/>
|
<ContactSection/>
|
||||||
</View>
|
</View>
|
||||||
<PopUpAd />
|
<PopUpAd />
|
||||||
|
|||||||
Reference in New Issue
Block a user