mirror of
				https://github.com/songquanpeng/one-api.git
				synced 2025-11-04 15:53:42 +08:00 
			
		
		
		
	feat: i18n support
This commit is contained in:
		@@ -429,5 +429,173 @@
 | 
			
		||||
        "value": "Value"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "setting": {
 | 
			
		||||
    "title": "System Settings",
 | 
			
		||||
    "tabs": {
 | 
			
		||||
      "personal": "Personal Settings",
 | 
			
		||||
      "operation": "Operation Settings", 
 | 
			
		||||
      "system": "System Settings",
 | 
			
		||||
      "other": "Other Settings"
 | 
			
		||||
    },
 | 
			
		||||
    "personal": {
 | 
			
		||||
      "general": {
 | 
			
		||||
        "title": "General Settings",
 | 
			
		||||
        "system_token_notice": "Note: The token generated here is for system management, not for requesting OpenAI related services.",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "update_profile": "Update Profile",
 | 
			
		||||
          "generate_token": "Generate System Token",
 | 
			
		||||
          "copy_invite": "Copy Invite Link",
 | 
			
		||||
          "delete_account": "Delete Account"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "binding": {
 | 
			
		||||
        "title": "Account Binding",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "bind_wechat": "Bind WeChat Account",
 | 
			
		||||
          "bind_github": "Bind GitHub Account",
 | 
			
		||||
          "bind_email": "Bind Email Address",
 | 
			
		||||
          "bind_lark": "Bind Lark Account"
 | 
			
		||||
        },
 | 
			
		||||
        "wechat": {
 | 
			
		||||
          "title": "WeChat Binding",
 | 
			
		||||
          "description": "Scan QR code to follow the official account, enter 'verification code' to get the code (valid for 3 minutes)",
 | 
			
		||||
          "verification_code": "Verification Code",
 | 
			
		||||
          "bind": "Bind"
 | 
			
		||||
        },
 | 
			
		||||
        "email": {
 | 
			
		||||
          "title": "Bind Email Address",
 | 
			
		||||
          "email_placeholder": "Enter email address",
 | 
			
		||||
          "code_placeholder": "Verification code",
 | 
			
		||||
          "get_code": "Get Code",
 | 
			
		||||
          "get_code_retry": "Resend({{countdown}})",
 | 
			
		||||
          "bind": "Confirm Binding",
 | 
			
		||||
          "cancel": "Cancel"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "delete_account": {
 | 
			
		||||
        "title": "Dangerous Operation",
 | 
			
		||||
        "warning": "You are deleting your account. All data will be cleared and cannot be recovered",
 | 
			
		||||
        "confirm_placeholder": "Enter your username {{username}} to confirm deletion",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "confirm": "Confirm Delete",
 | 
			
		||||
          "cancel": "Cancel"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "system": {
 | 
			
		||||
      "general": {
 | 
			
		||||
        "title": "General Settings",
 | 
			
		||||
        "server_address": "Server Address",
 | 
			
		||||
        "server_address_placeholder": "e.g.: https://yourdomain.com",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "update": "Update Server Address"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "login": {
 | 
			
		||||
        "title": "Login & Registration Settings",
 | 
			
		||||
        "password_login": "Allow Password Login",
 | 
			
		||||
        "password_register": "Allow Password Registration",
 | 
			
		||||
        "email_verification": "Require Email Verification for Password Registration",
 | 
			
		||||
        "github_oauth": "Allow GitHub OAuth Login & Registration",
 | 
			
		||||
        "wechat_login": "Allow WeChat Login & Registration",
 | 
			
		||||
        "registration": "Allow New User Registration (When disabled, new users cannot register by any means)",
 | 
			
		||||
        "turnstile": "Enable Turnstile User Verification"
 | 
			
		||||
      },
 | 
			
		||||
      "email_restriction": {
 | 
			
		||||
        "title": "Email Domain Whitelist",
 | 
			
		||||
        "subtitle": "Used to prevent malicious users from batch registering using temporary emails",
 | 
			
		||||
        "enable": "Enable Email Domain Whitelist",
 | 
			
		||||
        "allowed_domains": "Allowed Email Domains",
 | 
			
		||||
        "add_domain": "Add New Allowed Email Domain",
 | 
			
		||||
        "add_domain_placeholder": "Enter new allowed email domain",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "fill": "Fill",
 | 
			
		||||
          "save": "Save Email Domain Whitelist Settings"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "smtp": {
 | 
			
		||||
        "title": "SMTP Configuration",
 | 
			
		||||
        "subtitle": "Used to support system email sending",
 | 
			
		||||
        "server": "SMTP Server Address",
 | 
			
		||||
        "server_placeholder": "e.g.: smtp.gmail.com",
 | 
			
		||||
        "port": "SMTP Port",
 | 
			
		||||
        "port_placeholder": "Default: 587",
 | 
			
		||||
        "account": "SMTP Account",
 | 
			
		||||
        "account_placeholder": "Usually your email address",
 | 
			
		||||
        "from": "SMTP Sender Email",
 | 
			
		||||
        "from_placeholder": "Usually same as email address",
 | 
			
		||||
        "token": "SMTP Access Token",
 | 
			
		||||
        "token_placeholder": "Sensitive information will not be sent to frontend",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "Save SMTP Settings"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "github": {
 | 
			
		||||
        "title": "GitHub OAuth App Configuration",
 | 
			
		||||
        "subtitle": "Used to support GitHub login and registration",
 | 
			
		||||
        "manage_link": "Click here",
 | 
			
		||||
        "manage_text": "to manage your GitHub OAuth Apps",
 | 
			
		||||
        "url_notice": "Set Homepage URL to {{server_url}}, and Authorization callback URL to {{callback_url}}",
 | 
			
		||||
        "client_id": "GitHub Client ID",
 | 
			
		||||
        "client_id_placeholder": "Enter your registered GitHub OAuth APP ID",
 | 
			
		||||
        "client_secret": "GitHub Client Secret",
 | 
			
		||||
        "client_secret_placeholder": "Sensitive information will not be sent to frontend",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "Save GitHub OAuth Settings"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "lark": {
 | 
			
		||||
        "title": "Lark OAuth Configuration",
 | 
			
		||||
        "subtitle": "Used to support Lark login and registration",
 | 
			
		||||
        "manage_link": "Click here",
 | 
			
		||||
        "manage_text": "to manage your Lark applications",
 | 
			
		||||
        "url_notice": "Set Homepage URL to {{server_url}}, and Redirect URL to {{callback_url}}",
 | 
			
		||||
        "client_id": "App ID",
 | 
			
		||||
        "client_id_placeholder": "Enter App ID",
 | 
			
		||||
        "client_secret": "App Secret",
 | 
			
		||||
        "client_secret_placeholder": "Sensitive information will not be sent to frontend",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "Save Lark OAuth Settings"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "wechat": {
 | 
			
		||||
        "title": "WeChat Server Configuration",
 | 
			
		||||
        "subtitle": "Used to support WeChat login and registration",
 | 
			
		||||
        "learn_more": "Learn about WeChat Server",
 | 
			
		||||
        "server_address": "WeChat Server Address",
 | 
			
		||||
        "server_address_placeholder": "e.g.: https://yourdomain.com",
 | 
			
		||||
        "token": "WeChat Server Access Token",
 | 
			
		||||
        "token_placeholder": "Sensitive information will not be sent to frontend",
 | 
			
		||||
        "qrcode": "WeChat Official Account QR Code Image URL",
 | 
			
		||||
        "qrcode_placeholder": "Enter an image URL",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "Save WeChat Server Settings"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "turnstile": {
 | 
			
		||||
        "title": "Turnstile Configuration",
 | 
			
		||||
        "subtitle": "Used to support user verification",
 | 
			
		||||
        "manage_link": "Click here",
 | 
			
		||||
        "manage_text": "to manage your Turnstile Sites, Invisible Widget Type recommended",
 | 
			
		||||
        "site_key": "Turnstile Site Key",
 | 
			
		||||
        "site_key_placeholder": "Enter your registered Turnstile Site Key",
 | 
			
		||||
        "secret_key": "Turnstile Secret Key",
 | 
			
		||||
        "secret_key_placeholder": "Sensitive information will not be sent to frontend",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "Save Turnstile Settings"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "password_login": {
 | 
			
		||||
        "warning": {
 | 
			
		||||
          "title": "Warning",
 | 
			
		||||
          "content": "Disabling password login will prevent all users (including administrators) who haven't bound other login methods from logging in via password. Confirm disable?",
 | 
			
		||||
          "buttons": {
 | 
			
		||||
            "confirm": "Confirm",
 | 
			
		||||
            "cancel": "Cancel"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -429,5 +429,173 @@
 | 
			
		||||
        "value": "数值"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "setting": {
 | 
			
		||||
    "title": "系统设置",
 | 
			
		||||
    "tabs": {
 | 
			
		||||
      "personal": "个人设置",
 | 
			
		||||
      "operation": "运营设置",
 | 
			
		||||
      "system": "系统设置",
 | 
			
		||||
      "other": "其他设置"
 | 
			
		||||
    },
 | 
			
		||||
    "personal": {
 | 
			
		||||
      "general": {
 | 
			
		||||
        "title": "通用设置",
 | 
			
		||||
        "system_token_notice": "注意,此处生成的令牌用于系统管理,而非用于请求 OpenAI 相关的服务,请知悉。",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "update_profile": "更新个人信息",
 | 
			
		||||
          "generate_token": "生成系统访问令牌",
 | 
			
		||||
          "copy_invite": "复制邀请链接",
 | 
			
		||||
          "delete_account": "删除个人账户"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "binding": {
 | 
			
		||||
        "title": "账号绑定",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "bind_wechat": "绑定微信账号",
 | 
			
		||||
          "bind_github": "绑定 GitHub 账号",
 | 
			
		||||
          "bind_email": "绑定邮箱地址",
 | 
			
		||||
          "bind_lark": "绑定飞书账号"
 | 
			
		||||
        },
 | 
			
		||||
        "wechat": {
 | 
			
		||||
          "title": "微信绑定",
 | 
			
		||||
          "description": "微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)",
 | 
			
		||||
          "verification_code": "验证码",
 | 
			
		||||
          "bind": "绑定"
 | 
			
		||||
        },
 | 
			
		||||
        "email": {
 | 
			
		||||
          "title": "绑定邮箱地址",
 | 
			
		||||
          "email_placeholder": "输入邮箱地址",
 | 
			
		||||
          "code_placeholder": "验证码",
 | 
			
		||||
          "get_code": "获取验证码",
 | 
			
		||||
          "get_code_retry": "重新发送({{countdown}})",
 | 
			
		||||
          "bind": "确认绑定",
 | 
			
		||||
          "cancel": "取消"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "delete_account": {
 | 
			
		||||
        "title": "危险操作",
 | 
			
		||||
        "warning": "您正在删除自己的帐户,将清空所有数据且不可恢复",
 | 
			
		||||
        "confirm_placeholder": "输入你的账户名 {{username}} 以确认删除",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "confirm": "确认删除",
 | 
			
		||||
          "cancel": "取消"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "system": {
 | 
			
		||||
      "general": {
 | 
			
		||||
        "title": "通用设置",
 | 
			
		||||
        "server_address": "服务器地址",
 | 
			
		||||
        "server_address_placeholder": "例如:https://yourdomain.com",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "update": "更新服务器地址"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "login": {
 | 
			
		||||
        "title": "配置登录注册",
 | 
			
		||||
        "password_login": "允许通过密码进行登录",
 | 
			
		||||
        "password_register": "允许通过密码进行注册",
 | 
			
		||||
        "email_verification": "通过密码注册时需要进行邮箱验证",
 | 
			
		||||
        "github_oauth": "允许通过 GitHub 账户登录 & 注册",
 | 
			
		||||
        "wechat_login": "允许通过微信登录 & 注册",
 | 
			
		||||
        "registration": "允许新用户注册(此项为否时,新用户将无法以任何方式进行注册)",
 | 
			
		||||
        "turnstile": "启用 Turnstile 用户校验"
 | 
			
		||||
      },
 | 
			
		||||
      "email_restriction": {
 | 
			
		||||
        "title": "配置邮箱域名白名单",
 | 
			
		||||
        "subtitle": "用以防止恶意用户利用临时邮箱批量注册",
 | 
			
		||||
        "enable": "启用邮箱域名白名单",
 | 
			
		||||
        "allowed_domains": "允许的邮箱域名",
 | 
			
		||||
        "add_domain": "添加新的允许的邮箱域名",
 | 
			
		||||
        "add_domain_placeholder": "输入新的允许的邮箱域名",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "fill": "填入",
 | 
			
		||||
          "save": "保存邮箱域名白名单设置"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "smtp": {
 | 
			
		||||
        "title": "配置 SMTP",
 | 
			
		||||
        "subtitle": "用以支持系统的邮件发送",
 | 
			
		||||
        "server": "SMTP 服务器地址",
 | 
			
		||||
        "server_placeholder": "例如:smtp.qq.com",
 | 
			
		||||
        "port": "SMTP 端口",
 | 
			
		||||
        "port_placeholder": "默认: 587",
 | 
			
		||||
        "account": "SMTP 账户",
 | 
			
		||||
        "account_placeholder": "通常是邮箱地址",
 | 
			
		||||
        "from": "SMTP 发送者邮箱",
 | 
			
		||||
        "from_placeholder": "通常和邮箱地址保持一致",
 | 
			
		||||
        "token": "SMTP 访问凭证",
 | 
			
		||||
        "token_placeholder": "敏感信息不会发送到前端显示",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "保存 SMTP 设置"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "github": {
 | 
			
		||||
        "title": "配置 GitHub OAuth App",
 | 
			
		||||
        "subtitle": "用以支持通过 GitHub 进行登录注册",
 | 
			
		||||
        "manage_link": "点击此处",
 | 
			
		||||
        "manage_text": "管理你的 GitHub OAuth App",
 | 
			
		||||
        "url_notice": "Homepage URL 填 {{server_url}},Authorization callback URL 填 {{callback_url}}",
 | 
			
		||||
        "client_id": "GitHub Client ID",
 | 
			
		||||
        "client_id_placeholder": "输入你注册的 GitHub OAuth APP 的 ID",
 | 
			
		||||
        "client_secret": "GitHub Client Secret",
 | 
			
		||||
        "client_secret_placeholder": "敏感信息不会发送到前端显示",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "保存 GitHub OAuth 设置"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "lark": {
 | 
			
		||||
        "title": "配置飞书授权登录",
 | 
			
		||||
        "subtitle": "用以支持通过飞书进行登录注册",
 | 
			
		||||
        "manage_link": "点击此处",
 | 
			
		||||
        "manage_text": "管理你的飞书应用",
 | 
			
		||||
        "url_notice": "主页链接填 {{server_url}},重定向 URL 填 {{callback_url}}",
 | 
			
		||||
        "client_id": "App ID",
 | 
			
		||||
        "client_id_placeholder": "输入 App ID",
 | 
			
		||||
        "client_secret": "App Secret",
 | 
			
		||||
        "client_secret_placeholder": "敏感信息不会发送到前端显示",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "保存飞书 OAuth 设置"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "wechat": {
 | 
			
		||||
        "title": "配置 WeChat Server",
 | 
			
		||||
        "subtitle": "用以支持通过微信进行登录注册",
 | 
			
		||||
        "learn_more": "了解 WeChat Server",
 | 
			
		||||
        "server_address": "WeChat Server 服务器地址",
 | 
			
		||||
        "server_address_placeholder": "例如:https://yourdomain.com",
 | 
			
		||||
        "token": "WeChat Server 访问凭证",
 | 
			
		||||
        "token_placeholder": "敏感信息不会发送到前端显示",
 | 
			
		||||
        "qrcode": "微信公众号二维码图片链接",
 | 
			
		||||
        "qrcode_placeholder": "输入一个图片链接",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "保存 WeChat Server 设置"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "turnstile": {
 | 
			
		||||
        "title": "配置 Turnstile",
 | 
			
		||||
        "subtitle": "用以支持用户校验",
 | 
			
		||||
        "manage_link": "点击此处",
 | 
			
		||||
        "manage_text": "管理你的 Turnstile Sites,推荐选择 Invisible Widget Type",
 | 
			
		||||
        "site_key": "Turnstile Site Key",
 | 
			
		||||
        "site_key_placeholder": "输入你注册的 Turnstile Site Key",
 | 
			
		||||
        "secret_key": "Turnstile Secret Key",
 | 
			
		||||
        "secret_key_placeholder": "敏感信息不会发送到前端显示",
 | 
			
		||||
        "buttons": {
 | 
			
		||||
          "save": "保存 Turnstile 设置"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "password_login": {
 | 
			
		||||
        "warning": {
 | 
			
		||||
          "title": "警告",
 | 
			
		||||
          "content": "取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?",
 | 
			
		||||
          "buttons": {
 | 
			
		||||
            "confirm": "确定",
 | 
			
		||||
            "cancel": "取消"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import React, { useContext, useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Button, Divider, Form, Header, Image, Message, Modal } from 'semantic-ui-react';
 | 
			
		||||
import { Link, useNavigate } from 'react-router-dom';
 | 
			
		||||
import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers';
 | 
			
		||||
@@ -7,6 +8,7 @@ import { UserContext } from '../context/User';
 | 
			
		||||
import { onGitHubOAuthClicked, onLarkOAuthClicked } from './utils';
 | 
			
		||||
 | 
			
		||||
const PersonalSetting = () => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const [userState, userDispatch] = useContext(UserContext);
 | 
			
		||||
  let navigate = useNavigate();
 | 
			
		||||
 | 
			
		||||
@@ -169,18 +171,24 @@ const PersonalSetting = () => {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div style={{ lineHeight: '40px' }}>
 | 
			
		||||
      <Header as='h3'>通用设置</Header>
 | 
			
		||||
      <Header as='h3'>{t('setting.personal.general.title')}</Header>
 | 
			
		||||
      <Message>
 | 
			
		||||
        注意,此处生成的令牌用于系统管理,而非用于请求 OpenAI 相关的服务,请知悉。
 | 
			
		||||
        {t('setting.personal.general.system_token_notice')}
 | 
			
		||||
      </Message>
 | 
			
		||||
      <Button as={Link} to={`/user/edit/`}>
 | 
			
		||||
        更新个人信息
 | 
			
		||||
        {t('setting.personal.general.buttons.update_profile')}
 | 
			
		||||
      </Button>
 | 
			
		||||
      <Button onClick={generateAccessToken}>
 | 
			
		||||
        {t('setting.personal.general.buttons.generate_token')}
 | 
			
		||||
      </Button>
 | 
			
		||||
      <Button onClick={getAffLink}>
 | 
			
		||||
        {t('setting.personal.general.buttons.copy_invite')}
 | 
			
		||||
      </Button>
 | 
			
		||||
      <Button onClick={generateAccessToken}>生成系统访问令牌</Button>
 | 
			
		||||
      <Button onClick={getAffLink}>复制邀请链接</Button>
 | 
			
		||||
      <Button onClick={() => {
 | 
			
		||||
        setShowAccountDeleteModal(true);
 | 
			
		||||
      }}>删除个人账户</Button>
 | 
			
		||||
      }}>
 | 
			
		||||
        {t('setting.personal.general.buttons.delete_account')}
 | 
			
		||||
      </Button>
 | 
			
		||||
      
 | 
			
		||||
      {systemToken && (
 | 
			
		||||
        <Form.Input 
 | 
			
		||||
@@ -201,18 +209,12 @@ const PersonalSetting = () => {
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      <Divider />
 | 
			
		||||
      <Header as='h3'>账号绑定</Header>
 | 
			
		||||
      {
 | 
			
		||||
        status.wechat_login && (
 | 
			
		||||
          <Button
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              setShowWeChatBindModal(true);
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            绑定微信账号
 | 
			
		||||
          </Button>
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      <Header as='h3'>{t('setting.personal.binding.title')}</Header>
 | 
			
		||||
      {status.wechat_login && (
 | 
			
		||||
        <Button onClick={() => setShowWeChatBindModal(true)}>
 | 
			
		||||
          {t('setting.personal.binding.buttons.bind_wechat')}
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
      <Modal
 | 
			
		||||
        onClose={() => setShowWeChatBindModal(false)}
 | 
			
		||||
        onOpen={() => setShowWeChatBindModal(true)}
 | 
			
		||||
@@ -223,41 +225,35 @@ const PersonalSetting = () => {
 | 
			
		||||
          <Modal.Description>
 | 
			
		||||
            <Image src={status.wechat_qrcode} fluid />
 | 
			
		||||
            <div style={{ textAlign: 'center' }}>
 | 
			
		||||
              <p>
 | 
			
		||||
                微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
 | 
			
		||||
              </p>
 | 
			
		||||
              <p>{t('setting.personal.binding.wechat.description')}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <Form size='large'>
 | 
			
		||||
              <Form.Input
 | 
			
		||||
                fluid
 | 
			
		||||
                placeholder='验证码'
 | 
			
		||||
                placeholder={t('setting.personal.binding.wechat.verification_code')}
 | 
			
		||||
                name='wechat_verification_code'
 | 
			
		||||
                value={inputs.wechat_verification_code}
 | 
			
		||||
                onChange={handleInputChange}
 | 
			
		||||
              />
 | 
			
		||||
              <Button color='' fluid size='large' onClick={bindWeChat}>
 | 
			
		||||
                绑定
 | 
			
		||||
                {t('setting.personal.binding.wechat.bind')}
 | 
			
		||||
              </Button>
 | 
			
		||||
            </Form>
 | 
			
		||||
          </Modal.Description>
 | 
			
		||||
        </Modal.Content>
 | 
			
		||||
      </Modal>
 | 
			
		||||
      {
 | 
			
		||||
        status.github_oauth && (
 | 
			
		||||
          <Button onClick={()=>{onGitHubOAuthClicked(status.github_client_id)}}>绑定 GitHub 账号</Button>
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      {
 | 
			
		||||
        status.lark_client_id && (
 | 
			
		||||
          <Button onClick={()=>{onLarkOAuthClicked(status.lark_client_id)}}>绑定飞书账号</Button>
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      <Button
 | 
			
		||||
        onClick={() => {
 | 
			
		||||
          setShowEmailBindModal(true);
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        绑定邮箱地址
 | 
			
		||||
      {status.github_oauth && (
 | 
			
		||||
        <Button onClick={() => onGitHubOAuthClicked(status.github_client_id)}>
 | 
			
		||||
          {t('setting.personal.binding.buttons.bind_github')}
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
      {status.lark_client_id && (
 | 
			
		||||
        <Button onClick={() => onLarkOAuthClicked(status.lark_client_id)}>
 | 
			
		||||
          {t('setting.personal.binding.buttons.bind_lark')}
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
      <Button onClick={() => setShowEmailBindModal(true)}>
 | 
			
		||||
        {t('setting.personal.binding.buttons.bind_email')}
 | 
			
		||||
      </Button>
 | 
			
		||||
      <Modal
 | 
			
		||||
        onClose={() => setShowEmailBindModal(false)}
 | 
			
		||||
@@ -266,57 +262,57 @@ const PersonalSetting = () => {
 | 
			
		||||
        size={'tiny'}
 | 
			
		||||
        style={{ maxWidth: '450px' }}
 | 
			
		||||
      >
 | 
			
		||||
        <Modal.Header>绑定邮箱地址</Modal.Header>
 | 
			
		||||
        <Modal.Header>{t('setting.personal.binding.email.title')}</Modal.Header>
 | 
			
		||||
        <Modal.Content>
 | 
			
		||||
          <Modal.Description>
 | 
			
		||||
            <Form size='large'>
 | 
			
		||||
              <Form.Input
 | 
			
		||||
                fluid
 | 
			
		||||
                placeholder='输入邮箱地址'
 | 
			
		||||
                placeholder={t('setting.personal.binding.email.email_placeholder')}
 | 
			
		||||
                onChange={handleInputChange}
 | 
			
		||||
                name='email'
 | 
			
		||||
                type='email'
 | 
			
		||||
                action={
 | 
			
		||||
                  <Button onClick={sendVerificationCode} disabled={disableButton || loading}>
 | 
			
		||||
                    {disableButton ? `重新发送(${countdown})` : '获取验证码'}
 | 
			
		||||
                    {disableButton 
 | 
			
		||||
                      ? t('setting.personal.binding.email.get_code_retry', { countdown })
 | 
			
		||||
                      : t('setting.personal.binding.email.get_code')}
 | 
			
		||||
                  </Button>
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
              <Form.Input
 | 
			
		||||
                fluid
 | 
			
		||||
                placeholder='验证码'
 | 
			
		||||
                placeholder={t('setting.personal.binding.email.code_placeholder')}
 | 
			
		||||
                name='email_verification_code'
 | 
			
		||||
                value={inputs.email_verification_code}
 | 
			
		||||
                onChange={handleInputChange}
 | 
			
		||||
              />
 | 
			
		||||
              {turnstileEnabled ? (
 | 
			
		||||
              {turnstileEnabled && (
 | 
			
		||||
                <Turnstile
 | 
			
		||||
                  sitekey={turnstileSiteKey}
 | 
			
		||||
                  onVerify={(token) => {
 | 
			
		||||
                    setTurnstileToken(token);
 | 
			
		||||
                  }}
 | 
			
		||||
                />
 | 
			
		||||
              ) : (
 | 
			
		||||
                <></>
 | 
			
		||||
              )}
 | 
			
		||||
              <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '1rem' }}>
 | 
			
		||||
              <Button
 | 
			
		||||
                color=''
 | 
			
		||||
                fluid
 | 
			
		||||
                size='large'
 | 
			
		||||
                onClick={bindEmail}
 | 
			
		||||
                loading={loading}
 | 
			
		||||
              >
 | 
			
		||||
                确认绑定
 | 
			
		||||
              </Button>
 | 
			
		||||
              <div style={{ width: '1rem' }}></div> 
 | 
			
		||||
              <Button
 | 
			
		||||
                fluid
 | 
			
		||||
                size='large'
 | 
			
		||||
                onClick={() => setShowEmailBindModal(false)}
 | 
			
		||||
              >
 | 
			
		||||
                取消
 | 
			
		||||
              </Button>
 | 
			
		||||
                <Button
 | 
			
		||||
                  color=''
 | 
			
		||||
                  fluid
 | 
			
		||||
                  size='large'
 | 
			
		||||
                  onClick={bindEmail}
 | 
			
		||||
                  loading={loading}
 | 
			
		||||
                >
 | 
			
		||||
                  {t('setting.personal.binding.email.bind')}
 | 
			
		||||
                </Button>
 | 
			
		||||
                <div style={{ width: '1rem' }}></div>
 | 
			
		||||
                <Button
 | 
			
		||||
                  fluid
 | 
			
		||||
                  size='large'
 | 
			
		||||
                  onClick={() => setShowEmailBindModal(false)}
 | 
			
		||||
                >
 | 
			
		||||
                  {t('setting.personal.binding.email.cancel')}
 | 
			
		||||
                </Button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </Form>
 | 
			
		||||
          </Modal.Description>
 | 
			
		||||
@@ -329,27 +325,27 @@ const PersonalSetting = () => {
 | 
			
		||||
        size={'tiny'}
 | 
			
		||||
        style={{ maxWidth: '450px' }}
 | 
			
		||||
      >
 | 
			
		||||
        <Modal.Header>危险操作</Modal.Header>
 | 
			
		||||
        <Modal.Header>{t('setting.personal.delete_account.title')}</Modal.Header>
 | 
			
		||||
        <Modal.Content>
 | 
			
		||||
        <Message>您正在删除自己的帐户,将清空所有数据且不可恢复</Message>
 | 
			
		||||
          <Message>{t('setting.personal.delete_account.warning')}</Message>
 | 
			
		||||
          <Modal.Description>
 | 
			
		||||
            <Form size='large'>
 | 
			
		||||
              <Form.Input
 | 
			
		||||
                fluid
 | 
			
		||||
                placeholder={`输入你的账户名 ${userState?.user?.username} 以确认删除`}
 | 
			
		||||
                placeholder={t('setting.personal.delete_account.confirm_placeholder', {
 | 
			
		||||
                  username: userState?.user?.username
 | 
			
		||||
                })}
 | 
			
		||||
                name='self_account_deletion_confirmation'
 | 
			
		||||
                value={inputs.self_account_deletion_confirmation}
 | 
			
		||||
                onChange={handleInputChange}
 | 
			
		||||
              />
 | 
			
		||||
              {turnstileEnabled ? (
 | 
			
		||||
              {turnstileEnabled && (
 | 
			
		||||
                <Turnstile
 | 
			
		||||
                  sitekey={turnstileSiteKey}
 | 
			
		||||
                  onVerify={(token) => {
 | 
			
		||||
                    setTurnstileToken(token);
 | 
			
		||||
                  }}
 | 
			
		||||
                />
 | 
			
		||||
              ) : (
 | 
			
		||||
                <></>
 | 
			
		||||
              )}
 | 
			
		||||
              <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '1rem' }}>
 | 
			
		||||
                <Button
 | 
			
		||||
@@ -359,7 +355,7 @@ const PersonalSetting = () => {
 | 
			
		||||
                  onClick={deleteAccount}
 | 
			
		||||
                  loading={loading}
 | 
			
		||||
                >
 | 
			
		||||
                  确认删除
 | 
			
		||||
                  {t('setting.personal.delete_account.buttons.confirm')}
 | 
			
		||||
                </Button>
 | 
			
		||||
                <div style={{ width: '1rem' }}></div>
 | 
			
		||||
                <Button
 | 
			
		||||
@@ -367,7 +363,7 @@ const PersonalSetting = () => {
 | 
			
		||||
                  size='large'
 | 
			
		||||
                  onClick={() => setShowAccountDeleteModal(false)}
 | 
			
		||||
                >
 | 
			
		||||
                  取消
 | 
			
		||||
                  {t('setting.personal.delete_account.buttons.cancel')}
 | 
			
		||||
                </Button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </Form>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Button, Divider, Form, Grid, Header, Modal, Message } from 'semantic-ui-react';
 | 
			
		||||
import { API, removeTrailingSlash, showError } from '../helpers';
 | 
			
		||||
 | 
			
		||||
const SystemSetting = () => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  let [inputs, setInputs] = useState({
 | 
			
		||||
    PasswordLoginEnabled: '',
 | 
			
		||||
    PasswordRegisterEnabled: '',
 | 
			
		||||
@@ -260,42 +262,43 @@ const SystemSetting = () => {
 | 
			
		||||
    <Grid columns={1}>
 | 
			
		||||
      <Grid.Column>
 | 
			
		||||
        <Form loading={loading}>
 | 
			
		||||
          <Header as='h3'>通用设置</Header>
 | 
			
		||||
          <Header as='h3'>{t('setting.system.general.title')}</Header>
 | 
			
		||||
          <Form.Group widths='equal'>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='服务器地址'
 | 
			
		||||
              placeholder='例如:https://yourdomain.com'
 | 
			
		||||
              label={t('setting.system.general.server_address')}
 | 
			
		||||
              placeholder={t('setting.system.general.server_address_placeholder')}
 | 
			
		||||
              value={inputs.ServerAddress}
 | 
			
		||||
              name='ServerAddress'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitServerAddress}>
 | 
			
		||||
            更新服务器地址
 | 
			
		||||
            {t('setting.system.general.buttons.update')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>配置登录注册</Header>
 | 
			
		||||
          <Header as='h3'>{t('setting.system.login.title')}</Header>
 | 
			
		||||
          <Form.Group inline>
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.PasswordLoginEnabled === 'true'}
 | 
			
		||||
              label='允许通过密码进行登录'
 | 
			
		||||
              label={t('setting.system.login.password_login')}
 | 
			
		||||
              name='PasswordLoginEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
            {
 | 
			
		||||
              showPasswordWarningModal &&
 | 
			
		||||
            {showPasswordWarningModal && (
 | 
			
		||||
              <Modal
 | 
			
		||||
                open={showPasswordWarningModal}
 | 
			
		||||
                onClose={() => setShowPasswordWarningModal(false)}
 | 
			
		||||
                size={'tiny'}
 | 
			
		||||
                style={{ maxWidth: '450px' }}
 | 
			
		||||
              >
 | 
			
		||||
                <Modal.Header>警告</Modal.Header>
 | 
			
		||||
                <Modal.Header>{t('setting.system.password_login.warning.title')}</Modal.Header>
 | 
			
		||||
                <Modal.Content>
 | 
			
		||||
                  <p>取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?</p>
 | 
			
		||||
                  <p>{t('setting.system.password_login.warning.content')}</p>
 | 
			
		||||
                </Modal.Content>
 | 
			
		||||
                <Modal.Actions>
 | 
			
		||||
                  <Button onClick={() => setShowPasswordWarningModal(false)}>取消</Button>
 | 
			
		||||
                  <Button onClick={() => setShowPasswordWarningModal(false)}>
 | 
			
		||||
                    {t('setting.system.password_login.warning.buttons.cancel')}
 | 
			
		||||
                  </Button>
 | 
			
		||||
                  <Button
 | 
			
		||||
                    color='yellow'
 | 
			
		||||
                    onClick={async () => {
 | 
			
		||||
@@ -303,32 +306,32 @@ const SystemSetting = () => {
 | 
			
		||||
                      await updateOption('PasswordLoginEnabled', 'false');
 | 
			
		||||
                    }}
 | 
			
		||||
                  >
 | 
			
		||||
                    确定
 | 
			
		||||
                    {t('setting.system.password_login.warning.buttons.confirm')}
 | 
			
		||||
                  </Button>
 | 
			
		||||
                </Modal.Actions>
 | 
			
		||||
              </Modal>
 | 
			
		||||
            }
 | 
			
		||||
            )}
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.PasswordRegisterEnabled === 'true'}
 | 
			
		||||
              label='允许通过密码进行注册'
 | 
			
		||||
              label={t('setting.system.login.password_register')}
 | 
			
		||||
              name='PasswordRegisterEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.EmailVerificationEnabled === 'true'}
 | 
			
		||||
              label='通过密码注册时需要进行邮箱验证'
 | 
			
		||||
              label={t('setting.system.login.email_verification')}
 | 
			
		||||
              name='EmailVerificationEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.GitHubOAuthEnabled === 'true'}
 | 
			
		||||
              label='允许通过 GitHub 账户登录 & 注册'
 | 
			
		||||
              label={t('setting.system.login.github_oauth')}
 | 
			
		||||
              name='GitHubOAuthEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.WeChatAuthEnabled === 'true'}
 | 
			
		||||
              label='允许通过微信登录 & 注册'
 | 
			
		||||
              label={t('setting.system.login.wechat_login')}
 | 
			
		||||
              name='WeChatAuthEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
@@ -336,304 +339,283 @@ const SystemSetting = () => {
 | 
			
		||||
          <Form.Group inline>
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.RegisterEnabled === 'true'}
 | 
			
		||||
              label='允许新用户注册(此项为否时,新用户将无法以任何方式进行注册)'
 | 
			
		||||
              label={t('setting.system.login.registration')}
 | 
			
		||||
              name='RegisterEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              checked={inputs.TurnstileCheckEnabled === 'true'}
 | 
			
		||||
              label='启用 Turnstile 用户校验'
 | 
			
		||||
              label={t('setting.system.login.turnstile')}
 | 
			
		||||
              name='TurnstileCheckEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置邮箱域名白名单
 | 
			
		||||
            <Header.Subheader>用以防止恶意用户利用临时邮箱批量注册</Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
          <Header as='h3'>{t('setting.system.email_restriction.title')}</Header>
 | 
			
		||||
          <Message>{t('setting.system.email_restriction.subtitle')}</Message>
 | 
			
		||||
          <Form.Group inline>
 | 
			
		||||
            <Form.Checkbox
 | 
			
		||||
              label='启用邮箱域名白名单'
 | 
			
		||||
              checked={inputs.EmailDomainRestrictionEnabled === 'true'}
 | 
			
		||||
              label={t('setting.system.email_restriction.enable')}
 | 
			
		||||
              name='EmailDomainRestrictionEnabled'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              checked={inputs.EmailDomainRestrictionEnabled === 'true'}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Group widths={2}>
 | 
			
		||||
            <Form.Dropdown
 | 
			
		||||
              label='允许的邮箱域名'
 | 
			
		||||
              placeholder='允许的邮箱域名'
 | 
			
		||||
              name='EmailDomainWhitelist'
 | 
			
		||||
              required
 | 
			
		||||
              fluid
 | 
			
		||||
              multiple
 | 
			
		||||
              selection
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              value={inputs.EmailDomainWhitelist}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              options={EmailDomainWhitelist}
 | 
			
		||||
            />
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='添加新的允许的邮箱域名'
 | 
			
		||||
              action={
 | 
			
		||||
                <Button type='button' onClick={() => {
 | 
			
		||||
                  submitNewRestrictedDomain();
 | 
			
		||||
                }}>填入</Button>
 | 
			
		||||
              }
 | 
			
		||||
              onKeyDown={(e) => {
 | 
			
		||||
                if (e.key === 'Enter') {
 | 
			
		||||
                  submitNewRestrictedDomain();
 | 
			
		||||
                }
 | 
			
		||||
              }}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              placeholder='输入新的允许的邮箱域名'
 | 
			
		||||
              label={t('setting.system.email_restriction.add_domain')}
 | 
			
		||||
              placeholder={t('setting.system.email_restriction.add_domain_placeholder')}
 | 
			
		||||
              value={restrictedDomainInput}
 | 
			
		||||
              onChange={(e, { value }) => {
 | 
			
		||||
                setRestrictedDomainInput(value);
 | 
			
		||||
              }}
 | 
			
		||||
              action={
 | 
			
		||||
                <Button onClick={() => {
 | 
			
		||||
                  if (restrictedDomainInput === '') return;
 | 
			
		||||
                  setEmailDomainWhitelist([...EmailDomainWhitelist, {
 | 
			
		||||
                    key: restrictedDomainInput,
 | 
			
		||||
                    text: restrictedDomainInput,
 | 
			
		||||
                    value: restrictedDomainInput
 | 
			
		||||
                  }]);
 | 
			
		||||
                  setRestrictedDomainInput('');
 | 
			
		||||
                }}>
 | 
			
		||||
                  {t('setting.system.email_restriction.buttons.fill')}
 | 
			
		||||
                </Button>
 | 
			
		||||
              }
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitEmailDomainWhitelist}>保存邮箱域名白名单设置</Form.Button>
 | 
			
		||||
          <Form.Dropdown
 | 
			
		||||
            label={t('setting.system.email_restriction.allowed_domains')}
 | 
			
		||||
            placeholder={t('setting.system.email_restriction.allowed_domains')}
 | 
			
		||||
            fluid
 | 
			
		||||
            multiple
 | 
			
		||||
            search
 | 
			
		||||
            selection
 | 
			
		||||
            allowAdditions
 | 
			
		||||
            value={EmailDomainWhitelist.map(item => item.value)}
 | 
			
		||||
            options={EmailDomainWhitelist}
 | 
			
		||||
            onAddItem={(e, { value }) => {
 | 
			
		||||
              setEmailDomainWhitelist([...EmailDomainWhitelist, {
 | 
			
		||||
                key: value,
 | 
			
		||||
                text: value,
 | 
			
		||||
                value: value
 | 
			
		||||
              }]);
 | 
			
		||||
            }}
 | 
			
		||||
            onChange={(e, { value }) => {
 | 
			
		||||
              let newEmailDomainWhitelist = [];
 | 
			
		||||
              value.forEach((item) => {
 | 
			
		||||
                newEmailDomainWhitelist.push({
 | 
			
		||||
                  key: item,
 | 
			
		||||
                  text: item,
 | 
			
		||||
                  value: item
 | 
			
		||||
                });
 | 
			
		||||
              });
 | 
			
		||||
              setEmailDomainWhitelist(newEmailDomainWhitelist);
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
          <Form.Button onClick={submitEmailDomainWhitelist}>
 | 
			
		||||
            {t('setting.system.email_restriction.buttons.save')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置 SMTP
 | 
			
		||||
            <Header.Subheader>用以支持系统的邮件发送</Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Header as='h3'>{t('setting.system.smtp.title')}</Header>
 | 
			
		||||
          <Message>{t('setting.system.smtp.subtitle')}</Message>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='SMTP 服务器地址'
 | 
			
		||||
              label={t('setting.system.smtp.server')}
 | 
			
		||||
              placeholder={t('setting.system.smtp.server_placeholder')}
 | 
			
		||||
              name='SMTPServer'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.SMTPServer}
 | 
			
		||||
              placeholder='例如:smtp.qq.com'
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='SMTP 端口'
 | 
			
		||||
              label={t('setting.system.smtp.port')}
 | 
			
		||||
              placeholder={t('setting.system.smtp.port_placeholder')}
 | 
			
		||||
              name='SMTPPort'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.SMTPPort}
 | 
			
		||||
              placeholder='默认: 587'
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='SMTP 账户'
 | 
			
		||||
              label={t('setting.system.smtp.account')}
 | 
			
		||||
              placeholder={t('setting.system.smtp.account_placeholder')}
 | 
			
		||||
              name='SMTPAccount'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.SMTPAccount}
 | 
			
		||||
              placeholder='通常是邮箱地址'
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='SMTP 发送者邮箱'
 | 
			
		||||
              label={t('setting.system.smtp.from')}
 | 
			
		||||
              placeholder={t('setting.system.smtp.from_placeholder')}
 | 
			
		||||
              name='SMTPFrom'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.SMTPFrom}
 | 
			
		||||
              placeholder='通常和邮箱地址保持一致'
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='SMTP 访问凭证'
 | 
			
		||||
              label={t('setting.system.smtp.token')}
 | 
			
		||||
              placeholder={t('setting.system.smtp.token_placeholder')}
 | 
			
		||||
              name='SMTPToken'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              type='password'
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              checked={inputs.RegisterEnabled === 'true'}
 | 
			
		||||
              placeholder='敏感信息不会发送到前端显示'
 | 
			
		||||
              value={inputs.SMTPToken}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitSMTP}>保存 SMTP 设置</Form.Button>
 | 
			
		||||
          <Form.Button onClick={submitSMTP}>
 | 
			
		||||
            {t('setting.system.smtp.buttons.save')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置 GitHub OAuth App
 | 
			
		||||
            <Header.Subheader>
 | 
			
		||||
              用以支持通过 GitHub 进行登录注册,
 | 
			
		||||
              <a href='https://github.com/settings/developers' target='_blank'>
 | 
			
		||||
                点击此处
 | 
			
		||||
              </a>
 | 
			
		||||
              管理你的 GitHub OAuth App
 | 
			
		||||
            </Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Header as='h3'>{t('setting.system.github.title')}</Header>
 | 
			
		||||
          <Message>
 | 
			
		||||
            Homepage URL 填 <code>{inputs.ServerAddress}</code>
 | 
			
		||||
            ,Authorization callback URL 填{' '}
 | 
			
		||||
            <code>{`${inputs.ServerAddress}/oauth/github`}</code>
 | 
			
		||||
            {t('setting.system.github.subtitle')}
 | 
			
		||||
            <a href='https://github.com/settings/developers' target='_blank'>
 | 
			
		||||
              {t('setting.system.github.manage_link')}
 | 
			
		||||
            </a>
 | 
			
		||||
            {t('setting.system.github.manage_text')}
 | 
			
		||||
          </Message>
 | 
			
		||||
          <Message>
 | 
			
		||||
            {t('setting.system.github.url_notice', {
 | 
			
		||||
              server_url: originInputs.ServerAddress,
 | 
			
		||||
              callback_url: `${originInputs.ServerAddress}/oauth/github`
 | 
			
		||||
            })}
 | 
			
		||||
          </Message>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='GitHub Client ID'
 | 
			
		||||
              label={t('setting.system.github.client_id')}
 | 
			
		||||
              placeholder={t('setting.system.github.client_id_placeholder')}
 | 
			
		||||
              name='GitHubClientId'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.GitHubClientId}
 | 
			
		||||
              placeholder='输入你注册的 GitHub OAuth APP 的 ID'
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='GitHub Client Secret'
 | 
			
		||||
              label={t('setting.system.github.client_secret')}
 | 
			
		||||
              placeholder={t('setting.system.github.client_secret_placeholder')}
 | 
			
		||||
              name='GitHubClientSecret'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              type='password'
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.GitHubClientSecret}
 | 
			
		||||
              placeholder='敏感信息不会发送到前端显示'
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitGitHubOAuth}>
 | 
			
		||||
            保存 GitHub OAuth 设置
 | 
			
		||||
            {t('setting.system.github.buttons.save')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置飞书授权登录
 | 
			
		||||
            {t('setting.system.lark.title')}
 | 
			
		||||
            <Header.Subheader>
 | 
			
		||||
              用以支持通过飞书进行登录注册,
 | 
			
		||||
              {t('setting.system.lark.subtitle')}
 | 
			
		||||
              <a href='https://open.feishu.cn/app' target='_blank'>
 | 
			
		||||
                点击此处
 | 
			
		||||
                {t('setting.system.lark.manage_link')}
 | 
			
		||||
              </a>
 | 
			
		||||
              管理你的飞书应用
 | 
			
		||||
              {t('setting.system.lark.manage_text')}
 | 
			
		||||
            </Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Message>
 | 
			
		||||
            主页链接填 <code>{inputs.ServerAddress}</code>
 | 
			
		||||
            ,重定向 URL 填{' '}
 | 
			
		||||
            <code>{`${inputs.ServerAddress}/oauth/lark`}</code>
 | 
			
		||||
            {t('setting.system.lark.url_notice', {
 | 
			
		||||
              server_url: inputs.ServerAddress,
 | 
			
		||||
              callback_url: `${inputs.ServerAddress}/oauth/lark`
 | 
			
		||||
            })}
 | 
			
		||||
          </Message>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='App ID'
 | 
			
		||||
              label={t('setting.system.lark.client_id')}
 | 
			
		||||
              name='LarkClientId'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.LarkClientId}
 | 
			
		||||
              placeholder='输入 App ID'
 | 
			
		||||
              placeholder={t('setting.system.lark.client_id_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='App Secret'
 | 
			
		||||
              label={t('setting.system.lark.client_secret')}
 | 
			
		||||
              name='LarkClientSecret'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              type='password'
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.LarkClientSecret}
 | 
			
		||||
              placeholder='敏感信息不会发送到前端显示'
 | 
			
		||||
              placeholder={t('setting.system.lark.client_secret_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitLarkOAuth}>
 | 
			
		||||
            保存飞书 OAuth 设置
 | 
			
		||||
            {t('setting.system.lark.buttons.save')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置 WeChat Server
 | 
			
		||||
            {t('setting.system.wechat.title')}
 | 
			
		||||
            <Header.Subheader>
 | 
			
		||||
              用以支持通过微信进行登录注册,
 | 
			
		||||
              {t('setting.system.wechat.subtitle')}
 | 
			
		||||
              <a
 | 
			
		||||
                href='https://github.com/songquanpeng/wechat-server'
 | 
			
		||||
                target='_blank'
 | 
			
		||||
              >
 | 
			
		||||
                点击此处
 | 
			
		||||
                {t('setting.system.wechat.learn_more')}
 | 
			
		||||
              </a>
 | 
			
		||||
              了解 WeChat Server
 | 
			
		||||
            </Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='WeChat Server 服务器地址'
 | 
			
		||||
              label={t('setting.system.wechat.server_address')}
 | 
			
		||||
              name='WeChatServerAddress'
 | 
			
		||||
              placeholder='例如:https://yourdomain.com'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.WeChatServerAddress}
 | 
			
		||||
              placeholder={t('setting.system.wechat.server_address_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='WeChat Server 访问凭证'
 | 
			
		||||
              label={t('setting.system.wechat.token')}
 | 
			
		||||
              name='WeChatServerToken'
 | 
			
		||||
              type='password'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              type='password'
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.WeChatServerToken}
 | 
			
		||||
              placeholder='敏感信息不会发送到前端显示'
 | 
			
		||||
              placeholder={t('setting.system.wechat.token_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='微信公众号二维码图片链接'
 | 
			
		||||
              label={t('setting.system.wechat.qrcode')}
 | 
			
		||||
              name='WeChatAccountQRCodeImageURL'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.WeChatAccountQRCodeImageURL}
 | 
			
		||||
              placeholder='输入一个图片链接'
 | 
			
		||||
              placeholder={t('setting.system.wechat.qrcode_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitWeChat}>
 | 
			
		||||
            保存 WeChat Server 设置
 | 
			
		||||
            {t('setting.system.wechat.buttons.save')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置 Message Pusher
 | 
			
		||||
            {t('setting.system.turnstile.title')}
 | 
			
		||||
            <Header.Subheader>
 | 
			
		||||
              用以推送报警信息,
 | 
			
		||||
              <a
 | 
			
		||||
                href='https://github.com/songquanpeng/message-pusher'
 | 
			
		||||
                target='_blank'
 | 
			
		||||
              >
 | 
			
		||||
                点击此处
 | 
			
		||||
              </a>
 | 
			
		||||
              了解 Message Pusher
 | 
			
		||||
            </Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='Message Pusher 推送地址'
 | 
			
		||||
              name='MessagePusherAddress'
 | 
			
		||||
              placeholder='例如:https://msgpusher.com/push/your_username'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.MessagePusherAddress}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='Message Pusher 访问凭证'
 | 
			
		||||
              name='MessagePusherToken'
 | 
			
		||||
              type='password'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.MessagePusherToken}
 | 
			
		||||
              placeholder='敏感信息不会发送到前端显示'
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitMessagePusher}>
 | 
			
		||||
            保存 Message Pusher 设置
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
          <Divider />
 | 
			
		||||
          <Header as='h3'>
 | 
			
		||||
            配置 Turnstile
 | 
			
		||||
            <Header.Subheader>
 | 
			
		||||
              用以支持用户校验,
 | 
			
		||||
              {t('setting.system.turnstile.subtitle')}
 | 
			
		||||
              <a href='https://dash.cloudflare.com/' target='_blank'>
 | 
			
		||||
                点击此处
 | 
			
		||||
                {t('setting.system.turnstile.manage_link')}
 | 
			
		||||
              </a>
 | 
			
		||||
              管理你的 Turnstile Sites,推荐选择 Invisible Widget Type
 | 
			
		||||
              {t('setting.system.turnstile.manage_text')}
 | 
			
		||||
            </Header.Subheader>
 | 
			
		||||
          </Header>
 | 
			
		||||
          <Form.Group widths={3}>
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='Turnstile Site Key'
 | 
			
		||||
              label={t('setting.system.turnstile.site_key')}
 | 
			
		||||
              name='TurnstileSiteKey'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.TurnstileSiteKey}
 | 
			
		||||
              placeholder='输入你注册的 Turnstile Site Key'
 | 
			
		||||
              placeholder={t('setting.system.turnstile.site_key_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
            <Form.Input
 | 
			
		||||
              label='Turnstile Secret Key'
 | 
			
		||||
              label={t('setting.system.turnstile.secret_key')}
 | 
			
		||||
              name='TurnstileSecretKey'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
              type='password'
 | 
			
		||||
              autoComplete='new-password'
 | 
			
		||||
              value={inputs.TurnstileSecretKey}
 | 
			
		||||
              placeholder='敏感信息不会发送到前端显示'
 | 
			
		||||
              placeholder={t('setting.system.turnstile.secret_key_placeholder')}
 | 
			
		||||
            />
 | 
			
		||||
          </Form.Group>
 | 
			
		||||
          <Form.Button onClick={submitTurnstile}>
 | 
			
		||||
            保存 Turnstile 设置
 | 
			
		||||
            {t('setting.system.turnstile.buttons.save')}
 | 
			
		||||
          </Form.Button>
 | 
			
		||||
        </Form>
 | 
			
		||||
      </Grid.Column>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Card, Tab } from 'semantic-ui-react';
 | 
			
		||||
import SystemSetting from '../../components/SystemSetting';
 | 
			
		||||
import { isRoot } from '../../helpers';
 | 
			
		||||
@@ -7,9 +8,11 @@ import PersonalSetting from '../../components/PersonalSetting';
 | 
			
		||||
import OperationSetting from '../../components/OperationSetting';
 | 
			
		||||
 | 
			
		||||
const Setting = () => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
 | 
			
		||||
  let panes = [
 | 
			
		||||
    {
 | 
			
		||||
      menuItem: '个人设置',
 | 
			
		||||
      menuItem: t('setting.tabs.personal'),
 | 
			
		||||
      render: () => (
 | 
			
		||||
        <Tab.Pane attached={false}>
 | 
			
		||||
          <PersonalSetting />
 | 
			
		||||
@@ -20,7 +23,7 @@ const Setting = () => {
 | 
			
		||||
 | 
			
		||||
  if (isRoot()) {
 | 
			
		||||
    panes.push({
 | 
			
		||||
      menuItem: '运营设置',
 | 
			
		||||
      menuItem: t('setting.tabs.operation'),
 | 
			
		||||
      render: () => (
 | 
			
		||||
        <Tab.Pane attached={false}>
 | 
			
		||||
          <OperationSetting />
 | 
			
		||||
@@ -28,7 +31,7 @@ const Setting = () => {
 | 
			
		||||
      ),
 | 
			
		||||
    });
 | 
			
		||||
    panes.push({
 | 
			
		||||
      menuItem: '系统设置',
 | 
			
		||||
      menuItem: t('setting.tabs.system'),
 | 
			
		||||
      render: () => (
 | 
			
		||||
        <Tab.Pane attached={false}>
 | 
			
		||||
          <SystemSetting />
 | 
			
		||||
@@ -36,7 +39,7 @@ const Setting = () => {
 | 
			
		||||
      ),
 | 
			
		||||
    });
 | 
			
		||||
    panes.push({
 | 
			
		||||
      menuItem: '其他设置',
 | 
			
		||||
      menuItem: t('setting.tabs.other'),
 | 
			
		||||
      render: () => (
 | 
			
		||||
        <Tab.Pane attached={false}>
 | 
			
		||||
          <OtherSetting />
 | 
			
		||||
@@ -49,12 +52,12 @@ const Setting = () => {
 | 
			
		||||
    <div className='dashboard-container'>
 | 
			
		||||
      <Card fluid className='chart-card'>
 | 
			
		||||
        <Card.Content>
 | 
			
		||||
          <Card.Header className='header'>系统设置</Card.Header>
 | 
			
		||||
          <Card.Header className='header'>{t('setting.title')}</Card.Header>
 | 
			
		||||
          <Tab
 | 
			
		||||
            menu={{
 | 
			
		||||
              secondary: true,
 | 
			
		||||
              pointing: true,
 | 
			
		||||
              className: 'settings-tab', // 添加自定义类名以便样式化
 | 
			
		||||
              className: 'settings-tab',
 | 
			
		||||
            }}
 | 
			
		||||
            panes={panes}
 | 
			
		||||
          />
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user