@ -1,211 +0,0 @@ |
|||
import "./style.scss"; |
|||
import React, { useState, useEffect } from "react"; |
|||
|
|||
import search from "./search.png"; |
|||
import close from "./close.png"; |
|||
import go from "./go.png"; |
|||
import arrow from "./arrow.png"; |
|||
import ShopsWithFilter from "../ShopsWithFilter/ShopsWithFilter"; |
|||
const STATES = { |
|||
init: 0, |
|||
moreFac: 1, |
|||
facList: 2, |
|||
}; |
|||
export const DefaultPopupStates = STATES; |
|||
const initMarginBottom = 47; |
|||
const DefaultPopup = ({ |
|||
state, |
|||
setState, |
|||
onSearch, |
|||
facilities, |
|||
onClickFac, |
|||
mall, |
|||
onClick, |
|||
setEnd, |
|||
hasTab, |
|||
blurMap = () => {}, |
|||
}) => { |
|||
const marginBottomStateMap = { |
|||
0: 47, |
|||
1: hasTab |
|||
? window.innerHeight - 52 - 179 - 98 |
|||
: window.innerHeight - 52 - 179, |
|||
}; |
|||
const baseMarginBottom = marginBottomStateMap[state]; |
|||
const [facList, setFacList] = useState(null); |
|||
const [focused, setFocused] = useState(null); |
|||
const [start, setStart] = useState(null); |
|||
const [marginBottom, setMarginBottom] = useState(null); |
|||
const [doTransition, setdoTransition] = useState(false); |
|||
useEffect(() => { |
|||
setdoTransition(true); |
|||
setMarginBottom(baseMarginBottom); |
|||
setTimeout(() => { |
|||
setdoTransition(false); |
|||
}, 500); |
|||
}, [state]); |
|||
const handleTouchStart = (e) => { |
|||
if (start) return; |
|||
setStart({ |
|||
identifier: e.changedTouches[0].identifier, |
|||
y: e.changedTouches[0].clientY, |
|||
}); |
|||
}; |
|||
const handleTouchMove = (e) => { |
|||
if (!start) return; |
|||
const touch = Array.from(e.changedTouches).find( |
|||
({ identifier }) => identifier === start.identifier |
|||
); |
|||
if (!touch) return; |
|||
const delta = touch.clientY - start.y; |
|||
setMarginBottom(baseMarginBottom - delta); |
|||
}; |
|||
const handleTouchEnd = (e) => { |
|||
if (!start) return; |
|||
const touch = Array.from(e.changedTouches).find( |
|||
({ identifier }) => identifier === start.identifier |
|||
); |
|||
if (!touch) return; |
|||
setStart(null); |
|||
const delta = touch.clientY - start.y; |
|||
const newState = |
|||
state === STATES.init && delta < -100 |
|||
? STATES.moreFac |
|||
: state === STATES.moreFac && delta > 100 |
|||
? STATES.init |
|||
: state; |
|||
|
|||
if (state === newState) { |
|||
setdoTransition(true); |
|||
setMarginBottom(baseMarginBottom); |
|||
setTimeout(() => { |
|||
setdoTransition(false); |
|||
}, 500); |
|||
} else setState(newState); |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
{state === STATES.init || state === STATES.moreFac ? ( |
|||
<div |
|||
className={"dp" + (state === STATES.moreFac ? " more-fac" : "")} |
|||
style={{ |
|||
marginBottom: marginBottom + "px", |
|||
transition: !doTransition ? "none" : "margin-bottom 0.5s ease", |
|||
}} |
|||
onTouchStart={handleTouchStart} |
|||
onTouchMove={handleTouchMove} |
|||
onTouchCancel={handleTouchEnd} |
|||
onTouchEnd={handleTouchEnd} |
|||
> |
|||
<div |
|||
className="ts" |
|||
onClick={() => |
|||
setState(state === STATES.moreFac ? STATES.init : STATES.moreFac) |
|||
} |
|||
> |
|||
<img className="t1" src={arrow} /> |
|||
</div> |
|||
|
|||
<div className="search" onClick={onSearch}> |
|||
<img className="icon" src={search}></img> |
|||
<div className="sep"></div> |
|||
搜索店铺 |
|||
</div> |
|||
<div className="facs"> |
|||
{Object.entries(facilities).map(([name, list]) => ( |
|||
<div |
|||
className="fac" |
|||
key={name} |
|||
onClick={() => { |
|||
list.sort((a, b) => a.floorOrder - b.floorOrder); |
|||
setFacList(list); |
|||
setState(STATES.facList); |
|||
}} |
|||
> |
|||
<img src={list[0].url}></img> |
|||
{name} |
|||
</div> |
|||
))} |
|||
</div> |
|||
</div> |
|||
) : ( |
|||
<> |
|||
<img |
|||
src={close} |
|||
className="close" |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
setState(STATES.init); |
|||
setFacList(null); |
|||
blurMap(); |
|||
}} |
|||
></img> |
|||
<div className="dp1"> |
|||
{facList && |
|||
facList.map((fac, i) => { |
|||
const showRow1 = |
|||
i === 0 || fac.floorName !== facList[i - 1].floorName; |
|||
const isActive = focused === fac.id; |
|||
return ( |
|||
<div key={fac.id}> |
|||
{showRow1 && ( |
|||
<div className={"row1" + (i === 0 ? "" : " has-border")}> |
|||
{fac.floorName} |
|||
</div> |
|||
)} |
|||
<div |
|||
className={[ |
|||
"row2", |
|||
isActive ? "active" : "", |
|||
!showRow1 ? "has-margin" : "", |
|||
].join(" ")} |
|||
onClick={() => { |
|||
setFocused(fac.id); |
|||
onClickFac(fac.id); |
|||
}} |
|||
> |
|||
{fac.name} |
|||
<span className="meta">{fac.floorName}</span> |
|||
{isActive && ( |
|||
<div |
|||
className="go" |
|||
src={go} |
|||
onClick={(e) => { |
|||
e.stopPropagation(); |
|||
setState(STATES.init); |
|||
onClickFac(fac.id); |
|||
}} |
|||
> |
|||
GO |
|||
</div> |
|||
)} |
|||
</div> |
|||
</div> |
|||
); |
|||
})} |
|||
</div> |
|||
</> |
|||
)} |
|||
{state !== STATES.facList && ( |
|||
<div |
|||
className="sf" |
|||
onClick={() => { |
|||
setState(STATES.moreFac); |
|||
}} |
|||
> |
|||
<ShopsWithFilter |
|||
mall={mall} |
|||
onClick={(e) => { |
|||
setState(STATES.init); |
|||
onClick(e); |
|||
}} |
|||
wingHeight="calc(100vh - 310px)" |
|||
></ShopsWithFilter> |
|||
</div> |
|||
)} |
|||
</> |
|||
); |
|||
}; |
|||
export default DefaultPopup; |
|||
|
Before Width: | Height: | Size: 526 B |
|
Before Width: | Height: | Size: 596 B |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,231 +0,0 @@ |
|||
.dp { |
|||
position: relative; |
|||
width: calc(100vw - 20px); |
|||
margin-left: 10px; |
|||
height: 179px; |
|||
border-top-left-radius: 24px; |
|||
border-top-right-radius: 24px; |
|||
text-align: center; |
|||
position: relative; |
|||
padding: 14px 0 0 0; |
|||
background: #ffffff; |
|||
box-shadow: 0px 12px 16px rgba(104, 110, 127, 0.08); |
|||
border-radius: 18px; |
|||
&::before { |
|||
position: absolute; |
|||
content: ""; |
|||
top: 0; |
|||
left: -10px; |
|||
right: -10px; |
|||
height: 236px; |
|||
background: linear-gradient( |
|||
180deg, |
|||
rgba(243, 244, 248, 0) 0%, |
|||
#f3f4f8 41.53%, |
|||
#f3f4f8 100% |
|||
); |
|||
z-index: -1; |
|||
} |
|||
&::after { |
|||
position: absolute; |
|||
content: ""; |
|||
left: -10px; |
|||
right: -10px; |
|||
top: 236px; |
|||
height: calc(100vh - 52px - 236px); |
|||
background: #f3f4f8; |
|||
z-index: -1; |
|||
} |
|||
&.more-fac { |
|||
.t1, |
|||
.t2 { |
|||
transform: rotate(180deg); |
|||
} |
|||
.facs { |
|||
max-height: 333px; |
|||
overflow-y: scroll; |
|||
} |
|||
} |
|||
.ts { |
|||
position: absolute; |
|||
margin: auto; |
|||
left: 0; |
|||
right: 0; |
|||
top: 0; |
|||
width: 24px; |
|||
height: 24px; |
|||
.t1 { |
|||
position: absolute; |
|||
margin: auto; |
|||
left: 0; |
|||
right: 0; |
|||
top: 3px; |
|||
width: 33px; |
|||
height: 7px; |
|||
border-radius: 5px; |
|||
} |
|||
} |
|||
|
|||
.search { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 14px; |
|||
height: 60px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 16px; |
|||
color: #323337; |
|||
text-align: left; |
|||
background: #f3f4f8; |
|||
border: 1px solid #edeff3; |
|||
box-sizing: border-box; |
|||
border-radius: 10px; |
|||
padding-left: 14px; |
|||
.icon { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
.sep { |
|||
width: 1px; |
|||
height: 16px; |
|||
background: #c9cbd1; |
|||
margin: 0 14px; |
|||
} |
|||
} |
|||
|
|||
.facs { |
|||
display: inline-flex; |
|||
align-items: flex-start; |
|||
overflow-x: auto; |
|||
overflow-y: hidden; |
|||
width: 100%; |
|||
white-space: nowrap; |
|||
margin-top: 20px; |
|||
padding-left: 20px; |
|||
height: 75px; |
|||
.fac { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
height: 65px; |
|||
margin-right: 20px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 11px; |
|||
line-height: 15px; |
|||
text-align: center; |
|||
color: #474a56; |
|||
align-items: center; |
|||
img { |
|||
display: block; |
|||
width: 44px; |
|||
height: 44px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.close { |
|||
position: absolute; |
|||
top: 16px; |
|||
right: 26px; |
|||
width: 24px; |
|||
height: 24px; |
|||
z-index: 10; |
|||
} |
|||
.dp1 { |
|||
position: relative; |
|||
margin: 0 10px 26px 10px; |
|||
height: 326px; |
|||
border-radius: 18px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 12px 16px rgba(104, 110, 127, 0.08); |
|||
text-align: center; |
|||
padding: 14px; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
.row1, |
|||
.row2 { |
|||
text-align: left; |
|||
line-height: 48px; |
|||
height: 48px; |
|||
} |
|||
.row1 { |
|||
font-family: DINPro; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 24px; |
|||
line-height: 48px; |
|||
height: 48px; |
|||
color: #323337; |
|||
padding: 0 16px; |
|||
&.has-border { |
|||
position: relative; |
|||
padding-top: 24px; |
|||
height: 72px; |
|||
&::after { |
|||
position: absolute; |
|||
content: ""; |
|||
top: 12px; |
|||
left: 0; |
|||
right: 0; |
|||
border-top: 1px dashed #edeff3; |
|||
} |
|||
} |
|||
} |
|||
.row2 { |
|||
display: flex; |
|||
position: relative; |
|||
padding-left: 16px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 16px; |
|||
color: #323337; |
|||
background: #f9f9fb; |
|||
border-radius: 12px; |
|||
&.has-margin { |
|||
margin-top: 4px; |
|||
} |
|||
&.active { |
|||
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%); |
|||
color: #ffffff; |
|||
border-radius: 12px; |
|||
.meta { |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
.meta { |
|||
margin-left: 16px; |
|||
font-family: DINPro; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-size: 17px; |
|||
color: #a1a5b3; |
|||
} |
|||
.go { |
|||
position: absolute; |
|||
top: 8px; |
|||
right: 8px; |
|||
width: 96px; |
|||
height: 32px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 2px 6px rgba(93, 172, 249, 0.2); |
|||
border-radius: 8px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 600; |
|||
font-size: 16px; |
|||
line-height: 32px; |
|||
text-align: center; |
|||
color: #437af7; |
|||
} |
|||
} |
|||
} |
|||
.sf { |
|||
position: absolute; |
|||
top: 177px; |
|||
left: 0; |
|||
} |
|||
@ -1,184 +0,0 @@ |
|||
import React, { useState, useEffect } from "react"; |
|||
import ShopList from "../ShopList/ShopList.js"; |
|||
import "./HeadBar.scss"; |
|||
import { searchTypes } from "../Options/Options"; |
|||
import backpng from './back.png' |
|||
|
|||
const HeadBar = ({ |
|||
mall, |
|||
exit, |
|||
start, |
|||
end, |
|||
floors, |
|||
onSwap, |
|||
shop, |
|||
onSetStart, |
|||
onSetEnd, |
|||
isPick, |
|||
setIsPick, |
|||
blurMap, |
|||
showSearchType, |
|||
onClickSearchType, |
|||
searchType, |
|||
onIsTypingChange |
|||
}) => { |
|||
const [isTypingStart, setIsTypingStart] = useState(false); |
|||
const [isTypingEnd, setIsTypingEnd] = useState(false); |
|||
const isTyping = isTypingStart || isTypingEnd; |
|||
const [q, setQ] = useState(null); |
|||
const onlyShowStart = isTypingStart || (!start && isPick); |
|||
const onlyShowEnd = isTypingEnd || (!end && isPick); |
|||
const showStart = !onlyShowEnd; |
|||
const showEnd = !onlyShowStart; |
|||
const showBoth = !(isPick || isTyping); |
|||
const hasBoth = start && end; |
|||
const startValue = |
|||
q !== null ? q : isPick ? (shop ? shop.name : "") : start ? start.name : ""; |
|||
const endValue = |
|||
q !== null ? q : isPick ? (shop ? shop.name : "") : end ? end.name : ""; |
|||
|
|||
useEffect(() => { onIsTypingChange(isTyping) }, [isTyping]) |
|||
return ( |
|||
<div |
|||
className={"head-bar" + (showBoth ? " double" : "")} |
|||
onClick={() => blurMap()} |
|||
> |
|||
<div |
|||
className="back" |
|||
onClick={() => { |
|||
if (isPick) setIsPick(false); |
|||
else if (isTypingStart) { |
|||
setQ(null); |
|||
setIsTypingStart(false); |
|||
} else if (isTypingEnd) { |
|||
setQ(null); |
|||
setIsTypingEnd(false); |
|||
} else exit(); |
|||
}} |
|||
> |
|||
<img src={backpng}></img> |
|||
</div> |
|||
<div className="content"> |
|||
{showBoth && <div className="dots"></div>} |
|||
{showStart && ( |
|||
<div className={"row start" + (onlyShowStart ? " single" : "")}> |
|||
<div className="text"> |
|||
<input |
|||
value={startValue} |
|||
onFocus={() => setIsTypingStart(true)} |
|||
onChange={(e) => setQ(e.target.value)} |
|||
readOnly={isPick} |
|||
disabled={isPick} |
|||
placeholder={isPick ? "请点击地图选择起点" : "请输入起点"} |
|||
></input> |
|||
{(start || (isPick && shop)) && ( |
|||
<span className="label"> |
|||
{floors[(start ? start : shop).floorOrder][1]} |
|||
</span> |
|||
)} |
|||
<div style={{ flex: 1 }}></div> |
|||
{start === null && isPick && ( |
|||
<div |
|||
className='right' |
|||
onClick={() => { |
|||
setIsPick(false); |
|||
onSetStart(shop); |
|||
}} |
|||
> |
|||
开始导航 |
|||
</div> |
|||
)} |
|||
{start === null && !isPick && !isTypingStart && ( |
|||
<div |
|||
className="right" |
|||
onClick={() => { |
|||
setQ(null); |
|||
setIsPick(true); |
|||
setIsTypingStart(false); |
|||
setIsTypingEnd(false); |
|||
}} |
|||
> |
|||
地图选点 |
|||
</div> |
|||
)} |
|||
</div> |
|||
</div> |
|||
)} |
|||
{showEnd && ( |
|||
<div className={"row end" + (isPick ? " single" : "")}> |
|||
<div className={"text " + (isTypingEnd ? '' : 'has-border')}> |
|||
<input |
|||
value={endValue} |
|||
onFocus={() => setIsTypingEnd(true)} |
|||
onChange={(e) => setQ(e.target.value)} |
|||
readOnly={isPick} |
|||
disabled={isPick} |
|||
placeholder={isPick ? "请点击地图选择终点" : "请输入终点"} |
|||
></input> |
|||
{((isPick && shop) || end) && ( |
|||
<span className="label"> |
|||
{floors[(end ? end : shop).floorOrder][1]} |
|||
</span> |
|||
)} |
|||
<div style={{ flex: 1 }}></div> |
|||
{end === null && isPick && ( |
|||
<div |
|||
className={shop ? "right green" : "right grey"} |
|||
onClick={() => { |
|||
setIsPick(false); |
|||
onSetEnd(shop); |
|||
}} |
|||
> |
|||
开始导航 |
|||
</div> |
|||
)} |
|||
{end === null && !isPick && !isTypingEnd && ( |
|||
<div |
|||
className="right" |
|||
onClick={() => { |
|||
setQ(null); |
|||
setIsPick(true); |
|||
setIsTypingEnd(false); |
|||
}} |
|||
> |
|||
地图选点 |
|||
</div> |
|||
)} |
|||
</div> |
|||
</div> |
|||
)} |
|||
|
|||
{showBoth && <div className="switch" onClick={() => onSwap()}></div>} |
|||
</div> |
|||
{showBoth && !hasBoth && ( |
|||
<div className={"banner " + (start === null ? "start" : "end")}> |
|||
请在顶部选择{!start ? "起" : "终"}点 |
|||
</div> |
|||
)} |
|||
{isTyping && q && ( |
|||
<div className="shop-list-wrapper"> |
|||
<ShopList |
|||
mall={mall} |
|||
q={q} |
|||
onClick={(shop) => { |
|||
if (isTypingStart) { |
|||
onSetStart(shop); |
|||
setQ(null); |
|||
setIsTypingStart(false); |
|||
} |
|||
if (isTypingEnd) { |
|||
onSetEnd(shop); |
|||
setQ(null); |
|||
setIsTypingEnd(false); |
|||
} |
|||
}} |
|||
top={"70px"} |
|||
isRow={true} |
|||
></ShopList> |
|||
</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default HeadBar; |
|||
@ -1,271 +0,0 @@ |
|||
.head-bar { |
|||
display: flex; |
|||
box-sizing: border-box; |
|||
width: calc(100vw - 20px); |
|||
margin-left: 10px; |
|||
margin-top: 10px; |
|||
font-size: 16px; |
|||
line-height: 44px; |
|||
position: relative; |
|||
z-index: 1; |
|||
height: 64px; |
|||
position: relative; |
|||
border-radius: 12px; |
|||
align-items: center; |
|||
pointer-events: auto; |
|||
&.double { |
|||
height: 114px; |
|||
.back { |
|||
height: 114px; |
|||
} |
|||
.content { |
|||
height: 114px; |
|||
} |
|||
} |
|||
|
|||
.back { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: relative; |
|||
background: #ffffff; |
|||
flex: 0 0 50px; |
|||
margin-right: 8px; |
|||
height: 64px; |
|||
border-radius: 12px; |
|||
img { |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
} |
|||
.content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
background: #ffffff; |
|||
height: 64px; |
|||
z-index: 2; |
|||
flex: 1; |
|||
position: relative; |
|||
border-radius: 12px; |
|||
.dots { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 23px; |
|||
width: 2px; |
|||
height: 2px; |
|||
border-radius: 50%; |
|||
background: #c9cbd1; |
|||
margin: auto 0; |
|||
&::before { |
|||
content: ""; |
|||
display: block; |
|||
position: absolute; |
|||
top: -6px; |
|||
width: 2px; |
|||
height: 2px; |
|||
border-radius: 50%; |
|||
background: #c9cbd1; |
|||
left: 0; |
|||
right: 0; |
|||
margin: 0 auto; |
|||
} |
|||
&::after { |
|||
content: ""; |
|||
display: block; |
|||
position: absolute; |
|||
bottom: -6px; |
|||
width: 2px; |
|||
height: 2px; |
|||
border-radius: 50%; |
|||
background: #c9cbd1; |
|||
left: 0; |
|||
right: 0; |
|||
margin: 0 auto; |
|||
} |
|||
} |
|||
.row { |
|||
position: relative; |
|||
line-height: 57px; |
|||
height: 57px; |
|||
padding-left: 48px; |
|||
padding-right: 49px; |
|||
&.start { |
|||
background: 16px center/16px 16px no-repeat url("./start.png"); |
|||
} |
|||
&.end { |
|||
background: 16px center/16px 16px no-repeat url("./end.png"); |
|||
} |
|||
&.single { |
|||
padding-right: 10px; |
|||
} |
|||
.text { |
|||
display: flex; |
|||
align-items: center; |
|||
input { |
|||
border: none; |
|||
background: transparent; |
|||
display: inline-block; |
|||
line-height: 57px; |
|||
outline: none; |
|||
width: 100%; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 600; |
|||
font-size: 18px; |
|||
color: #323337; |
|||
} |
|||
::placeholder { |
|||
font-size: 16px; |
|||
font-weight: 400; |
|||
color: #c9cbd1; |
|||
} |
|||
&.has-border { |
|||
border-top: 1px solid rgba(238, 238, 238, 0.7); |
|||
} |
|||
|
|||
.label { |
|||
display: inline-block; |
|||
flex: 0 0 30px; |
|||
text-align: right; |
|||
margin-left: 8px; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 12px; |
|||
color: #b3aea7; |
|||
} |
|||
.right { |
|||
background: #f3f4f8; |
|||
border: 1px solid #edeff3; |
|||
box-sizing: border-box; |
|||
border-radius: 8px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 600; |
|||
font-size: 12px; |
|||
line-height: 33px; |
|||
color: #437af7; |
|||
flex: 0 0 80px; |
|||
text-align: center; |
|||
display: inline-block; |
|||
white-space: nowrap; |
|||
margin-left: 8px; |
|||
} |
|||
} |
|||
} |
|||
.switch { |
|||
position: absolute; |
|||
width: 49px; |
|||
height: 32px; |
|||
background-image: url("./switch.png"); |
|||
background-size: contain; |
|||
background-repeat: no-repeat; |
|||
background-position: center; |
|||
top: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
margin: auto 0; |
|||
} |
|||
} |
|||
.banner { |
|||
position: absolute; |
|||
display: flex; |
|||
background: rgba(0, 0, 0, 0.6); |
|||
width: 237px; |
|||
line-height: 40px; |
|||
height: 40px; |
|||
text-align: center; |
|||
bottom: -48px; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-size: 14px; |
|||
color: #ffffff; |
|||
border-radius: 20px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
&.start::before { |
|||
content: ""; |
|||
display: inline-block; |
|||
width: 16px; |
|||
height: 16px; |
|||
margin-right: 8px; |
|||
vertical-align: middle; |
|||
background-image: url("./start.png"); |
|||
background-size: contain; |
|||
} |
|||
&.end::before { |
|||
content: ""; |
|||
display: inline-block; |
|||
width: 16px; |
|||
height: 16px; |
|||
margin-right: 8px; |
|||
vertical-align: middle; |
|||
background-image: url("./end.png"); |
|||
background-size: contain; |
|||
} |
|||
&::after { |
|||
content: ""; |
|||
display: inline-block; |
|||
margin-left: 8px; |
|||
width: 16px; |
|||
height: 16px; |
|||
vertical-align: middle; |
|||
background-image: url("./arrow.png"); |
|||
background-size: contain; |
|||
} |
|||
} |
|||
.shop-list-wrapper { |
|||
position: absolute; |
|||
top: 64px; |
|||
left: -10px; |
|||
width: 100vw; |
|||
height: calc(100vh - 74px); |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
} |
|||
.search-type { |
|||
position: absolute; |
|||
top: 100px; |
|||
width: 100vw; |
|||
height: 40px; |
|||
line-height: 40px; |
|||
background: #fff; |
|||
display: flex; |
|||
color: #404040; |
|||
left: 0; |
|||
font-size: 12px; |
|||
.el { |
|||
flex: 1 1 33%; |
|||
text-align: center; |
|||
span { |
|||
position: relative; |
|||
display: inline-block; |
|||
img { |
|||
width: 18px; |
|||
height: 18px; |
|||
vertical-align: middle; |
|||
margin-right: 8px; |
|||
} |
|||
&.active { |
|||
color: #0074ed; |
|||
} |
|||
&.active { |
|||
&::after { |
|||
content: ""; |
|||
position: absolute; |
|||
width: 100%; |
|||
height: 4px; |
|||
background: #0074ed; |
|||
bottom: 0; |
|||
left: 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 316 B |
|
Before Width: | Height: | Size: 841 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 791 B |
@ -1,260 +0,0 @@ |
|||
import React, { useState, useEffect, useContext } from "react"; |
|||
import { ListView } from "antd-mobile"; |
|||
import Modal from "react-modal"; |
|||
import "./Malls.scss"; |
|||
import search from "./search.png"; |
|||
import pos from "./pos.png"; |
|||
import close_white from "./close_white.png"; |
|||
import up from "./up.png"; |
|||
import { |
|||
Mall, |
|||
cityMallsGetter, |
|||
CityMall, |
|||
} from "../../js/helpers/data-helper.js"; |
|||
import { MallCode } from "../../pages/Index/Index"; |
|||
|
|||
const getSectionData = (dataBlob, sectionID) => dataBlob[sectionID]; |
|||
const getRowData = (dataBlob, sectionID, rowID) => dataBlob[rowID]; |
|||
|
|||
function genData(ds, cityMalls) { |
|||
const dataBlob = {}; |
|||
const sectionIDs = []; |
|||
const rowIDs = []; |
|||
const groupByIndex = (list) => |
|||
list.reduce((acc, nxt) => { |
|||
acc[nxt.index] = acc[nxt.index] ? [...acc[nxt.index], nxt] : [nxt]; |
|||
return acc; |
|||
}, {}); |
|||
const data = groupByIndex(cityMalls); |
|||
Object.keys(data).forEach((item, index) => { |
|||
sectionIDs.push(item); |
|||
dataBlob[item] = item; |
|||
rowIDs[index] = []; |
|||
|
|||
data[item].forEach((city) => { |
|||
rowIDs[index].push(city.name); |
|||
dataBlob[city.name] = city; |
|||
}); |
|||
}); |
|||
return ds.cloneWithRowsAndSections(dataBlob, sectionIDs, rowIDs); |
|||
} |
|||
|
|||
const Malls = ({ isOpen, onRequestClose, setMallCode }) => { |
|||
const [q, setQ] = useState(""); |
|||
const [showList, setShowList] = useState(false); |
|||
const [cities, setCities] = useState([]); |
|||
const [currentMall, setCurrentMall] = useState(null); |
|||
const [currentCity, setCurrentCity] = useState(null); |
|||
const [currentMalls, setCurrentMalls] = useState([]); |
|||
const [isMallExpand, setIsMallExpand] = useState(false); |
|||
const [dataSource, setDataSource] = useState( |
|||
new ListView.DataSource({ |
|||
getRowData, |
|||
getSectionHeaderData: getSectionData, |
|||
rowHasChanged: (row1, row2) => row1 !== row2, |
|||
sectionHeaderHasChanged: (s1, s2) => s1 !== s2, |
|||
}) |
|||
); |
|||
const mallCode = useContext(MallCode); |
|||
const setDefaultCityMall = (list) => { |
|||
setCurrentCity(list[0]); |
|||
setCurrentMall(list[0].malls[0]); |
|||
setCurrentMalls(list[0].malls); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
document.title = "城市商场选择"; |
|||
cityMallsGetter().then((cityMalls) => { |
|||
setCities(cityMalls); |
|||
setDataSource(genData(dataSource, cityMalls)); |
|||
|
|||
if (cityMalls.length) { |
|||
const city = cityMalls.find(({ malls }) => |
|||
malls.find(({ code }) => mallCode === code) |
|||
); |
|||
if (city) { |
|||
setCurrentCity(city); |
|||
const mall = city.malls.find(({ code }) => mallCode === code); |
|||
if (mall) setCurrentMall(mall); |
|||
setCurrentMalls(city.malls); |
|||
} else setDefaultCityMall(cityMalls); |
|||
} |
|||
}); |
|||
}, [mallCode]); |
|||
|
|||
return ( |
|||
<Modal |
|||
isOpen={isOpen} |
|||
style={{ overlay: { zIndex: 10000, background: "#fff" } }} |
|||
ariaHideApp={false} |
|||
className="malls" |
|||
onRequestClose={() => onRequestClose()} |
|||
> |
|||
<div className="malls" onClick={() => setIsMallExpand(false)}> |
|||
<div className="input-wrapper"> |
|||
<input |
|||
value={q} |
|||
className="input" |
|||
placeholder="输入城市进行搜索" |
|||
onChange={(e) => setQ(e.target.value)} |
|||
onFocus={() => setShowList(true)} |
|||
onBlur={() => !q && setShowList(false)} |
|||
></input> |
|||
</div> |
|||
<img className="search-icon" src={search}></img> |
|||
{q && ( |
|||
<img className="close" src={close_white} onClick={() => setQ("")} /> |
|||
)} |
|||
{showList && ( |
|||
<div className="list"> |
|||
{cities |
|||
.filter(({ name }) => name.includes(q)) |
|||
.map((city) => ( |
|||
<div |
|||
className="item" |
|||
key={city.name} |
|||
onClick={() => { |
|||
setCurrentCity(city); |
|||
setCurrentMall(city.malls[0]); |
|||
setCurrentMalls(city.malls); |
|||
setShowList(false); |
|||
}} |
|||
> |
|||
{city.name} |
|||
</div> |
|||
))} |
|||
</div> |
|||
)} |
|||
{!showList && ( |
|||
<div className="main"> |
|||
<div className="r1"> |
|||
<div className="left"> |
|||
<img className="pos" src={pos}></img> |
|||
{currentCity && <span>{currentCity.name}</span>} |
|||
|
|||
{currentMall && <span>{currentMall.name}</span>} |
|||
<img className="up" src={up}></img> |
|||
</div> |
|||
<span className="right">当前定位城市</span> |
|||
</div> |
|||
<div className="r2">切换商场</div> |
|||
<div |
|||
className="malls-wrapper" |
|||
onClick={() => { |
|||
setIsMallExpand(false); |
|||
}} |
|||
> |
|||
<div |
|||
className={"malls1" + (isMallExpand ? " expand" : "")} |
|||
onClick={(e) => { |
|||
e.stopPropagation(); |
|||
}} |
|||
> |
|||
{currentMalls.map((mall) => ( |
|||
<span |
|||
key={mall.code} |
|||
className="tag" |
|||
onClick={() => { |
|||
console.log("setMallCode", mall.code); |
|||
setCurrentMall(mall); |
|||
setIsMallExpand(false); |
|||
setMallCode(mall.code); |
|||
onRequestClose(); |
|||
// Taro.reLaunch({
|
|||
// url: `/pages/index/index?mallId=${mall.id}`
|
|||
// });
|
|||
}} |
|||
> |
|||
{mall.name} |
|||
</span> |
|||
))} |
|||
{!isMallExpand && ( |
|||
<div |
|||
className="more" |
|||
onClick={(e) => { |
|||
e.stopPropagation(); |
|||
setIsMallExpand(true); |
|||
}} |
|||
> |
|||
更多 |
|||
</div> |
|||
)} |
|||
{isMallExpand && ( |
|||
<img |
|||
className="fold" |
|||
src={up} |
|||
onClick={(e) => { |
|||
e.stopPropagation(); |
|||
setIsMallExpand(false); |
|||
}} |
|||
></img> |
|||
)} |
|||
</div> |
|||
<ListView.IndexedList |
|||
dataSource={dataSource} |
|||
className="am-list sticky-list" |
|||
useBodyScroll |
|||
renderSectionHeader={(sectionData) => ( |
|||
<div> |
|||
<div |
|||
className="sticky" |
|||
style={{ |
|||
zIndex: 3, |
|||
}} |
|||
> |
|||
{sectionData} |
|||
</div> |
|||
</div> |
|||
)} |
|||
renderHeader={() => ( |
|||
<div> |
|||
<div className="meta">切换城市</div> |
|||
<div className="city-buttons"> |
|||
{cities.map((city) => ( |
|||
<div |
|||
key={city.name} |
|||
className="city-button" |
|||
onClick={() => { |
|||
setCurrentCity(city); |
|||
setCurrentMall(city.malls[0]); |
|||
setCurrentMalls(city.malls); |
|||
}} |
|||
> |
|||
{city.name} |
|||
</div> |
|||
))} |
|||
</div> |
|||
</div> |
|||
)} |
|||
renderRow={(rowData) => ( |
|||
<div |
|||
key={rowData.name} |
|||
className="city-button" |
|||
onClick={() => { |
|||
setCurrentCity(rowData); |
|||
setCurrentMalls(rowData.malls); |
|||
setCurrentMall(rowData.malls[0]); |
|||
}} |
|||
> |
|||
{rowData.name} |
|||
</div> |
|||
)} |
|||
quickSearchBarStyle={{ |
|||
position: "absolute", |
|||
top: 25, |
|||
}} |
|||
delayTime={10} |
|||
delayActivityIndicator={ |
|||
<div style={{ padding: 25, textAlign: "center" }}> |
|||
rendering... |
|||
</div> |
|||
} |
|||
/> |
|||
</div> |
|||
</div> |
|||
)} |
|||
</div> |
|||
</Modal> |
|||
); |
|||
}; |
|||
export default Malls; |
|||
@ -1,242 +0,0 @@ |
|||
/*postcss-pxtransform disable*/ |
|||
.malls { |
|||
position: relative; |
|||
width: 100vw; |
|||
height: 100vh; |
|||
box-sizing: border-box; |
|||
color: #5a5a5a; |
|||
font-family: SourceHanSansCN-Medium, SourceHanSansCN; |
|||
background: #fff; |
|||
box-sizing: border-box; |
|||
.search-icon { |
|||
position: absolute; |
|||
width: 13px; |
|||
height: 13px; |
|||
top: 21px; |
|||
left: 26px; |
|||
z-index: 1; |
|||
} |
|||
.close { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
background: #8d8d8d; |
|||
width: 20px; |
|||
height: 20px; |
|||
top: 17px; |
|||
right: 19px; |
|||
} |
|||
.input-wrapper { |
|||
padding: 12px 14px 0 14px; |
|||
.input { |
|||
padding: 5px 30px; |
|||
background: #ececec; |
|||
border-radius: 100px; |
|||
height: 30px; |
|||
line-height: 20px; |
|||
font-size: 11px; |
|||
box-sizing: border-box; |
|||
border: none; |
|||
width: 100%; |
|||
outline: none; |
|||
} |
|||
::placeholder { |
|||
color: #a9a9a9; |
|||
} |
|||
} |
|||
.list { |
|||
padding: 0 50px 0 15px; |
|||
line-height: 36px; |
|||
height: calc(100vh - 42px); |
|||
font-size: 12px; |
|||
overflow: scroll; |
|||
.item { |
|||
border-bottom: 1px solid #f4f4f4; |
|||
} |
|||
} |
|||
.main { |
|||
.r1 { |
|||
padding: 18px 15px; |
|||
line-height: 30px; |
|||
.left { |
|||
position: relative; |
|||
display: inline-block; |
|||
font-size: 14px; |
|||
background: rgba(244, 244, 244, 1); |
|||
border-radius: 8px; |
|||
border: 1px solid rgba(236, 236, 236, 1); |
|||
padding: 0 30px; |
|||
.pos { |
|||
position: absolute; |
|||
width: 14px; |
|||
height: 16px; |
|||
top: 7px; |
|||
left: 9px; |
|||
} |
|||
.up { |
|||
position: absolute; |
|||
right: 7.5px; |
|||
top: 12.5px; |
|||
width: 8px; |
|||
height: 5px; |
|||
transform-origin: center; |
|||
transform: rotate(90deg); |
|||
} |
|||
|
|||
Text + Text { |
|||
margin-left: 22px; |
|||
} |
|||
} |
|||
.right { |
|||
margin-left: 15px; |
|||
font-size: 11px; |
|||
font-weight: 400; |
|||
color: rgba(169, 169, 169, 1); |
|||
} |
|||
} |
|||
.r2 { |
|||
padding-left: 15px; |
|||
color: #a9a9a9; |
|||
font-size: 11px; |
|||
line-height: 11px; |
|||
font-weight: 400; |
|||
} |
|||
.malls-wrapper { |
|||
height: calc(100vh - 119px); |
|||
.malls1 { |
|||
position: relative; |
|||
margin-top: 11px; |
|||
padding-left: 15px; |
|||
padding-right: 60px; |
|||
height: 32px; |
|||
overflow: hidden; |
|||
background: #fff; |
|||
z-index: 10; |
|||
.more { |
|||
position: absolute; |
|||
line-height: 30px; |
|||
color: #a9a9a9; |
|||
right: 14px; |
|||
font-size: 11px; |
|||
top: 0; |
|||
} |
|||
&.expand { |
|||
box-shadow: 0px 15px 12px 0px rgba(0, 0, 0, 0.22); |
|||
padding-right: 15px; |
|||
padding-bottom: 17px; |
|||
overflow: auto; |
|||
height: auto; |
|||
} |
|||
.tag { |
|||
color: #878787; |
|||
font-size: 12px; |
|||
padding: 0 11px; |
|||
border-radius: 15px; |
|||
border: 1px solid rgba(236, 236, 236, 1); |
|||
line-height: 30px; |
|||
display: inline-block; |
|||
margin-bottom: 12px; |
|||
margin-right: 10px; |
|||
} |
|||
.fold { |
|||
position: absolute; |
|||
bottom: 0; |
|||
width: 8px; |
|||
height: 5px; |
|||
padding: 8px 6.5px; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
} |
|||
.fold::after { |
|||
content: ""; |
|||
position: absolute; |
|||
left: -5px; |
|||
right: -5px; |
|||
top: -5px; |
|||
bottom: -5px; |
|||
} |
|||
} |
|||
} |
|||
.am-indexed-list-container { |
|||
position: absolute; |
|||
top: 178px; |
|||
border-top: 1px solid #f4f4f4; |
|||
padding: 0 50px 0 15px; |
|||
height: calc(100vh - 178px); |
|||
width: 100vw; |
|||
box-sizing: border-box; |
|||
.am-indexed-list-quick-search-bar :first-child { |
|||
display: none !important; |
|||
} |
|||
.am-indexed-list-quick-search-bar { |
|||
top: 204px; |
|||
font-size: 11px; |
|||
transform: none; |
|||
right: 15px; |
|||
z-index: 1; |
|||
text-align: center; |
|||
li { |
|||
display: block; |
|||
padding: 0; |
|||
font-size: 11px; |
|||
color: #a9a9a9; |
|||
line-height: 15px; |
|||
height: 15px; |
|||
width: 15px; |
|||
} |
|||
li:active { |
|||
background: #0091ff; |
|||
|
|||
color: white; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
.at-list::after { |
|||
content: none; |
|||
} |
|||
.am-indexed-list-section-body { |
|||
line-height: 36px; |
|||
color: #878787; |
|||
font-size: 12px; |
|||
font-weight: 400; |
|||
border-bottom: 1px solid #f4f4f4; |
|||
background: none; |
|||
padding: 0; |
|||
} |
|||
.am-indexed-list-section-header { |
|||
font-size: 12px; |
|||
font-weight: 400; |
|||
border-bottom: 1px solid #f4f4f4; |
|||
padding: 0; |
|||
} |
|||
.am-list-body { |
|||
color: #5a5a5a; |
|||
line-height: 36px; |
|||
} |
|||
} |
|||
.meta { |
|||
font-size: 11px; |
|||
font-weight: 400; |
|||
margin-top: 7px; |
|||
padding: 11px 0; |
|||
color: #a9a9a9; |
|||
} |
|||
.city-buttons { |
|||
display: grid; |
|||
grid-column-gap: 10px; |
|||
grid-row-gap: 11px; |
|||
grid-auto-rows: 30px; |
|||
grid-auto-columns: 70px; |
|||
grid-template-columns: 1fr 1fr 1fr 1fr; |
|||
.city-button { |
|||
display: inline-block; |
|||
color: #878787; |
|||
font-size: 12px; |
|||
line-height: 30px; |
|||
background: rgba(244, 244, 244, 1); |
|||
border-radius: 4px; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 833 B |
|
Before Width: | Height: | Size: 998 B |
|
Before Width: | Height: | Size: 936 B |
|
Before Width: | Height: | Size: 464 B |
|
Before Width: | Height: | Size: 870 B |
|
Before Width: | Height: | Size: 1.3 KiB |
@ -1,53 +0,0 @@ |
|||
import React from "react"; |
|||
import { searchTypes, audioOptions } from "../Options/Options"; |
|||
import "./More.scss"; |
|||
import flat from "./2d.png"; |
|||
import thrD from "./3d.png"; |
|||
|
|||
const displayModes = [ |
|||
{ |
|||
id: 0, |
|||
name: "2D", |
|||
bg: flat, |
|||
}, |
|||
{ |
|||
id: 1, |
|||
name: "3D", |
|||
bg: thrD, |
|||
}, |
|||
]; |
|||
const More = ({ |
|||
showHeadBar, |
|||
displayMode, |
|||
searchType, |
|||
onClickDisplayMode, |
|||
onClickSearchType, |
|||
}) => { |
|||
return ( |
|||
<div className={"more " + (showHeadBar ? "has-header-top" : "")}> |
|||
<div className="types"> |
|||
{searchTypes.map(({ id, name, bg, bgb }) => ( |
|||
<div |
|||
key={id} |
|||
className={"btn " + (searchType === id ? "active" : "")} |
|||
onClick={() => { |
|||
onClickSearchType(id); |
|||
}} |
|||
> |
|||
<img src={searchType === id ? bgb : bg} /> |
|||
<div>{name}</div> |
|||
</div> |
|||
))} |
|||
</div> |
|||
|
|||
<div |
|||
className="btn big" |
|||
onClick={() => onClickDisplayMode(displayMode == 0 ? 1 : 0)} |
|||
> |
|||
<img src={displayMode == 0 ? flat : thrD}></img> |
|||
{displayMode == 0 ? "2D" : "3D"} |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
export default More; |
|||
@ -1,53 +0,0 @@ |
|||
.more { |
|||
position: absolute; |
|||
top: 10px; |
|||
right: 10px; |
|||
display: inline-flex; |
|||
flex-direction: column; |
|||
pointer-events: auto; |
|||
&.has-header-top { |
|||
top: 138px; |
|||
} |
|||
.types { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 40px; |
|||
height: 160px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 8px 8px rgba(104, 110, 127, 0.04); |
|||
border-radius: 12px; |
|||
justify-content: space-evenly; |
|||
align-items: center; |
|||
} |
|||
.btn { |
|||
display: inline-flex; |
|||
flex-direction: column; |
|||
width: 32px; |
|||
height: 48px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 10px; |
|||
line-height: 14px; |
|||
text-align: center; |
|||
color: #474a56; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
&.active { |
|||
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%); |
|||
color: #fff; |
|||
} |
|||
&.big { |
|||
width: 40px; |
|||
height: 56px; |
|||
margin-top: 8px; |
|||
box-shadow: 0px 8px 8px rgba(104, 110, 127, 0.04); |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
@ -1,137 +0,0 @@ |
|||
import React from "react"; |
|||
import Modal from "react-modal"; |
|||
import flat from "./2d.png"; |
|||
import thrD from "./3d.png"; |
|||
import on from "./on.png"; |
|||
import mute from "./mute.png"; |
|||
import ft from "./ft.png"; |
|||
import ftb from "./ftb.png"; |
|||
import ztb from "./ztb.png"; |
|||
import zt from "./zt.png"; |
|||
import shortest from "./shortest.png"; |
|||
import shortestb from "./shortestb.png"; |
|||
import ft1 from "./ft1.png"; |
|||
import ftb1 from "./ftb1.png"; |
|||
import ztb1 from "./ztb1.png"; |
|||
import zt1 from "./zt1.png"; |
|||
import shortest1 from "./shortest1.png"; |
|||
import shortestb1 from "./shortestb1.png"; |
|||
import "antd-mobile/lib/switch/style/css"; |
|||
import "./Options.scss"; |
|||
|
|||
export const displayModes = [ |
|||
{ |
|||
id: 0, |
|||
name: "2D", |
|||
bg: flat, |
|||
}, |
|||
{ |
|||
id: 1, |
|||
name: "3D", |
|||
bg: thrD, |
|||
}, |
|||
]; |
|||
export const searchTypes = [ |
|||
{ |
|||
id: 0, |
|||
name: "最佳", |
|||
bg: shortest, |
|||
bgb: shortestb, |
|||
bg1: shortest1, |
|||
bgb1: shortestb1, |
|||
}, |
|||
{ |
|||
id: 1, |
|||
name: "扶梯", |
|||
bg: ft, |
|||
bgb: ftb, |
|||
bg1: ft1, |
|||
bgb1: ftb1, |
|||
}, |
|||
{ |
|||
id: 2, |
|||
name: "直梯", |
|||
bg: zt, |
|||
bgb: ztb, |
|||
bg1: zt1, |
|||
bgb1: ztb1, |
|||
}, |
|||
]; |
|||
export const audioOptions = [ |
|||
{ |
|||
id: 0, |
|||
name: "语音", |
|||
bg: on, |
|||
}, |
|||
{ |
|||
id: 1, |
|||
name: "语音", |
|||
bg: mute, |
|||
}, |
|||
]; |
|||
|
|||
const Options = ({ |
|||
show, |
|||
hide, |
|||
onClickDisplayMode, |
|||
onClickSearchType, |
|||
onClickPlayAudioMode, |
|||
showHeadBar, |
|||
}) => ( |
|||
<Modal |
|||
isOpen={show} |
|||
style={{ |
|||
overlay: { |
|||
zIndex: 10000, |
|||
background: "rgba(0,0,0,0)", |
|||
}, |
|||
}} |
|||
ariaHideApp={false} |
|||
className={"modal" + (showHeadBar ? " has-header-bar" : "")} |
|||
onRequestClose={() => hide()} |
|||
> |
|||
<div className="row"> |
|||
{displayModes.map(({ id, name, bg }) => ( |
|||
<div |
|||
key={id} |
|||
className={"col"} |
|||
onClick={() => { |
|||
onClickDisplayMode(id); |
|||
hide(); |
|||
}} |
|||
> |
|||
<div |
|||
className="up" |
|||
style={{ |
|||
background: `center/22px 22px no-repeat url(${bg})`, |
|||
}} |
|||
></div> |
|||
<div className="down">{name}</div> |
|||
</div> |
|||
))} |
|||
|
|||
<div className="col"></div> |
|||
</div> |
|||
<div className="row"> |
|||
{searchTypes.map(({ id, name, bg }) => ( |
|||
<div |
|||
key={id} |
|||
className="col" |
|||
onClick={() => { |
|||
onClickSearchType(id); |
|||
hide(); |
|||
}} |
|||
> |
|||
<div |
|||
className="up" |
|||
style={{ |
|||
background: `center/22px 22px no-repeat url(${bg})`, |
|||
}} |
|||
></div> |
|||
<div className="down">{name}</div> |
|||
</div> |
|||
))} |
|||
</div> |
|||
</Modal> |
|||
); |
|||
export default Options; |
|||
@ -1,106 +0,0 @@ |
|||
.modal { |
|||
position: absolute; |
|||
width: 168px; |
|||
height: 136px; |
|||
background: #ffffff; |
|||
border-radius: 8px; |
|||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.08); |
|||
outline: none; |
|||
right: 59px; |
|||
top: 12px; |
|||
overflow: hidden; |
|||
padding-top: 16px; |
|||
&.has-header-bar { |
|||
top: 112px; |
|||
} |
|||
.title { |
|||
background: #f4f4f4; |
|||
padding: 0 19px; |
|||
color: #878787; |
|||
font-family: SourceHanSansCN-Regular, SourceHanSansCN; |
|||
font-weight: 400; |
|||
line-height: 40px; |
|||
font-size: 11px; |
|||
} |
|||
.row { |
|||
display: flex; |
|||
flex: 1; |
|||
flex-direction: row; |
|||
margin-bottom: 18px; |
|||
.col { |
|||
flex: 1; |
|||
text-align: center; |
|||
.up { |
|||
width: 22px; |
|||
height: 22px; |
|||
margin: auto; |
|||
} |
|||
.down { |
|||
font-size: 12px; |
|||
font-family: SourceHanSansCN, SourceHanSansCN-Regular; |
|||
font-weight: 400; |
|||
text-align: center; |
|||
color: #696969; |
|||
line-height: 20px; |
|||
} |
|||
&.active { |
|||
.down { |
|||
color: #0074ed; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.bottom { |
|||
position: absolute; |
|||
bottom: 0; |
|||
width: 100%; |
|||
line-height: 52px; |
|||
padding: 0 20px; |
|||
background: #f4f4f4; |
|||
color: #404040; |
|||
font-size: 12px; |
|||
font-family: SourceHanSansCN-Regular, SourceHanSansCN; |
|||
font-weight: 400; |
|||
.am-switch { |
|||
position: absolute; |
|||
top: 16px; |
|||
right: 20px; |
|||
input[type="checkbox"]:checked + .checkbox:after { |
|||
transform: translateX(22px); |
|||
} |
|||
.checkbox { |
|||
width: 42px; |
|||
height: 20px; |
|||
border-radius: 20px; |
|||
&:before { |
|||
content: " "; |
|||
position: absolute; |
|||
left: 1.5px; |
|||
top: 1.5px; |
|||
width: 39px; |
|||
height: 17px; |
|||
border-radius: 17px; |
|||
box-sizing: border-box; |
|||
background: #fff; |
|||
z-index: 1; |
|||
transition: all 200ms; |
|||
transform: scale(1); |
|||
} |
|||
&:after { |
|||
content: " "; |
|||
height: 17px; |
|||
width: 17px; |
|||
border-radius: 17px; |
|||
background: #fff; |
|||
position: absolute; |
|||
z-index: 2; |
|||
left: 1.5px; |
|||
top: 1.5px; |
|||
transform: translateX(0); |
|||
transition: all 200ms; |
|||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.21); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 720 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 452 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 905 B |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 565 B |
|
Before Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 466 B |
|
Before Width: | Height: | Size: 590 B |
@ -1,64 +1,100 @@ |
|||
import React from "react"; |
|||
import desc from "./desc.png"; |
|||
import closeButton from "./close.png"; |
|||
import React, { useState, useEffect } from "react"; |
|||
import "./Popup.scss"; |
|||
import navpng from "./nav.png"; |
|||
import arpng from "./ar.png"; |
|||
import couponTop from "./couponTop.png"; |
|||
const Popup = ({ |
|||
showPopup, |
|||
defaultPopup, |
|||
floors, |
|||
closePopup, |
|||
shop, |
|||
showDetail, |
|||
setEnd, |
|||
handleAR, |
|||
onClickCoupon, |
|||
}) => ( |
|||
<div className={["popup-wrapper", showPopup ? "" : "noshow"].join(" ")}> |
|||
{floors} |
|||
{defaultPopup} |
|||
{showPopup && ( |
|||
<div className="popup"> |
|||
{shop.hasCoupon && ( |
|||
<img |
|||
className="couponTop" |
|||
src={couponTop} |
|||
onClick={(shop) => onClickCoupon(shop)} |
|||
></img> |
|||
)} |
|||
<img |
|||
alt="关闭" |
|||
className="close-icon" |
|||
src={closeButton} |
|||
onClick={() => closePopup()} |
|||
></img> |
|||
<div className="r1"> |
|||
{shop.logoPath && ( |
|||
import ShopList from "../ShopList/ShopList.js"; |
|||
const Popup = ({ mall, sceneIndex, onClick, floors, shop, onClickActive }) => { |
|||
const [long, setLong] = useState(false); |
|||
const [height, setHeight] = useState(false); |
|||
const [start, setStart] = useState(null); |
|||
const [doTransition, setdoTransition] = useState(false); |
|||
const baseHeight = long ? window.innerHeight : 312; |
|||
useEffect(() => { |
|||
setdoTransition(true); |
|||
setHeight(baseHeight); |
|||
setTimeout(() => { |
|||
setdoTransition(false); |
|||
}, 500); |
|||
}, [long]); |
|||
const handleTouchStart = (e) => { |
|||
if (start) return; |
|||
setStart({ |
|||
identifier: e.changedTouches[0].identifier, |
|||
y: e.changedTouches[0].clientY, |
|||
}); |
|||
}; |
|||
const handleTouchMove = (e) => { |
|||
if (!start) return; |
|||
const touch = Array.from(e.changedTouches).find( |
|||
({ identifier }) => identifier === start.identifier |
|||
); |
|||
if (!touch) return; |
|||
const delta = touch.clientY - start.y; |
|||
setHeight(baseHeight - delta); |
|||
}; |
|||
const handleTouchEnd = (e) => { |
|||
if (!start) return; |
|||
const touch = Array.from(e.changedTouches).find( |
|||
({ identifier }) => identifier === start.identifier |
|||
); |
|||
if (!touch) return; |
|||
setStart(null); |
|||
const delta = touch.clientY - start.y; |
|||
const nxtLong = |
|||
!long && delta < -100 ? true : long && delta > 100 ? false : long; |
|||
|
|||
if (long === nxtLong) { |
|||
setdoTransition(true); |
|||
setHeight(baseHeight); |
|||
setTimeout(() => { |
|||
setdoTransition(false); |
|||
}, 500); |
|||
} else setLong(nxtLong); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
if (shop) { |
|||
if (long) { |
|||
setLong(false); |
|||
setTimeout(() => { |
|||
const domEl = document.getElementById("shop" + shop.houseNum); |
|||
if (domEl) |
|||
domEl.scrollIntoView({ behavior: "smooth", block: "center" }); |
|||
}, 500); |
|||
} else { |
|||
const domEl = document.getElementById("shop" + shop.houseNum); |
|||
if (domEl) |
|||
domEl.scrollIntoView({ behavior: "smooth", block: "center" }); |
|||
} |
|||
} |
|||
}, [shop]); |
|||
return ( |
|||
<div |
|||
className="avatar" |
|||
className={["popup-wrapper", long ? "long" : ""].join(" ")} |
|||
style={{ |
|||
backgroundImage: `url(${shop.logoPath})`, |
|||
height: height + "px", |
|||
transition: !doTransition ? "none" : "margin-bottom 0.5s ease", |
|||
backgroundImage: mall.theme.image.backgroundImg |
|||
? `url(${mall.theme.image.backgroundImg})` |
|||
: "", |
|||
}} |
|||
></div> |
|||
)} |
|||
<div style={{ flex: 1 }}> |
|||
<div className="popupname">{shop.name}</div> |
|||
<div className="popupdesc"> |
|||
<span> {shop.shopFormat ? shop.shopFormat : " "}</span> |
|||
<span> {shop.floorName}</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className="tabs"> |
|||
<div className="tab" onClick={() => setEnd()}> |
|||
<img src={navpng} /> 导航动画 |
|||
</div> |
|||
</div> |
|||
onTouchStart={handleTouchStart} |
|||
onTouchMove={handleTouchMove} |
|||
onTouchCancel={handleTouchEnd} |
|||
onTouchEnd={handleTouchEnd} |
|||
> |
|||
{floors} |
|||
<div className="listWrapper"> |
|||
<ShopList |
|||
className="flex1" |
|||
mall={mall} |
|||
isRow={false} |
|||
format={null} |
|||
floorOrder={sceneIndex} |
|||
onClick={onClick} |
|||
shop={shop} |
|||
onClickActive={onClickActive} |
|||
></ShopList> |
|||
</div> |
|||
)} |
|||
</div> |
|||
); |
|||
); |
|||
}; |
|||
export default Popup; |
|||
|
|||
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 596 B |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 97 B |
|
Before Width: | Height: | Size: 480 B |
@ -1,91 +1,100 @@ |
|||
/*postcss-pxtransform disable*/ |
|||
.shop { |
|||
position: relative; |
|||
font-size: 0; |
|||
line-height: 0; |
|||
overflow: hidden; |
|||
background: var(--brand-background); |
|||
border-radius: 6px; |
|||
.active { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background: linear-gradient(99.5deg, #f0b92b 0%, #f9d556 100%); |
|||
.avatar { |
|||
display: block; |
|||
width: 100%; |
|||
height: calc((100vw - 55px) / 4); |
|||
padding: 8px; |
|||
background: #ffffff; |
|||
box-sizing: border-box; |
|||
border-radius: 4px; |
|||
} |
|||
.r1 { |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
} |
|||
&.is-row { |
|||
position: relative; |
|||
height: 66px; |
|||
background: #ffffff; |
|||
height: 80px; |
|||
background: rgba(255, 255, 255, 0.6); |
|||
border-radius: 12px; |
|||
.rowRight { |
|||
position: absolute; |
|||
right: 12px; |
|||
top: 0; |
|||
bottom: 0; |
|||
margin: auto; |
|||
width: 56px; |
|||
height: 44px; |
|||
background: center / cover no-repeat url(./rowRight.png); |
|||
} |
|||
.avatar { |
|||
position: absolute; |
|||
width: 50px; |
|||
height: 50px; |
|||
width: 64px; |
|||
height: 64px; |
|||
top: 8px; |
|||
left: 8px; |
|||
border: 1px solid #e9d7ad; |
|||
box-sizing: border-box; |
|||
border-radius: 6px; |
|||
padding: 7px; |
|||
} |
|||
.name { |
|||
position: absolute; |
|||
top: 10px; |
|||
left: 66px; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
top: 14px; |
|||
left: 92px; |
|||
font-weight: 600; |
|||
font-size: 16px; |
|||
line-height: 22px; |
|||
color: #333333; |
|||
} |
|||
.houseNum { |
|||
position: absolute; |
|||
left: 67px; |
|||
bottom: 13px; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 10px; |
|||
line-height: 13px; |
|||
color: #b3aea7; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
.format { |
|||
.meta { |
|||
display: flex; |
|||
position: absolute; |
|||
top: 11px; |
|||
right: 16px; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
top: 49px; |
|||
left: 92px; |
|||
font-weight: 600; |
|||
font-size: 12px; |
|||
line-height: 17px; |
|||
color: #b3aea7; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
align-items: center; |
|||
.sep { |
|||
display: inline-block; |
|||
margin: 0 12px; |
|||
width: 1px; |
|||
height: 10px; |
|||
background: rgba(0, 0, 0, 0.1); |
|||
} |
|||
} |
|||
} |
|||
.avatar { |
|||
width: calc((100vw - 96px - 18px - 10px - 11px) / 3); |
|||
height: calc((100vw - 96px - 18px - 10px - 11px) / 3); |
|||
display: block; |
|||
width: 100%; |
|||
height: calc((100vw - 55px) / 4); |
|||
padding: 8px; |
|||
background: #ffffff; |
|||
box-sizing: border-box; |
|||
border-radius: 6px; |
|||
border-radius: 4px; |
|||
} |
|||
.r1 { |
|||
padding: 0 4px; |
|||
margin-top: 4px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-weight: 600; |
|||
font-size: 12px; |
|||
line-height: 17px; |
|||
color: #323337; |
|||
line-height: 25px; |
|||
padding: 0 6px; |
|||
color: var(--brand-color, rgba(0, 0, 0, 0.8)); |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
} |
|||
.r2 { |
|||
margin-top: 4px; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 9px; |
|||
line-height: 13px; |
|||
color: #a1a5b3; |
|||
padding: 0 4px; |
|||
span { |
|||
font-weight: normal; |
|||
font-size: 10px; |
|||
color: #a1a5b3; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 814 B |
@ -1,24 +0,0 @@ |
|||
import React from "react"; |
|||
import "./ShopTabs.scss"; |
|||
import floor from "./floor.png"; |
|||
import floorActive from "./floor_active.png"; |
|||
import format from "./format.png"; |
|||
import formatActive from "./format_active.png"; |
|||
export default ({ tab, onSetTab }) => ( |
|||
<div className="shop-tabs"> |
|||
<div |
|||
onClick={() => onSetTab("业态")} |
|||
className={["tab", tab === "业态" ? "active" : ""].join(" ")} |
|||
> |
|||
<img src={tab === "业态" ? formatActive : format}></img> |
|||
业态 |
|||
</div> |
|||
<div |
|||
onClick={() => onSetTab("楼层")} |
|||
className={["tab", tab === "楼层" ? "active" : ""].join(" ")} |
|||
> |
|||
<img src={tab === "楼层" ? floorActive : floor}></img> |
|||
楼层 |
|||
</div> |
|||
</div> |
|||
); |
|||
@ -1,32 +0,0 @@ |
|||
.shop-tabs { |
|||
display: flex; |
|||
width: calc(100vw - 20px); |
|||
height: 56px; |
|||
background: #edeff3; |
|||
border-radius: 12px; |
|||
justify-content: space-around; |
|||
align-items: center; |
|||
.tab { |
|||
display: flex; |
|||
width: calc((100vw - 20px - 8px - 3px) / 2); |
|||
height: 48px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 16px; |
|||
line-height: 22px; |
|||
color: #7a7e8d; |
|||
&.active { |
|||
background: #ffffff; |
|||
border-radius: 8px; |
|||
color: #323337; |
|||
} |
|||
img { |
|||
width: 20px; |
|||
height: 20px; |
|||
margin-right: 8px; |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 901 B |
|
Before Width: | Height: | Size: 858 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,103 +0,0 @@ |
|||
import React, { useState, useEffect } from "react"; |
|||
import ShopList from "../ShopList/ShopList.js"; |
|||
import "./ShopsWithFilter.scss"; |
|||
import ShopTabs from "../ShopTabs/ShopTabs"; |
|||
import SideBar from "../SideBar/SideBar"; |
|||
const ShopsWithFilter = ({ |
|||
mall, |
|||
onClick, |
|||
reset, |
|||
onReset = () => {}, |
|||
wingHeight, |
|||
}) => { |
|||
const [tab, setTab] = useState("业态"); |
|||
const [format, setFormat] = useState(null); |
|||
const [floorOrder, setFloorOrder] = useState(null); |
|||
useEffect(() => { |
|||
if (reset) { |
|||
setFormat(null); |
|||
setFloorOrder(null); |
|||
setTab("业态"); |
|||
onReset(); |
|||
} |
|||
}, [reset]); |
|||
const formats = mall |
|||
? mall.shopInfo.reduce( |
|||
(acc, { shopList }) => |
|||
shopList.reduce( |
|||
(acc1, nxt) => |
|||
acc1.includes(nxt.shopFormat) |
|||
? [...acc1] |
|||
: [...acc1, nxt.shopFormat], |
|||
acc |
|||
), |
|||
[] |
|||
) |
|||
: []; |
|||
const floors = mall ? mall.floorData : []; |
|||
const floorNameOrderMap = floors.reduce( |
|||
(acc, nxt) => ({ ...acc, [nxt.name]: nxt.floorOrder }), |
|||
{} |
|||
); |
|||
const floorOrderNameMap = floors.reduce( |
|||
(acc, nxt) => ({ ...acc, [nxt.floorOrder]: nxt.name }), |
|||
{} |
|||
); |
|||
return ( |
|||
<> |
|||
<div style={{ marginTop: "16px", marginLeft: "10px" }}> |
|||
<ShopTabs |
|||
tab={tab} |
|||
onSetTab={(el) => { |
|||
setFormat(null); |
|||
setFloorOrder(null); |
|||
setTab(el); |
|||
}} |
|||
></ShopTabs> |
|||
</div> |
|||
|
|||
<div className="wings" style={{ height: wingHeight }}> |
|||
<div className="left"> |
|||
<SideBar |
|||
active={ |
|||
tab === "业态" && format === null |
|||
? "全部业态" |
|||
: tab === "楼层" && floorOrder === null |
|||
? "全部楼层" |
|||
: tab === "业态" |
|||
? format |
|||
: floorOrderNameMap[floorOrder] |
|||
} |
|||
onSetActive={(el) => { |
|||
if (tab === "业态") { |
|||
setFormat(el === "全部业态" ? null : el); |
|||
} else { |
|||
setFloorOrder(el === "全部楼层" ? null : floorNameOrderMap[el]); |
|||
} |
|||
}} |
|||
list={ |
|||
tab === "业态" |
|||
? ["全部业态", ...formats] |
|||
: [ |
|||
"全部楼层", |
|||
...floors |
|||
.filter(({ url }) => url !== null) |
|||
.map(({ name }) => name), |
|||
] |
|||
} |
|||
></SideBar> |
|||
</div> |
|||
<div className="right"> |
|||
<ShopList |
|||
mall={mall} |
|||
isRow={false} |
|||
format={format} |
|||
floorOrder={floorOrder} |
|||
onClick={onClick} |
|||
></ShopList> |
|||
</div> |
|||
</div> |
|||
</> |
|||
); |
|||
}; |
|||
export default ShopsWithFilter; |
|||
@ -1,22 +0,0 @@ |
|||
.wings { |
|||
display: flex; |
|||
width: 100vw; |
|||
height: calc(100vh - 156px); |
|||
border-top: 1px solid #edeff3; |
|||
margin-top: 8px; |
|||
.left { |
|||
width: 96px; |
|||
flex: 0 0 96px; |
|||
height: 100%; |
|||
background: #edeff3; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
} |
|||
.right { |
|||
flex: 1; |
|||
height: 100%; |
|||
background: #f3f4f8; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
} |
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
import React from "react"; |
|||
import "./SideBar.scss"; |
|||
export default ({ list, active, onSetActive }) => ( |
|||
<div className="side-bar"> |
|||
{list.map((el) => ( |
|||
<div |
|||
key={el} |
|||
className={["option", active === el ? "active" : ""].join(" ")} |
|||
onClick={() => onSetActive(el)} |
|||
> |
|||
{el} |
|||
</div> |
|||
))} |
|||
</div> |
|||
); |
|||
@ -1,20 +0,0 @@ |
|||
.side-bar { |
|||
width: 100%; |
|||
.option { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 100%; |
|||
height: 48px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
font-size: 12px; |
|||
color: #474a56; |
|||
&.active { |
|||
background: #ffffff; |
|||
color: #437af7; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
} |
|||
@ -1,212 +0,0 @@ |
|||
import React, { useState, useEffect } from "react"; |
|||
import car from "./car.png"; |
|||
import axios from "axios"; |
|||
import "./Car.scss"; |
|||
import plus from "./plus.svg"; |
|||
import Keyboard from "../Keyboard/Keyboard"; |
|||
import platepng from "./plate.png"; |
|||
import plateActive from "./plate_active.png"; |
|||
import lot from "./lot.png"; |
|||
import lotActive from "./lot_active.png"; |
|||
|
|||
const Car = ({ lots, onLot = () => {}, plate, hasReverse }) => { |
|||
const [isPlate, setIsPlate] = useState(hasReverse); |
|||
const [qArr, setQArr] = useState(hasReverse ? ["苏", "A"] : []); |
|||
const [opened, setOpened] = useState(false); |
|||
const [showKeyBoard, setShowKeyBoard] = useState(true); |
|||
const [focusedIndex, setFocusedIndex] = useState(hasReverse ? 2 : 0); |
|||
const [isNum, setIsNum] = useState(true); |
|||
const q = qArr.join(""); |
|||
const setQ = (str) => setQArr(str.split("")); |
|||
useEffect(() => { |
|||
if (!opened) { |
|||
setOpened(true); |
|||
if (plate) { |
|||
setQ(plate); |
|||
setFocusedIndex(null); |
|||
} |
|||
setShowKeyBoard(!plate); |
|||
} |
|||
}, [opened]); |
|||
const toPlate = () => { |
|||
if (!hasReverse) |
|||
return window.weui.toast("敬请期待", { |
|||
className: "toast", |
|||
}); |
|||
setQ("苏A"); |
|||
setIsPlate(true); |
|||
setFocusedIndex(2); |
|||
setShowKeyBoard(true); |
|||
}; |
|||
const toLot = () => { |
|||
setQ(""); |
|||
setFocusedIndex(0); |
|||
setIsPlate(false); |
|||
setShowKeyBoard(true); |
|||
}; |
|||
|
|||
const handleSubmit = async () => { |
|||
if (isPlate) { |
|||
if (!q) { |
|||
return window.weui.toast("请输入正确车牌号", { |
|||
className: "toast", |
|||
}); |
|||
} |
|||
const { |
|||
data: { data, code, msg }, |
|||
} = { data: { data: null, code: "201", msg: "123" } }; |
|||
if (code !== "200") |
|||
return window.weui.toast(msg, { |
|||
className: "toast", |
|||
}); |
|||
else { |
|||
if (!lots.includes(data.spaceNo)) |
|||
return window.weui.toast(`未找到车位号:${data.spaceNo}`, { |
|||
className: "toast", |
|||
}); |
|||
return onLot(data.spaceNo); |
|||
} |
|||
} |
|||
// if (!q || !lots.includes(floor + q.toUpperCase())) {
|
|||
if (!q || !lots.includes(q.toUpperCase())) { |
|||
return window.weui.toast("请输入正确车位号", { |
|||
className: "toast", |
|||
}); |
|||
} |
|||
// onLot(floor + q.toUpperCase());
|
|||
onLot(q.toUpperCase()); |
|||
}; |
|||
return ( |
|||
<div className="car"> |
|||
<img className="car-img" src={car} /> |
|||
<div className="car-modal"> |
|||
<div className={"content" + (showKeyBoard ? " has-keyboard" : "")}> |
|||
<div className="form"> |
|||
<div className="tabs"> |
|||
<div |
|||
className={`tab ${isPlate ? "active" : ""}`} |
|||
onClick={toPlate} |
|||
> |
|||
<img src={isPlate ? plateActive : platepng}></img> |
|||
车牌查找 |
|||
</div> |
|||
<div |
|||
className={`tab ${!isPlate ? "active" : ""}`} |
|||
onClick={toLot} |
|||
> |
|||
<img src={isPlate ? lot : lotActive}></img> |
|||
车位查找 |
|||
</div> |
|||
</div> |
|||
{isPlate ? ( |
|||
<div className="platenum"> |
|||
{new Array(8).fill(0).map((_, i) => ( |
|||
<div |
|||
className={[ |
|||
"box", |
|||
focusedIndex === i ? "active" : "", |
|||
i === 2 ? "more-margin" : "", |
|||
i === 7 ? "sp" : "", |
|||
].join(" ")} |
|||
key={i} |
|||
onClick={() => { |
|||
setIsNum(i !== 0); |
|||
setFocusedIndex(i); |
|||
setShowKeyBoard(true); |
|||
}} |
|||
> |
|||
{i === 7 && !qArr[i] ? ( |
|||
<> |
|||
<img src={plus} className="plus"></img> |
|||
</> |
|||
) : ( |
|||
qArr[i] |
|||
)} |
|||
</div> |
|||
))} |
|||
</div> |
|||
) : ( |
|||
<div className="lots"> |
|||
{new Array(4).fill(0).map((_, i) => ( |
|||
<div |
|||
className={[ |
|||
"box", |
|||
"big", |
|||
focusedIndex === i ? "active" : "", |
|||
].join(" ")} |
|||
key={i} |
|||
onClick={() => { |
|||
setIsNum(true); |
|||
setFocusedIndex(i); |
|||
setShowKeyBoard(true); |
|||
}} |
|||
> |
|||
{qArr[i]} |
|||
</div> |
|||
))} |
|||
</div> |
|||
)} |
|||
|
|||
{!isPlate && ( |
|||
<> |
|||
{/* <div className="floor1" onClick={() => setFloor(floor1)}> |
|||
{floor1} |
|||
</div> |
|||
<div className="floor2">{floor}</div> |
|||
<div className="floor3" onClick={() => setFloor(floor3)}> |
|||
{floor3} |
|||
</div> */} |
|||
</> |
|||
)} |
|||
<div className="btn" onClick={handleSubmit}> |
|||
寻车 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{showKeyBoard && ( |
|||
<Keyboard |
|||
isNum={isNum} |
|||
onClose={() => { |
|||
setFocusedIndex(null); |
|||
setShowKeyBoard(false); |
|||
}} |
|||
onSetIsNum={(val) => setIsNum(val)} |
|||
onInput={(val) => { |
|||
qArr[focusedIndex] = val; |
|||
setQArr([...qArr]); |
|||
if (isPlate) { |
|||
switch (focusedIndex) { |
|||
case 6: |
|||
case 7: |
|||
setShowKeyBoard(false); |
|||
break; |
|||
default: |
|||
setIsNum(true); |
|||
setFocusedIndex(focusedIndex + 1); |
|||
break; |
|||
} |
|||
} else { |
|||
switch (focusedIndex) { |
|||
case 3: |
|||
setShowKeyBoard(false); |
|||
break; |
|||
default: |
|||
setIsNum(true); |
|||
setFocusedIndex(focusedIndex + 1); |
|||
break; |
|||
} |
|||
} |
|||
}} |
|||
onBackspace={() => { |
|||
qArr[focusedIndex] = ""; |
|||
setQArr([...qArr]); |
|||
setFocusedIndex(Math.max(0, focusedIndex - 1)); |
|||
}} |
|||
onFinish={handleSubmit} |
|||
></Keyboard> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
export default Car; |
|||
@ -1,255 +0,0 @@ |
|||
.car { |
|||
position: relative; |
|||
width: 100vw; |
|||
height: calc(100vh - 98px); |
|||
background: #f3f4f8; |
|||
pointer-events: auto; |
|||
.car-img { |
|||
position: absolute; |
|||
width: 220px; |
|||
height: 220px; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: auto; |
|||
margin: auto; |
|||
top: 16px; |
|||
} |
|||
.car-modal { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 10; |
|||
} |
|||
.content { |
|||
position: absolute; |
|||
left: 2.6667vw; |
|||
right: 2.6667vw; |
|||
width: calc(100vw - 4.2667vw); |
|||
height: 458px; |
|||
bottom: 10px; |
|||
padding-top: 34px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 12px 16px rgba(104, 110, 127, 0.08); |
|||
border-radius: 18px; |
|||
overflow: hidden; |
|||
|
|||
.form { |
|||
position: absolute; |
|||
top: 14px; |
|||
left: 3.7333vw; |
|||
right: 3.7333vw; |
|||
bottom: 14px; |
|||
z-index: 3; |
|||
text-align: left; |
|||
.platenum { |
|||
display: flex; |
|||
justify-content: center; |
|||
position: absolute; |
|||
top: 102px; |
|||
left: -3.7333vw; |
|||
right: -3.7333vw; |
|||
text-align: center; |
|||
} |
|||
.lots { |
|||
position: absolute; |
|||
top: 95px; |
|||
left: 0; |
|||
right: 0; |
|||
display: inline-flex; |
|||
justify-content: center; |
|||
} |
|||
.box { |
|||
width: 9.6vw; |
|||
height: 64px; |
|||
background: #f3f4f8; |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 18px; |
|||
text-align: center; |
|||
color: #323337; |
|||
border-radius: 8px; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
align-content: center; |
|||
flex-direction: column; |
|||
&.big { |
|||
width: 12.8vw; |
|||
} |
|||
&.active { |
|||
border: 2px solid #437af7; |
|||
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2); |
|||
} |
|||
&.sp { |
|||
background: none; |
|||
border: 1px solid #c9cbd1; |
|||
&.active { |
|||
border: 2px solid #437af7; |
|||
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2); |
|||
} |
|||
} |
|||
.plus { |
|||
position: relative; |
|||
width: 6.4vw; |
|||
margin: 0; |
|||
} |
|||
} |
|||
.box + .box { |
|||
margin-left: 1.0667vw; |
|||
} |
|||
.box + .box.more-margin { |
|||
margin-left: 5.0667vw; |
|||
} |
|||
.input { |
|||
position: absolute; |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 16px; |
|||
top: 114px; |
|||
width: 216px; |
|||
left: calc((100vw - 28px - 216px) / 2); |
|||
background: transparent; |
|||
height: 40px; |
|||
line-height: 40px; |
|||
color: #474747; |
|||
border: none; |
|||
outline: none; |
|||
text-align: center; |
|||
&.right { |
|||
text-align: left; |
|||
left: calc((100vw - 28px - 216px + 63px) / 2); |
|||
} |
|||
} |
|||
::placeholder { |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-size: 14px; |
|||
color: #b3aea7; |
|||
} |
|||
.dec1 { |
|||
position: absolute; |
|||
top: 154px; |
|||
bottom: auto; |
|||
right: auto; |
|||
width: 223px; |
|||
height: 21px; |
|||
left: calc((100vw - 28px - 216px) / 2); |
|||
&.right { |
|||
left: calc((100vw - 28px - 216px + 63px) / 2); |
|||
} |
|||
} |
|||
.dec2 { |
|||
position: absolute; |
|||
top: 132px; |
|||
bottom: auto; |
|||
right: auto; |
|||
width: 11.7333vw; |
|||
height: 21px; |
|||
left: calc((100vw - 7.4667vw - 57.6vw - 16.8vw) / 2); |
|||
pointer-events: none; |
|||
} |
|||
.floor1, |
|||
.floor2, |
|||
.floor3 { |
|||
position: absolute; |
|||
left: calc((100vw - 7.4667vw - 57.6vw - 16.8vw) / 2); |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 4.2667vw; |
|||
color: #474747; |
|||
width: 9.8667vw; |
|||
text-align: center; |
|||
} |
|||
.floor1, |
|||
.floor3 { |
|||
color: rgba(113, 112, 110, 0.2); |
|||
font-size: 3.2vw; |
|||
line-height: 4.8vw; |
|||
height: 4.8vw; |
|||
} |
|||
.floor1 { |
|||
top: 77px; |
|||
} |
|||
.floor2 { |
|||
top: 101px; |
|||
line-height: 6.4vw; |
|||
height: 6.4vw; |
|||
} |
|||
.floor3 { |
|||
top: 134px; |
|||
} |
|||
.btns { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
position: absolute; |
|||
top: 129px; |
|||
left: 24px; |
|||
right: 24px; |
|||
gap: 0 16px; |
|||
} |
|||
.btn { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
height: 56px; |
|||
left: 1.0667vw; |
|||
right: 1.0667vw; |
|||
margin: auto; |
|||
bottom: 14px; |
|||
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%); |
|||
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2); |
|||
border-radius: 16px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 16px; |
|||
line-height: 22px; |
|||
text-align: center; |
|||
color: #ffffff; |
|||
} |
|||
|
|||
.tabs { |
|||
display: flex; |
|||
width: 100%; |
|||
padding: 4px; |
|||
background: #edeff3; |
|||
border-radius: 12px; |
|||
} |
|||
.tab { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex: 1; |
|||
height: 48px; |
|||
font-family: PingFang SC; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 16px; |
|||
line-height: 22px; |
|||
color: #7a7e8d; |
|||
img { |
|||
position: relative; |
|||
margin: 0; |
|||
margin-right: 8px; |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
} |
|||
.tab.active { |
|||
background: #ffffff; |
|||
border-radius: 10px; |
|||
color: #323337; |
|||
} |
|||
.tab + .tab { |
|||
margin-left: 4px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 685 B |
|
Before Width: | Height: | Size: 675 B |
|
Before Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 354 B |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
@ -1,15 +0,0 @@ |
|||
import act from "./act.svg"; |
|||
import actActive from "./actActive.svg"; |
|||
import car from "./car.svg"; |
|||
import carActive from "./carActive.svg"; |
|||
import map from "./map.svg"; |
|||
import mapActive from "./mapActive.svg"; |
|||
import my from "./my.svg"; |
|||
import myActive from "./myActive.svg"; |
|||
const TabMap = { |
|||
活动: { logo: act, logoActive: actActive }, |
|||
寻车: { logo: car, logoActive: carActive }, |
|||
地图: { logo: map, logoActive: mapActive }, |
|||
我的: { logo: my, logoActive: myActive }, |
|||
}; |
|||
export default TabMap; |
|||
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 971 B |
|
Before Width: | Height: | Size: 1015 B |
|
After Width: | Height: | Size: 5.0 KiB |
@ -1,104 +0,0 @@ |
|||
import React from "react"; |
|||
import "./Keyboard.scss"; |
|||
const N1 = "1234567890"; |
|||
const N2 = "QWERTYUIOP"; |
|||
const N3 = "ASDFGHJKL"; |
|||
const N4 = "ZXCVBNM"; |
|||
const C1 = "京津渝沪冀晋辽吉黑苏"; |
|||
const C2 = "浙皖闽赣鲁豫鄂湘粤琼"; |
|||
const C3 = "川贵云陕甘青蒙桂宁新"; |
|||
const C4 = "藏使领警学港澳"; |
|||
const Keyboard = ({ |
|||
isNum, |
|||
onInput, |
|||
onBackspace, |
|||
onSetIsNum, |
|||
onClose, |
|||
onFinish, |
|||
}) => { |
|||
return ( |
|||
<div className="keyboard"> |
|||
<div className="bar"> |
|||
<div className="btn1" onClick={onClose}> |
|||
取消 |
|||
</div> |
|||
<div className="btn2" onClick={onFinish}> |
|||
完成 |
|||
</div> |
|||
</div> |
|||
{isNum ? ( |
|||
<div className="plane"> |
|||
<div className="row"> |
|||
{N1.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="row"> |
|||
{N2.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="row"> |
|||
{N3.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="row"> |
|||
<div className="key1" onClick={() => onSetIsNum(false)}> |
|||
字 |
|||
</div> |
|||
{N4.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
<div className="key2" onClick={onBackspace}></div> |
|||
</div> |
|||
</div> |
|||
) : ( |
|||
<div className="plane"> |
|||
<div className="row"> |
|||
{C1.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="row"> |
|||
{C2.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="row"> |
|||
{C3.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="row"> |
|||
<div className="key1" onClick={() => onSetIsNum(true)}> |
|||
ABC |
|||
</div> |
|||
{C4.split("").map((key) => ( |
|||
<div className="key" key={key} onClick={() => onInput(key)}> |
|||
{key} |
|||
</div> |
|||
))} |
|||
<div className="key2" onClick={onBackspace}></div> |
|||
</div> |
|||
</div> |
|||
)} |
|||
<div className="safe"></div> |
|||
</div> |
|||
); |
|||
}; |
|||
export default Keyboard; |
|||
@ -1,128 +0,0 @@ |
|||
.keyboard { |
|||
position: absolute; |
|||
bottom: -98px; |
|||
left: 0; |
|||
right: 0; |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 100vw; |
|||
height: 294px; |
|||
z-index: 10; |
|||
.bar { |
|||
display: flex; |
|||
flex: 0 0 40px; |
|||
justify-content: space-between; |
|||
line-height: 40px; |
|||
background: #ffffff; |
|||
box-shadow: 0px -1px 12px rgba(0, 0, 0, 0.05); |
|||
.btn1 { |
|||
position: relative; |
|||
flex: 0 0 80px; |
|||
text-align: center; |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-size: 16px; |
|||
color: #4f4f4f; |
|||
&::after { |
|||
content: ""; |
|||
position: absolute; |
|||
top: 14px; |
|||
right: 0; |
|||
width: 1px; |
|||
height: 14px; |
|||
background: #e0e0e0; |
|||
} |
|||
} |
|||
.btn2 { |
|||
position: relative; |
|||
flex: 0 0 80px; |
|||
text-align: center; |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: bold; |
|||
font-size: 16px; |
|||
color: #437af7; |
|||
&::after { |
|||
content: ""; |
|||
position: absolute; |
|||
top: 14px; |
|||
left: 0; |
|||
width: 1px; |
|||
height: 14px; |
|||
background: #e0e0e0; |
|||
} |
|||
} |
|||
} |
|||
.safe { |
|||
flex: 0 0 34px; |
|||
background: #d1d5db; |
|||
} |
|||
.plane { |
|||
flex: 1; |
|||
background: #d1d5db; |
|||
.row { |
|||
display: flex; |
|||
width: 100vw; |
|||
justify-content: center; |
|||
padding-top: 12px; |
|||
} |
|||
.key { |
|||
width: 8.5333vw; |
|||
height: 40px; |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-size: 16px; |
|||
line-height: 40px; |
|||
text-align: center; |
|||
color: #333333; |
|||
background: #ffffff; |
|||
box-shadow: 0px 1px 0px #898a8d; |
|||
border-radius: 4px; |
|||
&.bold { |
|||
font-weight: bold; |
|||
} |
|||
&:active { |
|||
background: #0166b3; |
|||
box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.2); |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
.key + .key { |
|||
margin-left: 1.0667vw; |
|||
} |
|||
.key1 { |
|||
width: 13.3333vw; |
|||
height: 40px; |
|||
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%); |
|||
color: #fff; |
|||
box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.2); |
|||
border-radius: 4px; |
|||
font-family: Noto IKEA Simplified Chinese; |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
font-size: 16px; |
|||
line-height: 40px; |
|||
text-align: center; |
|||
} |
|||
.key1 + .key { |
|||
margin-left: 1.0667vw; |
|||
} |
|||
.key2 { |
|||
width: 13.3333vw; |
|||
height: 40px; |
|||
background: #adb3bc; |
|||
color: #fff; |
|||
box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.2); |
|||
border-radius: 4px; |
|||
background-image: url(./backspace.png); |
|||
background-repeat: no-repeat; |
|||
background-size: 20px; |
|||
background-position: center; |
|||
} |
|||
.key + .key2 { |
|||
margin-left: 1.0667vw; |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 502 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.1 KiB |