From faf722fa15b5e1e9fc355597c3e39fc2aa23860f Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Sun, 16 Apr 2023 19:53:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=89=8B=E6=9C=BA=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=A0=81=E4=BD=9C=E4=B8=BA=E7=94=A8=E6=88=B7=E5=87=AD=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 + pnpm-lock.yaml | 179 ++++++++++++++++++ public/docs/intro.md | 2 +- src/api/user.ts | 27 +-- src/constants/common.ts | 2 +- src/hooks/useSendCode.ts | 10 +- src/pages/api/user/loginByPassword.ts | 16 +- src/pages/api/user/register.ts | 29 ++- .../user/{sendEmail.ts => sendAuthCode.ts} | 29 +-- src/pages/api/user/updatePasswordByCode.ts | 16 +- .../login/components/ForgetPasswordForm.tsx | 27 +-- src/pages/login/components/LoginForm.tsx | 21 +- src/pages/login/components/RegisterForm.tsx | 26 +-- src/pages/number/setting.tsx | 4 +- src/service/models/authCode.ts | 2 +- src/service/models/user.ts | 3 +- src/service/utils/sendEmail.ts | 63 ------ src/service/utils/sendNote.ts | 72 +++++++ src/types/mongoSchema.d.ts | 4 +- src/types/user.d.ts | 7 +- 20 files changed, 375 insertions(+), 167 deletions(-) rename src/pages/api/user/{sendEmail.ts => sendAuthCode.ts} (63%) delete mode 100644 src/service/utils/sendEmail.ts create mode 100644 src/service/utils/sendNote.ts diff --git a/package.json b/package.json index 183248fb6..55cbc3957 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,9 @@ "format": "prettier --config \"./.prettierrc.js\" --write \"./src/**/*.{ts,tsx,scss}\"" }, "dependencies": { + "@alicloud/dysmsapi20170525": "^2.0.23", + "@alicloud/openapi-client": "^0.4.5", + "@alicloud/tea-util": "^1.4.5", "@chakra-ui/icons": "^2.0.17", "@chakra-ui/react": "^2.5.1", "@emotion/react": "^11.10.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20336d4c8..e368f8cb3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,9 @@ lockfileVersion: 5.4 specifiers: + '@alicloud/dysmsapi20170525': ^2.0.23 + '@alicloud/openapi-client': ^0.4.5 + '@alicloud/tea-util': ^1.4.5 '@chakra-ui/icons': ^2.0.17 '@chakra-ui/react': ^2.5.1 '@emotion/react': ^11.10.6 @@ -61,6 +64,9 @@ specifiers: zustand: ^4.3.5 dependencies: + '@alicloud/dysmsapi20170525': registry.npmmirror.com/@alicloud/dysmsapi20170525/2.0.23 + '@alicloud/openapi-client': registry.npmmirror.com/@alicloud/openapi-client/0.4.5 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util/1.4.5 '@chakra-ui/icons': registry.npmmirror.com/@chakra-ui/icons/2.0.17_react@18.2.0 '@chakra-ui/react': registry.npmmirror.com/@chakra-ui/react/2.5.1_e6pzu3hsaqmql4fl7jx73ckiym '@emotion/react': registry.npmmirror.com/@emotion/react/11.10.6_pmekkgnqduwlme35zpnqhenc34 @@ -124,6 +130,117 @@ devDependencies: packages: + registry.npmmirror.com/@alicloud/credentials/2.2.6: + resolution: {integrity: sha512-jG+msY77dHmAF3x+8VTy7fEgORyXLHmDci8t92HeipBdCHsPptDegA++GEwKgR7f6G4wvafYt+aqMZ1iligdrQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/credentials/-/credentials-2.2.6.tgz} + name: '@alicloud/credentials' + version: 2.2.6 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + httpx: registry.npmmirror.com/httpx/2.2.7 + ini: registry.npmmirror.com/ini/1.3.8 + kitx: registry.npmmirror.com/kitx/2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/dysmsapi20170525/2.0.23: + resolution: {integrity: sha512-C02xj9S2ZPL13SciChlIY3s5+PiOM13jEGZSn+L92aiWYCBqTlpx9UMwNKBNWImMSOlG71IOSYfsQggaoIY+4Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/dysmsapi20170525/-/dysmsapi20170525-2.0.23.tgz} + name: '@alicloud/dysmsapi20170525' + version: 2.0.23 + dependencies: + '@alicloud/endpoint-util': registry.npmmirror.com/@alicloud/endpoint-util/0.0.1 + '@alicloud/openapi-client': registry.npmmirror.com/@alicloud/openapi-client/0.4.5 + '@alicloud/openapi-util': registry.npmmirror.com/@alicloud/openapi-util/0.3.1 + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util/1.4.5 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/endpoint-util/0.0.1: + resolution: {integrity: sha512-+pH7/KEXup84cHzIL6UJAaPqETvln4yXlD9JzlrqioyCSaWxbug5FUobsiI6fuUOpw5WwoB3fWAtGbFnJ1K3Yg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/endpoint-util/-/endpoint-util-0.0.1.tgz} + name: '@alicloud/endpoint-util' + version: 0.0.1 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + kitx: registry.npmmirror.com/kitx/2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/gateway-spi/0.0.8: + resolution: {integrity: sha512-KM7fu5asjxZPmrz9sJGHJeSU+cNQNOxW+SFmgmAIrITui5hXL2LB+KNRuzWmlwPjnuA2X3/keq9h6++S9jcV5g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/gateway-spi/-/gateway-spi-0.0.8.tgz} + name: '@alicloud/gateway-spi' + version: 0.0.8 + dependencies: + '@alicloud/credentials': registry.npmmirror.com/@alicloud/credentials/2.2.6 + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/openapi-client/0.4.5: + resolution: {integrity: sha512-x1blwhfPOVkH/JCLWFssFRWDL0C75RToun9AwhNV+84gqJB2/GUipm3quHGLon8JiQ0DQ9YBUho2rukSoAvhJQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/openapi-client/-/openapi-client-0.4.5.tgz} + name: '@alicloud/openapi-client' + version: 0.4.5 + dependencies: + '@alicloud/credentials': registry.npmmirror.com/@alicloud/credentials/2.2.6 + '@alicloud/gateway-spi': registry.npmmirror.com/@alicloud/gateway-spi/0.0.8 + '@alicloud/openapi-util': registry.npmmirror.com/@alicloud/openapi-util/0.3.1 + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util/1.4.5 + '@alicloud/tea-xml': registry.npmmirror.com/@alicloud/tea-xml/0.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/openapi-util/0.3.1: + resolution: {integrity: sha512-6mGT+hs+SXismZi/CEkjPhhbn2U3qTT/Qv/RXAYFA1DC3Jk4/YaX3N7RtpgdzOhdD7uI8XtNkaULKHZY3BrtxQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/openapi-util/-/openapi-util-0.3.1.tgz} + name: '@alicloud/openapi-util' + version: 0.3.1 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util/1.4.5 + kitx: registry.npmmirror.com/kitx/2.1.0 + sm3: registry.npmmirror.com/sm3/1.0.3 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/tea-typescript/1.8.0: + resolution: {integrity: sha512-CWXWaquauJf0sW30mgJRVu9aaXyBth5uMBCUc+5vKTK1zlgf3hIqRUjJZbjlwHwQ5y9anwcu18r48nOZb7l2QQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/tea-typescript/-/tea-typescript-1.8.0.tgz} + name: '@alicloud/tea-typescript' + version: 1.8.0 + dependencies: + '@types/node': registry.npmmirror.com/@types/node/12.20.55 + httpx: registry.npmmirror.com/httpx/2.2.7 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/tea-util/1.4.5: + resolution: {integrity: sha512-7NuThYUi90/ivT/ORKusm0NVKlc1khPTtlzTR77xEqSBt7d24Ee/Lo70hx9PWP28nHpIZ1gM0NKYBtpq7HUDlg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/tea-util/-/tea-util-1.4.5.tgz} + name: '@alicloud/tea-util' + version: 1.4.5 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + kitx: registry.npmmirror.com/kitx/2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/tea-xml/0.0.2: + resolution: {integrity: sha512-Xs7v5y7YSNSDDYmiDWAC0/013VWPjS3dQU4KezSLva9VGiTVPaL3S7Nk4NrTmAYCG6MKcrRj/nGEDIWL5KRoPg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/tea-xml/-/tea-xml-0.0.2.tgz} + name: '@alicloud/tea-xml' + version: 0.0.2 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript/1.8.0 + '@types/xml2js': registry.npmmirror.com/@types/xml2js/0.4.11 + xml2js: registry.npmmirror.com/xml2js/0.4.23 + transitivePeerDependencies: + - supports-color + dev: false + registry.npmmirror.com/@ampproject/remapping/2.2.0: resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.0.tgz} name: '@ampproject/remapping' @@ -5031,6 +5148,18 @@ packages: version: 0.7.31 dev: false + registry.npmmirror.com/@types/node/12.20.55: + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-12.20.55.tgz} + name: '@types/node' + version: 12.20.55 + dev: false + + registry.npmmirror.com/@types/node/14.18.42: + resolution: {integrity: sha512-xefu+RBie4xWlK8hwAzGh3npDz/4VhF6icY/shU+zv/1fNn+ZVG7T7CRwe9LId9sAYRPxI+59QBPuKL3WpyGRg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-14.18.42.tgz} + name: '@types/node' + version: 14.18.42 + dev: false + registry.npmmirror.com/@types/node/18.14.0: resolution: {integrity: sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-18.14.0.tgz} name: '@types/node' @@ -5133,6 +5262,14 @@ packages: '@types/webidl-conversions': registry.npmmirror.com/@types/webidl-conversions/7.0.0 dev: false + registry.npmmirror.com/@types/xml2js/0.4.11: + resolution: {integrity: sha512-JdigeAKmCyoJUiQljjr7tQG3if9NkqGUgwEUqBvV0N7LM4HyQk7UXCnusRa1lnvXAEYJ8mw8GtZWioagNztOwA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/xml2js/-/xml2js-0.4.11.tgz} + name: '@types/xml2js' + version: 0.4.11 + dependencies: + '@types/node': registry.npmmirror.com/@types/node/18.14.0 + dev: false + registry.npmmirror.com/@typescript-eslint/parser/5.52.0_7kw3g6rralp5ps6mg3uyzz6azm: resolution: {integrity: sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.52.0.tgz} id: registry.npmmirror.com/@typescript-eslint/parser/5.52.0 @@ -7650,6 +7787,17 @@ packages: - supports-color dev: false + registry.npmmirror.com/httpx/2.2.7: + resolution: {integrity: sha512-Wjh2JOAah0pdczfqL8NC5378G7jMt0Zcpn8U+yyxAiejjlagzSTQgJHuVvka2VNPQlKfoGehYRc79WKq9E4gDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/httpx/-/httpx-2.2.7.tgz} + name: httpx + version: 2.2.7 + dependencies: + '@types/node': registry.npmmirror.com/@types/node/14.18.42 + debug: registry.npmmirror.com/debug/4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + registry.npmmirror.com/human-signals/3.0.1: resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/human-signals/-/human-signals-3.0.1.tgz} name: human-signals @@ -8284,6 +8432,14 @@ packages: commander: registry.npmmirror.com/commander/8.3.0 dev: false + registry.npmmirror.com/kitx/2.1.0: + resolution: {integrity: sha512-C/5v9MtIX7aHGOjwn5BmrrbNkJSf7i0R5mRzmh13GSAdRqQ7bYQo/Su2pTYNylFicqKNTVX3HML9k1u8k51+pQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/kitx/-/kitx-2.1.0.tgz} + name: kitx + version: 2.1.0 + dependencies: + '@types/node': registry.npmmirror.com/@types/node/12.20.55 + dev: false + registry.npmmirror.com/kleur/4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz} name: kleur @@ -10598,6 +10754,12 @@ packages: is-fullwidth-code-point: registry.npmmirror.com/is-fullwidth-code-point/4.0.0 dev: true + registry.npmmirror.com/sm3/1.0.3: + resolution: {integrity: sha512-KyFkIfr8QBlFG3uc3NaljaXdYcsbRy1KrSfc4tsQV8jW68jAktGeOcifu530Vx/5LC+PULHT0Rv8LiI8Gw+c1g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sm3/-/sm3-1.0.3.tgz} + name: sm3 + version: 1.0.3 + dev: false + registry.npmmirror.com/smart-buffer/4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz} name: smart-buffer @@ -11618,6 +11780,16 @@ packages: - supports-color dev: false + registry.npmmirror.com/xml2js/0.4.23: + resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xml2js/-/xml2js-0.4.23.tgz} + name: xml2js + version: 0.4.23 + engines: {node: '>=4.0.0'} + dependencies: + sax: registry.npmmirror.com/sax/1.1.6 + xmlbuilder: registry.npmmirror.com/xmlbuilder/11.0.1 + dev: false + registry.npmmirror.com/xmlbuilder/10.1.1: resolution: {integrity: sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-10.1.1.tgz} name: xmlbuilder @@ -11625,6 +11797,13 @@ packages: engines: {node: '>=4.0'} dev: false + registry.npmmirror.com/xmlbuilder/11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz} + name: xmlbuilder + version: 11.0.1 + engines: {node: '>=4.0'} + dev: false + registry.npmmirror.com/xregexp/2.0.0: resolution: {integrity: sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xregexp/-/xregexp-2.0.0.tgz} name: xregexp diff --git a/public/docs/intro.md b/public/docs/intro.md index 73a9a509b..3cce2007a 100644 --- a/public/docs/intro.md +++ b/public/docs/intro.md @@ -9,7 +9,7 @@ wx号: fastgpt123 ### 快速开始 -1. 使用邮箱注册账号。 +1. 使用手机号注册账号。 2. 进入账号页面,添加关联账号,目前只有 openai 的账号可以添加,直接去 openai 官网,把 API Key 粘贴过来。 3. 如果填写了自己的 openai 账号,使用时会直接用你的账号。如果没有填写,需要付费使用平台的账号。 4. 进入模型页,创建一个模型,建议直接用 ChatGPT。 diff --git a/src/api/user.ts b/src/api/user.ts index c16310de3..bd78ddf68 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -1,50 +1,55 @@ import { GET, POST, PUT } from './request'; import { createHashPassword, Obj2Query } from '@/utils/tools'; import { ResLogin } from './response/user'; -import { EmailTypeEnum } from '@/constants/common'; +import { UserAuthTypeEnum } from '@/constants/common'; import { UserType, UserUpdateParams } from '@/types/user'; import type { PagingData, RequestPaging } from '@/types'; import { BillSchema, PaySchema } from '@/types/mongoSchema'; import { adaptBill } from '@/utils/adapt'; -export const sendCodeToEmail = ({ email, type }: { email: string; type: `${EmailTypeEnum}` }) => - GET('/user/sendEmail', { email, type }); +export const sendAuthCode = ({ + username, + type +}: { + username: string; + type: `${UserAuthTypeEnum}`; +}) => GET('/user/sendAuthCode', { username, type }); export const getTokenLogin = () => GET('/user/tokenLogin'); export const postRegister = ({ - email, + phone, password, code }: { - email: string; + phone: string; code: string; password: string; }) => POST('/user/register', { - email, + phone, code, password: createHashPassword(password) }); export const postFindPassword = ({ - email, + username, code, password }: { - email: string; + username: string; code: string; password: string; }) => POST('/user/updatePasswordByCode', { - email, + username, code, password: createHashPassword(password) }); -export const postLogin = ({ email, password }: { email: string; password: string }) => +export const postLogin = ({ username, password }: { username: string; password: string }) => POST('/user/loginByPassword', { - email, + username, password: createHashPassword(password) }); diff --git a/src/constants/common.ts b/src/constants/common.ts index 42f111be8..ae4557e4c 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -1,4 +1,4 @@ -export enum EmailTypeEnum { +export enum UserAuthTypeEnum { register = 'register', findPassword = 'findPassword' } diff --git a/src/hooks/useSendCode.ts b/src/hooks/useSendCode.ts index 71939a364..c770e7903 100644 --- a/src/hooks/useSendCode.ts +++ b/src/hooks/useSendCode.ts @@ -1,6 +1,6 @@ import { useState, useMemo, useCallback } from 'react'; -import { sendCodeToEmail } from '@/api/user'; -import { EmailTypeEnum } from '@/constants/common'; +import { sendAuthCode } from '@/api/user'; +import { UserAuthTypeEnum } from '@/constants/common'; let timer: any; import { useToast } from './useToast'; @@ -19,11 +19,11 @@ export const useSendCode = () => { }, [codeCountDown]); const sendCode = useCallback( - async ({ email, type }: { email: string; type: `${EmailTypeEnum}` }) => { + async ({ username, type }: { username: string; type: `${UserAuthTypeEnum}` }) => { setCodeSending(true); try { - await sendCodeToEmail({ - email, + await sendAuthCode({ + username, type }); setCodeCountDown(60); diff --git a/src/pages/api/user/loginByPassword.ts b/src/pages/api/user/loginByPassword.ts index f7f58959c..ffd1db911 100644 --- a/src/pages/api/user/loginByPassword.ts +++ b/src/pages/api/user/loginByPassword.ts @@ -7,24 +7,24 @@ import { generateToken } from '@/service/utils/tools'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { email, password } = req.body; + const { username, password } = req.body; - if (!email || !password) { + if (!username || !password) { throw new Error('缺少参数'); } await connectToDatabase(); - // 检测邮箱是否存在 - const authEmail = await User.findOne({ - email + // 检测用户是否存在 + const authUser = await User.findOne({ + username }); - if (!authEmail) { - throw new Error('邮箱未注册'); + if (!authUser) { + throw new Error('用户未注册'); } const user = await User.findOne({ - email, + username, password }); diff --git a/src/pages/api/user/register.ts b/src/pages/api/user/register.ts index 38554c287..c7034c028 100644 --- a/src/pages/api/user/register.ts +++ b/src/pages/api/user/register.ts @@ -5,23 +5,29 @@ import { User } from '@/service/models/user'; import { AuthCode } from '@/service/models/authCode'; import { connectToDatabase } from '@/service/mongo'; import { generateToken } from '@/service/utils/tools'; -import { EmailTypeEnum } from '@/constants/common'; +import { UserAuthTypeEnum } from '@/constants/common'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { email, code, password } = req.body; + const { phone, code, password } = req.body; - if (!email || !code || !password) { + if (!phone || !code || !password) { throw new Error('缺少参数'); } + const reg = /^1[3456789]\d{9}$/; + + if (!reg.test(phone)) { + throw new Error('手机号格式错误'); + } + await connectToDatabase(); - // 验证码校验 + // 验证码校验. 注册只接收手机号 const authCode = await AuthCode.findOne({ - email, + username: phone, code, - type: EmailTypeEnum.register, + type: UserAuthTypeEnum.register, expiredTime: { $gte: Date.now() } }); @@ -31,15 +37,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< // 重名校验 const authRepeat = await User.findOne({ - email + username: phone }); if (authRepeat) { - throw new Error('邮箱已被注册'); + throw new Error('手机号已被注册'); } const response = await User.create({ - email, + username: phone, password }); @@ -50,6 +56,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< throw new Error('获取用户信息异常'); } + // 删除验证码记录 + await AuthCode.deleteMany({ + username: phone + }); + jsonRes(res, { data: { token: generateToken(user._id), diff --git a/src/pages/api/user/sendEmail.ts b/src/pages/api/user/sendAuthCode.ts similarity index 63% rename from src/pages/api/user/sendEmail.ts rename to src/pages/api/user/sendAuthCode.ts index cc1dab09a..a79c30394 100644 --- a/src/pages/api/user/sendEmail.ts +++ b/src/pages/api/user/sendAuthCode.ts @@ -2,28 +2,27 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { AuthCode } from '@/service/models/authCode'; -import { connectToDatabase, User } from '@/service/mongo'; -import { sendCode } from '@/service/utils/sendEmail'; -import { EmailTypeEnum } from '@/constants/common'; +import { connectToDatabase } from '@/service/mongo'; +import { sendPhoneCode, sendEmailCode } from '@/service/utils/sendNote'; +import { UserAuthTypeEnum } from '@/constants/common'; +import { customAlphabet } from 'nanoid'; +const nanoid = customAlphabet('1234567890', 6); export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { email, type } = req.query as { email: string; type: `${EmailTypeEnum}` }; + const { username, type } = req.query as { username: string; type: `${UserAuthTypeEnum}` }; - if (!email || !type) { + if (!username || !type) { throw new Error('缺少参数'); } await connectToDatabase(); - let code = ''; - for (let i = 0; i < 6; i++) { - code += Math.floor(Math.random() * 10); - } + let code = nanoid(); // 判断 1 分钟内是否有重复数据 const authCode = await AuthCode.findOne({ - email, + username, type, expiredTime: { $gte: Date.now() + 4 * 60 * 1000 } // 如果有一个记录的过期时间,大于当前+4分钟,说明距离上次发送还没到1分钟。(因为默认创建时,过期时间是未来5分钟) }); @@ -34,13 +33,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) // 创建 auth 记录 await AuthCode.create({ - email, + username, type, code }); - // 发送验证码 - await sendCode(email as string, code, type as `${EmailTypeEnum}`); + if (username.includes('@')) { + await sendEmailCode(username, code, type); + } else { + // 发送验证码 + await sendPhoneCode(username, code); + } jsonRes(res, { message: '发送验证码成功' diff --git a/src/pages/api/user/updatePasswordByCode.ts b/src/pages/api/user/updatePasswordByCode.ts index ad3a2c308..fb021fa6f 100644 --- a/src/pages/api/user/updatePasswordByCode.ts +++ b/src/pages/api/user/updatePasswordByCode.ts @@ -5,13 +5,13 @@ import { User } from '@/service/models/user'; import { AuthCode } from '@/service/models/authCode'; import { connectToDatabase } from '@/service/mongo'; import { generateToken } from '@/service/utils/tools'; -import { EmailTypeEnum } from '@/constants/common'; +import { UserAuthTypeEnum } from '@/constants/common'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { email, code, password } = req.body; + const { username, code, password } = req.body; - if (!email || !code || !password) { + if (!username || !code || !password) { throw new Error('缺少参数'); } @@ -19,9 +19,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< // 验证码校验 const authCode = await AuthCode.findOne({ - email, + username, code, - type: EmailTypeEnum.findPassword, + type: UserAuthTypeEnum.findPassword, expiredTime: { $gte: Date.now() } }); @@ -32,16 +32,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< // 更新对应的记录 await User.updateOne( { - email + username }, { password } ); - // 根据 email 获取用户信息 + // 根据 username 获取用户信息 const user = await User.findOne({ - email + username }); if (!user) { diff --git a/src/pages/login/components/ForgetPasswordForm.tsx b/src/pages/login/components/ForgetPasswordForm.tsx index 31d2fd32a..38ab71474 100644 --- a/src/pages/login/components/ForgetPasswordForm.tsx +++ b/src/pages/login/components/ForgetPasswordForm.tsx @@ -14,7 +14,7 @@ interface Props { } interface RegisterType { - email: string; + username: string; code: string; password: string; password2: string; @@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode(); const onclickSendCode = useCallback(async () => { - const check = await trigger('email'); + const check = await trigger('username'); if (!check) return; sendCode({ - email: getValues('email'), + username: getValues('username'), type: 'findPassword' }); }, [getValues, sendCode, trigger]); @@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { const [requesting, setRequesting] = useState(false); const onclickFindPassword = useCallback( - async ({ email, code, password }: RegisterType) => { + async ({ username, code, password }: RegisterType) => { setRequesting(true); try { loginSuccess( await postFindPassword({ - email, + username, code, password }) @@ -78,23 +78,24 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { 找回 FastGPT 账号
- + - {!!errors.email && errors.email.message} + {!!errors.username && errors.username.message} - + { const [requesting, setRequesting] = useState(false); const onclickLogin = useCallback( - async ({ email, password }: LoginFormType) => { + async ({ username, password }: LoginFormType) => { setRequesting(true); try { loginSuccess( await postLogin({ - email, + username, password }) ); @@ -59,20 +59,21 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { 登录 FastGPT - + - {!!errors.email && errors.email.message} + {!!errors.username && errors.username.message} diff --git a/src/pages/login/components/RegisterForm.tsx b/src/pages/login/components/RegisterForm.tsx index aec2cdc61..e98aa185c 100644 --- a/src/pages/login/components/RegisterForm.tsx +++ b/src/pages/login/components/RegisterForm.tsx @@ -14,7 +14,7 @@ interface Props { } interface RegisterType { - email: string; + phone: string; password: string; password2: string; code: string; @@ -36,10 +36,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { const { codeSending, sendCodeText, sendCode, codeCountDown } = useSendCode(); const onclickSendCode = useCallback(async () => { - const check = await trigger('email'); + const check = await trigger('phone'); if (!check) return; sendCode({ - email: getValues('email'), + username: getValues('phone'), type: 'register' }); }, [getValues, sendCode, trigger]); @@ -47,12 +47,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { const [requesting, setRequesting] = useState(false); const onclickRegister = useCallback( - async ({ email, password, code }: RegisterType) => { + async ({ phone, password, code }: RegisterType) => { setRequesting(true); try { loginSuccess( await postRegister({ - email, + phone, code, password }) @@ -78,23 +78,23 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { 注册 FastGPT 账号 - + - {!!errors.email && errors.email.message} + {!!errors.phone && errors.phone.message} - + { 账号信息 - 邮箱: - {userInfo?.email} + 用户账号: + {userInfo?.username} diff --git a/src/service/models/authCode.ts b/src/service/models/authCode.ts index fb73f60e4..3b1a3c423 100644 --- a/src/service/models/authCode.ts +++ b/src/service/models/authCode.ts @@ -2,7 +2,7 @@ import { Schema, model, models, Model } from 'mongoose'; import { AuthCodeSchema as AuthCodeType } from '@/types/mongoSchema'; const AuthCodeSchema = new Schema({ - email: { + username: { type: String, required: true }, diff --git a/src/service/models/user.ts b/src/service/models/user.ts index 70351e3df..f0b345ec8 100644 --- a/src/service/models/user.ts +++ b/src/service/models/user.ts @@ -3,7 +3,8 @@ import { hashPassword } from '@/service/utils/tools'; import { PRICE_SCALE } from '@/constants/common'; import { UserModelSchema } from '@/types/mongoSchema'; const UserSchema = new Schema({ - email: { + username: { + // 可以是手机/邮箱,新的验证都只用手机 type: String, required: true, unique: true // 唯一 diff --git a/src/service/utils/sendEmail.ts b/src/service/utils/sendEmail.ts deleted file mode 100644 index f0fb5aad9..000000000 --- a/src/service/utils/sendEmail.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as nodemailer from 'nodemailer'; -import { EmailTypeEnum } from '@/constants/common'; -import dayjs from 'dayjs'; - -const myEmail = process.env.MY_MAIL; -let mailTransport = nodemailer.createTransport({ - // host: 'smtp.qq.email', - service: 'qq', - secure: true, //安全方式发送,建议都加上 - auth: { - user: myEmail, - pass: process.env.MAILE_CODE - } -}); - -const emailMap: { [key: string]: any } = { - [EmailTypeEnum.register]: { - subject: '注册 FastGPT 账号', - html: (code: string) => `
您正在注册 FastGPT 账号,验证码为:${code}
` - }, - [EmailTypeEnum.findPassword]: { - subject: '修改 FastGPT 密码', - html: (code: string) => `
您正在修改 FastGPT 账号密码,验证码为:${code}
` - } -}; - -export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`) => { - return new Promise((resolve, reject) => { - const options = { - from: `"FastGPT" ${myEmail}`, - to: email, - subject: emailMap[type]?.subject, - html: emailMap[type]?.html(code) - }; - mailTransport.sendMail(options, function (err, msg) { - if (err) { - console.log('send email error->', err); - reject('邮箱异常'); - } else { - resolve(''); - } - }); - }); -}; - -export const sendTrainSucceed = (email: string, modelName: string) => { - return new Promise((resolve, reject) => { - const options = { - from: `"FastGPT" ${myEmail}`, - to: email, - subject: '模型训练完成通知', - html: `你的模型 ${modelName} 已于 ${dayjs().format('YYYY-MM-DD HH:mm')} 训练完成!` - }; - mailTransport.sendMail(options, function (err, msg) { - if (err) { - console.log('send email error->', err); - reject('邮箱异常'); - } else { - resolve(''); - } - }); - }); -}; diff --git a/src/service/utils/sendNote.ts b/src/service/utils/sendNote.ts new file mode 100644 index 000000000..4ef222c3c --- /dev/null +++ b/src/service/utils/sendNote.ts @@ -0,0 +1,72 @@ +import * as nodemailer from 'nodemailer'; +import { UserAuthTypeEnum } from '@/constants/common'; +import dayjs from 'dayjs'; +import Dysmsapi, * as dysmsapi from '@alicloud/dysmsapi20170525'; +// @ts-ignore +import * as OpenApi from '@alicloud/openapi-client'; +// @ts-ignore +import * as Util from '@alicloud/tea-util'; + +const myEmail = process.env.MY_MAIL; +const mailTransport = nodemailer.createTransport({ + // host: 'smtp.qq.phone', + service: 'qq', + secure: true, //安全方式发送,建议都加上 + auth: { + user: myEmail, + pass: process.env.MAILE_CODE + } +}); + +const emailMap: { [key: string]: any } = { + [UserAuthTypeEnum.register]: { + subject: '注册 FastGPT 账号', + html: (code: string) => `
您正在注册 FastGPT 账号,验证码为:${code}
` + }, + [UserAuthTypeEnum.findPassword]: { + subject: '修改 FastGPT 密码', + html: (code: string) => `
您正在修改 FastGPT 账号密码,验证码为:${code}
` + } +}; + +export const sendEmailCode = (email: string, code: string, type: `${UserAuthTypeEnum}`) => { + return new Promise((resolve, reject) => { + const options = { + from: `"FastGPT" ${myEmail}`, + to: email, + subject: emailMap[type]?.subject, + html: emailMap[type]?.html(code) + }; + mailTransport.sendMail(options, function (err, msg) { + if (err) { + console.log('send email error->', err); + reject('发生邮件异常'); + } else { + resolve(''); + } + }); + }); +}; + +export const sendPhoneCode = async (phone: string, code: string) => { + const accessKeyId = process.env.aliAccessKeyId; + const accessKeySecret = process.env.aliAccessKeySecret; + const signName = process.env.aliSignName; + const templateCode = process.env.aliTemplateCode; + const endpoint = 'dysmsapi.aliyuncs.com'; + + const sendSmsRequest = new dysmsapi.SendSmsRequest({ + phoneNumbers: phone, + signName, + templateCode, + templateParam: `{"code":${code}}` + }); + + const config = new OpenApi.Config({ accessKeyId, accessKeySecret, endpoint }); + const client = new Dysmsapi(config); + const runtime = new Util.RuntimeOptions({}); + const res = await client.sendSmsWithOptions(sendSmsRequest, runtime); + if (res.body.code !== 'OK') { + return Promise.reject(res.body.message || '发送短信失败'); + } +}; diff --git a/src/types/mongoSchema.d.ts b/src/types/mongoSchema.d.ts index 0f141ca34..6c049a7ff 100644 --- a/src/types/mongoSchema.d.ts +++ b/src/types/mongoSchema.d.ts @@ -11,7 +11,7 @@ export type ServiceName = 'openai'; export interface UserModelSchema { _id: string; - email: string; + username: string; password: string; balance: number; openaiKey: string; @@ -20,7 +20,7 @@ export interface UserModelSchema { export interface AuthCodeSchema { _id: string; - email: string; + username: string; code: string; type: 'register' | 'findPassword'; expiredTime: number; diff --git a/src/types/user.d.ts b/src/types/user.d.ts index 9684e9c81..a17df20b3 100644 --- a/src/types/user.d.ts +++ b/src/types/user.d.ts @@ -1,11 +1,6 @@ -export enum UserNumberEnum { - phone = 'phone', - wx = 'wx' -} - export interface UserType { _id: string; - email: string; + username: string; openaiKey: string; balance: number; }