Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e9d9f00e8 | |||
| e155682b5f |
@@ -24,11 +24,33 @@ def get_active_contracts(db: Session) -> list[str]:
|
||||
|
||||
@router.get("/", response_class=HTMLResponse)
|
||||
def contract_index(request: Request, db: Session = Depends(get_db)):
|
||||
active_contracts = get_active_contracts(db)
|
||||
from app.models import Product
|
||||
|
||||
# Build product → contracts mapping, ordered by product code
|
||||
products = (
|
||||
db.query(Product)
|
||||
.order_by(Product.code)
|
||||
.all()
|
||||
)
|
||||
|
||||
product_groups = []
|
||||
all_codes = []
|
||||
for prod in products:
|
||||
codes = [
|
||||
c.code for c in prod.contracts if c.is_active
|
||||
]
|
||||
if codes:
|
||||
product_groups.append({
|
||||
"code": prod.code,
|
||||
"name": prod.name,
|
||||
"exchange": prod.exchange,
|
||||
"contracts": codes,
|
||||
})
|
||||
all_codes.extend(codes)
|
||||
|
||||
latest = (
|
||||
db.query(DailyBar)
|
||||
.filter(DailyBar.contract.in_(active_contracts))
|
||||
.filter(DailyBar.contract.in_(all_codes))
|
||||
.order_by(DailyBar.date.desc())
|
||||
.all()
|
||||
)
|
||||
@@ -42,7 +64,7 @@ def contract_index(request: Request, db: Session = Depends(get_db)):
|
||||
template.render(
|
||||
request=request,
|
||||
active_nav="contracts",
|
||||
contracts=active_contracts,
|
||||
product_groups=product_groups,
|
||||
contract_bars=contract_bars,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -5,12 +5,20 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="section-title">合约列表</div>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
{% for pg in product_groups %}
|
||||
<div style="margin-bottom:24px;border:1px solid var(--border);border-radius:10px;overflow:hidden;">
|
||||
<div class="product-header"
|
||||
style="display:flex;align-items:center;gap:12px;padding:12px 18px;background:var(--th-bg);cursor:pointer;user-select:none;"
|
||||
onclick="toggleProduct(this)">
|
||||
<span class="collapse-arrow" style="font-size:0.75rem;transition:transform .2s;display:inline-block;transform:rotate(0deg);">▼</span>
|
||||
<strong style="font-size:0.92rem;">{{ pg.code }} · {{ pg.name }}</strong>
|
||||
<span style="font-size:0.78rem;color:var(--sub);">{{ pg.exchange }}</span>
|
||||
<span style="font-size:0.78rem;color:var(--sub);margin-left:8px;">{{ pg.contracts|length }} 合约</span>
|
||||
</div>
|
||||
<div class="product-body">
|
||||
<table>
|
||||
<tr><th>合约</th><th>日期</th><th>开盘</th><th>收盘</th><th>最高</th><th>最低</th><th>振幅</th><th>操作</th></tr>
|
||||
{% for c in contracts %}
|
||||
{% for c in pg.contracts %}
|
||||
<tr>
|
||||
<td><strong>{{ c }}</strong></td>
|
||||
{% if c in contract_bars %}
|
||||
@@ -32,6 +40,22 @@
|
||||
<td><a href="/contracts/{{ c }}" style="color:var(--accent);text-decoration:none;">详情 →</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<script>
|
||||
function toggleProduct(header) {
|
||||
var body = header.nextElementSibling;
|
||||
var arrow = header.querySelector('.collapse-arrow');
|
||||
if (body.style.display === 'none') {
|
||||
body.style.display = 'block';
|
||||
arrow.style.transform = 'rotate(0deg)';
|
||||
} else {
|
||||
body.style.display = 'none';
|
||||
arrow.style.transform = 'rotate(-90deg)';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user