diff --git a/makefile b/makefile index 603f5aa..1e8ab1b 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ FRONTEND_DIR = ./web BACKEND_DIR = . -.PHONY: all start-frontend start-backend +.PHONY: all build-frontend start-backend all: start-frontend start-backend @@ -9,12 +9,6 @@ build-frontend: @echo "Building frontend..." @cd $(FRONTEND_DIR) && npm install && DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat VERSION) npm run build npm run build -# 启动前端开发服务器 -start-frontend: - @echo "Starting frontend dev server..." - @cd $(FRONTEND_DIR) && npm start & - -# 启动后端开发服务器 start-backend: @echo "Starting backend dev server..." @cd $(BACKEND_DIR) && go run main.go & diff --git a/model/user.go b/model/user.go index 3e727a0..7b70bfe 100644 --- a/model/user.go +++ b/model/user.go @@ -3,10 +3,11 @@ package model import ( "errors" "fmt" - "gorm.io/gorm" "one-api/common" "strings" "time" + + "gorm.io/gorm" ) // User if you add sensitive fields, don't forget to clean them in setupLogin function. @@ -21,6 +22,7 @@ type User struct { Email string `json:"email" gorm:"index" validate:"max=50"` GitHubId string `json:"github_id" gorm:"column:github_id;index"` WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` + TelegramId string `json:"telegram_id" gorm:"column:telegram_id;index"` VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! AccessToken string `json:"access_token" gorm:"type:char(32);column:access_token;uniqueIndex"` // this token is for system management Quota int `json:"quota" gorm:"type:int;default:0"` diff --git a/web/src/components/LoginForm.js b/web/src/components/LoginForm.js index 03aec65..ec49ece 100644 --- a/web/src/components/LoginForm.js +++ b/web/src/components/LoginForm.js @@ -1,14 +1,14 @@ -import React, {useContext, useEffect, useState} from 'react'; -import {Link, useNavigate, useSearchParams} from 'react-router-dom'; -import {UserContext} from '../context/User'; -import {API, getLogo, isMobile, showError, showInfo, showSuccess, showWarning} from '../helpers'; -import {onGitHubOAuthClicked} from './utils'; +import React, { useContext, useEffect, useState } from 'react'; +import { Link, useNavigate, useSearchParams } from 'react-router-dom'; +import { UserContext } from '../context/User'; +import { API, getLogo, isMobile, showError, showInfo, showSuccess, showWarning } from '../helpers'; +import { onGitHubOAuthClicked } from './utils'; import Turnstile from "react-turnstile"; -import {Layout, Card, Image, Form, Button, Divider, Modal} from "@douyinfe/semi-ui"; +import { Layout, Card, Image, Form, Button, Divider, Modal } from "@douyinfe/semi-ui"; import Title from "@douyinfe/semi-ui/lib/es/typography/title"; import Text from "@douyinfe/semi-ui/lib/es/typography/text"; -import {IconGithubLogo} from '@douyinfe/semi-icons'; +import { IconGithubLogo } from '@douyinfe/semi-icons'; const LoginForm = () => { const [inputs, setInputs] = useState({ @@ -18,7 +18,7 @@ const LoginForm = () => { }); const [searchParams, setSearchParams] = useSearchParams(); const [submitted, setSubmitted] = useState(false); - const {username, password} = inputs; + const { username, password } = inputs; const [userState, userDispatch] = useContext(UserContext); const [turnstileEnabled, setTurnstileEnabled] = useState(false); const [turnstileSiteKey, setTurnstileSiteKey] = useState(''); @@ -56,9 +56,9 @@ const LoginForm = () => { const res = await API.get( `/api/oauth/wechat?code=${inputs.wechat_verification_code}` ); - const {success, message, data} = res.data; + const { success, message, data } = res.data; if (success) { - userDispatch({type: 'login', payload: data}); + userDispatch({ type: 'login', payload: data }); localStorage.setItem('user', JSON.stringify(data)); navigate('/'); showSuccess('登录成功!'); @@ -69,7 +69,7 @@ const LoginForm = () => { }; function handleChange(name, value) { - setInputs((inputs) => ({...inputs, [name]: value})); + setInputs((inputs) => ({ ...inputs, [name]: value })); } async function handleSubmit(e) { @@ -83,13 +83,13 @@ const LoginForm = () => { username, password }); - const {success, message, data} = res.data; + const { success, message, data } = res.data; if (success) { - userDispatch({type: 'login', payload: data}); + userDispatch({ type: 'login', payload: data }); localStorage.setItem('user', JSON.stringify(data)); showSuccess('登录成功!'); if (username === 'root' && password === '123456') { - Modal.error({title: '您正在使用默认密码!', content: '请立刻修改默认密码!', centered: true}); + Modal.error({ title: '您正在使用默认密码!', content: '请立刻修改默认密码!', centered: true }); } navigate('/token'); } else { @@ -100,16 +100,23 @@ const LoginForm = () => { } } + // 添加Telegram登录处理函数 + const onTelegramLoginClicked = async () => { + // 这里调用后端API进行Telegram登录 + // 例如: const res = await API.get(`/api/oauth/telegram`); + // 根据响应处理登录逻辑 + }; + return (
-
-
+
+
- + <Title heading={2} style={{ textAlign: 'center' }}> 用户登录
@@ -129,12 +136,12 @@ const LoginForm = () => { onChange={(value) => handleChange('password', value)} /> -
-
+
没有账号请先 注册账号 @@ -142,16 +149,16 @@ const LoginForm = () => { 忘记密码 点击重置
- {status.github_oauth || status.wechat_login ? ( + {status.github_oauth || status.wechat_login || status.telegram_oauth ? ( <> 第三方登录 -
+
{status.github_oauth ? ( + ) : ( + <> + )}
) : ( @@ -208,7 +227,7 @@ const LoginForm = () => { {/**/} {turnstileEnabled ? ( -
+
{ diff --git a/web/src/components/PersonalSetting.js b/web/src/components/PersonalSetting.js index 78d3240..3c67a3f 100644 --- a/web/src/components/PersonalSetting.js +++ b/web/src/components/PersonalSetting.js @@ -443,6 +443,27 @@ const PersonalSetting = () => {
+
+ Telegram +
+
+ +
+
+ +
+
+
+
diff --git a/web/src/components/SystemSetting.js b/web/src/components/SystemSetting.js index f5d87be..436cc67 100644 --- a/web/src/components/SystemSetting.js +++ b/web/src/components/SystemSetting.js @@ -34,7 +34,7 @@ const SystemSetting = () => { EmailDomainRestrictionEnabled: '', EmailDomainWhitelist: '', // telegram login - TelegramLoginEnabled: '', + TelegramOAuthEnabled: '', TelegramBotToken: '', TelegramBotName: '', }); @@ -81,7 +81,7 @@ const SystemSetting = () => { case 'EmailVerificationEnabled': case 'GitHubOAuthEnabled': case 'WeChatAuthEnabled': - case 'TelegramLoginEnabled': + case 'TelegramOAuthEnabled': case 'TurnstileCheckEnabled': case 'EmailDomainRestrictionEnabled': case 'RegisterEnabled': @@ -240,7 +240,7 @@ const SystemSetting = () => { }; const submitTelegramSettings = async () => { - await updateOption('TelegramLoginEnabled', inputs.TelegramLoginEnabled); + await updateOption('TelegramOAuthEnabled', inputs.TelegramOAuthEnabled); await updateOption('TelegramBotToken', inputs.TelegramBotToken); await updateOption('TelegramBotName', inputs.TelegramBotName); }; @@ -397,6 +397,12 @@ const SystemSetting = () => { name='WeChatAuthEnabled' onChange={handleInputChange} /> + {
配置 Telegram 登录
- diff --git a/web/src/pages/User/EditUser.js b/web/src/pages/User/EditUser.js index 705f7a2..6d79127 100644 --- a/web/src/pages/User/EditUser.js +++ b/web/src/pages/User/EditUser.js @@ -1,9 +1,9 @@ import React, { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import {API, isMobile, showError, showSuccess} from '../../helpers'; +import { API, isMobile, showError, showSuccess } from '../../helpers'; import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render'; import Title from "@douyinfe/semi-ui/lib/es/typography/title"; -import {SideSheet, Space, Button, Spin, Input, Typography, Select, Divider} from "@douyinfe/semi-ui"; +import { SideSheet, Space, Button, Spin, Input, Typography, Select, Divider } from "@douyinfe/semi-ui"; const EditUser = (props) => { const userId = props.editingUser.id; @@ -19,8 +19,8 @@ const EditUser = (props) => { group: 'default' }); const [groupOptions, setGroupOptions] = useState([]); - const { username, display_name, password, github_id, wechat_id, email, quota, group } = - inputs; + const { username, display_name, password, github_id, wechat_id, telegram_id, email, quota, group } = + inputs; const handleInputChange = (name, value) => { setInputs((inputs) => ({ ...inputs, [name]: value })); }; @@ -88,126 +88,132 @@ const EditUser = (props) => { }; return ( - <> - {'编辑用户'}} - headerStyle={{borderBottom: '1px solid var(--semi-color-border)'}} - bodyStyle={{borderBottom: '1px solid var(--semi-color-border)'}} - visible={props.visible} - footer={ -
- - - - + <> + {'编辑用户'}} + headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }} + bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }} + visible={props.visible} + footer={ +
+ + + + +
+ } + closeIcon={null} + onCancel={() => handleCancel()} + width={isMobile() ? '100%' : 600} + > + +
+ 用户名 +
+ handleInputChange('username', value)} + value={username} + autoComplete='new-password' + /> +
+ 密码 +
+ handleInputChange('password', value)} + value={password} + autoComplete='new-password' + /> +
+ 显示名称 +
+ handleInputChange('display_name', value)} + value={display_name} + autoComplete='new-password' + /> + { + userId && <> +
+ 分组
- } - closeIcon={null} - onCancel={() => handleCancel()} - width={isMobile() ? '100%' : 600} - > - -
- 用户名 -
- handleInputChange('username', value)} - value={username} + handleInputChange('password', value)} - value={password} + optionList={groupOptions} + /> +
+ {`剩余额度${renderQuotaWithPrompt(quota)}`} +
+ handleInputChange('quota', value)} + value={quota} + type={'number'} autoComplete='new-password' - /> -
- 显示名称 -
- handleInputChange('display_name', value)} - value={display_name} - autoComplete='new-password' - /> - { - userId && <> -
- 分组 -
- handleInputChange('quota', value)} - value={quota} - type={'number'} - autoComplete='new-password' - /> - - } - 以下信息不可修改 -
- 已绑定的 GitHub 账户 -
- -
- 已绑定的微信账户 -
- -
- 已绑定的邮箱账户 -
- -
- -
- + /> + + } + 以下信息不可修改 +
+ 已绑定的 GitHub 账户 +
+ +
+ 已绑定的微信账户 +
+ + +
+ 已绑定的邮箱账户 +
+ + + + ); };