zlwu преди 9 месеца
родител
ревизия
8a72186346
променени са 6 файла, в които са добавени 847 реда и са изтрити 1 реда
  1. 2 0
      admin/src/App.tsx
  2. 10 0
      admin/src/api/admin.ts
  3. 6 0
      admin/src/components/Layout.tsx
  4. 514 0
      admin/src/pages/SystemConfig/index.tsx
  5. 2 1
      backend/app/api/admin/__init__.py
  6. 313 0
      backend/app/api/admin/system_config.py

+ 2 - 0
admin/src/App.tsx

@@ -10,6 +10,7 @@ import Cards from './pages/Cards'
 import Keys from './pages/Keys'
 import Logs from './pages/Logs'
 import Announcements from './pages/Announcements'
+import SystemConfig from './pages/SystemConfig'
 
 function App() {
   return (
@@ -33,6 +34,7 @@ function App() {
           <Route path="keys" element={<Keys />} />
           <Route path="logs" element={<Logs />} />
           <Route path="announcements" element={<Announcements />} />
+          <Route path="system-config" element={<SystemConfig />} />
         </Route>
       </Routes>
     </BrowserRouter>

+ 10 - 0
admin/src/api/admin.ts

@@ -93,3 +93,13 @@ export const adminManagementApi = {
     apiClient.put(`/admin/admins/${id}/status`, null, { params: { status } }),
 }
 
+// 系统配置管理
+export const systemConfigApi = {
+  getList: (params?: any) => apiClient.get('/admin/system-config', { params }),
+  getDetail: (id: number) => apiClient.get(`/admin/system-config/${id}`),
+  create: (data: any) => apiClient.post('/admin/system-config', data),
+  update: (id: number, data: any) =>
+    apiClient.put(`/admin/system-config/${id}`, data),
+  delete: (id: number) => apiClient.delete(`/admin/system-config/${id}`),
+  toggleEditable: (id: number) => apiClient.put(`/admin/system-config/${id}/editable`),
+}

+ 6 - 0
admin/src/components/Layout.tsx

@@ -9,6 +9,7 @@ import {
   LogoutOutlined,
   SettingOutlined,
   BellOutlined,
+  DatabaseOutlined,
 } from '@ant-design/icons'
 import { useAuthStore } from '../store/authStore'
 import type { MenuProps } from 'antd'
@@ -56,6 +57,11 @@ const menuItems: MenuProps['items'] = [
     icon: <BellOutlined />,
     label: '公告管理',
   },
+  {
+    key: '/system-config',
+    icon: <DatabaseOutlined />,
+    label: '系统配置',
+  },
 ]
 
 export default function Layout() {

+ 514 - 0
admin/src/pages/SystemConfig/index.tsx

@@ -0,0 +1,514 @@
+import { useState, useEffect } from 'react'
+import {
+  Button,
+  message,
+  Modal,
+  Form,
+  Input,
+  Select,
+  Space,
+  Tag,
+  Card,
+  Descriptions,
+  Switch,
+} from 'antd'
+import { EyeOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'
+import { systemConfigApi } from '../../api/admin'
+import type { ColumnsType } from 'antd/es/table'
+import dayjs from 'dayjs'
+import utc from 'dayjs/plugin/utc'
+import timezone from 'dayjs/plugin/timezone'
+import ResizableTable from '../../components/ResizableTable'
+
+dayjs.extend(utc)
+dayjs.extend(timezone)
+
+const { TextArea } = Input
+
+interface SystemConfigItem {
+  id: number
+  config_key: string
+  config_value: string
+  config_type: string
+  description: string | null
+  is_system: boolean
+  is_editable: boolean
+  created_at: string | null
+  updated_at: string | null
+}
+
+export default function SystemConfig() {
+  const [loading, setLoading] = useState(false)
+  const [data, setData] = useState<SystemConfigItem[]>([])
+  const [keyword, setKeyword] = useState<string>('')
+  const [configType, setConfigType] = useState<string>('')
+  const [pagination, setPagination] = useState({
+    current: 1,
+    pageSize: 10,
+    total: 0,
+  })
+  const [modalVisible, setModalVisible] = useState(false)
+  const [editingId, setEditingId] = useState<number | null>(null)
+  const [form] = Form.useForm()
+  const [detailVisible, setDetailVisible] = useState(false)
+  const [detailData, setDetailData] = useState<any>(null)
+  const [detailLoading, setDetailLoading] = useState(false)
+
+  const configTypeOptions = [
+    { value: 'int', label: '整数' },
+    { value: 'string', label: '字符串' },
+    { value: 'bool', label: '布尔值' },
+    { value: 'json', label: 'JSON' },
+  ]
+
+  const columns: ColumnsType<SystemConfigItem> = [
+    {
+      title: 'ID',
+      dataIndex: 'id',
+      key: 'id',
+      width: 80,
+    },
+    {
+      title: '配置键',
+      dataIndex: 'config_key',
+      key: 'config_key',
+      width: 200,
+      ellipsis: true,
+    },
+    {
+      title: '配置值',
+      dataIndex: 'config_value',
+      key: 'config_value',
+      width: 250,
+      ellipsis: true,
+      render: (text: string, record: SystemConfigItem) => {
+        // 对JSON类型的值进行特殊处理
+        if (record.config_type === 'json') {
+          try {
+            const parsed = JSON.parse(text)
+            return JSON.stringify(parsed, null, 2).substring(0, 100) + '...'
+          } catch {
+            return text
+          }
+        }
+        return text
+      },
+    },
+    {
+      title: '类型',
+      dataIndex: 'config_type',
+      key: 'config_type',
+      width: 100,
+      render: (type: string) => {
+        const typeMap: Record<string, { text: string; color: string }> = {
+          'int': { text: '整数', color: 'blue' },
+          'string': { text: '字符串', color: 'green' },
+          'bool': { text: '布尔值', color: 'orange' },
+          'json': { text: 'JSON', color: 'purple' },
+        }
+        const info = typeMap[type] || { text: type, color: 'default' }
+        return <Tag color={info.color}>{info.text}</Tag>
+      },
+    },
+    {
+      title: '描述',
+      dataIndex: 'description',
+      key: 'description',
+      width: 200,
+      ellipsis: true,
+      render: (text: string) => (text ? text : '-'),
+    },
+    {
+      title: '系统配置',
+      dataIndex: 'is_system',
+      key: 'is_system',
+      width: 100,
+      render: (isSystem: boolean) => (
+        isSystem ? <Tag color="red">系统</Tag> : <Tag color="default">自定义</Tag>
+      ),
+    },
+    {
+      title: '可编辑',
+      dataIndex: 'is_editable',
+      key: 'is_editable',
+      width: 100,
+      render: (isEditable: boolean, record: SystemConfigItem) => (
+        <Switch
+          checked={isEditable}
+          disabled={record.is_system} // 系统配置不可编辑
+          onChange={() => handleToggleEditable(record.id)}
+        />
+      ),
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'created_at',
+      key: 'created_at',
+      width: 180,
+      render: (text: string) => (text ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '-'),
+    },
+    {
+      title: '操作',
+      key: 'action',
+      width: 200,
+      render: (_, record) => (
+        <Space>
+          <Button
+            type="link"
+            size="small"
+            onClick={() => handleViewDetail(record.id)}
+          >
+            <EyeOutlined />
+            详情
+          </Button>
+          <Button
+            type="link"
+            size="small"
+            onClick={() => handleEdit(record)}
+            disabled={!record.is_editable}
+          >
+            <EditOutlined />
+            编辑
+          </Button>
+          <Button
+            type="link"
+            size="small"
+            danger
+            onClick={() => handleDelete(record.id)}
+            disabled={record.is_system} // 系统配置不可删除
+          >
+            <DeleteOutlined />
+            删除
+          </Button>
+        </Space>
+      ),
+    },
+  ]
+
+  const fetchData = async (
+    page: number = pagination.current,
+    pageSize: number = pagination.pageSize,
+    searchKeyword: string = keyword,
+    typeFilter: string = configType
+  ) => {
+    setLoading(true)
+    try {
+      const response = await systemConfigApi.getList({
+        page,
+        page_size: pageSize,
+        keyword: searchKeyword || undefined,
+        config_type: typeFilter || undefined,
+      })
+      if (response.code === 200) {
+        setData(response.data || [])
+        setPagination({
+          current: response.page || page,
+          pageSize: response.page_size || pageSize,
+          total: response.total || 0,
+        })
+      }
+    } catch (error) {
+      message.error('获取系统配置列表失败')
+    } finally {
+      setLoading(false)
+    }
+  }
+
+  useEffect(() => {
+    fetchData()
+  }, [])
+
+  const handleTableChange = (pag: any) => {
+    const { current, pageSize } = pag
+    fetchData(current, pageSize)
+  }
+
+  const handleSearch = () => {
+    // 搜索时从第一页开始
+    fetchData(1, pagination.pageSize, keyword, configType)
+  }
+
+  const handleCreate = async (values: any) => {
+    try {
+      if (editingId) {
+        await systemConfigApi.update(editingId, values)
+        message.success('更新成功')
+      } else {
+        await systemConfigApi.create(values)
+        message.success('创建成功')
+      }
+      setModalVisible(false)
+      setEditingId(null)
+      form.resetFields()
+      fetchData()
+    } catch (error) {
+      message.error(editingId ? '更新失败' : '创建失败')
+    }
+  }
+
+  const handleEdit = (record: SystemConfigItem) => {
+    setEditingId(record.id)
+    form.setFieldsValue({
+      ...record,
+    })
+    setModalVisible(true)
+  }
+
+  const handleDelete = async (id: number) => {
+    Modal.confirm({
+      title: '确认删除',
+      content: '确定要删除这条系统配置吗?删除后不可恢复。',
+      onOk: async () => {
+        try {
+          await systemConfigApi.delete(id)
+          message.success('删除成功')
+          fetchData()
+        } catch (error) {
+          message.error('删除失败')
+        }
+      },
+    })
+  }
+
+  const handleToggleEditable = async (id: number) => {
+    try {
+      const response = await systemConfigApi.toggleEditable(id)
+      if (response.code === 200) {
+        message.success('编辑状态更新成功')
+        fetchData()
+      } else {
+        message.error(response.msg || '编辑状态更新失败')
+      }
+    } catch (error) {
+      message.error('编辑状态更新失败')
+    }
+  }
+
+  const handleViewDetail = async (id: number) => {
+    setDetailLoading(true)
+    setDetailVisible(true)
+    try {
+      const response = await systemConfigApi.getDetail(id)
+      if (response.code === 200) {
+        setDetailData(response.data)
+      } else {
+        message.error('获取系统配置详情失败')
+      }
+    } catch (error) {
+      message.error('获取系统配置详情失败')
+    } finally {
+      setDetailLoading(false)
+    }
+  }
+
+  return (
+    <div>
+      {/* 第一区域:模块标题和检索栏 */}
+      <Card style={{ marginBottom: 24 }}>
+        <div style={{ marginBottom: 16 }}>
+          <div className="page-title">系统配置管理(管理系统配置参数)</div>
+        </div>
+
+        {/* 搜索栏 */}
+        <div style={{ padding: 16 }}>
+          <Space>
+            <Input.Search
+              allowClear
+              placeholder="按配置键或描述搜索"
+              value={keyword}
+              onChange={(e) => setKeyword(e.target.value)}
+              onSearch={handleSearch}
+              style={{ width: 260 }}
+            />
+            <Select
+              allowClear
+              placeholder="选择配置类型"
+              value={configType}
+              onChange={(value) => setConfigType(value)}
+              style={{ width: 120 }}
+            >
+              {configTypeOptions.map(option => (
+                <Select.Option key={option.value} value={option.value}>
+                  {option.label}
+                </Select.Option>
+              ))}
+            </Select>
+            <Button type="primary" onClick={handleSearch}>
+              搜索
+            </Button>
+          </Space>
+        </div>
+      </Card>
+
+      {/* 第二区域:列表和列表的按钮栏 */}
+      <Card>
+        {/* 按钮栏 */}
+        <div style={{ marginBottom: 16 }}>
+          <Space>
+            <Button
+              type="primary"
+              onClick={() => {
+                setEditingId(null)
+                form.resetFields()
+                form.setFieldsValue({
+                  config_type: 'string',
+                  is_editable: true,
+                })
+                setModalVisible(true)
+              }}
+            >
+              创建配置
+            </Button>
+          </Space>
+        </div>
+
+        <ResizableTable
+          columns={columns}
+          dataSource={data}
+          loading={loading}
+          rowKey="id"
+          actionColumnKey="action"
+          pagination={{
+            current: pagination.current,
+            pageSize: pagination.pageSize,
+            total: pagination.total,
+            showSizeChanger: true,
+            pageSizeOptions: [10, 20, 50],
+            showTotal: (total) => `共 ${total} 条`,
+          }}
+          onChange={handleTableChange}
+        />
+      </Card>
+
+      <Modal
+        title={editingId ? '编辑系统配置' : '创建系统配置'}
+        open={modalVisible}
+        onCancel={() => {
+          setModalVisible(false)
+          setEditingId(null)
+          form.resetFields()
+        }}
+        onOk={() => form.submit()}
+        width={800}
+      >
+        <Form form={form} onFinish={handleCreate} layout="vertical">
+          <Form.Item
+            name="config_key"
+            label="配置键"
+            rules={[
+              { required: true, message: '请输入配置键' },
+              { pattern: /^[a-zA-Z0-9_-]+$/, message: '配置键只能包含字母、数字、下划线和连字符' }
+            ]}
+          >
+            <Input
+              placeholder="请输入配置键"
+              disabled={!!editingId} // 编辑时不能修改配置键
+            />
+          </Form.Item>
+          <Form.Item
+            name="config_value"
+            label="配置值"
+            rules={[{ required: true, message: '请输入配置值' }]}
+          >
+            <TextArea
+              rows={4}
+              placeholder="请输入配置值"
+            />
+          </Form.Item>
+          <Form.Item
+            name="config_type"
+            label="配置类型"
+            rules={[{ required: true, message: '请选择配置类型' }]}
+          >
+            <Select placeholder="选择配置类型">
+              {configTypeOptions.map(option => (
+                <Select.Option key={option.value} value={option.value}>
+                  {option.label}
+                </Select.Option>
+              ))}
+            </Select>
+          </Form.Item>
+          <Form.Item name="description" label="描述">
+            <TextArea rows={2} placeholder="请输入配置描述" />
+          </Form.Item>
+          <Form.Item name="is_editable" label="可编辑" valuePropName="checked">
+            <Switch checkedChildren="可编辑" unCheckedChildren="不可编辑" />
+          </Form.Item>
+        </Form>
+      </Modal>
+
+      {/* 系统配置详情弹窗 */}
+      <Modal
+        title="系统配置详情"
+        open={detailVisible}
+        onCancel={() => setDetailVisible(false)}
+        footer={[
+          <Button key="close" onClick={() => setDetailVisible(false)}>
+            关闭
+          </Button>,
+        ]}
+        width={700}
+      >
+        {detailLoading ? (
+          <div style={{ textAlign: 'center', padding: 40 }}>加载中...</div>
+        ) : detailData ? (
+          <div>
+            <Descriptions title="基本信息" bordered column={1}>
+              <Descriptions.Item label="ID">{detailData.id}</Descriptions.Item>
+              <Descriptions.Item label="配置键">{detailData.config_key}</Descriptions.Item>
+              <Descriptions.Item label="配置类型">
+                {detailData.config_type === 'int' && <Tag color="blue">整数</Tag>}
+                {detailData.config_type === 'string' && <Tag color="green">字符串</Tag>}
+                {detailData.config_type === 'bool' && <Tag color="orange">布尔值</Tag>}
+                {detailData.config_type === 'json' && <Tag color="purple">JSON</Tag>}
+              </Descriptions.Item>
+              <Descriptions.Item label="配置类型">{detailData.config_type}</Descriptions.Item>
+              <Descriptions.Item label="描述">{detailData.description || '-'}</Descriptions.Item>
+              <Descriptions.Item label="系统配置">
+                {detailData.is_system ? (
+                  <Tag color="red">系统配置</Tag>
+                ) : (
+                  <Tag color="default">自定义配置</Tag>
+                )}
+              </Descriptions.Item>
+              <Descriptions.Item label="可编辑">
+                {detailData.is_editable ? (
+                  <Tag color="green">可编辑</Tag>
+                ) : (
+                  <Tag color="default">不可编辑</Tag>
+                )}
+              </Descriptions.Item>
+              <Descriptions.Item label="创建时间">
+                {detailData.created_at
+                  ? dayjs(detailData.created_at).format('YYYY-MM-DD HH:mm:ss')
+                  : '-'}
+              </Descriptions.Item>
+              <Descriptions.Item label="更新时间">
+                {detailData.updated_at
+                  ? dayjs(detailData.updated_at).format('YYYY-MM-DD HH:mm:ss')
+                  : '-'}
+              </Descriptions.Item>
+            </Descriptions>
+            <div style={{ marginTop: 24 }}>
+              <h3>配置值</h3>
+              <div
+                style={{
+                  background: '#f5f5f5',
+                  padding: 16,
+                  borderRadius: 4,
+                  whiteSpace: 'pre-wrap',
+                  wordBreak: 'break-word',
+                  fontFamily: 'monospace',
+                }}
+              >
+                {detailData.config_type === 'json'
+                  ? JSON.stringify(JSON.parse(detailData.config_value), null, 2)
+                  : detailData.config_value}
+              </div>
+            </div>
+          </div>
+        ) : null}
+      </Modal>
+    </div>
+  )
+}

+ 2 - 1
backend/app/api/admin/__init__.py

@@ -1,7 +1,7 @@
 """管理端接口"""
 
 from fastapi import APIRouter
-from app.api.admin import auth, users, software, cards, keys, logs, announcements, admins, dashboard
+from app.api.admin import auth, users, software, cards, keys, logs, announcements, admins, dashboard, system_config
 
 router = APIRouter()
 
@@ -13,5 +13,6 @@ router.include_router(cards.router, prefix="/cards", tags=["卡密管理"])
 router.include_router(keys.router, prefix="/keys", tags=["密钥管理"])
 router.include_router(logs.router, prefix="/logs", tags=["日志管理"])
 router.include_router(announcements.router, prefix="/announcements", tags=["公告管理"])
+router.include_router(system_config.router, prefix="/system-config", tags=["系统配置管理"])
 router.include_router(dashboard.router, prefix="/dashboard", tags=["仪表盘"])
 

+ 313 - 0
backend/app/api/admin/system_config.py

@@ -0,0 +1,313 @@
+"""
+系统配置管理接口
+"""
+from app.utils.timezone import beijing_now
+from typing import Optional, Any
+
+from fastapi import APIRouter, Depends, Query, Request
+from pydantic import BaseModel
+from sqlalchemy import or_
+from sqlalchemy.orm import Session
+
+from app.api.deps import get_current_admin
+from app.database import get_db
+from app.models.system_config import SystemConfig
+
+router = APIRouter()
+
+
+class SystemConfigCreate(BaseModel):
+    """创建系统配置请求"""
+    config_key: str
+    config_value: str
+    config_type: str = 'string'
+    description: Optional[str] = None
+    is_system: int = 0
+    is_editable: int = 1
+
+
+class SystemConfigUpdate(BaseModel):
+    """更新系统配置请求"""
+    config_value: Optional[str] = None
+    config_type: Optional[str] = None
+    description: Optional[str] = None
+
+
+@router.get("")
+async def get_system_configs(
+    page: int = Query(1, ge=1),
+    page_size: int = Query(10, ge=1, le=100),
+    keyword: Optional[str] = Query(None, description="搜索关键词(配置键、描述)"),
+    config_type: Optional[str] = Query(None, description="配置类型过滤"),
+    db: Session = Depends(get_db),
+    current_admin: Any = Depends(get_current_admin),
+):
+    """获取系统配置列表(支持检索与分页),按创建时间倒序"""
+    offset = (page - 1) * page_size
+
+    query = db.query(SystemConfig).filter(SystemConfig.is_deleted == 0)
+
+    # 关键字搜索:配置键或描述模糊匹配
+    if keyword:
+        like_pattern = f"%{keyword}%"
+        query = query.filter(
+            or_(
+                SystemConfig.config_key.like(like_pattern),
+                SystemConfig.description.like(like_pattern),
+            )
+        )
+
+    # 配置类型过滤
+    if config_type:
+        query = query.filter(SystemConfig.config_type == config_type)
+
+    # 按创建时间倒序
+    query = query.order_by(SystemConfig.created_at.desc())
+
+    total = query.count()
+    configs = query.offset(offset).limit(page_size).all()
+
+    return {
+        "code": 200,
+        "msg": "成功",
+        "data": [
+            {
+                "id": config.id,
+                "config_key": config.config_key,
+                "config_value": config.config_value,
+                "config_type": config.config_type,
+                "description": config.description,
+                "is_system": bool(config.is_system),
+                "is_editable": bool(config.is_editable),
+                "created_at": config.created_at.isoformat() if config.created_at else None,
+                "updated_at": config.updated_at.isoformat() if config.updated_at else None,
+            }
+            for config in configs
+        ],
+        "total": total,
+        "page": page,
+        "page_size": page_size,
+    }
+
+
+@router.get("/{config_id}")
+async def get_system_config_detail(
+    config_id: int,
+    db: Session = Depends(get_db),
+    current_admin: Any = Depends(get_current_admin)
+):
+    """获取系统配置详情"""
+    config = db.query(SystemConfig).filter(SystemConfig.id == config_id).first()
+    if not config:
+        return {"code": 404, "msg": "配置不存在"}
+
+    return {
+        "code": 200,
+        "msg": "成功",
+        "data": {
+            "id": config.id,
+            "config_key": config.config_key,
+            "config_value": config.config_value,
+            "config_type": config.config_type,
+            "description": config.description,
+            "is_system": bool(config.is_system),
+            "is_editable": bool(config.is_editable),
+            "created_at": config.created_at.isoformat() if config.created_at else None,
+            "updated_at": config.updated_at.isoformat() if config.updated_at else None
+        }
+    }
+
+
+@router.post("")
+async def create_system_config(
+    req: SystemConfigCreate,
+    request: Request,
+    db: Session = Depends(get_db),
+    current_admin: Any = Depends(get_current_admin)
+):
+    """创建系统配置"""
+    # 检查配置键是否已存在
+    existing_config = db.query(SystemConfig).filter(
+        SystemConfig.config_key == req.config_key,
+        SystemConfig.is_deleted == 0
+    ).first()
+
+    if existing_config:
+        return {"code": 400, "msg": "配置键已存在"}
+
+    config = SystemConfig(
+        config_key=req.config_key,
+        config_value=req.config_value,
+        config_type=req.config_type,
+        description=req.description,
+        is_system=req.is_system,
+        is_editable=req.is_editable,
+        created_at=beijing_now(),
+        updated_at=beijing_now()
+    )
+    db.add(config)
+
+    # 记录操作日志
+    from app.utils.history import create_operation_log
+    client_ip = request.client.host if request.client else None
+    create_operation_log(
+        db=db,
+        admin_id=current_admin.id,
+        module="系统配置管理",
+        action="创建配置",
+        description=f"创建系统配置:{req.config_key}",
+        new_data={
+            "config_key": req.config_key,
+            "config_value": req.config_value,
+            "config_type": req.config_type,
+            "description": req.description
+        },
+        ip_address=client_ip
+    )
+
+    db.commit()
+
+    return {"code": 200, "msg": "创建成功", "data": {"id": config.id}}
+
+
+@router.put("/{config_id}")
+async def update_system_config(
+    config_id: int,
+    req: SystemConfigUpdate,
+    request: Request,
+    db: Session = Depends(get_db),
+    current_admin: Any = Depends(get_current_admin)
+):
+    """更新系统配置"""
+    config = db.query(SystemConfig).filter(SystemConfig.id == config_id).first()
+    if not config:
+        return {"code": 404, "msg": "配置不存在"}
+
+    # 检查是否可编辑
+    if not config.is_editable:
+        return {"code": 403, "msg": "该配置不可编辑"}
+
+    # 记录更新前的状态
+    old_data = {
+        "config_key": config.config_key,
+        "config_value": config.config_value,
+        "config_type": config.config_type,
+        "description": config.description
+    }
+
+    # 更新字段
+    if req.config_value is not None:
+        config.config_value = req.config_value
+    if req.config_type is not None:
+        config.config_type = req.config_type
+    if req.description is not None:
+        config.description = req.description
+    config.updated_at = beijing_now()
+
+    # 记录操作日志
+    from app.utils.history import create_operation_log
+    client_ip = request.client.host if request.client else None
+    create_operation_log(
+        db=db,
+        admin_id=current_admin.id,
+        module="系统配置管理",
+        action="更新配置",
+        description=f"更新系统配置:{config.config_key}",
+        old_data=old_data,
+        new_data={
+            "config_key": config.config_key,
+            "config_value": config.config_value,
+            "config_type": config.config_type,
+            "description": config.description
+        },
+        ip_address=client_ip
+    )
+
+    db.commit()
+
+    return {"code": 200, "msg": "更新成功"}
+
+
+@router.put("/{config_id}/editable")
+async def toggle_system_config_editable(
+    config_id: int,
+    request: Request,
+    db: Session = Depends(get_db),
+    current_admin: Any = Depends(get_current_admin)
+):
+    """切换系统配置的可编辑状态"""
+    config = db.query(SystemConfig).filter(SystemConfig.id == config_id).first()
+    if not config:
+        return {"code": 404, "msg": "配置不存在"}
+
+    # 系统配置不能修改可编辑状态
+    if config.is_system:
+        return {"code": 403, "msg": "系统配置的可编辑状态不能修改"}
+
+    old_editable = config.is_editable
+    config.is_editable = 0 if config.is_editable else 1
+    config.updated_at = beijing_now()
+
+    # 记录操作日志
+    from app.utils.history import create_operation_log
+    client_ip = request.client.host if request.client else None
+    create_operation_log(
+        db=db,
+        admin_id=current_admin.id,
+        module="系统配置管理",
+        action="切换配置可编辑状态",
+        description=f"{'启用' if config.is_editable else '禁用'}配置编辑:{config.config_key}",
+        old_data={"is_editable": bool(old_editable)},
+        new_data={"is_editable": bool(config.is_editable)},
+        ip_address=client_ip
+    )
+
+    db.commit()
+
+    return {"code": 200, "msg": "可编辑状态更新成功", "data": {"is_editable": bool(config.is_editable)}}
+
+
+@router.delete("/{config_id}")
+async def delete_system_config(
+    config_id: int,
+    request: Request,
+    db: Session = Depends(get_db),
+    current_admin: Any = Depends(get_current_admin)
+):
+    """删除系统配置(软删除)"""
+    config = db.query(SystemConfig).filter(
+        SystemConfig.id == config_id,
+        SystemConfig.is_deleted == 0
+    ).first()
+
+    if not config:
+        return {"code": 404, "msg": "配置不存在"}
+
+    # 检查是否为系统配置(系统配置不能删除)
+    if config.is_system:
+        return {"code": 403, "msg": "系统配置不能删除"}
+
+    config.is_deleted = 1
+    config.updated_at = beijing_now()
+
+    # 记录操作日志
+    from app.utils.history import create_operation_log
+    client_ip = request.client.host if request.client else None
+    create_operation_log(
+        db=db,
+        admin_id=current_admin.id,
+        module="系统配置管理",
+        action="删除配置",
+        description=f"删除系统配置:{config.config_key}",
+        old_data={
+            "config_key": config.config_key,
+            "config_value": config.config_value,
+            "config_type": config.config_type,
+            "description": config.description
+        },
+        ip_address=client_ip
+    )
+
+    db.commit()
+
+    return {"code": 200, "msg": "删除成功"}