|
|
|
|
@ -365,13 +365,43 @@
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.symbol-table .symbol-category-row td {
|
|
|
|
|
background: var(--primary-light);
|
|
|
|
|
color: white;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
/* 分类 Tab 样式 */
|
|
|
|
|
.category-tabs-container {
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.category-tabs {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.category-tab {
|
|
|
|
|
padding: 8px 16px;
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
background: white;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.category-tab:hover {
|
|
|
|
|
border-color: var(--primary-light);
|
|
|
|
|
color: var(--primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.category-tab.active {
|
|
|
|
|
background: var(--primary);
|
|
|
|
|
border-color: var(--primary);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.category-content {
|
|
|
|
|
margin-top: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.add-symbol-form {
|
|
|
|
|
@ -1523,7 +1553,7 @@
|
|
|
|
|
const stockCount = Object.keys(stock).length;
|
|
|
|
|
document.getElementById('configCount').textContent = `期货 ${futuresCount} 个, 股票 ${stockCount} 个`;
|
|
|
|
|
|
|
|
|
|
const renderTable = (items, type) => {
|
|
|
|
|
const renderTable = (items, type, containerId) => {
|
|
|
|
|
let filteredItems = items;
|
|
|
|
|
|
|
|
|
|
if (currentSearchTerm) {
|
|
|
|
|
@ -1556,52 +1586,81 @@
|
|
|
|
|
grouped[category].push({ name, code });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 按分类顺序渲染
|
|
|
|
|
let tbodyHtml = '';
|
|
|
|
|
// 获取有数据的分类列表
|
|
|
|
|
const activeCategories = [];
|
|
|
|
|
for (const category of CATEGORY_ORDER) {
|
|
|
|
|
if (!grouped[category] || grouped[category].length === 0) continue;
|
|
|
|
|
tbodyHtml += `<tr class="symbol-category-row"><td colspan="3">${category}</td></tr>`;
|
|
|
|
|
for (const { name, code } of grouped[category]) {
|
|
|
|
|
tbodyHtml += `<tr>
|
|
|
|
|
<td class="symbol-name">${highlightText(name)}</td>
|
|
|
|
|
<td><input type="text" class="symbol-code-input" value="${code}" data-type="${type}" data-name="${name}" data-original="${code}"></td>
|
|
|
|
|
<td class="symbol-actions">
|
|
|
|
|
<button class="btn btn-primary btn-sm" onclick="saveSymbolCode('${type}', '${name}', this)">保存</button>
|
|
|
|
|
<button class="btn btn-danger btn-sm" onclick="deleteSymbol('${type}', '${code}')">删除</button>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>`;
|
|
|
|
|
if (grouped[category] && grouped[category].length > 0) {
|
|
|
|
|
activeCategories.push(category);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 处理未在映射表中的分类
|
|
|
|
|
for (const [category, symbols] of Object.entries(grouped)) {
|
|
|
|
|
if (CATEGORY_ORDER.includes(category)) continue;
|
|
|
|
|
tbodyHtml += `<tr class="symbol-category-row"><td colspan="3">${category}</td></tr>`;
|
|
|
|
|
for (const { name, code } of symbols) {
|
|
|
|
|
tbodyHtml += `<tr>
|
|
|
|
|
for (const category of Object.keys(grouped)) {
|
|
|
|
|
if (!CATEGORY_ORDER.includes(category) && grouped[category].length > 0) {
|
|
|
|
|
activeCategories.push(category);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (activeCategories.length === 0) {
|
|
|
|
|
return '<div class="empty-state"><p>暂无品种</p></div>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成 tab 导航
|
|
|
|
|
const tabsHtml = activeCategories.map((category, index) =>
|
|
|
|
|
`<button class="category-tab ${index === 0 ? 'active' : ''}"
|
|
|
|
|
onclick="switchCategoryTab('${containerId}', '${category}', this)">
|
|
|
|
|
${category} (${grouped[category].length})
|
|
|
|
|
</button>`
|
|
|
|
|
).join('');
|
|
|
|
|
|
|
|
|
|
// 生成表格内容(每个分类一个表格,默认只显示第一个)
|
|
|
|
|
const tablesHtml = activeCategories.map((category, index) => {
|
|
|
|
|
const rows = grouped[category].map(({ name, code }) =>
|
|
|
|
|
`<tr>
|
|
|
|
|
<td class="symbol-name">${highlightText(name)}</td>
|
|
|
|
|
<td><input type="text" class="symbol-code-input" value="${code}" data-type="${type}" data-name="${name}" data-original="${code}"></td>
|
|
|
|
|
<td class="symbol-actions">
|
|
|
|
|
<button class="btn btn-primary btn-sm" onclick="saveSymbolCode('${type}', '${name}', this)">保存</button>
|
|
|
|
|
<button class="btn btn-danger btn-sm" onclick="deleteSymbol('${type}', '${code}')">删除</button>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `<table class="symbol-table">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>品种名称</th>
|
|
|
|
|
<th>合约代码</th>
|
|
|
|
|
<th>操作</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>${tbodyHtml}</tbody>
|
|
|
|
|
</table>`;
|
|
|
|
|
</tr>`
|
|
|
|
|
).join('');
|
|
|
|
|
|
|
|
|
|
return `<div class="category-table-wrapper" data-category="${category}" style="display: ${index === 0 ? 'block' : 'none'}">
|
|
|
|
|
<table class="symbol-table">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>品种名称</th>
|
|
|
|
|
<th>合约代码</th>
|
|
|
|
|
<th>操作</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>${rows}</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>`;
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
return `<div class="category-tabs-container">
|
|
|
|
|
<div class="category-tabs">${tabsHtml}</div>
|
|
|
|
|
<div class="category-content">${tablesHtml}</div>
|
|
|
|
|
</div>`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.getElementById('tab-futures').innerHTML = renderTable(futures, 'futures');
|
|
|
|
|
document.getElementById('tab-stock').innerHTML = renderTable(stock, 'stock');
|
|
|
|
|
document.getElementById('tab-futures').innerHTML = renderTable(futures, 'futures', 'futures');
|
|
|
|
|
document.getElementById('tab-stock').innerHTML = renderTable(stock, 'stock', 'stock');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 切换分类 tab
|
|
|
|
|
function switchCategoryTab(containerId, category, btn) {
|
|
|
|
|
const container = btn.closest('.category-tabs-container');
|
|
|
|
|
|
|
|
|
|
// 更新 tab 按钮状态
|
|
|
|
|
container.querySelectorAll('.category-tab').forEach(tab => tab.classList.remove('active'));
|
|
|
|
|
btn.classList.add('active');
|
|
|
|
|
|
|
|
|
|
// 显示对应的表格
|
|
|
|
|
container.querySelectorAll('.category-table-wrapper').forEach(wrapper => {
|
|
|
|
|
wrapper.style.display = wrapper.dataset.category === category ? 'block' : 'none';
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterSymbols(searchTerm) {
|
|
|
|
|
|