mirror of
https://gitee.com/ShopeX/ECShopX_mobile-frontend
synced 2026-08-10 05:46:05 +08:00
[TBID:ECX-8807] chore: merge master changes for release
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -18,4 +18,4 @@ openspec/
|
||||
scripts/
|
||||
.agent/
|
||||
.codex/
|
||||
.cursor/commit-summary
|
||||
.cursor/
|
||||
|
||||
@@ -23,6 +23,11 @@ export function cartFastBuyAdd(params) {
|
||||
return req.post('/operator/cartfastbuyadd', params)
|
||||
}
|
||||
|
||||
// 移动收银选择会员后同步会话(POST body;company_id 由 req 拦截器注入,与 cartdataadd 一致)
|
||||
export function memberReady(params) {
|
||||
return req.post('/operator/member/ready', params)
|
||||
}
|
||||
|
||||
// 扫码加入收银台
|
||||
export function scanAddToCart(params) {
|
||||
return req.post('/operator/scancodeAddcart', params)
|
||||
|
||||
@@ -47,14 +47,6 @@ function WgtFilm(props) {
|
||||
})}
|
||||
style={styleNames(outerStyle)}
|
||||
>
|
||||
{base.title && (
|
||||
<View className='wgt-head'>
|
||||
<View className='wgt-hd'>
|
||||
<Text className='wgt-title'>{base.title}</Text>
|
||||
{base.subtitle && <Text className='wgt-subtitle'>{base.subtitle}</Text>}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<View className={classNames('wgt-film__video-wrap', videoWrapClass)}>
|
||||
<View className='wgt-film__video-inner'>
|
||||
<Video
|
||||
|
||||
@@ -31,12 +31,14 @@
|
||||
video,
|
||||
.flim-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.flim-video {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.taro-video-video{
|
||||
|
||||
@@ -129,35 +129,34 @@ export function getGlobalBaseStyle(baseStyle) {
|
||||
|
||||
const bgType = baseStyle.bgType
|
||||
const style = {}
|
||||
|
||||
if (baseStyle.paddedt !== undefined && baseStyle.paddedt !== null) {
|
||||
const v = toDesignPx(baseStyle.paddedt)
|
||||
if (v !== null) style.paddingTop = Taro.pxTransform(v)
|
||||
}
|
||||
if (baseStyle.paddedb !== undefined && baseStyle.paddedb !== null) {
|
||||
const v = toDesignPx(baseStyle.paddedb)
|
||||
if (v !== null) style.paddingBottom = Taro.pxTransform(v)
|
||||
}
|
||||
if (baseStyle.paddedl !== undefined && baseStyle.paddedl !== null) {
|
||||
const v = toDesignPx(baseStyle.paddedl)
|
||||
if (v !== null) style.paddingLeft = Taro.pxTransform(v)
|
||||
}
|
||||
if (baseStyle.paddedr !== undefined && baseStyle.paddedr !== null) {
|
||||
const v = toDesignPx(baseStyle.paddedr)
|
||||
if (v !== null) style.paddingRight = Taro.pxTransform(v)
|
||||
}
|
||||
|
||||
style.padding = `${Taro.pxTransform(baseStyle.paddedt || 0)} ${Taro.pxTransform(baseStyle.paddedr || 0)} ${Taro.pxTransform(baseStyle.paddedb || 0)} ${Taro.pxTransform(baseStyle.paddedl || 0)}`
|
||||
if (bgType === 'color' && baseStyle.bgColor) {
|
||||
style.backgroundColor = baseStyle.bgColor
|
||||
if(isWeb){
|
||||
style['background-color'] = baseStyle.bgColor
|
||||
} else {
|
||||
style.backgroundColor = baseStyle.bgColor
|
||||
}
|
||||
} else if (bgType === 'pic' && baseStyle.bgPic) {
|
||||
style.backgroundImage = `url(${baseStyle.bgPic})`
|
||||
if(isWeb){
|
||||
style['background-image'] = `url('${baseStyle.bgPic}')`
|
||||
style['background-size'] = '100% 100%'
|
||||
style['background-position'] = 'center'
|
||||
style['background-repeat'] = 'no-repeat'
|
||||
} else {
|
||||
style.backgroundImage = `url('${baseStyle.bgPic}')`
|
||||
style.backgroundSize = '100% 100%'
|
||||
style.backgroundPosition = 'center'
|
||||
style.backgroundRepeat = 'no-repeat'
|
||||
}
|
||||
} else if (bgType === 'gradient' && baseStyle.startColor) {
|
||||
const endColor = baseStyle.endColor || baseStyle.startColor
|
||||
style.backgroundImage = `linear-gradient(${baseStyle.startColor}, ${endColor})`
|
||||
style.backgroundSize = 'cover'
|
||||
if(isWeb){
|
||||
style['background-image'] = `linear-gradient(${baseStyle.startColor}, ${endColor})`
|
||||
style['background-size'] = 'cover'
|
||||
} else {
|
||||
style.backgroundImage = `linear-gradient(${baseStyle.startColor}, ${endColor})`
|
||||
style.backgroundSize = 'cover'
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import React, { useMemo } from 'react'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { Button, View } from '@tarojs/components'
|
||||
import { Button, View, ScrollView } from '@tarojs/components'
|
||||
import { SpImage, SpLogin } from '@/components'
|
||||
import { linkPage, classNames, styleNames, isArray, getDistributorId } from '@/utils'
|
||||
import { needLoginPage, needLoginPageType } from '@/consts'
|
||||
@@ -102,6 +102,17 @@ function WgtImgHotZone(props) {
|
||||
return <View {...zoneProps} onClick={clickHandler} />
|
||||
}
|
||||
|
||||
const renderImgContent = () => (
|
||||
<>
|
||||
<SpImage
|
||||
src={config.imgUrl}
|
||||
className='wgt-imghot-zone__body-img'
|
||||
mode={!isVertical ? 'widthFix' : 'heightFix'}
|
||||
/>
|
||||
{isArray(data) && data.length > 0 && data.map(renderHotZone)}
|
||||
</>
|
||||
)
|
||||
|
||||
if (!info || !config.imgUrl) {
|
||||
return null
|
||||
}
|
||||
@@ -113,19 +124,20 @@ function WgtImgHotZone(props) {
|
||||
style={styleNames(outerStyle)}
|
||||
>
|
||||
<View className='wgt-imghot-zone__body' style={styleNames(bodyStyle)}>
|
||||
<View
|
||||
className={classNames('wgt-imghot-zone__body-img-wrapper', {
|
||||
'wgt-imghot-zone__body-img-wrapper__vertical': isVertical,
|
||||
'wgt-imghot-zone__body-img-wrapper__horizontal': !isVertical
|
||||
})}
|
||||
>
|
||||
<SpImage
|
||||
src={config.imgUrl}
|
||||
className='wgt-imghot-zone__body-img'
|
||||
mode={!isVertical ? 'widthFix' : 'heightFix'}
|
||||
/>
|
||||
{isArray(data) && data.length > 0 && data.map(renderHotZone)}
|
||||
</View>
|
||||
{isVertical ? (
|
||||
<ScrollView
|
||||
scrollX
|
||||
enhanced
|
||||
showScrollbar={false}
|
||||
className='wgt-imghot-zone__body-img-wrapper wgt-imghot-zone__body-img-wrapper__vertical'
|
||||
>
|
||||
<View className='wgt-imghot-zone__scroll-inner'>{renderImgContent()}</View>
|
||||
</ScrollView>
|
||||
) : (
|
||||
<View className='wgt-imghot-zone__body-img-wrapper wgt-imghot-zone__body-img-wrapper__horizontal'>
|
||||
{renderImgContent()}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -22,22 +22,29 @@
|
||||
.wgt-imghot-zone__body-img-wrapper__vertical {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: scroll;
|
||||
scroll-snap-type: x mandatory;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
|
||||
.wgt-imghot-zone__scroll-inner {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.wgt-imghot-zone__body-img {
|
||||
height: 100% !important;
|
||||
width: min-content;
|
||||
width: max-content;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.wgt-imghot-zone__body_zone {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.wgt-imghot-zone__body {
|
||||
position: relative;
|
||||
|
||||
&_zone {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,14 +230,15 @@ function PurchaseAuth() {
|
||||
// 企业二维码扫码登录
|
||||
const getQrcodeEid = async () => {
|
||||
try {
|
||||
const { id, enterprise_id, code } = await entryLaunch.getRouteParams()
|
||||
const { id, activity_id, enterprise_id, code } = await entryLaunch.getRouteParams()
|
||||
//亲友扫码
|
||||
let _id = id || activity_id || ''
|
||||
setState((draft) => {
|
||||
draft.invite_code = code || ''
|
||||
draft.activity_id = id || ''
|
||||
draft.activity_id = _id || ''
|
||||
draft.enterprise_id = enterprise_id || ''
|
||||
})
|
||||
return { id, enterprise_id, code }
|
||||
return { id:_id, enterprise_id, code }
|
||||
} catch (error) {
|
||||
return {}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import './detail.scss'
|
||||
const initialState = {
|
||||
itemId: '',
|
||||
title: '',
|
||||
summary: '',
|
||||
articleFocusNum: 0,
|
||||
content: [],
|
||||
updated: '',
|
||||
@@ -33,7 +34,7 @@ function GuideRecommendDetail(props) {
|
||||
const { i18n } = useTranslation()
|
||||
const $instance = getCurrentInstance() || {}
|
||||
const [state, setState] = useImmer(initialState)
|
||||
const { img, shareImageUrl, itemId, title, content, articleFocusNum, updated } = state
|
||||
const { img, shareImageUrl, itemId, title, summary, content, articleFocusNum, updated } = state
|
||||
const { userInfo } = useSelector((state) => state.guide)
|
||||
const router = useRouter()
|
||||
|
||||
@@ -88,7 +89,7 @@ function GuideRecommendDetail(props) {
|
||||
})
|
||||
}
|
||||
}
|
||||
const { itemId, title, articleFocusNum, content, updated, isPraise, articlePraiseNum } = pickBy(
|
||||
const { itemId, title, summary, articleFocusNum, content, updated, isPraise, articlePraiseNum } = pickBy(
|
||||
res,
|
||||
doc.article.ARTICLE_ITEM
|
||||
)
|
||||
@@ -96,6 +97,7 @@ function GuideRecommendDetail(props) {
|
||||
setState((draft) => {
|
||||
draft.itemId = itemId
|
||||
draft.title = title
|
||||
draft.summary = summary
|
||||
draft.articleFocusNum = articleFocusNum
|
||||
draft.content = content
|
||||
draft.updated = updated
|
||||
@@ -162,7 +164,10 @@ function GuideRecommendDetail(props) {
|
||||
>
|
||||
<ScrollView className='scrollview-container' scrollY>
|
||||
<View className='article-hd'>
|
||||
<View className='article-title'>{title}</View>
|
||||
<View className='article-title-row'>
|
||||
<View className='article-title'>{title}</View>
|
||||
{summary ? <Text className='article-summary'>{summary}</Text> : null}
|
||||
</View>
|
||||
<View className='article-info'>
|
||||
<Text className='update-time'>{updated}</Text>
|
||||
</View>
|
||||
|
||||
@@ -13,10 +13,19 @@
|
||||
.article-bd {
|
||||
background: #fff;
|
||||
}
|
||||
.article-title-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.article-title {
|
||||
font-size: 40px;
|
||||
color: #222;
|
||||
}
|
||||
.article-summary {
|
||||
font-size: 28px;
|
||||
color: #666;
|
||||
}
|
||||
.article-info {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
SpInput as AtInput
|
||||
} from '@/components'
|
||||
import { useDianWuLogin, useDebounce } from '@/hooks'
|
||||
import { styleNames, pickBy, showToast, classNames, validate } from '@/utils'
|
||||
import { styleNames, pickBy, showToast, classNames } from '@/utils'
|
||||
import { useTranslation, $t, i18n, ti } from '@/i18n'
|
||||
import { selectMember } from '@/store/slices/dianwu'
|
||||
import CompGoods from './comps/comp-goods'
|
||||
@@ -33,6 +33,7 @@ import CompGoodsPrice from './comps/comp-goods-price'
|
||||
import CompTabbar from './comps/comp-tabbar'
|
||||
import CompDianwuSelectMember from './comps/comp-dianwu-select-member'
|
||||
import CompDianwuPlatformOrder from './comps/comp-dianwu-platform-order'
|
||||
import { isDianwuGoodsDisabled, resolveDianwuGoodsActions } from './utils/dianwu-goods-action'
|
||||
import './cashier.scss'
|
||||
|
||||
const initialState = {
|
||||
@@ -43,7 +44,8 @@ const initialState = {
|
||||
searchResultLayout: false,
|
||||
addUserCurtain: false,
|
||||
isCameraOpend: false,
|
||||
platformOrderItem: null
|
||||
platformOrderItem: null,
|
||||
isPlatformStoreBuy: false
|
||||
}
|
||||
|
||||
function DianWuCashier() {
|
||||
@@ -57,7 +59,8 @@ function DianWuCashier() {
|
||||
searchGoodsList,
|
||||
isCameraOpend,
|
||||
distributor_id,
|
||||
platformOrderItem
|
||||
platformOrderItem,
|
||||
isPlatformStoreBuy
|
||||
} = state
|
||||
const pageRef = useRef()
|
||||
const getCashierListRef = useRef(null)
|
||||
@@ -113,7 +116,7 @@ function DianWuCashier() {
|
||||
|
||||
const handleSearchByKeyword = async (keywords) => {
|
||||
Taro.showLoading({ title: '' })
|
||||
const { list: goodsList } = await dianwuApi.goodsItems({
|
||||
const { list: goodsList, is_platform_store_buy } = await dianwuApi.goodsItems({
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
keywords,
|
||||
@@ -123,6 +126,9 @@ function DianWuCashier() {
|
||||
|
||||
setState((draft) => {
|
||||
draft.searchGoodsList = pickBy(goodsList, doc.dianwu.GOODS_ITEM)
|
||||
if (is_platform_store_buy != null) {
|
||||
draft.isPlatformStoreBuy = !!is_platform_store_buy
|
||||
}
|
||||
// draft.searchMemberList = pickBy(memberList, doc.dianwu.MEMBER_ITEM)
|
||||
draft.searchResultLayout = true
|
||||
})
|
||||
@@ -268,43 +274,6 @@ function DianWuCashier() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreateMember = async () => {
|
||||
const res = await dianwuApi.createMember({ mobile })
|
||||
const newUser = pickBy(res, doc.dianwu.CREATE_MEMBER_ITEM)
|
||||
const userInfo = await dianwuApi.getMemberByUserId({ user_id: newUser.userId })
|
||||
const { couponNum, point, vipDiscount } = pickBy(userInfo, doc.dianwu.MEMBER_INFO)
|
||||
dispatch(
|
||||
selectMember({
|
||||
...newUser,
|
||||
couponNum,
|
||||
point,
|
||||
vipDiscount
|
||||
})
|
||||
)
|
||||
setState((draft) => {
|
||||
draft.addUserCurtain = false
|
||||
})
|
||||
}
|
||||
|
||||
const onChangeMobile = (e) => {
|
||||
setState((draft) => {
|
||||
draft.mobile = e
|
||||
})
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (validate.isMobileNum(mobile)) {
|
||||
const { list } = await dianwuApi.getMembers({
|
||||
mobile
|
||||
})
|
||||
setState((draft) => {
|
||||
draft.searchMemberResult = pickBy(list, doc.dianwu.MEMBER_ITEM)
|
||||
})
|
||||
} else {
|
||||
showToast($t('7187dbd0.a32ab5'))
|
||||
}
|
||||
}
|
||||
|
||||
const onChangePlus = async (item, idx, index) => {
|
||||
const _num = parseInt(item.num) + 1
|
||||
if (_num > item.store) {
|
||||
@@ -657,35 +626,43 @@ function DianWuCashier() {
|
||||
}}
|
||||
>
|
||||
<ScrollView className='tab-scroll-list' scrollY>
|
||||
{searchGoodsList.map((item, index) => (
|
||||
<View className='goods-item-wrap' key={`goods-item-wrap__${index}`}>
|
||||
<CompGoods info={item}>
|
||||
{item.store > 0 && item.isTotalStore === true && (
|
||||
<AtButton
|
||||
circle
|
||||
className='btn-add-cart'
|
||||
onClick={handleAddToCart.bind(this, item)}
|
||||
>
|
||||
{$t('7187dbd0.cd2240')}
|
||||
</AtButton>
|
||||
)}
|
||||
{searchGoodsList.map((item, index) => {
|
||||
const actions = resolveDianwuGoodsActions(item, isPlatformStoreBuy)
|
||||
return (
|
||||
<View
|
||||
className={classNames('goods-item-wrap', {
|
||||
'item-disabled': isDianwuGoodsDisabled(item, isPlatformStoreBuy)
|
||||
})}
|
||||
key={`goods-item-wrap__${index}`}
|
||||
>
|
||||
<CompGoods info={item} isPlatformStoreBuy={isPlatformStoreBuy}>
|
||||
{actions.addToCashier && (
|
||||
<AtButton
|
||||
circle
|
||||
className='btn-add-cart'
|
||||
onClick={handleAddToCart.bind(this, item)}
|
||||
>
|
||||
{$t('7187dbd0.cd2240')}
|
||||
</AtButton>
|
||||
)}
|
||||
|
||||
{item.store == 0 && item.platformStore > 0 && (
|
||||
<AtButton
|
||||
className='btn-add-cart btn-platform-order'
|
||||
circle
|
||||
onClick={() => {
|
||||
setState((draft) => {
|
||||
draft.platformOrderItem = item
|
||||
})
|
||||
}}
|
||||
>
|
||||
立即下单
|
||||
</AtButton>
|
||||
)}
|
||||
</CompGoods>
|
||||
</View>
|
||||
))}
|
||||
{actions.buyNow && (
|
||||
<AtButton
|
||||
className='btn-add-cart btn-platform-order'
|
||||
circle
|
||||
onClick={() => {
|
||||
setState((draft) => {
|
||||
draft.platformOrderItem = item
|
||||
})
|
||||
}}
|
||||
>
|
||||
{$t('8cac8565.887eb6')}
|
||||
</AtButton>
|
||||
)}
|
||||
</CompGoods>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</ScrollView>
|
||||
</SpFloatLayout>
|
||||
|
||||
|
||||
@@ -542,6 +542,9 @@
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
&.item-disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.at-button {
|
||||
display: inline-block;
|
||||
min-width: 120px;
|
||||
|
||||
@@ -54,6 +54,17 @@ function CompDianwuSelectMember({ open, onClose, onAfterSelect, distributor_id }
|
||||
const handleSelectMember = async () => {
|
||||
const [item] = searchMemberResult
|
||||
const userInfo = await dianwuApi.getMemberByUserId({ user_id: item.userId })
|
||||
try {
|
||||
await dianwuApi.memberReady({
|
||||
user_id: item.userId,
|
||||
distributor_id,
|
||||
showError: false
|
||||
})
|
||||
} catch (e) {
|
||||
const msg =
|
||||
e?.message || e?.res?.data?.data?.message || $t('09e29d60.g3q6mc')
|
||||
showToast(msg)
|
||||
}
|
||||
const { couponNum, point, vipDiscount } = pickBy(userInfo, doc.dianwu.MEMBER_INFO)
|
||||
dispatch(
|
||||
selectMember({
|
||||
|
||||
@@ -6,19 +6,19 @@ import React from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { SpImage } from '@/components'
|
||||
import { useTranslation, $t, ti } from '@/i18n'
|
||||
import { resolveDianwuGoodsDisplay } from '../utils/dianwu-goods-action'
|
||||
import CompGoodsPrice from './comp-goods-price'
|
||||
import './comp-goods.scss'
|
||||
|
||||
function CompGoods(props) {
|
||||
useTranslation()
|
||||
const { children, info } = props
|
||||
const { children, info, isPlatformStoreBuy = false } = props
|
||||
if (!info) {
|
||||
return null
|
||||
}
|
||||
|
||||
const showStore = info.isTotalStore === true
|
||||
const showPlatformStore = info.platformStore != null
|
||||
const showInventory = showStore || showPlatformStore
|
||||
const display = resolveDianwuGoodsDisplay(info, isPlatformStoreBuy)
|
||||
const showInventory = display.showStore || display.showCloud
|
||||
|
||||
return (
|
||||
<View className='comp-goods'>
|
||||
@@ -34,26 +34,15 @@ function CompGoods(props) {
|
||||
{info.name}
|
||||
</View>
|
||||
{info.itemSpecDesc && <View className='sku'>{info.itemSpecDesc}</View>}
|
||||
{/* <View className='price-list'>
|
||||
<SpPrice className='sale-price' value={999.99}></SpPrice>
|
||||
<View className='price-wrap'>
|
||||
<SpPrice className='vip-price' value={888.99}></SpPrice>
|
||||
<SpVipLabel content='VIP' type='vip' />
|
||||
</View>
|
||||
<View className='price-wrap'>
|
||||
<SpPrice className='svip-price' value={666.99}></SpPrice>
|
||||
<SpVipLabel content='SVIP' type='svip' />
|
||||
</View>
|
||||
</View> */}
|
||||
<CompGoodsPrice info={info} />
|
||||
<View className='goods-info'>
|
||||
<View className='kc-bn'>
|
||||
{showInventory && (
|
||||
<View className='kc'>
|
||||
<Text className='label'>{$t('982aa174.b008bd')}</Text>
|
||||
{showStore && <Text>{ti('982aa174.285600', [info.store])}</Text>}
|
||||
{showStore && showPlatformStore && <Text> | </Text>}
|
||||
{showPlatformStore && <Text>{ti('982aa174.f36d41', [info.platformStore])}</Text>}
|
||||
{display.showStore && <Text>{ti('982aa174.285600', [display.storeValue])}</Text>}
|
||||
{display.showStore && display.showCloud && <Text> | </Text>}
|
||||
{display.showCloud && <Text>{ti('982aa174.f36d41', [display.cloudValue])}</Text>}
|
||||
</View>
|
||||
)}
|
||||
{info.barcode && (
|
||||
@@ -64,12 +53,6 @@ function CompGoods(props) {
|
||||
)}
|
||||
</View>
|
||||
<View className='btn-actions'>{children}</View>
|
||||
{/* <AtButton circle className={classNames({ 'active': true })}>
|
||||
<Text className='iconfont icon-plus'></Text>
|
||||
</AtButton> */}
|
||||
{/* <AtButton circle disabled>
|
||||
缺货
|
||||
</AtButton> */}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -16,28 +16,21 @@ import { useNavigation } from '@/hooks'
|
||||
import CompGoods from './comps/comp-goods'
|
||||
import CompTabbar from './comps/comp-tabbar'
|
||||
import CompDianwuPlatformOrder from './comps/comp-dianwu-platform-order'
|
||||
import { isDianwuGoodsDisabled, resolveDianwuGoodsActions } from './utils/dianwu-goods-action'
|
||||
import './list.scss'
|
||||
|
||||
/** 无库存不可加购:门店与云仓均为 0 才禁用;未返回 platform_store 时仅按门店库存判断(与历史行为一致) */
|
||||
function isDianwuListGoodsDisabled(item) {
|
||||
if (item.store != 0) return false
|
||||
const ps = item.platformStore
|
||||
if (ps == null || ps === '') return true
|
||||
return ps == 0
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
keywords: '',
|
||||
list: [],
|
||||
current: 0,
|
||||
cartList: [],
|
||||
platformOrderItem: null
|
||||
platformOrderItem: null,
|
||||
isPlatformStoreBuy: false
|
||||
}
|
||||
|
||||
function DianWuList() {
|
||||
useTranslation()
|
||||
const [state, setState] = useImmer(initialState)
|
||||
const { keywords, typeList, current, list, cartList, platformOrderItem } = state
|
||||
const { keywords, list, cartList, platformOrderItem, isPlatformStoreBuy } = state
|
||||
const goodsRef = useRef()
|
||||
const $instance = getCurrentInstance() || {}
|
||||
const { distributor_id } = $instance?.router?.params
|
||||
@@ -72,13 +65,16 @@ function DianWuList() {
|
||||
}
|
||||
Taro.showLoading({ title: '' })
|
||||
try {
|
||||
const { list: _list, total_count } = await dianwuApi.goodsItems(params)
|
||||
const { list: _list, total_count, is_platform_store_buy } = await dianwuApi.goodsItems(params)
|
||||
|
||||
setState((draft) => {
|
||||
// 首屏请求需清空分页缓存,否则搜索无结果时仍保留上一关键词的多页数据
|
||||
if (pageIndex === 1) {
|
||||
draft.list = []
|
||||
}
|
||||
if (pageIndex === 1 && is_platform_store_buy != null) {
|
||||
draft.isPlatformStoreBuy = !!is_platform_store_buy
|
||||
}
|
||||
draft.list[pageIndex - 1] = pickBy(_list, doc.dianwu.GOODS_ITEM)
|
||||
})
|
||||
|
||||
@@ -153,40 +149,43 @@ function DianWuList() {
|
||||
</View>
|
||||
<SpScrollView className='item-list-scroll' auto={false} ref={goodsRef} fetch={fetch}>
|
||||
{list.map((items, idx) => {
|
||||
return items.map((item, sidx) => (
|
||||
<View
|
||||
className={classNames('item-wrap', {
|
||||
'item-disabled': isDianwuListGoodsDisabled(item)
|
||||
})}
|
||||
key={`item-wrap__${idx}_${sidx}`}
|
||||
>
|
||||
<CompGoods info={item}>
|
||||
{item.store > 0 && item.isTotalStore === true && (
|
||||
<AtButton
|
||||
className='btn-add-cart'
|
||||
circle
|
||||
onClick={handleAddToCart.bind(this, item)}
|
||||
>
|
||||
{$t('8cac8565.cd2240')}
|
||||
</AtButton>
|
||||
)}
|
||||
return items.map((item, sidx) => {
|
||||
const actions = resolveDianwuGoodsActions(item, isPlatformStoreBuy)
|
||||
return (
|
||||
<View
|
||||
className={classNames('item-wrap', {
|
||||
'item-disabled': isDianwuGoodsDisabled(item, isPlatformStoreBuy)
|
||||
})}
|
||||
key={`item-wrap__${idx}_${sidx}`}
|
||||
>
|
||||
<CompGoods info={item} isPlatformStoreBuy={isPlatformStoreBuy}>
|
||||
{actions.addToCashier && (
|
||||
<AtButton
|
||||
className='btn-add-cart'
|
||||
circle
|
||||
onClick={handleAddToCart.bind(this, item)}
|
||||
>
|
||||
{$t('8cac8565.cd2240')}
|
||||
</AtButton>
|
||||
)}
|
||||
|
||||
{item.store == 0 && item.platformStore > 0 && (
|
||||
<AtButton
|
||||
className='btn-add-cart btn-platform-order'
|
||||
circle
|
||||
onClick={() => {
|
||||
setState((draft) => {
|
||||
draft.platformOrderItem = item
|
||||
})
|
||||
}}
|
||||
>
|
||||
{$t('8cac8565.887eb6')}
|
||||
</AtButton>
|
||||
)}
|
||||
</CompGoods>
|
||||
</View>
|
||||
))
|
||||
{actions.buyNow && (
|
||||
<AtButton
|
||||
className='btn-add-cart btn-platform-order'
|
||||
circle
|
||||
onClick={() => {
|
||||
setState((draft) => {
|
||||
draft.platformOrderItem = item
|
||||
})
|
||||
}}
|
||||
>
|
||||
{$t('8cac8565.887eb6')}
|
||||
</AtButton>
|
||||
)}
|
||||
</CompGoods>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
})}
|
||||
</SpScrollView>
|
||||
|
||||
|
||||
107
src/subpages/dianwu/utils/dianwu-goods-action.js
Normal file
107
src/subpages/dianwu/utils/dianwu-goods-action.js
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright © ShopeX (http://www.shopex.cn). All rights reserved.
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
/** 商品开启店铺库存(店铺发货) */
|
||||
export function isDianwuStoreInventoryEnabled(item) {
|
||||
const v = item?.isTotalStore
|
||||
return v === false || v === 0 || v === '0' || v === 'false'
|
||||
}
|
||||
|
||||
function toStockNum(val) {
|
||||
const n = Number(val)
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
|
||||
function resolvePlatformStockNum(item) {
|
||||
if (item?.platformStore == null || item.platformStore === '') {
|
||||
return null
|
||||
}
|
||||
return toStockNum(item.platformStore)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} item pickBy(GOODS_ITEM)
|
||||
* @param {boolean} isPlatformStoreBuy 门店 is_platform_store_buy
|
||||
*/
|
||||
export function resolveDianwuGoodsDisplay(item, isPlatformStoreBuy) {
|
||||
const storeStock = toStockNum(item?.store)
|
||||
const platformStock = resolvePlatformStockNum(item)
|
||||
const storeInventoryEnabled = isDianwuStoreInventoryEnabled(item)
|
||||
|
||||
if (isPlatformStoreBuy) {
|
||||
if (storeInventoryEnabled) {
|
||||
return {
|
||||
showStore: true,
|
||||
showCloud: platformStock != null,
|
||||
storeValue: storeStock,
|
||||
cloudValue: platformStock != null ? platformStock : 0
|
||||
}
|
||||
}
|
||||
return {
|
||||
showStore: false,
|
||||
showCloud: true,
|
||||
storeValue: 0,
|
||||
cloudValue: platformStock != null ? platformStock : storeStock
|
||||
}
|
||||
}
|
||||
|
||||
if (storeInventoryEnabled) {
|
||||
return {
|
||||
showStore: true,
|
||||
showCloud: false,
|
||||
storeValue: storeStock,
|
||||
cloudValue: 0
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
showStore: false,
|
||||
showCloud: true,
|
||||
storeValue: 0,
|
||||
cloudValue: storeStock
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} item
|
||||
* @param {boolean} isPlatformStoreBuy
|
||||
*/
|
||||
export function resolveDianwuGoodsActions(item, isPlatformStoreBuy) {
|
||||
const storeStock = toStockNum(item?.store)
|
||||
const platformStock = resolvePlatformStockNum(item)
|
||||
const storeInventoryEnabled = isDianwuStoreInventoryEnabled(item)
|
||||
|
||||
let addToCashier = false
|
||||
let buyNow = false
|
||||
|
||||
if (isPlatformStoreBuy) {
|
||||
if (storeInventoryEnabled) {
|
||||
if (storeStock > 0) {
|
||||
addToCashier = true
|
||||
} else if (platformStock != null && platformStock > 0) {
|
||||
buyNow = true
|
||||
}
|
||||
} else if (platformStock != null && platformStock > 0) {
|
||||
buyNow = true
|
||||
}
|
||||
} else if (storeInventoryEnabled) {
|
||||
if (storeStock > 0) {
|
||||
addToCashier = true
|
||||
}
|
||||
} else if (storeStock > 0) {
|
||||
buyNow = true
|
||||
}
|
||||
|
||||
return { addToCashier, buyNow }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} item
|
||||
* @param {boolean} isPlatformStoreBuy
|
||||
*/
|
||||
export function isDianwuGoodsDisabled(item, isPlatformStoreBuy) {
|
||||
const { addToCashier, buyNow } = resolveDianwuGoodsActions(item, isPlatformStoreBuy)
|
||||
return !addToCashier && !buyNow
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export default class WgtFilm extends Component {
|
||||
const { width, height, objectFit } = this.resolveSize(config, screenWidth, base)
|
||||
|
||||
return (
|
||||
<View className={`wgt ${base.padded ? 'wgt__padded' : null}`}>
|
||||
<View className={`wgt wgt-guide-film ${base.padded ? 'wgt__padded' : null}`}>
|
||||
{base.title && (
|
||||
<View className='wgt__header'>
|
||||
<View className='wgt__title'>{base.title}</View>
|
||||
|
||||
@@ -2,34 +2,13 @@
|
||||
* Copyright © ShopeX (http://www.shopex.cn). All rights reserved.
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
.wgt-film {
|
||||
.wgts {
|
||||
&__header {
|
||||
// padding: 45px 30px 30px;
|
||||
padding: 15px 30px 30px;
|
||||
}
|
||||
&__title {
|
||||
line-height: 18px;
|
||||
letter-spacing: 1px;
|
||||
color: #000000;
|
||||
font-size: 32px;
|
||||
}
|
||||
&__subtitle {
|
||||
font-size: 22px;
|
||||
line-height: 18px;
|
||||
margin-top: 22px;
|
||||
color: #8a8a8a;
|
||||
}
|
||||
&__wrap {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
.wgt-guide-film {
|
||||
.flim-video {
|
||||
width: 100%;
|
||||
display: block;
|
||||
|
||||
.flim-video {
|
||||
width: 100%;
|
||||
display: block;
|
||||
&.is-fullscreen {
|
||||
position: absolute;
|
||||
&.is-fullscreen {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2932,6 +2932,7 @@
|
||||
"09e29d60.625fb2": "إلغاء",
|
||||
"09e29d60.3a6fa4": "اختيار عضو",
|
||||
"09e29d60.9fd000": "إنشاء الآن",
|
||||
"09e29d60.g3q6mc": "فشل مزامنة جلسة العضو",
|
||||
"eac57497.887eb6": "اطلب الآن",
|
||||
"eac57497.0bf60b": "الكمية",
|
||||
"eac57497.5591b7": "${0} متاح في المستودع السحابي",
|
||||
|
||||
@@ -2932,6 +2932,7 @@
|
||||
"09e29d60.625fb2": "Cancel",
|
||||
"09e29d60.3a6fa4": "Select member",
|
||||
"09e29d60.9fd000": "Create now",
|
||||
"09e29d60.g3q6mc": "Failed to sync member session",
|
||||
"eac57497.887eb6": "Order now",
|
||||
"eac57497.0bf60b": "Quantity",
|
||||
"eac57497.5591b7": "${0} available in cloud warehouse",
|
||||
|
||||
@@ -2936,6 +2936,7 @@
|
||||
"09e29d60.625fb2": "取消",
|
||||
"09e29d60.3a6fa4": "选择会员",
|
||||
"09e29d60.9fd000": "立即创建",
|
||||
"09e29d60.g3q6mc": "会员就绪同步失败",
|
||||
"eac57497.887eb6": "立即下单",
|
||||
"eac57497.0bf60b": "数量",
|
||||
"eac57497.5591b7": "云仓可售 ${0} 件",
|
||||
|
||||
@@ -5,25 +5,24 @@
|
||||
.page-point-detail {
|
||||
overflow-x: hidden;
|
||||
.point-detail-hd {
|
||||
width: 850px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
background: var(--color-primary);
|
||||
border-radius: 0 0 150px 150px;
|
||||
border-radius: 0 0 80px 80px;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.point-info {
|
||||
width: 710px;
|
||||
box-sizing: border-box;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
width: auto;
|
||||
height: 190px;
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: -80px;
|
||||
padding: 30px 40px;
|
||||
box-sizing: border-box;
|
||||
&-hd {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -11,21 +11,34 @@
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 14px 16px 0;
|
||||
}
|
||||
.switch-tab {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
max-width: 100%;
|
||||
background: #f5f5f5;
|
||||
border-radius: 50px;
|
||||
margin: 14px 16px 10px 20px;
|
||||
margin: 0 0 16px;
|
||||
padding: 4px;
|
||||
font-size: 24px;
|
||||
box-sizing: border-box;
|
||||
.switch-item {
|
||||
// padding: 0px 30px;
|
||||
width: 160px;
|
||||
width: auto;
|
||||
min-width: 100px;
|
||||
max-width: 100%;
|
||||
padding: 0 24px;
|
||||
text-align: center;
|
||||
height: 65px;
|
||||
line-height: 65px;
|
||||
color: #666;
|
||||
border-radius: 50px;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
&.active {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
@@ -34,6 +47,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.address-picker {
|
||||
.address {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
.address-module {
|
||||
background: #fff;
|
||||
padding: 12px 30px;
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
pickBy,
|
||||
authSetting,
|
||||
showToast,
|
||||
isWeb,
|
||||
isAPP,
|
||||
isWxWeb,
|
||||
log,
|
||||
@@ -48,7 +47,7 @@ function PointShopEspierCheckout() {
|
||||
const { i18n } = useTranslation()
|
||||
const $instance = getCurrentInstance() || {}
|
||||
const { updateAddress } = useLocation()
|
||||
const { isLogin, isNewUser, getUserInfoAuth } = useLogin({
|
||||
const { isLogin } = useLogin({
|
||||
autoLogin: true,
|
||||
loginSuccess: () => {
|
||||
updateAddress()
|
||||
@@ -125,12 +124,13 @@ function PointShopEspierCheckout() {
|
||||
}, [isLogin])
|
||||
|
||||
useEffect(() => {
|
||||
if (isNewUser) {
|
||||
const token = S?.getAuthToken()
|
||||
if (!token) {
|
||||
Taro.redirectTo({
|
||||
url: `/subpages/member/index`
|
||||
})
|
||||
}
|
||||
}, [isNewUser])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(
|
||||
@@ -638,7 +638,12 @@ function PointShopEspierCheckout() {
|
||||
}
|
||||
|
||||
return (
|
||||
<SpPage ref={pageRef} className='page-pointshop-espiercheckout' renderFooter={renderFooter()}>
|
||||
<SpPage
|
||||
ref={pageRef}
|
||||
className='page-pointshop-espiercheckout'
|
||||
footerHeight={140}
|
||||
renderFooter={renderFooter()}
|
||||
>
|
||||
<View className='cart-checkout__address'>
|
||||
<CompDeliver
|
||||
ref={deliverRef}
|
||||
|
||||
@@ -13,15 +13,23 @@ $margin24: 24px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
background: #fff;
|
||||
padding: 0 20px;
|
||||
padding: 12px 20px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
&__total {
|
||||
white-space: nowrap;
|
||||
white-space: normal;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
line-height: 1.35;
|
||||
color: #333;
|
||||
.last_price {
|
||||
display: inline-block;
|
||||
.sp-price__append {
|
||||
@@ -30,8 +38,23 @@ $margin24: 24px;
|
||||
}
|
||||
}
|
||||
.checkout-total {
|
||||
margin-left: 20px;
|
||||
line-height: 32px;
|
||||
margin-left: 0;
|
||||
margin-top: 4px;
|
||||
width: 100%;
|
||||
line-height: 1.4;
|
||||
font-size: 22px;
|
||||
word-break: break-word;
|
||||
}
|
||||
.at-button {
|
||||
flex-shrink: 0;
|
||||
width: auto !important;
|
||||
min-width: 180px;
|
||||
max-width: 240px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
margin: 0;
|
||||
padding: 0 24px;
|
||||
font-size: 28px;
|
||||
}
|
||||
&__price {
|
||||
display: inline-block;
|
||||
@@ -211,11 +234,27 @@ $margin24: 24px;
|
||||
padding: 16px 0px;
|
||||
}
|
||||
}
|
||||
.trade-remark {
|
||||
.sp-cell__bd {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
.trade-remark__input,
|
||||
.at-input {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
&:after {
|
||||
border: none;
|
||||
}
|
||||
.at-input__input {
|
||||
font-size: 24px;
|
||||
}
|
||||
.input-placeholder {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright © ShopeX (http://www.shopex.cn). All rights reserved.
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import React, { useEffect, useRef, useState, memo, useCallback } from 'react'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { View, Text, Input, Picker } from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
@@ -24,6 +24,13 @@ const PLACEHOLDER_CITY = '选择市'
|
||||
const PLACEHOLDER_DISTRICT = '选择区'
|
||||
const DISTRICT_UNLIMITED = '__DISTRICT_UNLIMITED__'
|
||||
|
||||
function getDistrictLabels(city, unlimitedLabel) {
|
||||
if (city?.children?.length) {
|
||||
return [unlimitedLabel, ...city.children.map((d) => d.label)]
|
||||
}
|
||||
return [unlimitedLabel]
|
||||
}
|
||||
|
||||
function displayPickerLabel(value) {
|
||||
if (value === PLACEHOLDER_PROVINCE) return $t('9e660622.19a4c5')
|
||||
if (value === PLACEHOLDER_CITY) return $t('9e660622.0c1085')
|
||||
@@ -32,12 +39,114 @@ function displayPickerLabel(value) {
|
||||
return value
|
||||
}
|
||||
|
||||
/** 独立子组件:避免列表刷新导致 Picker value 被重置、滚动回弹 */
|
||||
const LocationRegionPicker = memo(function LocationRegionPicker({
|
||||
provinceLabel,
|
||||
cityLabel,
|
||||
districtLabel,
|
||||
onConfirm
|
||||
}) {
|
||||
useTranslation()
|
||||
const [areaData, setAreaData] = useState([])
|
||||
const [areaList, setAreaList] = useState([[], [], []])
|
||||
const [multiIndex, setMultiIndex] = useState([0, 0, 0])
|
||||
|
||||
const loadArea = useCallback(async () => {
|
||||
try {
|
||||
const res = await api.member.areaList()
|
||||
if (!res?.length) return
|
||||
|
||||
const unlimitedLabel = $t('9e660622.8441b3')
|
||||
const provinces = res.map((item) => item.label)
|
||||
const firstCity = res[0]?.children?.[0]
|
||||
const cities = res[0]?.children?.map((c) => c.label) || ['']
|
||||
const districts = getDistrictLabels(firstCity, unlimitedLabel)
|
||||
|
||||
setAreaData(res)
|
||||
setAreaList([provinces, cities.length ? cities : [''], districts])
|
||||
setMultiIndex([0, 0, 0])
|
||||
} catch (e) {
|
||||
console.error('loadArea error', e)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadArea()
|
||||
}, [loadArea])
|
||||
|
||||
useEffect(() => {
|
||||
const onLanguageChanged = () => {
|
||||
loadArea()
|
||||
}
|
||||
i18n.on('languageChanged', onLanguageChanged)
|
||||
return () => i18n.off('languageChanged', onLanguageChanged)
|
||||
}, [loadArea])
|
||||
|
||||
const onColumnChange = (e) => {
|
||||
const { column, value } = e.detail
|
||||
const unlimitedLabel = $t('9e660622.8441b3')
|
||||
|
||||
if (column === 0) {
|
||||
const province = areaData[value]
|
||||
const cities = province?.children?.map((c) => c.label) || ['']
|
||||
const districts = getDistrictLabels(province?.children?.[0], unlimitedLabel)
|
||||
setMultiIndex([value, 0, 0])
|
||||
setAreaList([areaList[0], cities.length ? cities : [''], districts])
|
||||
} else if (column === 1) {
|
||||
const city = areaData[multiIndex[0]]?.children?.[value]
|
||||
const districts = getDistrictLabels(city, unlimitedLabel)
|
||||
setMultiIndex([multiIndex[0], value, 0])
|
||||
setAreaList([areaList[0], areaList[1], districts])
|
||||
} else {
|
||||
setMultiIndex([multiIndex[0], multiIndex[1], value])
|
||||
}
|
||||
}
|
||||
|
||||
const onChange = (e) => {
|
||||
const [provinceIndex, cityIndex, districtIndex] = e.detail.value || [0, 0, 0]
|
||||
const province = areaData[provinceIndex]
|
||||
const city = province?.children?.[cityIndex]
|
||||
const district = districtIndex === 0 ? null : city?.children?.[districtIndex - 1]
|
||||
|
||||
setMultiIndex([provinceIndex, cityIndex, districtIndex])
|
||||
onConfirm({
|
||||
province: province?.label || PLACEHOLDER_PROVINCE,
|
||||
city: city?.label || PLACEHOLDER_CITY,
|
||||
district:
|
||||
districtIndex === 0 ? DISTRICT_UNLIMITED : district?.label || PLACEHOLDER_DISTRICT
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Picker
|
||||
mode='multiSelector'
|
||||
range={areaList}
|
||||
value={multiIndex}
|
||||
disabled={!areaList[0]?.length}
|
||||
onColumnChange={onColumnChange}
|
||||
onChange={onChange}
|
||||
>
|
||||
<View className='location-picker'>
|
||||
<View className='picker-item'>
|
||||
<Text className='picker-item-label'>{displayPickerLabel(provinceLabel)}</Text>
|
||||
<Text className='iconfont icon-xialajiantou arrow-icon'></Text>
|
||||
</View>
|
||||
<View className='picker-item'>
|
||||
<Text className='picker-item-label'>{displayPickerLabel(cityLabel)}</Text>
|
||||
<Text className='iconfont icon-xialajiantou arrow-icon'></Text>
|
||||
</View>
|
||||
<View className='picker-item'>
|
||||
<Text className='picker-item-label'>{displayPickerLabel(districtLabel)}</Text>
|
||||
<Text className='iconfont icon-xialajiantou arrow-icon'></Text>
|
||||
</View>
|
||||
</View>
|
||||
</Picker>
|
||||
)
|
||||
})
|
||||
|
||||
const initialState = {
|
||||
shopList: [],
|
||||
keyword: '',
|
||||
locationList: [],
|
||||
locationRange: [[], [], []],
|
||||
locationValue: [0, 0, 0],
|
||||
selectedProvince: PLACEHOLDER_PROVINCE,
|
||||
selectedCity: PLACEHOLDER_CITY,
|
||||
selectedDistrict: PLACEHOLDER_DISTRICT,
|
||||
@@ -62,8 +171,6 @@ function NearbyList() {
|
||||
const {
|
||||
shopList,
|
||||
keyword,
|
||||
locationRange,
|
||||
locationValue,
|
||||
selectedProvince,
|
||||
selectedCity,
|
||||
selectedDistrict,
|
||||
@@ -125,7 +232,6 @@ function NearbyList() {
|
||||
useEffect(() => {
|
||||
const onLanguageChanged = () => {
|
||||
setNavigationBarTitle($t('678873b3.9f3102'))
|
||||
initLocationPicker()
|
||||
}
|
||||
onLanguageChanged()
|
||||
i18n.on('languageChanged', onLanguageChanged)
|
||||
@@ -133,7 +239,6 @@ function NearbyList() {
|
||||
}, [setNavigationBarTitle])
|
||||
|
||||
useEffect(() => {
|
||||
initLocationPicker()
|
||||
getLocationInfo()
|
||||
fetchCategoryList()
|
||||
}, [])
|
||||
@@ -158,28 +263,6 @@ function NearbyList() {
|
||||
}
|
||||
}, [refresh])
|
||||
|
||||
const initLocationPicker = async () => {
|
||||
try {
|
||||
const res = await api.member.areaList()
|
||||
if (!res || !Array.isArray(res)) return
|
||||
|
||||
const provinces = res.map((item) => item.label)
|
||||
const cities = res[0]?.children ? res[0].children.map((c) => c.label) : []
|
||||
const unlimitedLabel = $t('9e660622.8441b3')
|
||||
const districts = res[0]?.children?.[0]?.children
|
||||
? [unlimitedLabel, ...res[0].children[0].children.map((d) => d.label)]
|
||||
: [unlimitedLabel]
|
||||
|
||||
setState((draft) => {
|
||||
draft.locationList = res
|
||||
draft.locationRange = [provinces, cities, districts]
|
||||
draft.locationValue = [0, 0, 0]
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('initLocationPicker error', e)
|
||||
}
|
||||
}
|
||||
|
||||
const getLocationInfo = async () => {
|
||||
await entryLaunch.isOpenPosition(async (res) => {
|
||||
bumpListFetchGen()
|
||||
@@ -361,49 +444,16 @@ function NearbyList() {
|
||||
return category?.category_name || $t('9e660622.a48948')
|
||||
}
|
||||
|
||||
const onColumnChange = (e) => {
|
||||
const { column, value } = e.detail
|
||||
const handleLocationConfirm = useCallback((selection) => {
|
||||
bumpListFetchGen()
|
||||
setState((draft) => {
|
||||
if (column === 0) {
|
||||
draft.locationValue = [value, 0, 0]
|
||||
const currentProvince = draft.locationList[value]
|
||||
const cities = currentProvince?.children ? currentProvince.children.map((c) => c.label) : []
|
||||
const unlimitedLabel = $t('9e660622.8441b3')
|
||||
const districts = currentProvince?.children?.[0]?.children
|
||||
? [unlimitedLabel, ...currentProvince.children[0].children.map((d) => d.label)]
|
||||
: [unlimitedLabel]
|
||||
draft.locationRange = [draft.locationRange[0], cities, districts]
|
||||
} else if (column === 1) {
|
||||
draft.locationValue[1] = value
|
||||
draft.locationValue[2] = 0
|
||||
const currentProvince = draft.locationList[draft.locationValue[0]]
|
||||
const currentCity = currentProvince?.children?.[value]
|
||||
const unlimitedLabel = $t('9e660622.8441b3')
|
||||
const districts = currentCity?.children
|
||||
? [unlimitedLabel, ...currentCity.children.map((d) => d.label)]
|
||||
: [unlimitedLabel]
|
||||
draft.locationRange[2] = districts
|
||||
} else if (column === 2) {
|
||||
draft.locationValue[2] = value
|
||||
}
|
||||
draft.selectedProvince = selection.province
|
||||
draft.selectedCity = selection.city
|
||||
draft.selectedDistrict = selection.district
|
||||
draft.shopList = []
|
||||
draft.refresh = true
|
||||
})
|
||||
}
|
||||
|
||||
const onLocationChange = (e) => {
|
||||
const [provinceIndex, cityIndex, districtIndex] = e.detail.value || [0, 0, 0]
|
||||
setState((draft) => {
|
||||
const province = draft.locationList[provinceIndex]
|
||||
const city = province?.children?.[cityIndex]
|
||||
// 区列表第一项是"不限",所以索引需要减1
|
||||
const district = districtIndex === 0 ? null : city?.children?.[districtIndex - 1]
|
||||
draft.selectedProvince = province?.label || PLACEHOLDER_PROVINCE
|
||||
draft.selectedCity = city?.label || PLACEHOLDER_CITY
|
||||
draft.selectedDistrict =
|
||||
districtIndex === 0 ? DISTRICT_UNLIMITED : district?.label || PLACEHOLDER_DISTRICT
|
||||
draft.locationValue = [provinceIndex, cityIndex, districtIndex]
|
||||
})
|
||||
refreshList()
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleNavigation = (e, info) => {
|
||||
e.stopPropagation()
|
||||
@@ -479,7 +529,7 @@ function NearbyList() {
|
||||
/>
|
||||
|
||||
{/* 搜索筛选区域 */}
|
||||
<View className='filter-section'>
|
||||
<View className={classNames('filter-section', { 'is-store-type-open': showStoreTypePicker })}>
|
||||
{/* 搜索框和门店类型 */}
|
||||
<View className='search-row-wrapper'>
|
||||
<View className='search-row'>
|
||||
@@ -550,28 +600,12 @@ function NearbyList() {
|
||||
|
||||
{/* 省市区选择 */}
|
||||
<View className='location-row'>
|
||||
<Picker
|
||||
mode='multiSelector'
|
||||
range={locationRange}
|
||||
value={locationValue}
|
||||
onColumnChange={onColumnChange}
|
||||
onChange={onLocationChange}
|
||||
>
|
||||
<View className='location-picker'>
|
||||
<View className='picker-item'>
|
||||
<Text>{displayPickerLabel(selectedProvince)}</Text>
|
||||
<Text className='iconfont icon-xialajiantou arrow-icon'></Text>
|
||||
</View>
|
||||
<View className='picker-item'>
|
||||
<Text>{displayPickerLabel(selectedCity)}</Text>
|
||||
<Text className='iconfont icon-xialajiantou arrow-icon'></Text>
|
||||
</View>
|
||||
<View className='picker-item'>
|
||||
<Text>{displayPickerLabel(selectedDistrict)}</Text>
|
||||
<Text className='iconfont icon-xialajiantou arrow-icon'></Text>
|
||||
</View>
|
||||
</View>
|
||||
</Picker>
|
||||
<LocationRegionPicker
|
||||
provinceLabel={selectedProvince}
|
||||
cityLabel={selectedCity}
|
||||
districtLabel={selectedDistrict}
|
||||
onConfirm={handleLocationConfirm}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
.filter-section {
|
||||
background-color: #f3f3f3;
|
||||
padding: 40px 36px 24px;
|
||||
flex-shrink: 0;
|
||||
|
||||
border-radius: 16px 16px 0 0;
|
||||
display: flex;
|
||||
@@ -34,6 +35,7 @@
|
||||
|
||||
.search-row-wrapper {
|
||||
position: relative;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.search-row {
|
||||
@@ -97,6 +99,9 @@
|
||||
}
|
||||
|
||||
.location-row {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
|
||||
.location-picker {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -104,19 +109,36 @@
|
||||
padding: 0 16px;
|
||||
|
||||
.picker-item {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
font-size: 24px;
|
||||
color: #000;
|
||||
|
||||
.picker-item-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@include multi-ellipsis(1);
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 10px;
|
||||
color: #444;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-store-type-open {
|
||||
.location-row {
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 门店列表滚动区域
|
||||
@@ -288,7 +310,7 @@
|
||||
right: -36px;
|
||||
width: calc(100% + 72px);
|
||||
background-color: #fff;
|
||||
z-index: 100;
|
||||
z-index: 201;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.dropdown-content {
|
||||
|
||||
Reference in New Issue
Block a user