复用现有 LegalSettings 模式,新增 TermsOfService 和 UsagePolicy 字段, 添加 /terms 和 /usage-policy 前端页面及 API 端点。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>master
| @@ -115,6 +115,8 @@ func GetStatus(c *gin.Context) { | |||
| "setup": constant.Setup, | |||
| "user_agreement_enabled": legalSetting.UserAgreement != "", | |||
| "privacy_policy_enabled": legalSetting.PrivacyPolicy != "", | |||
| "terms_enabled": legalSetting.TermsOfService != "", | |||
| "usage_policy_enabled": legalSetting.UsagePolicy != "", | |||
| "checkin_enabled": operation_setting.GetCheckinSetting().Enabled, | |||
| "_qn": "new-api", | |||
| } | |||
| @@ -206,6 +208,24 @@ func GetPrivacyPolicy(c *gin.Context) { | |||
| return | |||
| } | |||
| func GetTermsOfService(c *gin.Context) { | |||
| c.JSON(http.StatusOK, gin.H{ | |||
| "success": true, | |||
| "message": "", | |||
| "data": system_setting.GetLegalSettings().TermsOfService, | |||
| }) | |||
| return | |||
| } | |||
| func GetUsagePolicy(c *gin.Context) { | |||
| c.JSON(http.StatusOK, gin.H{ | |||
| "success": true, | |||
| "message": "", | |||
| "data": system_setting.GetLegalSettings().UsagePolicy, | |||
| }) | |||
| return | |||
| } | |||
| func GetMidjourney(c *gin.Context) { | |||
| common.OptionMapRWMutex.RLock() | |||
| defer common.OptionMapRWMutex.RUnlock() | |||
| @@ -26,6 +26,8 @@ func SetApiRouter(router *gin.Engine) { | |||
| apiRouter.GET("/notice", controller.GetNotice) | |||
| apiRouter.GET("/user-agreement", controller.GetUserAgreement) | |||
| apiRouter.GET("/privacy-policy", controller.GetPrivacyPolicy) | |||
| apiRouter.GET("/terms", controller.GetTermsOfService) | |||
| apiRouter.GET("/usage-policy", controller.GetUsagePolicy) | |||
| apiRouter.GET("/about", controller.GetAbout) | |||
| //apiRouter.GET("/midjourney", controller.GetMidjourney) | |||
| apiRouter.GET("/home_page_content", controller.GetHomePageContent) | |||
| @@ -3,13 +3,17 @@ package system_setting | |||
| import "github.com/QuantumNous/new-api/setting/config" | |||
| type LegalSettings struct { | |||
| UserAgreement string `json:"user_agreement"` | |||
| PrivacyPolicy string `json:"privacy_policy"` | |||
| UserAgreement string `json:"user_agreement"` | |||
| PrivacyPolicy string `json:"privacy_policy"` | |||
| TermsOfService string `json:"terms_of_service"` | |||
| UsagePolicy string `json:"usage_policy"` | |||
| } | |||
| var defaultLegalSettings = LegalSettings{ | |||
| UserAgreement: "", | |||
| PrivacyPolicy: "", | |||
| UserAgreement: "", | |||
| PrivacyPolicy: "", | |||
| TermsOfService: "", | |||
| UsagePolicy: "", | |||
| } | |||
| func init() { | |||
| @@ -55,6 +55,8 @@ const Dashboard = lazy(() => import('./pages/Dashboard')); | |||
| const About = lazy(() => import('./pages/About')); | |||
| const UserAgreement = lazy(() => import('./pages/UserAgreement')); | |||
| const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy')); | |||
| const Terms = lazy(() => import('./pages/Terms')); | |||
| const UsagePolicy = lazy(() => import('./pages/UsagePolicy')); | |||
| function DynamicOAuth2Callback() { | |||
| const { provider } = useParams(); | |||
| @@ -358,6 +360,22 @@ function App() { | |||
| </Suspense> | |||
| } | |||
| /> | |||
| <Route | |||
| path='/terms' | |||
| element={ | |||
| <Suspense fallback={<Loading></Loading>} key={location.pathname}> | |||
| <Terms /> | |||
| </Suspense> | |||
| } | |||
| /> | |||
| <Route | |||
| path='/usage-policy' | |||
| element={ | |||
| <Suspense fallback={<Loading></Loading>} key={location.pathname}> | |||
| <UsagePolicy /> | |||
| </Suspense> | |||
| } | |||
| /> | |||
| <Route | |||
| path='/console/chat/:id?' | |||
| element={ | |||
| @@ -36,6 +36,8 @@ import Text from '@douyinfe/semi-ui/lib/es/typography/text'; | |||
| const LEGAL_USER_AGREEMENT_KEY = 'legal.user_agreement'; | |||
| const LEGAL_PRIVACY_POLICY_KEY = 'legal.privacy_policy'; | |||
| const LEGAL_TERMS_KEY = 'legal.terms_of_service'; | |||
| const LEGAL_USAGE_POLICY_KEY = 'legal.usage_policy'; | |||
| const OtherSetting = () => { | |||
| const { t } = useTranslation(); | |||
| @@ -43,6 +45,8 @@ const OtherSetting = () => { | |||
| Notice: '', | |||
| [LEGAL_USER_AGREEMENT_KEY]: '', | |||
| [LEGAL_PRIVACY_POLICY_KEY]: '', | |||
| [LEGAL_TERMS_KEY]: '', | |||
| [LEGAL_USAGE_POLICY_KEY]: '', | |||
| SystemName: '', | |||
| Logo: '', | |||
| Footer: '', | |||
| @@ -76,6 +80,8 @@ const OtherSetting = () => { | |||
| Notice: false, | |||
| [LEGAL_USER_AGREEMENT_KEY]: false, | |||
| [LEGAL_PRIVACY_POLICY_KEY]: false, | |||
| [LEGAL_TERMS_KEY]: false, | |||
| [LEGAL_USAGE_POLICY_KEY]: false, | |||
| SystemName: false, | |||
| Logo: false, | |||
| HomePageContent: false, | |||
| @@ -147,6 +153,47 @@ const OtherSetting = () => { | |||
| })); | |||
| } | |||
| }; | |||
| // 通用设置 - TermsOfService | |||
| const submitTermsOfService = async () => { | |||
| try { | |||
| setLoadingInput((loadingInput) => ({ | |||
| ...loadingInput, | |||
| [LEGAL_TERMS_KEY]: true, | |||
| })); | |||
| await updateOption(LEGAL_TERMS_KEY, inputs[LEGAL_TERMS_KEY]); | |||
| showSuccess(t('服务条款已更新')); | |||
| } catch (error) { | |||
| console.error(t('服务条款更新失败'), error); | |||
| showError(t('服务条款更新失败')); | |||
| } finally { | |||
| setLoadingInput((loadingInput) => ({ | |||
| ...loadingInput, | |||
| [LEGAL_TERMS_KEY]: false, | |||
| })); | |||
| } | |||
| }; | |||
| // 通用设置 - UsagePolicy | |||
| const submitUsagePolicy = async () => { | |||
| try { | |||
| setLoadingInput((loadingInput) => ({ | |||
| ...loadingInput, | |||
| [LEGAL_USAGE_POLICY_KEY]: true, | |||
| })); | |||
| await updateOption( | |||
| LEGAL_USAGE_POLICY_KEY, | |||
| inputs[LEGAL_USAGE_POLICY_KEY], | |||
| ); | |||
| showSuccess(t('使用政策已更新')); | |||
| } catch (error) { | |||
| console.error(t('使用政策更新失败'), error); | |||
| showError(t('使用政策更新失败')); | |||
| } finally { | |||
| setLoadingInput((loadingInput) => ({ | |||
| ...loadingInput, | |||
| [LEGAL_USAGE_POLICY_KEY]: false, | |||
| })); | |||
| } | |||
| }; | |||
| // 个性化设置 | |||
| const formAPIPersonalization = useRef(); | |||
| // 个性化设置 - SystemName | |||
| @@ -413,6 +460,38 @@ const OtherSetting = () => { | |||
| > | |||
| {t('设置隐私政策')} | |||
| </Button> | |||
| <Form.TextArea | |||
| label={t('服务条款')} | |||
| placeholder={t( | |||
| '在此输入服务条款内容,支持 Markdown & HTML 代码', | |||
| )} | |||
| field={LEGAL_TERMS_KEY} | |||
| onChange={handleInputChange} | |||
| style={{ fontFamily: 'JetBrains Mono, Consolas' }} | |||
| autosize={{ minRows: 6, maxRows: 12 }} | |||
| /> | |||
| <Button | |||
| onClick={submitTermsOfService} | |||
| loading={loadingInput[LEGAL_TERMS_KEY]} | |||
| > | |||
| {t('设置服务条款')} | |||
| </Button> | |||
| <Form.TextArea | |||
| label={t('使用政策')} | |||
| placeholder={t( | |||
| '在此输入使用政策内容,支持 Markdown & HTML 代码', | |||
| )} | |||
| field={LEGAL_USAGE_POLICY_KEY} | |||
| onChange={handleInputChange} | |||
| style={{ fontFamily: 'JetBrains Mono, Consolas' }} | |||
| autosize={{ minRows: 6, maxRows: 12 }} | |||
| /> | |||
| <Button | |||
| onClick={submitUsagePolicy} | |||
| loading={loadingInput[LEGAL_USAGE_POLICY_KEY]} | |||
| > | |||
| {t('设置使用政策')} | |||
| </Button> | |||
| </Form.Section> | |||
| </Card> | |||
| </Form> | |||
| @@ -0,0 +1,18 @@ | |||
| import React from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import DocumentRenderer from '../../components/common/DocumentRenderer'; | |||
| const Terms = () => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <DocumentRenderer | |||
| apiEndpoint='/api/terms' | |||
| title={t('服务条款')} | |||
| cacheKey='terms_of_service' | |||
| emptyMessage={t('加载服务条款内容失败...')} | |||
| /> | |||
| ); | |||
| }; | |||
| export default Terms; | |||
| @@ -0,0 +1,18 @@ | |||
| import React from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import DocumentRenderer from '../../components/common/DocumentRenderer'; | |||
| const UsagePolicy = () => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <DocumentRenderer | |||
| apiEndpoint='/api/usage-policy' | |||
| title={t('使用政策')} | |||
| cacheKey='usage_policy' | |||
| emptyMessage={t('加载使用政策内容失败...')} | |||
| /> | |||
| ); | |||
| }; | |||
| export default UsagePolicy; | |||