重构设置页面,实现config前端可视化配置
This commit is contained in:
parent
e2a09d0dde
commit
c59355dcae
86
apps/jingrow/frontend/src/shared/api/system.ts
Normal file
86
apps/jingrow/frontend/src/shared/api/system.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import axios from 'axios'
|
||||
import { get_session_api_headers } from './auth'
|
||||
|
||||
const jingrowServerUrl = import.meta.env.VITE_JINGROW_SERVER_URL || ''
|
||||
|
||||
export interface EnvironmentConfig {
|
||||
jingrow_server_url: string
|
||||
jingrow_api_key: string
|
||||
jingrow_api_secret: string
|
||||
jingrow_session_cookie: string
|
||||
jingrow_cloud_url: string
|
||||
jingrow_cloud_api_url: string
|
||||
jingrow_cloud_api_key: string
|
||||
jingrow_cloud_api_secret: string
|
||||
jingrow_db_host: string
|
||||
jingrow_db_port: string
|
||||
jingrow_db_name: string
|
||||
jingrow_db_user: string
|
||||
jingrow_db_password: string
|
||||
jingrow_db_type: string
|
||||
qdrant_host: string
|
||||
qdrant_port: number
|
||||
run_mode: string
|
||||
environment: string
|
||||
log_level: string
|
||||
backend_host: string
|
||||
backend_port: number
|
||||
backend_reload: boolean
|
||||
worker_processes: number
|
||||
worker_threads: number
|
||||
watch: boolean
|
||||
}
|
||||
|
||||
// 获取环境配置
|
||||
export const getEnvironmentConfig = async (): Promise<{ success: boolean; data?: EnvironmentConfig; message?: string }> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${jingrowServerUrl}/jingrow/system/environment-config`,
|
||||
{
|
||||
headers: get_session_api_headers(),
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
|
||||
if (response.data?.success) {
|
||||
return { success: true, data: response.data.data }
|
||||
}
|
||||
return { success: false, message: response.data?.message || '获取环境配置失败' }
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 403) {
|
||||
return { success: false, message: '仅系统管理员可以访问此功能' }
|
||||
}
|
||||
if (error.response?.status === 401) {
|
||||
return { success: false, message: '认证失败,请重新登录' }
|
||||
}
|
||||
return { success: false, message: error.response?.data?.detail || error.message || '获取环境配置失败' }
|
||||
}
|
||||
}
|
||||
|
||||
// 更新环境配置
|
||||
export const updateEnvironmentConfig = async (config: Partial<EnvironmentConfig>): Promise<{ success: boolean; message?: string }> => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${jingrowServerUrl}/jingrow/system/environment-config`,
|
||||
config,
|
||||
{
|
||||
headers: get_session_api_headers(),
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
|
||||
if (response.data?.success) {
|
||||
return { success: true, message: response.data.message || '环境配置已更新' }
|
||||
}
|
||||
return { success: false, message: response.data?.message || '更新环境配置失败' }
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 403) {
|
||||
return { success: false, message: '仅系统管理员可以访问此功能' }
|
||||
}
|
||||
if (error.response?.status === 401) {
|
||||
return { success: false, message: '认证失败,请重新登录' }
|
||||
}
|
||||
return { success: false, message: error.response?.data?.detail || error.message || '更新环境配置失败' }
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,16 +57,164 @@
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
|
||||
<!-- 环境配置(仅系统管理员可见) -->
|
||||
<n-grid-item v-if="isAdmin">
|
||||
<n-card :title="t('Environment Configuration')">
|
||||
<n-alert type="warning" style="margin-bottom: 16px">
|
||||
{{ t('Only system administrators can view and edit environment configuration') }}
|
||||
</n-alert>
|
||||
<n-form
|
||||
:model="envConfig"
|
||||
label-placement="left"
|
||||
label-width="180px"
|
||||
:loading="envConfigLoading"
|
||||
>
|
||||
<n-collapse>
|
||||
<n-collapse-item name="jingrow" :title="t('Jingrow API Configuration')">
|
||||
<n-form-item label="Jingrow Server URL">
|
||||
<n-input v-model:value="envConfig.jingrow_server_url" placeholder="https://example.jingrow.com" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Jingrow API Key">
|
||||
<n-input v-model:value="envConfig.jingrow_api_key" type="password" show-password-on="click" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Jingrow API Secret">
|
||||
<n-input v-model:value="envConfig.jingrow_api_secret" type="password" show-password-on="click" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Jingrow Session Cookie">
|
||||
<n-input v-model:value="envConfig.jingrow_session_cookie" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
|
||||
<n-collapse-item name="cloud" :title="t('Jingrow Cloud Configuration')">
|
||||
<n-form-item label="Cloud URL">
|
||||
<n-input v-model:value="envConfig.jingrow_cloud_url" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Cloud API URL">
|
||||
<n-input v-model:value="envConfig.jingrow_cloud_api_url" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Cloud API Key">
|
||||
<n-input v-model:value="envConfig.jingrow_cloud_api_key" type="password" show-password-on="click" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Cloud API Secret">
|
||||
<n-input v-model:value="envConfig.jingrow_cloud_api_secret" type="password" show-password-on="click" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
|
||||
<n-collapse-item name="database" :title="t('Database Configuration')">
|
||||
<n-form-item label="DB Host">
|
||||
<n-input v-model:value="envConfig.jingrow_db_host" />
|
||||
</n-form-item>
|
||||
<n-form-item label="DB Port">
|
||||
<n-input v-model:value="envConfig.jingrow_db_port" />
|
||||
</n-form-item>
|
||||
<n-form-item label="DB Name">
|
||||
<n-input v-model:value="envConfig.jingrow_db_name" />
|
||||
</n-form-item>
|
||||
<n-form-item label="DB User">
|
||||
<n-input v-model:value="envConfig.jingrow_db_user" />
|
||||
</n-form-item>
|
||||
<n-form-item label="DB Password">
|
||||
<n-input v-model:value="envConfig.jingrow_db_password" type="password" show-password-on="click" />
|
||||
</n-form-item>
|
||||
<n-form-item label="DB Type">
|
||||
<n-select v-model:value="envConfig.jingrow_db_type" :options="dbTypeOptions" style="width: 200px" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
|
||||
<n-collapse-item name="qdrant" :title="t('Qdrant Configuration')">
|
||||
<n-form-item label="Qdrant Host">
|
||||
<n-input v-model:value="envConfig.qdrant_host" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Qdrant Port">
|
||||
<n-input-number v-model:value="envConfig.qdrant_port" :min="1" :max="65535" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
|
||||
<n-collapse-item name="runtime" :title="t('Runtime Configuration')">
|
||||
<n-form-item label="Run Mode">
|
||||
<n-select v-model:value="envConfig.run_mode" :options="runModeOptions" style="width: 200px" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Environment">
|
||||
<n-select v-model:value="envConfig.environment" :options="environmentOptions" style="width: 200px" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Log Level">
|
||||
<n-select v-model:value="envConfig.log_level" :options="logLevelOptions" style="width: 200px" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Backend Host">
|
||||
<n-input v-model:value="envConfig.backend_host" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Backend Port">
|
||||
<n-input-number v-model:value="envConfig.backend_port" :min="1" :max="65535" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Backend Reload">
|
||||
<n-switch v-model:value="envConfig.backend_reload" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Worker Processes">
|
||||
<n-input-number v-model:value="envConfig.worker_processes" :min="1" :max="32" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Worker Threads">
|
||||
<n-input-number v-model:value="envConfig.worker_threads" :min="1" :max="32" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Watch">
|
||||
<n-switch v-model:value="envConfig.watch" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
|
||||
<n-form-item style="margin-top: 16px">
|
||||
<n-space>
|
||||
<n-button type="primary" :loading="envConfigSaving" @click="saveEnvironmentConfig">
|
||||
{{ t('Save Environment Configuration') }}
|
||||
</n-button>
|
||||
<n-button @click="loadEnvironmentConfig">
|
||||
{{ t('Refresh') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted } from 'vue'
|
||||
import { NGrid, NGridItem, NCard, NForm, NFormItem, NInput, NButton, NInputNumber, NSelect, useMessage } from 'naive-ui'
|
||||
import { reactive, onMounted, computed, ref } from 'vue'
|
||||
import {
|
||||
NGrid,
|
||||
NGridItem,
|
||||
NCard,
|
||||
NForm,
|
||||
NFormItem,
|
||||
NInput,
|
||||
NButton,
|
||||
NInputNumber,
|
||||
NSelect,
|
||||
NSwitch,
|
||||
NAlert,
|
||||
NCollapse,
|
||||
NCollapseItem,
|
||||
NSpace,
|
||||
useMessage
|
||||
} from 'naive-ui'
|
||||
import { getCurrentLocale, setLocale, locales, initLocale, t } from '../shared/i18n'
|
||||
import { useAuthStore } from '../shared/stores/auth'
|
||||
import { getEnvironmentConfig, updateEnvironmentConfig, type EnvironmentConfig } from '../shared/api/system'
|
||||
|
||||
const message = useMessage()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
// 检查是否为系统管理员
|
||||
const isAdmin = computed(() => {
|
||||
const user = authStore.user
|
||||
return user?.username === 'Administrator' || user?.id === 'Administrator'
|
||||
})
|
||||
|
||||
// 环境配置
|
||||
const envConfig = reactive<Partial<EnvironmentConfig>>({})
|
||||
const envConfigLoading = ref(false)
|
||||
const envConfigSaving = ref(false)
|
||||
|
||||
const systemSettings = reactive({
|
||||
appName: localStorage.getItem('appName') || 'Jingrow',
|
||||
@ -111,6 +259,36 @@ const timezoneOptions = [
|
||||
{ label: 'Pacific/Auckland (新西兰时间)', value: 'Pacific/Auckland' }
|
||||
]
|
||||
|
||||
// 数据库类型选项
|
||||
const dbTypeOptions = [
|
||||
{ label: 'MariaDB', value: 'mariadb' },
|
||||
{ label: 'MySQL', value: 'mysql' },
|
||||
{ label: 'PostgreSQL', value: 'postgresql' }
|
||||
]
|
||||
|
||||
// 运行模式选项
|
||||
const runModeOptions = [
|
||||
{ label: 'API', value: 'api' },
|
||||
{ label: 'Worker', value: 'worker' },
|
||||
{ label: 'Scheduler', value: 'scheduler' }
|
||||
]
|
||||
|
||||
// 环境选项
|
||||
const environmentOptions = [
|
||||
{ label: 'Development', value: 'development' },
|
||||
{ label: 'Production', value: 'production' },
|
||||
{ label: 'Testing', value: 'testing' }
|
||||
]
|
||||
|
||||
// 日志级别选项
|
||||
const logLevelOptions = [
|
||||
{ label: 'DEBUG', value: 'DEBUG' },
|
||||
{ label: 'INFO', value: 'INFO' },
|
||||
{ label: 'WARNING', value: 'WARNING' },
|
||||
{ label: 'ERROR', value: 'ERROR' },
|
||||
{ label: 'CRITICAL', value: 'CRITICAL' }
|
||||
]
|
||||
|
||||
const changeLanguage = (locale: string) => {
|
||||
setLocale(locale)
|
||||
message.success(t('Language updated'))
|
||||
@ -131,9 +309,60 @@ const saveSystemSettings = () => {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 加载环境配置
|
||||
const loadEnvironmentConfig = async () => {
|
||||
if (!isAdmin.value) {
|
||||
return
|
||||
}
|
||||
|
||||
envConfigLoading.value = true
|
||||
try {
|
||||
const result = await getEnvironmentConfig()
|
||||
if (result.success && result.data) {
|
||||
Object.assign(envConfig, result.data)
|
||||
message.success(t('Environment configuration loaded'))
|
||||
} else {
|
||||
message.error(result.message || t('Failed to load environment configuration'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
message.error(error.message || t('Failed to load environment configuration'))
|
||||
} finally {
|
||||
envConfigLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 保存环境配置
|
||||
const saveEnvironmentConfig = async () => {
|
||||
if (!isAdmin.value) {
|
||||
message.error(t('Only system administrators can edit environment configuration'))
|
||||
return
|
||||
}
|
||||
|
||||
envConfigSaving.value = true
|
||||
try {
|
||||
const result = await updateEnvironmentConfig(envConfig)
|
||||
if (result.success) {
|
||||
message.success(result.message || t('Environment configuration saved'))
|
||||
// 重新加载配置以获取最新值
|
||||
await loadEnvironmentConfig()
|
||||
} else {
|
||||
message.error(result.message || t('Failed to save environment configuration'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
message.error(error.message || t('Failed to save environment configuration'))
|
||||
} finally {
|
||||
envConfigSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
initLocale()
|
||||
systemSettings.language = getCurrentLocale()
|
||||
|
||||
// 如果是系统管理员,加载环境配置
|
||||
if (isAdmin.value) {
|
||||
await loadEnvironmentConfig()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
267
apps/jingrow/jingrow/api/system.py
Normal file
267
apps/jingrow/jingrow/api/system.py
Normal file
@ -0,0 +1,267 @@
|
||||
# Copyright (c) 2025, JINGROW and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
"""
|
||||
系统环境配置管理 API
|
||||
仅限系统管理员用户可以访问
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from typing import Dict, Any, Optional
|
||||
import logging
|
||||
from jingrow.utils.jingrow_api import get_logged_user
|
||||
from jingrow.config import Config, get_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def check_admin_permission(request: Request) -> str:
|
||||
"""
|
||||
检查用户是否为系统管理员(Administrator)
|
||||
返回当前用户名,如果不是管理员则抛出异常
|
||||
"""
|
||||
session_cookie = request.cookies.get('sid')
|
||||
if not session_cookie:
|
||||
raise HTTPException(status_code=401, detail="未提供认证信息")
|
||||
|
||||
user = get_logged_user(session_cookie)
|
||||
if not user:
|
||||
raise HTTPException(status_code=401, detail="认证失败")
|
||||
|
||||
if user != "Administrator":
|
||||
raise HTTPException(status_code=403, detail="仅系统管理员可以访问此功能")
|
||||
|
||||
return user
|
||||
|
||||
|
||||
@router.get("/jingrow/system/environment-config")
|
||||
async def get_environment_config(request: Request):
|
||||
"""
|
||||
获取环境配置信息
|
||||
仅限系统管理员访问
|
||||
"""
|
||||
try:
|
||||
# 检查管理员权限
|
||||
check_admin_permission(request)
|
||||
|
||||
# 获取当前配置
|
||||
settings = get_settings()
|
||||
|
||||
# 返回完整配置信息(仅管理员可以访问,因此返回完整信息)
|
||||
config_dict = settings.model_dump()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": config_dict
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"获取环境配置失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"获取环境配置失败: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/jingrow/system/environment-config")
|
||||
async def update_environment_config(request: Request, config_data: Dict[str, Any]):
|
||||
"""
|
||||
更新环境配置信息
|
||||
仅限系统管理员访问
|
||||
"""
|
||||
try:
|
||||
# 检查管理员权限
|
||||
check_admin_permission(request)
|
||||
|
||||
# 验证配置数据
|
||||
if not config_data:
|
||||
raise HTTPException(status_code=400, detail="配置数据不能为空")
|
||||
|
||||
# 获取当前配置
|
||||
settings = get_settings()
|
||||
|
||||
# 可更新的配置字段列表(从 config.py 中的 Settings 类定义)
|
||||
# 按照 config.py 中的注释分组
|
||||
field_groups = {
|
||||
'Jingrow API配置': [
|
||||
'jingrow_server_url',
|
||||
'jingrow_api_key',
|
||||
'jingrow_api_secret',
|
||||
'jingrow_session_cookie',
|
||||
],
|
||||
'Jingrow Cloud API配置': [
|
||||
'jingrow_cloud_url',
|
||||
'jingrow_cloud_api_url',
|
||||
'jingrow_cloud_api_key',
|
||||
'jingrow_cloud_api_secret',
|
||||
],
|
||||
'数据库配置': [
|
||||
'jingrow_db_host',
|
||||
'jingrow_db_port',
|
||||
'jingrow_db_name',
|
||||
'jingrow_db_user',
|
||||
'jingrow_db_password',
|
||||
'jingrow_db_type',
|
||||
],
|
||||
'Qdrant 向量数据库配置': [
|
||||
'qdrant_host',
|
||||
'qdrant_port',
|
||||
],
|
||||
'运行模式': [
|
||||
'run_mode',
|
||||
],
|
||||
'环境:development/production(控制启动模式、热重载等)': [
|
||||
'environment',
|
||||
],
|
||||
'日志级别:DEBUG/INFO/WARNING/ERROR/CRITICAL(全局默认级别)': [
|
||||
'log_level',
|
||||
],
|
||||
'本地后端主机配置': [
|
||||
'backend_host',
|
||||
'backend_port',
|
||||
'backend_reload',
|
||||
],
|
||||
'Dramatiq 任务队列': [
|
||||
'worker_processes',
|
||||
'worker_threads',
|
||||
'watch',
|
||||
],
|
||||
}
|
||||
|
||||
# 生成所有允许的字段列表
|
||||
allowed_fields = []
|
||||
for fields in field_groups.values():
|
||||
allowed_fields.extend(fields)
|
||||
|
||||
# 更新允许的字段
|
||||
updated_fields = []
|
||||
env_file_path = settings.model_config.get('env_file')
|
||||
|
||||
# 读取现有的 .env 文件内容(如果存在)
|
||||
env_lines = []
|
||||
if env_file_path:
|
||||
try:
|
||||
from pathlib import Path
|
||||
env_path = Path(env_file_path)
|
||||
if env_path.exists():
|
||||
env_lines = env_path.read_text(encoding='utf-8').split('\n')
|
||||
except Exception as e:
|
||||
logger.warning(f"读取 .env 文件失败: {e}")
|
||||
|
||||
# 构建更新的配置字典
|
||||
env_updates = {}
|
||||
for field, value in config_data.items():
|
||||
if field in allowed_fields:
|
||||
env_updates[field.upper()] = str(value) if value is not None else ''
|
||||
updated_fields.append(field)
|
||||
|
||||
# 更新 .env 文件
|
||||
if env_file_path and env_updates:
|
||||
try:
|
||||
from pathlib import Path
|
||||
env_path = Path(env_file_path)
|
||||
|
||||
# 收集所有已存在的键值对(包括未更新的)
|
||||
existing_config = {}
|
||||
header_comments = [] # 保存文件开头的注释(分组注释之前的)
|
||||
|
||||
# 解析现有文件内容
|
||||
found_first_config = False
|
||||
for line in env_lines:
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
if not found_first_config:
|
||||
header_comments.append('')
|
||||
continue
|
||||
|
||||
if stripped.startswith('#'):
|
||||
# 检查是否是分组注释
|
||||
is_group_comment = any(group in stripped for group in field_groups.keys())
|
||||
if not found_first_config and not is_group_comment:
|
||||
# 文件开头的非分组注释,保留
|
||||
header_comments.append(line.rstrip())
|
||||
continue
|
||||
|
||||
if '=' in stripped:
|
||||
found_first_config = True
|
||||
key, value = stripped.split('=', 1)
|
||||
key = key.strip()
|
||||
existing_config[key.upper()] = (key, value.strip())
|
||||
|
||||
# 更新配置字典
|
||||
for key_upper, new_value in env_updates.items():
|
||||
# 保持原有的键名格式(大小写)
|
||||
if key_upper in existing_config:
|
||||
original_key, _ = existing_config[key_upper]
|
||||
existing_config[key_upper] = (original_key, new_value)
|
||||
else:
|
||||
# 新字段,使用大写键名
|
||||
existing_config[key_upper] = (key_upper, new_value)
|
||||
|
||||
# 按照分组顺序生成新的 .env 文件内容
|
||||
new_lines = []
|
||||
|
||||
# 添加文件开头的注释
|
||||
if header_comments:
|
||||
new_lines.extend(header_comments)
|
||||
# 如果最后一行不是空行,添加一个空行用于分隔
|
||||
if header_comments and header_comments[-1].strip():
|
||||
new_lines.append('')
|
||||
|
||||
# 按照分组顺序添加配置项
|
||||
has_previous_group = False
|
||||
for group_name, fields in field_groups.items():
|
||||
# 检查该组是否有配置项
|
||||
group_configs = []
|
||||
for field in fields:
|
||||
field_upper = field.upper()
|
||||
if field_upper in existing_config:
|
||||
key, value = existing_config[field_upper]
|
||||
group_configs.append(f'{key}={value}')
|
||||
|
||||
# 如果有配置项,添加分组注释和配置
|
||||
if group_configs:
|
||||
if has_previous_group:
|
||||
new_lines.append('') # 组之间添加空行
|
||||
new_lines.append(f'# {group_name}')
|
||||
new_lines.extend(group_configs)
|
||||
has_previous_group = True
|
||||
|
||||
# 添加剩余的未分组配置项(如果有)
|
||||
remaining_keys = set(existing_config.keys())
|
||||
for fields in field_groups.values():
|
||||
for field in fields:
|
||||
remaining_keys.discard(field.upper())
|
||||
|
||||
if remaining_keys:
|
||||
if has_previous_group:
|
||||
new_lines.append('') # 与其他分组之间添加空行
|
||||
new_lines.append('# 其他配置')
|
||||
for key_upper in sorted(remaining_keys):
|
||||
key, value = existing_config[key_upper]
|
||||
new_lines.append(f'{key}={value}')
|
||||
|
||||
# 写入文件(移除末尾的多个空行)
|
||||
content = '\n'.join(new_lines).rstrip()
|
||||
if content:
|
||||
env_path.write_text(content + '\n', encoding='utf-8')
|
||||
else:
|
||||
env_path.write_text('\n', encoding='utf-8')
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"更新 .env 文件失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"更新配置文件失败: {str(e)}")
|
||||
|
||||
logger.info(f"环境配置已更新,字段: {updated_fields}")
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": "环境配置已更新",
|
||||
"updated_fields": updated_fields
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"更新环境配置失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"更新环境配置失败: {str(e)}")
|
||||
|
||||
@ -11,7 +11,6 @@ class Settings(BaseSettings):
|
||||
jingrow_api_key: str = ''
|
||||
jingrow_api_secret: str = ''
|
||||
jingrow_session_cookie: str = ''
|
||||
jingrow_site: str = ''
|
||||
|
||||
# Jingrow Cloud API配置
|
||||
jingrow_cloud_url: str = 'https://cloud.jingrow.com'
|
||||
@ -43,7 +42,7 @@ class Settings(BaseSettings):
|
||||
backend_port: int = 9001
|
||||
backend_reload: bool = True
|
||||
|
||||
# 异步任务队列(Dramatiq)配置
|
||||
# Dramatiq 任务队列
|
||||
worker_processes: int = 1
|
||||
worker_threads: int = 1
|
||||
watch: bool = True
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user