فهرست منبع

集成全局状态管理工具zustand

username 1 سال پیش
والد
کامیت
00f4fdc2f5

+ 2 - 1
package.json

@@ -22,7 +22,8 @@
     "react-dom": "^18.3.1",
     "sass": "^1.77.8",
     "swiper": "^11.1.5",
-    "tailwind-merge": "^2.4.0"
+    "tailwind-merge": "^2.4.0",
+    "zustand": "^4.5.4"
   },
   "devDependencies": {
     "@types/node": "^20.14.10",

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 234 - 215
pnpm-lock.yaml


+ 39 - 0
src/app/[locale]/(ordinary)/profile/component/ItemCom/index.tsx

@@ -0,0 +1,39 @@
+"use client";
+import { ChangeEvent, FC, PropsWithChildren, useMemo, useState } from "react";
+import clsx from "clsx";
+import Link from "next/link";
+import ButtonOwn from "@/components/ButtonOwn";
+import "./style.scss";
+
+/**
+ * @description 列表组件
+ * @param {string} type 使用类型
+ * @param {(params: any) => void} callbackFun 回调方法
+ */
+export interface ItemComProps {
+    type?: string;
+    callbackFun?: (params: any) => void;
+}
+
+const ItemCom: FC<PropsWithChildren<ItemComProps>> = ({type = 'login', callbackFun}) => {
+
+    let amountList = [10,20,50,100,200,500,1000,5000,10000,500,1000,5000,10000]
+
+    return (
+        <ul className="itemCom-box">
+            {
+                amountList.map((item, index) => (
+                    <li className={index==0?'free':''} key={index}>
+                        <div className="content"> Afiliado - Ganhe R$ 10.000 por dia | 9F.COM 
+                            <span data-v-5c42ece6="" className="iconfont icon-hot"></span>
+                            <div data-v-5c42ece6=""></div>
+                        </div>
+                        <div><span className="iconfont icon-xiangyou1"></span></div>
+                    </li>
+                ))
+            }
+        </ul>
+    );
+};
+
+export default ItemCom;

+ 62 - 0
src/app/[locale]/(ordinary)/profile/component/ItemCom/style.scss

@@ -0,0 +1,62 @@
+.itemCom-box {
+  width: 100%;
+  height: auto;
+
+  li {
+    color: #fff;
+    height: .5rem;
+    line-height: .5rem;
+    font-size: .12rem;
+    border-bottom: .01rem solid #3f3f3f;
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    margin: 0 .18rem;
+    -webkit-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    line-height: .2rem;
+
+    &.free {
+      padding-top: .12rem;
+      margin: 0;
+      padding: 0 .18rem;
+      border-bottom: .08rem solid #131212;
+    }
+
+    & > div {
+      display: -webkit-box;
+      display: -ms-flexbox;
+      display: flex;
+      -webkit-box-align: center;
+      -ms-flex-align: center;
+      align-items: center;
+    }
+
+    .icon-hot {
+      font-size: .14rem;
+      color: #fc9b26;
+      margin-left: .1rem;
+    }
+
+    div {
+      &.content {
+        .iconfont {
+          margin-right: .04rem;
+          margin-left: .1rem;
+          font-size: .14rem;
+        }
+      }
+    }
+
+    .iconfont {
+      
+      &.icon-to {
+        -webkit-transform: rotate(180deg);
+        -ms-transform: rotate(180deg);
+        transform: rotate(180deg);
+      }
+    }
+  }
+}
+  

+ 3 - 54
src/app/[locale]/(ordinary)/profile/page.scss

@@ -1,5 +1,5 @@
-.main {
-    padding: .44rem 0 .04rem;
+.profile-box {
+    padding: .44rem 0 .6rem;
     min-height: 100vh;
     background-color: #1f1f1f;
     -webkit-box-sizing: border-box;
@@ -147,58 +147,7 @@
         text-align: center;
       }
     }
-    ul {
-      li {
-        color: #fff;
-        height: .5rem;
-        line-height: .5rem;
-        font-size: .14rem;
-        border-bottom: .01rem solid #3f3f3f;
-        display: -webkit-box;
-        display: -ms-flexbox;
-        display: flex;
-        margin: 0 .18rem;
-        -webkit-box-pack: justify;
-        -ms-flex-pack: justify;
-        justify-content: space-between;
-        line-height: .2rem;
-        &.free {
-          padding-top: .12rem;
-          margin: 0;
-          padding: 0 .18rem;
-          border-bottom: .08rem solid #131212;
-        }
-        & > div {
-          display: -webkit-box;
-          display: -ms-flexbox;
-          display: flex;
-          -webkit-box-align: center;
-          -ms-flex-align: center;
-          align-items: center;
-        }
-        .icon-hot {
-          font-size: .16rem;
-          color: #fc9b26;
-          margin-left: .1rem;
-        }
-        div {
-          &.content {
-            .iconfont {
-              margin-right: .04rem;
-              margin-left: .1rem;
-              font-size: .16rem;
-            }
-          }
-        }
-        .iconfont {
-          &.icon-to {
-            -webkit-transform: rotate(180deg);
-            -ms-transform: rotate(180deg);
-            transform: rotate(180deg);
-          }
-        }
-      }
-    }
+
     .logOut {
       color: #fff;
       font-size: .12rem;

+ 52 - 42
src/app/[locale]/(ordinary)/profile/page.tsx

@@ -2,14 +2,24 @@
 import { FC, PropsWithChildren } from "react";
 import { useRouter } from "@/i18n";
 // import ButtonOwn from "@/components/ButtonOwn";
+import ItemCom from "./component/ItemCom";
 import './page.scss'
+import { useGlobalStore } from '@/stores';
+import {getLogoutApi} from "@/api/user";
 
 interface Props {}
 
 const Profile: FC<PropsWithChildren<Props>> = (props) => {
-    // let [amount, setAmount] = React.useState(0)
-    let amount = 50
-    let amountList = [10,20,50,100,200,500,1000,5000,10000,500,1000,5000,10000]
+    const { token, setToken, userInfo, setUserInfo } = useGlobalStore();
+
+    const logoutRequest = async () => {
+        let res = await getLogoutApi()
+        if(res.code == 200) {
+            setUserInfo('')
+            setToken('')
+            router.replace('/login')
+        }
+    }
 
     const router = useRouter();
     const goPage = (path = '/') => {
@@ -17,43 +27,51 @@ const Profile: FC<PropsWithChildren<Props>> = (props) => {
     }
 
     return (
-        <div className="main">
+        <div className="profile-box">
             <div className="userContent">
                 <div className="userInfo">
                     <div>
                         <div className="bgImg"></div>
-                        <div>
-                            <span>Conta</span>
-                            <span className="phone">5516982013895</span>
-                        </div>
+                        {
+                            token && (
+                                <div>
+                                    <span>{userInfo?.user_name || ''}</span>
+                                    <span className="phone">{userInfo?.user_phone || ''}</span>
+                                </div>
+                            )
+                        }
                     </div>
                     <div className="goto" onClick={() => goPage('/login')}>
-                        <span>Login</span>
+                        { !token && <span>Login</span> }
                         <span className="iconfont icon-xiangzuo1"></span>
                     </div>
                 </div>
-                <div className="coin">
-                    <div>
-                        <span className="iconfont icon-wallet"></span>
-                        <div>
-                            <span> Saldo </span>
-                            <div className="num">
-                                <span className="uppercase">brl </span>
-                                <span>0.00</span>
+                { 
+                    token && (
+                        <div className="coin">
+                            <div>
+                                <span className="iconfont icon-wallet"></span>
+                                <div>
+                                    <span> Saldo </span>
+                                    <div className="num">
+                                        <span className="uppercase">brl </span>
+                                        <span>0.00</span>
+                                    </div>
+                                </div>
                             </div>
-                        </div>
-                    </div>
-                    <div>
-                        <span className="iconfont icon-gift2"></span>
-                        <div>
-                            <span> Bônus </span>
-                            <div className="num">
-                                <span className="uppercase">brl </span>
-                                <span>0.00</span>
+                            <div>
+                                <span className="iconfont icon-gift2"></span>
+                                <div>
+                                    <span> Bônus </span>
+                                    <div className="num">
+                                        <span className="uppercase">brl </span>
+                                        <span>0.00</span>
+                                    </div>
+                                </div>
                             </div>
                         </div>
-                    </div>
-                </div>
+                    ) 
+                }
             </div>
 
             <div className="link">
@@ -63,21 +81,13 @@ const Profile: FC<PropsWithChildren<Props>> = (props) => {
                 <ButtonOwn active={true}>Sacar</ButtonOwn> */}
             </div>
 
-            <ul>
-                {
-                    amountList.map((item, index) => (
-                        <li className={index==0?'free':''} key={index}>
-                            <div className="content"> Afiliado - Ganhe R$ 10.000 por dia | 9F.COM 
-                                <span data-v-5c42ece6="" className="iconfont icon-hot"></span>
-                                <div data-v-5c42ece6=""></div>
-                            </div>
-                            <div><span className="iconfont icon-xiangyou1"></span></div>
-                        </li>
-                    ))
-                }
-            </ul>
+            <ItemCom />
 
-            <span className="logOut" onClick={() => goPage('/login')}>Login</span>
+            {
+                token ? <span className="logOut" onClick={logoutRequest}>Sair</span> : (
+                    <span className="logOut" onClick={() => goPage('/login')}>Login</span>
+                )
+            }
         </div>
     );
 };

+ 5 - 1
src/app/[locale]/login/page.tsx

@@ -7,10 +7,13 @@ import FromCom from "./component/FromCom";
 import DomainFooter from "@/components/DomainFooter";
 import './page.scss'
 import {getLoginApi} from "@/api/user";
+import { useGlobalStore } from '@/stores';
 
 interface Props {}
 
 const Login: FC<PropsWithChildren<Props>> = () => {
+    const { setToken, setUserInfo } = useGlobalStore();
+
     const router:any = useRouter()
     const [msgError, setMsgError] = useState('')
     const loginRequest = async ({userPhone, pwd}: any) => {
@@ -18,7 +21,8 @@ const Login: FC<PropsWithChildren<Props>> = () => {
         let res = await getLoginApi(params)
         if(res.code == 200) {
             alert('登录成功')
-            window.localStorage.setItem('userInfo',JSON.stringify(res.data))
+            setUserInfo({...res.data, user_phone: userPhone})
+            setToken(res.data.token)
             router.replace('/')
         }
         setMsgError(res.msg || '')

+ 41 - 0
src/stores/index.ts

@@ -0,0 +1,41 @@
+import { create } from 'zustand'
+import { devtools, persist, createJSONStorage } from 'zustand/middleware';
+
+interface State {
+  lang: string;
+  token: string;
+  userInfo: any
+}
+
+interface Action {
+  setLang: (lang: State['lang']) => void;
+  setToken: (lang: State['token']) => void;
+  setUserInfo: (lang: State['userInfo']) => void;
+}
+
+export const useGlobalStore = create<State & Action>()(
+  devtools(persist(
+    (set) => {
+      return {
+        lang: 'zh',
+        token: '',
+        userInfo: '',
+        setLang: (lang: State['lang']) => set({
+          lang,
+        }),
+        setToken: (token: State['token']) => set({
+          token,
+        }),
+        setUserInfo: (userInfo: State['userInfo']) => set({
+          userInfo,
+        }),
+      };
+    },
+    {
+      name: 'globalStore',
+      storage: createJSONStorage(() => localStorage),
+    }
+  ),
+    { name: 'globalStore' }
+  )
+)

+ 4 - 4
src/utils/server/axios.ts

@@ -42,10 +42,10 @@ export default class Request {
                     config = requestInterceptor(config);
 
                     // header请求头添加token
-                    let userInfo = window.localStorage.getItem("userInfo") || '';
-                    if (userInfo) {
-                        let userInfoObj = JSON.parse(userInfo)
-                        config.headers['token'] = userInfoObj?.token;
+                    let globalStore = window.localStorage.getItem("globalStore") || '';
+                    if (globalStore) {
+                        let userInfo = JSON.parse(globalStore)
+                        config.headers['token'] = userInfo?.state?.token;
                     }
                 }
                 return config;

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است