fix: 🐛 修复系统配置页面报错的问题
This commit is contained in:
@@ -30,7 +30,7 @@ interface BasicConfigTabProps {
|
||||
|
||||
const BasicConfigTab: React.FC<BasicConfigTabProps> = ({
|
||||
configs,
|
||||
loading,
|
||||
// loading,
|
||||
saving,
|
||||
onSave,
|
||||
onReset,
|
||||
@@ -38,20 +38,26 @@ const BasicConfigTab: React.FC<BasicConfigTabProps> = ({
|
||||
onConfigChange
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||
|
||||
// 初始化表单数据
|
||||
useEffect(() => {
|
||||
const initialData: Record<string, any> = {};
|
||||
const [formData, setFormData] = useState<Record<string, unknown>>(() => {
|
||||
// 初始化时设置默认数据
|
||||
const initialData: Record<string, unknown> = {};
|
||||
configs.forEach(config => {
|
||||
initialData[config.config_key] = config.config_value;
|
||||
});
|
||||
return initialData;
|
||||
});
|
||||
|
||||
// 初始化表单数据
|
||||
useEffect(() => {
|
||||
const initialData: Record<string, unknown> = {};
|
||||
configs.forEach(config => {
|
||||
initialData[config.config_key] = config.config_value;
|
||||
});
|
||||
setFormData(initialData);
|
||||
form.setFieldsValue(initialData);
|
||||
}, [configs, form]);
|
||||
|
||||
// 处理表单值变化
|
||||
const handleValuesChange = (changedValues: any, allValues: any) => {
|
||||
const handleValuesChange = (_changedValues: Record<string, unknown>, allValues: Record<string, unknown>) => {
|
||||
setFormData(allValues);
|
||||
onConfigChange();
|
||||
};
|
||||
@@ -61,9 +67,10 @@ const BasicConfigTab: React.FC<BasicConfigTabProps> = ({
|
||||
form.validateFields().then(() => {
|
||||
const saveRequests: SaveConfigRequest[] = configs.map(config => ({
|
||||
config_key: config.config_key,
|
||||
config_value: formData[config.config_key] || '',
|
||||
config_value: String(formData[config.config_key] || ''),
|
||||
config_label: config.config_label,
|
||||
config_group: config.config_group
|
||||
config_group: config.config_group,
|
||||
config_type: config.config_type
|
||||
}));
|
||||
onSave(saveRequests);
|
||||
}).catch(() => {
|
||||
@@ -155,7 +162,7 @@ const BasicConfigTab: React.FC<BasicConfigTabProps> = ({
|
||||
style={{ marginBottom: '24px' }}
|
||||
>
|
||||
<Row gutter={[24, 0]}>
|
||||
{configItems.map((item, index) => {
|
||||
{configItems.map((item) => {
|
||||
const config = configs.find(c => c.config_key === item.key);
|
||||
if (!config) return null;
|
||||
|
||||
@@ -218,11 +225,10 @@ const BasicConfigTab: React.FC<BasicConfigTabProps> = ({
|
||||
|
||||
{/* 输入控件 */}
|
||||
<Form.Item
|
||||
name={item.key}
|
||||
rules={[
|
||||
{ required: item.required, message: `请输入${item.title}` },
|
||||
...(item.key === 'admin_email' ? [
|
||||
{ type: 'email', message: '请输入有效的邮箱地址' }
|
||||
{ type: 'email' as const, message: '请输入有效的邮箱地址' }
|
||||
] : [])
|
||||
]}
|
||||
>
|
||||
@@ -230,16 +236,33 @@ const BasicConfigTab: React.FC<BasicConfigTabProps> = ({
|
||||
<Input
|
||||
placeholder={item.placeholder}
|
||||
disabled={config.config_type === 'boolean'}
|
||||
value={String(formData[item.key] || '')}
|
||||
onChange={(e) => {
|
||||
form.setFieldValue(item.key, e.target.value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'textarea' && (
|
||||
<TextArea
|
||||
placeholder={item.placeholder}
|
||||
rows={item.rows || 2}
|
||||
value={String(formData[item.key] || '')}
|
||||
onChange={(e) => {
|
||||
form.setFieldValue(item.key, e.target.value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'select' && (
|
||||
<Select placeholder={item.placeholder}>
|
||||
<Select
|
||||
placeholder={item.placeholder}
|
||||
value={String(formData[item.key] || '')}
|
||||
onChange={(value) => {
|
||||
form.setFieldValue(item.key, value);
|
||||
onConfigChange();
|
||||
}}
|
||||
>
|
||||
{item.options?.map(option => (
|
||||
<Option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Form, Input, InputNumber, Switch, Card, Button, Space, Row, Col, Tooltip, Alert } from 'antd';
|
||||
import { Form, Input, InputNumber, Switch, Select, Card, Button, Space, Row, Col, Tooltip, Alert } from 'antd';
|
||||
import {
|
||||
InfoCircleOutlined,
|
||||
SaveOutlined,
|
||||
@@ -21,10 +21,10 @@ import { SystemConfig, SaveConfigRequest } from '../../types/systemConfig';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
|
||||
interface GameConfigTabProps {
|
||||
configs: SystemConfig[];
|
||||
loading: boolean;
|
||||
saving: boolean;
|
||||
saving?: boolean;
|
||||
onSave: (requests: SaveConfigRequest[]) => void;
|
||||
onReset: (configKey: string) => void;
|
||||
onShowHistory: (configKey: string) => void;
|
||||
@@ -33,7 +33,6 @@ interface GameConfigTabProps {
|
||||
|
||||
const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
configs,
|
||||
loading,
|
||||
saving,
|
||||
onSave,
|
||||
onReset,
|
||||
@@ -41,11 +40,11 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
onConfigChange
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||
const [formData, setFormData] = useState<Record<string, unknown>>({});
|
||||
|
||||
// 初始化表单数据
|
||||
useEffect(() => {
|
||||
const initialData: Record<string, any> = {};
|
||||
const initialData: Record<string, unknown> = {};
|
||||
configs.forEach(config => {
|
||||
if (config.config_type === 'boolean') {
|
||||
initialData[config.config_key] = config.config_value === '1' || config.config_value === 'true';
|
||||
@@ -53,12 +52,17 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
initialData[config.config_key] = config.config_value;
|
||||
}
|
||||
});
|
||||
setFormData(initialData);
|
||||
form.setFieldsValue(initialData);
|
||||
// 延迟设置表单值,避免在渲染期间直接修改
|
||||
const timer = setTimeout(() => {
|
||||
setFormData(initialData);
|
||||
form.setFieldsValue(initialData);
|
||||
}, 0);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [configs, form]);
|
||||
|
||||
// 处理表单值变化
|
||||
const handleValuesChange = (changedValues: any, allValues: any) => {
|
||||
const handleValuesChange = (changedValues: Record<string, unknown>, allValues: Record<string, unknown>) => {
|
||||
setFormData(allValues);
|
||||
onConfigChange();
|
||||
};
|
||||
@@ -69,8 +73,9 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
const saveRequests: SaveConfigRequest[] = configs.map(config => ({
|
||||
config_key: config.config_key,
|
||||
config_value: config.config_type === 'boolean'
|
||||
? (formData[config.config_key] ? '1' : '0')
|
||||
? ((formData[config.config_key] as boolean) ? '1' : '0')
|
||||
: String(formData[config.config_key] || ''),
|
||||
config_type: config.config_type,
|
||||
config_label: config.config_label,
|
||||
config_group: config.config_group
|
||||
}));
|
||||
@@ -92,8 +97,9 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
|
||||
// 检查API地址格式
|
||||
const validateApiUrl = (url: string) => {
|
||||
if (!url) return { valid: false, message: 'API地址不能为空' };
|
||||
if (!/^https?:\/\/.+/.test(url)) {
|
||||
const urlStr = String(url || '');
|
||||
if (!urlStr) return { valid: false, message: 'API地址不能为空' };
|
||||
if (!/^https?:\/\/.+/.test(urlStr)) {
|
||||
return { valid: false, message: '请输入有效的HTTP/HTTPS地址' };
|
||||
}
|
||||
return { valid: true, message: 'API地址格式正确' };
|
||||
@@ -101,10 +107,12 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
|
||||
// 检查PSK密钥强度
|
||||
const checkPskStrength = (psk: string) => {
|
||||
if (!psk) return { level: 'weak', message: 'PSK密钥不能为空' };
|
||||
if (psk.length < 32) return { level: 'weak', message: 'PSK密钥至少需要32位字符' };
|
||||
if (psk.length < 64) return { level: 'medium', message: 'PSK密钥长度适中,建议使用更长的密钥' };
|
||||
return { level: 'strong', message: 'PSK密钥强度良好' };
|
||||
const pskStr = String(psk || '');
|
||||
if (!pskStr) return { level: 'weak', message: 'PSK密钥不能为空' };
|
||||
if (pskStr.length < 8) return { level: 'weak', message: 'PSK密钥长度不足8位' };
|
||||
if (pskStr.length < 32) return { level: 'medium', message: 'PSK密钥长度不足32位,建议使用更强的密钥' };
|
||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(pskStr)) return { level: 'medium', message: 'PSK密钥缺少特殊字符,建议添加特殊字符' };
|
||||
return { level: 'strong', message: 'PSK密钥强度符合要求' };
|
||||
};
|
||||
|
||||
const apiUrlValidation = validateApiUrl(formData.game_server_api || '');
|
||||
@@ -223,7 +231,7 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
style={{ marginBottom: '24px' }}
|
||||
>
|
||||
<Row gutter={[24, 0]}>
|
||||
{configItems.map((item, index) => {
|
||||
{configItems.map((item) => {
|
||||
const config = configs.find(c => c.config_key === item.key);
|
||||
if (!config) return null;
|
||||
|
||||
@@ -278,74 +286,104 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
</div>
|
||||
|
||||
{/* 输入控件 */}
|
||||
<Form.Item
|
||||
name={item.key}
|
||||
rules={[
|
||||
{ required: item.required, message: `请输入${item.title}` },
|
||||
...(item.key === 'game_server_api' ? [
|
||||
{item.type === 'switch' ? (
|
||||
// Switch组件不需要表单验证,直接渲染
|
||||
<div style={{ marginTop: '8px' }}>
|
||||
<Switch
|
||||
checked={Boolean(formData[item.key])}
|
||||
onChange={(checked) => {
|
||||
form.setFieldValue(item.key, checked);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
<span style={{ marginLeft: '8px', fontSize: '12px', color: '#666' }}>
|
||||
{String(formData[item.key] || '') ? '已启用' : '未启用'}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
// 其他输入控件使用Form.Item进行布局,但使用value/onChange进行状态管理
|
||||
<Form.Item
|
||||
rules={[
|
||||
{
|
||||
pattern: /^https?:\/\/.+/,
|
||||
message: '请输入有效的HTTP/HTTPS地址'
|
||||
}
|
||||
] : []),
|
||||
...(item.key === 'game_server_psk' ? [
|
||||
{ min: 32, message: 'PSK密钥至少需要32位字符' }
|
||||
] : [])
|
||||
]}
|
||||
>
|
||||
{item.type === 'input' && (
|
||||
<Input
|
||||
placeholder={item.placeholder}
|
||||
style={{ fontFamily: item.sensitive ? 'monospace' : 'inherit' }}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'textarea' && (
|
||||
<TextArea
|
||||
placeholder={item.placeholder}
|
||||
rows={item.rows || 3}
|
||||
maxLength={500}
|
||||
showCount={!item.sensitive}
|
||||
autoSize={{ minRows: item.rows || 3, maxRows: 6 }}
|
||||
style={{ fontFamily: item.sensitive ? 'monospace' : 'inherit' }}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'inputnumber' && (
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={item.min}
|
||||
max={item.max}
|
||||
placeholder={item.placeholder}
|
||||
suffix={item.suffix}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'select' && (
|
||||
<Input.Group compact>
|
||||
required: item.required,
|
||||
message: `请输入${item.title}`
|
||||
},
|
||||
...(item.key === 'game_server_api' ? [
|
||||
{
|
||||
validator: (_: unknown, value: string) => {
|
||||
if (!value || !/^https?:\/\/.+/.test(value)) {
|
||||
return Promise.reject(new Error('请输入有效的API地址'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
] : []),
|
||||
...(item.key === 'game_server_psk' ? [
|
||||
{
|
||||
min: 32,
|
||||
message: 'PSK密钥至少需要32位字符'
|
||||
}
|
||||
] : [])
|
||||
]}
|
||||
>
|
||||
{item.type === 'input' && (
|
||||
<Input
|
||||
style={{ width: 'calc(100% - 80px)' }}
|
||||
placeholder={item.placeholder}
|
||||
readOnly
|
||||
/>
|
||||
<InputNumber
|
||||
style={{ width: '80px' }}
|
||||
placeholder="级别"
|
||||
/>
|
||||
</Input.Group>
|
||||
)}
|
||||
{item.type === 'switch' && (
|
||||
<div style={{ marginTop: '8px' }}>
|
||||
<Switch
|
||||
checked={formData[item.key]}
|
||||
onChange={(checked) => {
|
||||
form.setFieldValue(item.key, checked);
|
||||
disabled={config.config_type === 'boolean'}
|
||||
value={formData[item.key]}
|
||||
onChange={(e) => {
|
||||
form.setFieldValue(item.key, e.target.value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
<span style={{ marginLeft: '8px', fontSize: '12px', color: '#666' }}>
|
||||
{formData[item.key] ? '已启用' : '未启用'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</Form.Item>
|
||||
)}
|
||||
{item.type === 'textarea' && (
|
||||
<TextArea
|
||||
placeholder={item.placeholder}
|
||||
rows={item.rows || 3}
|
||||
maxLength={500}
|
||||
showCount={!item.sensitive}
|
||||
autoSize={{ minRows: item.rows || 3, maxRows: 6 }}
|
||||
style={{ fontFamily: item.sensitive ? 'monospace' : 'inherit' }}
|
||||
value={formData[item.key]}
|
||||
onChange={(e) => {
|
||||
form.setFieldValue(item.key, e.target.value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'inputnumber' && (
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={item.min}
|
||||
max={item.max}
|
||||
placeholder={item.placeholder}
|
||||
suffix={item.suffix}
|
||||
value={formData[item.key]}
|
||||
onChange={(value) => {
|
||||
form.setFieldValue(item.key, value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'select' && (
|
||||
<Select
|
||||
placeholder={item.placeholder}
|
||||
value={formData[item.key]}
|
||||
onChange={(value) => {
|
||||
form.setFieldValue(item.key, value);
|
||||
onConfigChange();
|
||||
}}
|
||||
>
|
||||
{item.options?.map((option, optionIndex) => (
|
||||
<Select.Option key={`${item.key}-${option.value}-${optionIndex}`} value={option.value}>
|
||||
{option.label}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
{/* 特殊字段验证信息 */}
|
||||
{item.key === 'game_server_api' && formData.game_server_api && (
|
||||
@@ -362,7 +400,7 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
{apiUrlValidation.valid ? '✅ 格式正确' : '❌ 格式错误'}
|
||||
</div>
|
||||
<div>
|
||||
协议:{formData.game_server_api.startsWith('https') ? 'HTTPS' : 'HTTP'}
|
||||
协议:{String(formData.game_server_api || '').startsWith('https') ? 'HTTPS' : 'HTTP'}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -377,11 +415,11 @@ const GameConfigTab: React.FC<GameConfigTabProps> = ({
|
||||
}}>
|
||||
<strong>密钥强度评估:</strong>
|
||||
<div style={{ marginTop: '4px' }}>
|
||||
长度: {formData.game_server_psk.length} 字符
|
||||
{formData.game_server_psk.length >= 32 && ' ✅'}
|
||||
长度: {String(formData.game_server_psk || '').length} 字符
|
||||
{String(formData.game_server_psk || '').length >= 32 && ' ✅'}
|
||||
</div>
|
||||
<div>
|
||||
包含特殊字符: {/[!@#$%^&*(),.?":{}|<>]/.test(formData.game_server_psk) ? '✅' : '❌'}
|
||||
包含特殊字符: {/[!@#$%^&*(),.?":{}|<>]/.test(String(formData.game_server_psk || '')) ? '✅' : '❌'}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -39,7 +39,7 @@ type FormData = Record<string, FormFieldValue>;
|
||||
key: string;
|
||||
title: string;
|
||||
description: string;
|
||||
type: 'input' | 'textarea' | 'inputnumber' | 'switch';
|
||||
type: 'input' | 'textarea' | 'inputnumber' | 'switch' | 'select';
|
||||
required: boolean;
|
||||
sensitive?: boolean;
|
||||
placeholder?: string;
|
||||
@@ -48,10 +48,12 @@ type FormData = Record<string, FormFieldValue>;
|
||||
rows?: number;
|
||||
suffix?: string;
|
||||
icon?: React.ReactNode;
|
||||
}
|
||||
options?: Array<{ value: string; label: string }>;
|
||||
}
|
||||
|
||||
const SecurityConfigTab: React.FC<SecurityConfigTabProps> = ({
|
||||
configs,
|
||||
// loading,
|
||||
saving,
|
||||
onSave,
|
||||
onReset,
|
||||
@@ -76,7 +78,7 @@ const SecurityConfigTab: React.FC<SecurityConfigTabProps> = ({
|
||||
}, [configs, form]);
|
||||
|
||||
// 处理表单值变化
|
||||
const handleValuesChange = (_changedValues: Partial<FormData>, allValues: FormData) => {
|
||||
const handleValuesChange = (changedValues: Partial<FormData>, allValues: FormData) => {
|
||||
setFormData(allValues);
|
||||
onConfigChange();
|
||||
};
|
||||
@@ -291,56 +293,73 @@ const SecurityConfigTab: React.FC<SecurityConfigTabProps> = ({
|
||||
</div>
|
||||
|
||||
{/* 输入控件 */}
|
||||
<Form.Item
|
||||
name={item.key}
|
||||
rules={[
|
||||
{ required: item.required, message: `请输入${item.title}` },
|
||||
...(item.key === 'jwt_secret' ? [
|
||||
{ min: 32, message: 'JWT密钥至少需要32位字符' }
|
||||
] : [])
|
||||
]}
|
||||
>
|
||||
{item.type === 'input' && (
|
||||
<Input.Password
|
||||
placeholder={item.placeholder}
|
||||
disabled={config.config_type === 'boolean'}
|
||||
visibilityToggle={!item.sensitive}
|
||||
{item.type === 'switch' ? (
|
||||
// Switch组件不需要表单验证,直接渲染
|
||||
<div style={{ marginTop: '8px' }}>
|
||||
<Switch
|
||||
checked={Boolean(formData[item.key])}
|
||||
onChange={(checked) => {
|
||||
form.setFieldValue(item.key, checked);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'textarea' && (
|
||||
<TextArea
|
||||
placeholder={item.placeholder}
|
||||
rows={item.rows || 3}
|
||||
maxLength={500}
|
||||
showCount={!item.sensitive}
|
||||
autoSize={{ minRows: item.rows || 3, maxRows: 6 }}
|
||||
style={{ fontFamily: item.sensitive ? 'monospace' : 'inherit' }}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'inputnumber' && (
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={item.min}
|
||||
max={item.max}
|
||||
placeholder={item.placeholder}
|
||||
suffix={item.suffix}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'switch' && (
|
||||
<div style={{ marginTop: '8px' }}>
|
||||
<Switch
|
||||
checked={Boolean(formData[item.key])}
|
||||
onChange={(checked) => {
|
||||
form.setFieldValue(item.key, checked);
|
||||
<span style={{ marginLeft: '8px', fontSize: '12px', color: '#666' }}>
|
||||
{String(formData[item.key] || '') ? '已启用' : '未启用'}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
// 其他输入控件使用Form.Item进行布局,但使用value/onChange进行状态管理
|
||||
<Form.Item
|
||||
rules={[
|
||||
{ required: item.required, message: `请输入${item.title}` },
|
||||
...(item.key === 'jwt_secret' ? [
|
||||
{ min: 32 as const, message: 'JWT密钥至少需要32位字符' }
|
||||
] : [])
|
||||
]}
|
||||
>
|
||||
{item.type === 'input' && (
|
||||
<Input.Password
|
||||
placeholder={item.placeholder}
|
||||
disabled={config.config_type === 'boolean'}
|
||||
visibilityToggle={!item.sensitive}
|
||||
value={formData[item.key]}
|
||||
onChange={(e) => {
|
||||
form.setFieldValue(item.key, e.target.value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
<span style={{ marginLeft: '8px', fontSize: '12px', color: '#666' }}>
|
||||
{formData[item.key] ? '已启用' : '未启用'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</Form.Item>
|
||||
)}
|
||||
{item.type === 'textarea' && (
|
||||
<TextArea
|
||||
placeholder={item.placeholder}
|
||||
rows={item.rows || 3}
|
||||
maxLength={500}
|
||||
showCount={!item.sensitive}
|
||||
autoSize={{ minRows: item.rows || 3, maxRows: 6 }}
|
||||
style={{ fontFamily: item.sensitive ? 'monospace' : 'inherit' }}
|
||||
value={formData[item.key]}
|
||||
onChange={(e) => {
|
||||
form.setFieldValue(item.key, e.target.value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type === 'inputnumber' && (
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={item.min}
|
||||
max={item.max}
|
||||
placeholder={item.placeholder}
|
||||
suffix={item.suffix}
|
||||
value={formData[item.key]}
|
||||
onChange={(value) => {
|
||||
form.setFieldValue(item.key, value);
|
||||
onConfigChange();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
{/* JWT密钥特殊提示 */}
|
||||
{item.key === 'jwt_secret' && formData.jwt_secret && (
|
||||
|
||||
Reference in New Issue
Block a user