627 lines
27 KiB
HTML
627 lines
27 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>中国烟草AI合同及卷宗审核系统 - 新增/编辑系统配置</title>
|
||
<link href="https://unpkg.com/remixicon@2.5.0/fonts/remixicon.css" rel="stylesheet">
|
||
<link href="https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||
<!-- <link href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" rel="stylesheet">
|
||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> -->
|
||
<!-- 引入外部CSS文件 -->
|
||
<link href="main.css" rel="stylesheet">
|
||
<style>
|
||
.json-editor {
|
||
width: 100%;
|
||
min-height: 320px;
|
||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
border: 1px solid #e2e8f0;
|
||
border-radius: 4px;
|
||
padding: 12px;
|
||
background-color: #f8f9fc;
|
||
color: #374151;
|
||
}
|
||
|
||
.editor-actions {
|
||
text-align: right;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.json-error {
|
||
color: #e53e3e;
|
||
margin-top: 8px;
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.example-card {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background-color: #f8f9fc;
|
||
border-radius: 4px;
|
||
border: 1px solid #e2e8f0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.example-header {
|
||
padding: 12px;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
background-color: #f1f5f9;
|
||
}
|
||
|
||
.example-title {
|
||
font-weight: 500;
|
||
color: #4a5568;
|
||
}
|
||
|
||
.example-content {
|
||
padding: 12px;
|
||
flex-grow: 1;
|
||
overflow: auto;
|
||
}
|
||
|
||
.example-pre {
|
||
margin: 0;
|
||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
color: #374151;
|
||
}
|
||
|
||
.example-footer {
|
||
padding: 12px;
|
||
border-top: 1px solid #e2e8f0;
|
||
background-color: #f1f5f9;
|
||
}
|
||
|
||
/* 标签按钮样式 */
|
||
.tag-buttons {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.tag-button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 4px 12px;
|
||
border-radius: 16px;
|
||
font-size: 12px;
|
||
background-color: #f3f4f6;
|
||
color: #4b5563;
|
||
border: 1px solid #e5e7eb;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.tag-button:hover {
|
||
background-color: rgba(0, 104, 74, 0.1);
|
||
border-color: var(--primary-color);
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.tag-button.active {
|
||
background-color: rgba(0, 104, 74, 0.15);
|
||
border-color: var(--primary-color);
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
/* 代码语法高亮基础样式 */
|
||
.code-json .key { color: #07a; }
|
||
.code-json .string { color: #690; }
|
||
.code-json .number { color: #905; }
|
||
.code-json .boolean { color: #07a; }
|
||
.code-json .null { color: #999; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layout-container">
|
||
<!-- 侧边栏 -->
|
||
<div class="sidebar">
|
||
<div class="py-6 px-4 border-b border-gray-100">
|
||
<div class="flex items-center">
|
||
<i class="ri-file-search-line text-primary text-xl mr-2"></i>
|
||
<h2 class="text-lg font-medium">AI审核系统</h2>
|
||
</div>
|
||
</div>
|
||
<div class="py-4">
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-dashboard-line mr-3"></i>
|
||
<span>首页</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-file-upload-line mr-3"></i>
|
||
<span>文件上传</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-list-check-2 mr-3"></i>
|
||
<span>评查规则库</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-history-line mr-3"></i>
|
||
<span>审核历史</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item active">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-settings-3-line mr-3"></i>
|
||
<span>系统设置</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-content">
|
||
<!-- 面包屑导航 -->
|
||
<div class="breadcrumb">
|
||
<span class="breadcrumb-item">首页</span>
|
||
<span class="breadcrumb-item">系统设置</span>
|
||
<span class="breadcrumb-item">系统配置管理</span>
|
||
<span class="breadcrumb-item" id="page-title">新增系统配置</span>
|
||
</div>
|
||
|
||
<!-- 页面头部 -->
|
||
<div class="flex justify-between items-center mb-4">
|
||
<h2 class="text-xl font-medium" id="header-title">新增系统配置</h2>
|
||
<div>
|
||
<button class="ant-btn ant-btn-default mr-2" onclick="window.location.href='配置-列表.html'">
|
||
<i class="ri-arrow-left-line"></i> 返回
|
||
</button>
|
||
<button class="ant-btn ant-btn-primary" id="save-btn">
|
||
<i class="ri-save-line"></i> 保存
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 表单 -->
|
||
<div class="ant-card">
|
||
<div class="ant-card-body">
|
||
<form id="config-form">
|
||
<div class="grid grid-cols-1 gap-6">
|
||
<!-- 配置名称和状态放在同一行 -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div class="form-group">
|
||
<label class="form-label">配置名称 <span class="text-red-500">*</span></label>
|
||
<input type="text" class="form-input" id="config-name" name="config_name" placeholder="请输入配置名称(如:database_connection)" required>
|
||
<div class="text-sm text-secondary mt-1">唯一标识符,建议使用下划线命名法</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label class="form-label">状态</label>
|
||
<div class="mt-2">
|
||
<label class="inline-flex items-center">
|
||
<input type="checkbox" class="form-checkbox" id="is-active" name="is_active" checked>
|
||
<span class="ml-2">启用此配置</span>
|
||
</label>
|
||
</div>
|
||
<div class="text-sm text-secondary mt-1">禁用配置后,系统将不会读取此配置</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 修改所属模块为输入框+标签按钮(使用中文显示) -->
|
||
<div class="form-group">
|
||
<label class="form-label">所属模块 <span class="text-red-500">*</span></label>
|
||
<input type="text" class="form-input" id="module" name="module" placeholder="请输入或选择所属模块" required>
|
||
<div class="tag-buttons" id="module-tags">
|
||
<span class="tag-button" data-value="system">系统</span>
|
||
<span class="tag-button" data-value="auth">认证</span>
|
||
<span class="tag-button" data-value="file">文件</span>
|
||
<span class="tag-button" data-value="ai">AI配置</span>
|
||
<span class="tag-button" data-value="notification">通知</span>
|
||
</div>
|
||
<div class="text-sm text-secondary mt-1">将配置按功能模块进行分类,便于管理和查找</div>
|
||
</div>
|
||
|
||
<!-- 修改环境为输入框+标签按钮(使用中文显示,增加通用选项) -->
|
||
<div class="form-group">
|
||
<label class="form-label">环境 <span class="text-red-500">*</span></label>
|
||
<input type="text" class="form-input" id="environment" name="environment" placeholder="请输入或选择环境" required>
|
||
<div class="tag-buttons" id="env-tags">
|
||
<span class="tag-button" data-value="dev">开发环境</span>
|
||
<span class="tag-button" data-value="test">测试环境</span>
|
||
<span class="tag-button" data-value="prod">生产环境</span>
|
||
<span class="tag-button" data-value="common">通用</span>
|
||
</div>
|
||
<div class="text-sm text-secondary mt-1">不同环境可以使用相同的配置名称,系统会自动识别当前环境并使用对应配置</div>
|
||
</div>
|
||
|
||
<!-- 修改配置数据为左右等高两栏布局 -->
|
||
<div class="form-group">
|
||
<label class="form-label">配置数据 (JSON) <span class="text-red-500">*</span></label>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4" style="min-height: 390px;">
|
||
<!-- 左侧JSON编辑区 -->
|
||
<div class="h-full">
|
||
<textarea class="json-editor" id="config-data" name="config_data" required placeholder='请输入JSON格式的配置数据'></textarea>
|
||
<div class="editor-actions">
|
||
<button type="button" class="ant-btn ant-btn-text" id="btn-format-json">
|
||
<i class="ri-braces-line"></i> 格式化JSON
|
||
</button>
|
||
</div>
|
||
<div id="json-error" class="json-error hidden"></div>
|
||
</div>
|
||
|
||
<!-- 右侧示例区 -->
|
||
<div class="h-full">
|
||
<div class="example-card">
|
||
<div class="example-header">
|
||
<div class="example-title">配置示例</div>
|
||
</div>
|
||
<div class="example-content">
|
||
<pre class="example-pre" id="example-json"></pre>
|
||
</div>
|
||
<div class="example-footer">
|
||
<div class="text-sm font-medium mb-2">常用配置模板:</div>
|
||
<div class="flex flex-wrap gap-2">
|
||
<button type="button" class="ant-btn ant-btn-sm" onclick="loadTemplateJson('database')">数据库配置</button>
|
||
<button type="button" class="ant-btn ant-btn-sm" onclick="loadTemplateJson('file')">文件存储配置</button>
|
||
<button type="button" class="ant-btn ant-btn-sm" onclick="loadTemplateJson('ai')">AI服务配置</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 备注移到最后 -->
|
||
<div class="form-group">
|
||
<label class="form-label">备注</label>
|
||
<textarea class="form-textarea" id="remarks" name="remarks" placeholder="请输入配置备注信息" rows="2"></textarea>
|
||
<div class="text-sm text-secondary mt-1">可选填项,用于描述配置的用途、注意事项等</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 获取页面参数
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const configId = urlParams.get('id');
|
||
|
||
// 判断是新增还是编辑模式
|
||
if (configId) {
|
||
document.getElementById('page-title').textContent = '编辑系统配置';
|
||
document.getElementById('header-title').textContent = '编辑系统配置';
|
||
|
||
// 加载配置数据
|
||
// 实际应用中应通过AJAX请求获取数据
|
||
loadConfigData(configId);
|
||
}
|
||
|
||
// 初始化示例JSON
|
||
initExampleJson();
|
||
|
||
// 格式化JSON按钮点击事件
|
||
document.getElementById('btn-format-json').addEventListener('click', function() {
|
||
formatJSON();
|
||
});
|
||
|
||
// 保存按钮点击事件
|
||
document.getElementById('save-btn').addEventListener('click', function() {
|
||
saveConfig();
|
||
});
|
||
|
||
// 初始化标签按钮事件
|
||
initTagButtons();
|
||
});
|
||
|
||
// 初始化示例JSON
|
||
function initExampleJson() {
|
||
const exampleObj = {
|
||
database: {
|
||
host: "db.cluster.com",
|
||
port: 5432,
|
||
pool_size: 20,
|
||
ssl: true
|
||
},
|
||
cache: {
|
||
ttl: 3600,
|
||
max_entries: 1000
|
||
},
|
||
feature_flags: ["new_ui", "analytics_v2"]
|
||
};
|
||
|
||
const exampleElement = document.getElementById('example-json');
|
||
exampleElement.innerHTML = syntaxHighlightJson(JSON.stringify(exampleObj, null, 2));
|
||
}
|
||
|
||
// JSON语法高亮
|
||
function syntaxHighlightJson(json) {
|
||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
|
||
let cls = 'number';
|
||
if (/^"/.test(match)) {
|
||
if (/:$/.test(match)) {
|
||
cls = 'key';
|
||
match = match.replace(':', '');
|
||
} else {
|
||
cls = 'string';
|
||
}
|
||
} else if (/true|false/.test(match)) {
|
||
cls = 'boolean';
|
||
} else if (/null/.test(match)) {
|
||
cls = 'null';
|
||
}
|
||
return '<span class="code-json ' + cls + '">' + match + '</span>';
|
||
});
|
||
}
|
||
|
||
// 初始化标签按钮事件
|
||
function initTagButtons() {
|
||
// 模块标签点击事件
|
||
document.querySelectorAll('#module-tags .tag-button').forEach(button => {
|
||
button.addEventListener('click', function() {
|
||
document.getElementById('module').value = this.textContent.trim();
|
||
|
||
// 更新选中状态
|
||
document.querySelectorAll('#module-tags .tag-button').forEach(btn => {
|
||
btn.classList.remove('active');
|
||
});
|
||
this.classList.add('active');
|
||
});
|
||
});
|
||
|
||
// 环境标签点击事件
|
||
document.querySelectorAll('#env-tags .tag-button').forEach(button => {
|
||
button.addEventListener('click', function() {
|
||
document.getElementById('environment').value = this.textContent.trim();
|
||
|
||
// 更新选中状态
|
||
document.querySelectorAll('#env-tags .tag-button').forEach(btn => {
|
||
btn.classList.remove('active');
|
||
});
|
||
this.classList.add('active');
|
||
});
|
||
});
|
||
}
|
||
|
||
// 加载配置数据
|
||
function loadConfigData(id) {
|
||
// 模拟数据
|
||
let configData = {
|
||
id: id,
|
||
config_name: 'database_connection',
|
||
module: 'system',
|
||
environment: 'prod',
|
||
is_active: true,
|
||
remarks: '数据库连接配置,包含主库和从库配置',
|
||
config_data: {
|
||
database: {
|
||
host: "db.cluster.com",
|
||
port: 5432,
|
||
pool_size: 20,
|
||
ssl: true
|
||
},
|
||
cache: {
|
||
ttl: 3600,
|
||
max_entries: 1000
|
||
},
|
||
feature_flags: ["new_ui", "analytics_v2"]
|
||
}
|
||
};
|
||
|
||
if (id === '2') {
|
||
configData.config_name = 'text_extraction_ai';
|
||
configData.module = 'ai';
|
||
configData.environment = 'test';
|
||
configData.remarks = 'AI文本抽取服务配置';
|
||
} else if (id === '3') {
|
||
configData.config_name = 'notification_service';
|
||
configData.module = 'notification';
|
||
configData.environment = 'dev';
|
||
configData.is_active = false;
|
||
configData.remarks = '通知服务配置,目前处于开发测试阶段';
|
||
} else if (id === '4') {
|
||
configData.config_name = 'file_storage';
|
||
configData.module = 'file';
|
||
configData.environment = 'common';
|
||
configData.remarks = '文件存储通用配置,适用于所有环境';
|
||
}
|
||
|
||
// 填充表单
|
||
document.getElementById('config-name').value = configData.config_name;
|
||
document.getElementById('module').value = getModuleDisplayName(configData.module);
|
||
document.getElementById('environment').value = getEnvironmentDisplayName(configData.environment);
|
||
document.getElementById('is-active').checked = configData.is_active;
|
||
document.getElementById('remarks').value = configData.remarks || '';
|
||
document.getElementById('config-data').value = JSON.stringify(configData.config_data, null, 2);
|
||
|
||
// 更新标签选中状态
|
||
updateTagSelection('module', configData.module);
|
||
updateTagSelection('environment', configData.environment);
|
||
}
|
||
|
||
// 获取模块显示名称
|
||
function getModuleDisplayName(moduleCode) {
|
||
const moduleMap = {
|
||
'system': '系统',
|
||
'auth': '认证',
|
||
'file': '文件',
|
||
'ai': 'AI配置',
|
||
'notification': '通知'
|
||
};
|
||
return moduleMap[moduleCode] || moduleCode;
|
||
}
|
||
|
||
// 获取环境显示名称
|
||
function getEnvironmentDisplayName(envCode) {
|
||
const envMap = {
|
||
'dev': '开发环境',
|
||
'test': '测试环境',
|
||
'prod': '生产环境',
|
||
'common': '通用'
|
||
};
|
||
return envMap[envCode] || envCode;
|
||
}
|
||
|
||
// 更新标签选中状态
|
||
function updateTagSelection(type, value) {
|
||
const selector = type === 'module' ? '#module-tags .tag-button' : '#env-tags .tag-button';
|
||
document.querySelectorAll(selector).forEach(btn => {
|
||
if (btn.getAttribute('data-value') === value) {
|
||
btn.classList.add('active');
|
||
} else {
|
||
btn.classList.remove('active');
|
||
}
|
||
});
|
||
}
|
||
|
||
// 加载模板JSON
|
||
function loadTemplateJson(type) {
|
||
let template = {};
|
||
|
||
if (type === 'database') {
|
||
template = {
|
||
database: {
|
||
host: "localhost",
|
||
port: 5432,
|
||
username: "db_user",
|
||
password: "******",
|
||
name: "app_database",
|
||
pool_size: 10,
|
||
timeout: 5000,
|
||
ssl: false
|
||
}
|
||
};
|
||
} else if (type === 'file') {
|
||
template = {
|
||
storage: {
|
||
type: "local", // or "s3", "oss"
|
||
path: "/data/uploads",
|
||
allowed_types: ["pdf", "docx", "jpg", "png"],
|
||
max_size: 10485760, // 10MB
|
||
backup_enabled: true
|
||
}
|
||
};
|
||
} else if (type === 'ai') {
|
||
template = {
|
||
ai_service: {
|
||
provider: "openai",
|
||
api_key: "sk-******",
|
||
model: "gpt-4",
|
||
max_tokens: 2000,
|
||
temperature: 0.7,
|
||
timeout: 30000,
|
||
rate_limit: 10 // requests per minute
|
||
}
|
||
};
|
||
}
|
||
|
||
document.getElementById('config-data').value = JSON.stringify(template, null, 2);
|
||
formatJSON();
|
||
}
|
||
|
||
// 格式化JSON
|
||
function formatJSON() {
|
||
const jsonArea = document.getElementById('config-data');
|
||
const jsonError = document.getElementById('json-error');
|
||
|
||
try {
|
||
const jsonStr = jsonArea.value.trim();
|
||
if (!jsonStr) {
|
||
return;
|
||
}
|
||
|
||
const jsonObj = JSON.parse(jsonStr);
|
||
jsonArea.value = JSON.stringify(jsonObj, null, 2);
|
||
jsonError.classList.add('hidden');
|
||
} catch (error) {
|
||
jsonError.textContent = '无效的JSON格式: ' + error.message;
|
||
jsonError.classList.remove('hidden');
|
||
}
|
||
}
|
||
|
||
// 保存配置
|
||
function saveConfig() {
|
||
const form = document.getElementById('config-form');
|
||
|
||
// 表单验证
|
||
if (!form.checkValidity()) {
|
||
form.reportValidity();
|
||
return;
|
||
}
|
||
|
||
// 验证JSON
|
||
const jsonArea = document.getElementById('config-data');
|
||
const jsonError = document.getElementById('json-error');
|
||
let configDataObj = null;
|
||
|
||
try {
|
||
configDataObj = JSON.parse(jsonArea.value);
|
||
jsonError.classList.add('hidden');
|
||
} catch (error) {
|
||
jsonError.textContent = '无效的JSON格式: ' + error.message;
|
||
jsonError.classList.remove('hidden');
|
||
return;
|
||
}
|
||
|
||
// 获取表单数据
|
||
const configName = document.getElementById('config-name').value;
|
||
const moduleDisplay = document.getElementById('module').value;
|
||
const environmentDisplay = document.getElementById('environment').value;
|
||
const isActive = document.getElementById('is-active').checked;
|
||
const remarks = document.getElementById('remarks').value;
|
||
|
||
// 获取模块和环境的实际值
|
||
const module = getModuleCodeFromDisplay(moduleDisplay);
|
||
const environment = getEnvironmentCodeFromDisplay(environmentDisplay);
|
||
|
||
// 构建要提交的数据
|
||
const formData = {
|
||
id: urlParams.get('id') || null,
|
||
config_name: configName,
|
||
module: module,
|
||
environment: environment,
|
||
is_active: isActive,
|
||
remarks: remarks,
|
||
config_data: configDataObj
|
||
};
|
||
|
||
console.log('提交数据:', formData);
|
||
|
||
// 实际应用中应通过AJAX提交数据
|
||
setTimeout(() => {
|
||
alert('保存成功!');
|
||
window.location.href = '配置-列表.html';
|
||
}, 500);
|
||
}
|
||
|
||
// 从显示名称获取模块代码
|
||
function getModuleCodeFromDisplay(displayName) {
|
||
const moduleMap = {
|
||
'系统': 'system',
|
||
'认证': 'auth',
|
||
'文件': 'file',
|
||
'AI配置': 'ai',
|
||
'通知': 'notification'
|
||
};
|
||
return moduleMap[displayName] || displayName;
|
||
}
|
||
|
||
// 从显示名称获取环境代码
|
||
function getEnvironmentCodeFromDisplay(displayName) {
|
||
const envMap = {
|
||
'开发环境': 'dev',
|
||
'测试环境': 'test',
|
||
'生产环境': 'prod',
|
||
'通用': 'common'
|
||
};
|
||
return envMap[displayName] || displayName;
|
||
}
|
||
</script>
|
||
</body>
|
||
</html> |