Quellcode durchsuchen

feat: 服务条款和使用政策页面,支持后台 Markdown 配置

复用现有 LegalSettings 模式,新增 TermsOfService 和 UsagePolicy 字段,
添加 /terms 和 /usage-policy 前端页面及 API 端点。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
master
fengsilin vor 2 Wochen
Ursprung
Commit
1cc75aa9a2
7 geänderte Dateien mit 163 neuen und 4 gelöschten Zeilen
  1. +20
    -0
      controller/misc.go
  2. +2
    -0
      router/api-router.go
  3. +8
    -4
      setting/system_setting/legal.go
  4. +18
    -0
      web/src/App.jsx
  5. +79
    -0
      web/src/components/settings/OtherSetting.jsx
  6. +18
    -0
      web/src/pages/Terms/index.jsx
  7. +18
    -0
      web/src/pages/UsagePolicy/index.jsx

+ 20
- 0
controller/misc.go Datei anzeigen

@@ -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()


+ 2
- 0
router/api-router.go Datei anzeigen

@@ -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)


+ 8
- 4
setting/system_setting/legal.go Datei anzeigen

@@ -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() {


+ 18
- 0
web/src/App.jsx Datei anzeigen

@@ -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={


+ 79
- 0
web/src/components/settings/OtherSetting.jsx Datei anzeigen

@@ -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>


+ 18
- 0
web/src/pages/Terms/index.jsx Datei anzeigen

@@ -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;

+ 18
- 0
web/src/pages/UsagePolicy/index.jsx Datei anzeigen

@@ -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;

Laden…
Abbrechen
Speichern