You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
buffer_platform/buffer_platform_v2/app/static/index.html

447 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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">&#9672;</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="切换主题">&#127769;</button>
<span class="datetime" id="userInfo"></span>
<button class="nav-btn" id="btn-logout" title="登出">&#x23FB;</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">&#128202;</div>
<div class="config-card__title">品种分析</div>
<div class="config-card__desc">智能期货品种分析工具提供K线图表、技术指标、AI智能分析等功能。</div>
<span class="config-card__action">进入分析 &rarr;</span>
</a>
<a class="config-card" href="/static/ai_config.html" style="text-decoration:none;color:inherit;">
<div class="config-card__icon">&#129302;</div>
<div class="config-card__title">AI 模型配置</div>
<div class="config-card__desc">配置AI分析模型、API密钥、分析参数和交易建议设置。</div>
<span class="config-card__action">配置模型 &rarr;</span>
</a>
<a class="config-card" href="/static/review_plan.html" style="text-decoration:none;color:inherit;">
<div class="config-card__icon">&#128221;</div>
<div class="config-card__title">复盘计划</div>
<div class="config-card__desc">查看和管理交易复盘计划,生成每日复盘报告。</div>
<span class="config-card__action">查看计划 &rarr;</span>
</a>
<a class="config-card" href="/static/role_select.html" style="text-decoration:none;color:inherit;">
<div class="config-card__icon">&#128101;</div>
<div class="config-card__title">用户管理</div>
<div class="config-card__desc">管理系统用户、角色权限和登录设置。</div>
<span class="config-card__action">用户管理 &rarr;</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">
&#128228; 上传配置
</button>
<button class="btn btn--secondary btn--sm" id="btnBatchCollect">
&#9654; 批量采集
</button>
<button class="btn btn--secondary btn--sm" id="btnBatchTask">
&#128197; 批量建任务
</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">&#128194;</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">&#10005;</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>