| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- /*
- Copyright (C) 2025 QuantumNous
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- For commercial licensing, please contact support@quantumnous.com
- */
- import React, { useEffect, useState, useContext } from 'react';
- import { Button, Card, Col, Form, Row, Switch, Typography } from '@douyinfe/semi-ui';
- import { API, showError, showSuccess } from '../../../helpers';
- import { useTranslation } from 'react-i18next';
- import { StatusContext } from '../../../context/Status';
- const { Text } = Typography;
- export default function SettingsHeaderNavModules(props) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [statusState, statusDispatch] = useContext(StatusContext);
-
- // 顶栏模块管理状态
- const [headerNavModules, setHeaderNavModules] = useState({
- home: true,
- console: true,
- pricing: {
- enabled: true,
- requireAuth: false // 默认不需要登录鉴权
- },
- docs: true,
- about: true,
- });
- // 处理顶栏模块配置变更
- function handleHeaderNavModuleChange(moduleKey) {
- return (checked) => {
- const newModules = { ...headerNavModules };
- if (moduleKey === 'pricing') {
- // 对于pricing模块,只更新enabled属性
- newModules[moduleKey] = {
- ...newModules[moduleKey],
- enabled: checked
- };
- } else {
- newModules[moduleKey] = checked;
- }
- setHeaderNavModules(newModules);
- };
- }
- // 处理模型广场权限控制变更
- function handlePricingAuthChange(checked) {
- const newModules = { ...headerNavModules };
- newModules.pricing = {
- ...newModules.pricing,
- requireAuth: checked
- };
- setHeaderNavModules(newModules);
- }
- // 重置顶栏模块为默认配置
- function resetHeaderNavModules() {
- const defaultModules = {
- home: true,
- console: true,
- pricing: {
- enabled: true,
- requireAuth: false
- },
- docs: true,
- about: true,
- };
- setHeaderNavModules(defaultModules);
- showSuccess(t('已重置为默认配置'));
- }
- // 保存配置
- async function onSubmit() {
- setLoading(true);
- try {
- const res = await API.put('/api/option/', {
- key: 'HeaderNavModules',
- value: JSON.stringify(headerNavModules),
- });
- const { success, message } = res.data;
- if (success) {
- showSuccess(t('保存成功'));
- // 立即更新StatusContext中的状态
- statusDispatch({
- type: 'set',
- payload: {
- ...statusState.status,
- HeaderNavModules: JSON.stringify(headerNavModules)
- }
- });
- // 刷新父组件状态
- if (props.refresh) {
- await props.refresh();
- }
- } else {
- showError(message);
- }
- } catch (error) {
- showError(t('保存失败,请重试'));
- } finally {
- setLoading(false);
- }
- }
- useEffect(() => {
- // 从 props.options 中获取配置
- if (props.options && props.options.HeaderNavModules) {
- try {
- const modules = JSON.parse(props.options.HeaderNavModules);
- // 处理向后兼容性:如果pricing是boolean,转换为对象格式
- if (typeof modules.pricing === 'boolean') {
- modules.pricing = {
- enabled: modules.pricing,
- requireAuth: false // 默认不需要登录鉴权
- };
- }
- setHeaderNavModules(modules);
- } catch (error) {
- // 使用默认配置
- const defaultModules = {
- home: true,
- console: true,
- pricing: {
- enabled: true,
- requireAuth: false
- },
- docs: true,
- about: true,
- };
- setHeaderNavModules(defaultModules);
- }
- }
- }, [props.options]);
- // 模块配置数据
- const moduleConfigs = [
- {
- key: 'home',
- title: t('首页'),
- description: t('用户主页,展示系统信息')
- },
- {
- key: 'console',
- title: t('控制台'),
- description: t('用户控制面板,管理账户')
- },
- {
- key: 'pricing',
- title: t('模型广场'),
- description: t('模型定价,需要登录访问'),
- hasSubConfig: true // 标识该模块有子配置
- },
- {
- key: 'docs',
- title: t('文档'),
- description: t('系统文档和帮助信息')
- },
- {
- key: 'about',
- title: t('关于'),
- description: t('关于系统的详细信息')
- }
- ];
- return (
- <Card>
- <Form.Section text={t('顶栏管理')} extraText={t('控制顶栏模块显示状态,全局生效')}>
- <Row gutter={[16, 16]} style={{ marginBottom: '24px' }}>
- {moduleConfigs.map((module) => (
- <Col key={module.key} xs={24} sm={12} md={6} lg={6} xl={6}>
- <Card
- style={{
- borderRadius: '8px',
- border: '1px solid var(--semi-color-border)',
- transition: 'all 0.2s ease',
- background: 'var(--semi-color-bg-1)',
- minHeight: '80px'
- }}
- bodyStyle={{ padding: '16px' }}
- hoverable
- >
- <div style={{
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- height: '100%'
- }}>
- <div style={{ flex: 1, textAlign: 'left' }}>
- <div style={{
- fontWeight: '600',
- fontSize: '14px',
- color: 'var(--semi-color-text-0)',
- marginBottom: '4px'
- }}>
- {module.title}
- </div>
- <Text
- type="secondary"
- size="small"
- style={{
- fontSize: '12px',
- color: 'var(--semi-color-text-2)',
- lineHeight: '1.4',
- display: 'block'
- }}
- >
- {module.description}
- </Text>
- </div>
- <div style={{ marginLeft: '16px' }}>
- <Switch
- checked={module.key === 'pricing' ? headerNavModules[module.key]?.enabled : headerNavModules[module.key]}
- onChange={handleHeaderNavModuleChange(module.key)}
- size="default"
- />
- </div>
- </div>
- {/* 为模型广场添加权限控制子开关 */}
- {module.key === 'pricing' && (module.key === 'pricing' ? headerNavModules[module.key]?.enabled : headerNavModules[module.key]) && (
- <div style={{
- borderTop: '1px solid var(--semi-color-border)',
- marginTop: '12px',
- paddingTop: '12px'
- }}>
- <div style={{
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center'
- }}>
- <div style={{ flex: 1, textAlign: 'left' }}>
- <div style={{
- fontWeight: '500',
- fontSize: '12px',
- color: 'var(--semi-color-text-1)',
- marginBottom: '2px'
- }}>
- {t('需要登录访问')}
- </div>
- <Text
- type="secondary"
- size="small"
- style={{
- fontSize: '11px',
- color: 'var(--semi-color-text-2)',
- lineHeight: '1.4',
- display: 'block'
- }}
- >
- {t('开启后未登录用户无法访问模型广场')}
- </Text>
- </div>
- <div style={{ marginLeft: '16px' }}>
- <Switch
- checked={headerNavModules.pricing?.requireAuth || false}
- onChange={handlePricingAuthChange}
- size="small"
- />
- </div>
- </div>
- </div>
- )}
- </Card>
- </Col>
- ))}
- </Row>
- <div style={{
- display: 'flex',
- gap: '12px',
- justifyContent: 'flex-start',
- alignItems: 'center',
- paddingTop: '8px',
- borderTop: '1px solid var(--semi-color-border)'
- }}>
- <Button
- size='default'
- type='tertiary'
- onClick={resetHeaderNavModules}
- style={{
- borderRadius: '6px',
- fontWeight: '500'
- }}
- >
- {t('重置为默认')}
- </Button>
- <Button
- size='default'
- type='primary'
- onClick={onSubmit}
- loading={loading}
- style={{
- borderRadius: '6px',
- fontWeight: '500',
- minWidth: '100px'
- }}
- >
- {t('保存设置')}
- </Button>
- </div>
- </Form.Section>
- </Card>
- );
- }
|