|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>期货智析 - 配置管理</title>
|
|
|
|
|
|
<!-- CSS -->
|
|
|
<link rel="stylesheet" href="/static/css/variables.css">
|
|
|
<link rel="stylesheet" href="/static/css/base.css">
|
|
|
<link rel="stylesheet" href="/static/css/components.css">
|
|
|
<link rel="stylesheet" href="/static/css/layout.css">
|
|
|
|
|
|
<style>
|
|
|
.config-grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
|
gap: var(--spacing-lg);
|
|
|
margin-bottom: var(--spacing-xl);
|
|
|
}
|
|
|
|
|
|
.config-card {
|
|
|
background: var(--bg-card);
|
|
|
border: 1px solid var(--border-color);
|
|
|
border-radius: var(--radius-lg);
|
|
|
padding: var(--spacing-lg);
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
transition: all var(--transition-fast);
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
|
|
|
.config-card:hover {
|
|
|
transform: translateY(-4px);
|
|
|
box-shadow: var(--shadow-lg);
|
|
|
border-color: var(--border-glow);
|
|
|
}
|
|
|
|
|
|
.config-card__icon {
|
|
|
font-size: 40px;
|
|
|
margin-bottom: var(--spacing-md);
|
|
|
}
|
|
|
|
|
|
.config-card__title {
|
|
|
font-size: var(--font-size-lg);
|
|
|
font-weight: 700;
|
|
|
color: var(--text-primary);
|
|
|
margin-bottom: var(--spacing-xs);
|
|
|
}
|
|
|
|
|
|
.config-card__desc {
|
|
|
font-size: var(--font-size-sm);
|
|
|
color: var(--text-secondary);
|
|
|
line-height: 1.6;
|
|
|
margin-bottom: var(--spacing-md);
|
|
|
}
|
|
|
|
|
|
.config-card__action {
|
|
|
display: inline-flex;
|
|
|
align-items: center;
|
|
|
gap: 6px;
|
|
|
font-size: var(--font-size-sm);
|
|
|
color: var(--color-primary);
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
/* 品种表格区域 */
|
|
|
.symbols-section {
|
|
|
margin-top: var(--spacing-xl);
|
|
|
}
|
|
|
|
|
|
.symbols-table-wrap {
|
|
|
background: var(--bg-card);
|
|
|
border: 1px solid var(--border-color);
|
|
|
border-radius: var(--radius-lg);
|
|
|
overflow: hidden;
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
}
|
|
|
|
|
|
.symbols-toolbar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
padding: var(--spacing-md) var(--spacing-lg);
|
|
|
border-bottom: 1px solid var(--border-color);
|
|
|
flex-wrap: wrap;
|
|
|
gap: var(--spacing-sm);
|
|
|
}
|
|
|
|
|
|
.symbols-toolbar__left {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: var(--spacing-sm);
|
|
|
}
|
|
|
|
|
|
.symbols-toolbar__right {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: var(--spacing-sm);
|
|
|
}
|
|
|
|
|
|
.table {
|
|
|
width: 100%;
|
|
|
border-collapse: collapse;
|
|
|
}
|
|
|
|
|
|
.table thead th {
|
|
|
padding: 12px var(--spacing-md);
|
|
|
font-size: var(--font-size-xs);
|
|
|
font-weight: 600;
|
|
|
color: var(--text-secondary);
|
|
|
text-align: left;
|
|
|
background: var(--bg-primary);
|
|
|
border-bottom: 1px solid var(--border-color);
|
|
|
text-transform: uppercase;
|
|
|
letter-spacing: 0.5px;
|
|
|
}
|
|
|
|
|
|
.table tbody tr {
|
|
|
transition: background var(--transition-fast);
|
|
|
}
|
|
|
|
|
|
.table tbody tr:hover {
|
|
|
background: var(--bg-primary);
|
|
|
}
|
|
|
|
|
|
.table tbody td {
|
|
|
padding: 12px var(--spacing-md);
|
|
|
font-size: var(--font-size-sm);
|
|
|
color: var(--text-primary);
|
|
|
border-bottom: 1px solid var(--border-color);
|
|
|
}
|
|
|
|
|
|
.table tbody tr:last-child td {
|
|
|
border-bottom: none;
|
|
|
}
|
|
|
|
|
|
.action-btns {
|
|
|
display: flex;
|
|
|
gap: 6px;
|
|
|
}
|
|
|
|
|
|
/* 上传区域 */
|
|
|
.upload-area {
|
|
|
border: 2px dashed var(--border-color);
|
|
|
border-radius: var(--radius-md);
|
|
|
padding: var(--spacing-xl);
|
|
|
text-align: center;
|
|
|
margin: var(--spacing-lg);
|
|
|
transition: all var(--transition-fast);
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
|
|
|
.upload-area:hover {
|
|
|
border-color: var(--color-primary);
|
|
|
background: var(--color-primary-soft);
|
|
|
}
|
|
|
|
|
|
.upload-area__icon {
|
|
|
font-size: 40px;
|
|
|
margin-bottom: var(--spacing-sm);
|
|
|
opacity: 0.5;
|
|
|
}
|
|
|
|
|
|
.upload-area__text {
|
|
|
font-size: var(--font-size-sm);
|
|
|
color: var(--text-secondary);
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="app-container">
|
|
|
<!-- 顶部导航 -->
|
|
|
<nav class="top-nav">
|
|
|
<div class="nav-left">
|
|
|
<div class="logo">
|
|
|
<div class="logo-icon">◈</div>
|
|
|
<div class="logo-text">
|
|
|
<span class="logo-title">期货智析</span>
|
|
|
<span class="logo-subtitle">CONFIG</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="nav-center">
|
|
|
<a class="nav-item active" href="/static/index.html">配置管理</a>
|
|
|
<a class="nav-item" href="/static/futures_analysis.html">品种分析</a>
|
|
|
<a class="nav-item" href="/static/ai_config.html">AI配置</a>
|
|
|
<a class="nav-item" href="/static/review_plan.html">复盘计划</a>
|
|
|
</div>
|
|
|
<div class="nav-right">
|
|
|
<button class="nav-btn" id="themeToggle" title="切换主题">🌙</button>
|
|
|
<span class="datetime" id="userInfo"></span>
|
|
|
<button class="nav-btn" id="btn-logout" title="登出">⏻</button>
|
|
|
</div>
|
|
|
</nav>
|
|
|
|
|
|
<!-- 主内容区 -->
|
|
|
<main class="main-content">
|
|
|
<!-- 功能入口卡片 -->
|
|
|
<div class="config-grid">
|
|
|
<a class="config-card" href="/static/futures_analysis.html" style="text-decoration:none;color:inherit;">
|
|
|
<div class="config-card__icon">📊</div>
|
|
|
<div class="config-card__title">品种分析</div>
|
|
|
<div class="config-card__desc">智能期货品种分析工具,提供K线图表、技术指标、AI智能分析等功能。</div>
|
|
|
<span class="config-card__action">进入分析 →</span>
|
|
|
</a>
|
|
|
|
|
|
<a class="config-card" href="/static/ai_config.html" style="text-decoration:none;color:inherit;">
|
|
|
<div class="config-card__icon">🤖</div>
|
|
|
<div class="config-card__title">AI 模型配置</div>
|
|
|
<div class="config-card__desc">配置AI分析模型、API密钥、分析参数和交易建议设置。</div>
|
|
|
<span class="config-card__action">配置模型 →</span>
|
|
|
</a>
|
|
|
|
|
|
<a class="config-card" href="/static/review_plan.html" style="text-decoration:none;color:inherit;">
|
|
|
<div class="config-card__icon">📝</div>
|
|
|
<div class="config-card__title">复盘计划</div>
|
|
|
<div class="config-card__desc">查看和管理交易复盘计划,生成每日复盘报告。</div>
|
|
|
<span class="config-card__action">查看计划 →</span>
|
|
|
</a>
|
|
|
|
|
|
<a class="config-card" href="/static/role_select.html" style="text-decoration:none;color:inherit;">
|
|
|
<div class="config-card__icon">👥</div>
|
|
|
<div class="config-card__title">用户管理</div>
|
|
|
<div class="config-card__desc">管理系统用户、角色权限和登录设置。</div>
|
|
|
<span class="config-card__action">用户管理 →</span>
|
|
|
</a>
|
|
|
</div>
|
|
|
|
|
|
<!-- 品种配置区域 -->
|
|
|
<div class="symbols-section">
|
|
|
<div class="symbols-table-wrap">
|
|
|
<div class="symbols-toolbar">
|
|
|
<div class="symbols-toolbar__left">
|
|
|
<h3 style="font-size:var(--font-size-lg);font-weight:700;">品种列表</h3>
|
|
|
<span class="badge" id="symbolCount">0 个品种</span>
|
|
|
</div>
|
|
|
<div class="symbols-toolbar__right">
|
|
|
<button class="btn btn--secondary btn--sm" id="btnUpload">
|
|
|
📤 上传配置
|
|
|
</button>
|
|
|
<button class="btn btn--secondary btn--sm" id="btnBatchCollect">
|
|
|
▶ 批量采集
|
|
|
</button>
|
|
|
<button class="btn btn--secondary btn--sm" id="btnBatchTask">
|
|
|
📅 批量建任务
|
|
|
</button>
|
|
|
<button class="btn btn--primary btn--sm" id="btnAddSymbol">
|
|
|
+ 添加品种
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 上传区域(默认隐藏) -->
|
|
|
<div class="upload-area" id="uploadArea" style="display:none;">
|
|
|
<div class="upload-area__icon">📂</div>
|
|
|
<div class="upload-area__text">点击或拖拽配置文件到此处<br><small>支持 JSON 格式</small></div>
|
|
|
<input type="file" id="fileInput" accept=".json" style="display:none;">
|
|
|
</div>
|
|
|
|
|
|
<!-- 品种表格 -->
|
|
|
<table class="table">
|
|
|
<thead>
|
|
|
<tr>
|
|
|
<th>品种名称</th>
|
|
|
<th>代码</th>
|
|
|
<th>交易所</th>
|
|
|
<th>类别</th>
|
|
|
<th>状态</th>
|
|
|
<th>操作</th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
<tbody id="symbolsTableBody">
|
|
|
<!-- 动态生成 -->
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
</main>
|
|
|
</div>
|
|
|
|
|
|
<!-- 添加/编辑品种模态框 -->
|
|
|
<div class="modal-overlay" id="symbolModal">
|
|
|
<div class="modal-content">
|
|
|
<div class="modal-header">
|
|
|
<h3 id="symbolModalTitle">添加品种</h3>
|
|
|
<button class="modal-close" data-close="symbolModal">✕</button>
|
|
|
</div>
|
|
|
<div class="modal-body">
|
|
|
<form id="symbolForm">
|
|
|
<div style="display:flex;flex-direction:column;gap:var(--spacing-md);">
|
|
|
<div>
|
|
|
<label style="display:block;font-size:var(--font-size-sm);font-weight:500;margin-bottom:var(--spacing-xs);color:var(--text-secondary);">品种名称</label>
|
|
|
<input type="text" class="input" id="symbolName" placeholder="如:螺纹钢" required>
|
|
|
</div>
|
|
|
<div>
|
|
|
<label style="display:block;font-size:var(--font-size-sm);font-weight:500;margin-bottom:var(--spacing-xs);color:var(--text-secondary);">品种代码</label>
|
|
|
<input type="text" class="input" id="symbolCode" placeholder="如:RB" required>
|
|
|
</div>
|
|
|
<div>
|
|
|
<label style="display:block;font-size:var(--font-size-sm);font-weight:500;margin-bottom:var(--spacing-xs);color:var(--text-secondary);">交易所</label>
|
|
|
<select class="select" id="symbolExchange">
|
|
|
<option value="SHFE">上海期货交易所</option>
|
|
|
<option value="DCE">大连商品交易所</option>
|
|
|
<option value="CZCE">郑州商品交易所</option>
|
|
|
<option value="CFFEX">中国金融期货交易所</option>
|
|
|
<option value="INE">上海国际能源交易中心</option>
|
|
|
<option value="GFEX">广州期货交易所</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
<div>
|
|
|
<label style="display:block;font-size:var(--font-size-sm);font-weight:500;margin-bottom:var(--spacing-xs);color:var(--text-secondary);">类别</label>
|
|
|
<select class="select" id="symbolCategory">
|
|
|
<option value="energy">能源</option>
|
|
|
<option value="metal">金属</option>
|
|
|
<option value="agriculture">农产品</option>
|
|
|
<option value="finance">金融</option>
|
|
|
<option value="chemical">化工</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div style="display:flex;gap:var(--spacing-sm);justify-content:flex-end;margin-top:var(--spacing-lg);">
|
|
|
<button type="button" class="btn btn--secondary" data-close="symbolModal">取消</button>
|
|
|
<button type="submit" class="btn btn--primary">保存</button>
|
|
|
</div>
|
|
|
</form>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- JS -->
|
|
|
<script type="module">
|
|
|
import { api } from '/static/js/api.js';
|
|
|
import { themeManager } from '/static/js/theme.js';
|
|
|
import { showNotification } from '/static/js/components.js';
|
|
|
import { logout } from '/static/js/auth.js';
|
|
|
|
|
|
// 主题切换
|
|
|
document.getElementById('themeToggle').addEventListener('click', () => {
|
|
|
themeManager.toggle();
|
|
|
});
|
|
|
|
|
|
// 登出
|
|
|
document.getElementById('btn-logout').addEventListener('click', () => {
|
|
|
logout();
|
|
|
});
|
|
|
|
|
|
// 用户信息
|
|
|
const userInfo = JSON.parse(localStorage.getItem('user_info') || '{}');
|
|
|
document.getElementById('userInfo').textContent = userInfo.username || '';
|
|
|
|
|
|
// 加载品种列表
|
|
|
async function loadSymbols() {
|
|
|
try {
|
|
|
const data = await api.get('/config/symbols');
|
|
|
const symbols = data.symbols || data || [];
|
|
|
renderSymbols(symbols);
|
|
|
} catch (err) {
|
|
|
showNotification('加载品种列表失败: ' + err.message, 'error');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function renderSymbols(symbols) {
|
|
|
const tbody = document.getElementById('symbolsTableBody');
|
|
|
document.getElementById('symbolCount').textContent = symbols.length + ' 个品种';
|
|
|
|
|
|
if (!symbols.length) {
|
|
|
tbody.innerHTML = '<tr><td colspan="6" style="text-align:center;color:var(--text-secondary);padding:40px;">暂无品种数据</td></tr>';
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
tbody.innerHTML = symbols.map((s, i) => `
|
|
|
<tr>
|
|
|
<td style="font-weight:600;">${s.name || '--'}</td>
|
|
|
<td><code style="background:var(--bg-primary);padding:2px 8px;border-radius:4px;font-size:12px;">${s.symbol || s.code || '--'}</code></td>
|
|
|
<td>${s.exchange || '--'}</td>
|
|
|
<td><span class="badge">${s.category || '--'}</span></td>
|
|
|
<td><span class="badge ${s.enabled !== false ? 'badge--success' : ''}">${s.enabled !== false ? '启用' : '禁用'}</span></td>
|
|
|
<td>
|
|
|
<div class="action-btns">
|
|
|
<button class="btn btn--secondary btn--sm" onclick="editSymbol(${i})">编辑</button>
|
|
|
<button class="btn btn--danger btn--sm" onclick="deleteSymbol(${i})">删除</button>
|
|
|
</div>
|
|
|
</td>
|
|
|
</tr>
|
|
|
`).join('');
|
|
|
}
|
|
|
|
|
|
// 添加品种
|
|
|
document.getElementById('btnAddSymbol').addEventListener('click', () => {
|
|
|
document.getElementById('symbolModalTitle').textContent = '添加品种';
|
|
|
document.getElementById('symbolForm').reset();
|
|
|
document.getElementById('symbolModal').classList.add('active');
|
|
|
});
|
|
|
|
|
|
// 上传配置
|
|
|
document.getElementById('btnUpload').addEventListener('click', () => {
|
|
|
const area = document.getElementById('uploadArea');
|
|
|
area.style.display = area.style.display === 'none' ? 'block' : 'none';
|
|
|
});
|
|
|
|
|
|
document.getElementById('uploadArea').addEventListener('click', () => {
|
|
|
document.getElementById('fileInput').click();
|
|
|
});
|
|
|
|
|
|
// 关闭模态框
|
|
|
document.querySelectorAll('[data-close]').forEach(btn => {
|
|
|
btn.addEventListener('click', () => {
|
|
|
const modalId = btn.getAttribute('data-close');
|
|
|
document.getElementById(modalId).classList.remove('active');
|
|
|
});
|
|
|
});
|
|
|
|
|
|
// 表单提交
|
|
|
document.getElementById('symbolForm').addEventListener('submit', async (e) => {
|
|
|
e.preventDefault();
|
|
|
const name = document.getElementById('symbolName').value;
|
|
|
const code = document.getElementById('symbolCode').value;
|
|
|
const exchange = document.getElementById('symbolExchange').value;
|
|
|
const category = document.getElementById('symbolCategory').value;
|
|
|
|
|
|
try {
|
|
|
await api.post('/config/symbols', { name, symbol: code, exchange, category });
|
|
|
document.getElementById('symbolModal').classList.remove('active');
|
|
|
showNotification('品种添加成功', 'success');
|
|
|
loadSymbols();
|
|
|
} catch (err) {
|
|
|
showNotification('添加失败: ' + err.message, 'error');
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 全局函数
|
|
|
window.editSymbol = (index) => {
|
|
|
showNotification('编辑功能 - 待实现', 'info');
|
|
|
};
|
|
|
|
|
|
window.deleteSymbol = async (index) => {
|
|
|
if (confirm('确定要删除该品种吗?')) {
|
|
|
showNotification('删除功能 - 待实现', 'info');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 初始化
|
|
|
loadSymbols();
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|