diff --git a/.env.development b/.env.development index a7519b9..a5df16f 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,10 @@ +### + # @LastEditors: John + # @Date: 2024-06-03 14:42:56 + # @LastEditTime: 2024-06-06 17:31:31 + # @Author: John +### VITE_APP_DEV = 'dev-api' -# VITE_API_URL = 'http://192.168.10.166:8096' +VITE_API_URL = 'http://192.168.10.166:8097' # VITE_API_URL = 'https://8.217.122.133:10020' -VITE_API_URL = 'https://api.pineer.cc' \ No newline at end of file +# VITE_API_URL = 'https://api.pineer.cc' \ No newline at end of file diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index d60d84e..843388b 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/index.html b/index.html index 1228873..ac811a3 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ @@ -9,7 +9,10 @@ - + Pioneer diff --git a/package.json b/package.json index c84da9f..7c2f1b8 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "@use-gesture/react": "^10.3.1", "antd-mobile": "^5.34.0", "axios": "^1.6.7", "i18next": "^23.7.20", diff --git a/src/App.css b/src/App.css index b73928a..6372346 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,9 @@ #root { - /* max-width: 1280px; */ - /* margin: 0 auto; */ padding: 2rem; text-align: center; -} \ No newline at end of file +} + +.adm-center-popup-wrap { + min-width: fit-content !important; + max-width: fit-content !important; +} diff --git a/src/App.tsx b/src/App.tsx index 5bcf1e0..b91a2f2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-05-22 18:06:14 - * @LastEditTime: 2024-05-22 18:45:10 + * @LastEditTime: 2024-06-06 16:49:46 * @Author: John */ import "./App.css"; @@ -11,6 +11,7 @@ import SignIn from "./pages/SignIn"; import Download from "./pages/Download"; import SelectCountry from "./pages/SelectCountry"; import { useTranslation } from "react-i18next"; +import Auth from "./pages/Auth"; function App() { const { i18n } = useTranslation(); @@ -25,6 +26,7 @@ function App() { + diff --git a/src/api/index.ts b/src/api/index.ts index 0be8c5d..7cee2dd 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,29 +1,52 @@ import { request } from "./request"; -import { AxiosRequestConfig } from 'axios'; +import { AxiosRequestConfig } from "axios"; + +export type SendCodeResType = { + sms?: boolean; + captcha?: { + bigWidth: number; + bigHeight: number; + bigImageBase64: string; + bigImage: null; + posY: number; + posX: null; + smallWidth: number; + smallHeight: number; + smallImageBase64: string; + smallImage: null; + }; +}; //发送验证码 -export const sendCode = (params: { - areaCode?: string; // 区号,只有手机号才有 - account: string; // 账号(邮箱或手机号) - status: 1 | 2; // 1=登录 2=注册 - signature: string; - timestamp: string; -},config:AxiosRequestConfig) => - request.get("/api/account/sendVerificationCode", params, { +export const sendCode = ( + params: { + areaCode?: string; // 区号,只有手机号才有 + account: string; // 账号(邮箱或手机号) + status: 1 | 2; // 1=登录 2=注册 + signature: string; + timestamp: string; + posX?: number; + }, + config: AxiosRequestConfig +) => + request.get("/api/account/sendVerificationCode", params, { timeout: 15000, - ...config + ...config, }); //注册 -export const signUp = (params: { - account: string; // account - area?: string; // 顶级区域:朝鲜/平壤、中国/广东 - areaCode?: string; // 区号,只有手机号才有 - authCode: string; // 验证码 - district?: string; // 二级区域:具体的区域 - shareCode: string; // invitation code - userName: string; // 用户名称 -},config:AxiosRequestConfig) => +export const signUp = ( + params: { + account: string; // account + area?: string; // 顶级区域:朝鲜/平壤、中国/广东 + areaCode?: string; // 区号,只有手机号才有 + authCode: string; // 验证码 + district?: string; // 二级区域:具体的区域 + shareCode: string; // invitation code + userName: string; // 用户名称 + }, + config: AxiosRequestConfig +) => request.post("/api/account/signUp", params, { timeout: 15000, - ...config - }); \ No newline at end of file + ...config, + }); diff --git a/src/api/request.ts b/src/api/request.ts index e6932c2..ada7700 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -32,6 +32,7 @@ service.interceptors.request.use( config.headers = { ...config.headers, ...customHeaders, + appVersion: "1.0.4", } as AxiosRequestHeaders; return config; @@ -55,7 +56,7 @@ interface axiosTypes { interface responseTypes { code: number; msg: string; - result: T; + data: T | null; } //核心处理代码 将返回一个promise 调用then将可获取响应的业务数据 @@ -64,7 +65,7 @@ const requestHandler = ( url: string, params: object = {}, config: AxiosRequestConfig = {} -): Promise => { +): Promise>> => { let response: Promise>>; switch (method) { case "get": @@ -81,26 +82,28 @@ const requestHandler = ( break; } - return new Promise((resolve, reject) => { + return new Promise>>((resolve, reject) => { response .then((res) => { //业务代码 可根据需求自行处理 - const data = res.data; - if (data.code !== 200 && data.code !== 0) { - //特定状态码 处理特定的需求 - if (data.code == 401) { - console.log("登录异常,执行登出..."); - } + // const data = res.data; + // if (data.code !== 200 && data.code !== 0) { + // //特定状态码 处理特定的需求 + // if (data.code == 401) { + // console.log("登录异常,执行登出..."); + // } - const e = JSON.stringify(data); - console.log(`请求错误:${e}`); - //数据请求错误 使用reject将错误返回 - reject(data); - } else { - //数据请求正确 使用resolve将结果返回 - resolve(res as T); - } + // const e = JSON.stringify(data); + // console.log(`请求错误:${e}`); + // //数据请求错误 使用reject将错误返回 + // reject(data); + // } else { + // //数据请求正确 使用resolve将结果返回 + // resolve(res as axiosTypes>); + // } + + resolve(res as axiosTypes>); }) .catch((error) => { const e = JSON.stringify(error); diff --git a/src/components/EmailForm.tsx b/src/components/EmailForm.tsx index f7b7934..011c879 100644 --- a/src/components/EmailForm.tsx +++ b/src/components/EmailForm.tsx @@ -1,16 +1,17 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { useState, useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; -import { Form, Input, Button } from "antd-mobile"; +import { Form, Input, Button, Modal } from "antd-mobile"; import "../pages/SignIn.scss"; import { useCountdown } from "../hooks/useCountdown"; import { sendCode, signUp } from "../api"; -import { sendCodeTypes, signUpTypes, ErrorType } from "../type/SignIn"; +import { signUpTypes, ErrorType } from "../type/SignIn"; import { Toast } from "antd-mobile"; import { useNavigate } from "react-router-dom"; import { Md5 } from "ts-md5"; import { FormInstance } from "antd-mobile/es/components/form"; import useUserStore from "../store/user"; +import SilderVertify, { SilderVertify_handleType } from "./SilderVertify"; function EmailForm() { const formRef = useRef(null); @@ -22,7 +23,7 @@ function EmailForm() { const [shareCode, setShareCode] = useState(""); const [remainingTime, setRemainingTime] = useState(0); const { Lang } = useUserStore(); - + const SilderVertifyRef = useRef(null); const config = { headers: { "Accept-Language": Lang, @@ -33,33 +34,59 @@ function EmailForm() { if (email === "") { return; } - const timestamp = `${new Date().getTime()}`; - const res = await sendCode( - { - account: email, - areaCode: "", - status: 2, - signature: Md5.hashStr(`Neer${email},${2},${timestamp}GetCode`), - timestamp, - }, - config - ); - console.log("res", res); - if (res.status === 200 && res.data.data.sms) { - Toast.show({ - content: t("send successfully"), - afterClose: () => { - start(60 * 1000); - }, - }); - } else { - Toast.show({ - content: t("Send failure"), - afterClose: () => { - // start(60 * 1000); - }, - }); + if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { + Toast.show({ content: t("Invalid email") }); + return; } + Modal.show({ + content: ( + <> + { + const timestamp = `${new Date().getTime()}`; + const res = await sendCode( + { + account: email, + areaCode: "", + status: 2, + signature: Md5.hashStr( + `Neer${email},${2},${timestamp}GetCode` + ), + timestamp, + posX: pox, + }, + config + ); + console.log("res", res); + if (res.status === 200 && res.data.data?.sms) { + Toast.show({ + content: t("send successfully"), + afterClose: () => { + start(60 * 1000); + }, + }); + Modal.clear(); + } else { + Toast.show({ + content: res.data.msg, + afterClose: () => { + // start(60 * 1000); + }, + }); + if (res.data.code == 1014) { + SilderVertifyRef.current?._init(); + return; + } + Modal.clear(); + } + }} + /> + + ), + closeOnMaskClick: true, + }); } catch (error: unknown) { // 检查 error 是否是 ErrorType 类型 if (typeof error === "object" && error !== null && "msg" in error) { @@ -99,8 +126,7 @@ function EmailForm() { config ); console.log("res", res); - if (res.status === 200 && res.data.data.token) { - console.log(111); + if (res.status === 200 && res.data.data?.token) { Toast.show({ content: res.data.msg, }); diff --git a/src/components/PhoneForm.tsx b/src/components/PhoneForm.tsx index 84b4292..5ac54fe 100644 --- a/src/components/PhoneForm.tsx +++ b/src/components/PhoneForm.tsx @@ -1,15 +1,23 @@ +/* + * @LastEditors: John + * @Date: 2024-06-03 18:43:16 + * @LastEditTime: 2024-06-06 18:59:13 + * @Author: John + */ import { useState, useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; -import { Form, Input, Button } from "antd-mobile"; +import { Form, Input, Button, Modal } from "antd-mobile"; import { useNavigate } from "react-router-dom"; import "../pages/SignIn.scss"; import useUserStore from "../store/user.ts"; import { useCountdown } from "../hooks/useCountdown"; import { sendCode, signUp } from "../api"; -import { sendCodeTypes, signUpTypes, ErrorType } from "../type/SignIn"; +import { signUpTypes, ErrorType } from "../type/SignIn"; import { Toast } from "antd-mobile"; import { Md5 } from "ts-md5"; import { FormInstance } from "antd-mobile/es/components/form/form"; +import SilderVertify, { SilderVertify_handleType } from "./SilderVertify.tsx"; +const defaultAreaCode = "+1"; function PhoneForm() { const formRef = useRef(null); const { t } = useTranslation(); @@ -38,10 +46,10 @@ function PhoneForm() { return ""; }; - const defaultAreaCode = "+1"; const [authCode, setAuthCode] = useState(""); const [shareCode, setShareCode] = useState(""); const [remainingTime, setRemainingTime] = useState(0); + const SilderVertifyRef = useRef(null); const gotoSelectCountry = () => { UpdatePreviousPathName("/"); @@ -60,36 +68,55 @@ function PhoneForm() { if (CurrentPhoneNumber === "") { return; } - const timestamp = `${new Date().getTime()}`; - const res = await sendCode( - { - account: CurrentPhoneNumber, - areaCode: SelectCountry?.code || defaultAreaCode, - status: 2, - signature: Md5.hashStr( - `Neer${CurrentPhoneNumber},${2},${timestamp}GetCode` - ), - timestamp, - }, - config - ); - console.log("res", res); - if (res.status === 200 && res.data.data.sms) { - console.log(111); - Toast.show({ - content: t("send successfully"), - afterClose: () => { - start(60 * 1000); - }, - }); - } else { - Toast.show({ - content: t("Send failure"), - afterClose: () => { - // start(60 * 1000); - }, - }); - } + + Modal.show({ + content: ( + <> + { + const timestamp = `${new Date().getTime()}`; + const res = await sendCode( + { + account: CurrentPhoneNumber, + areaCode: SelectCountry?.code || defaultAreaCode, + status: 2, + signature: Md5.hashStr( + `Neer${CurrentPhoneNumber},${2},${timestamp}GetCode` + ), + timestamp, + posX: pox, + }, + config + ); + if (res.status === 200 && res.data.data?.sms) { + Toast.show({ + content: t("send successfully"), + afterClose: () => { + start(60 * 1000); + }, + }); + Modal.clear(); + } else { + Toast.show({ + content: res.data.msg, + afterClose: () => { + // start(60 * 1000); + }, + }); + if (res.data.code == 1014) { + SilderVertifyRef.current?._init(); + return; + } + Modal.clear(); + } + }} + /> + + ), + closeOnMaskClick: true, + }); } catch (error: unknown) { // 检查 error 是否是 ErrorType 类型 if (typeof error === "object" && error !== null && "msg" in error) { @@ -127,8 +154,7 @@ function PhoneForm() { }, config ); - console.log("res", res); - if (res.status === 200 && res.data.data.token) { + if (res.status === 200 && res.data.data?.token) { Toast.show({ content: res.data.msg, }); diff --git a/src/components/SilderVertify.tsx b/src/components/SilderVertify.tsx new file mode 100644 index 0000000..336a455 --- /dev/null +++ b/src/components/SilderVertify.tsx @@ -0,0 +1,148 @@ +import { useDrag } from "@use-gesture/react"; +import { forwardRef, useState, useImperativeHandle, useEffect } from "react"; +import { Md5 } from "ts-md5"; +import { sendCode } from "../api"; +import useUserStore from "../store/user"; + +/* + * @LastEditors: John + * @Date: 2024-06-06 16:41:24 + * @LastEditTime: 2024-06-06 20:25:13 + * @Author: John + */ +export type SilderVertify_handleType = { + _init: () => void; +}; +const SilderVertify = forwardRef< + SilderVertify_handleType, + { + account: string; + onFinish: (pox: number) => Promise; + } +>(function ({ onFinish, account }, ref) { + const [offsetX, setOffsetX] = useState(0); + // Set the drag hook and define component movement based on gesture data. + const bind = useDrag(async ({ event, down, movement: [mx, _] }) => { + event.preventDefault(); + // console.log(down, [mx, my]); + if (down) { + if (mx <= 0) return; + if (mx >= 280) return; + setOffsetX(mx); + } else { + await onFinish(parseInt(`${mx}`)); + setOffsetX(0); + } + }); + + const [bigImage, setBigImage] = useState(""); + const [smallImage, setSmallImage] = useState(""); + const [smallImageY, setSmallImageY] = useState(0); + const { SelectCountry, Lang } = useUserStore(); + useImperativeHandle(ref, () => { + return { + _init() { + init(); + }, + }; + }); + + const config = { + headers: { + "Accept-Language": Lang, + }, + }; + async function init() { + setOffsetX(0); + const timestamp = `${new Date().getTime()}`; + const res = await sendCode( + { + account: account, + areaCode: SelectCountry?.code || "+1", + status: 2, + signature: Md5.hashStr(`Neer${account},${2},${timestamp}GetCode`), + timestamp, + }, + config + ); + if (res.status == 200 && res.data.code == 0) { + setBigImage(res.data.data?.captcha?.bigImageBase64 || ""); + setSmallImage(res.data.data?.captcha?.smallImageBase64 || ""); + setSmallImageY(res.data.data?.captcha?.posY || 0); + } + } + useEffect(() => { + init(); + + return () => {}; + }, []); + + return ( +
+ 请完成安全验证 +
+ + +
+
+
+ --{">"} +
+
+
+ ); +}); + +export default SilderVertify; diff --git a/src/i18n/cn/translation.json b/src/i18n/cn/translation.json index 6d02926..2527e9e 100644 --- a/src/i18n/cn/translation.json +++ b/src/i18n/cn/translation.json @@ -20,5 +20,6 @@ "Download": "下載", "send successfully": "發送成功", "Send failure": "發送失敗", - "Invalid phone number": "無效手機號碼" + "Invalid phone number": "無效手機號碼", + "Invalid email": "無效電子郵件" } diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json index e79f857..868e802 100644 --- a/src/i18n/en/translation.json +++ b/src/i18n/en/translation.json @@ -20,5 +20,6 @@ "Download": "Download", "send successfully": "send successfully", "Send failure": "Send failure", - "Invalid phone number": "Invalid phone number" + "Invalid phone number": "Invalid phone number", + "Invalid email": "Invalid email" } diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx new file mode 100644 index 0000000..f8cb4e8 --- /dev/null +++ b/src/pages/Auth.tsx @@ -0,0 +1,15 @@ +/* + * @LastEditors: John + * @Date: 2024-06-06 11:22:50 + * @LastEditTime: 2024-06-06 11:35:16 + * @Author: John + */ +export default function () { + return ( + <> + + Open My App with Params + + + ); +} diff --git a/tsconfig.node.json b/tsconfig.node.json index a381973..9d0aba7 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -5,7 +5,7 @@ "module": "commonjs", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, - "sourceMap":true + "sourceMap": true }, "include": ["vite.config.ts"] } diff --git a/vite.config.ts b/vite.config.ts index 861b04b..2be9464 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,16 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' +/* + * @LastEditors: John + * @Date: 2024-05-22 18:06:14 + * @LastEditTime: 2024-06-05 17:41:40 + * @Author: John + */ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; // https://vitejs.dev/config/ export default defineConfig({ + server: { + host: "192.168.10.167", + }, plugins: [react()], -}) +}); diff --git a/yarn.lock b/yarn.lock index f39f617..04ffb5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -612,6 +612,13 @@ __metadata: languageName: node linkType: hard +"@use-gesture/core@npm:10.3.1": + version: 10.3.1 + resolution: "@use-gesture/core@npm:10.3.1" + checksum: 10c0/2e3b5c0f7fe26cdb47be3a9c2a58a6a9edafc5b2895b07d2898eda9ab5a2b29fb0098b15597baa0856907b593075cd44cc69bba4785c9cfb7b6fabaa3b52cd3e + languageName: node + linkType: hard + "@use-gesture/react@npm:10.3.0": version: 10.3.0 resolution: "@use-gesture/react@npm:10.3.0" @@ -623,6 +630,17 @@ __metadata: languageName: node linkType: hard +"@use-gesture/react@npm:^10.3.1": + version: 10.3.1 + resolution: "@use-gesture/react@npm:10.3.1" + dependencies: + "@use-gesture/core": "npm:10.3.1" + peerDependencies: + react: ">= 16.8.0" + checksum: 10c0/978da66e4e7c424866ad52eba8fdf0ce93a4c8fc44f8837c7043e68c6a6107cd67e817fffb27f7db2ae871ef2f6addb0c8ddf1586f24c67b7e6aef1646c668cf + languageName: node + linkType: hard + "@vitejs/plugin-react-swc@npm:^3.5.0": version: 3.5.0 resolution: "@vitejs/plugin-react-swc@npm:3.5.0" @@ -1565,6 +1583,7 @@ __metadata: "@types/node": "npm:^20.11.7" "@types/react": "npm:^18.2.43" "@types/react-dom": "npm:^18.2.17" + "@use-gesture/react": "npm:^10.3.1" "@vitejs/plugin-react-swc": "npm:^3.5.0" antd-mobile: "npm:^5.34.0" axios: "npm:^1.6.7"