Browse Source

feat: search

chenlei 1 year ago
parent
commit
7599d53696

+ 1 - 0
src/app.config.ts

@@ -7,6 +7,7 @@ export default defineAppConfig({
         "pages/shopmall/index",
         "pages/feedback/index",
         "pages/order/index",
+        "pages/iframe/index",
       ],
     },
   ],

+ 51 - 20
src/pages/home/components/SearchLayout/index.tsx

@@ -1,26 +1,49 @@
-import { useState } from "react";
+import { useCallback, useMemo, useState } from "react";
 import { FC } from "@tarojs/taro";
 import { AtFloatLayout, AtInput, AtTabs, AtTabsPane } from "taro-ui";
 import { AtFloatLayoutProps } from "taro-ui/types/float-layout";
 import { View } from "@tarojs/components";
+import { CITY_LIST, SIGHT_LIST } from "../../constants";
+import { debounce } from "../../../../utils";
 import "./index.scss";
 
-export interface SearchLayoutProps extends AtFloatLayoutProps {}
+export interface SearchLayoutProps extends AtFloatLayoutProps {
+  openDetail(id: (typeof SIGHT_LIST)[0]): void;
+}
 
 export const SearchLayout: FC<SearchLayoutProps> = (props) => {
   const [curTab, setCurTab] = useState(0);
+  const [keyword, setKeyword] = useState("");
+  const [input, setInput] = useState("");
 
   const handleTabClick = (idx: number) => {
     setCurTab(idx);
   };
 
+  const debounceSearch = useCallback(
+    debounce((v: string) => {
+      setKeyword(v);
+    }, 1000),
+    []
+  );
+
+  const fakeSearch = (v: string) => {
+    return v.match(keyword) !== null;
+  };
+
   return (
     <AtFloatLayout className="search-layout" {...props}>
       <View className="search-input">
         <AtInput
+          clear
           className="search-input__input"
           name="keyword"
+          value={input}
           placeholder="请输入要搜索的内容..."
+          onChange={(v) => {
+            setInput(v as string);
+            debounceSearch(v as string);
+          }}
         />
         <View className="search-input__cancel" onClick={props.onClose}>
           取消
@@ -31,28 +54,36 @@ export const SearchLayout: FC<SearchLayoutProps> = (props) => {
         current={curTab}
         scroll
         className="search-tab"
-        tabList={[
-          { title: "标签页1" },
-          { title: "标签页2" },
-          { title: "标签页3" },
-          { title: "标签页1" },
-          { title: "标签页2" },
-          { title: "标签页3" },
-        ]}
+        tabList={CITY_LIST}
         onClick={handleTabClick}
       >
-        {Array.from({ length: 6 }).map((_, idx) => (
-          <AtTabsPane current={curTab} index={idx}>
-            <View className="search-tab__item">
-              <View className="search-tab__item-inner">
-                <View className="search-tab__item-inner__label">点位名称</View>
-                <View className="limit-line">
-                  点位介绍点位介绍点位介绍点位介绍点位介绍
+        {CITY_LIST.map((item) => (
+          <AtTabsPane current={curTab} index={item.id}>
+            {SIGHT_LIST.filter(
+              (i) =>
+                (keyword ? fakeSearch(i.title) : true) &&
+                i.parentCity === item.id
+            ).map((subItem) => (
+              <View
+                key={subItem.id}
+                className="search-tab__item"
+                onClick={props.openDetail.bind(undefined, subItem)}
+              >
+                <View className="search-tab__item-inner">
+                  <View className="search-tab__item-inner__label">
+                    {subItem.title}
+                  </View>
+                  <View className="limit-line">
+                    {(Array.isArray(subItem.content)
+                      ? subItem.content[0]
+                      : subItem.content
+                    ).slice(0, 50)}
+                  </View>
                 </View>
-              </View>
 
-              <View className="search-tab__item__more" />
-            </View>
+                <View className="search-tab__item__more" />
+              </View>
+            ))}
           </AtTabsPane>
         ))}
       </AtTabs>

+ 10 - 2
src/pages/home/components/SightDetailLayout/index.tsx

@@ -41,12 +41,20 @@ export const SightDetailLayout: FC<SightDetailLayoutProps> = (props) => {
         />
 
         <View className="sight-layout-toolbar">
-          <View className="sight-layout-toolbar__btn">全景浏览</View>
+          {/* <View className="sight-layout-toolbar__btn">全景浏览</View> */}
 
           <View className="sight-layout-toolbar__btn">场景漫游</View>
         </View>
 
-        <View className="sight-layout__text">{props.item.content}</View>
+        {Array.isArray(props.item.content) ? (
+          props.item.content.map((i, idx) => (
+            <View className="sight-layout__text" key={idx}>
+              {i}
+            </View>
+          ))
+        ) : (
+          <View className="sight-layout__text">{props.item.content}</View>
+        )}
 
         <Image
           className="sight-layout__close"

+ 2 - 2
src/pages/home/components/Swiper/index.tsx

@@ -39,7 +39,7 @@ export const Swiper = forwardRef<SwiperMethods, SwiperProps>(
     const [itemStack, setItemStack] = useState(getItemStack());
     const touchStartX = useRef(0);
     const moving = useRef(false);
-    const [isRunning, setIsRunning] = useState(true);
+    const [isRunning, setIsRunning] = useState(false);
 
     const getNextItem = (curIndex: number, length: number) => {
       return (curIndex + 1) % length;
@@ -89,9 +89,9 @@ export const Swiper = forwardRef<SwiperMethods, SwiperProps>(
       moving.current = true;
       fn();
 
+      setIsRunning(true);
       setTimeout(() => {
         moving.current = false;
-        setIsRunning(true);
       }, 800);
     };
 

File diff suppressed because it is too large
+ 67 - 2
src/pages/home/constants.ts


+ 26 - 1
src/pages/home/index.scss

@@ -120,6 +120,31 @@
   left: 0;
   right: 0;
   bottom: 0;
-  background: white;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgba(255, 255, 255);
+  transition: opacity ease-in 1s;
+  will-change: opacity;
   z-index: 999;
+
+  &__icon {
+    animation: loading-rotate 2s linear infinite;
+  }
+  &.hide {
+    animation: loading-leave 1s ease-in forwards;
+  }
+}
+
+@keyframes loading-leave {
+  100% {
+    opacity: 0;
+    z-index: -1;
+  }
+}
+
+@keyframes loading-rotate {
+  100% {
+    transform: rotate(360deg);
+  }
 }

+ 60 - 16
src/pages/home/index.tsx

@@ -1,6 +1,14 @@
 import { useMemo, useRef, useState } from "react";
 import { Image, View, Text } from "@tarojs/components";
-import { FC, pxTransform, useDidHide, useDidShow } from "@tarojs/taro";
+import classNames from "classnames";
+import { AtIcon } from "taro-ui";
+import Taro, {
+  FC,
+  nextTick,
+  pxTransform,
+  useDidHide,
+  useDidShow,
+} from "@tarojs/taro";
 import { Menu } from "./components/Menu";
 import BtmBgImg from "../../images/img_map2@2x-min.png";
 import BgImg from "../../images/img_map@2x-min.png";
@@ -14,14 +22,20 @@ import { SIGHT_LIST } from "./constants";
 import "./index.scss";
 
 const HomePage: FC = () => {
+  const [loaded, setLoaded] = useState(false);
   const [showMenu, setShowMenu] = useState(false);
   const [showSearch, setShowSearch] = useState(false);
   const [showSight, setShowSight] = useState(false);
   const swiperRef = useRef<SwiperMethods>(null);
   const [curSwiperItem, setCurSwiperItem] = useState(10);
-  const item = useMemo(() => {
-    return SIGHT_LIST.find((i) => i.id === curSwiperItem);
-  }, [curSwiperItem]);
+  const [item, setItem] = useState(
+    SIGHT_LIST.find((i) => i.id === curSwiperItem)
+  );
+
+  const realItem = useMemo(
+    () => SIGHT_LIST.find((i) => i.id === curSwiperItem),
+    [curSwiperItem]
+  );
 
   const openSearch = () => {
     setShowMenu(false);
@@ -30,6 +44,7 @@ const HomePage: FC = () => {
 
   const handleDetail = () => {
     swiperRef.current?.setIsRunning(false);
+    setItem(SIGHT_LIST.find((i) => i.id === curSwiperItem));
     setShowSight(true);
   };
 
@@ -38,8 +53,20 @@ const HomePage: FC = () => {
     swiperRef.current?.setIsRunning(true);
   };
 
-  useDidShow(() => {
+  const closeMenu = () => {
+    setShowMenu(false);
     swiperRef.current?.setIsRunning(true);
+  };
+
+  const handleLoaded = () => {
+    nextTick(() => {
+      setLoaded(true);
+      swiperRef.current?.setIsRunning(true);
+    });
+  };
+
+  useDidShow(() => {
+    loaded && swiperRef.current?.setIsRunning(true);
   });
   useDidHide(() => {
     swiperRef.current?.setIsRunning(false);
@@ -47,6 +74,15 @@ const HomePage: FC = () => {
 
   return (
     <View className="home-container">
+      <View className={classNames("ld-page", { hide: loaded })}>
+        <AtIcon
+          className="ld-page__icon"
+          value="loading"
+          color="#589498"
+          size={40}
+        />
+      </View>
+
       <View className="home">
         <View
           className="home__menu-btn"
@@ -66,14 +102,7 @@ const HomePage: FC = () => {
           />
         )}
 
-        <Menu
-          show={showMenu}
-          onClose={() => {
-            setShowMenu(false);
-            swiperRef.current?.setIsRunning(true);
-          }}
-          openSearch={openSearch}
-        />
+        <Menu show={showMenu} onClose={closeMenu} openSearch={openSearch} />
 
         <View className="home-main">
           <Swiper
@@ -92,9 +121,9 @@ const HomePage: FC = () => {
             <View className="home-toggle-inner">
               <View className="home-toggle-label">
                 <Text className="home-toggle-label__title limit-line">
-                  {item?.title}
+                  {realItem?.title}
                 </Text>
-                <Text>{item?.address}</Text>
+                <Text>{realItem?.address}</Text>
               </View>
 
               <View className="home-toggle__detail" onClick={handleDetail}>
@@ -114,17 +143,32 @@ const HomePage: FC = () => {
               mode="widthFix"
               className="home-main__btn__btn"
               src={ButtonImg}
+              onClick={() => {
+                Taro.navigateTo({
+                  url: "/subModule/pages/iframe/index?url=https://houseoss.4dkankan.com/project/wx-csbwg-public/web/index.html",
+                });
+              }}
             />
           </View>
         </View>
 
-        <Image className="home__bg" src={BgImg} mode="widthFix" />
+        <Image
+          className="home__bg"
+          src={BgImg}
+          mode="widthFix"
+          onLoad={handleLoaded}
+        />
         <Image className="home__btm-bg" src={BtmBgImg} mode="widthFix" />
       </View>
 
       <SearchLayout
         isOpened={showSearch}
         onClose={() => setShowSearch(false)}
+        openDetail={(item) => {
+          swiperRef.current?.setIsRunning(false);
+          setItem(item);
+          setShowSight(true);
+        }}
       />
 
       {item && (

+ 0 - 10
src/pages/login/index.scss

@@ -74,13 +74,3 @@
     }
   }
 }
-
-.ld-page {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: white;
-  z-index: 999;
-}

+ 35 - 45
src/pages/login/index.tsx

@@ -16,7 +16,6 @@ import {
   setVistorName,
   wechatLoginApi,
 } from "../../api";
-// import { LoadingPage } from "../../components/LoadingPage";
 import baseStore from "../../store/base";
 import "./index.scss";
 
@@ -26,7 +25,6 @@ const formRules = {
 
 const LoginPage: FC = () => {
   const [loading, setLoading] = useState(false);
-  // const [showLoading, setShowLoading] = useState(true);
   const [wechatLoading, setWechatLoading] = useState(false);
   const [name, setName] = useState(`云城居民${createRandomString()}`);
 
@@ -135,54 +133,46 @@ const LoginPage: FC = () => {
   }, []);
 
   return (
-    <>
-      <View className={classNames("login")}>
-        <AtForm
-          className="login-main margin-safe-area-bottom"
-          onSubmit={handleVisitor}
-        >
-          <View className="login-main__name">
-            <AtInput
-              value={name}
-              className="login__name-input"
-              name="name"
-              maxLength={6}
-              // @ts-ignore
-              type="nickname"
-              placeholder="请输入昵称"
-              onChange={(val) => {
-                setName(val as string);
-              }}
-            >
-              <Text className="login__name-input__num">{name.length}/6</Text>
-            </AtInput>
-
-            <AtButton
-              loading={loading}
-              className="login__visitor"
-              formType="submit"
-            >
-              游客模式
-            </AtButton>
-          </View>
+    <View className={classNames("login")}>
+      <AtForm
+        className="login-main margin-safe-area-bottom"
+        onSubmit={handleVisitor}
+      >
+        <View className="login-main__name">
+          <AtInput
+            value={name}
+            className="login__name-input"
+            name="name"
+            maxLength={6}
+            // @ts-ignore
+            type="nickname"
+            placeholder="请输入昵称"
+            onChange={(val) => {
+              setName(val as string);
+            }}
+          >
+            <Text className="login__name-input__num">{name.length}/6</Text>
+          </AtInput>
 
           <AtButton
-            loading={wechatLoading}
-            className="login__wechat-login"
-            onClick={handleUserInfo}
+            loading={loading}
+            className="login__visitor"
+            formType="submit"
           >
-            <Image className="login__wechat-login__icon" src={WechatIcon} />
-            微信一键登录
+            游客模式
           </AtButton>
-        </AtForm>
-      </View>
-
-      {/* {showLoading && (
-        <View className="ld-page">
-          <LoadingPage />
         </View>
-      )} */}
-    </>
+
+        <AtButton
+          loading={wechatLoading}
+          className="login__wechat-login"
+          onClick={handleUserInfo}
+        >
+          <Image className="login__wechat-login__icon" src={WechatIcon} />
+          微信一键登录
+        </AtButton>
+      </AtForm>
+    </View>
   );
 };
 

+ 5 - 0
src/subModule/pages/iframe/index.config.ts

@@ -0,0 +1,5 @@
+export default definePageConfig({
+  navigationBarTitleText: "锡善云城",
+  pageOrientation: "landscape",
+  navigationStyle: "custom",
+});

+ 10 - 0
src/subModule/pages/iframe/index.tsx

@@ -0,0 +1,10 @@
+import { WebView } from "@tarojs/components";
+import { FC, useRouter } from "@tarojs/taro";
+
+const IframePage: FC = () => {
+  const route = useRouter();
+
+  return route.params.url ? <WebView src={route.params.url} /> : null;
+};
+
+export default IframePage;

+ 17 - 0
src/utils/index.ts

@@ -49,3 +49,20 @@ export const handleValidate = async (params, formRules) => {
 
   return true;
 };
+
+export function debounce(func: Function, time: number, immediate = false) {
+  let timer: number | null = null;
+  return (...args: any) => {
+    if (timer) clearInterval(timer);
+    if (immediate) {
+      if (!timer) func.apply(this, args);
+      timer = window.setTimeout(() => {
+        timer = null;
+      }, time);
+    } else {
+      timer = window.setTimeout(() => {
+        func.apply(this, args);
+      }, time);
+    }
+  };
+}