Commit f2c18992 authored by GuanHua's avatar GuanHua

feat:企业商城和店铺的积分商城商品接口对接

parent 3fcdf329
...@@ -19,6 +19,14 @@ const shopRoute = { ...@@ -19,6 +19,14 @@ const shopRoute = {
component: '@/pages/lxMall/commodity', component: '@/pages/lxMall/commodity',
}, },
{ {
// 商品搜索
path: `/shop/commodity/search`,
name: 'shopCommoditySearch',
key: 'shopCommoditySearch',
hide: true,
component: '@/pages/lxMall/commodity/search',
},
{
// 积分商城 // 积分商城
path: `/shop/pointsMall`, path: `/shop/pointsMall`,
name: 'shopPointsMall', name: 'shopPointsMall',
......
...@@ -9,9 +9,30 @@ export const MALL_TYPE = { ...@@ -9,9 +9,30 @@ export const MALL_TYPE = {
} }
export enum LAYOUT_TYPE { export enum LAYOUT_TYPE {
/**
* 企业商城
*/
mall = 'mall', mall = 'mall',
/**
* 店铺(店铺商城)
*/
shop = 'shop', shop = 'shop',
channel = 'channel' /**
* 渠道商城
*/
channel = 'channel',
/**
* 企业商城-积分商城
*/
scoreMall = 'scoreMall',
/**
* 店铺-积分兑换
*/
shopScoreMall = 'shopScoreMall',
/**
* 渠道商城-积分兑换
*/
channelScoreMall = 'channelScoreMall',
} }
// 本地环境跳过权限校验 // 本地环境跳过权限校验
...@@ -35,6 +56,10 @@ export enum FILTER_TYPE { ...@@ -35,6 +56,10 @@ export enum FILTER_TYPE {
*/ */
category = 'category', category = 'category',
/** /**
* 分类和属性
*/
categoryAndAttr = 'categoryAndAttr',
/**
* 风格 * 风格
*/ */
style = 'style', style = 'style',
...@@ -83,6 +108,14 @@ export enum FILTER_TYPE { ...@@ -83,6 +108,14 @@ export enum FILTER_TYPE {
*/ */
points = 'points', points = 'points',
/** /**
* 最低积分
*/
minPoints = 'minPoints',
/**
* 最高积分
*/
maxPoints = 'maxPoints',
/**
* 商品名称 * 商品名称
*/ */
name = 'name' name = 'name'
......
...@@ -12,7 +12,7 @@ import { useLocalStore, observer } from 'mobx-react' ...@@ -12,7 +12,7 @@ import { useLocalStore, observer } from 'mobx-react'
import { store } from '@/store' import { store } from '@/store'
import { PublicApi } from '@/services/api' import { PublicApi } from '@/services/api'
import { LAYOUT_TYPE } from '@/constants' import { LAYOUT_TYPE } from '@/constants'
import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services' import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services/SearchApi'
import bannerImg from '@/assets/imgs/banner_2.png' import bannerImg from '@/assets/imgs/banner_2.png'
import arrowDownIcon from '@/assets/imgs/arrow_down.png' import arrowDownIcon from '@/assets/imgs/arrow_down.png'
import arrowDownActiveIcon from '@/assets/imgs/arrow_down_active.png' import arrowDownActiveIcon from '@/assets/imgs/arrow_down_active.png'
...@@ -20,7 +20,9 @@ import styles from './index.less' ...@@ -20,7 +20,9 @@ import styles from './index.less'
interface CommodityPropsType { interface CommodityPropsType {
location: any, location: any,
layoutType: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType: LAYOUT_TYPE,
memberId: number;
shopId: number;
} }
interface filterQuery { interface filterQuery {
...@@ -36,24 +38,24 @@ interface filterQuery { ...@@ -36,24 +38,24 @@ interface filterQuery {
Min?: number; Min?: number;
Max?: number; Max?: number;
priceType?: number; priceType?: number;
storeId?: number;
} }
const Commodity: React.FC<CommodityPropsType> = (props) => { const Commodity: React.FC<CommodityPropsType> = (props) => {
const FilterStore = useLocalStore(() => store.FilterStore) const FilterStore = useLocalStore(() => store.FilterStore)
const { filterList, filterUpdate, filterParam, onDeleteFilterItem, onResetFilter, onFilter, onFilterParamChange } = FilterStore const { filterList, filterUpdate, filterParam, onDeleteFilterItem, onResetFilter, onFilter, onFilterParamChange } = FilterStore
const { layoutType } = props const { layoutType, shopId } = props
const { query: { categoryId, categoryName } } = props.location const { query: { categoryId, categoryName } } = props.location
const [loading, setLoading] = useState<boolean>(true) const [loading, setLoading] = useState<boolean>(true)
const [showType, setShowType] = useState<number>(1) // 展示方式:1:矩阵排列; 2:列表排列 const [showType, setShowType] = useState<number>(1) // 展示方式:1:矩阵排列; 2:列表排列
const [commodityList, setCommodityList] = useState<GetSearchShopEnterpriseGetCommodityListResponseDetail[]>([]) const [commodityList, setCommodityList] = useState<GetSearchShopEnterpriseGetCommodityListResponseDetail[]>([])
const [current, setCurrent] = useState<number>(1) const [current, setCurrent] = useState<number>(1)
const [pageSize, setPageSize] = useState<number>(20) const [pageSize] = useState<number>(20)
const [totalCount, setTotalCount] = useState<number>(0) const [totalCount, setTotalCount] = useState<number>(0)
// const [filterParam, setFilterParam] = useState<filterQuery | {}>({}) const filterConfig = [FILTER_TYPE.commonlyUsed, FILTER_TYPE.categoryAndAttr, FILTER_TYPE.brand, FILTER_TYPE.price, FILTER_TYPE.useArea, FILTER_TYPE.commodityType]
const filterConfig = [FILTER_TYPE.commonlyUsed, FILTER_TYPE.category, FILTER_TYPE.style, FILTER_TYPE.brand, FILTER_TYPE.price, FILTER_TYPE.useArea, FILTER_TYPE.commodityType]
console.log(layoutType, "layoutType")
useEffect(() => { useEffect(() => {
console.log(layoutType, "layoutType")
fetchCommodityList() fetchCommodityList()
}, [filterParam, current]) }, [filterParam, current])
...@@ -89,8 +91,22 @@ const Commodity: React.FC<CommodityPropsType> = (props) => { ...@@ -89,8 +91,22 @@ const Commodity: React.FC<CommodityPropsType> = (props) => {
param = Object.assign(param, filterParam) param = Object.assign(param, filterParam)
} }
setLoading(true) setLoading(true)
let getFn;
switch (layoutType) {
case LAYOUT_TYPE.mall:
getFn = PublicApi.getSearchShopEnterpriseGetCommodityList
break
case LAYOUT_TYPE.shop:
param.storeId = shopId
getFn = PublicApi.getSearchShopStoreGetCommodityList
break
case LAYOUT_TYPE.channel:
getFn = PublicApi.getSearchShopStoreGetCommodityList
break
}
//@ts-ignore //@ts-ignore
PublicApi.getSearchShopEnterpriseGetCommodityList(param).then(res => { getFn(param).then(res => {
setLoading(false) setLoading(false)
if (res.code === 1000) { if (res.code === 1000) {
setCommodityList(res.data.data) setCommodityList(res.data.data)
...@@ -122,7 +138,7 @@ const Commodity: React.FC<CommodityPropsType> = (props) => { ...@@ -122,7 +138,7 @@ const Commodity: React.FC<CommodityPropsType> = (props) => {
<div className={styles.commodity}> <div className={styles.commodity}>
<div className={styles.mall_container}> <div className={styles.mall_container}>
<div className={styles.commodity_container}> <div className={styles.commodity_container}>
<Filter filterConfig={filterConfig} layoutType={layoutType} /> <Filter filterConfig={filterConfig} {...props} />
<div className={styles.commodity_main}> <div className={styles.commodity_main}>
<div className={styles.banner}> <div className={styles.banner}>
<img src={bannerImg} /> <img src={bannerImg} />
......
import React from 'react' import React from 'react'
import cx from 'classnames' import cx from 'classnames'
import { Skeleton } from 'antd' import { Skeleton } from 'antd'
import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services' import { LAYOUT_TYPE } from '@/constants'
import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services/SearchApi'
import creditIcon from '@/assets/imgs/credit_icon.png' import creditIcon from '@/assets/imgs/credit_icon.png'
import styles from './list.less' import styles from './list.less'
interface CommodityListPropsType { interface CommodityListPropsType {
showType: number; showType: number;
commodityList: GetSearchShopEnterpriseGetCommodityListResponseDetail[] commodityList: GetSearchShopEnterpriseGetCommodityListResponseDetail[]
layoutType: 'mall' | 'shop' | 'channel' layoutType: LAYOUT_TYPE
} }
const CommodityList: React.FC<CommodityListPropsType> = (props) => { const CommodityList: React.FC<CommodityListPropsType> = (props) => {
const { showType, commodityList = [], layoutType = 'mall' } = props const { showType, commodityList = [], layoutType = LAYOUT_TYPE.mall } = props
const renderPrice = (commodityItem: GetSearchShopEnterpriseGetCommodityListResponseDetail) => { const renderPrice = (commodityItem: GetSearchShopEnterpriseGetCommodityListResponseDetail) => {
switch (commodityItem.priceType) { switch (commodityItem.priceType) {
...@@ -49,7 +50,7 @@ const CommodityList: React.FC<CommodityListPropsType> = (props) => { ...@@ -49,7 +50,7 @@ const CommodityList: React.FC<CommodityListPropsType> = (props) => {
{ {
commodityList.map((item, index) => ( commodityList.map((item, index) => (
<div key={item.id} className={cx(styles.commodity_list_item, styles.row)}> <div key={item.id} className={cx(styles.commodity_list_item, styles.row)}>
<a href={`/${layoutType === 'channel' ? 'channelmall' : 'shop'}/commodity/detail?id=${item.id}&type=${item.priceType}`} target="_blank"> <a href={`/${layoutType === LAYOUT_TYPE.channel ? 'channelmall' : 'shop'}/commodity/detail?id=${item.id}&type=${item.priceType}&shopId=${btoa(JSON.stringify({ shopId: item.storeId, memberId: item.memberId }))}`} target="_blank">
<div className={styles.goods_img}> <div className={styles.goods_img}>
{ {
item.commodityPic ? <img src={item.commodityPic} /> : <Skeleton.Image style={{ width: 220, height: 220 }} /> item.commodityPic ? <img src={item.commodityPic} /> : <Skeleton.Image style={{ width: 220, height: 220 }} />
...@@ -82,9 +83,11 @@ const CommodityList: React.FC<CommodityListPropsType> = (props) => { ...@@ -82,9 +83,11 @@ const CommodityList: React.FC<CommodityListPropsType> = (props) => {
{ {
commodityList.map((item, index) => ( commodityList.map((item, index) => (
<div key={item.id} className={cx(styles.commodity_list_item, styles.column)}> <div key={item.id} className={cx(styles.commodity_list_item, styles.column)}>
<a href={`/shop/commodity/detail?id=${item.id}&type=${item.priceType}`} target="_blank"> <a href={`/${layoutType === LAYOUT_TYPE.channel ? 'channelmall' : 'shop'}/commodity/detail?id=${item.id}&type=${item.priceType}&shopId=${btoa(JSON.stringify({ shopId: item.storeId, memberId: item.memberId }))}`} target="_blank">
<div className={styles.goods_img}> <div className={styles.goods_img}>
<img src={item.commodityPic || "https://img.alicdn.com/bao/uploaded/i1/691602756/O1CN013mdkHl1WEI92iLR75_!!691602756.jpg_400x400q60.jpg"} /> {
item.commodityPic ? <img src={item.commodityPic} /> : <Skeleton.Image style={{ width: 120, height: 120 }} />
}
</div> </div>
<div className={styles.info_box}> <div className={styles.info_box}>
<div className={styles.info_box_content}> <div className={styles.info_box_content}>
......
...@@ -13,14 +13,16 @@ import { store } from '@/store' ...@@ -13,14 +13,16 @@ import { store } from '@/store'
import { PublicApi } from '@/services/api' import { PublicApi } from '@/services/api'
import { LAYOUT_TYPE } from '@/constants' import { LAYOUT_TYPE } from '@/constants'
import { useLocalStore, observer } from 'mobx-react' import { useLocalStore, observer } from 'mobx-react'
import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services' import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services/SearchApi'
import arrowDownIcon from '@/assets/imgs/arrow_down.png' import arrowDownIcon from '@/assets/imgs/arrow_down.png'
import arrowDownActiveIcon from '@/assets/imgs/arrow_down_active.png' import arrowDownActiveIcon from '@/assets/imgs/arrow_down_active.png'
import styles from './index.less' import styles from './index.less'
interface CommodityPropsType { interface CommodityPropsType {
location: any, location: any,
layoutType: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel,
shopId: number,
shopUrlParam: string
} }
interface filterQuery { interface filterQuery {
...@@ -36,13 +38,13 @@ interface filterQuery { ...@@ -36,13 +38,13 @@ interface filterQuery {
Min?: number; Min?: number;
Max?: number; Max?: number;
priceType?: number; priceType?: number;
storeId?: number;
} }
const CommoditySearch: React.FC<CommodityPropsType> = (props) => { const CommoditySearch: React.FC<CommodityPropsType> = (props) => {
const FilterStore = useLocalStore(() => store.FilterStore) const FilterStore = useLocalStore(() => store.FilterStore)
const { filterList, filterUpdate, filterParam, onDeleteFilterItem, onResetFilter, onFilterParamChange } = FilterStore const { filterList, filterUpdate, filterParam, onDeleteFilterItem, onResetFilter, onFilterParamChange } = FilterStore
const { layoutType } = props const { layoutType, shopId, shopUrlParam } = props
const { query: { search = "" } } = props.location const { query: { search = "" } } = props.location
const [loading, setLoading] = useState<boolean>(true) const [loading, setLoading] = useState<boolean>(true)
const [showType, setShowType] = useState<number>(1) // 展示方式:1:矩阵排列; 2:列表排列 const [showType, setShowType] = useState<number>(1) // 展示方式:1:矩阵排列; 2:列表排列
...@@ -50,8 +52,7 @@ const CommoditySearch: React.FC<CommodityPropsType> = (props) => { ...@@ -50,8 +52,7 @@ const CommoditySearch: React.FC<CommodityPropsType> = (props) => {
const [current, setCurrent] = useState<number>(1) const [current, setCurrent] = useState<number>(1)
const [pageSize, setPageSize] = useState<number>(20) const [pageSize, setPageSize] = useState<number>(20)
const [totalCount, setTotalCount] = useState<number>(0) const [totalCount, setTotalCount] = useState<number>(0)
// const [filterParam, setFilterParam] = useState<filterQuery | {}>({}) const filterConfig = [FILTER_TYPE.commonlyUsed, FILTER_TYPE.category, FILTER_TYPE.brand, FILTER_TYPE.price, FILTER_TYPE.useArea, FILTER_TYPE.commodityType]
const filterConfig = [FILTER_TYPE.commonlyUsed, FILTER_TYPE.category, FILTER_TYPE.style, FILTER_TYPE.brand, FILTER_TYPE.price, FILTER_TYPE.useArea, FILTER_TYPE.commodityType]
useEffect(() => { useEffect(() => {
fetchCommodityList() fetchCommodityList()
...@@ -77,8 +78,22 @@ const CommoditySearch: React.FC<CommodityPropsType> = (props) => { ...@@ -77,8 +78,22 @@ const CommoditySearch: React.FC<CommodityPropsType> = (props) => {
param = Object.assign(param, filterParam) param = Object.assign(param, filterParam)
} }
setLoading(true) setLoading(true)
let getFn;
switch (layoutType) {
case LAYOUT_TYPE.mall:
getFn = PublicApi.getSearchShopEnterpriseGetCommodityList
break
case LAYOUT_TYPE.shop:
param.storeId = shopId
getFn = PublicApi.getSearchShopStoreGetCommodityList
break
case LAYOUT_TYPE.channel:
getFn = PublicApi.getSearchShopStoreGetCommodityList
break
}
//@ts-ignore //@ts-ignore
PublicApi.getSearchShopEnterpriseGetCommodityList(param).then(res => { getFn(param).then(res => {
setLoading(false) setLoading(false)
if (res.code === 1000) { if (res.code === 1000) {
setCommodityList(res.data.data) setCommodityList(res.data.data)
...@@ -115,14 +130,24 @@ const CommoditySearch: React.FC<CommodityPropsType> = (props) => { ...@@ -115,14 +130,24 @@ const CommoditySearch: React.FC<CommodityPropsType> = (props) => {
* 清除搜索 * 清除搜索
*/ */
const handleClearSearch = () => { const handleClearSearch = () => {
history.push('/commodity/search') switch (layoutType) {
case LAYOUT_TYPE.mall:
history.push('/commodity/search')
break
case LAYOUT_TYPE.shop:
history.push(`/shop/commodity/search?shopId=${shopUrlParam}`)
break
case LAYOUT_TYPE.channel:
break
}
} }
return ( return (
<div className={styles.commodity}> <div className={styles.commodity}>
<div className={styles.mall_container}> <div className={styles.mall_container}>
<div className={styles.commodity_container}> <div className={styles.commodity_container}>
<Filter filterConfig={filterConfig} layoutType={layoutType} /> <Filter filterConfig={filterConfig} {...props} />
<div className={styles.commodity_main}> <div className={styles.commodity_main}>
<div className={styles.tool_bar}> <div className={styles.tool_bar}>
<div className={styles.tool_bar_left}> <div className={styles.tool_bar_left}>
......
...@@ -164,14 +164,23 @@ const CommodityDetail = (props) => { ...@@ -164,14 +164,23 @@ const CommodityDetail = (props) => {
<Exhibition /> <Exhibition />
<div className={styles.product_info_container}> <div className={styles.product_info_container}>
<div className={styles.product_info}> <div className={styles.product_info}>
<div className={styles.product_info_name}>{commodityDetail?.name}</div> <div className={styles.product_info_name}>
<div className={styles.product_info_tags}> <span>{commodityDetail?.name}</span>
{ {
commodityDetail?.sellingPoint.map((item, index) => ( commodityDetail?.sellingPoint && commodityDetail?.sellingPoint.length > 0 && (
<div className={styles.product_info_tags_item} key={`product_info_tags_item_${index}`}>{item}</div> <>
)) {
commodityDetail?.sellingPoint.map((item, index) => (
<span key={`product_info_tags_item_${index}`}>{item}{index !== commodityDetail?.sellingPoint.length - 1 ? ' ' : ''}</span>
))
}
</>
)
} }
</div> </div>
<div className={styles.product_info_tags}>
<div className={styles.product_info_tags_item} >{commodityDetail?.slogan}</div>
</div>
{ {
commodityDetail?.priceType === COMMODITY_TYPE.prompt && ( commodityDetail?.priceType === COMMODITY_TYPE.prompt && (
<div className={styles.prompt_goods_price}> <div className={styles.prompt_goods_price}>
...@@ -202,7 +211,6 @@ const CommodityDetail = (props) => { ...@@ -202,7 +211,6 @@ const CommodityDetail = (props) => {
<div className={styles.count}>≥100</div> <div className={styles.count}>≥100</div>
</div> </div>
</div> </div>
</div> </div>
) )
} }
...@@ -286,8 +294,8 @@ const CommodityDetail = (props) => { ...@@ -286,8 +294,8 @@ const CommodityDetail = (props) => {
<div className={styles.product_info_line_label}>{commodityDetail?.priceType === COMMODITY_TYPE.prompt ? '购买数量' : '兑换数量'}</div> <div className={styles.product_info_line_label}>{commodityDetail?.priceType === COMMODITY_TYPE.prompt ? '购买数量' : '兑换数量'}</div>
<div className={cx(styles.product_info_line_brief, styles.row)}> <div className={cx(styles.product_info_line_brief, styles.row)}>
<InputNumber value={buyCount} onChange={(value) => setBuyCount(value)} /> <InputNumber value={buyCount} onChange={(value) => setBuyCount(value)} />
<span className={cx(styles.text, styles.mar_left_10)}>平方英尺</span> <span className={cx(styles.text, styles.mar_left_10)}>{commodityDetail?.unitName}</span>
<span className={cx(styles.text, styles.mar_left_10)}>(库存20,000平方英尺)</span> <span className={cx(styles.text, styles.mar_left_10)}>(库存20,000{commodityDetail?.unitName})</span>
</div> </div>
</div> </div>
) )
...@@ -295,7 +303,7 @@ const CommodityDetail = (props) => { ...@@ -295,7 +303,7 @@ const CommodityDetail = (props) => {
{ {
commodityDetail?.priceType === COMMODITY_TYPE.prompt && ( commodityDetail?.priceType === COMMODITY_TYPE.prompt && (
<div className={styles.product_info_price}> <div className={styles.product_info_price}>
<div className={styles.product_info_price_text}>3<span>平方英尺</span></div> <div className={styles.product_info_price_text}>{buyCount}<span>{commodityDetail?.unitName}</span></div>
<div className={styles.product_info_price_split}></div> <div className={styles.product_info_price_split}></div>
<div className={styles.product_info_price_text}>69.70<span></span></div> <div className={styles.product_info_price_text}>69.70<span></span></div>
</div> </div>
......
...@@ -7,51 +7,36 @@ import styles from './index.less' ...@@ -7,51 +7,36 @@ import styles from './index.less'
interface BrandPropsType { interface BrandPropsType {
FilterStore?: any; FilterStore?: any;
layoutType?: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType?: LAYOUT_TYPE,
shopId?: number
} }
const Brand: React.FC<BrandPropsType> = (props) => { const Brand: React.FC<BrandPropsType> = (props) => {
const { layoutType = LAYOUT_TYPE.mall } = props const { layoutType = LAYOUT_TYPE.mall, shopId } = props
const { onFilter, filterList } = props.FilterStore const { onFilter, filterList } = props.FilterStore
const [brandList, setBrandList] = useState<GetSearchShopEnterpriseGetBrandResponse>([]) const [brandList, setBrandList] = useState<GetSearchShopEnterpriseGetBrandResponse>([])
let mock_brand_list = [
{
id: 1,
name: '1M',
brandUrl: 'https://img.alicdn.com/i2/2/TB1GJzSbQfb_uJjSsrbXXb6bVXa?abtest=&pos=1&abbucket=&acm=09042.1003.1.1200415&scm=1007.13029.131809.100200300000000_200x200q100.jpg_.webp'
},
{
id: 2,
name: '2M',
brandUrl: 'https://img.alicdn.com/i2/2/TB1GJzSbQfb_uJjSsrbXXb6bVXa?abtest=&pos=1&abbucket=&acm=09042.1003.1.1200415&scm=1007.13029.131809.100200300000000_200x200q100.jpg_.webp'
},
{
id: 3,
name: '3M',
brandUrl: 'https://img.alicdn.com/i2/2/TB1GJzSbQfb_uJjSsrbXXb6bVXa?abtest=&pos=1&abbucket=&acm=09042.1003.1.1200415&scm=1007.13029.131809.100200300000000_200x200q100.jpg_.webp'
},
{
id: 4,
name: '4M',
brandUrl: 'https://img.alicdn.com/i2/2/TB1GJzSbQfb_uJjSsrbXXb6bVXa?abtest=&pos=1&abbucket=&acm=09042.1003.1.1200415&scm=1007.13029.131809.100200300000000_200x200q100.jpg_.webp'
},
]
useEffect(() => { useEffect(() => {
let getBrandFn
let param: any = {}
switch (layoutType) { switch (layoutType) {
case LAYOUT_TYPE.mall: case LAYOUT_TYPE.mall:
PublicApi.getSearchShopEnterpriseGetBrand().then((res) => { getBrandFn = PublicApi.getSearchShopEnterpriseGetBrand
if (res.code === 1000) {
setBrandList(res.data)
}
})
break break
case LAYOUT_TYPE.shop: case LAYOUT_TYPE.shop:
param.storeId = shopId
getBrandFn = PublicApi.getSearchShopStoreGetBrand
break break
case LAYOUT_TYPE.channel: case LAYOUT_TYPE.channel:
param.storeId = shopId
getBrandFn = PublicApi.getSearchShopStoreGetBrand
break break
} }
getBrandFn(param).then((res) => {
if (res.code === 1000) {
setBrandList(res.data)
}
})
}, [layoutType]) }, [layoutType])
const handleSelectBrand = (brandInfo) => { const handleSelectBrand = (brandInfo) => {
......
...@@ -72,4 +72,53 @@ ...@@ -72,4 +72,53 @@
} }
} }
} }
}
.filter_style {
padding: 15px 20px 8px 20px;
:global {
.ant-checkbox-group-item {
display: block;
margin-bottom: 12px;
}
.ant-checkbox-wrapper {
font-size: 12px;
}
.ant-checkbox-checked::after {
border: 1px solid var(--mall_main_color);
}
.ant-checkbox-input {
&:active,
&:hover,
&:focus {
+.ant-checkbox-inner {
border-color: var(--mall_main_color);
}
}
}
.ant-checkbox-group-item {
&:hover,
&:active {
.ant-checkbox-inner {
border-color: var(--mall_main_color);
}
}
}
.ant-checkbox-checked .ant-checkbox-inner {
background-color: var(--mall_main_color);
border-color: var(--mall_main_color);
}
}
} }
\ No newline at end of file
import React, { useEffect, useState } from 'react' import React, { useEffect, useState, Fragment } from 'react'
import { Tree } from 'antd' import { Tree, Checkbox } from 'antd'
import FilterBox from '../FilterBox' import FilterBox from '../FilterBox'
import { LAYOUT_TYPE, FILTER_TYPE } from '@/constants' import { LAYOUT_TYPE, FILTER_TYPE } from '@/constants'
import { inject, observer } from 'mobx-react' import { PublicApi } from '@/services/api'
import isEmpty from 'lodash/isEmpty' import isEmpty from 'lodash/isEmpty'
import styles from './index.less' import styles from './index.less'
const CheckboxGroup = Checkbox.Group
interface CategoryPropsType { interface CategoryPropsType {
CategoryStore?: any;
FilterStore?: any; FilterStore?: any;
layoutType?: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType?: LAYOUT_TYPE
shopId?: number;
showAttr?: boolean
} }
const Category: React.FC<CategoryPropsType> = (props) => { const Category: React.FC<CategoryPropsType> = (props) => {
const { CategoryStore: { enterpriseCategoryList, storeCategoryList, fetchEnterpriseCategoryList, fetchStoreCategoryList }, layoutType = LAYOUT_TYPE.mall } = props const { layoutType = LAYOUT_TYPE.mall, shopId, showAttr = false } = props
const { onFilter, filterList } = props.FilterStore const { onFilter, filterList } = props.FilterStore
const [selectedKeys, setSelectedKeys] = useState<string[]>([]) const [selectedKeys, setSelectedKeys] = useState<string[]>([])
const [expandedKeys, setExpandedKeys] = useState<string[]>([]) const [expandedKeys, setExpandedKeys] = useState<string[]>([])
const [treeData, setTreeData] = useState<any>([]) const [categoryList, setCategoryList] = useState<any>([])
const [lastCategoryId, setLastCategoryId] = useState<number>()
const [attributeList, setAttributeList] = useState<any>([])
useEffect(() => { useEffect(() => {
console.log(layoutType, "layoutType")
if (isEmpty(filterList)) { if (isEmpty(filterList)) {
setSelectedKeys([]) setSelectedKeys([])
} else { } else {
...@@ -34,36 +41,70 @@ const Category: React.FC<CategoryPropsType> = (props) => { ...@@ -34,36 +41,70 @@ const Category: React.FC<CategoryPropsType> = (props) => {
}, [filterList]) }, [filterList])
useEffect(() => { useEffect(() => {
let getCategoryListFn
let param: any = {}
switch (layoutType) { switch (layoutType) {
case LAYOUT_TYPE.mall: case LAYOUT_TYPE.mall:
fetchEnterpriseCategoryList() getCategoryListFn = PublicApi.getSearchShopEnterpriseGetCategoryTree
break break
case LAYOUT_TYPE.shop: case LAYOUT_TYPE.shop:
param.storeId = shopId
getCategoryListFn = PublicApi.getSearchShopStoreGetCustomerCategoryTree
break break
case LAYOUT_TYPE.channel: case LAYOUT_TYPE.channel:
fetchStoreCategoryList() param.storeId = shopId
getCategoryListFn = PublicApi.getSearchShopStoreGetCustomerCategoryTree
break
case LAYOUT_TYPE.scoreMall:
getCategoryListFn = PublicApi.getSearchShopScoreGetCategoryTree
break
case LAYOUT_TYPE.shopScoreMall:
param.storeId = shopId
getCategoryListFn = PublicApi.getSearchShopScoreGetCategoryTree
break
default:
break break
} }
getCategoryListFn && getCategoryListFn(param).then((res) => {
if (res.code === 1000) {
setCategoryList(initTreeData(res.data))
}
})
}, [layoutType]) }, [layoutType])
useEffect(() => { useEffect(() => {
if (!isEmpty(enterpriseCategoryList) || !isEmpty(storeCategoryList)) { if (lastCategoryId) {
let param = {
categoryId: lastCategoryId
}
let getAttributeFn
switch (layoutType) { switch (layoutType) {
case LAYOUT_TYPE.mall: case LAYOUT_TYPE.mall:
initTreeData(enterpriseCategoryList) getAttributeFn = PublicApi.getSearchShopEnterpriseGetAttributeByCategoryId
break break;
case LAYOUT_TYPE.shop: case LAYOUT_TYPE.shop:
break getAttributeFn = PublicApi.getSearchShopStoreGetCustomerAttributeByCategoryId
break;
case LAYOUT_TYPE.channel: case LAYOUT_TYPE.channel:
initTreeData(storeCategoryList) getAttributeFn = PublicApi.getSearchShopStoreGetCustomerAttributeByCategoryId
break break;
} }
getAttributeFn(param).then(res => {
if (res.code === 1000) {
}
})
} }
}, [lastCategoryId])
}, [enterpriseCategoryList, storeCategoryList])
const initTreeData = (list: any) => { const initTreeData = (list: any) => {
if (!list) {
return []
}
let initExpandKeys = [] let initExpandKeys = []
let flag = true
let result: any = list.map(item => { let result: any = list.map(item => {
initExpandKeys.push(item.id) initExpandKeys.push(item.id)
return { return {
...@@ -75,8 +116,13 @@ const Category: React.FC<CategoryPropsType> = (props) => { ...@@ -75,8 +116,13 @@ const Category: React.FC<CategoryPropsType> = (props) => {
title: secondCategoryItem.title, title: secondCategoryItem.title,
key: secondCategoryItem.id, key: secondCategoryItem.id,
children: secondCategoryItem.children.map(thirdCategoryItem => { children: secondCategoryItem.children.map(thirdCategoryItem => {
if (!lastCategoryId && flag) {
flag = false
setLastCategoryId(thirdCategoryItem.id)
}
return { return {
title: <span className={styles.sub_category_title}>{thirdCategoryItem.title}</span>, title: <span className={styles.sub_category_title}>{thirdCategoryItem.title}</span>,
isLastNode: true,
key: thirdCategoryItem.id, key: thirdCategoryItem.id,
children: [] children: []
} }
...@@ -85,13 +131,19 @@ const Category: React.FC<CategoryPropsType> = (props) => { ...@@ -85,13 +131,19 @@ const Category: React.FC<CategoryPropsType> = (props) => {
}) })
} }
}) })
setTreeData(result)
return result
} }
const handleSelect = (selectedKeys, info) => { const handleSelect = (selectedKeys, info) => {
const { title } = info.node const { title, isLastNode } = info.node
console.log(info)
setSelectedKeys(selectedKeys) setSelectedKeys(selectedKeys)
console.log(selectedKeys, "selectedKeys") if (isLastNode) {
if (lastCategoryId !== selectedKeys[0]) {
setLastCategoryId(selectedKeys[0])
}
}
onFilter({ onFilter({
type: 'category', type: 'category',
key: selectedKeys, key: selectedKeys,
...@@ -103,21 +155,44 @@ const Category: React.FC<CategoryPropsType> = (props) => { ...@@ -103,21 +155,44 @@ const Category: React.FC<CategoryPropsType> = (props) => {
setExpandedKeys(expandedKeys) setExpandedKeys(expandedKeys)
} }
const styleOptions = [
{ label: '荔枝纹', value: '1' },
{ label: '网纹', value: '2' },
{ label: '自然摔纹', value: '3' },
];
const handleChange = (e) => {
console.log(e)
}
return ( return (
<FilterBox <Fragment>
title="分类" <FilterBox
> title="分类"
<div className={styles.filter_category}> >
<Tree <div className={styles.filter_category}>
expandedKeys={expandedKeys} <Tree
selectedKeys={selectedKeys} expandedKeys={expandedKeys}
onSelect={handleSelect} selectedKeys={selectedKeys}
treeData={treeData} onSelect={handleSelect}
onExpand={handleExpand} treeData={categoryList}
/> onExpand={handleExpand}
</div> />
</FilterBox> </div>
</FilterBox>
{
showAttr && attributeList.length > 0 && (
<FilterBox
title="风格"
>
<div className={styles.filter_style}>
<CheckboxGroup options={styleOptions} onChange={handleChange} />
</div>
</FilterBox>
)
}
</Fragment>
) )
} }
export default inject('CategoryStore')(observer(Category)) export default Category
...@@ -7,7 +7,7 @@ import styles from './index.less' ...@@ -7,7 +7,7 @@ import styles from './index.less'
interface CommodityTypePropsType { interface CommodityTypePropsType {
FilterStore?: any; FilterStore?: any;
layoutType?: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType?: LAYOUT_TYPE;
} }
const CheckboxGroup = Checkbox.Group const CheckboxGroup = Checkbox.Group
......
import React, { useState } from 'react' import React, { useState } from 'react'
import { Slider } from 'antd' import { Slider } from 'antd'
import { LAYOUT_TYPE, FILTER_TYPE } from '@/constants'
import FilterBox from '../FilterBox' import FilterBox from '../FilterBox'
import './index.less' import './index.less'
interface PointsPropsType { interface PricePropsType {
FilterStore?: any;
layoutType?: LAYOUT_TYPE
} }
const Points: React.FC<PointsPropsType> = (props) => { const Points: React.FC<PricePropsType> = (props) => {
const [priceRange, setPriceRange] = useState<any>([0, 1000]) const { onFilter } = props.FilterStore
const [pointsRange, setPointsRange] = useState<any>([0, 900])
const handlePriceChange = (value) => { const handlePriceChange = (value) => {
setPriceRange(value) setPointsRange(value)
}
const filterMinPoints = (min: number, state: boolean = true) => {
onFilter({
type: FILTER_TYPE.minPoints,
title: <span className="price_text">最低 <b>{min}</b></span>,
key: state ? min : null
})
}
const filterMaxPoints = (max: number, state: boolean = true) => {
onFilter({
type: FILTER_TYPE.maxPoints,
title: <span className="price_text">最高 <b>{max}</b></span>,
key: state ? max : null
})
}
const handleConfirmpointsRange = () => {
let min = pointsRange[0]
let max = pointsRange[1]
if (min === 900) {
filterMinPoints(min)
} else if (min === 0 && max !== 900) {
filterMinPoints(min, false)
filterMaxPoints(max)
} else if (min !== 0 && max === 900) {
filterMinPoints(min)
filterMaxPoints(max, false)
} else if ((min === 0 && max === 900) || (min !== 0 && max !== 900)) {
filterMinPoints(min)
filterMaxPoints(max)
}
} }
return ( return (
...@@ -19,15 +55,15 @@ const Points: React.FC<PointsPropsType> = (props) => { ...@@ -19,15 +55,15 @@ const Points: React.FC<PointsPropsType> = (props) => {
title="所需积分范围" title="所需积分范围"
> >
<div className="filter_price"> <div className="filter_price">
<Slider range step={1} min={0} max={1000} value={priceRange} onChange={handlePriceChange} /> <Slider range step={1} min={0} max={900} value={pointsRange} onChange={handlePriceChange} />
<div className="price_box"> <div className="price_box">
<span className="price_box_brief">积分:</span> <span className="price_box_brief">积分:</span>
<div className="price_range"> <div className="price_range">
<span className="price">{priceRange[0]}</span> <span className="price">{pointsRange[0]}</span>
<span className="split">-</span> <span className="split">-</span>
<span className="price">{priceRange[1]}</span> <span className="price">{pointsRange[0] === 900 ? '' : `${pointsRange[1]}`}</span>
</div> </div>
<div className="confirm_btn">确定</div> <div className="confirm_btn" onClick={() => handleConfirmpointsRange()}>确定</div>
</div> </div>
</div> </div>
</FilterBox> </FilterBox>
......
...@@ -6,12 +6,11 @@ import './index.less' ...@@ -6,12 +6,11 @@ import './index.less'
interface PricePropsType { interface PricePropsType {
FilterStore?: any; FilterStore?: any;
layoutType?: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType?: LAYOUT_TYPE
} }
const Price: React.FC<PricePropsType> = (props) => { const Price: React.FC<PricePropsType> = (props) => {
const { layoutType = LAYOUT_TYPE.mall } = props const { onFilter } = props.FilterStore
const { onFilter, filterList } = props.FilterStore
const [priceRange, setPriceRange] = useState<any>([0, 900]) const [priceRange, setPriceRange] = useState<any>([0, 900])
const handlePriceChange = (value) => { const handlePriceChange = (value) => {
......
...@@ -9,7 +9,8 @@ import styles from './index.less' ...@@ -9,7 +9,8 @@ import styles from './index.less'
interface UseAreaPropsType { interface UseAreaPropsType {
FilterStore?: any; FilterStore?: any;
layoutType?: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType?: LAYOUT_TYPE;
shopId?: number;
} }
...@@ -38,7 +39,7 @@ interface useAreaType { ...@@ -38,7 +39,7 @@ interface useAreaType {
} }
const UseArea: React.FC<UseAreaPropsType> = (props) => { const UseArea: React.FC<UseAreaPropsType> = (props) => {
const { layoutType = LAYOUT_TYPE.mall } = props const { layoutType = LAYOUT_TYPE.mall, shopId } = props
const { onFilter, filterList } = props.FilterStore const { onFilter, filterList } = props.FilterStore
const [areaList, setAreaList] = useState<useAreaType[]>([]) const [areaList, setAreaList] = useState<useAreaType[]>([])
const [selectCity, setSelectCity] = useState<string[]>([]) const [selectCity, setSelectCity] = useState<string[]>([])
...@@ -60,20 +61,27 @@ const UseArea: React.FC<UseAreaPropsType> = (props) => { ...@@ -60,20 +61,27 @@ const UseArea: React.FC<UseAreaPropsType> = (props) => {
}, [filterList]) }, [filterList])
useEffect(() => { useEffect(() => {
let getAreaFn
let param: any = {}
switch (layoutType) { switch (layoutType) {
case LAYOUT_TYPE.mall: case LAYOUT_TYPE.mall:
PublicApi.getSearchShopEnterpriseGetArea().then((res) => { getAreaFn = PublicApi.getSearchShopEnterpriseGetArea
if (res.code === 1000) {
setAreaList(initAreaData(res.data))
}
})
break break
case LAYOUT_TYPE.shop: case LAYOUT_TYPE.shop:
param.storeId = shopId
getAreaFn = PublicApi.getSearchShopStoreGetArea
break break
case LAYOUT_TYPE.channel: case LAYOUT_TYPE.channel:
param.storeId = shopId
getAreaFn = PublicApi.getSearchShopStoreGetArea
break break
} }
getAreaFn(param).then((res) => {
if (res.code === 1000) {
setAreaList(initAreaData(res.data))
}
})
}, [layoutType]) }, [layoutType])
const initAreaData = (data: GetSearchShopEnterpriseGetAreaResponse) => { const initAreaData = (data: GetSearchShopEnterpriseGetAreaResponse) => {
......
...@@ -17,7 +17,7 @@ import './index.less' ...@@ -17,7 +17,7 @@ import './index.less'
interface FilterPropsType { interface FilterPropsType {
filterConfig?: string[], filterConfig?: string[],
layoutType?: LAYOUT_TYPE.mall | LAYOUT_TYPE.shop | LAYOUT_TYPE.channel layoutType?: LAYOUT_TYPE
} }
const Filter: React.FC<FilterPropsType> = (props) => { const Filter: React.FC<FilterPropsType> = (props) => {
...@@ -31,8 +31,8 @@ const Filter: React.FC<FilterPropsType> = (props) => { ...@@ -31,8 +31,8 @@ const Filter: React.FC<FilterPropsType> = (props) => {
return <CommonlyUsed key={type} {...props} /> return <CommonlyUsed key={type} {...props} />
case FILTER_TYPE.category: case FILTER_TYPE.category:
return <Category key={type} {...props} /> return <Category key={type} {...props} />
case FILTER_TYPE.style: case FILTER_TYPE.categoryAndAttr:
return <Style key={type} {...props} /> return <Category key={type} {...props} showAttr={true} />
case FILTER_TYPE.brand: case FILTER_TYPE.brand:
return <Brand key={type} {...props} /> return <Brand key={type} {...props} />
case FILTER_TYPE.price: case FILTER_TYPE.price:
......
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import cx from 'classnames' import cx from 'classnames'
import { Input } from 'antd' import { Input } from 'antd'
import { Link, history } from 'umi' import { history } from 'umi'
import { FileTextOutlined } from '@ant-design/icons' import { FileTextOutlined } from '@ant-design/icons'
import logo from '@/theme/imgs/logo_w.png' import logo from '@/theme/imgs/logo_w.png'
import isEmpty from 'lodash/isEmpty' import isEmpty from 'lodash/isEmpty'
......
.no_result { .no_result {
padding-top: 120px; padding: 120px 0 120px 287px;
padding-left: 287px;
&_tip { &_tip {
font-size: 14px; font-size: 14px;
......
import React, { useState } from 'react' import React, { useState, useEffect } from 'react'
import { CaretDownOutlined } from '@ant-design/icons' import { CaretDownOutlined } from '@ant-design/icons'
import { Rate } from 'antd' import { Rate, Input } from 'antd'
import { Link, history } from 'umi' import { history } from 'umi'
import isEmpty from 'lodash/isEmpty'
import logo from '@/theme/imgs/logo_w.png' import logo from '@/theme/imgs/logo_w.png'
import shop_icon from '@/assets/imgs/shop_icon.png' import shop_icon from '@/assets/imgs/shop_icon.png'
import credit_icon from '@/assets/imgs/credit_icon.png' import credit_icon from '@/assets/imgs/credit_icon.png'
import shopLogo from '@/assets/imgs/shop_logo.png' import shopLogo from '@/assets/imgs/shop_logo.png'
import './index.less' import styles from './index.less'
interface ShopHeaderPropsType { interface ShopHeaderPropsType {
shopId: number;
shopUrlParam: string
} }
const ShopHeader: React.FC<ShopHeaderPropsType> = (props) => { const ShopHeader: React.FC<ShopHeaderPropsType> = (props) => {
const { shopId, shopUrlParam } = props
const [searchValue, setSearchValue] = useState<string>("")
const { search } = history.location.query
useEffect(() => {
if (!!search) {
setSearchValue(search)
} else {
setSearchValue("")
}
}, [search])
const { query } = history.location const handleSearchCommodity = () => {
if (!isEmpty(searchValue)) {
history.push(`/shop/commodity/search?shopId=${shopUrlParam}&search=${encodeURIComponent(searchValue)}`)
} else {
history.push(`/shop/commodity?shopId=${shopUrlParam}`)
}
}
return ( return (
<div className="shop_header"> <div className={styles.shop_header}>
<div className="shop_header_container"> <div className={styles.shop_header_container}>
<div className="logo"> <div className={styles.logo}>
<img src={logo} /> <img src={logo} />
</div> </div>
<div className="shop_header_split"></div> <div className={styles.shop_header_split}></div>
<div className="shop_header_info"> <div className={styles.shop_header_info}>
<div className="shop_header_info_logo"> <div className={styles.shop_header_info_logo}>
<img src={shopLogo} /> <img src={shopLogo} />
</div> </div>
<div className="shop_header_info_content"> <div className={styles.shop_header_info_content}>
<div className="shop_header_info_content_name"> <div className={styles.shop_header_info_content_name}>
<span>广州白马灯具有限公司</span> <span>广州白马灯具有限公司</span>
<CaretDownOutlined className="shop_header_info_content_icon" /> <CaretDownOutlined className={styles.shop_header_info_content_icon} />
</div> </div>
<div className="shop_header_info_content_about"> <div className={styles.shop_header_info_content_about}>
<div className="shop_header_info_content_about_item"> <div className={styles.shop_header_info_content_about_item}>
<i className="icon"><img src={shop_icon} /></i> <i className={styles.icon}><img src={shop_icon} /></i>
<span className="red">2</span> <span className={styles.red}>2</span>
<span></span> <span></span>
</div> </div>
<div className="shop_header_info_content_about_item"> <div className={styles.shop_header_info_content_about_item}>
<i className="icon"><img src={credit_icon} /></i> <i className={styles.icon}><img src={credit_icon} /></i>
<span>1288</span> <span>1288</span>
</div> </div>
</div> </div>
</div> </div>
<div className="shop_info"> <div className={styles.shop_info}>
<div className="shop_info_title"> <div className={styles.shop_info_title}>
<div className="shop_info_title_split"></div> <div className={styles.shop_info_title_split}></div>
<div className="shop_info_title_text">会员认证</div> <div className={styles.shop_info_title_text}>会员认证</div>
<div className="shop_info_title_split"></div> <div className={styles.shop_info_title_split}></div>
</div> </div>
<div className="shop_info_list"> <div className={styles.shop_info_list}>
<div className="shop_info_list_item"> <div className={styles.shop_info_list_item}>
<div className="label">满意度:</div> <div className={styles.label}>满意度:</div>
<div className="breif"><Rate className="star" count={4} disabled defaultValue={4} /></div> <div className={styles.breif}><Rate className="star" count={4} disabled defaultValue={4} /></div>
</div> </div>
<div className="shop_info_list_item"> <div className={styles.shop_info_list_item}>
<div className="label">注册资本:</div> <div className={styles.label}>注册资本:</div>
<div className="breif">5000万元</div> <div className={styles.breif}>5000万元</div>
</div> </div>
<div className="shop_info_list_item"> <div className={styles.shop_info_list_item}>
<div className="label">成立日期:</div> <div className={styles.label}>成立日期:</div>
<div className="breif">2014-09-09</div> <div className={styles.breif}>2014-09-09</div>
</div> </div>
<div className="shop_info_list_item"> <div className={styles.shop_info_list_item}>
<div className="label">营业执照:</div> <div className={styles.label}>营业执照:</div>
<div className="breif"><span className="certified">[已认证]</span></div> <div className={styles.breif}><span className="certified">[已认证]</span></div>
</div> </div>
</div> </div>
<div className="dashed_split"></div> <div className={styles.dashed_split}></div>
<div className="shop_info_btn_group"> <div className={styles.shop_info_btn_group}>
<div className="shop_info_btn">进入店铺</div> <div className={styles.shop_info_btn}>进入店铺</div>
<div className="shop_info_btn">收藏本店</div> <div className={styles.shop_info_btn}>收藏本店</div>
</div> </div>
<div className="apply_member_btn">申请成为本店会员</div> <div className={styles.apply_member_btn}>申请成为本店会员</div>
</div> </div>
</div> </div>
<div className="mall_search"> <div className={styles.mall_search}>
<div className="mall_search_box"> <div className={styles.mall_search_box}>
<input className="mall_search_input" placeholder="请输入关键词" /> <Input className={styles.mall_search_input} value={searchValue} placeholder="请输入关键词" onChange={e => setSearchValue(e.target.value)} onPressEnter={() => handleSearchCommodity()} />
<div className="search_btn">搜本店</div> <div className={styles.search_btn} onClick={() => handleSearchCommodity()}>搜本店</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -9,7 +9,7 @@ import { Advert, FloorLine } from 'lingxi-design-ui' ...@@ -9,7 +9,7 @@ import { Advert, FloorLine } from 'lingxi-design-ui'
import FloorSkeleton from '../components/FloorSkeleton' import FloorSkeleton from '../components/FloorSkeleton'
import { GetTemplatePlatformFindAllFirstCategoryResponse } from '@/services' import { GetTemplatePlatformFindAllFirstCategoryResponse } from '@/services'
import { LAYOUT_TYPE } from '@/constants' import { LAYOUT_TYPE } from '@/constants'
import './index.less' import styles from './index.less'
interface MallIndexPropsType { interface MallIndexPropsType {
SiteStore?: any SiteStore?: any
...@@ -106,7 +106,7 @@ const MallIndex: React.FC<MallIndexPropsType> = (props) => { ...@@ -106,7 +106,7 @@ const MallIndex: React.FC<MallIndexPropsType> = (props) => {
</FloorLine.FloorHeader> </FloorLine.FloorHeader>
<FloorLine.Horizontal> <FloorLine.Horizontal>
<FloorLine.Goods goodsList={categoryDetail.goodsBOList} /> <FloorLine.Goods goodsList={categoryDetail.goodsBOList} />
<FloorLine.Shops shopsList={categoryDetail.shopBOList} linkUrl={`/shop?shopId=${btoa(JSON.stringify({ shopId: 2, meberId: 6 }))}`} /> <FloorLine.Shops shopsList={categoryDetail.shopBOList} linkUrl={`/shop?shopId=${btoa(JSON.stringify({ shopId: 3, meberId: 6 }))}`} />
</FloorLine.Horizontal> </FloorLine.Horizontal>
</FloorLine.Vertical> </FloorLine.Vertical>
</FloorLine.Horizontal> </FloorLine.Horizontal>
...@@ -119,8 +119,8 @@ const MallIndex: React.FC<MallIndexPropsType> = (props) => { ...@@ -119,8 +119,8 @@ const MallIndex: React.FC<MallIndexPropsType> = (props) => {
return ( return (
<div className="mall_index"> <div className={styles.mall_index}>
<a href={`/shop?shopId=${btoa(JSON.stringify({ shopId: 2, memberId: 6 }))}`}>店铺链接测试</a> {/* <a href={`/shop?shopId=${btoa(JSON.stringify({ shopId: 3, memberId: 6 }))}`}>店铺链接测试</a> */}
{ {
useMemo(() => <Advert type="banner" advertList={firstAdvertList} hasQuickNav={true} ><QuickNav /></Advert>, [firstAdvertList]) useMemo(() => <Advert type="banner" advertList={firstAdvertList} hasQuickNav={true} ><QuickNav /></Advert>, [firstAdvertList])
} }
......
...@@ -49,7 +49,7 @@ const LXShopLayout: React.FC<LXMallLayoutPropsType> = (props) => { ...@@ -49,7 +49,7 @@ const LXShopLayout: React.FC<LXMallLayoutPropsType> = (props) => {
<div className={styles.lxmall_page}> <div className={styles.lxmall_page}>
<TopBar /> <TopBar />
<div className={styles.content}> <div className={styles.content}>
<ShopHeader /> <ShopHeader shopId={query.shopId} shopUrlParam={shopId} />
<MainNav menuData={menuData} pathname={location.pathname} type="shop" shopId={shopId} /> <MainNav menuData={menuData} pathname={location.pathname} type="shop" shopId={shopId} />
{ {
children && React.Children.map(children, (child: any) => { children && React.Children.map(children, (child: any) => {
...@@ -57,7 +57,8 @@ const LXShopLayout: React.FC<LXMallLayoutPropsType> = (props) => { ...@@ -57,7 +57,8 @@ const LXShopLayout: React.FC<LXMallLayoutPropsType> = (props) => {
{ {
layoutType: 'shop', layoutType: 'shop',
shopId: query.shopId, shopId: query.shopId,
memberId: query.memberId memberId: query.memberId,
shopUrlParam: shopId
}, },
); );
}) })
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
.commodity_container { .commodity_container {
display: flex; display: flex;
margin-top: 20px; padding-top: 20px;
width: 1200px;
margin: 0 auto;
.commodity_main { .commodity_main {
flex: 1; flex: 1;
...@@ -155,34 +158,36 @@ ...@@ -155,34 +158,36 @@
margin-top: 60px; margin-top: 60px;
text-align: right; text-align: right;
.ant-pagination-item { :global {
.ant-pagination-item {
&:hover, &:hover,
&:active { &:active {
border-color: var(--mall_main_color); border-color: var(--mall_main_color);
&>a { &>a {
color: var(--mall_main_color); color: var(--mall_main_color);
}
} }
} }
}
.ant-pagination-item-active { .ant-pagination-item-active {
background-color: var(--mall_main_color); background-color: var(--mall_main_color);
border-color: var(--mall_main_color); border-color: var(--mall_main_color);
&>a { &>a {
color: #ffffff; color: #ffffff;
}
} }
} }
} }
} }
} }
} }
.no_result { .no_result {
padding-top: 120px; padding: 120px 0 120px 287px;
padding-left: 287px;
&_tip { &_tip {
font-size: 14px; font-size: 14px;
......
import React, { useState } from 'react' import React, { useState, useEffect } from 'react'
import { CaretUpOutlined, CaretDownOutlined, UnorderedListOutlined, AppstoreOutlined, CloseOutlined } from '@ant-design/icons' import { CaretUpOutlined, CaretDownOutlined, UnorderedListOutlined, AppstoreOutlined, CloseOutlined } from '@ant-design/icons'
import Filter from '../components/Filter' import Filter from '../components/Filter'
import { FILTER_TYPE } from '@/constants' import { FILTER_TYPE } from '@/constants'
import cx from 'classnames'
import { Pagination } from 'antd' import { Pagination } from 'antd'
import CommodityList from './list' import CommodityList from './list'
import NoResult from './noResult' import SearchNoResult from '../components/SearchNoResult'
import isEmpty from 'lodash/isEmpty'
import { Spin } from 'antd'
import { useLocalStore, observer } from 'mobx-react'
import { store } from '@/store'
import { PublicApi } from '@/services/api'
import { LAYOUT_TYPE } from '@/constants'
import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services/SearchApi'
import bannerImg from '@/assets/imgs/banner_2.png' import bannerImg from '@/assets/imgs/banner_2.png'
import arrowDownIcon from '@/assets/imgs/arrow_down.png' import arrowDownIcon from '@/assets/imgs/arrow_down.png'
import arrowDownActiveIcon from '@/assets/imgs/arrow_down_active.png' import arrowDownActiveIcon from '@/assets/imgs/arrow_down_active.png'
import './index.less' import styles from './index.less'
interface filterValueType { interface CommodityPropsType {
key: string; location: any,
title: string; layoutType: LAYOUT_TYPE,
type: FILTER_TYPE; memberId: number;
shopId: number;
} }
interface CommodityPropsType { interface filterQuery {
location: any current: number;
pageSize: number;
name?: string;
categoryId?: number;
customerCategoryId?: number;
provinceCode?: number;
cityCode?: number;
brandId?: number;
customerAttributeList?: any;
Min?: number;
Max?: number;
priceType?: number;
storeId?: number;
} }
const PointsMall: React.FC<CommodityPropsType> = (props) => { const PointsMall: React.FC<CommodityPropsType> = (props) => {
const { query: { search = "" } } = props.location const FilterStore = useLocalStore(() => store.FilterStore)
const { filterList, filterUpdate, filterParam, onDeleteFilterItem, onResetFilter, onFilter, onFilterParamChange } = FilterStore
const { layoutType, memberId, shopId } = props
const { query: { categoryId, categoryName } } = props.location
const [loading, setLoading] = useState<boolean>(true)
const [showType, setShowType] = useState<number>(1) // 展示方式:1:矩阵排列; 2:列表排列 const [showType, setShowType] = useState<number>(1) // 展示方式:1:矩阵排列; 2:列表排列
const [filterList, setFilterList] = useState([]) const [commodityList, setCommodityList] = useState<GetSearchShopEnterpriseGetCommodityListResponseDetail[]>([])
const [current, setCurrent] = useState<number>(1)
const [pageSize] = useState<number>(20)
const [totalCount, setTotalCount] = useState<number>(0)
const filterConfig = [FILTER_TYPE.category, FILTER_TYPE.points] const filterConfig = [FILTER_TYPE.category, FILTER_TYPE.points]
const handleFilter = (filterValue: filterValueType) => { useEffect(() => {
let filteState = filterList.some(item => item.type === filterValue.type) console.log(layoutType, "layoutType")
let tempFilterList = [...filterList] fetchCommodityList()
if (filteState) { }, [filterParam, current])
tempFilterList = tempFilterList.map(item => {
if (item.type === filterValue.type) { useEffect(() => {
return filterValue if (categoryId && categoryName) {
} onFilter({
return item key: [categoryId],
title: decodeURIComponent(atob(categoryName)),
type: FILTER_TYPE.category,
}) })
} else {
tempFilterList = [...tempFilterList, filterValue]
} }
setFilterList(tempFilterList) }, [props.location.query])
useEffect(() => {
if (!isEmpty(filterList) || filterUpdate) {
handleFilterChange(filterList)
}
}, [filterList])
useEffect(() => {
return (() => {
onResetFilter()
})
}, [])
const fetchCommodityList = () => {
let param: filterQuery = {
current,
pageSize
}
if (!isEmpty(filterParam)) {
param = Object.assign(param, filterParam)
}
setLoading(true)
let getFn = PublicApi.getSearchShopScoreGetCommodityList
if (layoutType === LAYOUT_TYPE.shop) {
param.storeId = shopId
}
//@ts-ignore
getFn(param).then(res => {
setLoading(false)
if (res.code === 1000) {
setCommodityList(res.data.data)
setTotalCount(res.data.totalCount)
}
})
} }
const handleDeleteFilterItem = (key: string) => { const handleFilterChange = (newFilterList: any) => {
let tempFilterList = [...filterList] onFilterParamChange(newFilterList)
tempFilterList = tempFilterList.filter(item => String(item.key) !== String(key)) }
setFilterList(tempFilterList)
const handleDeleteFilterItem = (item: any) => {
onDeleteFilterItem(item.key, item.type)
} }
/** /**
* 重置筛选 * 重置筛选
*/ */
const handleResetFilter = () => { const handleResetFilter = () => {
setFilterList([]) onResetFilter()
}
const handlePageChange = (page) => {
setCurrent(page)
}
const renderPointLayoutType = (): LAYOUT_TYPE => {
let result: LAYOUT_TYPE
switch (layoutType) {
case LAYOUT_TYPE.mall:
result = LAYOUT_TYPE.scoreMall
break
case LAYOUT_TYPE.shop:
result = LAYOUT_TYPE.shopScoreMall
break
case LAYOUT_TYPE.channel:
result = LAYOUT_TYPE.channelScoreMall
break
}
return result
} }
return ( return (
<div className="commodity"> <div className={styles.commodity}>
<div className="mall_container"> <div className={styles.mall_container}>
<div className="commodity_container"> <div className={styles.commodity_container}>
<Filter filterConfig={filterConfig} /> <Filter filterConfig={filterConfig} {...props} layoutType={renderPointLayoutType()} />
<div className="commodity_main"> <div className={styles.commodity_main}>
<div className="banner"> <div className={styles.banner}>
<img src={bannerImg} /> <img src={bannerImg} />
</div> </div>
<div className="tool_bar"> <div className={styles.tool_bar}>
<div className="tool_bar_left"> <div className={styles.tool_bar_left}>
<div className="tool_bar_filter_item"> <div className={styles.tool_bar_filter_item}>
<span>积分</span> <span>积分</span>
<div className="price_filter_box"> <div className={styles.price_filter_box}>
<CaretUpOutlined className="icon" /> <CaretUpOutlined className={styles.icon} />
<CaretDownOutlined className="icon" /> <CaretDownOutlined className={styles.icon} />
</div> </div>
</div> </div>
</div> </div>
<div className="tool_bar_right"> <div className={styles.tool_bar_right}>
<div className="count"> <div className={styles.count}>
<span></span> <span></span>
<label>1,234</label> <label>{totalCount}</label>
<span>个商品</span> <span>个商品</span>
</div> </div>
</div> </div>
</div> </div>
<div className="filter_bar">
<div className="filter_bar_left">
<div className="filter_bar_left_text" onClick={handleResetFilter}>重置</div>
</div>
<div className="filter_bar_list">
{
filterList.map(item => (
<div className="filter_bar_list_item" key={item.key}>
<span className="filter_bar_list_item_text">{item.title}</span>
<CloseOutlined className="filter_bar_list_item_icon" onClick={() => handleDeleteFilterItem(item.key)} />
</div>
))
}
</div>
</div>
{ {
filterList && filterList.length > 0 && (
<div className={styles.filter_bar}>
<div className={styles.filter_bar_left}>
<div className={styles.filter_bar_left_text} onClick={handleResetFilter}>重置</div>
</div>
<div className={styles.filter_bar_list}>
{
filterList.map(item => (
<div className={styles.filter_bar_list_item} key={item.key}>
<span className={styles.filter_bar_list_item_text}>{item.title}</span>
<CloseOutlined className={styles.filter_bar_list_item_icon} onClick={() => handleDeleteFilterItem(item)} />
</div>
))
}
</div>
</div>
)
} }
{ {
!!search ? <NoResult search={search} /> : ( (commodityList.length === 0 || !commodityList) ? !loading && <SearchNoResult search="" /> : (
<> <>
<CommodityList showType={showType} /> <Spin spinning={loading}>
<div className="pagination_wrap"> <CommodityList showType={showType} commodityList={commodityList} layoutType={layoutType} />
<Pagination showQuickJumper showSizeChanger={false} defaultCurrent={1} total={100} /> </Spin>
<div className={styles.pagination_wrap}>
<Pagination showQuickJumper showSizeChanger={false} onChange={handlePageChange} current={current} pageSize={pageSize} total={totalCount} />
</div> </div>
</> </>
) )
...@@ -119,4 +206,4 @@ const PointsMall: React.FC<CommodityPropsType> = (props) => { ...@@ -119,4 +206,4 @@ const PointsMall: React.FC<CommodityPropsType> = (props) => {
) )
} }
export default PointsMall export default observer(PointsMall)
import React from 'react' import React from 'react'
import cx from 'classnames' import cx from 'classnames'
import { Skeleton } from 'antd'
import { LAYOUT_TYPE } from '@/constants'
import { GetSearchShopEnterpriseGetCommodityListResponseDetail } from '@/services/SearchApi'
import creditIcon from '@/assets/imgs/credit_icon.png' import creditIcon from '@/assets/imgs/credit_icon.png'
import './list.less' import styles from './list.less'
interface CommodityListPropsType { interface CommodityListPropsType {
showType: number showType: number;
commodityList: GetSearchShopEnterpriseGetCommodityListResponseDetail[]
layoutType: LAYOUT_TYPE
} }
const CommodityList: React.FC<CommodityListPropsType> = (props) => { const CommodityList: React.FC<CommodityListPropsType> = (props) => {
const { showType } = props const { showType, commodityList = [], layoutType = LAYOUT_TYPE.mall } = props
let dataList = []
for (let i = 0; i < 20; i++) {
dataList.push(i)
}
return ( return (
<div className={cx("point_commodity_list", showType === 2 ? 'column' : 'row')}> <div className={cx(styles.point_commodity_list, styles.row)}>
{ {
dataList.map((item, index) => ( commodityList.map((item, index) => (
<div key={item} className="point_commodity_list_item row"> <div key={item.id} className={cx(styles.point_commodity_list_item, styles.row)}>
<a href={`/shop/commodity/detail?id=asdjflewjfe&type=prompt`}> <a href={`/${layoutType === LAYOUT_TYPE.channel ? 'channelmall' : 'shop'}/commodity/detail?id=${item.id}&type=${item.priceType}&shopId=${btoa(JSON.stringify({ shopId: item.storeId, memberId: item.memberId }))}`} target="_blank">
<div className="goods_img"> <div className={styles.goods_img}>
<img src="https://img.alicdn.com/bao/uploaded/i1/691602756/O1CN013mdkHl1WEI92iLR75_!!691602756.jpg_400x400q60.jpg" /> {
item.commodityPic ? <img src={item.commodityPic} /> : <Skeleton.Image style={{ width: 220, height: 220 }} />
}
</div> </div>
<div className="info_box"> <div className={styles.info_box}>
<div className="goods_price"> <div className={styles.goods_price}>
2,000~3,000积分 {item.min}~{item.max}积分
</div> </div>
<div className="goods_name">Apple iPhone 11 Pro Max (A2220)暗夜绿色 移动联通电信4G手机 双卡双待特</div> <div className={styles.goods_name}>{item.name}</div>
<div className="count">库存:20</div> <div className={styles.count}>已售:{item.sold}</div>
</div> </div>
</a> </a>
</div> </div>
)) ))
} }
</div> </div>
...@@ -41,3 +42,4 @@ const CommodityList: React.FC<CommodityListPropsType> = (props) => { ...@@ -41,3 +42,4 @@ const CommodityList: React.FC<CommodityListPropsType> = (props) => {
} }
export default CommodityList export default CommodityList
import React from 'react'
import styles from './index.less'
interface NoResultPropsType {
search?: string
}
const NoResult: React.FC<NoResultPropsType> = (props) => {
const { search } = props
return (
<div className={styles.no_result}>
<div className={styles.no_result_tip}>
<div className={styles.no_result_tip_img}></div>
<div className={styles.no_result_tip_text}>
抱歉,没有找到与“
<span className={styles.no_result_tip_search}>{search}</span>
”相关的商品
</div>
</div>
<div className={styles.no_result_suggest}>
<ul className={styles.no_result_suggest_list}>
<li>建议您:</li>
<li>1、尝试其他关键字</li>
<li>2、适当减少筛选条件</li>
<li>3、调整价格区间</li>
</ul>
</div>
</div>
)
}
export default NoResult
...@@ -65,6 +65,7 @@ const ShopIndex: React.FC<ChannelIndexPropsType> = (props) => { ...@@ -65,6 +65,7 @@ const ShopIndex: React.FC<ChannelIndexPropsType> = (props) => {
*/ */
const fetchFirstCategory = () => { const fetchFirstCategory = () => {
return new Promise((resolve) => { return new Promise((resolve) => {
//@ts-ignore
PublicApi.getTemplateShopFindAllFirstCategory({ memberId }).then(res => { PublicApi.getTemplateShopFindAllFirstCategory({ memberId }).then(res => {
if (res.code === 1000) { if (res.code === 1000) {
setCategoryList(res.data) setCategoryList(res.data)
......
...@@ -76,8 +76,8 @@ class CategoryStore { ...@@ -76,8 +76,8 @@ class CategoryStore {
* 店铺商城商品分类列表 * 店铺商城商品分类列表
*/ */
@action.bound @action.bound
public async fetchStoreCategoryList() { public async fetchStoreCategoryList(param) {
let res = await PublicApi.getSearchShopStoreGetCustomerCategoryTree() let res = await PublicApi.getSearchShopStoreGetCustomerCategoryTree(param)
runInAction(() => { runInAction(() => {
this.storeCategoryList = res.data || [] this.storeCategoryList = res.data || []
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment