feat(ID1000738):需求拆分:内部商城新增二级面料分类、排序

This commit is contained in:
Haiyi 2022-12-06 14:37:59 +08:00
parent 81f6c48794
commit e2c4c99ff1
7 changed files with 358 additions and 14 deletions

View File

@ -8,6 +8,8 @@
"no-prototype-builtins": "off",
"import/first": "off",
"react/no-children-prop": "off",
"import/no-commonjs": "off"
"import/no-commonjs": "off",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": ["error"]
}
}

View File

@ -74,3 +74,13 @@ export const ProductListApi = () => {
method: 'get',
})
}
/**
*
*/
export const GetClassList = () => {
return useRequest({
url: '/v2/mp/product/kind/sub/list',
method: 'get',
})
}

View File

@ -70,10 +70,34 @@
.sideBar_con {
flex: 1;
min-width: 0;
position: relative;
padding-top: 90px;
.product_class {
width: 100%;
position: absolute;
top: 0;
z-index: 999;
}
.sideBar_con_scroll {
width: 100%;
height: 100%;
}
}
.nosideBar_con{
flex: 1;
min-width: 0;
position: relative;
.product_class {
width: 100%;
position: absolute;
top: 0;
z-index: 999;
}
.sideBar_con_scroll {
width: 100%;
height: 100%;
}
}
}

View File

@ -7,6 +7,8 @@ import type { StatusParam } from '../infiniteScroll'
import InfiniteScroll from '../infiniteScroll'
import LoadingCard from '../loadingCard'
import styles from './index.module.scss'
import ProductClass from '@/pages/index/components/productClass'
import { GetClassList } from '@/api/index'
interface Params {
list?: any[]
@ -20,6 +22,7 @@ interface Params {
selfOnScrolltolower?: () => void
hasMore?: true | false
statusMore?: StatusParam
selectClass?: (val: number) => void
}
const SideBar = ({
list = [],
@ -33,6 +36,7 @@ const SideBar = ({
selfOnScrolltolower,
hasMore = true,
statusMore = 0,
selectClass,
}: Params) => {
const num_half = useRef(0)
@ -76,21 +80,37 @@ const SideBar = ({
})
}, [])
// 二级面料系列分类
const [openClass, setOpenClass] = useState(false)
const [classList, setClassList] = useState([])
const [classId, setClassId] = useState(-1)
const { fetchData } = GetClassList()
const getClassData = async(id) => {
const res = await fetchData({ id })
if (res.success) {
if (res.data?.list.length > 0) {
res.data.list = [{ id: -1, name: '全部' }, ...res.data.list]
}
setClassList(() => res.data?.list)
console.log('res.data?.list=>', res.data?.list)
}
}
useEffect(() => {
if (selected) { getClassData(selected) }
}, [selected])
const getSelectClass = (id) => {
selectClass?.(id)
setClassId(() => id)
}
const clickEvent = ({ item, index }: { item; index: number }) => {
setSelected(item.id)
sideBarOnClick?.(item)
computeSelectTab(index)
setClassId(-1)
selectClass?.(-1)
}
const [currentIndex, setcurrentIndex] = useState(0)
useMemo(() => {
Taro.nextTick(() => {
let index = 0
index = list.findIndex((item) => { return item.id == selected })
setcurrentIndex(currentIndex)
})
}, [selected])
return (
<>
<View className={classnames(styles.sideBar_main, 'side_bar_select')}>
@ -116,7 +136,12 @@ const SideBar = ({
})
}
</ScrollView>
<View className={styles.sideBar_con}>
<View className={classnames(classList.length > 0 ? styles.sideBar_con : styles.nosideBar_con)}>
{classList.length > 0 && (
<View className={styles.product_class} style={{ height: openClass ? '100%' : '' }}>
<ProductClass list={classList} open={openClass} onOpenClick={val => setOpenClass(val)} onSelect={getSelectClass} defaultSelectId={classId} />
</View>
)}
<InfiniteScroll statusMore={statusMore} selfonScrollToLower={() => selfOnScrolltolower?.()} refresherTriggered={refresherTriggered} refresherEnabled selfOnRefresherRefresh={() => selfOnRefresherRefresh?.()}>
{children}
</InfiniteScroll>

View File

@ -0,0 +1,143 @@
.class_main {
position: relative;
height: 100%;
}
.product_class_main_line {
width: 100%;
height: 80px;
position: absolute;
top: 0;
left: 0;
// display: flex;
// align-items: center;
margin-bottom: 20px;
background-color: #fff;
.product_class_scroll {
box-sizing: border-box;
padding: 6px 90px 0 20px;
.product_class_list {
white-space: nowrap;
display: flex;
box-sizing: border-box;
.product_class_item {
height: 56px;
line-height: 56px;
padding: 0 15px;
background: #f5f5f5;
border-radius: 29px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: rgba(0, 0, 0, 0.8);
box-sizing: border-box;
max-width: 260px;
// @include common_ellipsis;
margin: 0 8px 16px 8px;
}
.product_class_item_selected {
border: 1px solid #3c78f4;
color: #3c78f4;
background: #ecf2ff;
box-sizing: border-box;
}
}
}
.product_class_more {
position: absolute;
right: 0;
top: 0;
width: 88px;
height: 100%;
background-color: #fff;
box-shadow: -7px 0px 7px -5px rgba(0, 0, 0, 0.16);
line-height: 100%;
display: flex;
align-items: center;
.zhankai{
margin-left: 15px;
}
.product_class_more_icon {
margin-left: 20px;
display: inline-block;
transform: rotate(90deg);
font-size: 30px;
color: rgba(0, 0, 0, 0.5);
}
}
}
.product_class_main_block {
width: 100%;
height: 100%;
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
.product_class_block_con {
max-height: 500px;
background-color: #fff;
z-index: 999;
position: relative;
}
.product_class_scroll {
box-sizing: border-box;
max-height: 500px;
padding: 0 20px;
padding: 6px 20px 0 20px;
.product_class_list {
// display: flex;
// flex-wrap: wrap;
box-sizing: border-box;
display: grid;
grid-template-columns: auto auto auto;
.product_class_item {
width: 169px;
height: 56px;
line-height: 56px;
text-align: center;
padding: 0 15px;
background: #f5f5f5;
border-radius: 29px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: rgba(0, 0, 0, 0.8);
margin: 0 8px 16px 8px;
box-sizing: border-box;
max-width: 260px;
@include common_ellipsis(1);
}
.product_class_item_selected {
border: 1px solid #3c78f4;
color: #3c78f4;
background: #ecf2ff;
box-sizing: border-box;
}
}
}
.product_class_close {
font-size: 24px;
color: rgba(0, 0, 0, 0.6);
// text-align: center;
padding-bottom: 20px;
display: flex;
justify-content: center;
// .product_class_close_icon {
// display: inline-block;
// transform: rotate(-90deg);
// font-size: 27px;
// color: rgba(0, 0, 0, 0.5);
// padding: 0 10px;
// }
}
.product_class_block_mask {
position: absolute;
top: 0;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
}
}

View File

@ -0,0 +1,126 @@
import { ScrollView, View } from '@tarojs/components'
import classnames from 'classnames'
import { memo, useCallback, useEffect, useState } from 'react'
import styles from './index.module.scss'
import IconFont from '@/components/iconfont/iconfont'
interface Param {
open: boolean
onOpenClick?: (val: boolean) => void
onSelect?: (id: number) => void
list?: { name: string; id: number }[]
defaultSelectId: number
}
type ParamProduct = Omit<Param, 'open'>
const ProductClassLine = memo((option: ParamProduct) => {
const { onOpenClick, defaultSelectId = 0, onSelect, list = [] } = option
const [selectInfo, setSelectInfo] = useState({
selected: 0, // 当前选中的id
tabId: 0, // 需要滚动到的id
})
console.log('刷新了')
useEffect(() => {
let data: { item: any; index: number } = { item: null, index: 0 }
list?.filter((item, index) => {
if (item.id == defaultSelectId) {
data = { item, index }
}
})
if (data.item) {
const num = data.index > 0 ? data.index - 1 : 0
console.log('获取数据::', list[num].id)
setSelectInfo(e => ({ ...e, tabId: list[num].id, selected: data.item.id }))
}
}, [defaultSelectId, list])
const clickEvent = ({ item, index }: { item: any; index: number }) => {
const num = index > 0 ? index - 1 : 0
setSelectInfo(e => ({ ...e, tabId: list[num].id, selected: item.id }))
onSelect?.(item.id)
}
return (
<View className={styles.product_class_main_line}>
<ScrollView scrollX scrollWithAnimation className={styles.product_class_scroll} scrollIntoView={`tabs_${selectInfo.tabId}`}>
<View className={styles.product_class_list}>
{list?.map((item, index) => (
<View
id={`tabs_${item.id}`}
className={classnames(styles.product_class_item, item.id == selectInfo.selected ? styles.product_class_item_selected : '')}
onClick={() => clickEvent({ item, index })}
key={item.id}
>
{item.name}
</View>
))}
</View>
</ScrollView>
<View className={styles.product_class_more} onClick={() => onOpenClick?.(true)}>
<IconFont name="icon-zhankai" color="#000000" size={40} customClassName={styles.zhankai}></IconFont>
</View>
</View>
)
})
ProductClassLine.displayName = 'ProductClassLine'
const ProductClassBlock = (option: ParamProduct & { open: boolean }) => {
const { onOpenClick, defaultSelectId = 0, onSelect, list = [], open } = option
const [selectInfo, setSelectInfo] = useState(0)
useEffect(() => {
setSelectInfo(defaultSelectId)
}, [defaultSelectId])
const clickEvent = (item) => {
setSelectInfo(item.id)
onSelect?.(item.id)
}
return (
<>
<View className={styles.product_class_main_block} style={{ display: open ? 'block' : 'none' }}>
<View className={styles.product_class_block_con}>
<ScrollView scrollY className={styles.product_class_scroll}>
<View className={styles.product_class_list}>
{list?.map(item => (
<View
className={classnames(styles.product_class_item, item.id == selectInfo ? styles.product_class_item_selected : '')}
onClick={() => clickEvent(item)}
key={item.id}
>
{item.name}
</View>
))}
</View>
</ScrollView>
<View className={styles.product_class_close} onClick={() => onOpenClick?.(false)}>
<IconFont name="icon-shouqi" color="#000000" size={40} customClassName={styles.shouqi}></IconFont>
</View>
</View>
<View className={styles.product_class_block_mask} onClick={() => onOpenClick?.(false)}></View>
</View>
</>
)
}
const PrcductSub = (option: Param) => {
const { open = false, onOpenClick, onSelect, list, defaultSelectId } = option
const getSelect = useCallback((id) => {
onSelect?.(id)
}, [])
const openClick = useCallback((val) => {
onOpenClick?.(val)
}, [])
return (
<>
<View className={styles.class_main}>
<ProductClassLine list={list} defaultSelectId={defaultSelectId} onSelect={getSelect} onOpenClick={openClick}></ProductClassLine>
<ProductClassBlock open={open} list={list} defaultSelectId={defaultSelectId} onSelect={getSelect} onOpenClick={openClick}></ProductClassBlock>
</View>
</>
)
}

View File

@ -13,6 +13,7 @@ import { ClientListApi, MpProductColorList, MpShoppingCartProductColorList } fro
import { dataLoadingStatus, getFilterData } from '@/common/util'
const Index = () => {
const product_kind_id_ref = useRef(0)
// 获取客户
const [clienList, setclienList] = useState<any[]>([])
const { fetchData: listFetchData } = ClientListApi()
@ -43,6 +44,7 @@ const Index = () => {
if (res.data?.list) {
setKindData({ ...kindData, list: res.data.list, defaultId: res.data.list[0].id })
setFiltrate({ ...filtrate, product_kind_id: res.data.list[0].id })
product_kind_id_ref.current = res.data.list[0].id
}
}
@ -67,6 +69,7 @@ const Index = () => {
pageNum.current.page = 1
setProductData({ list: [], total: 0 })
setFiltrate(list => ({ ...list, size: 5, product_kind_id: e.id }))
product_kind_id_ref.current = e.id
}, [])
// 上拉加载数据
@ -326,6 +329,16 @@ const Index = () => {
}
})
// 获取二级分类
const product_kind_id_next_ref = useRef(0)
const getSelectClassId = useCallback((id) => {
pageNum.current.page = 1
setProductData({ list: [], total: 0 })
const kind_id = id == -1 ? product_kind_id_ref.current : id
product_kind_id_next_ref.current = id
setFiltrate(list => ({ ...list, size: 5, product_kind_id: kind_id }))
}, [])
return (
// <MoveBtn onClick={() => setShowShopCart(showShopCart)}>
<View className={styles.main}>
@ -347,6 +360,7 @@ const Index = () => {
selfOnScrolltolower={getScrolltolower}
sideBarOnClick={getProductKindId}
heightItem={150}
selectClass={getSelectClassId}
refresherTriggered={refresherTriggeredStatus}
selfOnRefresherRefresh={() => getRefresherRefresh()}
>