From ed648a7365636549d8f6d3103c6e9779d48dee02 Mon Sep 17 00:00:00 2001 From: yyy9608 Date: Fri, 22 Dec 2023 15:57:30 +0800 Subject: [PATCH] commit --- .env | 5 + config/webpackDevServer.config.js | 7 +- env.md | 8 ++ package.json | 2 + src/App.tsx | 2 +- src/api/axios_config.ts | 35 +++++++ src/api/index.ts | 15 +++ src/api/service.ts | 65 +++++++++++++ src/assets/iconfont/iconfont.css | 10 +- src/assets/iconfont/iconfont.js | 2 +- src/assets/iconfont/iconfont.json | 7 ++ src/assets/iconfont/iconfont.ttf | Bin 3012 -> 3248 bytes src/assets/iconfont/iconfont.woff | Bin 2104 -> 2280 bytes src/assets/iconfont/iconfont.woff2 | Bin 1616 -> 1784 bytes src/assets/tabbar/tabbar-3-o.png | Bin 1578 -> 1938 bytes src/assets/tabbar/tabbar-3.png | Bin 1820 -> 3418 bytes src/global.d.ts | 3 + src/hooks/useConnectWallet.ts | 87 ++++++++++++++++++ src/index.tsx | 1 + src/pages/cart/index.tsx | 43 --------- src/pages/home/index.tsx | 43 ++++++++- src/pages/personal/index.tsx | 87 ++++++++---------- src/pages/share/index.tsx | 71 ++++++++++++++ src/router/index.tsx | 56 ----------- src/router/layout/ConnectButton.tsx | 78 ++++++++++++++++ src/router/layout/Navbar.tsx | 29 ++++++ src/router/{ => layout}/Notify.tsx | 0 .../{router.tsx => layout/RenderRouter.tsx} | 6 +- src/router/layout/Tabbar.tsx | 36 ++++++++ src/router/layout/index.tsx | 47 ++++++++++ src/router/routes.tsx | 12 +-- src/store/index.ts | 64 +++++++++++++ src/styles/cart.scss | 60 ------------ src/styles/home.scss | 60 +++++++++++- src/styles/layout.scss | 21 +++++ src/styles/personal.scss | 80 +++++++++------- src/styles/share.scss | 44 +++++++++ src/types/api.d.ts | 12 +++ src/types/index.ts | 2 + src/types/store.d.ts | 6 ++ src/utils/index.ts | 14 +++ src/utils/sign/sign.ts | 21 +++++ src/utils/sign/sort.ts | 35 +++++++ yarn.lock | 23 +++++ 44 files changed, 938 insertions(+), 261 deletions(-) create mode 100644 .env create mode 100644 env.md create mode 100644 src/api/axios_config.ts create mode 100644 src/api/index.ts create mode 100644 src/api/service.ts create mode 100644 src/global.d.ts create mode 100644 src/hooks/useConnectWallet.ts delete mode 100644 src/pages/cart/index.tsx create mode 100644 src/pages/share/index.tsx delete mode 100644 src/router/index.tsx create mode 100644 src/router/layout/ConnectButton.tsx create mode 100644 src/router/layout/Navbar.tsx rename src/router/{ => layout}/Notify.tsx (100%) rename src/router/{router.tsx => layout/RenderRouter.tsx} (83%) create mode 100644 src/router/layout/Tabbar.tsx create mode 100644 src/router/layout/index.tsx create mode 100644 src/store/index.ts delete mode 100644 src/styles/cart.scss create mode 100644 src/styles/share.scss create mode 100644 src/types/api.d.ts create mode 100644 src/types/index.ts create mode 100644 src/types/store.d.ts create mode 100644 src/utils/index.ts create mode 100644 src/utils/sign/sign.ts create mode 100644 src/utils/sign/sort.ts diff --git a/.env b/.env new file mode 100644 index 0000000..7485974 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +SKIP_PREFLIGHT_CHECK=true +GENERATE_SOURCEMAP=false +REACT_APP_BASE_URL='http://14.29.101.215:30304' +REACT_APP_SHARE_LINK='http://14.29.101.215:30305/#/' +REACT_APP_SIGN_KEY='finance_ad123' diff --git a/config/webpackDevServer.config.js b/config/webpackDevServer.config.js index 52f4edf..9446ab0 100644 --- a/config/webpackDevServer.config.js +++ b/config/webpackDevServer.config.js @@ -100,7 +100,12 @@ module.exports = function (proxy, allowedHost) { index: paths.publicUrlOrPath, }, // `proxy` is run between `before` and `after` `webpack-dev-server` hooks - proxy, + proxy: { + '/api': { + target: 'http://14.29.101.215:30304', // 你要代理的后端API服务器地址 + changeOrigin: true, // 设置为true,以处理跨域请求 + }, + }, onBeforeSetupMiddleware(devServer) { // Keep `evalSourceMapMiddleware` // middlewares before `redirectServedPath` otherwise will not have any effect diff --git a/env.md b/env.md new file mode 100644 index 0000000..c1a5fe6 --- /dev/null +++ b/env.md @@ -0,0 +1,8 @@ +``` +SKIP_PREFLIGHT_CHECK=true +GENERATE_SOURCEMAP=false + + +REACT_APP_BASE_URL='http://14.29.101.215:30304' +REACT_APP_SHARE_LINK='http://14.29.101.215:30305/#/' +REACT_APP_SIGN_KEY='finance_ad123' diff --git a/package.json b/package.json index 16cb0af..9c87c96 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "babel-preset-react-app": "^10.0.1", "bfj": "^7.0.2", "browserslist": "^4.18.1", + "buffer": "^6.0.3", "camelcase": "^6.2.1", "case-sensitive-paths-webpack-plugin": "^2.4.0", "css-loader": "^6.5.1", @@ -37,6 +38,7 @@ "jest": "^27.4.3", "jest-resolve": "^27.4.2", "jest-watch-typeahead": "^1.0.0", + "js-md5": "^0.8.3", "mini-css-extract-plugin": "^2.4.5", "mobx": "^6.12.0", "mobx-react": "^9.1.0", diff --git a/src/App.tsx b/src/App.tsx index db1924a..91a9b32 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ import '~/assets/iconfont/iconfont.css'; import { HashRouter } from 'react-router-dom'; -import LayoutRouter from '~/router' +import LayoutRouter from '~/router/layout' function App() { return ( diff --git a/src/api/axios_config.ts b/src/api/axios_config.ts new file mode 100644 index 0000000..a3039e9 --- /dev/null +++ b/src/api/axios_config.ts @@ -0,0 +1,35 @@ +export default { + baseURL: process.env.NODE_ENV === 'development' ? '/api' : process.env.REACT_APP_BASE_URL + '/api', + method: "post", + //`timeout`选项定义了请求发出的延迟毫秒数 + //如果请求花费的时间超过延迟的时间,那么请求会被终止 + timeout: 60 * 1000, + //发送请求前允许修改数据 + transformRequest: [ + function (data: any) { + return data; + }, + ], + //数据发送到then/catch方法之前允许数据改动 + transformResponse: [ + function (data: any) { + return data; + }, + ], + // headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + headers: { "Content-Type": "application/json; charset=UTF-8" }, + // withCredentials: false,//跨域请求时是否携带cookie + responseType: "json", //响应数据类型 + // xsrfCookieName: 'XSRF-TOKEN', + // xsrfHeaderName: 'X-XSRF-TOKEN', + onUploadProgress: function (progressEvent: any) {}, //上传进度事件 + onDownloadProgress: function (progressEvent: any) {}, //下载进度事件 + //`validateStatus`定义了是否根据http相应状态码,来resolve或者reject promise + //如果`validateStatus`返回true(或者设置为`null`或者`undefined`),那么promise的状态将会是resolved,否则其状态就是rejected + validateStatus: function (status: number) { + return status >= 200 && status < 300; // 默认的 + }, + + //`maxRedirects`定义了在nodejs中重定向的最大数量 + maxRedirects: 5, +} as any; diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..ef6ae96 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,15 @@ +import { PerformSignin, PerformSNonce } from "~/types" +import request from './service' + +/** + * @description 获取随机数 + */ +export const getNonce = (query: PerformSNonce) => request({ + url: '/v1/nonce', + data: query +}) + +/** + * @description 签名 + */ +export const performSignin = (query: PerformSignin) => request({ url: '/v1/signin', data: query }) \ No newline at end of file diff --git a/src/api/service.ts b/src/api/service.ts new file mode 100644 index 0000000..23d02f6 --- /dev/null +++ b/src/api/service.ts @@ -0,0 +1,65 @@ +import axiosConfig from "./axios_config"; +import axios from 'axios'; +import signGenerator from "../utils/sign/sign"; +import { Toast } from "react-vant"; +import sortParam from "../utils/sign/sort"; +import store from '../store'; + +const service = axios.create(axiosConfig); + +// 请求拦截 +service.interceptors.request.use( + config => { + (config.headers as any).token = store.state.token; + if (!config.data) config.data = {}; + let ps = config.params ? sortParam(config.params) : ""; + let timestamp = new Date().getTime(); + let signData = { + uri: '/api' + config.url, + timestamp: timestamp, + args: ps, + }; + let sign = signGenerator(signData); + (config.headers as any).sign = sign; + (config.headers as any).timestamp = timestamp; + config.data = JSON.stringify(config.data); + return config; + }, + error => { + return Promise.reject(error); + } +); + +// 响应拦截 +service.interceptors.response.use( + (res: any) => { + try { + let data = JSON.parse(res.data); + if (data.code === 101) { //Token 过期 + store.removeAddr() + store.removeToken() + }; + if (data.code !== 0) { + Toast.info({ + message: data.msg, + duration: 2000 + }); + }; + return data + } catch (error) { + return null; + } + }, + error => { + try { + if(error.response){ + let data = JSON.parse(error.response.data); + Toast.info(data.err); + return data + } + } catch (error) { + console.error(error); + } + } +) +export default service; \ No newline at end of file diff --git a/src/assets/iconfont/iconfont.css b/src/assets/iconfont/iconfont.css index b88bc1f..f7a7bc9 100644 --- a/src/assets/iconfont/iconfont.css +++ b/src/assets/iconfont/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 4379626 */ - src: url('iconfont.woff2?t=1702978569341') format('woff2'), - url('iconfont.woff?t=1702978569341') format('woff'), - url('iconfont.ttf?t=1702978569341') format('truetype'); + src: url('iconfont.woff2?t=1703215943461') format('woff2'), + url('iconfont.woff?t=1703215943461') format('woff'), + url('iconfont.ttf?t=1703215943461') format('truetype'); } .iconfont { @@ -13,6 +13,10 @@ -moz-osx-font-smoothing: grayscale; } +.icon-tuichu:before { + content: "\e669"; +} + .icon-shangchuandaochu:before { content: "\e8c6"; } diff --git a/src/assets/iconfont/iconfont.js b/src/assets/iconfont/iconfont.js index 7d9d704..c8a5e75 100644 --- a/src/assets/iconfont/iconfont.js +++ b/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4379626='',function(c){var t=(t=document.getElementsByTagName("script"))[t.length-1],e=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,i,n,l,a,s=function(t,e){e.parentNode.insertBefore(t,e)};if(e&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(t){console&&console.log(t)}}o=function(){var t,e=document.createElement("div");e.innerHTML=c._iconfont_svg_string_4379626,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?s(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),o()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(n=o,l=c.document,a=!1,h(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,d())})}function d(){a||(a=!0,n())}function h(){try{l.documentElement.doScroll("left")}catch(t){return void setTimeout(h,50)}d()}}(window); \ No newline at end of file +window._iconfont_svg_string_4379626='',function(c){var t=(t=document.getElementsByTagName("script"))[t.length-1],e=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,i,n,l,a,s=function(t,e){e.parentNode.insertBefore(t,e)};if(e&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(t){console&&console.log(t)}}o=function(){var t,e=document.createElement("div");e.innerHTML=c._iconfont_svg_string_4379626,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?s(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),o()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(n=o,l=c.document,a=!1,h(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,d())})}function d(){a||(a=!0,n())}function h(){try{l.documentElement.doScroll("left")}catch(t){return void setTimeout(h,50)}d()}}(window); \ No newline at end of file diff --git a/src/assets/iconfont/iconfont.json b/src/assets/iconfont/iconfont.json index 43c3c57..1a8d423 100644 --- a/src/assets/iconfont/iconfont.json +++ b/src/assets/iconfont/iconfont.json @@ -5,6 +5,13 @@ "css_prefix_text": "icon-", "description": "", "glyphs": [ + { + "icon_id": "12331673", + "name": "退出", + "font_class": "tuichu", + "unicode": "e669", + "unicode_decimal": 58985 + }, { "icon_id": "1727451", "name": "219上传、导出", diff --git a/src/assets/iconfont/iconfont.ttf b/src/assets/iconfont/iconfont.ttf index 0a2e44ed8b9eaeb2f6486239d065ccc7ace84c2f..1ce06677a70c1aa53ec319e368994d4ec1d48864 100644 GIT binary patch delta 769 zcmZvZOKTHR6oAi}OeW1F%>(n8lvqnrl7hBKI+GxMq!lR&SyMhCuKJ99_!n4MQUHA0-aG!gw_2?#`_iyNatAP)mOd?x zSGuu`4rK#pl@p9iZnd=luffnhU7(#O*DYY-5&65oK^j)Is$n&&mK)=Zdehe&YaVI0 z`kz+W#WUxT;{N^V((M{%>WBj)n6$o-Q+AnC<&ZJgtXhk(*k0-WT6P_Z12wEe89>eI zX#J{X9nHTnu0#2uQP-hL(Ddn0O=ynkP<3b?>FD#R!97@p?$h; zra_8unVvil4uwOKIEt~sh{x^Xf;PtO@_M|UNGuwQO5y;92T+U-VK;ioZsJUwArO+B zWF&v5i^HEwxy(rX>gugdyWlim%UzNNr&FI($>~99C_iC$3U=$%YOr@~^kKec6O3ky zUvMwShqJk*+uLhF!OnZm6<;KBsiY`LVltIWtQUKXF24|5xj8knT+EKd@l>$kzJs?4 rw%-#D5A0oJ`%PzgWYB;t8j(X2cAyz~v;bFG$fh$3O4)LQCJTQ6{V1#! delta 523 zcmY+9KTE@45XPTN(lq@8Rw-zUs9+_Fia0n`s)JuZ7wMuwt3?`{qG$y{bW(6oA`W#D zg{}p`$-z?T?9dOOOOnA=&?(;A=wQMx@7?9O=k9H!UivRakLm!O16W-%4eMbxmjxg&wd{wFO}B}`6HC) z-a*cjrct#hg);vi;Cy7;Fbj#hbhZI#9Ui!8m3MY;dotHREX#t^%cs#?1jHe8-zn{_ z^khE~Q@8-U*OO;|r|sEm)$lYk1&nQc4 zP*7xj9}--VoVcSq6?fikc`0wsYl}OHn!P0r>%^-6FGLSd4kN@qs&FRNZc1PFs}wtm zi)CPSzhXaj3g9j{dVtv4sRRg(J0HNFa9aWF4lfnJbKuPd@I-j+fZzK8LpZ@BMQK^3 fLwc4L9}=O7a56#?$)r$-R0@+u5sJdj$CrKp**I%E diff --git a/src/assets/iconfont/iconfont.woff b/src/assets/iconfont/iconfont.woff index 50cc1372055a16e907b2882667487e633daea05b..905d5ea12798ce2bfd8c79b217dffc9065e5cce7 100644 GIT binary patch delta 1782 zcmV zAR_T;iDztiW&i*JC;$KiX#fBPXf0dSeQ0H2WB>pLlmGw#F#rGnHYW|MglK4GVE_OI z$N&HUAOHXWBnWo|CTMMRcmMzf=l}o!7ytkOC@7o%|7>q#VE_OJ00000761SM76(KH zbZudHZ~y={2N(bV0384T03ZPx0B>$#ZDjxe2RHx#0YCr%0%s7TJg{(Yb94Xz2zUSh z0BryO0Fhz9P@j_s0YU*_lS=_Pe}KmgOn98-lEDpwFbqY1Af=_^&_gdwz@ts6Dl004NLZIoSX+f)?C@9~ZE;UrFj9Vbnf zCb1j4A8C^MD;;f`bW*#PHf_g8Ta>Js5Mph!mXEEYQqh)b>;-LIH;^_VkcN0e8jon2 z5R^Rtk07B*NE3o59(jNve+1OwI;9{aG=q7Z6c#9!cTq@!a9(V`+N zvZ0SaUQ>k-@03_7#D|5jpytiIY3LbHGN7A7&ewWc{e2JzIHDS=5Z7Gvk3^B;cFBBz2WWR?l2yBechReeE-&6EuG$B5glCUu&$d6pHYBgoS%;j4#4k<81;$BnO0W z10&=_EJ6^Lg5;v5V3OD*h3?)e-J%9d`;8Jt80}dl*xR%Apky^#Ynz*nw@LmnG=dOE z@-p)<0whz41(#D)e~2Xrgs>|^UfK`{nD7W_s!fFuA_#y5S%Do`>Nq~$0rf;OJOA>z z(_KuQ={kMxrTJV>m)6&x?Jv(&k8kI4+v6u^%b83{qA2USva+IB@51xe8*xEMz~$6Q zW2inWdk3>VU-l>?&(??XFDO#()lzk?+@Bp(wS4PCg|#%Mf2{MFM4}(Ike#{B;63<( z7!P6)hj@|^;v`;BOQTRNXg7#rde{(miCnE48^(BcUD<$ivABkB|DzI9&% zFLj;y)@?pF5dt)0{HpW^v zYV%ree}B4nV(P=GiQcsBEDY4TZ!l2~Zjb*RGqzzpyq12Yuy7dCitUWO>EWXGJ{)8p zAK|xfnUH=QjiToeN@XAm86X&24MTLgSc*_~27n9}LN@PCN^P|n(p6+2XNv4}1UOMv zk}RZ>q^amcG)1s$(Mrs&Qv9Iruz=5FKNftff3Z}c2d7O}VaZ^90`@rqY)rUAt25OZ zmA)gySZj-my9oz(oHNR9;N4~D+b?0pO>>MOO}=)0Yx1#R*ugs(%KLy~AQtH2c86DI zxLm0?z|E`5v;Y8joMT{QU|`^4NM>MT00Aa2j|)it z2lE*K6O93i006U#21EgEh(QhlAq)W9)kVaM@gMuBS{fiCO(?|gOXAhJ%w%AL9|8Uo zaKjUxaYu(2^mxU9H*jMX&hu`WT3SIZk}iA8I(a?ER3f#VtMbc5sWRlzOUmPjI-gYz Y>Rmt1ggR&c7Bfm>0ACIvAo>6R0QC3^!2kdN delta 1630 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 S?6!bFY5H~Gz0gdIF#rGwieyUw delta 1607 zcmV-N2Dth74bTi2cTYw#00961000J101E&B000Zb000I9kr*C-3JQrNhz9{S0we<@ z3lsnZAO(bH2Z0D1Q3_F%P)-=x7uYuJ(I%b6-#&cf+}pgu=KugV6bk?-0Kf$&)^H%d zZ@=H2nRQI0Ly}D5bPRaIWFsOJC}{^h!Iutw}*Ao0EbVeI4|tVAL;xIJmt7 zVnCXCf848@=?QS|Wdp#=oD)AqQ!Y@jw8q4O_X~U^Qw@?*K;`D~PYo14a3gFFu>;Z7@eLwv{e`ElrGq5v_ zPHyeo|2x?aH^lMZLk{4qzadzi0U98H&Y9V$t@hl=f=nk7ivDhH)*SNX68w^VXa24_ z2~4hj(EJdPzVSbj9mnP(`TUubP~lm0Cg&_%=6zQCkf{aF7HF z!9sFX2pZCVnnF;J4lu!h_6Eq#TjQNw@&TnlOEAX;m~O~ZG4~j9UI_fEa@BPZ?~r9y zwNy(&%4Ajb^Q7w*J~qUHge8ZRy$R>t4$WU@IP1d097M3JoThz-NVQ9T5e;z0H%1Ra zgplJYm|_C2I!1&66Tk_-NG0zA&H5FfeEcqTpSVYV-pLMm*2| zvMj2wVN)<7Od-dUb}s4Fgr^X%SjwkHAs`@p80G_*h)aA~@&W*7$&qV7K@d(KznDl- zBJE6=v;#zJV6tg~#{9gb!h%$136$VCieYe??%P$JDq5E+bwDebG7se2!xZO@3{#s# z>&S?In$^e*v~W|@%xo`XaEqn^z^7C!hE!CB#y}i|;c14UI8Gm~d>A4oN~nXHr%0E{ z!_6dXB$%Uf<;W3;m{ea?w-$9F8T2Xu;72VjhnH1{K{NC}-iyYz0=CB7MF9c0_}V~s zZhHNpFx61i!zH`E0Osm#SAxVi-k!7yW!W!-&VXJ(z~bnt^CGETpb3 zq)VV{=n4+eXx!5?X;bYhw2rb254VhevOa`}7-C$1$b1Z;V}@>9|G=1*krr^zVhwK_ zV3+PI_xZRKr^jB2?~KXFy5eK(kUo9N_b+WXIpzG}xw7sJwS&=)5wTX7K=%^S2i0!q zDnH+aD8FneFe_+z2|0(k#)QxIt*mVFJ@umeDWiz)uVvVzdSyutrrkuRtAz5 zEN{X}iUEO706&pHzUO`o1s|<{9B~RFU{(bPr=G0n?Vx4o2g4bFpu_Oq849dgM7amh z>`(%d>lRqHM-aJEWJP}htyls^u0III62ajzG$%J$2$d|%{vaA|oY1Q`>nr)bpyVY# zNxBGenAka_^Y_${bg@PE?Wd{^oN$FZ^=woMLo1xf=rE|ZMV$IDF;kzwX6ao z?Oder3hE$Jf;hJr5vYm-7jekRnZnEIINNkh=jJZ$j_5 zEV5U!R$Iiq$tqXuPly&Ko8{axHhCp4zmU>_L?3iuxt|pppa}o0)aIj@uvVVmb?7DY F+#D9;`N;qP diff --git a/src/assets/tabbar/tabbar-3-o.png b/src/assets/tabbar/tabbar-3-o.png index 52ee5dc2cec069c22ae28fe252db75a4814cf957..8b3ef3e2ffdef56cfe64846e6acb94339884f3a1 100644 GIT binary patch delta 1930 zcmV;52X*+W43ZBaiBL{Q4GJ0x0000DNk~Le0000;0000;2nGNE09Ea?N0A{Pe+N8C zL_t(|oaLNPXw*j($3KQ2bPqY~!9xy#F1XM@g$5d^&_MT4P%xmNP(h)V3I+@$MN4}q z)Y6s+7MfzAEgmc=L{P|~1zSQ{K}!WK3aP}>LJkTWNMR2VV%fmnNMn=$L9LKV16JpC|->0p|v@A+-a0c$b%-v%lv_{PFGuRh9=!28X7ZFefo~LtW(_owNEi%waRdj`1gyI_ozQQcu zFzuiK9fF=E8w`&SSD*%K?(C!;|xysAXSBSYv?-3xlbPY*UMWWf1g%(yDm2glS;iM z9GBYrN+XvYJDC(^bdNv_Si!!NuPHpVEr9i0Ij9Kuko@;KM+M$(;1aOirz-)ckeAFw zg-01#X*aPr-ewd5i`XGw5qL|>=CnY+X5n*4sHe`N67tAu>pDyPBJkfY(3b`JHg>m2 zU8vVUm_UK=wOTd*h)7d3mT7zG?9!!e=GPJzDd z$Wxj{*TRIu$O>=5ky$qefdjyMm}9~PjJ`O|)-N0Qvo{3(ZHx&HpT9i6BNDv}CWQK} zFuy5*utB_ScolO#(mLD5Yy|gVcH@%X373b!+rZ11!PkyKf1fzY>mhq4r@9Fj1fn@d zMgSj@Zw$<}Y!EM?I488T5D<9CdmoqWw})(=dr>}f9~(ec*3E!mOdwdtZFybn(Lh9% z>y9#a!$Y=&V*|)0^d|OD$s~eF>;Znn?3dz(cQ!G7jl!r0>=6EV&(iP^x|`q$a21n{ zv5ARoO%P8%e{2Ge(DyW}z^B01B#(XF1NKDx{(^_>9=LC5bQ1a8@-t>T|0wkPI~WTy zjeRLR0Nw&_VXWPL;1!?ervLY!fFCd)BMqd!RsoiYUVpnRjY`K77Z06w7HVM>ZIRg; zy98O5K;FGplmk)=UjW0Au56_D+9=1f9kQ)prqJuVb@&&z7c+RiCAO} zX^EBwkOlfnX;4~151d7kX)7_>$O@~%??VF_Gb%KLq6iG2jGj_Ynq5-pB?^+RlH|z~ zQeRggnUdDr4AQnC3`t3E0B0#Sj9n3AS%KtcJ{;)`$_?yh{-98|yR2a{S&K-eQ_Z|| zlD8cpf231z8#&S$_t_7SY-V&V^+ByqzFl~$5F#@MjbU5#_g1ga>Jd?*Dy}RRT z9}I?68V-Y`xjRM!g0v2^@B3gdq;ePiL)V0Qe@!s^piPXUDGCQHgM(jxKkyOpH;Olj zxBE_lQ9}OZ5TyK~>)rp6oc3$PciJytw^DcMSV<3~2jgB}Xkjer9*m#ql0v&I$m{I1 z&m-(}5EJS-j|uzC`U4?tB+I}V>=BV*aH1SsTH-||g5Ejo1F|Ns3mwV}73@ivSCslv ze{?n~d|el4BQ1D8gr2*x3pw_6TB#=m5srrFY64vwVUyes$qQjf*(RD(O_~))9qGj6 z1x=tfy-5&%U67?o^a*?vS(kP@`LxxdCQ)e#R1Jzx6yJ{A;borg^ls!8uuf-Iq)MOy z{rE7Su%l`4ts+kwW2S8v`M&IGZ(gBuf4bV$>m<%Fs-%nguhTK{nIv&SZ_|LIpy@_i z2`o~LjM9JuX#Spc^sKKua7K~Gwq$IH>CMS26>*Uh1v$KfKf%AnvvBz2tW-d@t_T!nONk znWI9yJ6&s-Y_wNN|FFPoep`h+ERg1D3J;U$G##^E_tO-=(RrHUZ=Qad;yF4`Q|u)9 z(-dD|&X+w)toTnqZju!|%(lK?V4laBp^u)&>Bb;NxL!T5G{ZCU5>*LvioQlMPjnsO z85x);3}enmSwHeNMFIJYX{=aMjQM2;ou>i^iGC*VF`Xv@f5%w9J4Fin4?@mS4m0pe Q)Bpeg07*qoM6N<$g8EK`6951J delta 1567 zcmV+)2H^RU52_3yiBL{Q4GJ0x0000DNk~Le0000_0000-2nGNE07hpT>yaTJe+AS@ zL_t(|ob8-XXdG1>$3Jg&o949LL9#e+CB!b(g)m zb+e*D%ht9j;G3)waA-)|HfUAdwus095xKWiZ13E;qbs(HowT!S5s|(n0jt%jBoYao zfT>Q}85V7Il9f`AfLDN-cs$P0qepd7w?%)i?Gc7j$^+g3{tRd|w5mQ&Y-)J6Bw$}( z-*1{I+rsly>nM8m?Ai0uf77Q=|Mm&00b^T9yNh`O{0bDeBwmxpK(B#xqJ#$=iy27h zHMZYGXb+GwF(q}|KpIhG(1dui2GWQkMHAxX45Sf7a&ZHREC2<3MinC?BOE?_*gzJY zBb&`qEEfHOZko#Ddwhmzr%s*no6U+8y}iAYZhO!8s0P*I)+^feLnpQW;MK|EV-vqPo zZGBamosDicaAsyk7c>iI#q-T6s-E}o;X@V{7W{&0G^#11;`zE*KA*?)JcHSULqL&T zuHQ|HS3>i?Hj3UCe^A{l-;C+CD!w^JQM>@pTke0E7SDIcGCl3v4eV+H`l!neVp=?3 z7mHeFxlkzR8jCW`#sWerwxv>uQmJG(D|@tPENV+9rp5DE@nlvKrT$((9lh!%OpCWJ zgXKS;5ApIVPi%r}NN9z=Mg5%7T5)#bLt^Brk)yXVzvHSXTM zs|yb8$?rq6Vt#SacZqXXaO>7BU1RaY?pbtg-wm2rC8gs%U`iL*-``Ivl_Hr;S~Q_Gp68Lv<#aE$ zml!}Z?6gIk#!g66n*uv^{9;;|jWP^WH(+459#4S%rbTIolSEU%MH&yk&AEO z+I8M>oKIM>)k;Jb9LLF)%jFBM>xR0N>f*(VL$O%w3*hZFL9@VxbUOV> zv^LomudQx~Qfl2^4wERQHq$NA+GJb2wpKNYh}HK5<#Kt|`nrt}i^a4{2&{@%uh%DO z&)BQBYyogxcY((D0XE8wvuDq0S7lli@7%d_1>ozA#1)aN>2&&rO?#T0W@BGj^F-w1 zb)X2=`+4bf`g7pRpg1D(L#0yr$hIv_dy4gX{Wwqzi1z5&vuDRgM@IuEM?)LiW-^&K zMC3!I)G)BG`E{Ua5xE?a$E~6{rv21$oDmV}r_nLKU$57Hu2d@DHj8*5{{s;9+P2K3 RC?x;@002ovPDHLkV1iFj{$~IH diff --git a/src/assets/tabbar/tabbar-3.png b/src/assets/tabbar/tabbar-3.png index b7f37f42d2871f5f79453206ed0560b24ab7b1fd..98bd0b3dccbd532a63666058c4059435bb212977 100644 GIT binary patch literal 3418 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 wYGjuR>{?Rc$n(tnc@#x+yaTJe+I@$ zL_t(|ob8-XXk0}c$G^Y#UUwJC!IG3Fkdw4fFo%K_3ntKt1q({eNe><>Dq8d+Xq(-p zWuVz?f=E2rQyXYOPa>pv=*7?q6)Ge&k`z*@5bVEf{*aUn^zC$aejc)ko85UY+3dW{ zK9kRBcV>2eKfZ6~H#5Jt?~xF~e~CmQ7l`O%08OYI7r&|<}6u?s}h zh0O^E05JeZi0BuCeuV;ynNJ$(YhO=K&tXG-g#wF+98;ayw*9)PzQTaT%s-myjEJ_^ z$jfH4-OPLy%YnZtn0Z@?M=KwM5Kc52ZC&}^+1dF z5kgD{;cUG@ewEDJ4&XX~hSIvrmoH;(Zcg``&O{EMPoza z0RR!*$MOiA1b{tz_P}wpe_Op_7V@kE7dp^7Ah7G_)oxwh6ZgiV7r_&eD`_lF)%RjlIyyEYpQZesbn>M z*DJPdFEI19csxE;m3RQq*Vi}8%$rSTg_WgzK7VXe)3$_L2Kopae+`b~3{)+iQfkzM zH(`UB4^=H55#2W7ObD5(TD)vFJ7U6V-0hFC8_V3@1y?ghXFtKHf zkB{T&)2C(S%>1RP6#NJ@;_cqO8}04whD>Y?qoeweZduldiPaVWv=*kP!<`e&WHNa6 z?3uRCb=@%|;wh!Hf7_L?i}&Qo6R)ZXA;gjq@t!|_J^{@=5Gf_n>9h$GTY}HU9|Jad zwk<^nk;8J_tHgo2$Lqo~^C)0QJivRu_xSN+QzmN8!-o&GgTPhS!uOq6r~{e+w8C@64Gq523ls281*2 zd4(HhUXAU>!~?wJUKqujnVIpbTHVtc70)Z~J$UfIq?wxF6|0p}s{_RJ$opSxS7v8t zy%r0%u%`uJSiEdDtDUx)Oa_@u#-yo0@tU%Q#Ui)z-Kcm%h$R3My1GY?9+@;1C|*;R znb!;sqv90^fBk0JC(Qg={3QtSv>BE#iRU$Kix&$Z0P#u<6g#ApGHuQ{>2%s_Q@?cf z?AbLT$+&oh)o7`-TuO=A*;&)(jI&-Qr5NMl6;`7%LqIsDuFtWoY#SCt%nS8N!{-8* z#qvPJ^EzqN`*uYsrTwdLp{_O~&nv?+H#b+;8J2W9e~nx&S5{6$i@Ha{0uj$I!*ciT z-5^XFVSIdCTV9+=DJBr{3jC@oym8|OCMWCb`97r-?%cV9u`%sB2WI|FS8nXlDUHEv zMD#&vxs(z^Lqlk6Y(!I26C#mFP%dl;DJ7<-r?oe>S72uCqY;6LC#4*UMx*xu?9(4-M)X^v}@tX@bK_o9UUE)9LFI5 z2LQZK3%i?OikXvA%8$;UKmX5qjg9=ptP+F}e~#lg2W{JKW9BAiE_*1jmROcGM?{NC zsgdpWj)Wa{*kOkqYDCRf+hj7?MnsL4WzD&+d$0ID=vE+vcrg-*ybJ(R%6meH4ev*5 zBAyV!*|lp|w`EzMqv*{+%)Dq>))m)v&lT?Z){LH>p2N0nUjXoCN!4ut=i>3WHY-$2 zf8gQ?AsS+_*o}1_pP#U8``GEzr)!d@Po+{P0bGK2VkF1RUndfY@BI1+{CF0PMt|DC zdk5N-QrCqLfn|AC=NtQYpJvnfeE#@)$ { + if (!(window as any).ethereum) { + return; + } + let res = await (window as any).ethereum.request({ + method: "eth_requestAccounts", + }); + if (res.length <= 0) { + removeTokenAndAddress(); + } else { + return res; + } + }; + + const removeTokenAndAddress = () => { + $store.removeAddr(); + $store.removeToken(); + }; + + const getWallet = async () => { + if (!(window as any).ethereum) { + return; + } + let res = await (window as any).ethereum.request({ + method: "eth_accounts", + }); + if (res.length <= 0) { + removeTokenAndAddress(); + } + }; + + const sign = async (nonce: string, address: string) => { + let random = ""; + if ( + (window as any).ethereum.isTokenPocket || + (window as any).ethereum.isTrust + ) { + random = nonce; + } else { + const Buffer = require("buffer").Buffer; + const buff = Buffer.from(nonce, "utf-8"); + random = "0x" + buff.toString("hex"); + } + + const signature = await (window as any).ethereum.request({ + method: "personal_sign", + params: [random, address], + }); + return signature; + }; + + const login = async () => { + try { + let [address] = await connect(); + const chain_id = await window.ethereum.request({ + method: "eth_chainId", + params: [], + }); + let nonce: any = await getNonce({ + address: address, + chainId: toNumber(chain_id), + }); + if (nonce.code !== 0) return; + let random = nonce.data.nonce; + let signature = await sign(random, address); + let res = await performSignin({ + address, + nonce: random, + signature, + // chain_id + }); + Toast.success("登錄成功"); + $store.setAddress(address); + $store.setToken(res.data.token); + } catch (error) { + console.log(error); + } + }; + + return { login, getWallet }; +} diff --git a/src/index.tsx b/src/index.tsx index b72d258..525aa1f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,6 +6,7 @@ import '~/styles/global.scss' const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); + root.render( diff --git a/src/pages/cart/index.tsx b/src/pages/cart/index.tsx deleted file mode 100644 index ce939fd..0000000 --- a/src/pages/cart/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Divider } from 'react-vant' -import '~/styles/cart.scss' - -const Cart = () => { - return ( -
-
购物车
-
- { - Array.from({ length: 5 }).map((_, index) => ( -
- -
-
The Unkown
-
-
ETH 2.25
-
- -
iamjackrider
-
-
-
Top Bid is By You
-
Time Remaining
-
-
- - -
00:02:30
-
-
- -
-
-
-
- )) - } -
-
- ) -} - -export default Cart \ No newline at end of file diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 4cf6fdd..92a5c29 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -1,6 +1,7 @@ import '~/styles/home.scss' import ProductItem from '~/components/ProductItem' import { useRouter } from '~/hooks/useRouter' +import { Button } from 'react-vant' const Home = () => { @@ -10,9 +11,45 @@ const Home = () => {
拍卖趋势
- push('/detail')} /> - - + { + Array.from({ length: 5 }).map((_, index) => ( +
+ push('/detail')} /> +
+
+
+
生肖唐彩-龙
+
+
+
铸造者
+
+ +
Filefast
+
+
+
+
售卖者
+
+ +
Filefast
+
+
+
+
+
+ + +
+
+
+
+ )) + }
售卖市场
diff --git a/src/pages/personal/index.tsx b/src/pages/personal/index.tsx index b707c37..e62ab24 100644 --- a/src/pages/personal/index.tsx +++ b/src/pages/personal/index.tsx @@ -1,59 +1,44 @@ -import { Tabs } from 'react-vant' import '~/styles/personal.scss' -import ProductItem from '~/components/ProductItem' -const Person = () => { +const Personal = () => { + return ( -
-
- -
- -
-
-
-
IamjackRider
-
-
开放我的资产
-
-
-
-
120K
-
ArtWorks
-
-
-
120K
-
Auctions
-
-
-
255 ETH
-
Earning
-
-
-
- - -
- {Array.from({ length: 10 }).map((_, index) => )} -
-
- -
- {Array.from({ length: 10 }).map((_, index) => )} +
+ + {/*
购物车
+
+ { + Array.from({ length: 5 }).map((_, index) => ( +
+ +
+
The Unkown
+
+
ETH 2.25
+
+ +
iamjackrider
+
+
+
Top Bid is By You
+
Time Remaining
+
+
+ + +
00:02:30
+
+
+ +
+
+
- - -
+ )) + } */} + {/*
*/}
) } -export default Person \ No newline at end of file +export default Personal \ No newline at end of file diff --git a/src/pages/share/index.tsx b/src/pages/share/index.tsx new file mode 100644 index 0000000..f9c35ea --- /dev/null +++ b/src/pages/share/index.tsx @@ -0,0 +1,71 @@ +import { Tabs } from 'react-vant' +import '~/styles/share.scss' +import ProductItem from '~/components/ProductItem' + +const Share = () => { + return ( +
+
+ +
+ +
+
+
+
IamjackRider
+
+
开放我的资产
+
+
+
+
5
+
售卖作品
+
+
+
15
+
拍卖作品
+
+
+
255 FIL
+
收入
+
+
+
+ + + 我的NFT + 25 +
} + titleClass='fz-wb-550' + > +
+ {Array.from({ length: 10 }).map((_, index) => )} +
+ + + 我喜欢的NFT + 999+ +
} + titleClass='fz-wb-550' + > +
+ {Array.from({ length: 10 }).map((_, index) => )} +
+
+
+
+
+ ) +} + +export default Share \ No newline at end of file diff --git a/src/router/index.tsx b/src/router/index.tsx deleted file mode 100644 index c215086..0000000 --- a/src/router/index.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useState } from 'react'; -import '~/styles/layout.scss' -import { useRouter } from '~/hooks/useRouter'; -import Notify from './Notify'; -import Router from './router'; -import { tabbarData } from './routes'; - -const LayoutRouter = () => { - - const { location, push } = useRouter() - const [visible, setVisible] = useState(false) - - return ( -
-
-
9527
-
setVisible(true)}> -
- -
-
-
- - { - tabbarData.includes(location.pathname) &&
- } -
- { - tabbarData.includes(location.pathname) && ( -
- { - tabbarData.map((item, index) => ( -
push(item)}> - - { - item === location.pathname && -
-
-
- } -
- )) - } -
- ) - } - -
- ); -} - -export default LayoutRouter \ No newline at end of file diff --git a/src/router/layout/ConnectButton.tsx b/src/router/layout/ConnectButton.tsx new file mode 100644 index 0000000..930d38e --- /dev/null +++ b/src/router/layout/ConnectButton.tsx @@ -0,0 +1,78 @@ +import '~/styles/layout.scss' +import { useEffect, useRef, useState } from "react" +import { Button, Popover, PopoverInstance, Toast } from "react-vant" +import { observer } from 'mobx-react' +import useConnectWallet from '~/hooks/useConnectWallet' +import store from '~/store' +import { splitAddress } from '~/utils' + +const ConnectButton = () => { + + const { token, walletAddress } = store.state + const [loading, setLoading] = useState(false) + const { login } = useConnectWallet(); + const popover = useRef(null); + + + const connectWallet = async () => { + setLoading(true); + await login(); + setLoading(false); + } + + const logout = () => { + popover.current && popover.current.hide(); + store.removeAddr(); + store.removeToken(); + Toast.success('退出成功'); + } + + useEffect(() => { + if (!(window as any).ethereum) { + return; + }; + (window as any).ethereum.on('accountsChanged', () => { + store.removeAddr(); + store.removeToken(); + }); + }, []); + + return ( +
+ { + token ? ( + + {splitAddress(walletAddress)} + + } + > + + + ) : ( + + ) + } + + +
+ ) +} + +export default observer(ConnectButton) \ No newline at end of file diff --git a/src/router/layout/Navbar.tsx b/src/router/layout/Navbar.tsx new file mode 100644 index 0000000..45fbab2 --- /dev/null +++ b/src/router/layout/Navbar.tsx @@ -0,0 +1,29 @@ + +import '~/styles/layout.scss' +import ConnectButton from './ConnectButton' + +interface NavbarProps { + pathname: string, + setVisible: Function +} + +const Navbar = (props: NavbarProps) => { + + const { pathname, setVisible } = props + + return ( +
+
9527
+ {/*
首页
*/} +
+ +
setVisible(true)}> +
+ +
+
+
+ ) +} + +export default Navbar \ No newline at end of file diff --git a/src/router/Notify.tsx b/src/router/layout/Notify.tsx similarity index 100% rename from src/router/Notify.tsx rename to src/router/layout/Notify.tsx diff --git a/src/router/router.tsx b/src/router/layout/RenderRouter.tsx similarity index 83% rename from src/router/router.tsx rename to src/router/layout/RenderRouter.tsx index 81bd74c..195b804 100644 --- a/src/router/router.tsx +++ b/src/router/layout/RenderRouter.tsx @@ -1,9 +1,9 @@ import { Suspense } from "react"; import { Route, Routes } from "react-router-dom"; import { Loading } from "react-vant"; -import routes from "./routes"; +import routes from "../routes"; -const Router = () => { +const RenderRouter = () => { return (
@@ -22,4 +22,4 @@ const Router = () => { ) } -export default Router; +export default RenderRouter; diff --git a/src/router/layout/Tabbar.tsx b/src/router/layout/Tabbar.tsx new file mode 100644 index 0000000..c3c7770 --- /dev/null +++ b/src/router/layout/Tabbar.tsx @@ -0,0 +1,36 @@ +import '~/styles/layout.scss' + +interface TabbarProps { + tabbarData: string[], + push: Function, + pathname: string +} + +const Tabbar = (props: TabbarProps) => { + + const { tabbarData, push, pathname } = props + + return ( +
+ { + tabbarData.map((item, index) => ( +
push(item)}> + + { + item === pathname && +
+
+
+ } +
+ )) + } +
+ ) +} + +export default Tabbar \ No newline at end of file diff --git a/src/router/layout/index.tsx b/src/router/layout/index.tsx new file mode 100644 index 0000000..22a3788 --- /dev/null +++ b/src/router/layout/index.tsx @@ -0,0 +1,47 @@ +import '~/styles/layout.scss' +import { LegacyRef, useEffect, useRef, useState } from 'react'; +import { useRouter } from '~/hooks/useRouter'; +import Notify from './Notify'; +import RenderRouter from './RenderRouter'; +import { tabbarData } from '../routes'; +import Navbar from './Navbar'; +import Tabbar from './Tabbar'; + +const LayoutRouter = () => { + + const { location, push } = useRouter() + const [visible, setVisible] = useState(false) + const pagesRef = useRef(null); + + useEffect(() => { + // 在路由变化时将自定义滚动条滚动到顶部 + + }, [location.pathname]) + + return ( +
+ +
+ + { + tabbarData.includes(location.pathname) &&
+ } +
+ { + tabbarData.includes(location.pathname) && ( + + ) + } + +
+ ); +} + +export default LayoutRouter \ No newline at end of file diff --git a/src/router/routes.tsx b/src/router/routes.tsx index 9b6f43b..89cd197 100644 --- a/src/router/routes.tsx +++ b/src/router/routes.tsx @@ -3,8 +3,8 @@ import { RouteObject } from "react-router-dom"; const Home = lazy(() => import("~/pages/home")); const Product = lazy(() => import("~/pages/product")); -const Cart = lazy(() => import("~/pages/cart")); -const Person = lazy(() => import("~/pages/personal")); +const Share = lazy(() => import("~/pages/share")); +const Personal = lazy(() => import("~/pages/personal")); const Detail = lazy(() => import("~/pages/detail")); const routes = [ @@ -17,12 +17,12 @@ const routes = [ element: , }, { - path: "/cart", - element: , + path: "/share", + element: , }, { path: "/personal", - element: , + element: , }, { path: "/detail", @@ -33,7 +33,7 @@ const routes = [ export const tabbarData = [ '/', '/product', - '/cart', + '/share', '/personal', ] diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..5e25ec8 --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,64 @@ +import { makeAutoObservable } from "mobx"; +import { StoreLocalStorageKey } from "~/types"; + +interface Store { + state: object; +} + +class AppStore implements Store { + state = { + token: "", + walletAddress: "", + }; + + constructor() { + makeAutoObservable(this); + this.initState() + } + + /** + * @description 初始化数据 + */ + initState() { + let addr = window.localStorage.getItem(StoreLocalStorageKey.ADDRESS) || ""; + let token = window.localStorage.getItem(StoreLocalStorageKey.TOKEN) || ""; + this.state.walletAddress = addr; + this.state.token = token; + } + + /** + * @description 设置token + */ + setToken(token: string): void { + this.state.token = token; + window.localStorage.setItem(StoreLocalStorageKey.TOKEN, token); + } + + /** + * @description 移除token + */ + removeToken(): void { + this.state.token = ""; + window.localStorage.removeItem(StoreLocalStorageKey.TOKEN); + } + + /** + * @description 设置地址 + */ + setAddress(addr: string): void { + this.state.walletAddress = addr; + window.localStorage.setItem(StoreLocalStorageKey.ADDRESS, addr); + } + + /** + * @description 移除地址 + */ + removeAddr(): void { + this.state.walletAddress = ""; + window.localStorage.removeItem(StoreLocalStorageKey.ADDRESS); + } +} + +const store = new AppStore(); + +export default store; diff --git a/src/styles/cart.scss b/src/styles/cart.scss deleted file mode 100644 index e4ddc9c..0000000 --- a/src/styles/cart.scss +++ /dev/null @@ -1,60 +0,0 @@ -.cart{ - - .cover{ - @include img-size(170px,170px) - } - - .box{ - height: 151px; - width: 100%; - background-color: $white; - box-shadow: 8px 8px 20px 0px rgba(0, 0, 0, 0.1); - border-top-right-radius: 10px; - border-bottom-right-radius: 10px; - - .price-tag{ - padding: 0px 8px; - height: 18px; - display: flex; - align-items: center; - background: linear-gradient(114deg, #320D6D 0%, #8A4CED 108%); - color: $white; - border-radius: 50px; - font-size: 12px; - } - - .user-tag{ - padding: 0px 8px 0px 0px; - height: 18px; - display: flex; - align-items: center; - background-color: #F1F1F1; - border-radius: 50px; - font-size: 12px; - .img{ - @include img-size(15px,15px); - border-radius:8px - } - } - - .timing-box{ - width: 85px; - height: 20px; - border-radius: 20px; - background-color: #f1f1f1; - display: flex; - justify-content: center; - align-items: center; - } - - .delete{ - width: 22px; - height: 22px; - border-radius: 12px; - background-color: #f1f1f1; - color:#F96900; - } - - } - -} diff --git a/src/styles/home.scss b/src/styles/home.scss index e1196c4..804cb17 100644 --- a/src/styles/home.scss +++ b/src/styles/home.scss @@ -7,10 +7,68 @@ &::-webkit-scrollbar{ display: none; } + + .swiper-item{ + min-width: 284px; + min-height: 375px; + position: relative; + } + + .cover-box{ + position: absolute; + width: 200px; + height: 130px; + right: 0; + bottom: 0; + background-color: rgb(248,247,255); + border-radius: 15px; + + .cover-box-item{ + position: absolute; + right: 5px; + bottom: 5px; + width: 190px; + height: 120px; + background-color: $white; + border: 1px solid #D8D8D8; + box-shadow: 0px 0px 50px 0px rgba(0, 0, 0, 0.06); + border-radius: 15px; + position: absolute; + display: flex; + justify-content: space-between; + flex-direction: column; + + .user-tag{ + width: 90%; + height: 16px; + background: #f5f5f5; + font-size: 8px; + border-radius: 8px; + + img{ + width: 16px; + height: 16px; + border-radius: 15px; + object-fit: cover; + } + } + + .button{ + width: 82px; + height: 30px; + background-color: $primary; + margin: 0; + padding: 0; + } + } + } } .swiper-img{ - @include img-size(203px,266px) + width: 220px; + height: 310px; + object-fit: cover; + border: 1px solid #D8D8D8; } } \ No newline at end of file diff --git a/src/styles/layout.scss b/src/styles/layout.scss index 073565c..82a1699 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss @@ -17,6 +17,7 @@ border-radius: 3px; background-color: $red; } + } .header-bg-color{ @@ -90,4 +91,24 @@ top: 49%; left: 0; } +} + +.connect-button{ + + .button{ + margin: 0; + padding: 0; + width: 126px; + height: 32px; + border-radius: 5px; + border: none; + display: flex; + align-items: center; + justify-content: center; + } + + .rv-popover__content{ + width: 126px; + } + } \ No newline at end of file diff --git a/src/styles/personal.scss b/src/styles/personal.scss index a180f11..e4ddc9c 100644 --- a/src/styles/personal.scss +++ b/src/styles/personal.scss @@ -1,44 +1,60 @@ -.personal{ +.cart{ - .box{ + .cover{ + @include img-size(170px,170px) + } + .box{ + height: 151px; width: 100%; - height: 200px; - position: relative; - .bg-cover{ - width: 100%; - height: 200px; - top: 0; - left: 0; - object-fit:cover; - position: absolute; - border-bottom-left-radius: 50px; - border-bottom-right-radius: 50px; + background-color: $white; + box-shadow: 8px 8px 20px 0px rgba(0, 0, 0, 0.1); + border-top-right-radius: 10px; + border-bottom-right-radius: 10px; + + .price-tag{ + padding: 0px 8px; + height: 18px; + display: flex; + align-items: center; + background: linear-gradient(114deg, #320D6D 0%, #8A4CED 108%); + color: $white; + border-radius: 50px; + font-size: 12px; } - .avatar{ - position: absolute; - left: calc(50% - 71px); - bottom: -71px; - + .user-tag{ + padding: 0px 8px 0px 0px; + height: 18px; + display: flex; + align-items: center; + background-color: #F1F1F1; + border-radius: 50px; + font-size: 12px; .img{ - @include img-size(142px,142px); - border-radius: 71px; + @include img-size(15px,15px); + border-radius:8px } } - } - .box-block{ - display: block; - height: 71px; - width: 100%; - } + .timing-box{ + width: 85px; + height: 20px; + border-radius: 20px; + background-color: #f1f1f1; + display: flex; + justify-content: center; + align-items: center; + } + + .delete{ + width: 22px; + height: 22px; + border-radius: 12px; + background-color: #f1f1f1; + color:#F96900; + } - .tag{ - background: linear-gradient(104deg, #1DD0DF -2%, #1DD0DF -2%, #1BEDFF -2%, #14BDEB 108%); - padding: 5px 15px; - font-size: 12px; - border-radius: 20px; } -} \ No newline at end of file +} diff --git a/src/styles/share.scss b/src/styles/share.scss new file mode 100644 index 0000000..a180f11 --- /dev/null +++ b/src/styles/share.scss @@ -0,0 +1,44 @@ +.personal{ + + .box{ + + width: 100%; + height: 200px; + position: relative; + .bg-cover{ + width: 100%; + height: 200px; + top: 0; + left: 0; + object-fit:cover; + position: absolute; + border-bottom-left-radius: 50px; + border-bottom-right-radius: 50px; + } + + .avatar{ + position: absolute; + left: calc(50% - 71px); + bottom: -71px; + + .img{ + @include img-size(142px,142px); + border-radius: 71px; + } + } + } + + .box-block{ + display: block; + height: 71px; + width: 100%; + } + + .tag{ + background: linear-gradient(104deg, #1DD0DF -2%, #1DD0DF -2%, #1BEDFF -2%, #14BDEB 108%); + padding: 5px 15px; + font-size: 12px; + border-radius: 20px; + } + +} \ No newline at end of file diff --git a/src/types/api.d.ts b/src/types/api.d.ts new file mode 100644 index 0000000..5a86228 --- /dev/null +++ b/src/types/api.d.ts @@ -0,0 +1,12 @@ +interface PerformSNonce { + address: string; + chainId: number; +} + +interface PerformSignin { + address: string; + nonce: string; + signature: string; +} + +export { PerformSNonce, PerformSignin } diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..fabb6b8 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,2 @@ +export { StoreLocalStorageKey } from "./store.d"; +export type { PerformSignin, PerformSNonce } from "./api"; diff --git a/src/types/store.d.ts b/src/types/store.d.ts new file mode 100644 index 0000000..30dec6a --- /dev/null +++ b/src/types/store.d.ts @@ -0,0 +1,6 @@ +enum StoreLocalStorageKey { + TOKEN = "MARKET_NFT_TOKEN", + ADDRESS = "MARKET_NFT_ADDRESS", +} + +export { StoreLocalStorageKey }; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..f820481 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,14 @@ +const splitAddress = (address: string, index?: number) => { + try { + let idx = index ? index : 5; + return ( + address.substring(0, idx) + + "..." + + address.substring(address.length - idx, address.length) + ); + } catch (error) { + return ""; + } +}; + +export { splitAddress }; diff --git a/src/utils/sign/sign.ts b/src/utils/sign/sign.ts new file mode 100644 index 0000000..6f088ee --- /dev/null +++ b/src/utils/sign/sign.ts @@ -0,0 +1,21 @@ +const md5 = require('js-md5') +var signkey = process.env.REACT_APP_SIGN_KEY + +var signGenerator = (data: any) => { + + var keys = []; + for (var key in data) { + keys.push(key); + } + keys.sort(); + + var ptxt = ""; + for (var i = 0; i < keys.length; i++) { + ptxt += keys[i] + data[keys[i]]; + } + ptxt = signkey + ptxt + signkey; + var signval = md5(ptxt).toLowerCase() + return signval; +} + +export default signGenerator; \ No newline at end of file diff --git a/src/utils/sign/sort.ts b/src/utils/sign/sort.ts new file mode 100644 index 0000000..9dbfee3 --- /dev/null +++ b/src/utils/sign/sort.ts @@ -0,0 +1,35 @@ +/* eslint-disable no-loop-func */ +var sortParam = (data: any) => { + var keys: any = []; + for (var key in data) { + keys.push(key); + } + + var ptxt = ""; + for (var i = 0; i < keys.length; i++) { + if (data[keys[i]] instanceof Array) { + if (i === 0) { + data[keys[i]].forEach((v: string, index: number) => { + if (index === 1) { + ptxt += keys[i] + "=" + v; + } else { + ptxt += "&" + keys[i] + "=" + v; + } + }); + } else { + data[keys[i]].forEach((v: any) => { + ptxt += "&" + keys[i] + "=" + v; + }); + } + } else { + if (i === 0) { + ptxt += keys[i] + "=" + data[keys[i]]; + } else { + ptxt += "&" + keys[i] + "=" + data[keys[i]]; + } + } + } + // console.log(ptxt); + return ptxt; +}; +export default sortParam; diff --git a/yarn.lock b/yarn.lock index 6c13ae8..ecb7c8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3078,6 +3078,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + batch@0.6.1: version "0.6.1" resolved "https://registry.npmmirror.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" @@ -3191,6 +3196,14 @@ buffer-from@^1.0.0: resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + builtin-modules@^3.1.0: version "3.3.0" resolved "https://registry.npmmirror.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" @@ -5328,6 +5341,11 @@ identity-obj-proxy@^3.0.0: dependencies: harmony-reflect "^1.4.6" +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0: version "5.3.0" resolved "https://registry.npmmirror.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" @@ -6274,6 +6292,11 @@ jiti@^1.19.1: resolved "https://registry.npmmirror.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +js-md5@^0.8.3: + version "0.8.3" + resolved "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz#921bab7efa95bfc9d62b87ee08a57f8fe4305b69" + integrity sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"